mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 14:41:28 +00:00
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)
This commit is contained in:
parent
c078257f70
commit
66cf4b546c
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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++)
|
||||
|
||||
@ -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++)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
96
zone/aa.cpp
96
zone/aa.cpp
@ -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,82 @@ 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));
|
||||
outapp->WriteSInt32(262);
|
||||
outapp->WriteSInt32(diff);
|
||||
outapp->WriteSInt32(0);
|
||||
outapp->WriteSInt32(1);
|
||||
|
||||
outapp->WriteSInt32(262);
|
||||
outapp->WriteSInt32(diff);
|
||||
outapp->WriteSInt32(1);
|
||||
outapp->WriteSInt32(2);
|
||||
|
||||
outapp->WriteSInt32(262);
|
||||
outapp->WriteSInt32(diff);
|
||||
outapp->WriteSInt32(2);
|
||||
outapp->WriteSInt32(3);
|
||||
|
||||
outapp->WriteSInt32(262);
|
||||
outapp->WriteSInt32(diff);
|
||||
outapp->WriteSInt32(3);
|
||||
outapp->WriteSInt32(4);
|
||||
|
||||
outapp->WriteSInt32(262);
|
||||
outapp->WriteSInt32(diff);
|
||||
outapp->WriteSInt32(4);
|
||||
outapp->WriteSInt32(5);
|
||||
|
||||
outapp->WriteSInt32(262);
|
||||
outapp->WriteSInt32(diff);
|
||||
outapp->WriteSInt32(5);
|
||||
outapp->WriteSInt32(6);
|
||||
|
||||
outapp->WriteSInt32(262);
|
||||
outapp->WriteSInt32(diff);
|
||||
outapp->WriteSInt32(6);
|
||||
outapp->WriteSInt32(7);
|
||||
|
||||
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 +1017,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 >= 300) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 charges = 0;
|
||||
auto ranks = GetAA(aa.second->first_rank_id, &charges);
|
||||
if(ranks) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,14 +315,16 @@ int32 Client::CalcHPRegenCap()
|
||||
|
||||
int32 Client::CalcMaxHP()
|
||||
{
|
||||
float nd = 10000;
|
||||
max_hp = (CalcBaseHP() + itembonuses.HP);
|
||||
int64 nd = 10000;
|
||||
int64 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 = max_hp * nd / 10000; //this is to fix the HP-above-495k issue
|
||||
max_hp += 5;
|
||||
max_hp += GetHeroicSTA() * 10;
|
||||
max_hp += spellbonuses.HP + aabonuses.HP;
|
||||
max_hp += GroupLeadershipAAHealthEnhancement();
|
||||
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
|
||||
@ -337,7 +340,8 @@ int32 Client::CalcMaxHP()
|
||||
}
|
||||
}
|
||||
|
||||
return max_hp;
|
||||
this->max_hp = std::min(max_hp, 2147483647LL);
|
||||
return this->max_hp;
|
||||
}
|
||||
|
||||
uint32 Mob::GetClassLevelFactor()
|
||||
@ -485,11 +489,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 +624,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 +656,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 +1613,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 +1638,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 {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user