int32 Client::CalcBaseHP() { if(GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { int stats = GetSTA(); if(stats > 255) { stats = (stats - 255) / 2; stats += 255; } base_hp = 5; auto base_data = database.GetBaseData(GetLevel(), GetClass()); if(base_data) { base_hp += base_data->base_hp + (base_data->hp_factor * stats); base_hp += (GetHeroicSTA() * 10); } } else { uint32 Post255; uint32 lm=GetClassLevelFactor(); if((GetSTA()-255)/2 > 0) Post255 = (GetSTA()-255)/2; else Post255 = 0; base_hp = (5)+(GetLevel()*lm/10) + (((GetSTA()-Post255)*GetLevel()*lm/3000)) + ((Post255*GetLevel())*lm/6000); } return base_hp; }
int32 Client::CalcBaseEndurance() { int32 base_end = 0; if(GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { double heroic_stats = (GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4.0f; double stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4.0f; if(stats > 201.0f) { stats = 1.25f * (stats - 201.0f) + 352.5f; } else if(stats > 100.0f) { stats = 2.5f * (stats - 100.0f) + 100.0f; } auto base_data = database.GetBaseData(GetLevel(), GetClass()); if(base_data) { base_end = base_data->base_end + (heroic_stats * 10.0f) + (base_data->endurance_factor * static_cast<int>(stats)); } } else { int Stats = GetSTR()+GetSTA()+GetDEX()+GetAGI(); int LevelBase = GetLevel() * 15; int at_most_800 = Stats; if(at_most_800 > 800) at_most_800 = 800; int Bonus400to800 = 0; int HalfBonus400to800 = 0; int Bonus800plus = 0; int HalfBonus800plus = 0; int BonusUpto800 = int( at_most_800 / 4 ) ; if(Stats > 400) { Bonus400to800 = int( (at_most_800 - 400) / 4 ); HalfBonus400to800 = int( std::max( ( at_most_800 - 400 ), 0 ) / 8 ); if(Stats > 800) { Bonus800plus = int( (Stats - 800) / 8 ) * 2; HalfBonus800plus = int( (Stats - 800) / 16 ); } } int bonus_sum = BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus; base_end = LevelBase; //take all of the sums from above, then multiply by level*0.075 base_end += ( bonus_sum * 3 * GetLevel() ) / 40; } return base_end; }
int32 Client::CalcBaseHP() { if(GetClientVersion() >= EQClientSoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { float SoDPost255; uint16 NormalSTA = GetSTA(); if(((NormalSTA - 255) / 2) > 0) SoDPost255 = ((NormalSTA - 255) / 2); else SoDPost255 = 0; int hp_factor = GetClassHPFactor(); if (level < 41) { base_hp = (5 + (GetLevel() * hp_factor / 12) + ((NormalSTA - SoDPost255) * GetLevel() * hp_factor / 3600)); } else if (level < 81) { base_hp = (5 + (40 * hp_factor / 12) + ((GetLevel() - 40) * hp_factor / 6) + ((NormalSTA - SoDPost255) * hp_factor / 90) + ((NormalSTA - SoDPost255) * (GetLevel() - 40) * hp_factor / 1800)); } else { base_hp = (5 + (80 * hp_factor / 8) + ((GetLevel() - 80) * hp_factor / 10) + ((NormalSTA - SoDPost255) * hp_factor / 90) + ((NormalSTA - SoDPost255) * hp_factor / 45)); } base_hp += (GetHeroicSTA() * 10); } else { uint16 Post255; uint16 lm=GetClassLevelFactor(); if((GetSTA()-255)/2 > 0) Post255 = (GetSTA()-255)/2; else Post255 = 0; base_hp = (5)+(GetLevel()*lm/10) + (((GetSTA()-Post255)*GetLevel()*lm/3000)) + ((Post255*GetLevel())*lm/6000); } return base_hp; }
int32 Client::CalcHPRegen(bool bCombat) { 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 max_hp = GetMaxHP(); int fast_regen = 6 * (max_hp / zone->newzone_data.FastRegenHP); 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::CalcEnduranceRegen(bool bCombat) { 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 max_end = GetMaxEndurance(); int fast_regen = 6 * (max_end / zone->newzone_data.FastRegenEndurance); 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::CalcBaseEndurance() { int32 base_end = 0; int32 base_endurance = 0; int32 ConvertedStats = 0; int32 sta_end = 0; int Stats = 0; if(GetClientVersion() >= EQClientSoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { int HeroicStats = 0; Stats = ((GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4); HeroicStats = ((GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4); if (Stats > 100) { ConvertedStats = (((Stats - 100) * 5 / 2) + 100); if (Stats > 201) { ConvertedStats -= ((Stats - 201) * 5 / 4); } } else { ConvertedStats = Stats; } if (GetLevel() < 41) { sta_end = (GetLevel() * 75 * ConvertedStats / 1000); base_endurance = (GetLevel() * 15); } else if (GetLevel() < 81) { sta_end = ((3 * ConvertedStats) + ((GetLevel() - 40) * 15 * ConvertedStats / 100)); base_endurance = (600 + ((GetLevel() - 40) * 30)); } else { sta_end = (9 * ConvertedStats); base_endurance = (1800 + ((GetLevel() - 80) * 18)); } base_end = (base_endurance + sta_end + (HeroicStats * 10)); } else { Stats = GetSTR()+GetSTA()+GetDEX()+GetAGI(); int LevelBase = GetLevel() * 15; int at_most_800 = Stats; if(at_most_800 > 800) at_most_800 = 800; int Bonus400to800 = 0; int HalfBonus400to800 = 0; int Bonus800plus = 0; int HalfBonus800plus = 0; int BonusUpto800 = int( at_most_800 / 4 ) ; if(Stats > 400) { Bonus400to800 = int( (at_most_800 - 400) / 4 ); HalfBonus400to800 = int( max( ( at_most_800 - 400 ), 0 ) / 8 ); if(Stats > 800) { Bonus800plus = int( (Stats - 800) / 8 ) * 2; HalfBonus800plus = int( (Stats - 800) / 16 ); } } int bonus_sum = BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus; base_end = LevelBase; //take all of the sums from above, then multiply by level*0.075 base_end += ( bonus_sum * 3 * GetLevel() ) / 40; } return base_end; }