Compare commits

...

8 Commits

Author SHA1 Message Date
KimLS 3ef106dc64 Bot compile fix 2021-09-27 00:57:04 -07:00
KimLS 7453326f87 HP overflow is now gated by a rule for clients (bots and mercs will always get fixed hp), fix for phantom stat aa regression 2021-09-21 21:29:28 -07:00
KimLS b82dfb91ae Fix for bot breaking, I don't normally build bots. 2021-09-16 11:21:37 -07:00
KimLS 5891b2c426 Change out 300 for named constant 2021-09-16 00:58:57 -07:00
KimLS 6e16f6c1b6 Match the client's bugged state with natural durability, remove redundant statbonus maxhp 2021-09-16 00:53:11 -07:00
KimLS fba333fe8a Suggested change, and simplified the AA function 2021-09-11 22:42:35 -07:00
KimLS edb7ea4ee3 Fix for build 2021-09-11 21:21:50 -07:00
KimLS 66cf4b546c Various changes:
- Heroic Sta HP calc will now apply after natural durability.
- The base 5 hp that everyone gets will now apply after natural
durability.
- Fixed a rounding issue in the mana calc that would sometimes give
the player +1 mana
- Fixed the endurance calc to match the client better.
- When a server has a custom stat cap active the new stat caps
will be reflected on the client.
    This is done by reserving an AA slot for a "Phantom" AA that will
    act like Planar Power with the difference between what the client
    sees and what the server has.
