mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-19 13:28:25 +00:00
Rework regens to match modern clients
This commit is contained in:
+205
-34
@@ -22,6 +22,8 @@
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/spdat.h"
|
||||
|
||||
#include "../common/data_verification.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "mob.h"
|
||||
|
||||
@@ -231,16 +233,81 @@ int32 Client::LevelRegen()
|
||||
return hp;
|
||||
}
|
||||
|
||||
int32 Client::CalcHPRegen()
|
||||
int32 Client::CalcHPRegen(bool bCombat)
|
||||
{
|
||||
int32 regen = LevelRegen() + itembonuses.HPRegen + spellbonuses.HPRegen;
|
||||
regen += aabonuses.HPRegen + GroupLeadershipAAHealthRegeneration();
|
||||
int item_regen = itembonuses.HPRegen; // worn spells and +regen, already capped
|
||||
item_regen += GetHeroicSTA() / 20;
|
||||
|
||||
item_regen += aabonuses.HPRegen;
|
||||
|
||||
int base = 0;
|
||||
auto base_data = database.GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data)
|
||||
base = static_cast<int>(base_data->hp_regen);
|
||||
|
||||
auto level = GetLevel();
|
||||
bool skip_innate = false;
|
||||
|
||||
if (IsSitting()) {
|
||||
if (level >= 50) {
|
||||
base++;
|
||||
if (level >= 65)
|
||||
base++;
|
||||
}
|
||||
|
||||
if ((Timer::GetCurrentTime() - tmSitting) > 60000) {
|
||||
if (!IsAffectedByBuffByGlobalGroup(GlobalGroup::Lich)) {
|
||||
auto tic_diff = std::min((Timer::GetCurrentTime() - tmSitting) / 60000, static_cast<uint32>(9));
|
||||
if (tic_diff != 1) { // starts at 2 mins
|
||||
int tic_bonus = tic_diff * 1.5 * base;
|
||||
if (m_pp.InnateSkills[InnateRegen] != InnateDisabled)
|
||||
tic_bonus = tic_bonus * 1.2;
|
||||
base = tic_bonus;
|
||||
skip_innate = true;
|
||||
} else if (m_pp.InnateSkills[InnateRegen] == InnateDisabled) { // no innate regen gets first tick
|
||||
int tic_bonus = base * 1.5;
|
||||
base = tic_bonus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip_innate && m_pp.InnateSkills[InnateRegen] != InnateDisabled) {
|
||||
if (level >= 50) {
|
||||
++base;
|
||||
if (level >= 55)
|
||||
++base;
|
||||
}
|
||||
base *= 2;
|
||||
}
|
||||
|
||||
if (IsStarved())
|
||||
base = 0;
|
||||
|
||||
base += GroupLeadershipAAHealthRegeneration();
|
||||
// some IsKnockedOut that sets to -1
|
||||
base = base * 100.0f * AreaHPRegen * 0.01f + 0.5f;
|
||||
// another check for IsClient && !(base + item_regen) && Cur_HP <= 0 do --base; do later
|
||||
|
||||
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||
auto fast_mod = RuleI(Character, RestRegenHP); // TODO: this is actually zone based
|
||||
auto max_hp = GetMaxHP();
|
||||
int fast_regen = 6 * (max_hp / fast_mod);
|
||||
if (base < fast_regen) // weird, but what the client is doing
|
||||
base = fast_regen;
|
||||
}
|
||||
|
||||
int regen = base + item_regen + spellbonuses.HPRegen; // TODO: client does this in buff tick
|
||||
return (regen * RuleI(Character, HPRegenMultiplier) / 100);
|
||||
}
|
||||
|
||||
int32 Client::CalcHPRegenCap()
|
||||
{
|
||||
int cap = RuleI(Character, ItemHealthRegenCap) + itembonuses.HeroicSTA / 25;
|
||||
int cap = RuleI(Character, ItemHealthRegenCap);
|
||||
if (GetLevel() > 60)
|
||||
cap = std::max(cap, GetLevel() - 30); // if the rule is set greater than normal I guess
|
||||
if (GetLevel() > 65)
|
||||
cap += GetLevel() - 65;
|
||||
cap += aabonuses.ItemHPRegenCap + spellbonuses.ItemHPRegenCap + itembonuses.ItemHPRegenCap;
|
||||
return (cap * RuleI(Character, HPRegenMultiplier) / 100);
|
||||
}
|
||||
@@ -1169,43 +1236,72 @@ int32 Client::CalcBaseManaRegen()
|
||||
return regen;
|
||||
}
|
||||
|
||||
int32 Client::CalcManaRegen()
|
||||
int32 Client::CalcManaRegen(bool bCombat)
|
||||
{
|
||||
uint8 clevel = GetLevel();
|
||||
int32 regen = 0;
|
||||
//this should be changed so we dont med while camping, etc...
|
||||
if (IsSitting() || (GetHorseId() != 0)) {
|
||||
BuffFadeBySitModifier();
|
||||
if (HasSkill(EQEmu::skills::SkillMeditate)) {
|
||||
this->medding = true;
|
||||
regen = (((GetSkill(EQEmu::skills::SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4;
|
||||
regen += spellbonuses.ManaRegen + itembonuses.ManaRegen;
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillMeditate, nullptr, -5);
|
||||
}
|
||||
else {
|
||||
regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen;
|
||||
int regen = 0;
|
||||
auto level = GetLevel();
|
||||
if (!IsStarved()) {
|
||||
// client does some base regen for shrouds here
|
||||
if (IsSitting() || CanMedOnHorse()) {
|
||||
// kind of weird to do it here w/e
|
||||
// client does some base medding regen for shrouds here
|
||||
if (GetClass() != BARD) {
|
||||
auto skill = GetSkill(EQEmu::skills::SkillMeditate);
|
||||
if (skill > 0) {
|
||||
regen++;
|
||||
if (skill > 1)
|
||||
regen++;
|
||||
if (skill >= 15)
|
||||
regen += skill / 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->medding = false;
|
||||
regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen;
|
||||
|
||||
if (level > 61) {
|
||||
regen++;
|
||||
if (level > 63)
|
||||
regen++;
|
||||
}
|
||||
//AAs
|
||||
|
||||
regen += aabonuses.ManaRegen;
|
||||
// add in + 1 bonus for SE_CompleteHeal, but we don't do anything for it yet?
|
||||
|
||||
int item_bonus = itembonuses.ManaRegen; // this is capped already
|
||||
int heroic_bonus = 0;
|
||||
|
||||
switch (GetCasterClass()) {
|
||||
case 'W':
|
||||
heroic_bonus = GetHeroicWIS();
|
||||
break;
|
||||
default:
|
||||
heroic_bonus = GetHeroicINT();
|
||||
break;
|
||||
}
|
||||
|
||||
item_bonus += heroic_bonus / 25;
|
||||
regen += item_bonus;
|
||||
|
||||
if (level <= 70 && regen > 65)
|
||||
regen = 65;
|
||||
|
||||
regen = regen * 100.0f * AreaManaRegen * 0.01f + 0.5f;
|
||||
|
||||
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||
auto fast_mod = RuleI(Character, RestRegenMana); // TODO: this is actually zone based
|
||||
auto max_mana = GetMaxMana();
|
||||
int fast_regen = 6 * (max_mana / fast_mod);
|
||||
if (regen < fast_regen) // weird, but what the client is doing
|
||||
regen = fast_regen;
|
||||
}
|
||||
|
||||
regen += spellbonuses.ManaRegen; // TODO: live does this in buff tick
|
||||
return (regen * RuleI(Character, ManaRegenMultiplier) / 100);
|
||||
}
|
||||
|
||||
int32 Client::CalcManaRegenCap()
|
||||
{
|
||||
int32 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap;
|
||||
switch (GetCasterClass()) {
|
||||
case 'I':
|
||||
cap += (itembonuses.HeroicINT / 25);
|
||||
break;
|
||||
case 'W':
|
||||
cap += (itembonuses.HeroicWIS / 25);
|
||||
break;
|
||||
}
|
||||
return (cap * RuleI(Character, ManaRegenMultiplier) / 100);
|
||||
}
|
||||
|
||||
@@ -2091,16 +2187,91 @@ int32 Client::CalcBaseEndurance()
|
||||
return base_end;
|
||||
}
|
||||
|
||||
int32 Client::CalcEnduranceRegen()
|
||||
int32 Client::CalcEnduranceRegen(bool bCombat)
|
||||
{
|
||||
int32 regen = int32(GetLevel() * 4 / 10) + 2;
|
||||
regen += aabonuses.EnduranceRegen + spellbonuses.EnduranceRegen + itembonuses.EnduranceRegen;
|
||||
int base = 0;
|
||||
if (!IsStarved()) {
|
||||
auto base_data = database.GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data) {
|
||||
base = static_cast<int>(base_data->end_regen);
|
||||
if (!auto_attack && base > 0)
|
||||
base += base / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// so when we are mounted, our local client SpeedRun is always 0, so this is always false, but the packets we process it to our own shit :P
|
||||
bool is_running = runmode && animation != 0 && GetHorseId() == 0; // TODO: animation is really what MQ2 calls SpeedRun
|
||||
|
||||
int weight_limit = GetSTR();
|
||||
auto level = GetLevel();
|
||||
if (GetClass() == MONK) {
|
||||
if (level > 99)
|
||||
weight_limit = 58;
|
||||
else if (level > 94)
|
||||
weight_limit = 57;
|
||||
else if (level > 89)
|
||||
weight_limit = 56;
|
||||
else if (level > 84)
|
||||
weight_limit = 55;
|
||||
else if (level > 79)
|
||||
weight_limit = 54;
|
||||
else if (level > 64)
|
||||
weight_limit = 53;
|
||||
else if (level > 63)
|
||||
weight_limit = 50;
|
||||
else if (level > 61)
|
||||
weight_limit = 47;
|
||||
else if (level > 59)
|
||||
weight_limit = 45;
|
||||
else if (level > 54)
|
||||
weight_limit = 40;
|
||||
else if (level > 50)
|
||||
weight_limit = 38;
|
||||
else if (level > 44)
|
||||
weight_limit = 36;
|
||||
else if (level > 29)
|
||||
weight_limit = 34;
|
||||
else if (level > 14)
|
||||
weight_limit = 32;
|
||||
else
|
||||
weight_limit = 30;
|
||||
}
|
||||
|
||||
bool encumbered = (CalcCurrentWeight() / 10) >= weight_limit;
|
||||
|
||||
if (is_running)
|
||||
base += level / -15;
|
||||
|
||||
if (encumbered)
|
||||
base += level / -15;
|
||||
|
||||
auto item_bonus = GetHeroicAGI() + GetHeroicDEX() + GetHeroicSTA() + GetHeroicSTR();
|
||||
item_bonus = item_bonus / 4 / 50;
|
||||
item_bonus += itembonuses.EnduranceRegen; // this is capped already
|
||||
base += item_bonus;
|
||||
|
||||
base = base * AreaEndRegen + 0.5f;
|
||||
|
||||
auto aa_regen = aabonuses.EnduranceRegen;
|
||||
|
||||
int regen = base;
|
||||
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||
auto fast_mod = RuleI(Character, RestRegenEnd); // TODO: this is actually zone based
|
||||
auto max_end = GetMaxEndurance();
|
||||
int fast_regen = 6 * (max_end / fast_mod);
|
||||
if (aa_regen < fast_regen) // weird, but what the client is doing
|
||||
aa_regen = fast_regen;
|
||||
}
|
||||
|
||||
regen += aa_regen;
|
||||
regen += spellbonuses.EnduranceRegen; // TODO: client does this in buff tick
|
||||
|
||||
return (regen * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
||||
}
|
||||
|
||||
int32 Client::CalcEnduranceRegenCap()
|
||||
{
|
||||
int cap = (RuleI(Character, ItemEnduranceRegenCap) + itembonuses.HeroicSTR / 25 + itembonuses.HeroicDEX / 25 + itembonuses.HeroicAGI / 25 + itembonuses.HeroicSTA / 25);
|
||||
int cap = RuleI(Character, ItemEnduranceRegenCap);
|
||||
return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user