mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 12:41:30 +00:00
* [Zone State] Additional improvements * Return early * Update zone_save_state.cpp * Push * Push * Update zone.cpp * Update zone_save_state.cpp * Equip items that were dynamically added on restore * IsZoneStateValid helper * ZoneStateSpawnsRepository::PurgeInvalidZoneStates * Add Zone:StateSaveClearDays and PurgeOldZoneStates * spawn2 / unique_spawn block when restored from zone state * One time purge * Update zone_state_spawns_repository.h * Update npc.cpp * Update npc.cpp * test * ORDER BY spawn2_id * Stuff * Restored corpses shouldn't trigger events * Fix weird edge case
858 lines
24 KiB
C++
858 lines
24 KiB
C++
/**
|
|
* EQEmulator: Everquest Server Emulator
|
|
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
* are required to give you total support for your newly bought product;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include "client.h"
|
|
#include "mob.h"
|
|
#include "npc_scale_manager.h"
|
|
|
|
inline std::string GetMobAttributeByString(Mob *mob, const std::string &attribute)
|
|
{
|
|
std::string entity_variable = "modify_stat_" + attribute;
|
|
std::string scaling_modified;
|
|
if (mob->EntityVariableExists(entity_variable)) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
if (attribute == "ac") {
|
|
if (mob->EntityVariableExists("modify_stat_max_hp")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string(mob->GetAC())) + scaling_modified;
|
|
}
|
|
|
|
if (attribute == "atk") {
|
|
return std::to_string(mob->GetATK()) + scaling_modified;
|
|
}
|
|
|
|
if (attribute == "end") {
|
|
int64 endurance = 0;
|
|
if (mob->IsClient()) {
|
|
endurance = mob->CastToClient()->GetEndurance();
|
|
}
|
|
|
|
return Strings::Commify(std::to_string(endurance));
|
|
}
|
|
|
|
if (attribute == "hp") {
|
|
return Strings::Commify(std::to_string(mob->GetHP()));
|
|
}
|
|
|
|
if (attribute == "hp_min_max") {
|
|
if (mob->EntityVariableExists("modify_stat_max_hp")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string(mob->GetHP())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxHP())) + " (" +
|
|
std::to_string((int) mob->GetHPRatio()) + "%)";
|
|
}
|
|
|
|
if (attribute == "mana") {
|
|
return Strings::Commify(std::to_string(mob->GetMana()));
|
|
}
|
|
|
|
if (attribute == "mp_min_max") {
|
|
return Strings::Commify(std::to_string(mob->GetMana())) + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxMana())) + " (" +
|
|
std::to_string((int) mob->GetManaPercent()) + "%)";
|
|
}
|
|
|
|
if (attribute == "end_min_max") {
|
|
return Strings::Commify(std::to_string(mob->GetEndurance())) + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxEndurance())) + " (" +
|
|
std::to_string((int)mob->GetEndurancePercent()) + "%)";
|
|
}
|
|
|
|
if (attribute == "str") {
|
|
return Strings::Commify(std::to_string(mob->GetSTR())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxSTR())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicSTR()));
|
|
}
|
|
|
|
if (attribute == "sta") {
|
|
return Strings::Commify(std::to_string(mob->GetSTA())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxSTA())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicSTA()));
|
|
}
|
|
|
|
if (attribute == "dex") {
|
|
return Strings::Commify(std::to_string(mob->GetDEX())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxDEX())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicDEX()));
|
|
}
|
|
|
|
if (attribute == "agi") {
|
|
return Strings::Commify(std::to_string(mob->GetAGI())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxAGI())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicAGI()));
|
|
}
|
|
|
|
if (attribute == "int") {
|
|
return Strings::Commify(std::to_string(mob->GetINT())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxINT())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicINT()));
|
|
}
|
|
|
|
if (attribute == "wis") {
|
|
return Strings::Commify(std::to_string(mob->GetWIS())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxWIS())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicWIS()));
|
|
}
|
|
|
|
if (attribute == "cha") {
|
|
return Strings::Commify(std::to_string(mob->GetCHA())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxCHA())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicCHA()));
|
|
}
|
|
|
|
if (attribute == "mr") {
|
|
return Strings::Commify(std::to_string(mob->GetMR())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxMR())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicMR()));
|
|
}
|
|
|
|
if (attribute == "cr") {
|
|
return Strings::Commify(std::to_string(mob->GetCR())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxCR())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicCR()));
|
|
}
|
|
|
|
if (attribute == "fr") {
|
|
return Strings::Commify(std::to_string(mob->GetFR())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxFR())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicFR()));
|
|
}
|
|
|
|
if (attribute == "pr") {
|
|
return Strings::Commify(std::to_string(mob->GetPR())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxPR())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicPR()));
|
|
}
|
|
|
|
if (attribute == "dr") {
|
|
return Strings::Commify(std::to_string(mob->GetDR())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxDR())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicDR()));
|
|
}
|
|
|
|
if (attribute == "cr") {
|
|
return Strings::Commify(std::to_string(mob->GetCR())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxCR())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicCR()));
|
|
}
|
|
|
|
if (attribute == "pr") {
|
|
return Strings::Commify(std::to_string(mob->GetPR())) + scaling_modified + " / " +
|
|
Strings::Commify(std::to_string(mob->GetMaxPR())) + " +" +
|
|
Strings::Commify(std::to_string(mob->GetHeroicPR()));
|
|
}
|
|
|
|
if (attribute == "cor") {
|
|
return Strings::Commify(std::to_string(mob->GetCorrup())) + scaling_modified;
|
|
}
|
|
|
|
if (attribute == "phy") {
|
|
return Strings::Commify(std::to_string(mob->GetPhR())) + scaling_modified;
|
|
}
|
|
|
|
if (attribute == "name") {
|
|
return mob->GetCleanName();
|
|
}
|
|
|
|
if (attribute == "surname") {
|
|
std::string last_name = mob->GetLastName();
|
|
return (last_name.length() > 0 ? mob->GetLastName() : " ");
|
|
}
|
|
|
|
if (attribute == "race") {
|
|
return GetRaceIDName(mob->GetRace());
|
|
}
|
|
|
|
if (attribute == "class") {
|
|
return GetClassIDName(mob->GetClass(), 0);
|
|
}
|
|
|
|
if (attribute == "level") {
|
|
return std::to_string(mob->GetLevel());
|
|
}
|
|
|
|
if (attribute == "flymode") {
|
|
return std::to_string(mob->GetFlyMode());
|
|
}
|
|
|
|
if (attribute == "maxbuffslots") {
|
|
return std::to_string(mob->GetMaxBuffSlots());
|
|
}
|
|
|
|
if (attribute == "can_open_doors") {
|
|
return std::to_string(mob->CanOpenDoors());
|
|
}
|
|
|
|
if (attribute == "curbuffslots") {
|
|
return std::to_string(mob->GetCurrentBuffSlots());
|
|
}
|
|
|
|
if (attribute == "tohit") {
|
|
return std::to_string(mob->compute_tohit(EQ::skills::SkillHandtoHand));
|
|
}
|
|
|
|
if (attribute == "total_to_hit") {
|
|
return std::to_string(mob->GetTotalToHit(EQ::skills::SkillHandtoHand, 0));
|
|
}
|
|
|
|
if (attribute == "defense") {
|
|
return std::to_string(mob->compute_defense());
|
|
}
|
|
|
|
if (attribute == "total_defense") {
|
|
return std::to_string(mob->GetTotalDefense());
|
|
}
|
|
|
|
if (attribute == "offense") {
|
|
return std::to_string(mob->offense(EQ::skills::SkillHandtoHand));
|
|
}
|
|
|
|
if (attribute == "mitigation_ac") {
|
|
return std::to_string(mob->GetMitigationAC());
|
|
}
|
|
|
|
if (attribute == "haste") {
|
|
if (mob->IsClient()) {
|
|
return Strings::Commify(std::to_string(mob->CastToClient()->GetHaste()));
|
|
}
|
|
else {
|
|
return Strings::Commify(std::to_string(mob->GetHaste()));
|
|
}
|
|
}
|
|
|
|
if (mob->IsNPC()) {
|
|
NPC *npc = mob->CastToNPC();
|
|
|
|
if (attribute == "npcid") {
|
|
return std::to_string(npc->GetNPCTypeID());
|
|
}
|
|
if (attribute == "texture") {
|
|
return std::to_string(npc->GetTexture());
|
|
}
|
|
if (attribute == "bodytype") {
|
|
return std::to_string(npc->GetBodyType());
|
|
}
|
|
if (attribute == "gender") {
|
|
return std::to_string(npc->GetGender());
|
|
}
|
|
if (attribute == "size") {
|
|
return std::to_string((int)npc->GetSize());
|
|
}
|
|
if (attribute == "runspeed") {
|
|
return std::to_string(npc->GetRunspeed());
|
|
}
|
|
if (attribute == "walkspeed") {
|
|
return std::to_string(npc->GetWalkspeed());
|
|
}
|
|
if (attribute == "spawngroup") {
|
|
return std::to_string(npc->GetSpawnGroupId());
|
|
}
|
|
if (attribute == "grid") {
|
|
return std::to_string(npc->GetGrid());
|
|
}
|
|
if (attribute == "emote") {
|
|
return std::to_string(npc->GetEmoteID());
|
|
}
|
|
if (attribute == "see_invis") {
|
|
return std::to_string(npc->SeeInvisible());
|
|
}
|
|
if (attribute == "see_invis_undead") {
|
|
return std::to_string(npc->SeeInvisibleUndead());
|
|
}
|
|
if (attribute == "faction") {
|
|
return std::to_string(npc->GetNPCFactionID());
|
|
}
|
|
if (attribute == "loottable") {
|
|
return std::to_string(npc->GetLoottableID());
|
|
}
|
|
if (attribute == "prim_skill") {
|
|
return std::to_string(npc->GetPrimSkill());
|
|
}
|
|
if (attribute == "sec_skill") {
|
|
return std::to_string(npc->GetSecSkill());
|
|
}
|
|
if (attribute == "melee_texture_1") {
|
|
return std::to_string(npc->GetMeleeTexture1());
|
|
}
|
|
if (attribute == "melee_texture_2") {
|
|
return std::to_string(npc->GetMeleeTexture2());
|
|
}
|
|
if (attribute == "aggrorange") {
|
|
return std::to_string((int)npc->GetAggroRange());
|
|
}
|
|
if (attribute == "assistrange") {
|
|
return std::to_string((int)npc->GetAssistRange());
|
|
}
|
|
if (attribute == "findable") {
|
|
return std::to_string(npc->IsFindable());
|
|
}
|
|
if (attribute == "trackable") {
|
|
return std::to_string(npc->IsTrackable());
|
|
}
|
|
if (attribute == "spells_id") {
|
|
return std::to_string(npc->GetNPCSpellsID());
|
|
}
|
|
if (attribute == "roambox_min_x") {
|
|
return std::to_string((int)npc->GetRoamboxMinX());
|
|
}
|
|
if (attribute == "roambox_max_x") {
|
|
return std::to_string((int)npc->GetRoamboxMaxX());
|
|
}
|
|
if (attribute == "roambox_min_y") {
|
|
return std::to_string((int)npc->GetRoamboxMinY());
|
|
}
|
|
if (attribute == "roambox_max_y") {
|
|
return std::to_string((int)npc->GetRoamboxMaxY());
|
|
}
|
|
if (attribute == "roambox_min_delay") {
|
|
return std::to_string((int)npc->GetRoamboxMinDelay());
|
|
}
|
|
if (attribute == "roambox_delay") {
|
|
return std::to_string((int)npc->GetRoamboxDelay());
|
|
}
|
|
if (attribute == "roambox_distance") {
|
|
return std::to_string((int)npc->GetRoamboxDistance());
|
|
}
|
|
if (attribute == "proximity_min_x") {
|
|
return std::to_string((int)npc->GetProximityMinX());
|
|
}
|
|
if (attribute == "proximity_max_x") {
|
|
return std::to_string((int)npc->GetProximityMaxX());
|
|
}
|
|
if (attribute == "proximity_min_y") {
|
|
return std::to_string((int)npc->GetProximityMinY());
|
|
}
|
|
if (attribute == "proximity_max_y") {
|
|
return std::to_string((int)npc->GetProximityMaxY());
|
|
}
|
|
if (attribute == "proximity_min_z") {
|
|
return std::to_string((int)npc->GetProximityMinZ());
|
|
}
|
|
if (attribute == "proximity_max_z") {
|
|
return std::to_string((int)npc->GetProximityMaxZ());
|
|
}
|
|
if (attribute == "accuracy") {
|
|
return std::to_string(npc->GetAccuracyRating()) + scaling_modified;
|
|
}
|
|
if (attribute == "slow_mitigation") {
|
|
if (mob->EntityVariableExists("modify_stat_slow_mitigation")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return std::to_string((int)npc->GetSlowMitigation()) + scaling_modified;
|
|
}
|
|
if (attribute == "min_hit") {
|
|
if (mob->EntityVariableExists("modify_stat_min_hit")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string((int) npc->GetMinDMG())) + scaling_modified;
|
|
}
|
|
if (attribute == "max_hit") {
|
|
if (mob->EntityVariableExists("modify_stat_max_hit")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string((int) npc->GetMaxDMG())) + scaling_modified;
|
|
}
|
|
if (attribute == "hp_regen") {
|
|
if (mob->EntityVariableExists("modify_stat_hp_regen")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string(npc->GetHPRegen())) + scaling_modified;
|
|
}
|
|
|
|
if (attribute == "hp_regen_per_second") {
|
|
if (mob->EntityVariableExists("modify_stat_hp_regen_per_second")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string(npc->GetHPRegenPerSecond())) + scaling_modified;
|
|
}
|
|
|
|
if (attribute == "attack_delay") {
|
|
if (mob->EntityVariableExists("modify_stat_attack_delay")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string(npc->GetAttackDelay())) + scaling_modified;
|
|
}
|
|
if (attribute == "spell_scale") {
|
|
if (mob->EntityVariableExists("modify_stat_spell_scale")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string((int) npc->GetSpellScale())) + scaling_modified;
|
|
}
|
|
if (attribute == "heal_scale") {
|
|
if (mob->EntityVariableExists("modify_stat_heal_scale")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string((int) npc->GetHealScale())) + scaling_modified;
|
|
}
|
|
if (attribute == "avoidance") {
|
|
if (mob->EntityVariableExists("modify_stat_avoidance")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string(npc->GetAvoidanceRating())) + scaling_modified;
|
|
}
|
|
|
|
if (attribute == "heroic_strikethrough") {
|
|
if (mob->EntityVariableExists("modify_stat_heroic_strikethrough")) {
|
|
scaling_modified = " *";
|
|
}
|
|
|
|
return Strings::Commify(std::to_string(npc->GetHeroicStrikethrough())) + scaling_modified;
|
|
}
|
|
|
|
npc->GetNPCEmote(npc->GetEmoteID(), 0);
|
|
}
|
|
|
|
if (mob->IsClient()) {
|
|
Client *client = mob->CastToClient();
|
|
|
|
if (attribute == "shielding") {
|
|
return Strings::Commify(std::to_string(client->GetShielding())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemShieldingCap)));
|
|
}
|
|
if (attribute == "spell_shielding") {
|
|
return Strings::Commify(std::to_string(client->GetSpellShield())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemSpellShieldingCap)));
|
|
}
|
|
if (attribute == "dot_shielding") {
|
|
return Strings::Commify(std::to_string(client->GetDoTShield())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemDoTShieldingCap)));
|
|
}
|
|
if (attribute == "stun_resist") {
|
|
return Strings::Commify(std::to_string(client->GetStunResist())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemStunResistCap)));
|
|
}
|
|
if (attribute == "damage_shield") {
|
|
return Strings::Commify(std::to_string(client->GetDS())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemDamageShieldCap)));
|
|
}
|
|
if (attribute == "avoidance") {
|
|
return Strings::Commify(std::to_string(client->GetAvoidance())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemAvoidanceCap)));
|
|
}
|
|
if (attribute == "strikethrough") {
|
|
return Strings::Commify(std::to_string(client->GetStrikeThrough())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemStrikethroughCap)));
|
|
}
|
|
if (attribute == "accuracy") {
|
|
return Strings::Commify(std::to_string(client->GetAccuracy())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemAccuracyCap)));
|
|
}
|
|
if (attribute == "combat_effects") {
|
|
return Strings::Commify(std::to_string(client->GetCombatEffects())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemCombatEffectsCap)));
|
|
}
|
|
if (attribute == "heal_amount") {
|
|
return Strings::Commify(std::to_string(client->GetHealAmt())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemHealAmtCap)));
|
|
}
|
|
if (attribute == "spell_dmg") {
|
|
return Strings::Commify(std::to_string(client->GetSpellDmg())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemSpellDmgCap)));
|
|
}
|
|
if (attribute == "clairvoyance") {
|
|
return Strings::Commify(std::to_string(client->GetClair())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemClairvoyanceCap)));
|
|
}
|
|
if (attribute == "ds_mitigation") {
|
|
return Strings::Commify(std::to_string(client->GetDSMit())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemDSMitigationCap)));
|
|
}
|
|
if (attribute == "hp_regen") {
|
|
return Strings::Commify(std::to_string(client->GetHPRegen())) + " / " +
|
|
Strings::Commify(std::to_string(RuleI(Character, ItemHealthRegenCap)));
|
|
}
|
|
if (attribute == "mana_regen") {
|
|
return Strings::Commify(std::to_string(client->GetManaRegen())) + " / " +
|
|
Strings::Commify(std::to_string((int64) RuleI(Character, ItemManaRegenCap)));
|
|
}
|
|
if (attribute == "end_regen") {
|
|
return Strings::Commify(std::to_string((int) client->CalcEnduranceRegen())) + " / " +
|
|
Strings::Commify(std::to_string((int) client->CalcEnduranceRegenCap()));
|
|
}
|
|
}
|
|
|
|
if (attribute == "type") {
|
|
std::string entity_type = "Mob";
|
|
|
|
if (mob->IsCorpse()) {
|
|
entity_type = "Corpse";
|
|
}
|
|
|
|
if (mob->IsNPC()) {
|
|
entity_type = "NPC";
|
|
}
|
|
|
|
if (mob->IsClient()) {
|
|
entity_type = "Client";
|
|
}
|
|
|
|
return entity_type;
|
|
}
|
|
|
|
return "null";
|
|
}
|
|
|
|
inline std::string WriteDisplayInfoSection(
|
|
Mob *mob,
|
|
const std::string §ion_name,
|
|
const std::vector<std::string>& attributes_list,
|
|
int column_count = 3,
|
|
bool display_section_name = false
|
|
)
|
|
{
|
|
std::string text;
|
|
|
|
if (display_section_name) {
|
|
text += "<c \"#FFFF66\">" + section_name + "</c><br>";
|
|
}
|
|
|
|
text += "<table><tbody>";
|
|
|
|
int index = 0;
|
|
bool first_row = true;
|
|
|
|
for (const auto &attribute : attributes_list) {
|
|
if (index == 0) {
|
|
if (first_row) {
|
|
text += "<tr>\n";
|
|
first_row = false;
|
|
}
|
|
else {
|
|
text += "</tr><tr>\n";
|
|
}
|
|
|
|
}
|
|
|
|
std::string attribute_name = attribute;
|
|
|
|
Strings::FindReplace(attribute_name, "_min_max", std::string(""));
|
|
|
|
/**
|
|
* Translate attribute names with underscores
|
|
* "total_to_hit" = "Total To Hit"
|
|
*/
|
|
if (attribute_name.find('_') != std::string::npos) {
|
|
auto split_string = Strings::Split(attribute_name, '_');
|
|
std::string new_attribute_name;
|
|
for (const std::string &string_value : split_string) {
|
|
new_attribute_name += Strings::UcFirst(string_value) + " ";
|
|
}
|
|
attribute_name = new_attribute_name;
|
|
}
|
|
|
|
/**
|
|
* Attribute names less than 4 characters get capitalized
|
|
* "hp" = "HP"
|
|
*/
|
|
if (attribute_name.length() <= 3) {
|
|
attribute_name = Strings::ToUpper(attribute_name);
|
|
}
|
|
|
|
/**
|
|
* Attribute names larger than 3 characters get capitalized first letter
|
|
* "avoidance" = "Avoidance"
|
|
*/
|
|
if (attribute_name.length() > 3) {
|
|
attribute_name = Strings::UcFirst(attribute_name);
|
|
}
|
|
|
|
Strings::FindReplace(attribute_name, "Proximity", std::string(""));
|
|
Strings::FindReplace(attribute_name, "Roambox", std::string(""));
|
|
|
|
std::string attribute_value = GetMobAttributeByString(mob, attribute);
|
|
|
|
if (attribute_value.length() <= 0) {
|
|
continue;
|
|
}
|
|
|
|
text += "<td>" + attribute_name + "</td><td>" + GetMobAttributeByString(mob, attribute) + "</td>";
|
|
|
|
if (index == column_count) {
|
|
index = 0;
|
|
continue;
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
text += "</tr></tbody></table>";
|
|
|
|
return text;
|
|
}
|
|
|
|
inline void NPCCommandsMenu(Client* client, NPC* npc)
|
|
{
|
|
std::string menu_commands;
|
|
|
|
if (npc->GetGrid() > 0) {
|
|
menu_commands += "[" + Saylink::Silent("#grid show", "Grid Points") + "] ";
|
|
}
|
|
|
|
if (npc->GetEmoteID() > 0) {
|
|
menu_commands += "[" + Saylink::Silent(fmt::format("#emotesearch {}", npc->GetEmoteID()), "Emotes") + "] ";
|
|
}
|
|
|
|
if (npc->GetLoottableID() > 0) {
|
|
menu_commands += "[" + Saylink::Silent("#npcloot show", "Loot") + "] ";
|
|
if (npc) {
|
|
menu_commands += fmt::format(" Item(s) ({}) ", npc->GetLootItems().size());
|
|
}
|
|
}
|
|
|
|
if (npc->IsProximitySet()) {
|
|
menu_commands += "[" + Saylink::Silent("#proximity show", "Proximity") + "] ";
|
|
}
|
|
|
|
if (menu_commands.length() > 0) {
|
|
const auto& dev_menu = Saylink::Silent("#devtools", "DevTools");
|
|
client->Message(
|
|
Chat::White,
|
|
fmt::format(
|
|
"| [{}] [Show Commands] {}",
|
|
dev_menu,
|
|
menu_commands
|
|
).c_str()
|
|
);
|
|
}
|
|
}
|
|
|
|
void Mob::DisplayInfo(Mob *mob)
|
|
{
|
|
if (!mob) {
|
|
return;
|
|
}
|
|
|
|
if (IsClient()) {
|
|
|
|
std::string window_text = "<c \"#FFFF66\">*Drag window open vertically to see all</c><br>";
|
|
|
|
Client *client = CastToClient();
|
|
|
|
if (!client->IsDevToolsEnabled()) {
|
|
return;
|
|
}
|
|
|
|
std::vector<std::string> info_attributes = {
|
|
"name",
|
|
"race",
|
|
"surname",
|
|
"class",
|
|
};
|
|
window_text += WriteDisplayInfoSection(mob, "Info", info_attributes, 1, false);
|
|
|
|
std::vector<std::string> basic_attributes = {
|
|
"type",
|
|
"level",
|
|
"hp_min_max",
|
|
"ac",
|
|
"mp_min_max",
|
|
"atk",
|
|
"end_min_max",
|
|
};
|
|
window_text += WriteDisplayInfoSection(mob, "Main", basic_attributes, 1, false);
|
|
|
|
std::vector<std::string> stat_attributes = {
|
|
"str",
|
|
"sta",
|
|
"agi",
|
|
"dex",
|
|
"wis",
|
|
"int",
|
|
"cha",
|
|
};
|
|
window_text += WriteDisplayInfoSection(mob, "Statistics", stat_attributes, 1, false);
|
|
|
|
std::vector<std::string> resist_attributes = {
|
|
"pr",
|
|
"mr",
|
|
"dr",
|
|
"fr",
|
|
"cr",
|
|
"cor",
|
|
"phy",
|
|
};
|
|
window_text += WriteDisplayInfoSection(mob, "Resists", resist_attributes, 1, false);
|
|
|
|
std::vector<std::string> calculations = {
|
|
"tohit",
|
|
"total_to_hit",
|
|
"defense",
|
|
"total_defense",
|
|
"offense",
|
|
"mitigation_ac",
|
|
"haste",
|
|
};
|
|
window_text += WriteDisplayInfoSection(mob, "Calculations", calculations, 1, true);
|
|
|
|
if (mob->IsClient()) {
|
|
std::vector<std::string> mods = {
|
|
"hp_regen",
|
|
"mana_regen",
|
|
"end_regen",
|
|
"heal_amount",
|
|
"spell_dmg",
|
|
"clairvoyance",
|
|
};
|
|
window_text += WriteDisplayInfoSection(mob, "Mods", mods, 1, true);
|
|
|
|
std::vector<std::string> mod_defensive = {
|
|
"shielding",
|
|
"spell_shielding",
|
|
"dot_shielding",
|
|
"stun_resist",
|
|
"damage_shield",
|
|
"ds_mitigation",
|
|
"avoidance",
|
|
};
|
|
|
|
window_text += WriteDisplayInfoSection(mob, "Mod Defensive", mod_defensive, 1, true);
|
|
|
|
std::vector<std::string> mod_offensive = {
|
|
"strikethrough",
|
|
"accuracy",
|
|
"combat_effects",
|
|
};
|
|
window_text += WriteDisplayInfoSection(mob, "Mod Offensive", mod_offensive, 1, true);
|
|
}
|
|
|
|
if (mob->IsNPC()) {
|
|
NPC *npc = mob->CastToNPC();
|
|
|
|
std::vector<std::string> npc_stats = {
|
|
"accuracy",
|
|
"slow_mitigation",
|
|
"min_hit",
|
|
"max_hit",
|
|
"hp_regen",
|
|
"hp_regen_per_second",
|
|
"attack_delay",
|
|
"spell_scale",
|
|
"heal_scale",
|
|
"avoidance",
|
|
"heroic_strikethrough",
|
|
};
|
|
|
|
window_text += WriteDisplayInfoSection(mob, "NPC Stats", npc_stats, 1, true);
|
|
|
|
std::vector<std::string> npc_attributes = {
|
|
"npcid",
|
|
"texture",
|
|
"bodytype",
|
|
"gender",
|
|
"size",
|
|
"runspeed",
|
|
"walkspeed",
|
|
"spawngroup",
|
|
"grid",
|
|
"emote",
|
|
"see_invis",
|
|
"see_invis_undead",
|
|
"faction",
|
|
"loottable",
|
|
"prim_skill",
|
|
"sec_skill",
|
|
"melee_texture_1",
|
|
"melee_texture_2",
|
|
"aggrorange",
|
|
"assistrange",
|
|
"findable",
|
|
"trackable",
|
|
"flymode",
|
|
"spells_id",
|
|
"curbuffslots",
|
|
"maxbuffslots",
|
|
"can_open_doors",
|
|
};
|
|
|
|
window_text += WriteDisplayInfoSection(mob, "NPC Attributes", npc_attributes, 1, true);
|
|
|
|
/**
|
|
* Print Roambox
|
|
*/
|
|
if (npc->GetRoamboxMaxX() != 0 && npc->GetRoamboxMinX() != 0) {
|
|
std::vector<std::string> npc_roambox = {
|
|
"roambox_min_x",
|
|
"roambox_max_x",
|
|
"roambox_min_y",
|
|
"roambox_max_y",
|
|
"roambox_min_delay",
|
|
"roambox_delay",
|
|
"roambox_distance",
|
|
};
|
|
|
|
window_text += WriteDisplayInfoSection(mob, "Roambox", npc_roambox, 1, true);
|
|
}
|
|
|
|
if (npc->proximity != nullptr) {
|
|
std::vector<std::string> npc_proximity = {
|
|
"proximity_min_x",
|
|
"proximity_max_x",
|
|
"proximity_min_y",
|
|
"proximity_max_y",
|
|
"proximity_min_z",
|
|
"proximity_max_z",
|
|
};
|
|
|
|
window_text += WriteDisplayInfoSection(mob, "Proximity", npc_proximity, 1, true);
|
|
}
|
|
|
|
client->Message(
|
|
Chat::White,
|
|
fmt::format(
|
|
"| # Target: {} Type: {} ({})",
|
|
npc->GetCleanName(),
|
|
npc_scale_manager->GetNPCScalingType(npc),
|
|
npc_scale_manager->GetNPCScalingTypeName(npc)
|
|
).c_str()
|
|
);
|
|
|
|
NPCCommandsMenu(client, npc);
|
|
}
|
|
|
|
if (client->GetDisplayMobInfoWindow()) {
|
|
client->SendFullPopup(
|
|
"GM: Entity Info",
|
|
window_text.c_str(),
|
|
EQ::popupresponse::MOB_INFO_DISMISS,
|
|
0,
|
|
100,
|
|
0,
|
|
"Snooze",
|
|
"OK"
|
|
);
|
|
}
|
|
}
|
|
}
|