- AA slots cap now will be 300 (the later clients max)
instead of 240 (titanium's max)
2021-09-10 19:52:28 -07:00
18 changed files with 203 additions and 119 deletions
+3
View File
@@ -224,6 +224,9 @@ IF(OpenSSL_FOUND AND MBEDTLS_FOUND)
SET(TLS_LIBRARY_LIBS ${OPENSSL_LIBRARIES})
SET(TLS_LIBRARY_INCLUDE ${OPENSSL_INCLUDE_DIR})
ADD_DEFINITIONS(-DEQEMU_USE_OPENSSL)
IF(${OPENSSL_VERSION} VERSION_GREATER_EQUAL "1.1.1")
ADD_DEFINITIONS(-DCPPHTTPLIB_OPENSSL_SUPPORT)
ENDIF()
ELSEIF(TLS_LIBRARY_SELECTION STREQUAL "mbedTLS")
SET(TLS_LIBRARY_TYPE " mbedTLS")
SET(TLS_LIBRARY_ENABLED ON)
+1 -1
View File
@@ -860,7 +860,7 @@ static const uint32 MAX_PP_LANGUAGE = 28;
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
static const uint32 MAX_PP_INNATE_SKILL = 25;
static const uint32 MAX_PP_AA_ARRAY = 240;
static const uint32 MAX_PP_AA_ARRAY = 300;
static const uint32 MAX_GROUP_MEMBERS = 6;
static const uint32 MAX_RECAST_TYPES = 20;
-9
View File
@@ -2098,15 +2098,6 @@ namespace RoF
outapp->WriteUInt32(emu->aa_array[r].charges);
}
// Fill the other 60 AAs with zeroes
for (uint32 r = 0; r < structs::MAX_PP_AA_ARRAY - MAX_PP_AA_ARRAY; r++)
{
outapp->WriteUInt32(0);
outapp->WriteUInt32(0);
outapp->WriteUInt32(0);
}
outapp->WriteUInt32(structs::MAX_PP_SKILL);
for (uint32 r = 0; r < structs::MAX_PP_SKILL; r++)
-9
View File
@@ -2155,15 +2155,6 @@ namespace RoF2
outapp->WriteUInt32(emu->aa_array[r].charges);
}
// Fill the other 60 AAs with zeroes
for (uint32 r = 0; r < structs::MAX_PP_AA_ARRAY - MAX_PP_AA_ARRAY; r++)
{
outapp->WriteUInt32(0);
outapp->WriteUInt32(0);
outapp->WriteUInt32(0);
}
outapp->WriteUInt32(structs::MAX_PP_SKILL);
for (uint32 r = 0; r < structs::MAX_PP_SKILL; r++)
+1 -2
View File
@@ -1504,8 +1504,7 @@ namespace SoD
OUT(item_tint.Slot[r].Color);
}
// OUT(unknown00224[48]);
//NOTE: new client supports 300 AAs, our internal rep/PP
//only supports 240..
//NOTE: new client supports 300 AAs
for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA);
OUT(aa_array[r].value);
+1 -2
View File
@@ -1172,8 +1172,7 @@ namespace SoF
OUT(item_tint.Slot[r].Color);
}
// OUT(unknown00224[48]);
//NOTE: new client supports 300 AAs, our internal rep/PP
//only supports 240..
//NOTE: new client supports 300 AAs
for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA);
OUT(aa_array[r].value);
+1 -2
View File
@@ -1734,8 +1734,7 @@ namespace UF
OUT(item_tint.Slot[r].Color);
}
// OUT(unknown00224[48]);
//NOTE: new client supports 300 AAs, our internal rep/PP
//only supports 240..
//NOTE: new client supports 300 AAs
for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
eq->aa_array[r].AA = emu->aa_array[r].AA;
eq->aa_array[r].value = emu->aa_array[r].value;
+1
View File
@@ -167,6 +167,7 @@ RULE_BOOL(Character, EnableCharacterEXPMods, false, "Enables character zone-base
RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.")
RULE_BOOL(Character, SkillUpFromItems, true, "Allow Skill ups from clickable items")
RULE_BOOL(Character, EnableTestBuff, false, "Allow the use of /testbuff")
RULE_BOOL(Character, FixHPCalculationOverflow, true, "Fix the HP overflow bug in HP calcs, this is a client bug, if fixed and clients overflow their hp wont match the server's hp but the difference serverside can be significant so it's left as an option.")
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
+68
View File
@@ -37,6 +37,12 @@ Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
extern QueryServ* QServ;
namespace detail
{
static const uint32 PhantomStatId = 999999;
}
void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg, uint16 *eye_id) {
//It might not be a bad idea to put these into the database, eventually..
@@ -845,6 +851,8 @@ void Client::SendAlternateAdvancementTable() {
SendAlternateAdvancementRank(aa.first, 1);
}
}
SendPhantomStatsAlternateAdvancementRank();
}
void Client::SendAlternateAdvancementRank(int aa_id, int level) {
@@ -918,6 +926,54 @@ void Client::SendAlternateAdvancementRank(int aa_id, int level) {
safe_delete(outapp);
}
void Client::SendPhantomStatsAlternateAdvancementRank() {
//We only need to send phantom stats if stats are set to a custom value
if (RuleI(Character, StatCap) <= 0) {
return;
}
auto diff = RuleI(Character, StatCap) - GetMaxStat(false);
int size = sizeof(AARankInfo_Struct) + (sizeof(AARankEffect_Struct) * 7);
auto outapp = new EQApplicationPacket(OP_SendAATable, size);
AARankInfo_Struct *aai = (AARankInfo_Struct*)outapp->pBuffer;
aai->id = detail::PhantomStatId;
aai->upper_hotkey_sid = -1;
aai->lower_hotkey_sid = -1;
aai->title_sid = detail::PhantomStatId;
aai->desc_sid = detail::PhantomStatId;
aai->cost = 1;
aai->seq = detail::PhantomStatId;
aai->type = 3;
aai->spell = -1;
aai->spell_type = 0;
aai->spell_refresh = 0;
aai->classes = 16777215;
aai->level_req = 1;
aai->current_level = 2;
aai->max_level = 1;
aai->prev_id = -1;
aai->next_id = -1;
aai->total_cost = 1;
aai->expansion = 0;
aai->category = -1;
aai->charges = 0;
aai->grant_only = 1;
aai->total_effects = 7;
aai->total_prereqs = 0;
outapp->SetWritePosition(sizeof(AARankInfo_Struct));
for (int i = 0; i < 7; ++i) {
outapp->WriteSInt32(SE_RaiseStatCap);
outapp->WriteSInt32(diff);
outapp->WriteSInt32(i);
outapp->WriteSInt32(i + 1);
}
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::SendAlternateAdvancementStats() {
auto outapp = new EQApplicationPacket(OP_AAExpUpdate, sizeof(AltAdvStats_Struct));
AltAdvStats_Struct *aps = (AltAdvStats_Struct *)outapp->pBuffer;
@@ -933,7 +989,19 @@ void Client::SendAlternateAdvancementPoints() {
AATable_Struct* aa2 = (AATable_Struct *)outapp->pBuffer;
int i = 0;
if (RuleI(Character, StatCap) > 0)
{
aa2->aa_list[i].AA = detail::PhantomStatId;
aa2->aa_list[i].value = 1;
aa2->aa_list[i].charges = 0;
i++;
}
for(auto &aa : zone->aa_abilities) {
if (i >= MAX_PP_AA_ARRAY) {
continue;
}
uint32 charges = 0;
auto ranks = GetAA(aa.second->first_rank_id, &charges);
if(ranks) {
+1 -1
View File
@@ -760,7 +760,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
case SE_IncreaseRange:
break;
case SE_MaxHPChange:
newbon->MaxHP += base1;
newbon->MaxHPChange += base1;
break;
case SE_Packrat:
newbon->Packrat += base1;
+24 -16
View File
@@ -25,6 +25,7 @@
#include "lua_parser.h"
#include "../common/string_util.h"
#include "../common/say_link.h"
#include "../common/data_verification.h"
extern volatile bool is_zone_loaded;
@@ -7919,24 +7920,31 @@ uint32 Bot::GetClassHPFactor() {
}
int32 Bot::CalcMaxHP() {
int32 bot_hp = 0;
uint32 nd = 10000;
bot_hp += (GenerateBaseHitPoints() + itembonuses.HP);
nd += aabonuses.MaxHP;
bot_hp = ((float)bot_hp * (float)nd / (float)10000);
bot_hp += (spellbonuses.HP + aabonuses.HP);
bot_hp += GroupLeadershipAAHealthEnhancement();
bot_hp += (bot_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f));
max_hp = bot_hp;
if (current_hp > max_hp)
int64 base_hp = (GenerateBaseHitPoints() + itembonuses.HP);
int64 nd = aabonuses.MaxHPChange + spellbonuses.MaxHPChange + itembonuses.MaxHPChange;
int64 max_hp = (base_hp * nd / 10000) + base_hp;
max_hp += GroupLeadershipAAHealthEnhancement();
max_hp += 5;
max_hp += GetHeroicSTA() * 10;
max_hp += aabonuses.HP + spellbonuses.HP;
if (current_hp > max_hp) {
current_hp = max_hp;
int hp_perc_cap = spellbonuses.HPPercCap[0];
if(hp_perc_cap) {
int curHP_cap = ((max_hp * hp_perc_cap) / 100);
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1]))
current_hp = curHP_cap;
}
int hp_perc_cap = spellbonuses.HPPercCap[SBIndex::RESOURCE_PERCENT_CAP];
if (hp_perc_cap) {
int curHP_cap = (max_hp * hp_perc_cap) / 100;
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_hp > spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) {
current_hp = curHP_cap;
}
}
this->max_hp = static_cast<int32>(
EQ::Clamp(max_hp,
static_cast<int64>(0LL),
static_cast<int64>(std::numeric_limits<int32>::max()))
);
return max_hp;
}
+2 -1
View File
@@ -480,7 +480,7 @@ public:
inline virtual int32 GetCorrup() const { return Corrup; }
inline virtual int32 GetPhR() const { return PhR; }
int32 GetMaxStat() const;
int32 GetMaxStat(bool check_stat_cap) const;
int32 GetMaxResist() const;
int32 GetMaxSTR() const;
int32 GetMaxSTA() const;
@@ -858,6 +858,7 @@ public:
//New AA Methods
void SendAlternateAdvancementRank(int aa_id, int level);
void SendPhantomStatsAlternateAdvancementRank();
void SendAlternateAdvancementTable();
void SendAlternateAdvancementStats();
void PurchaseAlternateAdvancementRank(int rank_id);
+76 -44
View File
@@ -34,11 +34,12 @@
#include <algorithm>
int32 Client::GetMaxStat() const
int32 Client::GetMaxStat(bool check_stat_cap) const
{
if ((RuleI(Character, StatCap)) > 0) {
return (RuleI(Character, StatCap));
if (check_stat_cap && RuleI(Character, StatCap) > 0) {
return RuleI(Character, StatCap);
}
int level = GetLevel();
int32 base = 0;
if (level < 61) {
@@ -68,49 +69,49 @@ int32 Client::GetMaxResist() const
int32 Client::GetMaxSTR() const
{
return GetMaxStat()
return GetMaxStat(true)
+ itembonuses.STRCapMod
+ spellbonuses.STRCapMod
+ aabonuses.STRCapMod;
}
int32 Client::GetMaxSTA() const
{
return GetMaxStat()
return GetMaxStat(true)
+ itembonuses.STACapMod
+ spellbonuses.STACapMod
+ aabonuses.STACapMod;
}
int32 Client::GetMaxDEX() const
{
return GetMaxStat()
return GetMaxStat(true)
+ itembonuses.DEXCapMod
+ spellbonuses.DEXCapMod
+ aabonuses.DEXCapMod;
}
int32 Client::GetMaxAGI() const
{
return GetMaxStat()
return GetMaxStat(true)
+ itembonuses.AGICapMod
+ spellbonuses.AGICapMod
+ aabonuses.AGICapMod;
}
int32 Client::GetMaxINT() const
{
return GetMaxStat()
return GetMaxStat(true)
+ itembonuses.INTCapMod
+ spellbonuses.INTCapMod
+ aabonuses.INTCapMod;
}
int32 Client::GetMaxWIS() const
{
return GetMaxStat()
return GetMaxStat(true)
+ itembonuses.WISCapMod
+ spellbonuses.WISCapMod
+ aabonuses.WISCapMod;
}
int32 Client::GetMaxCHA() const
{
return GetMaxStat()
return GetMaxStat(true)
+ itembonuses.CHACapMod
+ spellbonuses.CHACapMod
+ aabonuses.CHACapMod;
@@ -314,30 +315,55 @@ int32 Client::CalcHPRegenCap()
int32 Client::CalcMaxHP()
{
float nd = 10000;
max_hp = (CalcBaseHP() + itembonuses.HP);
//The AA desc clearly says it only applies to base hp..
//but the actual effect sent on live causes the client
//to apply it to (basehp + itemhp).. I will oblige to the client's whims over
//the aa description
nd += aabonuses.MaxHP; //Natural Durability, Physical Enhancement, Planar Durability
max_hp = (float)max_hp * (float)nd / (float)10000; //this is to fix the HP-above-495k issue
max_hp += spellbonuses.HP + aabonuses.HP;
max_hp += GroupLeadershipAAHealthEnhancement();
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
if (current_hp > max_hp) {
current_hp = max_hp;
}
int hp_perc_cap = spellbonuses.HPPercCap[SBIndex::RESOURCE_PERCENT_CAP];
if (hp_perc_cap) {
int curHP_cap = (max_hp * hp_perc_cap) / 100;
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_hp > spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) {
current_hp = curHP_cap;
if(RuleB(Character, FixHPCalculationOverflow)) {
int64 base_hp = (CalcBaseHP() + itembonuses.HP);
int64 nd = aabonuses.MaxHPChange + spellbonuses.MaxHPChange + itembonuses.MaxHPChange;
int64 max_hp = (base_hp * nd / 10000) + base_hp;
max_hp += GroupLeadershipAAHealthEnhancement();
max_hp += 5;
max_hp += GetHeroicSTA() * 10;
max_hp += aabonuses.HP + spellbonuses.HP;
if (current_hp > max_hp) {
current_hp = max_hp;
}
}
int hp_perc_cap = spellbonuses.HPPercCap[SBIndex::RESOURCE_PERCENT_CAP];
if (hp_perc_cap) {
int curHP_cap = (max_hp * hp_perc_cap) / 100;
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_hp > spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) {
return max_hp;
current_hp = curHP_cap;
}
}
this->max_hp = static_cast<int32>(
EQ::Clamp(max_hp,
static_cast<int64>(0LL),
static_cast<int64>(std::numeric_limits<int32>::max()))
);
return max_hp;
} else {
int32 base_hp = (CalcBaseHP() + itembonuses.HP);
int32 nd = aabonuses.MaxHPChange + spellbonuses.MaxHPChange + itembonuses.MaxHPChange;
max_hp = (base_hp * nd / 10000) + base_hp;
max_hp += GroupLeadershipAAHealthEnhancement();
max_hp += 5;
max_hp += GetHeroicSTA() * 10;
max_hp += aabonuses.HP + spellbonuses.HP;
if (current_hp > max_hp) {
current_hp = max_hp;
}
int hp_perc_cap = spellbonuses.HPPercCap[SBIndex::RESOURCE_PERCENT_CAP];
if (hp_perc_cap) {
int curHP_cap = (max_hp * hp_perc_cap) / 100;
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_hp > spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) {
current_hp = curHP_cap;
}
}
return max_hp;
}
}
uint32 Mob::GetClassLevelFactor()
@@ -485,11 +511,10 @@ int32 Client::CalcBaseHP()
stats = (stats - 255) / 2;
stats += 255;
}
base_hp = 5;
base_hp = 0;
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 {
@@ -621,7 +646,7 @@ int32 Client::CalcBaseMana()
}
auto base_data = database.GetBaseData(GetLevel(), GetClass());
if (base_data) {
max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicINT() * 10);
max_m = base_data->base_mana + static_cast<int32>(ConvertedWisInt * base_data->mana_factor) + (GetHeroicINT() * 10);
}
}
else {
@@ -653,7 +678,7 @@ int32 Client::CalcBaseMana()
}
auto base_data = database.GetBaseData(GetLevel(), GetClass());
if (base_data) {
max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicWIS() * 10);
max_m = base_data->base_mana + static_cast<int32>(ConvertedWisInt * base_data->mana_factor) + (GetHeroicWIS() * 10);
}
}
else {
@@ -1610,6 +1635,12 @@ uint32 Mob::GetInstrumentMod(uint16 spell_id) const
void Client::CalcMaxEndurance()
{
max_end = CalcBaseEndurance() + spellbonuses.Endurance + itembonuses.Endurance + aabonuses.Endurance;
int32 heroic_stats = (GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4;
if (heroic_stats > 0) {
max_end += heroic_stats * 10;
}
if (max_end < 0) {
max_end = 0;
}
@@ -1629,17 +1660,18 @@ int32 Client::CalcBaseEndurance()
{
int32 base_end = 0;
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && 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;
int32 stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4;
if (stats > 100) {
if (stats > 200) {
stats -= (stats - 200) / 2;
}
stats += (3 * stats - 300) / 2;
}
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));
base_end = base_data->base_end + static_cast<int32>(base_data->endurance_factor * stats);
}
}
else {
-1
View File
@@ -339,7 +339,6 @@ struct StatBonuses {
int32 AC;
int32 HP;
int32 HPRegen;
int32 MaxHP;
int32 ManaRegen;
int32 EnduranceRegen;
int32 Mana;
+2 -2
View File
@@ -860,7 +860,7 @@ void Client::SetLevel(uint8 set_level, bool command)
}
QueuePacket(outapp);
safe_delete(outapp);
this->SendAppearancePacket(AT_WhoLevel, set_level); // who level change
SendAppearancePacket(AT_WhoLevel, set_level); // who level change
LogInfo("Setting Level for [{}] to [{}]", GetName(), set_level);
@@ -881,8 +881,8 @@ void Client::SetLevel(uint8 set_level, bool command)
SendHPUpdate();
SetMana(CalcMaxMana());
UpdateWho();
UpdateMercLevel();
SendPhantomStatsAlternateAdvancementRank();
Save();
}
-6
View File
@@ -20,11 +20,6 @@ int32 Lua_StatBonuses::GetHPRegen() const {
return self->HPRegen;
}
int32 Lua_StatBonuses::GetMaxHP() const {
Lua_Safe_Call_Int();
return self->MaxHP;
}
int32 Lua_StatBonuses::GetManaRegen() const {
Lua_Safe_Call_Int();
return self->ManaRegen;
@@ -1291,7 +1286,6 @@ luabind::scope lua_register_stat_bonuses() {
.def("AC", &Lua_StatBonuses::GetAC)
.def("HP", &Lua_StatBonuses::GetHP)
.def("HPRegen", &Lua_StatBonuses::GetHPRegen)
.def("MaxHP", &Lua_StatBonuses::GetMaxHP)
.def("ManaRegen", &Lua_StatBonuses::GetManaRegen)
.def("EnduranceRegen", &Lua_StatBonuses::GetEnduranceRegen)
.def("Mana", &Lua_StatBonuses::GetMana)
-1
View File
@@ -28,7 +28,6 @@ public:
int32 GetAC() const;
int32 GetHP() const;
int32 GetHPRegen() const;
int32 GetMaxHP() const;
int32 GetManaRegen() const;
int32 GetEnduranceRegen() const;
int32 GetMana() const;
+22 -22
View File
@@ -17,6 +17,7 @@
#include "../common/string_util.h"
#include "../common/rulesys.h"
#include "../common/data_verification.h"
extern volatile bool is_zone_loaded;
@@ -843,31 +844,30 @@ int32 Merc::CalcHPRegenCap()
}
int32 Merc::CalcMaxHP() {
float nd = 10000;
max_hp = (CalcBaseHP() + itembonuses.HP);
//The AA desc clearly says it only applies to base hp..
//but the actual effect sent on live causes the client
//to apply it to (basehp + itemhp).. I will oblige to the client's whims over
//the aa description
nd += aabonuses.MaxHP; //Natural Durability, Physical Enhancement, Planar Durability
max_hp = (float)max_hp * (float)nd / (float)10000; //this is to fix the HP-above-495k issue
max_hp += spellbonuses.HP + aabonuses.HP;
int64 base_hp = (CalcBaseHP() + itembonuses.HP);
int64 nd = aabonuses.MaxHPChange + spellbonuses.MaxHPChange + itembonuses.MaxHPChange;
int64 max_hp = (base_hp * nd / 10000) + base_hp;
max_hp += GroupLeadershipAAHealthEnhancement();
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
if (current_hp > max_hp)
max_hp += 5;
max_hp += GetHeroicSTA() * 10;
max_hp += aabonuses.HP + spellbonuses.HP;
if (current_hp > max_hp) {
current_hp = max_hp;
int hp_perc_cap = spellbonuses.HPPercCap[SBIndex::RESOURCE_PERCENT_CAP];
if(hp_perc_cap) {
int curHP_cap = (max_hp * hp_perc_cap) / 100;
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_hp > spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP]))
current_hp = curHP_cap;
}
int hp_perc_cap = spellbonuses.HPPercCap[SBIndex::RESOURCE_PERCENT_CAP];
if (hp_perc_cap) {
int curHP_cap = (max_hp * hp_perc_cap) / 100;
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_hp > spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) {
current_hp = curHP_cap;
}
}
this->max_hp = static_cast<int32>(
EQ::Clamp(max_hp,
static_cast<int64>(0LL),
static_cast<int64>(std::numeric_limits<int32>::max()))
);
return max_hp;
}