diff --git a/common/classes.cpp b/common/classes.cpp index 693b826b1..95b13bc7d 100644 --- a/common/classes.cpp +++ b/common/classes.cpp @@ -17,6 +17,7 @@ */ #include "../common/global_define.h" #include "../common/classes.h" +#include "data_verification.h" const char *GetClassIDName(uint8 class_id, uint8 level) { @@ -750,3 +751,51 @@ uint8 ClassArmorType(uint8 class_id) return ARMOR_TYPE_UNKNOWN; } } + +const std::string GetPlayerClassAbbreviation(uint8 class_id) +{ + if (!EQ::ValueWithin(class_id, WARRIOR, BERSERKER)) { + return std::string(); + } + + switch (class_id) { + case WARRIOR: + return "WAR"; + case CLERIC: + return "CLR"; + case PALADIN: + return "PAL"; + case RANGER: + return "RNG"; + case SHADOWKNIGHT: + return "SHD"; + case DRUID: + return "DRU"; + case MONK: + return "MNK"; + case BARD: + return "BRD"; + case ROGUE: + return "ROG"; + case SHAMAN: + return "SHM"; + case NECROMANCER: + return "NEC"; + case WIZARD: + return "WIZ"; + case MAGICIAN: + return "MAG"; + case ENCHANTER: + return "ENC"; + case BEASTLORD: + return "BST"; + case BERSERKER: + return "BER"; + } + + return std::string(); +} + +bool IsPlayerClass(uint8 class_id) { + return EQ::ValueWithin(class_id, WARRIOR, BERSERKER); +} diff --git a/common/classes.h b/common/classes.h index df5dedcd7..a9cc7d9fc 100644 --- a/common/classes.h +++ b/common/classes.h @@ -19,6 +19,7 @@ #define CLASSES_CH #include "../common/types.h" +#include #define NO_CLASS 0 #define WARRIOR 1 @@ -127,6 +128,9 @@ const char* GetClassIDName(uint8 class_id, uint8 level = 0); const char* GetPlayerClassName(uint32 player_class_value, uint8 level = 0); +bool IsPlayerClass(uint8 class_id); +const std::string GetPlayerClassAbbreviation(uint8 class_id); + uint32 GetPlayerClassValue(uint8 class_id); uint32 GetPlayerClassBit(uint8 class_id); diff --git a/common/races.cpp b/common/races.cpp index bb7cce9c0..b6106aa09 100644 --- a/common/races.cpp +++ b/common/races.cpp @@ -17,6 +17,7 @@ */ #include "../common/races.h" +#include "data_verification.h" const char* GetRaceIDName(uint16 race_id) { @@ -67,7 +68,7 @@ const char* GetRaceIDName(uint16 race_id) // return "Froglok"; //case DRAKKIN: // return "Drakkin"; - + // RoF2 Race Labels case RT_ABHORRENT: return "Abhorrent"; @@ -1696,7 +1697,7 @@ bool PlayerAppearance::IsValidBeardColor(uint16 race_id, uint8 gender_id, uint8 { if (beard_color_value == 0xFF) return true; - + switch (BINDRG(race_id, gender_id)) { case GNOME_MALE: if (beard_color_value <= 24) @@ -1783,7 +1784,7 @@ bool PlayerAppearance::IsValidEyeColor(uint16 race_id, uint8 gender_id, uint8 ey case VAHSHIR_FEMALE: if (eye_color_value <= 9) return true; - break; + break; case TROLL_MALE: case TROLL_FEMALE: if (eye_color_value <= 10) @@ -2109,7 +2110,7 @@ bool PlayerAppearance::IsValidTexture(uint16 race_id, uint8 gender_id, uint8 tex { if (texture_value == 0xFF) return true; - + if (use_luclin) { switch (BINDRG(race_id, gender_id)) { case HUMAN_MALE: @@ -2243,4 +2244,58 @@ const char* GetGenderName(uint32 gender_id) { gender_name = "Neuter"; } return gender_name; -} \ No newline at end of file +} + +const std::string GetPlayerRaceAbbreviation(uint16 race_id) +{ + if (!IsPlayerRace(race_id)) { + return std::string(); + } + + switch (race_id) { + case RACE_HUMAN_1: + return "HUM"; + case RACE_BARBARIAN_2: + return "BAR"; + case RACE_ERUDITE_3: + return "ERU"; + case RACE_WOOD_ELF_4: + return "ELF"; + case RACE_HIGH_ELF_5: + return "HIE"; + case RACE_DARK_ELF_6: + return "DEF"; + case RACE_HALF_ELF_7: + return "HEF"; + case RACE_DWARF_8: + return "DWF"; + case RACE_TROLL_9: + return "TRL"; + case RACE_OGRE_10: + return "OGR"; + case RACE_HALFLING_11: + return "HFL"; + case RACE_GNOME_12: + return "GNM"; + case RACE_IKSAR_128: + return "IKS"; + case RACE_VAH_SHIR_130: + return "VAH"; + case RACE_FROGLOK_330: + return "FRG"; + case RACE_DRAKKIN_522: + return "DRK"; + } + + return std::string(); +} + +bool IsPlayerRace(uint16 race_id) { + return ( + EQ::ValueWithin(race_id, RACE_HUMAN_1, RACE_GNOME_12) || + race_id == RACE_IKSAR_128 || + race_id == RACE_VAH_SHIR_130 || + race_id == RACE_FROGLOK_330 || + race_id == RACE_DRAKKIN_522 + ); +} diff --git a/common/races.h b/common/races.h index 3373c8353..3ec25e4f9 100644 --- a/common/races.h +++ b/common/races.h @@ -19,6 +19,7 @@ #ifndef RACES_H #define RACES_H #include "../common/types.h" +#include #define MALE 0 #define FEMALE 1 @@ -853,6 +854,9 @@ const char* GetRaceIDName(uint16 race_id); const char* GetPlayerRaceName(uint32 player_race_value); const char* GetGenderName(uint32 gender_id); +bool IsPlayerRace(uint16 race_id); +const std::string GetPlayerRaceAbbreviation(uint16 race_id); + uint32 GetPlayerRaceValue(uint16 race_id); uint32 GetPlayerRaceBit(uint16 race_id); diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 79ad9e064..e0989f4f1 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -5316,7 +5316,7 @@ void bot_command_view_combos(Client *c, const Seperator *sep) const uint16 bot_race = static_cast(Strings::ToUnsignedInt(sep->arg[1])); const std::string race_name = GetRaceIDName(bot_race); - if (!Mob::IsPlayerRace(bot_race)) { + if (!IsPlayerRace(bot_race)) { c->Message( Chat::White, fmt::format( @@ -8900,7 +8900,7 @@ uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_clas return bot_id; } - if (!Bot::IsValidRaceClassCombo(bot_race, bot_class) && bot_owner->IsPlayerRace(bot_race)) { + if (!Bot::IsValidRaceClassCombo(bot_race, bot_class) && IsPlayerRace(bot_race)) { const std::string bot_race_name = GetRaceIDName(bot_race); const std::string bot_class_name = GetClassIDName(bot_class); const auto view_saylink = Saylink::Silent( diff --git a/zone/client.cpp b/zone/client.cpp index be557ff09..3168ce379 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -3958,32 +3958,32 @@ void Client::SendFullPopup( } void Client::SendWindow( - uint32 PopupID, - uint32 NegativeID, - uint32 Buttons, - const char *ButtonName0, - const char *ButtonName1, - uint32 Duration, + uint32 button_one_id, + uint32 button_two_id, + uint32 button_type, + const char* button_one_text, + const char* button_two_text, + uint32 duration, int title_type, - Client *target, - const char *Title, - const char *Text, + Mob* target, + const char* title, + const char* text, ... ) { va_list argptr; char buffer[4096]; - va_start(argptr, Text); - vsnprintf(buffer, sizeof(buffer), Text, argptr); + va_start(argptr, text); + vsnprintf(buffer, sizeof(buffer), text, argptr); va_end(argptr); size_t len = strlen(buffer); - auto app = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct)); - OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *) app->pBuffer; + auto app = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct)); + auto* olms = (OnLevelMessage_Struct *) app->pBuffer; - if (strlen(Text) > (sizeof(olms->Text) - 1)) { + if (strlen(text) > (sizeof(olms->Text) - 1)) { safe_delete(app); return; } @@ -3996,47 +3996,47 @@ void Client::SendWindow( case 1: { char name[64] = ""; strcpy(name, target->GetName()); + if (strlen(target->GetLastName()) > 0) { char last_name[64] = ""; strcpy(last_name, target->GetLastName()); strcat(name, " "); strcat(name, last_name); } + strcpy(olms->Title, name); break; } case 2: { - if (target->GuildID()) { - char *guild_name = (char *) guild_mgr.GetGuildName(target->GuildID()); - strcpy(olms->Title, guild_name); - } - else { + if (target->IsClient() && target->CastToClient()->GuildID()) { + auto guild_name = guild_mgr.GetGuildName(target->CastToClient()->GuildID()); + strn0cpy(olms->Title, guild_name, sizeof(olms->Title)); + } else { strcpy(olms->Title, "No Guild"); } break; } default: { - strcpy(olms->Title, Title); + strcpy(olms->Title, title); break; } } memcpy(olms->Text, buffer, len + 1); - olms->Buttons = Buttons; + olms->Buttons = button_type; - sprintf(olms->ButtonName0, "%s", ButtonName0); - sprintf(olms->ButtonName1, "%s", ButtonName1); + strn0cpy(olms->ButtonName0, button_one_text, sizeof(olms->ButtonName0)); + strn0cpy(olms->ButtonName1, button_two_text, sizeof(olms->ButtonName1)); - if (Duration > 0) { - olms->Duration = Duration * 1000; - } - else { - olms->Duration = 0xffffffff; + if (duration > 0) { + olms->Duration = duration * 1000; + } else { + olms->Duration = UINT32_MAX; } - olms->PopupID = PopupID; - olms->NegativeID = NegativeID; + olms->PopupID = button_one_id; + olms->NegativeID = button_two_id; FastQueuePacket(&app); } @@ -6365,544 +6365,6 @@ void Client::RemoveFromInstance(uint16 instance_id) database.RemoveClientFromInstance(instance_id, CharacterID()); } -void Client::SendStatsWindow(Client* client, bool use_window) -{ - // Define the types of page breaks we need - std::string indP = " "; - std::string indS = "          "; - std::string indM = "                          "; - std::string indL = "                                 "; - std::string div = " | "; - - std::string color_red = ""; - std::string color_blue = ""; - std::string color_green = ""; - std::string bright_green = ""; - std::string bright_red = ""; - std::string heroic_color = " +"; - - // Set Class - std::string class_Name = itoa(GetClass()); - std::string class_List[] = { "WAR", "CLR", "PAL", "RNG", "SHD", "DRU", "MNK", "BRD", "ROG", "SHM", "NEC", "WIZ", "MAG", "ENC", "BST", "BER" }; - - if (GetClass() < 17 && GetClass() > 0) { - class_Name = class_List[GetClass() - 1]; - } - - // Race - std::string race_name = GetRaceIDName(GetRace()); - - /*########################################################## - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - H/M/E String - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ##########################################################*/ - std::string HME_row = ""; - //Loop Variables - /*===========================*/ - std::string cur_field = ""; - std::string total_field = ""; - std::string cur_name = ""; - std::string cur_spacing = ""; - std::string cur_color = ""; - - int hme_rows = 3; // Rows in display - int max_HME_value_len = 9; // 9 digits in the displayed value - - for(int hme_row_counter = 0; hme_row_counter < hme_rows; hme_row_counter++) - { - switch(hme_row_counter) { - case 0: { - cur_name = " H: "; - cur_field = itoa(GetHP()); - total_field = itoa(GetMaxHP()); - break; - } - case 1: { - if(CalcMaxMana() > 0) { - cur_name = " M: "; - cur_field = itoa(GetMana()); - total_field = itoa(GetMaxMana()); - } - else { continue; } - - break; - } - case 2: { - cur_name = " E: "; - cur_field = itoa(GetEndurance()); - total_field = itoa(GetMaxEndurance()); - break; - } - default: { break; } - } - if(cur_field.compare(total_field) == 0) { cur_color = bright_green; } - else { cur_color = bright_red; } - - cur_spacing.clear(); - for(int a = cur_field.size(); a < max_HME_value_len; a++) { cur_spacing += " ."; } - - HME_row += indM + cur_name + cur_spacing + cur_color + cur_field + " / " + total_field + "
"; - } - /*########################################################## - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Regen String - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ##########################################################*/ - std::string regen_string; - //Loop Variables - /*===========================*/ - std::string regen_row_header = ""; - std::string regen_row_color = ""; - std::string base_regen_field = ""; - std::string base_regen_spacing = ""; - std::string item_regen_field = ""; - std::string item_regen_spacing = ""; - std::string cap_regen_field = ""; - std::string cap_regen_spacing = ""; - std::string spell_regen_field = ""; - std::string spell_regen_spacing = ""; - std::string aa_regen_field = ""; - std::string aa_regen_spacing = ""; - std::string total_regen_field = ""; - int regen_rows = 3; // Number of rows - int max_regen_value_len = 5; // 5 digits in the displayed value(larger values will not get cut off, this is just a baseline) - - for(int regen_row_counter = 0; regen_row_counter < regen_rows; regen_row_counter++) - { - switch(regen_row_counter) - { - case 0: { - regen_row_header = "H: "; - regen_row_color = color_red; - - base_regen_field = itoa(LevelRegen()); - item_regen_field = itoa(itembonuses.HPRegen + itembonuses.heroic_hp_regen); - cap_regen_field = itoa(CalcHPRegenCap()); - spell_regen_field = itoa(spellbonuses.HPRegen); - aa_regen_field = itoa(aabonuses.HPRegen); - total_regen_field = itoa(CalcHPRegen(true)); - break; - } - case 1: { - if(GetMaxMana() > 0) { - regen_row_header = "M: "; - regen_row_color = color_blue; - - base_regen_field = itoa(CalcBaseManaRegen()); - int32 heroic_mana_regen = itembonuses.heroic_mana_regen; - item_regen_field = itoa(itembonuses.ManaRegen + heroic_mana_regen); - cap_regen_field = itoa(CalcManaRegenCap()); - spell_regen_field = itoa(spellbonuses.ManaRegen); - aa_regen_field = itoa(aabonuses.ManaRegen); - total_regen_field = itoa(CalcManaRegen(true)); - } - else { continue; } - break; - } - case 2: { - regen_row_header = "E: "; - regen_row_color = color_green; - - base_regen_field = itoa(((GetLevel() * 4 / 10) + 2)); - item_regen_field = itoa(itembonuses.EnduranceRegen + itembonuses.heroic_end_regen); - cap_regen_field = itoa(CalcEnduranceRegenCap()); - spell_regen_field = itoa(spellbonuses.EnduranceRegen); - aa_regen_field = itoa(aabonuses.EnduranceRegen); - total_regen_field = itoa(CalcEnduranceRegen(true)); - break; - } - default: { break; } - } - - base_regen_spacing.clear(); - item_regen_spacing.clear(); - cap_regen_spacing.clear(); - spell_regen_spacing.clear(); - aa_regen_spacing.clear(); - - for(int b = base_regen_field.size(); b < max_regen_value_len; b++) { base_regen_spacing += " ."; } - for(int b = item_regen_field.size(); b < max_regen_value_len; b++) { item_regen_spacing += " ."; } - for(int b = cap_regen_field.size(); b < max_regen_value_len; b++) { cap_regen_spacing += " ."; } - for(int b = spell_regen_field.size(); b < max_regen_value_len; b++) { spell_regen_spacing += " ."; } - for(int b = aa_regen_field.size(); b < max_regen_value_len; b++) { aa_regen_spacing += " ."; } - - regen_string += indS + regen_row_color + regen_row_header + base_regen_spacing + base_regen_field; - regen_string += div + item_regen_spacing + item_regen_field + " (" + cap_regen_field; - regen_string += ") " + cap_regen_spacing + div + spell_regen_spacing + spell_regen_field; - regen_string += div + aa_regen_spacing + aa_regen_field + div + total_regen_field + "

