diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index db97818a5..5ae2c1a93 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -1184,15 +1184,15 @@ struct SpecialMesg_Struct ** When somebody changes what they're wearing or give a pet a weapon (model changes) ** Length: 19 Bytes */ -struct WearChange_Struct{ -/*000*/ uint16 spawn_id; -/*002*/ uint32 material; -/*006*/ uint32 unknown06; -/*010*/ uint32 elite_material; // 1 for Drakkin Elite Material -/*014*/ uint32 hero_forge_model; // New to VoA -/*018*/ uint32 unknown18; // New to RoF +struct WearChange_Struct { +/*000*/ uint16 spawn_id; +/*002*/ uint32 material; +/*006*/ uint32 unknown06; +/*010*/ uint32 elite_material; // 1 for Drakkin Elite Material +/*014*/ uint32 hero_forge_model; // New to VoA +/*018*/ uint32 unknown18; // New to RoF /*022*/ EQEmu::textures::Tint_Struct color; -/*026*/ uint8 wear_slot_id; +/*026*/ uint8 wear_slot_id; /*027*/ }; diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index be646432a..fb42ac8b4 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -93,6 +93,7 @@ namespace Logs { Traps, NPCRoamBox, NPCScaling, + MobAppearance, MaxCategoryID /* Don't Remove this */ }; @@ -151,7 +152,8 @@ namespace Logs { "Food", "Traps", "NPC Roam Box", - "NPC Scaling" + "NPC Scaling", + "Mob Appearance" }; } diff --git a/common/item_instance.cpp b/common/item_instance.cpp index ea7e94428..2c186e066 100644 --- a/common/item_instance.cpp +++ b/common/item_instance.cpp @@ -84,6 +84,7 @@ EQEmu::ItemInstance::ItemInstance(const ItemData* item, int16 charges) { m_ornamentidfile = 0; m_ornament_hero_model = 0; m_recast_timestamp = 0; + m_new_id_file = 0; } EQEmu::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) { @@ -117,6 +118,7 @@ EQEmu::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 char m_ornamentidfile = 0; m_ornament_hero_model = 0; m_recast_timestamp = 0; + m_new_id_file = 0; } EQEmu::ItemInstance::ItemInstance(ItemInstTypes use_type) { @@ -138,6 +140,7 @@ EQEmu::ItemInstance::ItemInstance(ItemInstTypes use_type) { m_ornamentidfile = 0; m_ornament_hero_model = 0; m_recast_timestamp = 0; + m_new_id_file = 0; } // Make a copy of an EQEmu::ItemInstance object @@ -195,6 +198,7 @@ EQEmu::ItemInstance::ItemInstance(const ItemInstance& copy) m_ornamentidfile = copy.m_ornamentidfile; m_ornament_hero_model = copy.m_ornament_hero_model; m_recast_timestamp = copy.m_recast_timestamp; + m_new_id_file = copy.m_new_id_file; } // Clean up container contents diff --git a/common/item_instance.h b/common/item_instance.h index 6566fd77e..d38ad0868 100644 --- a/common/item_instance.h +++ b/common/item_instance.h @@ -203,6 +203,8 @@ namespace EQEmu void SetOrnamentIcon(uint32 ornament_icon) { m_ornamenticon = ornament_icon; } uint32 GetOrnamentationIDFile() const { return m_ornamentidfile; } void SetOrnamentationIDFile(uint32 ornament_idfile) { m_ornamentidfile = ornament_idfile; } + uint32 GetNewIDFile() const { return m_new_id_file; } + void SetNewIDFile(uint32 new_id_file) { m_new_id_file = new_id_file; } uint32 GetOrnamentHeroModel(int32 material_slot = -1) const; void SetOrnamentHeroModel(uint32 ornament_hero_model) { m_ornament_hero_model = ornament_hero_model; } uint32 GetRecastTimestamp() const { return m_recast_timestamp; } @@ -306,6 +308,7 @@ namespace EQEmu bool m_scaling; uint32 m_ornamenticon; uint32 m_ornamentidfile; + uint32 m_new_id_file; uint32 m_ornament_hero_model; uint32 m_recast_timestamp; diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index d65ea4cba..cb9e468fb 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -5488,8 +5488,16 @@ namespace RoF2 ob.write(item->Lore, strlen(item->Lore)); ob.write("\0", 1); - if (strlen(item->IDFile) > 0) + if (inst->GetNewIDFile() > 0) { + char new_id_file[30]; + memset(new_id_file, 0x0, 30); + sprintf(new_id_file, "IT%d", inst->GetNewIDFile()); + ob.write(new_id_file, strlen(new_id_file)); + } + else if (strlen(item->IDFile) > 0) { ob.write(item->IDFile, strlen(item->IDFile)); + } + ob.write("\0", 1); ob.write("\0", 1); diff --git a/common/textures.h b/common/textures.h index a39f4c007..f489977ce 100644 --- a/common/textures.h +++ b/common/textures.h @@ -65,6 +65,12 @@ namespace EQEmu uint32 Unknown2; // same as material? }; + struct InternalTexture_Struct { + uint32 HerosForgeModel; + uint32 Material; + uint32 Color; + }; + struct TextureMaterial_Struct { uint32 Material; }; @@ -100,6 +106,23 @@ namespace EQEmu }; }; + struct InternalTextureProfile { + union { + struct { + textures::InternalTexture_Struct Head; + textures::InternalTexture_Struct Chest; + textures::InternalTexture_Struct Arms; + textures::InternalTexture_Struct Wrist; + textures::InternalTexture_Struct Hands; + textures::InternalTexture_Struct Legs; + textures::InternalTexture_Struct Feet; + textures::InternalTexture_Struct Primary; + textures::InternalTexture_Struct Secondary; + }; + textures::InternalTexture_Struct Slot[textures::materialCount]; + }; + }; + struct TextureMaterialProfile { union { struct { diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index 7eaafb9d7..c92102a2d 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -82,6 +82,7 @@ SET(zone_sources merc.cpp mob.cpp mob_ai.cpp + mob_appearance.cpp mob_movement_manager.cpp mob_info.cpp mod_functions.cpp diff --git a/zone/aa.cpp b/zone/aa.cpp index 1f5f9328d..cb2e6ab7e 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -286,7 +286,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) make_npc->min_dmg = 1; //base stats - make_npc->cur_hp = (GetLevel() * 55); + make_npc->current_hp = (GetLevel() * 55); make_npc->max_hp = (GetLevel() * 55); make_npc->STR = 85 + (GetLevel() * 3); make_npc->STA = 85 + (GetLevel() * 3); @@ -356,51 +356,51 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) case PALADIN: //SPECATK_TRIPLE strcpy(make_npc->special_abilities, "6,1"); - make_npc->cur_hp = make_npc->cur_hp * 150 / 100; + make_npc->current_hp = make_npc->current_hp * 150 / 100; make_npc->max_hp = make_npc->max_hp * 150 / 100; make_npc->npc_spells_id = 8; break; case SHADOWKNIGHT: strcpy(make_npc->special_abilities, "6,1"); - make_npc->cur_hp = make_npc->cur_hp * 150 / 100; + make_npc->current_hp = make_npc->current_hp * 150 / 100; make_npc->max_hp = make_npc->max_hp * 150 / 100; make_npc->npc_spells_id = 9; break; case RANGER: strcpy(make_npc->special_abilities, "7,1"); - make_npc->cur_hp = make_npc->cur_hp * 135 / 100; + make_npc->current_hp = make_npc->current_hp * 135 / 100; make_npc->max_hp = make_npc->max_hp * 135 / 100; make_npc->npc_spells_id = 10; break; case BARD: strcpy(make_npc->special_abilities, "6,1"); - make_npc->cur_hp = make_npc->cur_hp * 110 / 100; + make_npc->current_hp = make_npc->current_hp * 110 / 100; make_npc->max_hp = make_npc->max_hp * 110 / 100; make_npc->npc_spells_id = 11; break; case BEASTLORD: strcpy(make_npc->special_abilities, "7,1"); - make_npc->cur_hp = make_npc->cur_hp * 110 / 100; + make_npc->current_hp = make_npc->current_hp * 110 / 100; make_npc->max_hp = make_npc->max_hp * 110 / 100; make_npc->npc_spells_id = 12; break; case ROGUE: strcpy(make_npc->special_abilities, "7,1"); make_npc->max_dmg = make_npc->max_dmg * 150 /100; - make_npc->cur_hp = make_npc->cur_hp * 110 / 100; + make_npc->current_hp = make_npc->current_hp * 110 / 100; make_npc->max_hp = make_npc->max_hp * 110 / 100; break; case MONK: strcpy(make_npc->special_abilities, "7,1"); make_npc->max_dmg = make_npc->max_dmg * 150 /100; - make_npc->cur_hp = make_npc->cur_hp * 135 / 100; + make_npc->current_hp = make_npc->current_hp * 135 / 100; make_npc->max_hp = make_npc->max_hp * 135 / 100; break; case WARRIOR: case BERSERKER: strcpy(make_npc->special_abilities, "7,1"); make_npc->max_dmg = make_npc->max_dmg * 150 /100; - make_npc->cur_hp = make_npc->cur_hp * 175 / 100; + make_npc->current_hp = make_npc->current_hp * 175 / 100; make_npc->max_hp = make_npc->max_hp * 175 / 100; break; default: diff --git a/zone/attack.cpp b/zone/attack.cpp index 769568f34..771976ef1 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -33,6 +33,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "zone.h" #include "lua_parser.h" #include "fastmath.h" +#include "mob.h" + #include #include @@ -5444,7 +5446,7 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts) // For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true if ((GetSpecialAbility(SPECATK_INNATE_DW) || (RuleB(Combat, UseLiveCombatRounds) && GetSpecialAbility(SPECATK_QUAD))) || - GetEquipment(EQEmu::textures::weaponSecondary) != 0) { + GetEquippedItemFromTextureSlot(EQEmu::textures::weaponSecondary) != 0) { if (CheckDualWield()) { Attack(target, EQEmu::invslot::slotSecondary, false, false, false, opts); if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack()) { @@ -5476,4 +5478,4 @@ int32 Mob::GetHPRegen() const int32 Mob::GetManaRegen() const { return mana_regen; -} +} \ No newline at end of file diff --git a/zone/client.cpp b/zone/client.cpp index 3bdd647a2..bb43a3e4f 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2965,13 +2965,12 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail) return true; } -void Client::SetMaterial(int16 in_slot, uint32 item_id) { - const EQEmu::ItemData* item = database.GetItem(item_id); - if (item && item->IsClassCommon()) - { +void Client::SetMaterial(int16 in_slot, uint32 item_id) +{ + const EQEmu::ItemData *item = database.GetItem(item_id); + if (item && item->IsClassCommon()) { uint8 matslot = EQEmu::InventoryProfile::CalcMaterialFromSlot(in_slot); - if (matslot != EQEmu::textures::materialInvalid) - { + if (matslot != EQEmu::textures::materialInvalid) { m_pp.item_material.Slot[matslot].Material = GetEquipmentMaterial(matslot); } } @@ -8527,11 +8526,11 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, } void Client::SendHPUpdateMarquee(){ - if (!this || !this->IsClient() || !this->cur_hp || !this->max_hp) + if (!this || !this->IsClient() || !this->current_hp || !this->max_hp) return; /* Health Update Marquee Display: Custom*/ - uint8 health_percentage = (uint8)(this->cur_hp * 100 / this->max_hp); + uint8 health_percentage = (uint8)(this->current_hp * 100 / this->max_hp); if (health_percentage >= 100) return; diff --git a/zone/client.h b/zone/client.h index 4f7b0d9a0..48efba685 100644 --- a/zone/client.h +++ b/zone/client.h @@ -352,7 +352,7 @@ public: void SetHideMe(bool hm); inline uint16 GetPort() const { return port; } bool IsDead() const { return(dead); } - bool IsUnconscious() const { return ((cur_hp <= 0) ? true : false); } + bool IsUnconscious() const { return ((current_hp <= 0) ? true : false); } inline bool IsLFP() { return LFP; } void UpdateLFP(); @@ -798,7 +798,7 @@ public: #ifdef PACKET_PROFILER void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); } #endif - uint32 GetEquipment(uint8 material_slot) const; // returns item id + uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id uint32 GetEquipmentColor(uint8 material_slot) const; virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 8651a622f..299aa3f0b 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -325,15 +325,15 @@ int32 Client::CalcMaxHP() max_hp += spellbonuses.HP + aabonuses.HP; max_hp += GroupLeadershipAAHealthEnhancement(); max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f); - if (cur_hp > max_hp) { - cur_hp = max_hp; + if (current_hp > max_hp) { + current_hp = max_hp; } int hp_perc_cap = spellbonuses.HPPercCap[0]; if (hp_perc_cap) { int curHP_cap = (max_hp * hp_perc_cap) / 100; - if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1])) { + if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1])) { - cur_hp = curHP_cap; + current_hp = curHP_cap; } } return max_hp; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 43034da6b..efaa05e0a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -3237,42 +3237,40 @@ void Client::Handle_OP_AutoAttack(const EQApplicationPacket *app) return; } - if (app->pBuffer[0] == 0) - { + if (app->pBuffer[0] == 0) { auto_attack = false; - if (IsAIControlled()) + if (IsAIControlled()) { return; + } attack_timer.Disable(); ranged_timer.Disable(); attack_dw_timer.Disable(); - m_AutoAttackPosition = glm::vec4(); + m_AutoAttackPosition = glm::vec4(); m_AutoAttackTargetLocation = glm::vec3(); - aa_los_them_mob = nullptr; + aa_los_them_mob = nullptr; } - else if (app->pBuffer[0] == 1) - { + else if (app->pBuffer[0] == 1) { auto_attack = true; - auto_fire = false; - if (IsAIControlled()) + auto_fire = false; + if (IsAIControlled()) { return; + } SetAttackTimer(); - if (GetTarget()) - { - aa_los_them_mob = GetTarget(); - m_AutoAttackPosition = GetPosition(); + if (GetTarget()) { + aa_los_them_mob = GetTarget(); + m_AutoAttackPosition = GetPosition(); m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition()); - los_status = CheckLosFN(aa_los_them_mob); - los_status_facing = IsFacingMob(aa_los_them_mob); + los_status = CheckLosFN(aa_los_them_mob); + los_status_facing = IsFacingMob(aa_los_them_mob); } - else - { - m_AutoAttackPosition = GetPosition(); + else { + m_AutoAttackPosition = GetPosition(); m_AutoAttackTargetLocation = glm::vec3(); - aa_los_them_mob = nullptr; - los_status = false; - los_status_facing = false; + aa_los_them_mob = nullptr; + los_status = false; + los_status_facing = false; } } } @@ -14452,7 +14450,6 @@ void Client::Handle_OP_WearChange(const EQApplicationPacket *app) // we could maybe ignore this and just send our own from moveitem entity_list.QueueClients(this, app, true); - return; } void Client::Handle_OP_WhoAllRequest(const EQApplicationPacket *app) diff --git a/zone/client_process.cpp b/zone/client_process.cpp index fcfc1df53..82f118384 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -345,25 +345,22 @@ bool Client::Process() { } Mob *auto_attack_target = GetTarget(); - if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check()) - { + if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check()) { //check if change //only check on primary attack.. sorry offhand you gotta wait! - if (aa_los_them_mob) - { + if (aa_los_them_mob) { if (auto_attack_target != aa_los_them_mob || m_AutoAttackPosition.x != GetX() || m_AutoAttackPosition.y != GetY() || m_AutoAttackPosition.z != GetZ() || m_AutoAttackTargetLocation.x != aa_los_them_mob->GetX() || m_AutoAttackTargetLocation.y != aa_los_them_mob->GetY() || - m_AutoAttackTargetLocation.z != aa_los_them_mob->GetZ()) - { - aa_los_them_mob = auto_attack_target; - m_AutoAttackPosition = GetPosition(); + m_AutoAttackTargetLocation.z != aa_los_them_mob->GetZ()) { + aa_los_them_mob = auto_attack_target; + m_AutoAttackPosition = GetPosition(); m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition()); - los_status = CheckLosFN(auto_attack_target); - los_status_facing = IsFacingMob(aa_los_them_mob); + los_status = CheckLosFN(auto_attack_target); + los_status_facing = IsFacingMob(aa_los_them_mob); } // If only our heading changes, we can skip the CheckLosFN call // but above we still need to update los_status_facing @@ -372,25 +369,21 @@ bool Client::Process() { los_status_facing = IsFacingMob(aa_los_them_mob); } } - else - { - aa_los_them_mob = auto_attack_target; - m_AutoAttackPosition = GetPosition(); + else { + aa_los_them_mob = auto_attack_target; + m_AutoAttackPosition = GetPosition(); m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition()); - los_status = CheckLosFN(auto_attack_target); - los_status_facing = IsFacingMob(aa_los_them_mob); + los_status = CheckLosFN(auto_attack_target); + los_status_facing = IsFacingMob(aa_los_them_mob); } - if (!CombatRange(auto_attack_target)) - { + if (!CombatRange(auto_attack_target)) { Message_StringID(MT_TooFarAway, TARGET_TOO_FAR); } - else if (auto_attack_target == this) - { + else if (auto_attack_target == this) { Message_StringID(MT_TooFarAway, TRY_ATTACKING_SOMEONE); } - else if (!los_status || !los_status_facing) - { + else if (!los_status || !los_status_facing) { //you can't see your target } else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP @@ -400,8 +393,9 @@ bool Client::Process() { TriggerDefensiveProcs(auto_attack_target, EQEmu::invslot::slotPrimary, false); DoAttackRounds(auto_attack_target, EQEmu::invslot::slotPrimary); - if (CheckAATimer(aaTimerRampage)) + if (CheckAATimer(aaTimerRampage)) { entity_list.AEAttack(this, 30); + } } } diff --git a/zone/command.cpp b/zone/command.cpp index 1dc001a5c..681c22a7e 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -249,6 +249,7 @@ int command_init(void) command_add("itemsearch", "[search criteria] - Search for an item", 10, command_itemsearch) || command_add("kick", "[charname] - Disconnect charname", 150, command_kick) || command_add("kill", "- Kill your target", 100, command_kill) || + command_add("killallnpcs", "- Kills all npcs, also takes an optional npc name as parameter", 200, command_killallnpcs) || command_add("lastname", "[new lastname] - Set your or your player target's lastname", 50, command_lastname) || command_add("level", "[level] - Set your or your target's level", 10, command_level) || command_add("listnpcs", "[name/range] - Search NPCs", 20, command_listnpcs) || @@ -388,6 +389,7 @@ int command_init(void) command_add("tattoo", "- Change the tattoo of your target (Drakkin Only)", 80, command_tattoo) || command_add("tempname", "[newname] - Temporarily renames your target. Leave name blank to restore the original name.", 100, command_tempname) || command_add("petname", "[newname] - Temporarily renames your pet. Leave name blank to restore the original name.", 100, command_petname) || + command_add("test", "Test command", 200, command_test) || command_add("texture", "[texture] [helmtexture] - Change your or your target's appearance, use 255 to show equipment", 10, command_texture) || command_add("time", "[HH] [MM] - Set EQ time", 90, command_time) || command_add("timers", "- Display persistent timers for target", 200, command_timers) || @@ -748,21 +750,21 @@ void command_serversidename(Client *c, const Seperator *sep) void command_wc(Client *c, const Seperator *sep) { - if(sep->argnum < 2) - { - c->Message(0, "Usage: #wc [wear slot] [material] [ [hero_forge_model] [elite_material] [unknown06] [unknown18] ]"); + if (sep->argnum < 2) { + c->Message( + 0, + "Usage: #wc [wear slot] [material] [ [hero_forge_model] [elite_material] [unknown06] [unknown18] ]" + ); } - else if(c->GetTarget() == nullptr) { + else if (c->GetTarget() == nullptr) { c->Message(13, "You must have a target to do a wear change."); } - else - { + else { uint32 hero_forge_model = 0; - uint32 wearslot = atoi(sep->arg[1]); + uint32 wearslot = atoi(sep->arg[1]); // Hero Forge - if (sep->argnum > 2) - { + if (sep->argnum > 2) { hero_forge_model = atoi(sep->arg[3]); if (hero_forge_model != 0 && hero_forge_model < 1000) { @@ -778,45 +780,43 @@ void command_wc(Client *c, const Seperator *sep) else Color = c->GetTarget()->GetArmorTint(atoi(sep->arg[1])); */ - c->GetTarget()->SendTextureWC(wearslot, atoi(sep->arg[2]), hero_forge_model, atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6])); + c->GetTarget()->SendTextureWC( + wearslot, + atoi(sep->arg[2]), + hero_forge_model, + atoi(sep->arg[4]), + atoi(sep->arg[5]), + atoi(sep->arg[6])); } } void command_heromodel(Client *c, const Seperator *sep) { - if (sep->argnum < 1) - { + if (sep->argnum < 1) { c->Message(0, "Usage: #heromodel [hero forge model] [ [slot] ] (example: #heromodel 63)"); } - else if (c->GetTarget() == nullptr) - { + else if (c->GetTarget() == nullptr) { c->Message(13, "You must have a target to do a wear change for Hero's Forge Models."); } - else - { + else { uint32 hero_forge_model = atoi(sep->arg[1]); - if (sep->argnum > 1) - { - uint8 wearslot = (uint8)atoi(sep->arg[2]); + if (sep->argnum > 1) { + uint8 wearslot = (uint8) atoi(sep->arg[2]); c->GetTarget()->SendTextureWC(wearslot, 0, hero_forge_model, 0, 0, 0); } - else - { - if (hero_forge_model > 0) - { + else { + if (hero_forge_model > 0) { // Conversion to simplify the command arguments // Hero's Forge model is actually model * 1000 + texture * 100 + wearslot // Hero's Forge Model slot 7 is actually for Robes, but it still needs to use wearslot 1 in the packet hero_forge_model *= 100; - for (uint8 wearslot = 0; wearslot < 7; wearslot++) - { + for (uint8 wearslot = 0; wearslot < 7; wearslot++) { c->GetTarget()->SendTextureWC(wearslot, 0, (hero_forge_model + wearslot), 0, 0, 0); } } - else - { + else { c->Message(13, "Hero's Forge Model must be greater than 0."); } } @@ -827,12 +827,14 @@ void command_setanim(Client *c, const Seperator *sep) { if (c->GetTarget() && sep->IsNumber(1)) { int num = atoi(sep->arg[1]); - if(num < 0 || num >= _eaMaxAppearance) { - c->Message(0, "Invalid animation number, between 0 and %d", _eaMaxAppearance-1); + if (num < 0 || num >= _eaMaxAppearance) { + c->Message(0, "Invalid animation number, between 0 and %d", _eaMaxAppearance - 1); } c->GetTarget()->SetAppearance(EmuAppearance(num)); - } else + } + else { c->Message(0, "Usage: #setanim [animnum]"); + } } void command_serverinfo(Client *c, const Seperator *sep) @@ -2728,18 +2730,21 @@ void command_setskillall(Client *c, const Seperator *sep) void command_race(Client *c, const Seperator *sep) { - Mob *t=c->CastToMob(); + Mob *target = c->CastToMob(); if (sep->IsNumber(1)) { auto race = atoi(sep->arg[1]); if ((race >= 0 && race <= 732) || (race >= 2253 && race <= 2259)) { - if ((c->GetTarget()) && c->Admin() >= commandRaceOthers) - t = c->GetTarget(); - t->SendIllusionPacket(race); - } else { + if ((c->GetTarget()) && c->Admin() >= commandRaceOthers) { + target = c->GetTarget(); + } + target->SendIllusionPacket(race); + } + else { c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)"); } - } else { + } + else { c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)"); } } @@ -2817,6 +2822,21 @@ void command_spawn(Client *c, const Seperator *sep) } } +void command_test(Client *c, const Seperator *sep) +{ + c->Message(15, "Triggering test command"); + + // EQEmu::ItemInstance* fake_weapon_secondary = database.CreateItem(static_cast(c->GetItemIDAt(EQEmu::invslot::slotSecondary))); + // fake_weapon_secondary->SetNewIDFile(c->GetEquipmentMaterial(EQEmu::textures::weaponSecondary)); + // c->SendItemPacket(EQEmu::invslot::slotSecondary, fake_weapon_secondary, ItemPacketTrade); + // safe_delete(fake_weapon_secondary); + + EQEmu::ItemInstance* fake_weapon = database.CreateItem(static_cast(c->GetItemIDAt(EQEmu::invslot::slotPrimary))); + fake_weapon->SetNewIDFile(c->GetEquipmentMaterial(EQEmu::textures::weaponPrimary)); + c->SendItemPacket(EQEmu::invslot::slotPrimary, fake_weapon, ItemPacketTrade); + safe_delete(fake_weapon); +} + void command_texture(Client *c, const Seperator *sep) { @@ -5111,6 +5131,41 @@ void command_kill(Client *c, const Seperator *sep) c->GetTarget()->Kill(); } +void command_killallnpcs(Client *c, const Seperator *sep) +{ + std::string search_string; + if (sep->arg[1]) { + search_string = sep->arg[1]; + } + + int count = 0; + for (auto &itr : entity_list.GetMobList()) { + Mob *entity = itr.second; + if (!entity->IsNPC()) { + continue; + } + + std::string entity_name = entity->GetName(); + + /** + * Filter by name + */ + if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos) { + continue; + } + + if (entity->IsInvisible() || !entity->IsAttackAllowed(c)) { + continue; + } + + entity->Damage(c, 1000000000, 0, EQEmu::skills::SkillDragonPunch); + + count++; + } + + c->Message(15, "Killed (%i) npc(s)", count); +} + void command_haste(Client *c, const Seperator *sep) { // #haste command to set client attack speed. Takes a percentage (100 = twice normal attack speed) diff --git a/zone/command.h b/zone/command.h index 1c4b21529..0a4eec014 100644 --- a/zone/command.h +++ b/zone/command.h @@ -149,6 +149,7 @@ void command_iteminfo(Client *c, const Seperator *sep); void command_itemsearch(Client *c, const Seperator *sep); void command_itemtest(Client *c, const Seperator *sep); void command_kick(Client *c, const Seperator *sep); +void command_killallnpcs(Client *c, const Seperator *sep); void command_kill(Client *c, const Seperator *sep); void command_lastname(Client *c, const Seperator *sep); void command_level(Client *c, const Seperator *sep); @@ -297,6 +298,7 @@ void command_task(Client *c, const Seperator *sep); void command_tattoo(Client *c, const Seperator *sep); void command_tempname(Client *c, const Seperator *sep); void command_petname(Client *c, const Seperator *sep); +void command_test(Client *c, const Seperator *sep); void command_testspawn(Client *c, const Seperator *sep); void command_testspawnkill(Client *c, const Seperator *sep); void command_texture(Client *c, const Seperator *sep); diff --git a/zone/corpse.cpp b/zone/corpse.cpp index c31a9a5d2..dd362fedb 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -1479,7 +1479,7 @@ void Corpse::Spawn() { safe_delete(app); } -uint32 Corpse::GetEquipment(uint8 material_slot) const { +uint32 Corpse::GetEquippedItemFromTextureSlot(uint8 material_slot) const { int16 invslot; if (material_slot > EQEmu::textures::LastTexture) { @@ -1500,7 +1500,7 @@ uint32 Corpse::GetEquipmentColor(uint8 material_slot) const { return 0; } - item = database.GetItem(GetEquipment(material_slot)); + item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); if(item != 0) { return (item_tint.Slot[material_slot].UseTint ? item_tint.Slot[material_slot].Color : item->Color); } diff --git a/zone/corpse.h b/zone/corpse.h index ff323e791..e7a7c5805 100644 --- a/zone/corpse.h +++ b/zone/corpse.h @@ -126,7 +126,7 @@ class Corpse : public Mob { void Spawn(); char corpse_name[64]; - uint32 GetEquipment(uint8 material_slot) const; + uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; uint32 GetEquipmentColor(uint8 material_slot) const; inline int GetRezExp() { return rez_experience; } diff --git a/zone/entity.cpp b/zone/entity.cpp index c2201f97b..e288493f8 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -1274,32 +1274,35 @@ void EntityList::SendZoneSpawns(Client *client) void EntityList::SendZoneSpawnsBulk(Client *client) { - NewSpawn_Struct ns; - Mob *spawn; - uint32 maxspawns = 100; + NewSpawn_Struct ns{}; + Mob *spawn; EQApplicationPacket *app; - if (maxspawns > mob_list.size()) - maxspawns = mob_list.size(); - auto bzsp = new BulkZoneSpawnPacket(client, maxspawns); + uint32 max_spawns = 100; + + if (max_spawns > mob_list.size()) { + max_spawns = static_cast(mob_list.size()); + } + + auto bulk_zone_spawn_packet = new BulkZoneSpawnPacket(client, max_spawns); + const glm::vec4 &client_position = client->GetPosition(); + const float distance_max = (600.0 * 600.0); - bool delaypkt = false; - const glm::vec4& cpos = client->GetPosition(); - const float dmax = 600.0 * 600.0; for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { spawn = it->second; if (spawn && spawn->GetID() > 0 && spawn->Spawned()) { - if (!spawn->ShouldISpawnFor(client)) + if (!spawn->ShouldISpawnFor(client)) { continue; + } -#if 1 - const glm::vec4& spos = spawn->GetPosition(); + const glm::vec4 &spawn_position = spawn->GetPosition(); - delaypkt = false; - if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE))) - delaypkt = true; + bool is_delayed_packet = ( + DistanceSquared(client_position, spawn_position) > distance_max || + (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE)) + ); - if (delaypkt) { + if (is_delayed_packet) { app = new EQApplicationPacket; spawn->CreateSpawnPacket(app); client->QueuePacket(app, true, Client::CLIENT_CONNECTED); @@ -1308,35 +1311,38 @@ void EntityList::SendZoneSpawnsBulk(Client *client) else { memset(&ns, 0, sizeof(NewSpawn_Struct)); spawn->FillSpawnStruct(&ns, client); - bzsp->AddSpawn(&ns); + bulk_zone_spawn_packet->AddSpawn(&ns); } spawn->SendArmorAppearance(client); -#else - /* original code kept for spawn packet research */ - int32 race = spawn->GetRace(); - - // Illusion races on PCs don't work as a mass spawn - // But they will work as an add_spawn AFTER CLIENT_CONNECTED. - if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) { - app = new EQApplicationPacket; - spawn->CreateSpawnPacket(app); - client->QueuePacket(app, true, Client::CLIENT_CONNECTED); - safe_delete(app); - } - else { - memset(&ns, 0, sizeof(NewSpawn_Struct)); - spawn->FillSpawnStruct(&ns, client); - bzsp->AddSpawn(&ns); - } - // Despite being sent in the OP_ZoneSpawns packet, the client - // does not display worn armor correctly so display it. - spawn->SendArmorAppearance(client); -#endif + /** + * Original code kept for spawn packet research + * + * int32 race = spawn->GetRace(); + * + * Illusion races on PCs don't work as a mass spawn + * But they will work as an add_spawn AFTER CLIENT_CONNECTED. + * if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) { + * app = new EQApplicationPacket; + * spawn->CreateSpawnPacket(app); + * client->QueuePacket(app, true, Client::CLIENT_CONNECTED); + * safe_delete(app); + * } + * else { + * memset(&ns, 0, sizeof(NewSpawn_Struct)); + * spawn->FillSpawnStruct(&ns, client); + * bzsp->AddSpawn(&ns); + * } + * + * Despite being sent in the OP_ZoneSpawns packet, the client + * does not display worn armor correctly so display it. + * spawn->SendArmorAppearance(client); + */ } } - safe_delete(bzsp); + + safe_delete(bulk_zone_spawn_packet); } //this is a hack to handle a broken spawn struct @@ -3967,8 +3973,9 @@ Mob *EntityList::GetTargetForMez(Mob *caster) void EntityList::SendZoneAppearance(Client *c) { - if (!c) + if (!c) { return; + } auto it = mob_list.begin(); while (it != mob_list.end()) { @@ -3983,7 +3990,7 @@ void EntityList::SendZoneAppearance(Client *c) cur->SendAppearancePacket(AT_Anim, cur->GetAppearanceValue(cur->GetAppearance()), false, true, c); } if (cur->GetSize() != cur->GetBaseSize()) { - cur->SendAppearancePacket(AT_Size, (uint32)cur->GetSize(), false, true, c); + cur->SendAppearancePacket(AT_Size, (uint32) cur->GetSize(), false, true, c); } } ++it; diff --git a/zone/horse.cpp b/zone/horse.cpp index 9f5c9b4d3..6c81b3d21 100644 --- a/zone/horse.cpp +++ b/zone/horse.cpp @@ -90,7 +90,7 @@ const NPCType *Horse::BuildHorseType(uint16 spell_id) { strcpy(npc_type->name, "Unclaimed_Mount"); // this should never get used strcpy(npc_type->special_abilities, "19,1^20,1^24,1"); - npc_type->cur_hp = 1; + npc_type->current_hp = 1; npc_type->max_hp = 1; npc_type->race = atoi(row[0]); npc_type->gender = atoi(row[1]); // Drogmor's are female horses. Yuck. diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 24fa86b30..7e9f2d9a1 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -2858,26 +2858,24 @@ void Client::MoveSlotNotAllowed(bool client_update) } // these functions operate with a material slot, which is from 0 to 8 -uint32 Client::GetEquipment(uint8 material_slot) const +uint32 Client::GetEquippedItemFromTextureSlot(uint8 material_slot) const { - int16 invslot; + int16 inventory_slot; + const EQEmu::ItemInstance *item; - if(material_slot > EQEmu::textures::LastTexture) - { + if (material_slot > EQEmu::textures::LastTexture) { return 0; } - invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); - if (invslot == INVALID_INDEX) - { + inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); + if (inventory_slot == INVALID_INDEX) { return 0; } - item = m_inv.GetItem(invslot); + item = m_inv.GetItem(inventory_slot); - if(item && item->GetItem()) - { + if (item && item->GetItem()) { return item->GetItem()->ID; } @@ -2904,7 +2902,7 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const if (material_slot > EQEmu::textures::LastTexture) return 0; - const EQEmu::ItemData *item = database.GetItem(GetEquipment(material_slot)); + const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); if(item != nullptr) return ((m_pp.item_tint.Slot[material_slot].UseTint) ? m_pp.item_tint.Slot[material_slot].Color : item->Color); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index f94194754..fdb3facc9 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1413,7 +1413,7 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float luabind::adl::index_proxy cur = table["name"]; LuaCreateNPCParseString(name, 64, "_"); LuaCreateNPCParseString(lastname, 64, ""); - LuaCreateNPCParse(cur_hp, int32, 30); + LuaCreateNPCParse(current_hp, int32, 30); LuaCreateNPCParse(max_hp, int32, 30); LuaCreateNPCParse(size, float, 6.0f); LuaCreateNPCParse(runspeed, float, 1.25f); diff --git a/zone/merc.cpp b/zone/merc.cpp index f26531ccf..b33cade34 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -859,14 +859,14 @@ int32 Merc::CalcMaxHP() { max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f); - if (cur_hp > max_hp) - cur_hp = max_hp; + if (current_hp > max_hp) + current_hp = max_hp; int hp_perc_cap = spellbonuses.HPPercCap[0]; if(hp_perc_cap) { int curHP_cap = (max_hp * hp_perc_cap) / 100; - if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1])) - cur_hp = curHP_cap; + if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1])) + current_hp = curHP_cap; } return max_hp; @@ -4949,7 +4949,7 @@ void Merc::ScaleStats(int scalepercent, bool setmax) { max_hp = (int)((float)base_hp * scalerate); base_hp = max_hp; if (setmax) - cur_hp = max_hp; + current_hp = max_hp; } if (base_mana) diff --git a/zone/mob.cpp b/zone/mob.cpp index d38121b06..a8eeb996a 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -140,7 +140,7 @@ Mob::Mob( if (in_lastname) { strn0cpy(lastname, in_lastname, 64); } - cur_hp = in_cur_hp; + current_hp = in_cur_hp; max_hp = in_max_hp; base_hp = in_max_hp; gender = in_gender; @@ -265,7 +265,7 @@ Mob::Mob( hidden = false; improved_hidden = false; invulnerable = false; - IsFullHP = (cur_hp == max_hp); + IsFullHP = (current_hp == max_hp); qglobal = 0; spawned = false; rare_spawn = false; @@ -935,77 +935,76 @@ uint8 Mob::GetArchetype() const { } } -void Mob::CreateSpawnPacket(EQApplicationPacket* app, Mob* ForWho) { +void Mob::CreateSpawnPacket(EQApplicationPacket *app, Mob *ForWho) +{ app->SetOpcode(OP_NewSpawn); - app->size = sizeof(NewSpawn_Struct); + app->size = sizeof(NewSpawn_Struct); app->pBuffer = new uchar[app->size]; memset(app->pBuffer, 0, app->size); - NewSpawn_Struct* ns = (NewSpawn_Struct*)app->pBuffer; + NewSpawn_Struct *ns = (NewSpawn_Struct *) app->pBuffer; FillSpawnStruct(ns, ForWho); - if(RuleB(NPC, UseClassAsLastName) && strlen(ns->spawn.lastName) == 0) - { - switch(ns->spawn.class_) - { - case TRIBUTE_MASTER: - strcpy(ns->spawn.lastName, "Tribute Master"); - break; - case ADVENTURERECRUITER: - strcpy(ns->spawn.lastName, "Adventure Recruiter"); - break; - case BANKER: - strcpy(ns->spawn.lastName, "Banker"); - break; - case ADVENTUREMERCHANT: - strcpy(ns->spawn.lastName,"Adventure Merchant"); - break; - case WARRIORGM: - strcpy(ns->spawn.lastName, "GM Warrior"); - break; - case PALADINGM: - strcpy(ns->spawn.lastName, "GM Paladin"); - break; - case RANGERGM: - strcpy(ns->spawn.lastName, "GM Ranger"); - break; - case SHADOWKNIGHTGM: - strcpy(ns->spawn.lastName, "GM Shadowknight"); - break; - case DRUIDGM: - strcpy(ns->spawn.lastName, "GM Druid"); - break; - case BARDGM: - strcpy(ns->spawn.lastName, "GM Bard"); - break; - case ROGUEGM: - strcpy(ns->spawn.lastName, "GM Rogue"); - break; - case SHAMANGM: - strcpy(ns->spawn.lastName, "GM Shaman"); - break; - case NECROMANCERGM: - strcpy(ns->spawn.lastName, "GM Necromancer"); - break; - case WIZARDGM: - strcpy(ns->spawn.lastName, "GM Wizard"); - break; - case MAGICIANGM: - strcpy(ns->spawn.lastName, "GM Magician"); - break; - case ENCHANTERGM: - strcpy(ns->spawn.lastName, "GM Enchanter"); - break; - case BEASTLORDGM: - strcpy(ns->spawn.lastName, "GM Beastlord"); - break; - case BERSERKERGM: - strcpy(ns->spawn.lastName, "GM Berserker"); - break; - case MERCERNARY_MASTER: - strcpy(ns->spawn.lastName, "Mercenary Recruiter"); - break; - default: - break; + if (RuleB(NPC, UseClassAsLastName) && strlen(ns->spawn.lastName) == 0) { + switch (ns->spawn.class_) { + case TRIBUTE_MASTER: + strcpy(ns->spawn.lastName, "Tribute Master"); + break; + case ADVENTURERECRUITER: + strcpy(ns->spawn.lastName, "Adventure Recruiter"); + break; + case BANKER: + strcpy(ns->spawn.lastName, "Banker"); + break; + case ADVENTUREMERCHANT: + strcpy(ns->spawn.lastName, "Adventure Merchant"); + break; + case WARRIORGM: + strcpy(ns->spawn.lastName, "GM Warrior"); + break; + case PALADINGM: + strcpy(ns->spawn.lastName, "GM Paladin"); + break; + case RANGERGM: + strcpy(ns->spawn.lastName, "GM Ranger"); + break; + case SHADOWKNIGHTGM: + strcpy(ns->spawn.lastName, "GM Shadowknight"); + break; + case DRUIDGM: + strcpy(ns->spawn.lastName, "GM Druid"); + break; + case BARDGM: + strcpy(ns->spawn.lastName, "GM Bard"); + break; + case ROGUEGM: + strcpy(ns->spawn.lastName, "GM Rogue"); + break; + case SHAMANGM: + strcpy(ns->spawn.lastName, "GM Shaman"); + break; + case NECROMANCERGM: + strcpy(ns->spawn.lastName, "GM Necromancer"); + break; + case WIZARDGM: + strcpy(ns->spawn.lastName, "GM Wizard"); + break; + case MAGICIANGM: + strcpy(ns->spawn.lastName, "GM Magician"); + break; + case ENCHANTERGM: + strcpy(ns->spawn.lastName, "GM Enchanter"); + break; + case BEASTLORDGM: + strcpy(ns->spawn.lastName, "GM Beastlord"); + break; + case BERSERKERGM: + strcpy(ns->spawn.lastName, "GM Berserker"); + break; + case MERCERNARY_MASTER: + strcpy(ns->spawn.lastName, "Mercenary Recruiter"); + break; + default: + break; } } } @@ -1269,7 +1268,7 @@ void Mob::CreateDespawnPacket(EQApplicationPacket* app, bool Decay) void Mob::CreateHPPacket(EQApplicationPacket* app) { - this->IsFullHP=(cur_hp>=max_hp); + this->IsFullHP=(current_hp>=max_hp); app->SetOpcode(OP_MobHealth); app->size = sizeof(SpawnHPUpdate_Struct2); app->pBuffer = new uchar[app->size]; @@ -1312,7 +1311,7 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal * If our HP is different from last HP update call - let's update selves */ if (IsClient()) { - if (cur_hp != last_hp || force_update_all) { + if (current_hp != last_hp || force_update_all) { /** * This is to prevent excessive packet sending under trains/fast combat @@ -1321,17 +1320,16 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: Update HP of self (%s) HP: %i last: %i skip_self: %s", this->GetCleanName(), - cur_hp, + current_hp, last_hp, (skip_self ? "true" : "false") ); if (!skip_self || this->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { - auto client_packet = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct)); + auto client_packet = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct)); + auto *hp_packet_client = (SpawnHPUpdate_Struct *) client_packet->pBuffer; - SpawnHPUpdate_Struct *hp_packet_client = (SpawnHPUpdate_Struct *) client_packet->pBuffer; - - hp_packet_client->cur_hp = CastToClient()->GetHP() - itembonuses.HP; + hp_packet_client->cur_hp = static_cast(CastToClient()->GetHP() - itembonuses.HP); hp_packet_client->spawn_id = GetID(); hp_packet_client->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP; @@ -1345,12 +1343,12 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal /** * Used to check if HP has changed to update self next round */ - last_hp = cur_hp; + last_hp = current_hp; } } } - int8 current_hp_percent = (max_hp == 0 ? 0 : static_cast(cur_hp * 100 / max_hp)); + int8 current_hp_percent = static_cast(max_hp == 0 ? 0 : static_cast(current_hp * 100 / max_hp)); Log(Logs::General, Logs::HP_Update, @@ -1680,129 +1678,171 @@ void Mob::GMMove(float x, float y, float z, float heading, bool SendUpdate) { } } -void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture, uint8 in_helmtexture, uint8 in_haircolor, uint8 in_beardcolor, uint8 in_eyecolor1, uint8 in_eyecolor2, uint8 in_hairstyle, uint8 in_luclinface, uint8 in_beard, uint8 in_aa_title, uint32 in_drakkin_heritage, uint32 in_drakkin_tattoo, uint32 in_drakkin_details, float in_size) { +void Mob::SendIllusionPacket( + uint16 in_race, + uint8 in_gender, + uint8 in_texture, + uint8 in_helmtexture, + uint8 in_haircolor, + uint8 in_beardcolor, + uint8 in_eyecolor1, + uint8 in_eyecolor2, + uint8 in_hairstyle, + uint8 in_luclinface, + uint8 in_beard, + uint8 in_aa_title, + uint32 in_drakkin_heritage, + uint32 in_drakkin_tattoo, + uint32 in_drakkin_details, + float in_size +) +{ uint16 BaseRace = GetBaseRace(); - if (in_race == 0) - { + if (in_race == 0) { race = BaseRace; - if (in_gender == 0xFF) + if (in_gender == 0xFF) { gender = GetBaseGender(); - else + } + else { gender = in_gender; + } } - else - { + else { race = in_race; - if (in_gender == 0xFF) + if (in_gender == 0xFF) { gender = GetDefaultGender(race, gender); - else + } + else { gender = in_gender; + } } - if (in_texture == 0xFF) - { - if (IsPlayerRace(in_race)) + if (in_texture == 0xFF) { + if (IsPlayerRace(in_race)) { texture = 0xFF; - else + } + else { texture = GetTexture(); + } } - else - { + else { texture = in_texture; } - if (in_helmtexture == 0xFF) - { - if (IsPlayerRace(in_race)) + if (in_helmtexture == 0xFF) { + if (IsPlayerRace(in_race)) { helmtexture = 0xFF; - else if (in_texture != 0xFF) + } + else if (in_texture != 0xFF) { helmtexture = in_texture; - else + } + else { helmtexture = GetHelmTexture(); + } } - else - { + else { helmtexture = in_helmtexture; } - if (in_haircolor == 0xFF) + if (in_haircolor == 0xFF) { haircolor = GetHairColor(); - else + } + else { haircolor = in_haircolor; + } - if (in_beardcolor == 0xFF) + if (in_beardcolor == 0xFF) { beardcolor = GetBeardColor(); - else + } + else { beardcolor = in_beardcolor; + } - if (in_eyecolor1 == 0xFF) + if (in_eyecolor1 == 0xFF) { eyecolor1 = GetEyeColor1(); - else + } + else { eyecolor1 = in_eyecolor1; + } - if (in_eyecolor2 == 0xFF) + if (in_eyecolor2 == 0xFF) { eyecolor2 = GetEyeColor2(); - else + } + else { eyecolor2 = in_eyecolor2; + } - if (in_hairstyle == 0xFF) + if (in_hairstyle == 0xFF) { hairstyle = GetHairStyle(); - else + } + else { hairstyle = in_hairstyle; + } - if (in_luclinface == 0xFF) + if (in_luclinface == 0xFF) { luclinface = GetLuclinFace(); - else + } + else { luclinface = in_luclinface; + } - if (in_beard == 0xFF) + if (in_beard == 0xFF) { beard = GetBeard(); - else + } + else { beard = in_beard; + } aa_title = in_aa_title; - if (in_drakkin_heritage == 0xFFFFFFFF) + if (in_drakkin_heritage == 0xFFFFFFFF) { drakkin_heritage = GetDrakkinHeritage(); - else + } + else { drakkin_heritage = in_drakkin_heritage; + } - if (in_drakkin_tattoo == 0xFFFFFFFF) + if (in_drakkin_tattoo == 0xFFFFFFFF) { drakkin_tattoo = GetDrakkinTattoo(); - else + } + else { drakkin_tattoo = in_drakkin_tattoo; + } - if (in_drakkin_details == 0xFFFFFFFF) + if (in_drakkin_details == 0xFFFFFFFF) { drakkin_details = GetDrakkinDetails(); - else + } + else { drakkin_details = in_drakkin_details; + } - if (in_size <= 0.0f) + if (in_size <= 0.0f) { size = GetSize(); - else + } + else { size = in_size; + } // Reset features to Base from the Player Profile - if (IsClient() && in_race == 0) - { - race = CastToClient()->GetBaseRace(); - gender = CastToClient()->GetBaseGender(); - texture = 0xFF; - helmtexture = 0xFF; - haircolor = CastToClient()->GetBaseHairColor(); - beardcolor = CastToClient()->GetBaseBeardColor(); - eyecolor1 = CastToClient()->GetBaseEyeColor(); - eyecolor2 = CastToClient()->GetBaseEyeColor(); - hairstyle = CastToClient()->GetBaseHairStyle(); - luclinface = CastToClient()->GetBaseFace(); - beard = CastToClient()->GetBaseBeard(); - aa_title = 0xFF; + if (IsClient() && in_race == 0) { + race = CastToClient()->GetBaseRace(); + gender = CastToClient()->GetBaseGender(); + texture = 0xFF; + helmtexture = 0xFF; + haircolor = CastToClient()->GetBaseHairColor(); + beardcolor = CastToClient()->GetBaseBeardColor(); + eyecolor1 = CastToClient()->GetBaseEyeColor(); + eyecolor2 = CastToClient()->GetBaseEyeColor(); + hairstyle = CastToClient()->GetBaseHairStyle(); + luclinface = CastToClient()->GetBaseFace(); + beard = CastToClient()->GetBaseBeard(); + aa_title = 0xFF; drakkin_heritage = CastToClient()->GetBaseHeritage(); - drakkin_tattoo = CastToClient()->GetBaseTattoo(); - drakkin_details = CastToClient()->GetBaseDetails(); - switch(race){ + drakkin_tattoo = CastToClient()->GetBaseTattoo(); + drakkin_details = CastToClient()->GetBaseDetails(); + switch (race) { case OGRE: size = 9; break; @@ -1832,25 +1872,25 @@ void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture, } } - auto outapp = new EQApplicationPacket(OP_Illusion, sizeof(Illusion_Struct)); - Illusion_Struct* is = (Illusion_Struct*) outapp->pBuffer; + auto outapp = new EQApplicationPacket(OP_Illusion, sizeof(Illusion_Struct)); + Illusion_Struct *is = (Illusion_Struct *) outapp->pBuffer; is->spawnid = GetID(); strcpy(is->charname, GetCleanName()); - is->race = race; - is->gender = gender; - is->texture = texture; - is->helmtexture = helmtexture; - is->haircolor = haircolor; - is->beardcolor = beardcolor; - is->beard = beard; - is->eyecolor1 = eyecolor1; - is->eyecolor2 = eyecolor2; - is->hairstyle = hairstyle; - is->face = luclinface; + is->race = race; + is->gender = gender; + is->texture = texture; + is->helmtexture = helmtexture; + is->haircolor = haircolor; + is->beardcolor = beardcolor; + is->beard = beard; + is->eyecolor1 = eyecolor1; + is->eyecolor2 = eyecolor2; + is->hairstyle = hairstyle; + is->face = luclinface; is->drakkin_heritage = drakkin_heritage; - is->drakkin_tattoo = drakkin_tattoo; - is->drakkin_details = drakkin_details; - is->size = size; + is->drakkin_tattoo = drakkin_tattoo; + is->drakkin_details = drakkin_details; + is->size = size; entity_list.QueueClients(this, outapp); safe_delete(outapp); @@ -1858,8 +1898,23 @@ void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture, /* Refresh armor and tints after send illusion packet */ this->SendArmorAppearance(); - Log(Logs::Detail, Logs::Spells, "Illusion: Race = %i, Gender = %i, Texture = %i, HelmTexture = %i, HairColor = %i, BeardColor = %i, EyeColor1 = %i, EyeColor2 = %i, HairStyle = %i, Face = %i, DrakkinHeritage = %i, DrakkinTattoo = %i, DrakkinDetails = %i, Size = %f", - race, gender, texture, helmtexture, haircolor, beardcolor, eyecolor1, eyecolor2, hairstyle, luclinface, drakkin_heritage, drakkin_tattoo, drakkin_details, size); + Log(Logs::Detail, + Logs::Spells, + "Illusion: Race = %i, Gender = %i, Texture = %i, HelmTexture = %i, HairColor = %i, BeardColor = %i, EyeColor1 = %i, EyeColor2 = %i, HairStyle = %i, Face = %i, DrakkinHeritage = %i, DrakkinTattoo = %i, DrakkinDetails = %i, Size = %f", + race, + gender, + texture, + helmtexture, + haircolor, + beardcolor, + eyecolor1, + eyecolor2, + hairstyle, + luclinface, + drakkin_heritage, + drakkin_tattoo, + drakkin_details, + size); } bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables) @@ -2810,275 +2865,11 @@ uint32 Mob::RandomTimer(int min,int max) { return r; } -uint32 NPC::GetEquipment(uint8 material_slot) const -{ - if(material_slot > 8) - return 0; - int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); - if (invslot == INVALID_INDEX) - return 0; - return equipment[invslot]; -} - -void Mob::SendArmorAppearance(Client *one_client) -{ - // one_client of 0 means sent to all clients - // - // Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the - // armor being worn and its mats, the client doesn't update the display - // on arrival of these packets reliably. - // - // Send Wear changes if mob is a PC race and item is an armor slot. - // The other packets work for primary/secondary. - - if (IsPlayerRace(race)) - { - if (!IsClient()) - { - const EQEmu::ItemData *item = nullptr; - for (int i = 0; i < 7; ++i) - { - item = database.GetItem(GetEquipment(i)); - if (item != 0) - { - SendWearChange(i, one_client); - } - } - } - } -} - -void Mob::SendWearChange(uint8 material_slot, Client *one_client) -{ - auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); - WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; - - wc->spawn_id = GetID(); - wc->material = GetEquipmentMaterial(material_slot); - wc->elite_material = IsEliteMaterialItem(material_slot); - wc->hero_forge_model = GetHerosForgeModel(material_slot); - -#ifdef BOTS - if (IsBot()) { - auto item_inst = CastToBot()->GetBotItem(EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot)); - if (item_inst) - wc->color.Color = item_inst->GetColor(); - else - wc->color.Color = 0; - } - else { - wc->color.Color = GetEquipmentColor(material_slot); - } -#else - wc->color.Color = GetEquipmentColor(material_slot); -#endif - - wc->wear_slot_id = material_slot; - - if (!one_client) - { - entity_list.QueueClients(this, outapp); - } - else - { - one_client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED); - } - - safe_delete(outapp); -} - -void Mob::SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model, uint32 elite_material, uint32 unknown06, uint32 unknown18) -{ - auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); - WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; - - wc->spawn_id = this->GetID(); - wc->material = texture; - if (this->IsClient()) - wc->color.Color = GetEquipmentColor(slot); - else - wc->color.Color = this->GetArmorTint(slot); - wc->wear_slot_id = slot; - - wc->unknown06 = unknown06; - wc->elite_material = elite_material; - wc->hero_forge_model = hero_forge_model; - wc->unknown18 = unknown18; - - - entity_list.QueueClients(this, outapp); - safe_delete(outapp); -} - -void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint) -{ - uint32 color; - color = (red_tint & 0xFF) << 16; - color |= (green_tint & 0xFF) << 8; - color |= (blue_tint & 0xFF); - color |= (color) ? (0xFF << 24) : 0; - armor_tint.Slot[material_slot].Color = color; - - auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); - WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; - - wc->spawn_id = this->GetID(); - wc->material = GetEquipmentMaterial(material_slot); - wc->hero_forge_model = GetHerosForgeModel(material_slot); - wc->color.Color = color; - wc->wear_slot_id = material_slot; - - entity_list.QueueClients(this, outapp); - safe_delete(outapp); -} - -void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model) -{ - armor_tint.Slot[material_slot].Color = color; - - auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); - WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; - - wc->spawn_id = this->GetID(); - wc->material = texture; - wc->hero_forge_model = hero_forge_model; - wc->color.Color = color; - wc->wear_slot_id = material_slot; - - entity_list.QueueClients(this, outapp); - safe_delete(outapp); -} - -int32 Mob::GetEquipmentMaterial(uint8 material_slot) const -{ - uint32 equipmaterial = 0; - int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - const EQEmu::ItemData *item = nullptr; - item = database.GetItem(GetEquipment(material_slot)); - - if (item != 0) - { - // For primary and secondary we need the model, not the material - if (material_slot == EQEmu::textures::weaponPrimary || material_slot == EQEmu::textures::weaponSecondary) - { - if (this->IsClient()) - { - int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); - if (invslot == INVALID_INDEX) - { - return 0; - } - const EQEmu::ItemInstance* inst = CastToClient()->m_inv[invslot]; - if (inst) - { - if (inst->GetOrnamentationAug(ornamentationAugtype)) - { - item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); - if (item && strlen(item->IDFile) > 2) - { - equipmaterial = atoi(&item->IDFile[2]); - } - } - else if (inst->GetOrnamentationIDFile()) - { - equipmaterial = inst->GetOrnamentationIDFile(); - } - } - } - - if (equipmaterial == 0 && strlen(item->IDFile) > 2) - { - equipmaterial = atoi(&item->IDFile[2]); - } - } - else - { - equipmaterial = item->Material; - } - } - - return equipmaterial; -} - -int32 Mob::GetHerosForgeModel(uint8 material_slot) const -{ - uint32 HeroModel = 0; - if (material_slot >= 0 && material_slot < EQEmu::textures::weaponPrimary) - { - uint32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - const EQEmu::ItemData *item = nullptr; - item = database.GetItem(GetEquipment(material_slot)); - int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); - - if (item != 0 && invslot != INVALID_INDEX) - { - if (IsClient()) - { - const EQEmu::ItemInstance* inst = CastToClient()->m_inv[invslot]; - if (inst) - { - if (inst->GetOrnamentationAug(ornamentationAugtype)) - { - item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); - HeroModel = item->HerosForgeModel; - } - else if (inst->GetOrnamentHeroModel()) - { - HeroModel = inst->GetOrnamentHeroModel(); - } - } - } - - if (HeroModel == 0) - { - HeroModel = item->HerosForgeModel; - } - } - - if (IsNPC()) - { - HeroModel = CastToNPC()->GetHeroForgeModel(); - // Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots - if (HeroModel > 1000 && material_slot != 1 && material_slot != 2 && material_slot != 3 && material_slot != 5) - { - HeroModel = 0; - } - } - } - - // Auto-Convert Hero Model to match the slot - // Otherwise, use the exact Model if model is > 999 - // Robes for example are 11607 to 12107 in RoF - if (HeroModel > 0 && HeroModel < 1000) - { - HeroModel *= 100; - HeroModel += material_slot; - } - - return HeroModel; -} - -uint32 Mob::GetEquipmentColor(uint8 material_slot) const -{ - const EQEmu::ItemData *item = nullptr; - - if (armor_tint.Slot[material_slot].Color) - { - return armor_tint.Slot[material_slot].Color; - } - - item = database.GetItem(GetEquipment(material_slot)); - if (item != 0) - return item->Color; - - return 0; -} - uint32 Mob::IsEliteMaterialItem(uint8 material_slot) const { const EQEmu::ItemData *item = nullptr; - item = database.GetItem(GetEquipment(material_slot)); + item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); if(item != 0) { return item->EliteMaterial; @@ -3090,26 +2881,31 @@ uint32 Mob::IsEliteMaterialItem(uint8 material_slot) const // works just like a printf void Mob::Say(const char *format, ...) { - char buf[1000]; + char buf[1000]; va_list ap; va_start(ap, format); vsnprintf(buf, 1000, format, ap); va_end(ap); - Mob* talker = this; - if(spellbonuses.VoiceGraft != 0) { - if(spellbonuses.VoiceGraft == GetPetID()) + Mob *talker = this; + if (spellbonuses.VoiceGraft != 0) { + if (spellbonuses.VoiceGraft == GetPetID()) { talker = entity_list.GetMob(spellbonuses.VoiceGraft); - else + } + else { spellbonuses.VoiceGraft = 0; + } } - if(!talker) + if (!talker) { talker = this; + } - entity_list.MessageClose_StringID(talker, false, 200, 10, - GENERIC_SAY, GetCleanName(), buf); + entity_list.MessageClose_StringID( + talker, false, 200, 10, + GENERIC_SAY, GetCleanName(), buf + ); } // diff --git a/zone/mob.h b/zone/mob.h index 0fee32be4..56d6e5e4f 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -107,58 +107,59 @@ public: AuraMgr() : count(0) { } }; - Mob(const char* in_name, - const char* in_lastname, - int32 in_cur_hp, - int32 in_max_hp, - uint8 in_gender, - uint16 in_race, - uint8 in_class, - bodyType in_bodytype, - uint8 in_deity, - uint8 in_level, - uint32 in_npctype_id, - float in_size, - float in_runspeed, - const glm::vec4& position, - uint8 in_light, - uint8 in_texture, - uint8 in_helmtexture, - uint16 in_ac, - uint16 in_atk, - uint16 in_str, - uint16 in_sta, - uint16 in_dex, - uint16 in_agi, - uint16 in_int, - uint16 in_wis, - uint16 in_cha, - uint8 in_haircolor, - uint8 in_beardcolor, - uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye? - uint8 in_eyecolor2, - uint8 in_hairstyle, - uint8 in_luclinface, - uint8 in_beard, - uint32 in_drakkin_heritage, - uint32 in_drakkin_tattoo, - uint32 in_drakkin_details, - EQEmu::TintProfile in_armor_tint, - uint8 in_aa_title, - uint8 in_see_invis, // see through invis - uint8 in_see_invis_undead, // see through invis vs. undead - uint8 in_see_hide, - uint8 in_see_improved_hide, - int32 in_hp_regen, - int32 in_mana_regen, - uint8 in_qglobal, - uint8 in_maxlevel, - uint32 in_scalerate, - uint8 in_armtexture, - uint8 in_bracertexture, - uint8 in_handtexture, - uint8 in_legtexture, - uint8 in_feettexture + Mob( + const char *in_name, + const char *in_lastname, + int32 in_cur_hp, + int32 in_max_hp, + uint8 in_gender, + uint16 in_race, + uint8 in_class, + bodyType in_bodytype, + uint8 in_deity, + uint8 in_level, + uint32 in_npctype_id, + float in_size, + float in_runspeed, + const glm::vec4 &position, + uint8 in_light, + uint8 in_texture, + uint8 in_helmtexture, + uint16 in_ac, + uint16 in_atk, + uint16 in_str, + uint16 in_sta, + uint16 in_dex, + uint16 in_agi, + uint16 in_int, + uint16 in_wis, + uint16 in_cha, + uint8 in_haircolor, + uint8 in_beardcolor, + uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye? + uint8 in_eyecolor2, + uint8 in_hairstyle, + uint8 in_luclinface, + uint8 in_beard, + uint32 in_drakkin_heritage, + uint32 in_drakkin_tattoo, + uint32 in_drakkin_details, + EQEmu::TintProfile in_armor_tint, + uint8 in_aa_title, + uint8 in_see_invis, // see through invis + uint8 in_see_invis_undead, // see through invis vs. undead + uint8 in_see_hide, + uint8 in_see_improved_hide, + int32 in_hp_regen, + int32 in_mana_regen, + uint8 in_qglobal, + uint8 in_maxlevel, + uint32 in_scalerate, + uint8 in_armtexture, + uint8 in_bracertexture, + uint8 in_handtexture, + uint8 in_legtexture, + uint8 in_feettexture ); virtual ~Mob(); @@ -237,30 +238,43 @@ public: return; } - //Appearance - void SendLevelAppearance(); - void SendStunAppearance(); - void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, - Client *specific_target=nullptr); - void SendTargetable(bool on, Client *specific_target = nullptr); - virtual void SendArmorAppearance(Client *one_client = nullptr); - virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr); - virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, - uint32 unknown06 = 0, uint32 unknown18 = 0); - virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint); - virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0); - void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone); - void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0, - float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery); - void ChangeSize(float in_size, bool bNoRestriction = false); - inline uint8 SeeInvisible() const { return see_invis; } - inline bool SeeInvisibleUndead() const { return see_invis_undead; } + /** + ************************************************ + * Appearance + ************************************************ + */ + + EQEmu::InternalTextureProfile mob_texture_profile = {}; + + bool IsInvisible(Mob* other = 0) const; + + EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt); + + inline bool GetSeeInvisible(uint8 see_invis); inline bool SeeHide() const { return see_hide; } inline bool SeeImprovedHide() const { return see_improved_hide; } - inline bool GetSeeInvisible(uint8 see_invis); - bool IsInvisible(Mob* other = 0) const; + inline bool SeeInvisibleUndead() const { return see_invis_undead; } + inline uint8 SeeInvisible() const { return see_invis; } + + int32 GetTextureProfileMaterial(uint8 material_slot) const; + int32 GetTextureProfileColor(uint8 material_slot) const; + int32 GetTextureProfileHeroForgeModel(uint8 material_slot) const; + + virtual void SendArmorAppearance(Client *one_client = nullptr); + virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, uint32 unknown06 = 0, uint32 unknown18 = 0); + virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr); + virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint); + virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0); + + void ChangeSize(float in_size, bool bNoRestriction = false); + void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone); + void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0, float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery); + void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, Client *specific_target=nullptr); + void SendLevelAppearance(); + void SendStunAppearance(); + void SendTargetable(bool on, Client *specific_target = nullptr); void SetInvisible(uint8 state); - EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt); + void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0); //Song bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1); @@ -410,7 +424,7 @@ public: bool CanFacestab() { return can_facestab; } void SetFacestab(bool val) { can_facestab = val; } virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { return 0; } - virtual uint32 GetEquipment(uint8 material_slot) const { return(0); } + virtual uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const { return(0); } virtual int32 GetEquipmentMaterial(uint8 material_slot) const; virtual int32 GetHerosForgeModel(uint8 material_slot) const; virtual uint32 GetEquipmentColor(uint8 material_slot) const; @@ -420,12 +434,12 @@ public: virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) = 0; virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) = 0; - inline virtual void SetHP(int32 hp) { if (hp >= max_hp) cur_hp = max_hp; else cur_hp = hp;} + inline virtual void SetHP(int32 hp) { if (hp >= max_hp) current_hp = max_hp; else current_hp = hp;} bool ChangeHP(Mob* other, int32 amount, uint16 spell_id = 0, int8 buffslot = -1, bool iBuffTic = false); inline void SetOOCRegen(int32 newoocregen) {ooc_regen = newoocregen;} virtual void Heal(); virtual void HealDamage(uint32 ammount, Mob* caster = nullptr, uint16 spell_id = SPELL_UNKNOWN); - virtual void SetMaxHP() { cur_hp = max_hp; } + virtual void SetMaxHP() { current_hp = max_hp; } virtual inline uint16 GetBaseRace() const { return base_race; } virtual inline uint8 GetBaseGender() const { return base_gender; } virtual inline uint16 GetDeity() const { return deity; } @@ -471,8 +485,8 @@ public: inline Mob* GetTarget() const { return target; } virtual void SetTarget(Mob* mob); inline bool HasTargetReflection() const { return (target && target != this && target->target == this); } - virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); } - virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast(cur_hp * 100 / max_hp); } + virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)current_hp/max_hp*100); } + virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast(current_hp * 100 / max_hp); } inline int32 GetAC() const { return AC; } inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } @@ -521,7 +535,7 @@ public: inline virtual int32 GetMaxCR() const { return 255; } inline virtual int32 GetMaxFR() const { return 255; } inline virtual int32 GetDelayDeath() const { return 0; } - inline int32 GetHP() const { return cur_hp; } + inline int32 GetHP() const { return current_hp; } inline int32 GetMaxHP() const { return max_hp; } virtual int32 CalcMaxHP(); inline int32 GetMaxMana() const { return max_mana; } @@ -1231,7 +1245,7 @@ protected: int targeted; bool findable; bool trackable; - int32 cur_hp; + int32 current_hp; int32 max_hp; int32 base_hp; int32 current_mana; diff --git a/zone/mob_appearance.cpp b/zone/mob_appearance.cpp new file mode 100644 index 000000000..85894994b --- /dev/null +++ b/zone/mob_appearance.cpp @@ -0,0 +1,544 @@ +/** + * 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 "../common/eqemu_logsys.h" + +#include "../common/misc_functions.h" +#include "../common/spdat.h" +#include "../common/string_util.h" + +#include "mob.h" +#include "quest_parser_collection.h" +#include "zonedb.h" + +/** + * Stores internal representation of mob texture by material slot + * + * @param material_slot + * @param texture + * @param color + * @param hero_forge_model + */ +void Mob::SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model) +{ + Log(Logs::Detail, Logs::MobAppearance, + "Mob::SetMobTextureProfile [%s] material_slot: %u texture: %u color: %u hero_forge_model: %u", + this->GetCleanName(), + material_slot, + texture, + color, + hero_forge_model + ); + + switch (material_slot) { + case EQEmu::textures::armorHead: + mob_texture_profile.Head.Material = texture; + mob_texture_profile.Head.HerosForgeModel = hero_forge_model; + mob_texture_profile.Head.Color = color; + break; + case EQEmu::textures::armorChest: + mob_texture_profile.Chest.Material = texture; + mob_texture_profile.Chest.HerosForgeModel = hero_forge_model; + mob_texture_profile.Chest.Color = color; + break; + case EQEmu::textures::armorArms: + mob_texture_profile.Arms.Material = texture; + mob_texture_profile.Arms.HerosForgeModel = hero_forge_model; + mob_texture_profile.Arms.Color = color; + break; + case EQEmu::textures::armorWrist: + mob_texture_profile.Wrist.Material = texture; + mob_texture_profile.Wrist.HerosForgeModel = hero_forge_model; + mob_texture_profile.Wrist.Color = color; + break; + case EQEmu::textures::armorHands: + mob_texture_profile.Hands.Material = texture; + mob_texture_profile.Hands.HerosForgeModel = hero_forge_model; + mob_texture_profile.Hands.Color = color; + break; + case EQEmu::textures::armorLegs: + mob_texture_profile.Legs.Material = texture; + mob_texture_profile.Legs.HerosForgeModel = hero_forge_model; + mob_texture_profile.Legs.Color = color; + break; + case EQEmu::textures::armorFeet: + mob_texture_profile.Feet.Material = texture; + mob_texture_profile.Feet.HerosForgeModel = hero_forge_model; + mob_texture_profile.Feet.Color = color; + break; + case EQEmu::textures::weaponPrimary: + mob_texture_profile.Primary.Material = texture; + mob_texture_profile.Primary.HerosForgeModel = hero_forge_model; + mob_texture_profile.Primary.Color = color; + break; + case EQEmu::textures::weaponSecondary: + mob_texture_profile.Secondary.Material = texture; + mob_texture_profile.Secondary.HerosForgeModel = hero_forge_model; + mob_texture_profile.Secondary.Color = color; + break; + default: + return; + } +} + +/** + * Returns internal representation of mob texture by material + * + * @param material_slot + * @return + */ +int32 Mob::GetTextureProfileMaterial(uint8 material_slot) const +{ + switch (material_slot) { + case EQEmu::textures::armorHead: + return mob_texture_profile.Head.Material; + case EQEmu::textures::armorChest: + return mob_texture_profile.Chest.Material; + case EQEmu::textures::armorArms: + return mob_texture_profile.Arms.Material; + case EQEmu::textures::armorWrist: + return mob_texture_profile.Wrist.Material; + case EQEmu::textures::armorHands: + return mob_texture_profile.Hands.Material; + case EQEmu::textures::armorLegs: + return mob_texture_profile.Legs.Material; + case EQEmu::textures::armorFeet: + return mob_texture_profile.Feet.Material; + case EQEmu::textures::weaponPrimary: + return mob_texture_profile.Primary.Material; + case EQEmu::textures::weaponSecondary: + return mob_texture_profile.Secondary.Material; + default: + return 0; + } +} + +/** + * Returns internal representation of mob texture by color + * + * @param material_slot + * @return + */ +int32 Mob::GetTextureProfileColor(uint8 material_slot) const +{ + switch (material_slot) { + case EQEmu::textures::armorHead: + return mob_texture_profile.Head.Color; + case EQEmu::textures::armorChest: + return mob_texture_profile.Chest.Color; + case EQEmu::textures::armorArms: + return mob_texture_profile.Arms.Color; + case EQEmu::textures::armorWrist: + return mob_texture_profile.Wrist.Color; + case EQEmu::textures::armorHands: + return mob_texture_profile.Hands.Color; + case EQEmu::textures::armorLegs: + return mob_texture_profile.Legs.Color; + case EQEmu::textures::armorFeet: + return mob_texture_profile.Feet.Color; + case EQEmu::textures::weaponPrimary: + return mob_texture_profile.Primary.Color; + case EQEmu::textures::weaponSecondary: + return mob_texture_profile.Secondary.Color; + default: + return 0; + } +} + +/** + * Returns internal representation of mob texture by HerosForgeModel + * + * @param material_slot + * @return + */ +int32 Mob::GetTextureProfileHeroForgeModel(uint8 material_slot) const +{ + switch (material_slot) { + case EQEmu::textures::armorHead: + return mob_texture_profile.Head.HerosForgeModel; + case EQEmu::textures::armorChest: + return mob_texture_profile.Chest.HerosForgeModel; + case EQEmu::textures::armorArms: + return mob_texture_profile.Arms.HerosForgeModel; + case EQEmu::textures::armorWrist: + return mob_texture_profile.Wrist.HerosForgeModel; + case EQEmu::textures::armorHands: + return mob_texture_profile.Hands.HerosForgeModel; + case EQEmu::textures::armorLegs: + return mob_texture_profile.Legs.HerosForgeModel; + case EQEmu::textures::armorFeet: + return mob_texture_profile.Feet.HerosForgeModel; + case EQEmu::textures::weaponPrimary: + return mob_texture_profile.Primary.HerosForgeModel; + case EQEmu::textures::weaponSecondary: + return mob_texture_profile.Secondary.HerosForgeModel; + default: + return 0; + } +} + +/** + * Gets the material or texture for a slot (leather / plate etc.) + * + * @param material_slot + * @return + */ +int32 Mob::GetEquipmentMaterial(uint8 material_slot) const +{ + uint32 equipment_material = 0; + int32 ornamentation_augment_type = RuleI(Character, OrnamentationAugmentType); + + int32 texture_profile_material = GetTextureProfileMaterial(material_slot); + + Log(Logs::Detail, Logs::MobAppearance, + "Mob::GetEquipmentMaterial [%s] material_slot: %u texture_profile_material: %i", + this->clean_name, + material_slot, + texture_profile_material + ); + + if (texture_profile_material > 0) { + return texture_profile_material; + } + + auto item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); + + if (item != nullptr) { + + /** + * Handle primary / secondary texture + */ + bool is_primary_or_secondary_weapon = + material_slot == EQEmu::textures::weaponPrimary || + material_slot == EQEmu::textures::weaponSecondary; + + if (is_primary_or_secondary_weapon) { + if (this->IsClient()) { + + int16 inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); + if (inventory_slot == INVALID_INDEX) { + return 0; + } + + const EQEmu::ItemInstance *item_instance = CastToClient()->m_inv[inventory_slot]; + if (item_instance) { + if (item_instance->GetOrnamentationAug(ornamentation_augment_type)) { + item = item_instance->GetOrnamentationAug(ornamentation_augment_type)->GetItem(); + if (item && strlen(item->IDFile) > 2) { + equipment_material = atoi(&item->IDFile[2]); + } + } + else if (item_instance->GetOrnamentationIDFile()) { + equipment_material = item_instance->GetOrnamentationIDFile(); + } + } + } + + if (equipment_material == 0 && strlen(item->IDFile) > 2) { + equipment_material = atoi(&item->IDFile[2]); + } + } + else { + equipment_material = item->Material; + } + } + + return equipment_material; +} + +/** + * @param material_slot + * @return + */ +uint32 Mob::GetEquipmentColor(uint8 material_slot) const +{ + const EQEmu::ItemData *item = nullptr; + + if (armor_tint.Slot[material_slot].Color) { + return armor_tint.Slot[material_slot].Color; + } + + item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); + if (item != nullptr) { + return item->Color; + } + + return 0; +} + +/** + * @param material_slot + * @return + */ +int32 Mob::GetHerosForgeModel(uint8 material_slot) const +{ + uint32 hero_model = 0; + if (material_slot >= 0 && material_slot < EQEmu::textures::weaponPrimary) { + uint32 ornamentation_aug_type = RuleI(Character, OrnamentationAugmentType); + + const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); + int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); + + if (item != nullptr && invslot != INVALID_INDEX) { + if (IsClient()) { + const EQEmu::ItemInstance *inst = CastToClient()->m_inv[invslot]; + if (inst) { + if (inst->GetOrnamentationAug(ornamentation_aug_type)) { + item = inst->GetOrnamentationAug(ornamentation_aug_type)->GetItem(); + hero_model = item->HerosForgeModel; + } + else if (inst->GetOrnamentHeroModel()) { + hero_model = inst->GetOrnamentHeroModel(); + } + } + } + + if (hero_model == 0) { + hero_model = item->HerosForgeModel; + } + } + + if (IsNPC()) { + hero_model = CastToNPC()->GetHeroForgeModel(); + + /** + * Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots + */ + if (hero_model > 1000 && material_slot != 1 && material_slot != 2 && material_slot != 3 && + material_slot != 5) { + hero_model = 0; + } + } + } + + /** + * Auto-Convert Hero Model to match the slot + * + * Otherwise, use the exact Model if model is > 999 + * Robes for example are 11607 to 12107 in RoF + */ + if (hero_model > 0 && hero_model < 1000) { + hero_model *= 100; + hero_model += material_slot; + } + + return hero_model; +} + +uint32 NPC::GetEquippedItemFromTextureSlot(uint8 material_slot) const +{ + if (material_slot > 8) { + return 0; + } + + int16 inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); + if (inventory_slot == INVALID_INDEX) { + return 0; + } + + return equipment[inventory_slot]; +} + +/** + * NPCs typically use this function for sending appearance + * @param one_client + */ +void Mob::SendArmorAppearance(Client *one_client) +{ + /** + * one_client of 0 means sent to all clients + * + * Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the + * armor being worn and its mats, the client doesn't update the display + * on arrival of these packets reliably. + * + * Send Wear changes if mob is a PC race and item is an armor slot. + * The other packets work for primary/secondary. + */ + + Log(Logs::Detail, Logs::MobAppearance, "Mob::SendArmorAppearance [%s]", + this->GetCleanName() + ); + + if (IsPlayerRace(race)) { + if (!IsClient()) { + for (uint8 i = 0; i <= EQEmu::textures::materialCount; ++i) { + const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(i)); + if (item != nullptr) { + SendWearChange(i, one_client); + } + } + } + } + + for (uint8 i = 0; i <= EQEmu::textures::materialCount; ++i) { + if (GetTextureProfileMaterial(i)) { + SendWearChange(i, one_client); + } + } +} + +/** + * @param material_slot + * @param one_client + */ +void Mob::SendWearChange(uint8 material_slot, Client *one_client) +{ + auto packet = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto *wear_change = (WearChange_Struct *) packet->pBuffer; + + Log(Logs::Detail, Logs::MobAppearance, "Mob::SendWearChange [%s]", + this->GetCleanName() + ); + + wear_change->spawn_id = GetID(); + wear_change->material = static_cast(GetEquipmentMaterial(material_slot)); + wear_change->elite_material = IsEliteMaterialItem(material_slot); + wear_change->hero_forge_model = static_cast(GetHerosForgeModel(material_slot)); + +#ifdef BOTS + if (IsBot()) { + auto item_inst = CastToBot()->GetBotItem(EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot)); + if (item_inst) + wear_change->color.Color = item_inst->GetColor(); + else + wear_change->color.Color = 0; + } + else { + wear_change->color.Color = GetEquipmentColor(material_slot); + } +#else + wear_change->color.Color = GetEquipmentColor(material_slot); +#endif + + wear_change->wear_slot_id = material_slot; + + if (!one_client) { + entity_list.QueueClients(this, packet); + } + else { + one_client->QueuePacket(packet, false, Client::CLIENT_CONNECTED); + } + + safe_delete(packet); +} + +/** + * + * @param slot + * @param texture + * @param hero_forge_model + * @param elite_material + * @param unknown06 + * @param unknown18 + */ +void Mob::SendTextureWC( + uint8 slot, + uint16 texture, + uint32 hero_forge_model, + uint32 elite_material, + uint32 unknown06, + uint32 unknown18 +) +{ + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto *wear_change = (WearChange_Struct *) outapp->pBuffer; + + if (this->IsClient()) { + wear_change->color.Color = GetEquipmentColor(slot); + } + else { + wear_change->color.Color = this->GetArmorTint(slot); + } + + wear_change->spawn_id = this->GetID(); + wear_change->material = texture; + wear_change->wear_slot_id = slot; + wear_change->unknown06 = unknown06; + wear_change->elite_material = elite_material; + wear_change->hero_forge_model = hero_forge_model; + wear_change->unknown18 = unknown18; + + SetMobTextureProfile(slot, texture, wear_change->color.Color, hero_forge_model); + + entity_list.QueueClients(this, outapp); + safe_delete(outapp); +} + +/** + * @param material_slot + * @param red_tint + * @param green_tint + * @param blue_tint + */ +void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint) +{ + uint32 color; + color = (red_tint & 0xFF) << 16; + color |= (green_tint & 0xFF) << 8; + color |= (blue_tint & 0xFF); + color |= (color) ? (0xFF << 24) : 0; + armor_tint.Slot[material_slot].Color = color; + + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto *wc = (WearChange_Struct *) outapp->pBuffer; + + wc->spawn_id = this->GetID(); + wc->material = GetEquipmentMaterial(material_slot); + wc->hero_forge_model = GetHerosForgeModel(material_slot); + wc->color.Color = color; + wc->wear_slot_id = material_slot; + + SetMobTextureProfile(material_slot, texture, color); + + entity_list.QueueClients(this, outapp); + safe_delete(outapp); +} + +/** + * @param material_slot + * @param texture + * @param color + * @param hero_forge_model + */ +void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model) +{ + armor_tint.Slot[material_slot].Color = color; + + /** + * Change internal values + */ + SetMobTextureProfile(material_slot, texture, color, hero_forge_model); + + /** + * Packet update + */ + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto *wear_change = (WearChange_Struct *) outapp->pBuffer; + + wear_change->spawn_id = this->GetID(); + wear_change->material = texture; + wear_change->hero_forge_model = hero_forge_model; + wear_change->color.Color = color; + wear_change->wear_slot_id = material_slot; + + entity_list.QueueClients(this, outapp); + safe_delete(outapp); +} \ No newline at end of file diff --git a/zone/npc.cpp b/zone/npc.cpp index 31a8b9445..6f047169a 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -973,7 +973,7 @@ bool NPC::SpawnZoneController() memset(npc_type, 0, sizeof(NPCType)); strncpy(npc_type->name, "zone_controller", 60); - npc_type->cur_hp = 2000000000; + npc_type->current_hp = 2000000000; npc_type->max_hp = 2000000000; npc_type->hp_regen = 100000000; npc_type->race = 240; @@ -1024,7 +1024,7 @@ NPC * NPC::SpawnGridNodeNPC(std::string name, const glm::vec4 &position, uint32 sprintf(npc_type->name, "%u_%u", grid_id, grid_number); sprintf(npc_type->lastname, "Number: %u Grid: %u Pause: %u", grid_number, grid_id, pause); - npc_type->cur_hp = 4000000; + npc_type->current_hp = 4000000; npc_type->max_hp = 4000000; npc_type->race = 2254; npc_type->gender = 2; @@ -1058,7 +1058,7 @@ NPC * NPC::SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 sprintf(npc_type->name, "%s", name.c_str()); sprintf(npc_type->lastname, "%s", last_name.c_str()); - npc_type->cur_hp = 4000000; + npc_type->current_hp = 4000000; npc_type->max_hp = 4000000; npc_type->race = 2254; npc_type->gender = 2; @@ -1095,33 +1095,45 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* else { Seperator sep(spawncommand); //Lets see if someone didn't fill out the whole #spawn function properly - if (!sep.IsNumber(1)) - sprintf(sep.arg[1],"1"); - if (!sep.IsNumber(2)) - sprintf(sep.arg[2],"1"); - if (!sep.IsNumber(3)) - sprintf(sep.arg[3],"0"); - if (atoi(sep.arg[4]) > 2100000000 || atoi(sep.arg[4]) <= 0) - sprintf(sep.arg[4]," "); - if (!strcmp(sep.arg[5],"-")) - sprintf(sep.arg[5]," "); - if (!sep.IsNumber(5)) - sprintf(sep.arg[5]," "); - if (!sep.IsNumber(6)) - sprintf(sep.arg[6],"1"); - if (!sep.IsNumber(8)) - sprintf(sep.arg[8],"0"); - if (!sep.IsNumber(9)) + if (!sep.IsNumber(1)) { + sprintf(sep.arg[1], "1"); + } + if (!sep.IsNumber(2)) { + sprintf(sep.arg[2], "1"); + } + if (!sep.IsNumber(3)) { + sprintf(sep.arg[3], "0"); + } + if (atoi(sep.arg[4]) > 2100000000 || atoi(sep.arg[4]) <= 0) { + sprintf(sep.arg[4], " "); + } + if (!strcmp(sep.arg[5], "-")) { + sprintf(sep.arg[5], " "); + } + if (!sep.IsNumber(5)) { + sprintf(sep.arg[5], " "); + } + if (!sep.IsNumber(6)) { + sprintf(sep.arg[6], "1"); + } + if (!sep.IsNumber(8)) { + sprintf(sep.arg[8], "0"); + } + if (!sep.IsNumber(9)) { sprintf(sep.arg[9], "0"); - if (!sep.IsNumber(7)) - sprintf(sep.arg[7],"0"); - if (!strcmp(sep.arg[4],"-")) - sprintf(sep.arg[4]," "); - if (!sep.IsNumber(10)) // bodytype + } + if (!sep.IsNumber(7)) { + sprintf(sep.arg[7], "0"); + } + if (!strcmp(sep.arg[4], "-")) { + sprintf(sep.arg[4], " "); + } + if (!sep.IsNumber(10)) { // bodytype sprintf(sep.arg[10], "0"); + } //Calc MaxHP if client neglected to enter it... - if (!sep.IsNumber(4)) { - sep.arg[4] = 0; + if (sep.arg[4] && !sep.IsNumber(4)) { + sprintf(sep.arg[4], "0"); } // Autoselect NPC Gender @@ -1134,7 +1146,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* memset(npc_type, 0, sizeof(NPCType)); strncpy(npc_type->name, sep.arg[0], 60); - npc_type->cur_hp = atoi(sep.arg[4]); + npc_type->current_hp = atoi(sep.arg[4]); npc_type->max_hp = atoi(sep.arg[4]); npc_type->race = atoi(sep.arg[1]); npc_type->gender = atoi(sep.arg[5]); @@ -1487,38 +1499,49 @@ uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_ver int32 NPC::GetEquipmentMaterial(uint8 material_slot) const { - if (material_slot >= EQEmu::textures::materialCount) + int32 texture_profile_material = GetTextureProfileMaterial(material_slot); + + Log(Logs::Detail, Logs::MobAppearance, "NPC::GetEquipmentMaterial [%s] material_slot: %u", + this->clean_name, + material_slot + ); + + if (texture_profile_material > 0) { + return texture_profile_material; + } + + if (material_slot >= EQEmu::textures::materialCount) { return 0; + } int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot); - if (invslot == INVALID_INDEX) + if (invslot == INVALID_INDEX) { return 0; + } - if (equipment[invslot] == 0) - { - switch(material_slot) - { - case EQEmu::textures::armorHead: - return helmtexture; - case EQEmu::textures::armorChest: - return texture; - case EQEmu::textures::armorArms: - return armtexture; - case EQEmu::textures::armorWrist: - return bracertexture; - case EQEmu::textures::armorHands: - return handtexture; - case EQEmu::textures::armorLegs: - return legtexture; - case EQEmu::textures::armorFeet: - return feettexture; - case EQEmu::textures::weaponPrimary: - return d_melee_texture1; - case EQEmu::textures::weaponSecondary: - return d_melee_texture2; - default: - //they have nothing in the slot, and its not a special slot... they get nothing. - return(0); + if (equipment[invslot] == 0) { + switch (material_slot) { + case EQEmu::textures::armorHead: + return helmtexture; + case EQEmu::textures::armorChest: + return texture; + case EQEmu::textures::armorArms: + return armtexture; + case EQEmu::textures::armorWrist: + return bracertexture; + case EQEmu::textures::armorHands: + return handtexture; + case EQEmu::textures::armorLegs: + return legtexture; + case EQEmu::textures::armorFeet: + return feettexture; + case EQEmu::textures::weaponPrimary: + return d_melee_texture1; + case EQEmu::textures::weaponSecondary: + return d_melee_texture2; + default: + //they have nothing in the slot, and its not a special slot... they get nothing. + return (0); } } @@ -2164,8 +2187,8 @@ void NPC::ModifyNPCStat(const char *identifier, const char *new_value) base_hp = atoi(val.c_str()); CalcMaxHP(); - if (cur_hp > max_hp) { - cur_hp = max_hp; + if (current_hp > max_hp) { + current_hp = max_hp; } return; @@ -2346,14 +2369,14 @@ void NPC::LevelScale() { base_hp += (random_level - level) * 100; } - cur_hp = max_hp; + current_hp = max_hp; max_dmg += (random_level - level) * 2; } else { uint8 scale_adjust = 1; base_hp += (int)(base_hp * scaling); max_hp += (int)(max_hp * scaling); - cur_hp = max_hp; + current_hp = max_hp; if (max_dmg) { max_dmg += (int)(max_dmg * scaling / scale_adjust); @@ -2394,7 +2417,7 @@ void NPC::LevelScale() { ATK += (int)(ATK * scaling); base_hp += (int)(base_hp * scaling); max_hp += (int)(max_hp * scaling); - cur_hp = max_hp; + current_hp = max_hp; STR += (int)(STR * scaling / scale_adjust); STA += (int)(STA * scaling / scale_adjust); AGI += (int)(AGI * scaling / scale_adjust); diff --git a/zone/npc.h b/zone/npc.h index 7ad1fccd0..b9e0458e6 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -311,7 +311,7 @@ public: void MoveTo(const glm::vec4& position, bool saveguardspot); void GetClosestWaypoint(std::list &wp_list, int count, const glm::vec3& location); - uint32 GetEquipment(uint8 material_slot) const; // returns item id + uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id int32 GetEquipmentMaterial(uint8 material_slot) const; void NextGuardPosition(); @@ -468,6 +468,7 @@ public: virtual int GetStuckBehavior() const { return NPCTypedata_ours ? NPCTypedata_ours->stuck_behavior : NPCTypedata->stuck_behavior; } + protected: const NPCType* NPCTypedata; diff --git a/zone/pathfinder_waypoint.cpp b/zone/pathfinder_waypoint.cpp index 3d3f0162d..58ad5afea 100644 --- a/zone/pathfinder_waypoint.cpp +++ b/zone/pathfinder_waypoint.cpp @@ -529,7 +529,7 @@ void PathfinderWaypoint::ShowNode(const Node &n) { sprintf(npc_type->name, "%s", DigitToWord(n.id).c_str()); sprintf(npc_type->lastname, "%i", n.id); - npc_type->cur_hp = 4000000; + npc_type->current_hp = 4000000; npc_type->max_hp = 4000000; npc_type->race = 2254; npc_type->gender = 2; diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 6177961f4..b9884b2a0 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -639,7 +639,7 @@ XS(XS_Mob_GetEquipment) { if (THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->GetEquipment(material_slot); + RETVAL = THIS->GetEquippedItemFromTextureSlot(material_slot); XSprePUSH; PUSHi((IV) RETVAL); } diff --git a/zone/pets.cpp b/zone/pets.cpp index ad88f7a60..ab1f13bce 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -240,7 +240,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, if(scale_power > 0) { npc_type->max_hp *= (1 + scale_power); - npc_type->cur_hp = npc_type->max_hp; + npc_type->current_hp = npc_type->max_hp; npc_type->AC *= (1 + scale_power); npc_type->level += 1 + ((int)act_power / 25) > npc_type->level + RuleR(Pets, PetPowerLevelCap) ? RuleR(Pets, PetPowerLevelCap) : 1 + ((int)act_power / 25); // gains an additional level for every 25 pet power npc_type->min_dmg = (npc_type->min_dmg * (1 + (scale_power / 2))); @@ -255,7 +255,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, if (MaxHP){ npc_type->max_hp += (npc_type->max_hp*MaxHP)/100; - npc_type->cur_hp = npc_type->max_hp; + npc_type->current_hp = npc_type->max_hp; } //TODO: think about regen (engaged vs. not engaged) diff --git a/zone/trap.cpp b/zone/trap.cpp index 191d80fce..5e4198e5b 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -456,7 +456,7 @@ void Trap::CreateHiddenTrigger() auto make_npc = new NPCType; memcpy(make_npc, base_type, sizeof(NPCType)); make_npc->max_hp = 100000; - make_npc->cur_hp = 100000; + make_npc->current_hp = 100000; strcpy(make_npc->name, "a_trap"); make_npc->runspeed = 0.0f; make_npc->bodytype = BT_Special; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index d721edba4..b30c037b7 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -2495,7 +2495,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load temp_npctype_data->race = atoi(row[3]); temp_npctype_data->class_ = atoi(row[4]); temp_npctype_data->max_hp = atoi(row[5]); - temp_npctype_data->cur_hp = temp_npctype_data->max_hp; + temp_npctype_data->current_hp = temp_npctype_data->max_hp; temp_npctype_data->Mana = atoi(row[6]); temp_npctype_data->gender = atoi(row[7]); temp_npctype_data->texture = atoi(row[8]); @@ -2777,7 +2777,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client tmpNPCType->race = atoi(row[3]); tmpNPCType->class_ = atoi(row[4]); tmpNPCType->max_hp = atoi(row[5]); - tmpNPCType->cur_hp = tmpNPCType->max_hp; + tmpNPCType->current_hp = tmpNPCType->max_hp; tmpNPCType->Mana = atoi(row[6]); tmpNPCType->gender = atoi(row[7]); tmpNPCType->texture = atoi(row[8]); diff --git a/zone/zonedump.h b/zone/zonedump.h index 6636bfa1e..b75057a16 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -36,7 +36,7 @@ struct NPCType { char name[64]; char lastname[70]; - int32 cur_hp; + int32 current_hp; int32 max_hp; float size; float runspeed;