"; - } - /*########################################################## - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Stat String - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ##########################################################*/ - std::string stat_field = ""; - //Loop Variables - /*===========================*/ - //first field(stat) - std::string a_stat = "";; - std::string a_stat_name = ""; - std::string a_stat_spacing = ""; - //second field(heroic stat) - std::string h_stat = ""; - std::string h_stat_spacing = ""; - //third field(resist) - std::string a_resist = ""; - std::string a_resist_name = ""; - std::string a_resist_spacing = ""; - //fourth field(heroic resist) - std::string h_resist_field = ""; - - int stat_rows = 7; // Number of rows - int max_stat_value_len = 3; // 3 digits in the displayed value - - for(int stat_row_counter = 0; stat_row_counter < stat_rows; stat_row_counter++) - { - switch(stat_row_counter) { - case 0: { - a_stat_name = " STR: "; - a_resist_name = "MR: "; - a_stat = itoa(GetSTR()); - h_stat = itoa(GetHeroicSTR()); - a_resist = itoa(GetMR()); - h_resist_field = itoa(GetHeroicMR()); - break; - } - case 1: { - a_stat_name = " STA: "; - a_resist_name = "CR: "; - a_stat = itoa(GetSTA()); - h_stat = itoa(GetHeroicSTA()); - a_resist = itoa(GetCR()); - h_resist_field = itoa(GetHeroicCR()); - break; - } - case 2: { - a_stat_name = " AGI : "; - a_resist_name = "FR: "; - a_stat = itoa(GetAGI()); - h_stat = itoa(GetHeroicAGI()); - a_resist = itoa(GetFR()); - h_resist_field = itoa(GetHeroicFR()); - break; - } - case 3: { - a_stat_name = " DEX: "; - a_resist_name = "PR: "; - a_stat = itoa(GetDEX()); - h_stat = itoa(GetHeroicDEX()); - a_resist = itoa(GetPR()); - h_resist_field = itoa(GetHeroicPR()); - break; - } - case 4: { - a_stat_name = " INT : "; - a_resist_name = "DR: "; - a_stat = itoa(GetINT()); - h_stat = itoa(GetHeroicINT()); - a_resist = itoa(GetDR()); - h_resist_field = itoa(GetHeroicDR()); - break; - } - case 5: { - a_stat_name = " WIS: "; - a_resist_name = "Cp: "; - a_stat = itoa(GetWIS()); - h_stat = itoa(GetHeroicWIS()); - a_resist = itoa(GetCorrup()); - h_resist_field = itoa(GetHeroicCorrup()); - break; - } - case 6: { - a_stat_name = " CHA: "; - a_resist_name = "PhR: "; // Not implemented for clients yet - a_stat = itoa(GetCHA()); - h_stat = itoa(GetHeroicCHA()); - a_resist = itoa(GetPhR()); - h_resist_field = itoa(GetHeroicPhR()); - break; - } - default: { break; } - } - - a_stat_spacing.clear(); - h_stat_spacing.clear(); - a_resist_spacing.clear(); - - for(int a = a_stat.size(); a < max_stat_value_len; a++) { a_stat_spacing += " . "; } - for(int h = h_stat.size(); h < 20; h++) { h_stat_spacing += " . "; } - for(int h = a_resist.size(); h < max_stat_value_len; h++) { a_resist_spacing += " . "; } - - stat_field += indP + a_stat_name + a_stat_spacing + a_stat + heroic_color + h_stat + "
"; - stat_field += h_stat_spacing + a_resist_name + a_resist_spacing + a_resist + heroic_color + h_resist_field + "
"; - if(stat_row_counter < 6) { - stat_field += "
"; - } - } - /*########################################################## - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Mod2 String - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ##########################################################*/ - std::string mod2_field = ""; - //Loop Variables - /*===========================*/ - std::string mod2a = ""; - std::string mod2a_name = ""; - std::string mod2a_spacing = ""; - std::string mod2a_cap = ""; - std::string mod_row_spacing = ""; - std::string mod2b = ""; - std::string mod2b_name = ""; - std::string mod2b_spacing = ""; - std::string mod2b_cap = ""; - int mod2a_space_count; - int mod2b_space_count; - - int mod2_rows = 4; - int max_mod2_value_len = 3; // 3 digits in the displayed value - - for(int mod2_row_counter = 0; mod2_row_counter < mod2_rows; mod2_row_counter++) - { - switch (mod2_row_counter) - { - case 0: { - mod2a_name = "Avoidance: "; - mod2b_name = "Combat Effects: "; - mod2a = itoa(GetAvoidance()); - mod2a_cap = itoa(RuleI(Character, ItemAvoidanceCap)); - mod2b = itoa(GetCombatEffects()); - mod2b_cap = itoa(RuleI(Character, ItemCombatEffectsCap)); - mod2a_space_count = 2; - mod2b_space_count = 0; - break; - } - case 1: { - mod2a_name = "Accuracy: "; - mod2b_name = "Strike Through: "; - mod2a = itoa(GetAccuracy()); - mod2a_cap = itoa(RuleI(Character, ItemAccuracyCap)); - mod2b = itoa(GetStrikeThrough()); - mod2b_cap = itoa(RuleI(Character, ItemStrikethroughCap)); - mod2a_space_count = 3; - mod2b_space_count = 1; - break; - } - case 2: { - mod2a_name = "Shielding: "; - mod2b_name = "Spell Shielding: "; - mod2a = itoa(GetShielding()); - mod2a_cap = itoa(RuleI(Character, ItemShieldingCap)); - mod2b = itoa(GetSpellShield()); - mod2b_cap = itoa(RuleI(Character, ItemSpellShieldingCap)); - mod2a_space_count = 2; - mod2b_space_count = 1; - break; - } - case 3: { - mod2a_name = "Stun Resist: "; - mod2b_name = "DoT Shielding: "; - mod2a = itoa(GetStunResist()); - mod2a_cap = itoa(RuleI(Character, ItemStunResistCap)); - mod2b = itoa(GetDoTShield()); - mod2b_cap = itoa(RuleI(Character, ItemDoTShieldingCap)); - mod2a_space_count = 0; - mod2b_space_count = 2; - break; - } - } - - mod2a_spacing.clear(); - mod_row_spacing.clear(); - mod2b_spacing.clear(); - - for(int a = mod2a.size(); a < (max_mod2_value_len + mod2a_space_count); a++) { mod2a_spacing += " . "; } - for(int a = mod2a_cap.size(); a < 6 ; a++) { mod_row_spacing += " . "; } - for(int a = mod2b.size(); a < (max_mod2_value_len + mod2b_space_count); a++) { mod2b_spacing += " . "; } - - mod2_field += indP + mod2a_name + mod2a_spacing + mod2a + " / " + mod2a_cap + mod_row_spacing; - mod2_field += mod2b_name + mod2b_spacing + mod2b + " / " + mod2b_cap + "
"; - } - - uint32 rune_number = 0; - uint32 magic_rune_number = 0; - uint32 buff_count = GetMaxTotalSlots(); - for (int i=0; i < buff_count; i++) { - if (IsValidSpell(buffs[i].spellid)) { - if (buffs[i].melee_rune > 0) { rune_number += buffs[i].melee_rune; } - - if (buffs[i].magic_rune > 0) { magic_rune_number += buffs[i].magic_rune; } - } - } - - int shield_ac = 0; - GetRawACNoShield(shield_ac); - - std::string skill_list[] = { - "1H Blunt","1H Slashing","2H Blunt","2H Slashing","Abjuration", - "Alteration","Apply Poison","Archery","Backstab","Bind Wound", - "Bash","Block","Brass Instruments","Channeling","Conjuration", - "Defense","Disarm","Disarm Traps","Divination","Dodge", - "Double Attack","Dragon Punch","Dual Wield","Eagle Strike","Evocation", - "Feign Death","Flying Kick","Forage","Hand To Hand","Hide", - "Kick","Meditate","Mend","Offense","Parry", - "Pick Lock","1H Piercing","Riposte","Round Kick","Safe Fall", - "Sense Heading","Singing","Sneak","Specialize Abjuration","Specialize Alteration", - "Specialize Conjuration","Specialize Divination","Specialize Evocation","Pick Pockets","Stringed Instruments", - "Swimming","Throwing","Tiger Claw","Tracking","Wind Instruments", - "Fishing","Make Poison","Tinkering","Research","Alchemy", - "Baking","Tailoring","Sense Traps","Blacksmithing","Fletching", - "Brewing","Alcohol_Tolerance","Begging","Jewelry Making","Pottery", - "Percussion Instruments","Intimidation","Berserking","Taunt","Frenzy", - "Remove Traps","Triple Attack","2H Piercing" - }; - - std::string skill_mods = ""; - for (int j = 0; j <= EQ::skills::HIGHEST_SKILL; j++) { - if(itembonuses.skillmod[j] > 0) - skill_mods += indP + skill_list[j] + " : +" + itoa(itembonuses.skillmod[j]) + "%
"; - else if(itembonuses.skillmod[j] < 0) - skill_mods += indP + skill_list[j] + " : -" + itoa(itembonuses.skillmod[j]) + "%
"; - } - - std::string skill_dmgs = ""; - for (int j = 0; j <= EQ::skills::HIGHEST_SKILL; j++) { - if((itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) > 0) - skill_dmgs += indP + skill_list[j] + " : +" + itoa(itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) + "
"; - else if((itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) < 0) - skill_dmgs += indP + skill_list[j] + " : -" + itoa(itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) + "
"; - } - - std::string faction_item_string = ""; - char faction_buf[256]; - - for (auto iter = item_faction_bonuses.begin(); iter != item_faction_bonuses.end(); ++iter) { - memset(&faction_buf, 0, sizeof(faction_buf)); - - if(!content_db.GetFactionName((int)((*iter).first), faction_buf, sizeof(faction_buf))) - strcpy(faction_buf, "Not in DB"); - - if((*iter).second > 0) { - faction_item_string += indP + faction_buf + " : +" + itoa((*iter).second) + "
"; - } - else if((*iter).second < 0) { - faction_item_string += indP + faction_buf + " : -" + itoa((*iter).second) + "
"; - } - } - - std::string bard_info = ""; - if(GetClass() == BARD) { - bard_info = indP + "Singing: " + itoa(GetSingMod()) + "
" + - indP + "Brass: " + itoa(GetBrassMod()) + "
" + - indP + "String: " + itoa(GetStringMod()) + "
" + - indP + "Percussion: " + itoa(GetPercMod()) + "
" + - indP + "Wind: " + itoa(GetWindMod()) + "
"; - } - - EQ::skills::SkillType skill = EQ::skills::SkillHandtoHand; - auto *inst = GetInv().GetItem(EQ::invslot::slotPrimary); - if (inst && inst->IsClassCommon()) { - switch (inst->GetItem()->ItemType) { - case EQ::item::ItemType1HSlash: - skill = EQ::skills::Skill1HSlashing; - break; - case EQ::item::ItemType2HSlash: - skill = EQ::skills::Skill2HSlashing; - break; - case EQ::item::ItemType1HPiercing: - skill = EQ::skills::Skill1HPiercing; - break; - case EQ::item::ItemType1HBlunt: - skill = EQ::skills::Skill1HBlunt; - break; - case EQ::item::ItemType2HBlunt: - skill = EQ::skills::Skill2HBlunt; - break; - case EQ::item::ItemType2HPiercing: - if (ClientVersion() < EQ::versions::ClientVersion::RoF2) - skill = EQ::skills::Skill1HPiercing; - else - skill = EQ::skills::Skill2HPiercing; - break; - default: - break; - } - } - - std::ostringstream final_string; - final_string << - /* C/L/R */ indP << "Class: " << class_Name << indS << "Level: " << static_cast(GetLevel()) << indS << "Race: " << race_name << "
" << - /* Runes */ indP << "Rune: " << rune_number << indL << indS << "Spell Rune: " << magic_rune_number << "
" << - /* HP/M/E */ HME_row << - /* DS */ indP << "DS: " << (itembonuses.DamageShield + spellbonuses.DamageShield*-1) << " (Spell: " << (spellbonuses.DamageShield*-1) << " + Item: " << itembonuses.DamageShield << " / " << RuleI(Character, ItemDamageShieldCap) << ")
" << - /* Atk */ indP << "tohit: " << compute_tohit(skill) << " / " << GetTotalToHit(skill, 0) << "
" << - /* Atk2 */ indP << "- Offense: " << offense(skill) << " | Item: " << itembonuses.ATK << " (" << RuleI(Character, ItemATKCap) << ")~Used: " << (itembonuses.ATK * 1.342) << " | Spell: " << spellbonuses.ATK << "
" << - /* AC */ indP << "mitigation AC: " << GetMitigationAC() << "
" << - /* AC2 */ indP << "- defense: " << compute_defense() << " / " << GetTotalDefense() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "
" << - /* Haste */ indP << "Haste: " << GetHaste() << "
" << - /* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "
" << - /* RunSpeed*/ indP << "Runspeed: " << GetRunspeed() << "
" << - /* RegenLbl */ indL << indS << "Regen
" << indS << indP << indP << " Base | Items (Cap) " << indP << " | Spell | A.A.s | Total
" << - /* Regen */ regen_string << "
" << - /* Stats */ stat_field << "

" << - /* Mod2s */ mod2_field << "
" << - /* HealAmt */ indP << "Heal Amount: " << GetHealAmt() << " / " << RuleI(Character, ItemHealAmtCap) << "
" << - /* SpellDmg*/ indP << "Spell Dmg: " << GetSpellDmg() << " / " << RuleI(Character, ItemSpellDmgCap) << "
" << - /* Clair */ indP << "Clairvoyance: " << GetClair() << " / " << RuleI(Character, ItemClairvoyanceCap) << "
" << - /* DSMit */ indP << "Dmg Shld Mit: " << GetDSMit() << " / " << RuleI(Character, ItemDSMitigationCap) << "

"; - if(GetClass() == BARD) - final_string << bard_info << "
"; - if(skill_mods.size() > 0) - final_string << skill_mods << "
"; - if(skill_dmgs.size() > 0) - final_string << skill_dmgs << "
"; - if(faction_item_string.size() > 0) - final_string << faction_item_string; - - std::string final_stats = final_string.str(); - - if(use_window) { - if(final_stats.size() < 4096) - { - uint32 Buttons = (client->ClientVersion() < EQ::versions::ClientVersion::SoD) ? 0 : 1; - client->SendWindow(0, POPUPID_UPDATE_SHOWSTATSWINDOW, Buttons, "Cancel", "Update", 0, 1, this, "", "%s", final_stats.c_str()); - goto Extra_Info; - } - else { - client->Message(Chat::Yellow, "The window has exceeded its character limit, displaying stats to chat window:"); - } - } - - client->Message(Chat::Yellow, "~~~~~ %s %s ~~~~~", GetCleanName(), GetLastName()); - client->Message(Chat::White, " Level: %i Class: %i Race: %i DS: %i/%i Size: %1.1f Weight: %.1f/%d ", GetLevel(), GetClass(), GetRace(), GetDS(), RuleI(Character, ItemDamageShieldCap), GetSize(), (float)CalcCurrentWeight() / 10.0f, GetSTR()); - client->Message(Chat::White, " HP: %i/%i HP Regen: %i/%i",GetHP(), GetMaxHP(), CalcHPRegen(), CalcHPRegenCap()); - client->Message(Chat::White, " compute_tohit: %i TotalToHit: %i", compute_tohit(skill), GetTotalToHit(skill, 0)); - client->Message(Chat::White, " compute_defense: %i TotalDefense: %i", compute_defense(), GetTotalDefense()); - client->Message(Chat::White, " offense: %i mitigation ac: %i", offense(skill), GetMitigationAC()); - client->Message(Chat::White, " AFK: %i LFG: %i Anon: %i PVP: %i GM: %i Flymode: %i GMSpeed: %i Hideme: %i GMInvul: %d LD: %i ClientVersion: %i TellsOff: %i", AFK, LFG, GetAnon(), GetPVP(), GetGM(), flymode, GetGMSpeed(), GetHideMe(), GetGMInvul(), IsLD(), ClientVersionBit(), tellsoff); - if(CalcMaxMana() > 0) - client->Message(Chat::White, " Mana: %i/%i Mana Regen: %i/%i", GetMana(), GetMaxMana(), CalcManaRegen(), CalcManaRegenCap()); - client->Message(Chat::White, " End.: %i/%i End. Regen: %i/%i",GetEndurance(), GetMaxEndurance(), CalcEnduranceRegen(), CalcEnduranceRegenCap()); - client->Message(Chat::White, " ATK: %i Worn/Spell ATK %i/%i Server Side ATK: %i", GetTotalATK(), RuleI(Character, ItemATKCap), GetATKBonus(), GetATK()); - client->Message(Chat::White, " Haste: %i / %i (Item: %i + Spell: %i + Over: %i) Run speed: %i", GetHaste(), RuleI(Character, HasteCap), itembonuses.haste, spellbonuses.haste + spellbonuses.hastetype2, spellbonuses.hastetype3 + ExtraHaste, GetRunspeed()); - client->Message(Chat::White, " STR: %i STA: %i DEX: %i AGI: %i INT: %i WIS: %i CHA: %i", GetSTR(), GetSTA(), GetDEX(), GetAGI(), GetINT(), GetWIS(), GetCHA()); - client->Message(Chat::White, " hSTR: %i hSTA: %i hDEX: %i hAGI: %i hINT: %i hWIS: %i hCHA: %i", GetHeroicSTR(), GetHeroicSTA(), GetHeroicDEX(), GetHeroicAGI(), GetHeroicINT(), GetHeroicWIS(), GetHeroicCHA()); - client->Message(Chat::White, " MR: %i PR: %i FR: %i CR: %i DR: %i Corruption: %i PhR: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR(), GetCorrup(), GetPhR()); - client->Message(Chat::White, " hMR: %i hPR: %i hFR: %i hCR: %i hDR: %i hCorruption: %i", GetHeroicMR(), GetHeroicPR(), GetHeroicFR(), GetHeroicCR(), GetHeroicDR(), GetHeroicCorrup()); - client->Message(Chat::White, " Shielding: %i Spell Shield: %i DoT Shielding: %i Stun Resist: %i Strikethrough: %i Avoidance: %i Accuracy: %i Combat Effects: %i", GetShielding(), GetSpellShield(), GetDoTShield(), GetStunResist(), GetStrikeThrough(), GetAvoidance(), GetAccuracy(), GetCombatEffects()); - client->Message(Chat::White, " Heal Amt.: %i Spell Dmg.: %i Clairvoyance: %i DS Mitigation: %i", GetHealAmt(), GetSpellDmg(), GetClair(), GetDSMit()); - if(GetClass() == BARD) - client->Message(Chat::White, " Singing: %i Brass: %i String: %i Percussion: %i Wind: %i", GetSingMod(), GetBrassMod(), GetStringMod(), GetPercMod(), GetWindMod()); - - Extra_Info: - - client->Message(Chat::White, " BaseRace: %i Gender: %i BaseGender: %i Texture: %i HelmTexture: %i", GetBaseRace(), GetGender(), GetBaseGender(), GetTexture(), GetHelmTexture()); - if (client->Admin() >= AccountStatus::GMAdmin) { - client->Message(Chat::White, " CharID: %i EntityID: %i PetID: %i OwnerID: %i AIControlled: %i Targetted: %i", CharacterID(), GetID(), GetPetID(), GetOwnerID(), IsAIControlled(), targeted); - } -} - void Client::SendAltCurrencies() { if (ClientVersion() >= EQ::versions::ClientVersion::SoF) { uint32 count = zone->AlternateCurrencies.size(); diff --git a/zone/client.h b/zone/client.h index 95ce22526..6cdccc597 100644 --- a/zone/client.h +++ b/zone/client.h @@ -772,7 +772,6 @@ public: void SetLanguageSkill(int langid, int value); void SetHoTT(uint32 mobid); void ShowSkillsWindow(); - void SendStatsWindow(Client* client, bool use_window); uint16 MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const; inline uint16 MaxSkill(EQ::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } @@ -1095,7 +1094,7 @@ public: uint16 GetMaxSkillAfterSpecializationRules(EQ::skills::SkillType skillid, uint16 maxSkill); void SendPopupToClient(const char *Title, const char *Text, uint32 PopupID = 0, uint32 Buttons = 0, uint32 Duration = 0); void SendFullPopup(const char *Title, const char *Text, uint32 PopupID = 0, uint32 NegativeID = 0, uint32 Buttons = 0, uint32 Duration = 0, const char *ButtonName0 = 0, const char *ButtonName1 = 0, uint32 SoundControls = 0); - void SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const char *ButtonName0, const char *ButtonName1, uint32 Duration, int title_type, Client* target, const char *Title, const char *Text, ...); + void SendWindow(uint32 button_one_id, uint32 button_two_id, uint32 button_type, const char* button_one_text, const char* button_two_text, uint32 duration, int title_type, Mob* target, const char* title, const char* text, ...); bool PendingTranslocate; time_t TranslocateTime; bool PendingSacrifice; diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 267d2dfc5..c83d253f5 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -649,7 +649,7 @@ int64 Client::CalcBaseMana() int64 Client::CalcBaseManaRegen() { uint8 clevel = GetLevel(); - int32 regen = 0; + int64 regen = 0; if (IsSitting() || (GetHorseId() != 0)) { if (HasSkill(EQ::skills::SkillMeditate)) { regen = (((GetSkill(EQ::skills::SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4; @@ -666,7 +666,7 @@ int64 Client::CalcBaseManaRegen() int64 Client::CalcManaRegen(bool bCombat) { - int regen = 0; + int64 regen = 0; auto level = GetLevel(); // so the new formulas break down with older skill caps where you don't have the skill until 4 or 8 // so for servers that want to use the old skill progression they can set this rule so they @@ -688,9 +688,9 @@ int64 Client::CalcManaRegen(bool bCombat) } } if (old) - regen = std::max(regen, 2); + regen = std::max(regen, static_cast(2)); } else if (old) { - regen = std::max(regen, 1); + regen = std::max(regen, static_cast(1)); } } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 86c6297e5..2043ad57a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11462,10 +11462,9 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app) break; case POPUPID_UPDATE_SHOWSTATSWINDOW: - if (GetTarget() && GetTarget()->IsClient()) { - GetTarget()->CastToClient()->SendStatsWindow(this, true); - } - else { + if (GetTarget() && GetTarget()->IsOfClientBot()) { + GetTarget()->SendStatsWindow(this, true); + } else { SendStatsWindow(this, true); } return; diff --git a/zone/gm_commands/find/class.cpp b/zone/gm_commands/find/class.cpp index 9c6a6eec0..c838e0a93 100644 --- a/zone/gm_commands/find/class.cpp +++ b/zone/gm_commands/find/class.cpp @@ -13,7 +13,7 @@ void FindClass(Client *c, const Seperator *sep) class_id, class_name, ( - c->IsPlayerClass(class_id) ? + IsPlayerClass(class_id) ? fmt::format( " ({})", Strings::Commify(GetPlayerClassBit(class_id)) @@ -55,7 +55,7 @@ void FindClass(Client *c, const Seperator *sep) class_id, class_name, ( - c->IsPlayerClass(class_id) ? + IsPlayerClass(class_id) ? fmt::format( " | ({})", Strings::Commify(GetPlayerClassBit(class_id)) diff --git a/zone/gm_commands/find/race.cpp b/zone/gm_commands/find/race.cpp index c2f2db0d6..1b9fb23e7 100644 --- a/zone/gm_commands/find/race.cpp +++ b/zone/gm_commands/find/race.cpp @@ -13,7 +13,7 @@ void FindRace(Client *c, const Seperator *sep) race_id, race_name, ( - c->IsPlayerRace(race_id) ? + IsPlayerRace(race_id) ? fmt::format( " ({})", Strings::Commify(GetPlayerRaceBit(race_id)) @@ -55,7 +55,7 @@ void FindRace(Client *c, const Seperator *sep) race_id, race_name, ( - c->IsPlayerRace(race_id) ? + IsPlayerRace(race_id) ? fmt::format( " ({})", Strings::Commify(GetPlayerRaceBit(race_id)) diff --git a/zone/gm_commands/mystats.cpp b/zone/gm_commands/mystats.cpp index e5a781d8a..69343b304 100755 --- a/zone/gm_commands/mystats.cpp +++ b/zone/gm_commands/mystats.cpp @@ -2,16 +2,19 @@ void command_mystats(Client *c, const Seperator *sep) { - if (c->GetTarget() && c->GetPet()) { - if (c->GetTarget()->IsPet() && c->GetTarget() == c->GetPet()) { - c->GetTarget()->ShowStats(c); - } - else { - c->ShowStats(c); - } + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); } - else { - c->ShowStats(c); + + if ( + (t->IsPet() && t == c->GetPet()) || + (t->IsBot() && t->CastToBot()->GetOwner() && t->CastToBot()->GetOwner() == c) + ) { + t->ShowStats(c); + return; } + + c->ShowStats(c); } diff --git a/zone/gm_commands/showstats.cpp b/zone/gm_commands/showstats.cpp index cae9609c2..9e43b6f5a 100755 --- a/zone/gm_commands/showstats.cpp +++ b/zone/gm_commands/showstats.cpp @@ -2,11 +2,11 @@ void command_showstats(Client *c, const Seperator *sep) { - if (c->GetTarget() != 0) { - c->GetTarget()->ShowStats(c); - } - else { - c->ShowStats(c); + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); } + + t->ShowStats(c); } diff --git a/zone/gm_commands/texture.cpp b/zone/gm_commands/texture.cpp index 24dde1f0f..518b91549 100755 --- a/zone/gm_commands/texture.cpp +++ b/zone/gm_commands/texture.cpp @@ -20,7 +20,7 @@ void command_texture(Client *c, const Seperator *sep) target = c->GetTarget(); } - if (Mob::IsPlayerRace(target->GetModel())) { // Player Races Wear Armor, so Wearchange is sent instead + if (IsPlayerRace(target->GetModel())) { // Player Races Wear Armor, so Wearchange is sent instead for ( int texture_slot = EQ::textures::textureBegin; texture_slot <= EQ::textures::LastTintableTexture; @@ -44,7 +44,7 @@ void command_texture(Client *c, const Seperator *sep) c->GetTargetDescription(target, TargetDescriptionType::UCSelf), texture, ( - Mob::IsPlayerRace(target->GetModel()) ? + IsPlayerRace(target->GetModel()) ? "" : fmt::format( " Helmet Texture: {}", diff --git a/zone/mob.cpp b/zone/mob.cpp index 6e60ba31c..2537d1366 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -1269,7 +1269,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) //for (i = 0; i < _MaterialCount; i++) for (i = 0; i < 9; i++) { // Only Player Races Wear Armor - if (Mob::IsPlayerRace(race) || i > 6) { + if (IsPlayerRace(race) || i > 6) { ns->spawn.equipment.Slot[i].Material = GetEquipmentMaterial(i); ns->spawn.equipment.Slot[i].EliteModel = IsEliteMaterialItem(i); ns->spawn.equipment.Slot[i].HerosForgeModel = GetHerosForgeModel(i); @@ -1627,13 +1627,1151 @@ void Mob::MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu) { spu->delta_heading = FloatToEQ10(m_Delta.w); } -void Mob::ShowStats(Client* client) +void Mob::SendStatsWindow(Client* c, bool use_window) { + if (!IsOfClientBot()) { + return; + } + + const std::string& color_red = "red_1"; + const std::string& color_blue = "royal_blue"; + const std::string& color_green = "forest_green"; + const std::string& bright_green = "green"; + const std::string& bright_red = "red"; + const std::string& heroic_color = "gold"; + + // Health, Mana, and Endurance + std::string HME_row; + std::string hme_color; + std::string cur_field; + std::string total_field; + std::string cur_name; + std::string cur_color; + + auto hme_rows = 3; // Rows in display + + for (auto hme_row_counter = 0; hme_row_counter < hme_rows; hme_row_counter++) { + switch (hme_row_counter) { + case 0: { + cur_name = "Health "; + cur_field = Strings::Commify(GetHP()); + total_field = Strings::Commify(GetMaxHP()); + hme_color = color_red; + break; + } + case 1: { + if (CalcMaxMana()) { + cur_name = "Mana "; + cur_field = Strings::Commify(GetMana()); + total_field = Strings::Commify(GetMaxMana()); + hme_color = color_blue; + } else { + continue; + } + + break; + } + case 2: { + cur_name = "Endurance "; + cur_field = Strings::Commify(GetEndurance()); + total_field = Strings::Commify(GetMaxEndurance()); + hme_color = color_green; + break; + } + default: { + break; + } + } + + if (!cur_field.compare(total_field)) { + cur_color = bright_green; + } else { + cur_color = bright_red; + } + + HME_row += DialogueWindow::TableRow( + fmt::format( + "{}{}", + DialogueWindow::TableCell(DialogueWindow::ColorMessage(hme_color, cur_name)), + DialogueWindow::TableCell( + fmt::format( + "{} / {}", + DialogueWindow::ColorMessage(cur_color, cur_field), + DialogueWindow::ColorMessage(bright_green, total_field) + ) + ) + ) + ); + } + + // Regen + std::string regen_string; + std::string regen_row_header; + std::string regen_row_color; + std::string base_regen_field; + std::string item_regen_field; + std::string cap_regen_field; + std::string spell_regen_field; + std::string aa_regen_field; + std::string total_regen_field; + + auto regen_rows = 3; + + for (auto regen_row_counter = 0; regen_row_counter < regen_rows; regen_row_counter++) { + switch (regen_row_counter) { + case 0: { + regen_row_header = "Health"; + regen_row_color = color_red; + + if (IsBot()) { + base_regen_field = Strings::Commify(CastToBot()->LevelRegen()); + } else if (IsClient()) { + base_regen_field = Strings::Commify(CastToClient()->LevelRegen()); + } + + item_regen_field = Strings::Commify(itembonuses.HPRegen + itembonuses.heroic_hp_regen); + cap_regen_field = Strings::Commify(CalcHPRegenCap()); + spell_regen_field = Strings::Commify(spellbonuses.HPRegen); + aa_regen_field = Strings::Commify(aabonuses.HPRegen); + + if (IsBot()) { + total_regen_field = Strings::Commify(CastToBot()->CalcHPRegen()); + } else if (IsClient()) { + total_regen_field = Strings::Commify(CastToClient()->CalcHPRegen(true)); + } + + break; + } + case 1: { + if (GetMaxMana() > 0) { + regen_row_header = "Mana"; + regen_row_color = color_blue; + + if (IsBot()) { + base_regen_field = std::to_string(0); + } else if (IsClient()) { + base_regen_field = Strings::Commify(CastToClient()->CalcBaseManaRegen()); + } + + item_regen_field = Strings::Commify(itembonuses.ManaRegen + itembonuses.heroic_mana_regen); + cap_regen_field = Strings::Commify(CalcManaRegenCap()); + spell_regen_field = Strings::Commify(spellbonuses.ManaRegen); + aa_regen_field = Strings::Commify(aabonuses.ManaRegen); + + if (IsBot()) { + total_regen_field = Strings::Commify(CastToBot()->CalcManaRegen()); + } else if (IsClient()) { + total_regen_field = Strings::Commify(CastToClient()->CalcManaRegen(true)); + } + } else { + continue; + } + + break; + } + case 2: { + regen_row_header = "Endurance"; + regen_row_color = color_green; + + base_regen_field = Strings::Commify(((GetLevel() * 4 / 10) + 2)); + item_regen_field = Strings::Commify(itembonuses.EnduranceRegen + itembonuses.heroic_end_regen); + cap_regen_field = Strings::Commify(CalcEnduranceRegenCap()); + spell_regen_field = Strings::Commify(spellbonuses.EnduranceRegen); + aa_regen_field = Strings::Commify(aabonuses.EnduranceRegen); + + if (IsBot()) { + total_regen_field = Strings::Commify(CastToBot()->CalcEnduranceRegen()); + } else if (IsClient()) { + total_regen_field = Strings::Commify(CastToClient()->CalcEnduranceRegen(true)); + } + + break; + } + default: { + break; + } + } + + regen_string += DialogueWindow::TableRow( + fmt::format( + "{}{}{}{}{}{}", + DialogueWindow::TableCell(DialogueWindow::ColorMessage(regen_row_color, regen_row_header)), + DialogueWindow::TableCell(DialogueWindow::ColorMessage(regen_row_color, base_regen_field)), + DialogueWindow::TableCell(DialogueWindow::ColorMessage(regen_row_color, fmt::format("{} ({})", item_regen_field, cap_regen_field))), + DialogueWindow::TableCell(DialogueWindow::ColorMessage(regen_row_color, spell_regen_field)), + DialogueWindow::TableCell(DialogueWindow::ColorMessage(regen_row_color, aa_regen_field)), + DialogueWindow::TableCell(DialogueWindow::ColorMessage(regen_row_color, total_regen_field)) + ) + ); + } + + // Stats + std::string stat_table; + std::string a_stat; + std::string a_stat_name; + std::string h_stat; + std::string a_resist; + std::string a_resist_name; + std::string h_resist_field; + + auto stat_rows = 7; + + for (auto stat_row_counter = 0; stat_row_counter < stat_rows; stat_row_counter++) { + switch (stat_row_counter) { + case 0: { + a_stat_name = "Agility"; + a_resist_name = "Cold"; + + a_stat = Strings::Commify(GetAGI()); + h_stat = Strings::Commify(GetHeroicAGI()); + a_resist = Strings::Commify(GetCR()); + h_resist_field = Strings::Commify(GetHeroicCR()); + break; + } + case 1: { + a_stat_name = "Charisma"; + a_resist_name = "Corruption"; + + a_stat = Strings::Commify(GetCHA()); + h_stat = Strings::Commify(GetHeroicCHA()); + a_resist = Strings::Commify(GetCorrup()); + + if (IsBot()) { + h_resist_field = Strings::Commify(CastToBot()->GetHeroicCorrup()); + } else if (IsClient()) { + h_resist_field = Strings::Commify(CastToClient()->GetHeroicCorrup()); + } + + break; + } + case 2: { + a_stat_name = "Dexterity"; + a_resist_name = "Disease"; + + a_stat = Strings::Commify(GetDEX()); + h_stat = Strings::Commify(GetHeroicDEX()); + a_resist = Strings::Commify(GetDR()); + h_resist_field = Strings::Commify(GetHeroicDR()); + break; + } + case 3: { + a_stat_name = "Intelligence"; + a_resist_name = "Fire"; + + a_stat = Strings::Commify(GetINT()); + h_stat = Strings::Commify(GetHeroicINT()); + a_resist = Strings::Commify(GetFR()); + h_resist_field = Strings::Commify(GetHeroicFR()); + break; + } + case 4: { + a_stat_name = "Stamina"; + a_resist_name = "Magic"; + + a_stat = Strings::Commify(GetSTA()); + h_stat = Strings::Commify(GetHeroicSTA()); + a_resist = Strings::Commify(GetMR()); + h_resist_field = Strings::Commify(GetHeroicMR()); + break; + } + case 5: { + a_stat_name = "Strength"; + a_resist_name = "Physical"; + + a_stat = Strings::Commify(GetSTR()); + h_stat = Strings::Commify(GetHeroicSTR()); + a_resist = Strings::Commify(GetPhR()); + + if (IsBot()) { + h_resist_field = std::to_string(0); + } else if (IsClient()) { + h_resist_field = Strings::Commify(CastToClient()->GetHeroicPhR()); + } + + break; + } + case 6: { + a_stat_name = "Wisdom"; + a_resist_name = "Poison"; + + a_stat = Strings::Commify(GetWIS()); + h_stat = Strings::Commify(GetHeroicWIS()); + a_resist = Strings::Commify(GetPR()); + h_resist_field = Strings::Commify(GetHeroicPR()); + + break; + } + default: { + break; + } + } + + stat_table += DialogueWindow::TableRow( + fmt::format( + "{}{}{}{}", + DialogueWindow::TableCell(a_stat_name), + DialogueWindow::TableCell( + fmt::format( + "{} {}", + a_stat, + DialogueWindow::ColorMessage(heroic_color, fmt::format("+{}", h_stat)) + ) + ), + DialogueWindow::TableCell(a_resist_name), + DialogueWindow::TableCell( + fmt::format( + "{} {}", + a_resist, + DialogueWindow::ColorMessage(heroic_color, fmt::format("+{}", h_resist_field)) + ) + ) + ) + ); + } + + // Mod2 + std::string mod2_table; + std::string mod2a; + std::string mod2a_name; + std::string mod2a_cap; + std::string mod2b; + std::string mod2b_name; + std::string mod2b_cap; + + auto mod2_rows = 4; + + for (auto mod2_row_counter = 0; mod2_row_counter < mod2_rows; mod2_row_counter++) { + switch (mod2_row_counter) { + case 0: { + mod2a_name = "Avoidance"; + mod2b_name = "Combat Effects"; + mod2a_cap = Strings::Commify(RuleI(Character, ItemAvoidanceCap)); + mod2b_cap = Strings::Commify(RuleI(Character, ItemCombatEffectsCap)); + + if (IsBot()) { + mod2a = Strings::Commify(CastToBot()->GetAvoidance()); + } else if (IsClient()) { + mod2a = Strings::Commify(CastToClient()->GetAvoidance()); + } + + if (IsBot()) { + mod2b = Strings::Commify(CastToBot()->GetCombatEffects()); + } else if (IsClient()) { + mod2b = Strings::Commify(CastToClient()->GetCombatEffects()); + } + + break; + } + case 1: { + mod2a_name = "Accuracy"; + mod2b_name = "Strikethrough"; + mod2a_cap = Strings::Commify(RuleI(Character, ItemAccuracyCap)); + mod2b_cap = Strings::Commify(RuleI(Character, ItemStrikethroughCap)); + + if (IsBot()) { + mod2a = Strings::Commify(CastToBot()->GetAccuracy()); + } else if (IsClient()) { + mod2a = Strings::Commify(CastToClient()->GetAccuracy()); + } + + if (IsBot()) { + mod2b = Strings::Commify(CastToBot()->GetStrikeThrough()); + } else if (IsClient()) { + mod2b = Strings::Commify(CastToClient()->GetStrikeThrough()); + } + + break; + } + case 2: { + mod2a_name = "Shielding"; + mod2b_name = "Spell Shielding"; + mod2a_cap = Strings::Commify(RuleI(Character, ItemShieldingCap)); + mod2b_cap = Strings::Commify(RuleI(Character, ItemSpellShieldingCap)); + + if (IsBot()) { + mod2a = Strings::Commify(CastToBot()->GetShielding()); + } else if (IsClient()) { + mod2a = Strings::Commify(CastToClient()->GetShielding()); + } + + + if (IsBot()) { + mod2b = Strings::Commify(CastToBot()->GetSpellShield()); + } else if (IsClient()) { + mod2b = Strings::Commify(CastToClient()->GetSpellShield()); + } + + break; + } + case 3: { + mod2a_name = "Stun Resist"; + mod2b_name = "DOT Shielding"; + mod2a_cap = Strings::Commify(RuleI(Character, ItemStunResistCap)); + mod2b_cap = Strings::Commify(RuleI(Character, ItemDoTShieldingCap)); + + if (IsBot()) { + mod2a = Strings::Commify(CastToBot()->GetStunResist()); + } else if (IsClient()) { + mod2a = Strings::Commify(CastToClient()->GetStunResist()); + } + + if (IsBot()) { + mod2b = Strings::Commify(CastToBot()->GetDoTShield()); + } else if (IsClient()) { + mod2b = Strings::Commify(CastToClient()->GetDoTShield()); + } + + break; + } + } + + mod2_table += DialogueWindow::TableRow( + fmt::format( + "{}{}", + DialogueWindow::TableCell( + fmt::format( + "{}: {} / {}", + mod2a_name, + Strings::Commify(mod2a), + Strings::Commify(mod2a_cap) + ) + ), + DialogueWindow::TableCell( + fmt::format( + "{}: {} / {}", + mod2b_name, + Strings::Commify(mod2b), + Strings::Commify(mod2b_cap) + ) + ) + ) + ); + } + + uint32 rune_number = 0; + uint32 magic_rune_number = 0; + + for (auto i = 0; i < GetMaxTotalSlots(); i++) { + if (IsValidSpell(buffs[i].spellid)) { + if (buffs[i].melee_rune > 0) { + rune_number += buffs[i].melee_rune; + } + + if (buffs[i].magic_rune > 0) { + magic_rune_number += buffs[i].magic_rune; + } + } + } + + auto shield_ac = 0; + + if (IsBot()) { + CastToBot()->GetRawACNoShield(shield_ac); + } else if (IsClient()) { + CastToClient()->GetRawACNoShield(shield_ac); + } + + std::string skill_mods; + + for (auto j = 0; j <= EQ::skills::HIGHEST_SKILL; j++) { + if (itembonuses.skillmod[j] != 0) { + const std::string& sign = itembonuses.skillmod[j] >= 0 ? "+" : "-"; + + skill_mods += fmt::format( + "{}: {}{}%%{}", + EQ::skills::GetSkillName(static_cast(j)), + sign, + Strings::Commify(itembonuses.skillmod[j]), + DialogueWindow::Break(1) + ); + } + } + + std::string skill_dmgs; + + for (auto j = 0; j <= EQ::skills::HIGHEST_SKILL; j++) { + if ((itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) != 0) { + const std::string& sign = (itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) >= 0 ? "+" : "-"; + + skill_dmgs += fmt::format( + "{}: {}{}{}", + EQ::skills::GetSkillName(static_cast(j)), + sign, + Strings::Commify(itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]), + DialogueWindow::Break(1) + ); + } + } + + std::string faction_item_string; + + for (const auto& f : item_faction_bonuses) { + if (f.second != 0) { + const auto &faction_name = content_db.GetFactionName(f.first); + const std::string& sign = f.second >= 0 ? "+" : "-"; + + faction_item_string += fmt::format( + "{}: {}{}{}", + !faction_name.empty() ? faction_name : "Unknown Faction", + sign, + Strings::Commify(f.second), + DialogueWindow::Break(1) + ); + } + } + + std::string bard_info; + + if (GetClass() == BARD) { + const auto brass_mod = IsBot() ? CastToBot()->GetBrassMod() : CastToClient()->GetBrassMod(); + const auto perc_mod = IsBot() ? CastToBot()->GetPercMod() : CastToClient()->GetPercMod(); + const auto sing_mod = IsBot() ? CastToBot()->GetSingMod() : CastToClient()->GetSingMod(); + const auto string_mod = IsBot() ? CastToBot()->GetStringMod() : CastToClient()->GetStringMod(); + const auto wind_mod = IsBot() ? CastToBot()->GetWindMod() : CastToClient()->GetWindMod(); + + if (brass_mod) { + bard_info += fmt::format( + "Brass: {}{}", + Strings::Commify(brass_mod), + DialogueWindow::Break(1) + ); + } + + if (perc_mod) { + bard_info += fmt::format( + "Percussion: {}{}", + Strings::Commify(perc_mod), + DialogueWindow::Break(1) + ); + } + + if (sing_mod) { + bard_info += fmt::format( + "Singing: {}{}", + Strings::Commify(sing_mod), + DialogueWindow::Break(1) + ); + } + + if (string_mod) { + bard_info += fmt::format( + "String: {}{}", + Strings::Commify(string_mod), + DialogueWindow::Break(1) + ); + } + + if (wind_mod) { + bard_info += fmt::format( + "Wind: {}{}", + Strings::Commify(wind_mod), + DialogueWindow::Break(1) + ); + } + } + + auto skill = EQ::skills::SkillHandtoHand; + auto *inst = GetInv().GetItem(EQ::invslot::slotPrimary); + + if (inst && inst->IsClassCommon()) { + switch (inst->GetItem()->ItemType) { + case EQ::item::ItemType1HSlash: + skill = EQ::skills::Skill1HSlashing; + break; + case EQ::item::ItemType2HSlash: + skill = EQ::skills::Skill2HSlashing; + break; + case EQ::item::ItemType1HPiercing: + skill = EQ::skills::Skill1HPiercing; + break; + case EQ::item::ItemType1HBlunt: + skill = EQ::skills::Skill1HBlunt; + break; + case EQ::item::ItemType2HBlunt: + skill = EQ::skills::Skill2HBlunt; + break; + case EQ::item::ItemType2HPiercing: + if (IsClient() && CastToClient()->ClientVersion() < EQ::versions::ClientVersion::RoF2) { + skill = EQ::skills::Skill1HPiercing; + } else { + skill = EQ::skills::Skill2HPiercing; + } + + break; + default: + break; + } + } + + std::string final_string; + + // Class, Level, and Race + final_string += DialogueWindow::Table( + DialogueWindow::TableRow( + fmt::format( + "{}{}{}", + DialogueWindow::TableCell(fmt::format("Race: {}", GetPlayerRaceAbbreviation(GetBaseRace()))), + DialogueWindow::TableCell(fmt::format("Class: {}", GetPlayerClassAbbreviation(GetClass()))), + DialogueWindow::TableCell(fmt::format("Level: {}", std::to_string(GetLevel()))) + ) + ) + ); + + // Runes + if (rune_number || magic_rune_number) { + final_string += DialogueWindow::Table( + DialogueWindow::TableRow( + fmt::format( + "{}{}{}", + DialogueWindow::TableCell( + fmt::format("Rune: {}", rune_number) + ), + DialogueWindow::TableCell(""), + DialogueWindow::TableCell( + fmt::format("Spell Rune: {}", magic_rune_number) + ) + ) + ) + ); + + final_string += DialogueWindow::Break(1); + } + + // Health, Mana, and Endurance + final_string += DialogueWindow::Table(HME_row); + + // Attack + final_string += DialogueWindow::ColorMessage( + "green_yellow", + fmt::format( + "To Hit: {} / {}", + Strings::Commify(compute_tohit(skill)), + Strings::Commify(GetTotalToHit(skill, 0)) + ) + ); + + final_string += DialogueWindow::Break(1); + + // Attack 2 + final_string += fmt::format( + "Offense: {}{} | {}{}", + Strings::Commify(offense(skill)), + ( + itembonuses.ATK ? + fmt::format( + " | Item: {} / {} | Used: {}", + Strings::Commify(itembonuses.ATK), + Strings::Commify(RuleI(Character, ItemATKCap)), + Strings::Commify(static_cast(itembonuses.ATK * 1.342)) + ) : + "" + ), + spellbonuses.ATK ? fmt::format(" | Spell: {}", Strings::Commify(spellbonuses.ATK)) : "", + DialogueWindow::Break(1) + ); + + // Armor Class + final_string += fmt::format( + "{}{}", + DialogueWindow::ColorMessage( + "green_yellow", + fmt::format( + "Mitigation AC: {}", + Strings::Commify(GetMitigationAC()) + ) + ), + DialogueWindow::Break(1) + ); + + // Armor Class 2 + final_string += fmt::format( + "Defense: {} / {}{}{}{}", + Strings::Commify(compute_defense()), + Strings::Commify(GetTotalDefense()), + spellbonuses.AC ? fmt::format(" | Spell: {}", Strings::Commify(spellbonuses.AC)) : "", + shield_ac ? fmt::format(" | Shield: {}", Strings::Commify(shield_ac)) : "", + DialogueWindow::Break(1) + ); + + // Run Speed + final_string += fmt::format( + "{}{}", + DialogueWindow::ColorMessage( + "green_yellow", + fmt::format( + "Runspeed: {}", + IsBot() ? CastToBot()->GetRunspeed() : CastToClient()->GetRunspeed() + ) + ), + DialogueWindow::Break(1) + ); + + final_string += DialogueWindow::CenterMessage("Haste"); + + // Haste Table + const auto& haste_table = DialogueWindow::Table( + fmt::format( + "{}{}", + DialogueWindow::TableRow( + fmt::format( + "{}{}{}{}", + DialogueWindow::TableCell("Item"), + DialogueWindow::TableCell("Spell"), + DialogueWindow::TableCell("Over"), + DialogueWindow::TableCell("Total (Cap)") + ) + ), + DialogueWindow::TableRow( + fmt::format( + "{}{}{}{}", + DialogueWindow::TableCell(Strings::Commify(itembonuses.haste)), + DialogueWindow::TableCell(Strings::Commify(spellbonuses.haste + spellbonuses.hastetype2)), + DialogueWindow::TableCell(Strings::Commify(spellbonuses.hastetype3 + ExtraHaste)), + DialogueWindow::TableCell(fmt::format("{} ({})", Strings::Commify(GetHaste()), Strings::Commify(RuleI(Character, HasteCap)))) + ) + ) + ) + ); + + final_string += haste_table; + + // Regen Table + final_string += DialogueWindow::CenterMessage("Regen"); + + const auto& regen_table = DialogueWindow::Table( + fmt::format( + "{}{}", + DialogueWindow::TableRow( + fmt::format( + "{}{}{}{}{}{}", + DialogueWindow::TableCell("Type"), + DialogueWindow::TableCell("Base"), + DialogueWindow::TableCell("Items (Cap)"), + DialogueWindow::TableCell("Spell"), + DialogueWindow::TableCell("AAs"), + DialogueWindow::TableCell("Total") + ) + ), + regen_string + ) + ); + + // Regen + final_string += regen_table + DialogueWindow::Break(1); + + // Stats + final_string += DialogueWindow::Table(stat_table) + DialogueWindow::Break(1); + + // Mod 2 + final_string += DialogueWindow::Table(mod2_table) + DialogueWindow::Break(1); + + // Heal Amount + if (GetHealAmt()) { + final_string += fmt::format( + "Heal Amount: {} / {}{}", + Strings::Commify(GetHealAmt()), + Strings::Commify(RuleI(Character, ItemHealAmtCap)), + DialogueWindow::Break(1) + ); + } + + // Heal Amount + if (GetSpellDmg()) { + final_string += fmt::format( + "Spell Damage: {} / {}{}", + Strings::Commify(GetSpellDmg()), + Strings::Commify(RuleI(Character, ItemSpellDmgCap)), + DialogueWindow::Break(1) + ); + } + + // Damage Shield + if (itembonuses.DamageShield || spellbonuses.DamageShield) { + final_string += fmt::format( + "Damage Shield: {}{}{}{}", + Strings::Commify(itembonuses.DamageShield + spellbonuses.DamageShield), + ( + spellbonuses.DamageShield ? + fmt::format(" | Spell: {}", Strings::Commify(spellbonuses.DamageShield)) : + "" + ), + ( + itembonuses.DamageShield ? + fmt::format( + " | Item: {} / {}", + Strings::Commify(itembonuses.DamageShield), + Strings::Commify(RuleI(Character, ItemDamageShieldCap)) + ) : + "" + ), + DialogueWindow::Break(2) + ); + } + + // Clairvoyance + const auto clairvoyance = IsBot() ? CastToBot()->GetClair() : CastToClient()->GetClair(); + if (clairvoyance) { + final_string += fmt::format( + "Clairvoyance: {} / {}{}", + Strings::Commify(clairvoyance), + Strings::Commify(RuleI(Character, ItemClairvoyanceCap)), + DialogueWindow::Break(1) + ); + } + + // Damage Shield Mitigation + const auto ds_mitigation = IsBot() ? CastToBot()->GetDSMit() : CastToClient()->GetDSMit(); + if (ds_mitigation) { + final_string += fmt::format( + "DS Mitigation: {} / {}{}", + Strings::Commify(ds_mitigation), + Strings::Commify(RuleI(Character, ItemDSMitigationCap)), + DialogueWindow::Break(1) + ); + } + + if (clairvoyance || ds_mitigation) { + final_string += DialogueWindow::Break(1); + } + + // Bard Modifiers + if (GetClass() == BARD) { + final_string += bard_info + DialogueWindow::Break(1); + } + + // Skill Modifiers + if (!skill_mods.empty()) { + final_string += skill_mods + DialogueWindow::Break(1); + } + + // Skill Damage Modifiers + if (!skill_dmgs.empty()) { + final_string += skill_dmgs + DialogueWindow::Break(1); + } + + // Faction Modifiers + if (!faction_item_string.empty()) { + final_string += faction_item_string; + } + + if (use_window) { + if (final_string.size() < 4096) { + const uint32 popup_buttons = (c->ClientVersion() < EQ::versions::ClientVersion::SoD) ? 0 : 1; + c->SendWindow( + 0, + POPUPID_UPDATE_SHOWSTATSWINDOW, + popup_buttons, + "Close", + "Update", + 0, + 1, + this, + "", + final_string.c_str() + ); + + goto extra_info; + } else { + c->Message(Chat::Yellow, "The window has exceeded its character limit, displaying stats to chat window:"); + } + } + + c->Message( + Chat::White, + fmt::format( + "Statistics Information for {} {}", + GetCleanName(), + GetLastName() + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Level: {} Class: {} ({}) Race: {} ({}) Damage Shield: {}/{} Size: {:.1f} Run Speed: {} Weight: {:.1f}/{}", + GetLevel(), + GetClassIDName(GetClass()), + GetClass(), + GetRaceIDName(GetRace()), + GetRace(), + IsBot() ? Strings::Commify(CastToBot()->GetDS()) : Strings::Commify(CastToClient()->GetDS()), + Strings::Commify(RuleI(Character, ItemDamageShieldCap)), + GetSize(), + GetRunspeed(), + IsBot() ? static_cast(CastToBot()->CalcCurrentWeight()) / 10.0f : static_cast(CastToClient()->CalcCurrentWeight()) / 10.0f, + Strings::Commify(GetSTR()) + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Health: {}/{} Regen: {}/{}", + GetHP(), + GetMaxHP(), + IsBot() ? Strings::Commify(CastToBot()->CalcHPRegen()) : Strings::Commify(CastToClient()->CalcHPRegen()), + CalcHPRegenCap() + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "To Hit: {} Total: {}", + Strings::Commify(compute_tohit(skill)), + Strings::Commify(GetTotalToHit(skill, 0)) + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Defense: {} Total: {}", + Strings::Commify(compute_defense()), + Strings::Commify(GetTotalDefense()) + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Offense: {} Mitigation AC: {}", + Strings::Commify(offense(skill)), + Strings::Commify(GetMitigationAC()) + ).c_str() + ); + if (IsClient()) { - CastToClient()->SendStatsWindow(client, RuleB(Character, UseNewStatsWindow)); + c->Message( + Chat::White, + fmt::format( + " AFK: {} LFG: {} Anon: {} PVP: {} GM: {} Fly Mode: {} ({}) GM Speed: {} Hide Me: {} Invulnerability: {} LD: {} Client Version: {} Tells Off: {}", + CastToClient()->AFK ? "Yes" : "No", + CastToClient()->LFG ? "Yes" : "No", + CastToClient()->GetAnon() ? "Yes" : "No", + CastToClient()->GetPVP() ? "Yes" : "No", + CastToClient()->GetGM() ? "On" : "Off", + EQ::constants::GetFlyModeName(static_cast(flymode)), + flymode, + CastToClient()->GetGMSpeed() ? "On" : "Off", + CastToClient()->GetHideMe() ? "On" : "Off", + CastToClient()->GetGMInvul() ? "On" : "Off", + CastToClient()->IsLD() ? "Yes" : "No", + CastToClient()->ClientVersionBit(), + CastToClient()->tellsoff ? "Yes" : "No" + ).c_str() + ); + } + + if (CalcMaxMana()) { + c->Message( + Chat::White, + fmt::format( + "Mana: {}/{} Regen: {}/{}", + Strings::Commify(GetMana()), + Strings::Commify(GetMaxMana()), + IsBot() ? Strings::Commify(CastToBot()->CalcManaRegen()) : Strings::Commify(CastToClient()->CalcManaRegen()), + Strings::Commify(CalcManaRegenCap()) + ).c_str() + ); + } + + c->Message( + Chat::White, + fmt::format( + "Endurance: {}/{} Regen: {}/{}", + Strings::Commify(GetEndurance()), + Strings::Commify(GetMaxEndurance()), + IsBot() ? Strings::Commify(CastToBot()->CalcEnduranceRegen()) : Strings::Commify(CastToClient()->CalcEnduranceRegen(true)), + Strings::Commify(CalcEnduranceRegenCap()) + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Attack: {} Item and Spell Attack: {}/{} Server Side Attack: {}", + IsBot() ? Strings::Commify(CastToBot()->GetTotalATK()) : Strings::Commify(CastToClient()->GetTotalATK()), + Strings::Commify(GetATKBonus()), + Strings::Commify(RuleI(Character, ItemATKCap)), + Strings::Commify(GetATK()) + ).c_str() + ); + + if (GetHaste()) { + c->Message( + Chat::White, + fmt::format( + "Haste: {}/{} (Item: {} + Spell: {} + Over: {})", + Strings::Commify(GetHaste()), + Strings::Commify(RuleI(Character, HasteCap)), + Strings::Commify(itembonuses.haste), + Strings::Commify(spellbonuses.haste + spellbonuses.hastetype2), + Strings::Commify(spellbonuses.hastetype3 + ExtraHaste) + ).c_str() + ); + } + + c->Message( + Chat::White, + fmt::format( + "Statistics | Agility: {} Charisma: {} Dexterity: {} Intelligence: {} Stamina: {} Strength: {} Wisdom: {}", + Strings::Commify(GetAGI()), + Strings::Commify(GetCHA()), + Strings::Commify(GetDEX()), + Strings::Commify(GetINT()), + Strings::Commify(GetSTA()), + Strings::Commify(GetSTR()), + Strings::Commify(GetWIS()) + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Heroic Statistics | Agility: {} Charisma: {} Dexterity: {} Intelligence: {} Stamina: {} Strength: {} Wisdom: {}", + Strings::Commify(GetHeroicAGI()), + Strings::Commify(GetHeroicCHA()), + Strings::Commify(GetHeroicDEX()), + Strings::Commify(GetHeroicINT()), + Strings::Commify(GetHeroicSTA()), + Strings::Commify(GetHeroicSTR()), + Strings::Commify(GetHeroicWIS()) + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Resistances | Cold: {} Corruption: {} Disease: {} Fire: {} Magic: {} Poison: {} Physical: {}", + Strings::Commify(GetCR()), + Strings::Commify(GetCorrup()), + Strings::Commify(GetDR()), + Strings::Commify(GetFR()), + Strings::Commify(GetMR()), + Strings::Commify(GetPR()), + Strings::Commify(GetPhR()) + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Heroic Resistances | Cold: {} Corruption: {} Disease: {} Fire: {} Magic: {} Poison: {}", + GetHeroicCR(), + IsBot() ? Strings::Commify(CastToBot()->GetHeroicCorrup()) : Strings::Commify(CastToClient()->GetHeroicCorrup()), + GetHeroicDR(), + GetHeroicFR(), + GetHeroicMR(), + GetHeroicPR() + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Accuracy: {} Avoidance: {} Combat Effects: {} DOT Shielding: {} Shielding: {} Spell Shield: {} Strikethrough: {} Stun Resist: {}", + IsBot() ? Strings::Commify(CastToBot()->GetAccuracy()) : Strings::Commify(CastToClient()->GetAccuracy()), + IsBot() ? Strings::Commify(CastToBot()->GetAvoidance()) : Strings::Commify(CastToClient()->GetAvoidance()), + IsBot() ? Strings::Commify(CastToBot()->GetCombatEffects()) : Strings::Commify(CastToClient()->GetCombatEffects()), + IsBot() ? Strings::Commify(CastToBot()->GetDoTShield()) : Strings::Commify(CastToClient()->GetDoTShield()), + IsBot() ? Strings::Commify(CastToBot()->GetShielding()) : Strings::Commify(CastToClient()->GetShielding()), + IsBot() ? Strings::Commify(CastToBot()->GetSpellShield()) : Strings::Commify(CastToClient()->GetSpellShield()), + IsBot() ? Strings::Commify(CastToBot()->GetStrikeThrough()) : Strings::Commify(CastToClient()->GetStrikeThrough()), + IsBot() ? Strings::Commify(CastToBot()->GetStunResist()) : Strings::Commify(CastToClient()->GetStunResist()) + ).c_str() + ); + + if (GetHealAmt() || GetSpellDmg()) { + c->Message( + Chat::White, + fmt::format( + "Heal Amount: {} Spell Damage: {}", + Strings::Commify(GetHealAmt()), + Strings::Commify(GetSpellDmg()) + ).c_str() + ); + } + + if (clairvoyance || ds_mitigation) { + c->Message( + Chat::White, + fmt::format( + "Clairvoyance: {} Damage Shield Mitigation: {}", + Strings::Commify(clairvoyance), + Strings::Commify(ds_mitigation) + ).c_str() + ); + } + + if (GetClass() == BARD) { + const auto brass_mod = IsBot() ? CastToBot()->GetBrassMod() : CastToClient()->GetBrassMod(); + const auto perc_mod = IsBot() ? CastToBot()->GetPercMod() : CastToClient()->GetPercMod(); + const auto sing_mod = IsBot() ? CastToBot()->GetSingMod() : CastToClient()->GetSingMod(); + const auto string_mod = IsBot() ? CastToBot()->GetStringMod() : CastToClient()->GetStringMod(); + const auto wind_mod = IsBot() ? CastToBot()->GetWindMod() : CastToClient()->GetWindMod(); + + if ( + brass_mod || + perc_mod || + sing_mod || + string_mod || + wind_mod + ) { + c->Message( + Chat::White, + fmt::format( + "Brass: {} Percussion: {} Singing: {} String: {} Wind: {}", + Strings::Commify(brass_mod), + Strings::Commify(perc_mod), + Strings::Commify(sing_mod), + Strings::Commify(string_mod), + Strings::Commify(wind_mod) + ).c_str() + ); + } + } + + extra_info: + + c->Message( + Chat::White, + fmt::format( + "Base Race: {} ({}) Gender: {} ({}) Base Gender: {} ({}) Texture: {} Helmet Texture: {}", + GetRaceIDName(GetBaseRace()), + GetBaseRace(), + GetGenderName(GetGender()), + GetGender(), + GetGenderName(GetBaseGender()), + GetBaseGender(), + GetTexture(), + GetHelmTexture() + ).c_str() + ); + + if (c->Admin() >= AccountStatus::GMAdmin) { + c->Message( + Chat::White, + fmt::format( + "ID: {} Entity ID: {} Pet ID: {} Owner ID: {} AI Controlled: {} Targeted: {}", + IsBot() ? CastToBot()->GetBotID() : CastToClient()->CharacterID(), + GetID(), + GetPetID(), + GetOwnerID(), + IsAIControlled() ? "Yes" : "No", + targeted + ).c_str() + ); + } +} + +void Mob::ShowStats(Client* c) +{ + if (IsOfClientBot()) { + SendStatsWindow(c, RuleB(Character, UseNewStatsWindow)); } else if (IsCorpse()) { if (IsPlayerCorpse()) { - client->Message( + c->Message( Chat::White, fmt::format( "Player Corpse | Character ID: {} ID: {}", @@ -1642,7 +2780,7 @@ void Mob::ShowStats(Client* client) ).c_str() ); } else { - client->Message( + c->Message( Chat::White, fmt::format( "NPC Corpse | ID: {}", @@ -1651,24 +2789,26 @@ void Mob::ShowStats(Client* client) ); } } else { - NPC* target = CastToNPC(); - std::string target_name = target->GetCleanName(); - std::string target_last_name = target->GetLastName(); - bool has_charmed_stats = ( - target->GetCharmedAccuracy() != 0 || - target->GetCharmedArmorClass() != 0 || - target->GetCharmedAttack() != 0 || - target->GetCharmedAttackDelay() != 0 || - target->GetCharmedAvoidance() != 0 || - target->GetCharmedMaxDamage() != 0 || - target->GetCharmedMinDamage() != 0 + const auto& t = CastToNPC(); + + const std::string target_name = t->GetCleanName(); + const std::string target_last_name = t->GetLastName(); + + const auto has_charmed_stats = ( + t->GetCharmedAccuracy() != 0 || + t->GetCharmedArmorClass() != 0 || + t->GetCharmedAttack() != 0 || + t->GetCharmedAttackDelay() != 0 || + t->GetCharmedAvoidance() != 0 || + t->GetCharmedMaxDamage() != 0 || + t->GetCharmedMinDamage() != 0 ); // Faction - if (target->GetNPCFactionID()) { - auto faction_id = target->GetPrimaryFaction(); + if (t->GetNPCFactionID()) { + auto faction_id = t->GetPrimaryFaction(); auto faction_name = content_db.GetFactionName(faction_id); - client->Message( + c->Message( Chat::White, fmt::format( "Faction: {} ({})", @@ -1679,147 +2819,148 @@ void Mob::ShowStats(Client* client) } // Adventure Template - if (target->GetAdventureTemplate()) { - client->Message( + if (t->GetAdventureTemplate()) { + c->Message( Chat::White, fmt::format( "Adventure Template: {}", - target->GetAdventureTemplate() + t->GetAdventureTemplate() ).c_str() ); } // Body - auto bodytype_name = EQ::constants::GetBodyTypeName(target->GetBodyType()); - client->Message( + auto bodytype_name = EQ::constants::GetBodyTypeName(t->GetBodyType()); + c->Message( Chat::White, fmt::format( "Body | Size: {:.2f} Type: {}", - target->GetSize(), + t->GetSize(), ( bodytype_name.empty() ? fmt::format( "{}", - target->GetBodyType() + t->GetBodyType() ) : fmt::format( "{} ({})", bodytype_name, - target->GetBodyType() + t->GetBodyType() ) ) ).c_str() ); // Face - client->Message( + c->Message( Chat::White, fmt::format( "Features | Face: {} Eye One: {} Eye Two: {}", - target->GetLuclinFace(), - target->GetEyeColor1(), - target->GetEyeColor2() + t->GetLuclinFace(), + t->GetEyeColor1(), + t->GetEyeColor2() ).c_str() ); // Hair - client->Message( + c->Message( Chat::White, fmt::format( "Features | Hair: {} Hair Color: {}", - target->GetHairStyle(), - target->GetHairColor() + t->GetHairStyle(), + t->GetHairColor() ).c_str() ); // Beard - client->Message( + c->Message( Chat::White, fmt::format( "Features | Beard: {} Beard Color: {}", - target->GetBeard(), - target->GetBeardColor() + t->GetBeard(), + t->GetBeardColor() ).c_str() ); // Drakkin Features - if (target->GetRace() == RACE_DRAKKIN_522) { - client->Message( + if (t->GetRace() == RACE_DRAKKIN_522) { + c->Message( Chat::White, fmt::format( "Drakkin Features | Heritage: {} Tattoo: {} Details: {}", - target->GetDrakkinHeritage(), - target->GetDrakkinTattoo(), - target->GetDrakkinDetails() + t->GetDrakkinHeritage(), + t->GetDrakkinTattoo(), + t->GetDrakkinDetails() ).c_str() ); } // Textures - client->Message( + c->Message( Chat::White, fmt::format( "Textures | Armor: {} Helmet: {}", - target->GetTexture(), - target->GetHelmTexture() + t->GetTexture(), + t->GetHelmTexture() ).c_str() ); if ( - target->GetArmTexture() || - target->GetBracerTexture() || - target->GetHandTexture() + t->GetArmTexture() || + t->GetBracerTexture() || + t->GetHandTexture() ) { - client->Message( + c->Message( Chat::White, fmt::format( "Textures | Arms: {} Bracers: {} Hands: {}", - target->GetArmTexture(), - target->GetBracerTexture(), - target->GetHandTexture() + t->GetArmTexture(), + t->GetBracerTexture(), + t->GetHandTexture() ).c_str() ); } if ( - target->GetFeetTexture() || - target->GetLegTexture() + t->GetFeetTexture() || + t->GetLegTexture() ) { - client->Message( + c->Message( Chat::White, fmt::format( "Textures | Legs: {} Feet: {}", - target->GetLegTexture(), - target->GetFeetTexture() + t->GetLegTexture(), + t->GetFeetTexture() ).c_str() ); } // Hero's Forge - if (target->GetHeroForgeModel()) { - client->Message( + if (t->GetHeroForgeModel()) { + c->Message( Chat::White, fmt::format( "Hero's Forge: {}", - target->GetHeroForgeModel() + t->GetHeroForgeModel() ).c_str() ); } // Owner Data - if (target->GetOwner()) { - auto owner_name = target->GetOwner()->GetCleanName(); + if (t->GetOwner()) { + const auto& o = t->GetOwner(); + auto owner_name = o->GetCleanName(); auto owner_type = ( - target->GetOwner()->IsNPC() ? + o->IsNPC() ? "NPC" : ( - target->GetOwner()->IsClient() ? + o->IsClient() ? "Client" : "Other" ) ); - auto owner_id = target->GetOwnerID(); - client->Message( + auto owner_id = t->GetOwnerID(); + c->Message( Chat::White, fmt::format( "Owner | Name: {} ({}) Type: {}", @@ -1831,10 +2972,10 @@ void Mob::ShowStats(Client* client) } // Pet Data - if (target->GetPet()) { - auto pet_name = target->GetPet()->GetCleanName(); - auto pet_id = target->GetPetID(); - client->Message( + if (t->GetPet()) { + auto pet_name = t->GetPet()->GetCleanName(); + auto pet_id = t->GetPetID(); + c->Message( Chat::White, fmt::format( "Pet | Name: {} ({})", @@ -1845,128 +2986,128 @@ void Mob::ShowStats(Client* client) } // Merchant Data - if (target->MerchantType) { - client->Message( + if (t->MerchantType) { + c->Message( Chat::White, fmt::format( "Merchant | ID: {} Currency Type: {}", - target->MerchantType, - target->GetAltCurrencyType() + t->MerchantType, + t->GetAltCurrencyType() ).c_str() ); } // Spell Data - if (target->AI_HasSpells() || target->AI_HasSpellsEffects()) { - client->Message( + if (t->AI_HasSpells() || t->AI_HasSpellsEffects()) { + c->Message( Chat::White, fmt::format( "Spells | ID: {} Effects ID: {}", - target->GetNPCSpellsID(), - target->GetNPCSpellsEffectsID() + t->GetNPCSpellsID(), + t->GetNPCSpellsEffectsID() ).c_str() ); } // Health - client->Message( + c->Message( Chat::White, fmt::format( "Health: {}/{} ({:.2f}%) Regen: {}", - target->GetHP(), - target->GetMaxHP(), - target->GetHPRatio(), - target->GetHPRegen() + t->GetHP(), + t->GetMaxHP(), + t->GetHPRatio(), + t->GetHPRegen() ).c_str() ); // Mana - if (target->GetMaxMana() > 0) { - client->Message( + if (t->GetMaxMana() > 0) { + c->Message( Chat::White, fmt::format( "Mana: {}/{} ({:.2f}%) Regen: {}", - target->GetMana(), - target->GetMaxMana(), - target->GetManaRatio(), - target->GetManaRegen() + t->GetMana(), + t->GetMaxMana(), + t->GetManaRatio(), + t->GetManaRegen() ).c_str() ); } // Damage - client->Message( + c->Message( Chat::White, fmt::format( "Damage | Min: {} Max: {}", - target->GetMinDMG(), - target->GetMaxDMG() + t->GetMinDMG(), + t->GetMaxDMG() ).c_str() ); // Attack Count / Delay - client->Message( + c->Message( Chat::White, fmt::format( "Attack | Count: {} Delay: {}", - target->GetNumberOfAttacks(), - target->GetAttackDelay() + t->GetNumberOfAttacks(), + t->GetAttackDelay() ).c_str() ); // Weapon Textures - client->Message( + c->Message( Chat::White, fmt::format( "Weapon Textures | Primary: {} Secondary: {} Ammo: {}", - target->GetEquipmentMaterial(EQ::textures::weaponPrimary), - target->GetEquipmentMaterial(EQ::textures::weaponSecondary), - target->GetAmmoIDfile() + t->GetEquipmentMaterial(EQ::textures::weaponPrimary), + t->GetEquipmentMaterial(EQ::textures::weaponSecondary), + t->GetAmmoIDfile() ).c_str() ); // Weapon Types - client->Message( + c->Message( Chat::White, fmt::format( "Weapon Types | Primary: {} ({}) Secondary: {} ({})", - EQ::skills::GetSkillName(static_cast(target->GetPrimSkill())), - target->GetPrimSkill(), - EQ::skills::GetSkillName(static_cast(target->GetSecSkill())), - target->GetSecSkill() + EQ::skills::GetSkillName(static_cast(t->GetPrimSkill())), + t->GetPrimSkill(), + EQ::skills::GetSkillName(static_cast(t->GetSecSkill())), + t->GetSecSkill() ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Weapon Types | Ranged: {} ({})", - EQ::skills::GetSkillName(static_cast(target->GetRangedSkill())), - target->GetRangedSkill() + EQ::skills::GetSkillName(static_cast(t->GetRangedSkill())), + t->GetRangedSkill() ).c_str() ); // Combat Stats - client->Message( + c->Message( Chat::White, fmt::format( "Combat Stats | Accuracy: {} Armor Class: {} Attack: {}", - target->GetAccuracyRating(), - target->GetAC(), - target->GetATK() + t->GetAccuracyRating(), + t->GetAC(), + t->GetATK() ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Combat Stats | Avoidance: {} Slow Mitigation: {}", - target->GetAvoidanceRating(), - target->GetSlowMitigation() + t->GetAvoidanceRating(), + t->GetSlowMitigation() ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Combat Stats | To Hit: {} Total To Hit: {}", @@ -1975,7 +3116,7 @@ void Mob::ShowStats(Client* client) ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Combat Stats | Defense: {} Total Defense: {}", @@ -1984,7 +3125,7 @@ void Mob::ShowStats(Client* client) ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Combat Stats | Offense: {} Mitigation Armor Class: {}", @@ -1994,302 +3135,302 @@ void Mob::ShowStats(Client* client) ); // Stats - client->Message( + c->Message( Chat::White, fmt::format( "Stats | Agility: {} Charisma: {} Dexterity: {} Intelligence: {}", - target->GetAGI(), - target->GetCHA(), - target->GetDEX(), - target->GetINT() + t->GetAGI(), + t->GetCHA(), + t->GetDEX(), + t->GetINT() ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Stats | Stamina: {} Strength: {} Wisdom: {}", - target->GetSTA(), - target->GetSTR(), - target->GetWIS() + t->GetSTA(), + t->GetSTR(), + t->GetWIS() ).c_str() ); // Charmed Stats if (has_charmed_stats) { - client->Message( + c->Message( Chat::White, fmt::format( "Charmed Stats | Attack: {} Attack Delay: {}", - target->GetCharmedAttack(), - target->GetCharmedAttackDelay() + t->GetCharmedAttack(), + t->GetCharmedAttackDelay() ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Charmed Stats | Accuracy: {} Avoidance: {}", - target->GetCharmedAccuracy(), - target->GetCharmedAvoidance() + t->GetCharmedAccuracy(), + t->GetCharmedAvoidance() ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Charmed Stats | Min Damage: {} Max Damage: {}", - target->GetCharmedMinDamage(), - target->GetCharmedMaxDamage() + t->GetCharmedMinDamage(), + t->GetCharmedMaxDamage() ).c_str() ); } // Resists - client->Message( + c->Message( Chat::White, fmt::format( "Resists | Cold: {} Disease: {} Fire: {} Magic: {}", - target->GetCR(), - target->GetDR(), - target->GetFR(), - target->GetMR() + t->GetCR(), + t->GetDR(), + t->GetFR(), + t->GetMR() ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Resists | Poison: {} Corruption: {} Physical: {}", - target->GetPR(), - target->GetCorrup(), - target->GetPhR() + t->GetPR(), + t->GetCorrup(), + t->GetPhR() ).c_str() ); // Scaling - client->Message( + c->Message( Chat::White, fmt::format( "Scaling | Heal: {} Spell: {}", - target->GetHealScale(), - target->GetSpellScale() + t->GetHealScale(), + t->GetSpellScale() ).c_str() ); // See Invisible / Invisible vs. Undead / Hide / Improved Hide - client->Message( + c->Message( Chat::White, fmt::format( "Can See | Invisible: {} Invisible vs. Undead: {}", - target->SeeInvisible() ? "Yes" : "No", - target->SeeInvisibleUndead() ? "Yes" : "No" + t->SeeInvisible() ? "Yes" : "No", + t->SeeInvisibleUndead() ? "Yes" : "No" ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Can See | Hide: {} Improved Hide: {}", - target->SeeHide() ? "Yes" : "No", - target->SeeImprovedHide() ? "Yes" : "No" + t->SeeHide() ? "Yes" : "No", + t->SeeImprovedHide() ? "Yes" : "No" ).c_str() ); // Aggro / Assist Radius - client->Message( + c->Message( Chat::White, fmt::format( "Radius | Aggro: {} Assist: {}", - target->GetAggroRange(), - target->GetAssistRange() + t->GetAggroRange(), + t->GetAssistRange() ).c_str() ); // Emote - if (target->GetEmoteID()) { - client->Message( + if (t->GetEmoteID()) { + c->Message( Chat::White, fmt::format( "Emote: {}", - target->GetEmoteID() + t->GetEmoteID() ).c_str() ); } // Run/Walk Speed - client->Message( + c->Message( Chat::White, fmt::format( "Speed | Run: {} Walk: {}", - target->GetRunspeed(), - target->GetWalkspeed() + t->GetRunspeed(), + t->GetWalkspeed() ).c_str() ); // Position - client->Message( + c->Message( Chat::White, fmt::format( "Position | {}, {}, {}, {}", - target->GetX(), - target->GetY(), - target->GetZ(), - target->GetHeading() + t->GetX(), + t->GetY(), + t->GetZ(), + t->GetHeading() ).c_str() ); // Experience Modifier - client->Message( + c->Message( Chat::White, fmt::format( "Experience Modifier: {}", - target->GetKillExpMod() + t->GetKillExpMod() ).c_str() ); // Quest Globals - client->Message( + c->Message( Chat::White, fmt::format( "Quest Globals: {}", - target->qglobal ? "Enabled" : "Disabled" + t->qglobal ? "Enabled" : "Disabled" ).c_str() ); // Proximity - if (target->IsProximitySet()) { - client->Message( + if (t->IsProximitySet()) { + c->Message( Chat::White, fmt::format( "Proximity | Say: {}", - target->proximity->say ? "Enabled" : "Disabled" + t->proximity->say ? "Enabled" : "Disabled" ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Proximity X | Min: {} Max: {} Range: {}", - target->GetProximityMinX(), - target->GetProximityMaxX(), - (target->GetProximityMaxX() - target->GetProximityMinX()) + t->GetProximityMinX(), + t->GetProximityMaxX(), + (t->GetProximityMaxX() - t->GetProximityMinX()) ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Proximity Y | Min: {} Max: {} Range: {}", - target->GetProximityMinY(), - target->GetProximityMaxY(), - (target->GetProximityMaxY() - target->GetProximityMinY()) + t->GetProximityMinY(), + t->GetProximityMaxY(), + (t->GetProximityMaxY() - t->GetProximityMinY()) ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Proximity Z | Min: {} Max: {} Range: {}", - target->GetProximityMinZ(), - target->GetProximityMaxZ(), - (target->GetProximityMaxZ() - target->GetProximityMinZ()) + t->GetProximityMinZ(), + t->GetProximityMaxZ(), + (t->GetProximityMaxZ() - t->GetProximityMinZ()) ).c_str() ); } // Spawn Data if ( - target->GetGrid() || - target->GetSpawnGroupId() || - target->GetSpawnPointID() + t->GetGrid() || + t->GetSpawnGroupId() || + t->GetSpawnPointID() ) { - client->Message( + c->Message( Chat::White, fmt::format( "Spawn | Group: {} Point: {} Grid: {}", - target->GetSpawnGroupId(), - target->GetSpawnPointID(), - target->GetGrid() + t->GetSpawnGroupId(), + t->GetSpawnPointID(), + t->GetGrid() ).c_str() ); } - client->Message( + c->Message( Chat::White, fmt::format( "Spawn | Raid: {} Rare: {}", - target->IsRaidTarget() ? "Yes" : "No", - target->IsRareSpawn() ? "Yes" : "No", - target->GetSkipGlobalLoot() ? "Yes" : "No" + t->IsRaidTarget() ? "Yes" : "No", + t->IsRareSpawn() ? "Yes" : "No", + t->GetSkipGlobalLoot() ? "Yes" : "No" ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Spawn | Skip Global Loot: {} Ignore Despawn: {}", - target->GetSkipGlobalLoot() ? "Yes" : "No", - target->GetIgnoreDespawn() ? "Yes" : "No" + t->GetSkipGlobalLoot() ? "Yes" : "No", + t->GetIgnoreDespawn() ? "Yes" : "No" ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Spawn | Findable: {} Trackable: {} Underwater: {}", - target->IsFindable() ? "Yes" : "No", - target->IsTrackable() ? "Yes" : "No", - target->IsUnderwaterOnly() ? "Yes" : "No" + t->IsFindable() ? "Yes" : "No", + t->IsTrackable() ? "Yes" : "No", + t->IsUnderwaterOnly() ? "Yes" : "No" ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Spawn | Stuck Behavior: {} Fly Mode: {}", - target->GetStuckBehavior(), - static_cast(target->GetFlyMode()) + t->GetStuckBehavior(), + static_cast(t->GetFlyMode()) ).c_str() ); - client->Message( + c->Message( Chat::White, fmt::format( "Spawn | Aggro NPCs: {} Always Aggro: {}", - target->GetNPCAggro() ? "Yes" : "No", - target->GetAlwaysAggro() ? "Yes" : "No" + t->GetNPCAggro() ? "Yes" : "No", + t->GetAlwaysAggro() ? "Yes" : "No" ).c_str() ); // Race / Class / Gender - client->Message( + c->Message( Chat::White, fmt::format( "Race: {} ({}) Class: {} ({}) Gender: {} ({})", - GetRaceIDName(target->GetRace()), - target->GetRace(), - GetClassIDName(target->GetClass()), - target->GetClass(), - GetGenderName(target->GetGender()), - target->GetGender() + GetRaceIDName(t->GetRace()), + t->GetRace(), + GetClassIDName(t->GetClass()), + t->GetClass(), + GetGenderName(t->GetGender()), + t->GetGender() ).c_str() ); // NPC - client->Message( + c->Message( Chat::White, fmt::format( "NPC | ID: {} Entity ID: {} Name: {}{} Level: {}", - target->GetNPCTypeID(), - target->GetID(), + t->GetNPCTypeID(), + t->GetID(), target_name, ( !target_last_name.empty() ? fmt::format(" ({})", target_last_name) : "" ), - target->GetLevel() + t->GetLevel() ).c_str() ); } @@ -2806,32 +3947,6 @@ bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables) return false; } -bool Mob::IsPlayerClass(uint16 in_class) { - if ( - in_class >= WARRIOR && - in_class <= BERSERKER - ) { - return true; - } - - return false; -} - -bool Mob::IsPlayerRace(uint16 in_race) { - - if ( - (in_race >= HUMAN && in_race <= GNOME) || - in_race == IKSAR || - in_race == VAHSHIR || - in_race == FROGLOK || - in_race == DRAKKIN - ) { - return true; - } - - return false; -} - uint16 Mob::GetFactionRace() { uint16 current_race = GetRace(); if (IsPlayerRace(current_race) || current_race == TREE || @@ -2845,7 +3960,7 @@ uint16 Mob::GetFactionRace() { uint8 Mob::GetDefaultGender(uint16 in_race, uint8 in_gender) { if ( - Mob::IsPlayerRace(in_race) || + IsPlayerRace(in_race) || in_race == RACE_BROWNIE_15 || in_race == RACE_KERRAN_23 || in_race == RACE_LION_50 || diff --git a/zone/mob.h b/zone/mob.h index 2fb3c2805..6f27be3d0 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -801,8 +801,6 @@ public: //Util static uint32 RandomTimer(int min, int max); static uint8 GetDefaultGender(uint16 in_race, uint8 in_gender = 0xFF); - static bool IsPlayerClass(uint16 in_class); - static bool IsPlayerRace(uint16 in_race); EQ::skills::SkillType GetSkillByItemType(int ItemType); uint8 GetItemTypeBySkill(EQ::skills::SkillType skill); virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr); @@ -811,6 +809,7 @@ public: char GetCasterClass() const; uint8 GetArchetype() const; void SetZone(uint32 zone_id, uint32 instance_id); + void SendStatsWindow(Client* c, bool use_window); void ShowStats(Client* client); void ShowBuffs(Client* c); bool PlotPositionAroundTarget(Mob* target, float &x_dest, float &y_dest, float &z_dest, bool lookForAftArc = true);