diff --git a/changelog.txt b/changelog.txt index ca32db0d7..5aa90cfc9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,55 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 01/03/2015 == +Trevius: (RoF2) /shield (shielding) and /key (key ring) are both now functional after opcode updates. + +== 01/02/2015 == +Trevius: (RoF2) *Hopefully* Fixed looting incorrect items from NPCs. Please report any issues! +Trevius: (RoF2) Now able to loot items past the 10th slot on NPC corpses. +Trevius: Attuned Items can now be auto-looted and will equip properly. +Trevius: Mercenaries and Bots will no longer take a share from /split or /autosplit. + +== 12/30/2014 == +Trevius: (RoF2) Aug Type 21 no longer shows the "Buy Now" button in the aug slot of items. +Trevius: (RoF2) Identified the "Copied" item flag with the help of Uleat. + +== 12/29/2014 == +Trevius: (RoF2) Identified a few Item Fields and resolved an issue with cloth armor not accepting certain augments that they should. +Akkadius: Updated $client->UpdateTaskActivity to have optional argument ignore_quest_update IE: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count, [ignore_quest_update]) +Akkadius: Also updated internal UpdateTaskActivity methods to optionally ignore quest based task updates to prevent feedback + +== 12/28/2014 == +Uleat: Implemented class Client::TextLink as a replacement for the dozens of individual link formatters. + +== 12/27/2014 == +Akkadius: Add option to automatic database upgrade script 5) Download latest Opcodes from Github +Trevius: (RoF2) Fixed dropping items on the ground so they go to ground level instead of camera height. +Trevius: Show Helm Option should be functional again. +Kayen: Implemened npc special ability (43) CASTING_RESIST_DIFF which sets innate resist modifier on +ALL spells used by that NPC. Ie. 43,1,-200 will set a -200 innate resist diff, so if your npc cast +a spell that has a -10 resist modifier the final resist diff would be -210. + +== 12/25/2014 == +Uleat: Updated 'links' code for all clients + +== 12/24/2014 == +Trevius: (RoF+) Added herosforgemodel field to the npc_types table. +Trevius: (RoF2) Updated item links from #npcstat command output. +Trevius: (RoF+) Implemented Hero's Forge Armor for NPCs. Set the herosforgemodel field in npc_types table to the model (example: 84 for full set, or 12107 for robe). +Trevius: (RoF+) Hero's Forge Armor now overrides NPC texture settings. To display Hero's Forge Armor Helms, set helmtexture field to anything other than 0. + +== 12/23/2014 == +Uleat: Tidied up some ItemInst* declarations and added some nullptr checks. +Trevius: (RoF+) Added support for Hero's Forge Robe Models. Set herosforgemodel field in items table to exact model such as 11607, 11707, etc. + +== 12/22/2014 == +Trevius: (RoF2) Fixed Tracking. +Trevius: (RoF+) Added a work-around for the cursor buffer issue. + +== 12/21/2014 == +Trevius: (RoF2) Fixed Extended Targets Window by correcting opcodes. +Trevius: (RoF/RoF2) Fixed Guild Rank in the Player Profile, which prevents the guild rank message on login/zone. + == 12/20/2014 == Akkadius: Updated #cvs to display RoF2 Client Stream count diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index cec29178d..07daa97fd 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -1509,7 +1509,8 @@ enum ItemPacketType ItemPacketTributeItem = 0x6C, ItemPacketMerchant = 0x64, ItemPacketWorldContainer = 0x6B, - ItemPacketCharmUpdate = 0x6E + ItemPacketCharmUpdate = 0x6E, + ItemPacketInvalid = 0xFF }; struct ItemPacket_Struct { @@ -3015,14 +3016,14 @@ struct ClientError_Struct }; struct Track_Struct { - uint16 entityid; - uint16 padding002; + uint32 entityid; float distance; // Fields for SoD and later uint8 level; - uint8 NPC; - uint8 GroupMember; + uint8 is_npc; char name[64]; + uint8 is_pet; + uint8 is_merc; }; struct Tracking_Struct { diff --git a/common/item.cpp b/common/item.cpp index 1b99ad779..e5a788879 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -89,6 +89,17 @@ ItemInst* ItemInstQueue::pop() return inst; } +// Remove item from back of queue +ItemInst* ItemInstQueue::pop_back() +{ + if (m_list.size() == 0) + return nullptr; + + ItemInst* inst = m_list.back(); + m_list.pop_back(); + return inst; +} + // Look at item at front of queue ItemInst* ItemInstQueue::peek_front() const { @@ -259,6 +270,11 @@ int16 Inventory::PushCursor(const ItemInst& inst) return MainCursor; } +ItemInst* Inventory::GetCursorItem() +{ + return m_cursor.peek_front(); +} + // Swap items in inventory bool Inventory::SwapItem(int16 slot_a, int16 slot_b) { @@ -1170,13 +1186,13 @@ int16 Inventory::_HasItem(std::map& bucket, uint32 item_id, ui for (itb = inst->_begin(); itb != inst->_end(); ++itb) { ItemInst* baginst = itb->second; - if (baginst->GetID() == item_id) { + if (baginst && baginst->GetID() == item_id) { quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(it->first, itb->first); } for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1) + if (baginst && baginst->GetAugmentItemID(i) == item_id && quantity <= 1) return legacy::SLOT_AUGMENT; // Only one augment per slot. } } @@ -1214,13 +1230,13 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) for (itb = inst->_begin(); itb != inst->_end(); ++itb) { ItemInst* baginst = itb->second; - if (baginst->GetID() == item_id) { + if (baginst && baginst->GetID() == item_id) { quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(MainCursor, itb->first); } for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1) + if (baginst && baginst->GetAugmentItemID(i) == item_id && quantity <= 1) return legacy::SLOT_AUGMENT; // Only one augment per slot. } @@ -1314,7 +1330,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map& bucket, uint32 if (inst->GetItem()->LoreGroup == loregroup) return it->first; - ItemInst* Aug; + ItemInst* Aug = nullptr; for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { Aug = inst->GetAugment(i); if (Aug && Aug->GetItem()->LoreGroup == loregroup) @@ -1329,7 +1345,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map& bucket, uint32 if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup) return Inventory::CalcSlotId(it->first, itb->first); - ItemInst* Aug2; + ItemInst* Aug2 = nullptr; for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { Aug2 = baginst->GetAugment(i); if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup) @@ -1357,7 +1373,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) if (inst->GetItem()->LoreGroup == loregroup) return MainCursor; - ItemInst* Aug; + ItemInst* Aug = nullptr; for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { Aug = inst->GetAugment(i); if (Aug && Aug->GetItem()->LoreGroup == loregroup) @@ -1373,7 +1389,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) return Inventory::CalcSlotId(MainCursor, itb->first); - ItemInst* Aug2; + ItemInst* Aug2 = nullptr; for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { Aug2 = baginst->GetAugment(i); if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup) @@ -1703,6 +1719,8 @@ void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent) end = m_contents.end(); for (; cur != end;) { ItemInst* inst = cur->second; + if (inst == nullptr) + continue; const Item_Struct* item = inst->GetItem(); del = cur; ++cur; diff --git a/common/item.h b/common/item.h index b0aa06466..03182e4dd 100644 --- a/common/item.h +++ b/common/item.h @@ -93,6 +93,7 @@ public: void push(ItemInst* inst); void push_front(ItemInst* inst); ItemInst* pop(); + ItemInst* pop_back(); ItemInst* peek_front() const; inline int size() { return static_cast(m_list.size()); } @@ -152,6 +153,9 @@ public: // Add item to cursor queue int16 PushCursor(const ItemInst& inst); + // Get cursor item in front of queue + ItemInst* GetCursorItem(); + // Swap items in inventory bool SwapItem(int16 slot_a, int16 slot_b); diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index ad6fb95d6..36d487545 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2315,7 +2315,7 @@ namespace RoF outapp->WriteUInt8(emu->gm); outapp->WriteUInt32(emu->guild_id); - outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet. + outapp->WriteUInt8(emu->guildrank); // guildrank outapp->WriteUInt32(0); // Unknown - observed 1 in a live packet. outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet. outapp->WriteUInt32(0); // Unknown @@ -2576,7 +2576,7 @@ namespace RoF strn0cpy(general->player_name, raid_create->leader_name, 64); dest->FastQueuePacket(&outapp_create); - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_RaidUpdate) @@ -2643,7 +2643,7 @@ namespace RoF dest->FastQueuePacket(&outapp); } - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_ReadBook) @@ -2900,7 +2900,7 @@ namespace RoF { eq->entries[i] = emu->entries[i]; } - eq->entries[21] = 0; + eq->entries[21] = 1; FINISH_ENCODE(); } @@ -3294,9 +3294,9 @@ namespace RoF VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid); VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc); VARSTRUCT_ENCODE_STRING(Buffer, emu->name); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc); } delete[] __emu_buffer; @@ -4854,27 +4854,8 @@ namespace RoF ss.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem)); } //ORNAMENT IDFILE / ICON - uint16 ornaIcon = 0; - int32 heroModel = 0; - /* - if (inst->GetOrnamentationAug(ornamentationAugtype)) - { - const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); - //Mainhand - ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - //Offhand - ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - //Icon - ornaIcon = aug_weap->Icon; - if (aug_weap->HerosForgeModel > 0) - { - heroModel = (aug_weap->HerosForgeModel * 100) + Inventory::CalcMaterialFromSlot(slot_id_in); - } - } - else - */ + uint32 ornaIcon = 0; + uint32 heroModel = 0; if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { @@ -4896,8 +4877,6 @@ namespace RoF RoF::structs::ItemSerializationHeaderFinish hdrf; hdrf.ornamentIcon = ornaIcon; - hdrf.unknown061 = 0; - hdrf.unknown062 = 0; hdrf.unknowna1 = 0xffffffff; hdrf.ornamentHeroModel = heroModel; hdrf.unknown063 = 0; @@ -5506,7 +5485,6 @@ namespace RoF static inline uint32 ServerToRoFCorpseSlot(uint32 ServerCorpse) { - //uint32 RoFCorpse; return (ServerCorpse + 1); } @@ -5647,7 +5625,6 @@ namespace RoF static inline uint32 RoFToServerCorpseSlot(uint32 RoFCorpse) { - //uint32 ServerCorpse; return (RoFCorpse - 1); } } diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index a750d2abb..02ac289a9 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -21,15 +21,15 @@ namespace RoF2 static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth, ItemPacketType packet_type); // server to client inventory location converters - static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot); + static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot, ItemPacketType PacketType = ItemPacketInvalid); static inline structs::MainInvItemSlotStruct ServerToRoF2MainInvSlot(uint32 ServerSlot); static inline uint32 ServerToRoF2CorpseSlot(uint32 ServerCorpse); // client to server inventory location converters - static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot); + static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot, ItemPacketType PacketType = ItemPacketInvalid); static inline uint32 RoF2ToServerMainInvSlot(structs::MainInvItemSlotStruct RoF2Slot); static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse); @@ -116,6 +116,72 @@ namespace RoF2 #include "ss_define.h" // ENCODE methods + + + // RoF2 Specific Encodes Begin + ENCODE(OP_SendMembershipDetails) + { + ENCODE_LENGTH_EXACT(Membership_Details_Struct); + SETUP_DIRECT_ENCODE(Membership_Details_Struct, structs::Membership_Details_Struct); + + eq->membership_setting_count = 72; + for (uint32 i = 0; i < emu->membership_setting_count; ++i) // 66 + { + OUT(settings[i].setting_index); + OUT(settings[i].setting_id); + OUT(settings[i].setting_value); + } + // Last 6 new settings fields are all 0s on Live as of 12/29/14 + + eq->race_entry_count = emu->race_entry_count; + for (uint32 i = 0; i < emu->race_entry_count; ++i) // 15 + { + OUT(membership_races[i].purchase_id); + OUT(membership_races[i].bitwise_entry); + } + + eq->class_entry_count = emu->class_entry_count; + for (uint32 i = 0; i < emu->class_entry_count; ++i) // 15 + { + OUT(membership_classes[i].purchase_id); + OUT(membership_classes[i].bitwise_entry); + } + + eq->exit_url_length = emu->exit_url_length; + eq->exit_url_length2 = emu->exit_url_length2; + + FINISH_ENCODE(); + } + + ENCODE(OP_SendMembership) + { + ENCODE_LENGTH_EXACT(Membership_Struct); + SETUP_DIRECT_ENCODE(Membership_Struct, structs::Membership_Struct); + + eq->membership = emu->membership; + eq->races = emu->races; + eq->classes = emu->classes; + eq->entrysize = 25; //emu->entrysize; + + for (uint32 i = 0; i < emu->entrysize; ++i) // 21 + { + OUT(entries[i]); + } + // Last 4 new entries are 0s on Live Silver as of 12/29/14 + // Setting them each to 1 for now. + // This removes the "Buy Now" button from aug type 21 slots on items. + for (uint32 i = 21; i < 25; ++i) // 4 + { + eq->entries[i] = 1; + } + + + FINISH_ENCODE(); + } + + // RoF2 Specific Encodes End + + ENCODE(OP_Action) { ENCODE_LENGTH_EXACT(Action_Struct); @@ -556,7 +622,7 @@ namespace RoF2 uint32 Length = 0; - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); + char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0, ItemPacketCharInventory); if (Serialized) { @@ -1370,7 +1436,7 @@ namespace RoF2 InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0, old_item_pkt->PacketType); if (!serialized) { _log(NET__STRUCTS, "Serialization failed on item slot %d.", int_struct->slot_id); @@ -1676,8 +1742,15 @@ namespace RoF2 eq->FogDensity = emu->fog_density; /*fill in some unknowns with observed values, hopefully it will help */ + eq->unknown569 = 0; + eq->unknown571 = 0; + eq->unknown572 = 4; + eq->unknown576 = 2; + eq->unknown580 = 0; + eq->unknown800 = -1; eq->unknown844 = 600; + eq->unknown848 = 2008; // Guild Lobby observed value eq->unknown880 = 50; eq->unknown884 = 10; eq->unknown888 = 1; @@ -1987,17 +2060,17 @@ namespace RoF2 outapp->WriteUInt32(emu->drakkin_tattoo); outapp->WriteUInt32(emu->drakkin_details); - outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown 0 + outapp->WriteUInt8(0xff); // Unknown 0xff + outapp->WriteUInt8(1); // Unknown 1 + outapp->WriteUInt8(0xff); // Unknown 0xff + outapp->WriteUInt8(1); // Unknown 1 - outapp->WriteFloat(5.0f); // Height ? + outapp->WriteFloat(5.0f); // Height - outapp->WriteFloat(3.0f); // Unknown - outapp->WriteFloat(2.5f); // Unknown - outapp->WriteFloat(5.5f); // Unknown + outapp->WriteFloat(3.0f); // Unknown 3.0 + outapp->WriteFloat(2.5f); // Unknown 2.5 + outapp->WriteFloat(5.5f); // Unknown 5.5 outapp->WriteUInt32(0); // Primary ? outapp->WriteUInt32(0); // Secondary ? @@ -2316,14 +2389,14 @@ namespace RoF2 outapp->WriteUInt8(emu->gm); outapp->WriteUInt32(emu->guild_id); - outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(emu->guildrank); // guildrank outapp->WriteUInt32(0); // Unknown outapp->WriteUInt8(0); // Unknown outapp->WriteUInt32(0); // Unknown outapp->WriteUInt64(emu->exp); // int32 in client - outapp->WriteUInt8(0); // Unknown - Seen 5 on Live + outapp->WriteUInt8(5); // Unknown - Seen 5 on Live - Eye Height? outapp->WriteUInt32(emu->platinum_bank); outapp->WriteUInt32(emu->gold_bank); @@ -2587,7 +2660,7 @@ namespace RoF2 strn0cpy(general->player_name, raid_create->leader_name, 64); dest->FastQueuePacket(&outapp_create); - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_RaidUpdate) @@ -2654,7 +2727,7 @@ namespace RoF2 dest->FastQueuePacket(&outapp); } - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_ReadBook) @@ -2898,24 +2971,6 @@ namespace RoF2 FINISH_ENCODE(); } - ENCODE(OP_SendMembership) - { - ENCODE_LENGTH_EXACT(Membership_Struct); - SETUP_DIRECT_ENCODE(Membership_Struct, structs::Membership_Struct); - - eq->membership = emu->membership; - eq->races = emu->races; - eq->classes = emu->classes; - eq->entrysize = 22; - for (int i = 0; i<21; i++) - { - eq->entries[i] = emu->entries[i]; - } - eq->entries[21] = 0; - - FINISH_ENCODE(); - } - ENCODE(OP_SendZonepoints) { SETUP_VAR_ENCODE(ZonePoints); @@ -3289,7 +3344,7 @@ namespace RoF2 int PacketSize = 2; for (int i = 0; i < EntryCount; ++i, ++emu) - PacketSize += (12 + strlen(emu->name)); + PacketSize += (13 + strlen(emu->name)); emu = (Track_Struct *)__emu_buffer; @@ -3305,9 +3360,10 @@ namespace RoF2 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid); VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc); VARSTRUCT_ENCODE_STRING(Buffer, emu->name); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_pet); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc); } delete[] __emu_buffer; @@ -3734,7 +3790,7 @@ namespace RoF2 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_tattoo); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_details); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2); // unknown8 + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown9 VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown10 VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->helm); // unknown11 @@ -4811,7 +4867,7 @@ namespace RoF2 return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth, ItemPacketType packet_type) { int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); uint8 null_term = 0; @@ -4835,15 +4891,14 @@ namespace RoF2 hdr.stacksize = stackable ? charges : 1; hdr.unknown004 = 0; - structs::ItemSlotStruct slot_id = ServerToRoF2Slot(slot_id_in); + structs::ItemSlotStruct slot_id = ServerToRoF2Slot(slot_id_in, packet_type); hdr.slot_type = (merchant_slot == 0) ? slot_id.SlotType : 9; // 9 is merchant 20 is reclaim items? hdr.main_slot = (merchant_slot == 0) ? slot_id.MainSlot : merchant_slot; hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubSlot : 0xffff; - hdr.unknown013 = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff; + hdr.aug_slot = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff; hdr.price = inst->GetPrice(); hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - //hdr.merchant_slot = (merchant_slot == 0) ? 1 : 0xffffffff; hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; hdr.unknown028 = 0; @@ -4869,28 +4924,9 @@ namespace RoF2 ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem)); } //ORNAMENT IDFILE / ICON - uint16 ornaIcon = 0; - int32 heroModel = 0; - /* - if (inst->GetOrnamentationAug(ornamentationAugtype)) - { - const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); - //Mainhand - ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - //Offhand - ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - //Icon - ornaIcon = aug_weap->Icon; - if (aug_weap->HerosForgeModel > 0) - { - heroModel = (aug_weap->HerosForgeModel * 100) + Inventory::CalcMaterialFromSlot(slot_id_in); - } - } - else - */ - + uint32 ornaIcon = 0; + uint32 heroModel = 0; + if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); @@ -4911,12 +4947,10 @@ namespace RoF2 RoF2::structs::ItemSerializationHeaderFinish hdrf; hdrf.ornamentIcon = ornaIcon; - hdrf.unknown061 = 0; - hdrf.unknown062 = 0; hdrf.unknowna1 = 0xffffffff; hdrf.ornamentHeroModel = heroModel; hdrf.unknown063 = 0; - hdrf.unknowna3 = 0; + hdrf.Copied = 0; hdrf.unknowna4 = 0xffffffff; hdrf.unknowna5 = 0; hdrf.ItemClass = item->ItemClass; @@ -5066,7 +5100,7 @@ namespace RoF2 memset(&isbs, 0, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); isbs.augtype = item->AugType; - isbs.augdistiller = 65535; + isbs.augrestrict2 = -1; isbs.augrestrict = item->AugRestrict; for (int x = AUG_BEGIN; x < consts::ITEM_COMMON_SIZE; x++) @@ -5310,9 +5344,21 @@ namespace RoF2 iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; iqbs.clairvoyance = item->Clairvoyance; - iqbs.unknown28 = 0; - iqbs.unknown30 = 0; - iqbs.unknown37a = 0; + + //unknown18; //Power Source Capacity or evolve filename? + //evolve_string; // Some String, but being evolution related is just a guess + + iqbs.Heirloom = 0; + iqbs.Placeable = 0; + + iqbs.unknown28 = -1; + iqbs.unknown30 = -1; + + iqbs.NoZone = 0; + iqbs.NoGround = 0; + iqbs.unknown37a = 0; // (guessed position) New to RoF2 + iqbs.unknown38 = 0; + iqbs.unknown39 = 1; iqbs.subitem_count = 0; @@ -5350,7 +5396,7 @@ namespace RoF2 SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); */ - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); + SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1, packet_type); } } @@ -5376,7 +5422,7 @@ namespace RoF2 return item_serial; } - static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot) + static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot, ItemPacketType PacketType) { structs::ItemSlotStruct RoF2Slot; RoF2Slot.SlotType = INVALID_INDEX; @@ -5389,13 +5435,21 @@ namespace RoF2 uint32 TempSlot = 0; if (ServerSlot < 56 || ServerSlot == MainPowerSource) { // Main Inventory and Cursor - RoF2Slot.SlotType = maps::MapPossessions; - RoF2Slot.MainSlot = ServerSlot; - + if (PacketType == ItemPacketLoot) + { + RoF2Slot.SlotType = maps::MapCorpse; + RoF2Slot.MainSlot = ServerSlot - EmuConstants::CORPSE_BEGIN; + } + else + { + RoF2Slot.SlotType = maps::MapPossessions; + RoF2Slot.MainSlot = ServerSlot; + } + if (ServerSlot == MainPowerSource) RoF2Slot.MainSlot = slots::MainPowerSource; - else if (ServerSlot >= MainCursor) // Cursor and Extended Corpse Inventory + else if (ServerSlot >= MainCursor && PacketType != ItemPacketLoot) // Cursor and Extended Corpse Inventory RoF2Slot.MainSlot += 3; else if (ServerSlot >= MainAmmo) // (> 20) @@ -5522,11 +5576,10 @@ namespace RoF2 static inline uint32 ServerToRoF2CorpseSlot(uint32 ServerCorpse) { - //uint32 RoF2Corpse; - return (ServerCorpse + 1); + return (ServerCorpse - EmuConstants::CORPSE_BEGIN + 1); } - static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot) + static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot, ItemPacketType PacketType) { uint32 ServerSlot = INVALID_INDEX; uint32 TempSlot = 0; @@ -5621,6 +5674,10 @@ namespace RoF2 ServerSlot = INVALID_INDEX; } + else if (RoF2Slot.SlotType == maps::MapCorpse) { + ServerSlot = RoF2Slot.MainSlot + EmuConstants::CORPSE_BEGIN; + } + _log(NET__ERROR, "Convert RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", RoF2Slot.SlotType, RoF2Slot.Unknown02, RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01, ServerSlot); return ServerSlot; @@ -5663,8 +5720,7 @@ namespace RoF2 static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse) { - //uint32 ServerCorpse; - return (RoF2Corpse - 1); + return (RoF2Corpse + EmuConstants::CORPSE_BEGIN - 1); } } // end namespace RoF2 diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 19519212a..79614504d 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -1,6 +1,8 @@ // out-going packets that require an ENCODE translation: // Begin RoF2 Encodes +E(OP_SendMembershipDetails) + // incoming packets that require a DECODE translation: // Begin RoF2 Decodes diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 6776ff0e7..9ba71574c 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -243,11 +243,11 @@ struct Membership_Setting_Struct struct Membership_Details_Struct { /*0000*/ uint32 membership_setting_count; // Seen 66 -/*0016*/ Membership_Setting_Struct settings[66]; +/*0016*/ Membership_Setting_Struct settings[72]; // 864 Bytes /*0012*/ uint32 race_entry_count; // Seen 15 -/*1044*/ Membership_Entry_Struct membership_races[15]; +/*1044*/ Membership_Entry_Struct membership_races[15]; // 120 Bytes /*0012*/ uint32 class_entry_count; // Seen 15 -/*1044*/ Membership_Entry_Struct membership_classes[15]; +/*1044*/ Membership_Entry_Struct membership_classes[15]; // 120 Bytes /*1044*/ uint32 exit_url_length; // Length of the exit_url string (0 for none) /*1048*/ //char exit_url[42]; // Upgrade to Silver or Gold Membership URL /*1048*/ uint32 exit_url_length2; // Length of the exit_url2 string (0 for none) @@ -260,7 +260,7 @@ struct Membership_Struct /*004*/ uint32 races; // Seen ff ff 01 00 /*008*/ uint32 classes; // Seen ff ff 01 01 /*012*/ uint32 entrysize; // Seen 22 -/*016*/ int32 entries[22]; // Most -1, 1, and 0 for Gold Status +/*016*/ int32 entries[25]; // Most -1, 1, and 0 for Gold Status /*104*/ }; @@ -537,9 +537,13 @@ struct NewZone_Struct { /*0525*/ uint8 rain_duration[4]; /*0529*/ uint8 snow_chance[4]; /*0533*/ uint8 snow_duration[4]; - /*0537*/ uint8 unknown537[33]; + /*0537*/ uint8 unknown537[32]; // Seen all 0xff + /*0569*/ uint8 unknown569; // Unknown - Seen 0 /*0570*/ uint8 sky; // Sky Type - /*0571*/ uint8 unknown571[13]; // ***Placeholder + /*0571*/ uint8 unknown571; // Unknown - Seen 0 + /*0572*/ uint32 unknown572; // Unknown - Seen 4 in Guild Lobby + /*0576*/ uint32 unknown576; // Unknown - Seen 2 in Guild Lobby + /*0580*/ uint32 unknown580; // Unknown - Seen 0 in Guild Lobby /*0584*/ float zone_exp_multiplier; // Experience Multiplier /*0588*/ float safe_y; // Zone Safe Y /*0592*/ float safe_x; // Zone Safe X @@ -554,7 +558,7 @@ struct NewZone_Struct { /*0800*/ int32 unknown800; //seen -1 /*0804*/ char unknown804[40]; // /*0844*/ int32 unknown844; //seen 600 - /*0848*/ int32 unknown848; + /*0848*/ int32 unknown848; //seen 2008 /*0852*/ uint16 zone_id; /*0854*/ uint16 zone_instance; /*0856*/ char unknown856[20]; @@ -581,7 +585,7 @@ struct NewZone_Struct { /*0932*/ int32 unknown932; // Seen -1 /*0936*/ int32 unknown936; // Seen -1 /*0940*/ uint32 unknown940; // Seen 0 - /*0944*/ float unknown944; // Seen 1.0 + /*0944*/ float unknown944; // Seen 1.0 in PoK, and 0.25 in Guild Lobby /*0948*/ uint32 unknown948; // Seen 0 - New on Live as of Dec 15 2014 /*0952*/ uint32 unknown952; // Seen 100 - New on Live as of Dec 15 2014 /*0956*/ @@ -1219,64 +1223,17 @@ union /* ///////////////////// - Haven't identified the below fields in the PP yet -uint8 pvp; // 1=pvp, 0=not pvp uint8 anon; // 2=roleplay, 1=anon, 0=not anon -uint8 gm; // 0=no, 1=yes (guessing!) -uint32 guild_id; // guildid -uint8 guildrank; // 0=member, 1=officer, 2=guildleader -1=no guild -uint32 guildbanker; uint32 available_slots; -uint32 endurance; // Current endurance uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; // Refresh time (millis) - 4 bytes Each * 16 = 64 bytes uint32 abilitySlotRefresh; /////////////////////// -uint32 platinum_bank; // Platinum Pieces in Bank -uint32 gold_bank; // Gold Pieces in Bank -uint32 silver_bank; // Silver Pieces in Bank -uint32 copper_bank; // Copper Pieces in Bank uint32 platinum_shared; // Shared platinum pieces - uint32 autosplit; // 0 = off, 1 = on - char groupMembers[MAX_GROUP_MEMBERS][64];// 384 all the members in group, including self char groupLeader[64]; // Leader of the group ? uint32 entityid; - -uint32 leadAAActive; // 0 = leader AA off, 1 = leader AA on -int32 ldon_points_guk; // Earned GUK points -int32 ldon_points_mir; // Earned MIR points -int32 ldon_points_mmc; // Earned MMC points -int32 ldon_points_ruj; // Earned RUJ points -int32 ldon_points_tak; // Earned TAK points -int32 ldon_points_available;// Available LDON points -float tribute_time_remaining;// Time remaining on tribute (millisecs) -uint32 career_tribute_points;// Total favor points for this char -uint32 tribute_points; // Current tribute points -uint32 tribute_active; // 0 = off, 1=on -Tribute_Struct tributes[MAX_PLAYER_TRIBUTES]; // [40] Current tribute loadout -double group_leadership_exp; // Current group lead exp points -double raid_leadership_exp; // Current raid lead AA exp points -uint32 group_leadership_points; // Unspent group lead AA points -uint32 raid_leadership_points; // Unspent raid lead AA points -LeadershipAA_Struct leader_abilities; // [128]Leader AA ranks 19332 - -uint32 PVPKills; -uint32 PVPDeaths; -uint32 PVPCurrentPoints; -uint32 PVPCareerPoints; -uint32 PVPBestKillStreak; -uint32 PVPWorstDeathStreak; -uint32 PVPCurrentKillStreak; -PVPStatsEntry_Struct PVPLastKill; // size 88 -PVPStatsEntry_Struct PVPLastDeath; // size 88 -uint32 PVPNumberOfKillsInLast24Hours; -PVPStatsEntry_Struct PVPRecentKills[50]; // size 4400 - 88 each -uint32 expAA; // Exp earned in current AA point -uint32 currentRadCrystals; // Current count of radiant crystals -uint32 careerRadCrystals; // Total count of radiant crystals ever -uint32 currentEbonCrystals; // Current count of ebon crystals -uint32 careerEbonCrystals; // Total count of ebon crystals ever */ }; @@ -1886,8 +1843,8 @@ struct LootingItem_Struct { /*000*/ uint32 lootee; /*004*/ uint32 looter; /*008*/ uint16 slot_id; -/*010*/ uint16 unknown10; -/*012*/ uint32 auto_loot; +/*010*/ uint16 unknown10; // slot_id is probably uint32 +/*012*/ int32 auto_loot; /*016*/ uint32 unknown16; /*020*/ }; @@ -2892,7 +2849,8 @@ struct Resurrect_Struct /*160*/ char corpse_name[64]; /*224*/ uint32 action; /*228*/ uint32 unknown228; -/*232*/ +/*232*/ uint32 unknown232; +/*236*/ }; struct SetRunMode_Struct { @@ -3111,29 +3069,24 @@ struct MobHealth }; struct Track_Struct { - uint16 entityid; - uint16 y; - uint16 x; - uint16 z; + uint32 entityid; + float distance; + // Fields for SoD and later + uint8 level; + uint8 is_npc; + char name[64]; + uint8 is_pet; + uint8 is_merc; }; struct Tracking_Struct { + uint16 entry_count; Track_Struct Entrys[0]; }; -// Looks like new tracking structures - Opcode: 0x57a7 -struct Tracking_Struct_New { - uint16 totalcount; // Total Count of mobs within tracking range - Track_Struct Entrys[0]; -}; - -struct Track_Struct_New { - uint16 entityid; // Entity ID - uint16 unknown002; // 00 00 - uint32 unknown004; // - uint8 level; // level of mob - uint8 unknown009; // 01 maybe type of mob? player/npc? - char name[1]; // name of mob +struct TrackTarget_Struct +{ + uint32 EntityID; }; @@ -4399,7 +4352,7 @@ struct ItemSerializationHeader /*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ? /*026*/ uint16 main_slot; /*028*/ uint16 sub_slot; -/*030*/ uint16 unknown013; // 0xffff +/*030*/ uint16 aug_slot; // 0xffff /*032*/ uint32 price; /*036*/ uint32 merchant_slot; //1 if not a merchant item /*040*/ uint32 scaled_value; //0 @@ -4428,17 +4381,14 @@ struct EvolvingItem { struct ItemSerializationHeaderFinish { -/*079*/ uint16 ornamentIcon; -/*081*/ uint8 unknown061; // 0 - Add Evolving Item struct if this isn't set to 0? -/*082*/ uint8 unknown062; // 0 -/*083*/ int32 unknowna1; // 0xffffffff -/*087*/ uint32 ornamentHeroModel; // 0 -/*091*/ uint8 unknown063; // 0 -/*092*/ uint32 unknowna3; // 0 -/*096*/ int32 unknowna4; // 0xffffffff -/*100*/ uint32 unknowna5; // 0 -/*104*/ uint8 ItemClass; //0, 1, or 2 -/*105*/ + uint32 ornamentIcon; + int32 unknowna1; // 0xffffffff + uint32 ornamentHeroModel; + int32 unknown063; // 0 + uint8 Copied; // Copied Flag - Possibly for items copied during server transfer? + int32 unknowna4; // 0xffffffff + int32 unknowna5; // 0 + uint8 ItemClass; //0, 1, or 2 }; struct ItemBodyStruct @@ -4542,7 +4492,7 @@ struct ItemSecondaryBodyStruct // swapped augrestrict and augdistiller positions // (this swap does show the proper augment restrictions in Item Information window now) // unsure what the purpose of augdistiller is at this time -U 3/17/2014 - uint32 augdistiller; // New to December 10th 2012 client - NEW + int32 augrestrict2; // New to December 10th 2012 client - Hidden Aug Restriction uint32 augrestrict; AugSlotStruct augslots[6]; @@ -4647,7 +4597,7 @@ struct ItemQuaternaryBodyStruct uint8 quest_item; uint32 Power; // Enables "Power" percentage field used by Power Sources uint32 Purity; - uint8 unknown16; // RoF2 + uint8 unknown16; // RoF uint32 BackstabDmg; uint32 DSMitigation; int32 HeroicStr; @@ -4669,15 +4619,19 @@ struct ItemQuaternaryBodyStruct uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; - uint32 unknown20; // Bard Stuff? - //uint32 unknown21; - uint8 unknown22; + uint16 unknown20; + uint8 unknown21; + uint8 Heirloom; // Heirloom Flag + uint8 Placeable; // Placeable Flag + uint8 unknown22b; + uint8 unknown22c; + uint8 unknown22d; uint32 unknown23; uint32 unknown24; uint32 unknown25; float unknown26; float unknown27; - uint32 unknown_RoF26; // 0 New to March 21 2012 client + uint32 unknown_RoF_6; // 0 New to March 21 2012 client uint32 unknown28; // 0xffffffff uint16 unknown29; uint32 unknown30; // 0xffffffff @@ -4688,9 +4642,15 @@ struct ItemQuaternaryBodyStruct uint32 unknown35; uint32 unknown36; uint32 unknown37; - uint32 unknown_RoF27; - uint32 unknown_RoF28; - uint8 unknown37a; // (guessed position) New to RoF2 + uint8 NoZone; // No Zone Flag - Item will disappear upon zoning? + uint8 unknown_RoF_7b; // Maybe Uint32 ? + uint8 unknown_RoF_7c; + uint8 unknown_RoF_7d; + uint8 unknown_RoF_8a; + uint8 NoGround; // No Ground Flag - Item cannot be dropped on the ground? + uint8 unknown_RoF_8c; + uint8 unknown_RoF_8d; + uint8 unknown37a; // New to RoF2 - Probably variable length string uint8 unknown38; // 0 uint8 unknown39; // 1 uint32 subitem_count; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index c84a670a9..fb2f09615 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -3103,32 +3103,25 @@ struct MobHealth }; struct Track_Struct { - uint16 entityid; - uint16 y; - uint16 x; - uint16 z; + uint32 entityid; + float distance; + // Fields for SoD and later + uint8 level; + uint8 is_npc; + char name[64]; + uint8 is_merc; }; struct Tracking_Struct { + uint16 entry_count; Track_Struct Entrys[0]; }; -// Looks like new tracking structures - Opcode: 0x57a7 -struct Tracking_Struct_New { - uint16 totalcount; // Total Count of mobs within tracking range - Track_Struct Entrys[0]; +struct TrackTarget_Struct +{ + uint32 EntityID; }; -struct Track_Struct_New { - uint16 entityid; // Entity ID - uint16 unknown002; // 00 00 - uint32 unknown004; // - uint8 level; // level of mob - uint8 unknown009; // 01 maybe type of mob? player/npc? - char name[1]; // name of mob -}; - - /* ** ZoneServerInfo_Struct ** Zone server information @@ -4420,9 +4413,7 @@ struct EvolvingItem { struct ItemSerializationHeaderFinish { -/*079*/ uint16 ornamentIcon; -/*081*/ uint8 unknown061; // 0 - Add Evolving Item struct if this isn't set to 0? -/*082*/ uint8 unknown062; // 0 +/*079*/ uint32 ornamentIcon; /*083*/ int32 unknowna1; // 0xffffffff /*087*/ uint32 ornamentHeroModel; // 0 /*091*/ uint8 unknown063; // 0 diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 50d787472..7355526c4 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1638,7 +1638,7 @@ namespace SoD strn0cpy(general->player_name, raid_create->leader_name, 64); dest->FastQueuePacket(&outapp_create); - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_RaidUpdate) @@ -1705,7 +1705,7 @@ namespace SoD dest->FastQueuePacket(&outapp); } - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_ReadBook) @@ -2058,9 +2058,9 @@ namespace SoD VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid); VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc); VARSTRUCT_ENCODE_STRING(Buffer, emu->name); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc); } delete[] __emu_buffer; diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index f7d35d403..fc46c53cb 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1296,7 +1296,7 @@ namespace SoF strn0cpy(general->player_name, raid_create->leader_name, 64); dest->FastQueuePacket(&outapp_create); - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_RaidUpdate) @@ -1363,7 +1363,7 @@ namespace SoF dest->FastQueuePacket(&outapp); } - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_ReadBook) @@ -1645,7 +1645,7 @@ namespace SoF for (int i = 0; i < EntryCount; ++i, ++eq, ++emu) { OUT(entityid); - OUT(padding002); + //OUT(padding002); OUT(distance); } diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 385fd8b46..51f41a590 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -2624,8 +2624,8 @@ struct MobHealth }; struct Track_Struct { - uint16 entityid; - uint16 padding002; + uint32 entityid; + //uint16 padding002; float distance; }; diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 26ab0f531..f9ad6a4ff 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -1094,7 +1094,7 @@ namespace Titanium for (int i = 0; i < EntryCount; ++i, ++eq, ++emu) { OUT(entityid); - OUT(padding002); + //OUT(padding002); OUT(distance); } diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index b9d299ab9..0b5b1ec25 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -2319,8 +2319,8 @@ struct MobHealth }; struct Track_Struct { - uint16 entityid; - uint16 padding002; + uint32 entityid; + //uint16 padding002; float distance; }; diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index 3ddfeafd0..5ee38f586 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -1924,7 +1924,7 @@ namespace Underfoot strn0cpy(general->player_name, raid_create->leader_name, 64); dest->FastQueuePacket(&outapp_create); - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_RaidUpdate) @@ -1991,7 +1991,7 @@ namespace Underfoot dest->FastQueuePacket(&outapp); } - delete[] __emu_buffer; + safe_delete(inapp); } ENCODE(OP_ReadBook) @@ -2348,9 +2348,9 @@ namespace Underfoot VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid); VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc); VARSTRUCT_ENCODE_STRING(Buffer, emu->name); - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc); } delete[] __emu_buffer; diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 81dcb1b0a..e9a552165 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -177,6 +177,7 @@ bool SharedDatabase::SaveInventory(uint32 char_id, const ItemInst* inst, int16 s } bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, int16 slot_id) { + // need to check 'inst' argument for valid pointer uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM }; if (inst->IsType(ItemClassCommon)) @@ -221,6 +222,7 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i } bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst, int16 slot_id) { + // need to check 'inst' argument for valid pointer uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM }; if (inst->IsType(ItemClassCommon)) @@ -429,10 +431,6 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) { int16 put_slot_id = INVALID_INDEX; - ItemInst* inst = CreateBaseItem(item, charges); - if (item->ItemClass == ItemClassCommon) { - for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - if (aug[i]) { inst->PutAugment(this, i, aug[i]); } } @@ -527,6 +525,9 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) { ItemInst* inst = CreateBaseItem(item, charges); + if (inst == nullptr) + continue; + if(row[11]) { std::string data_str(row[11]); std::string idAsString; @@ -635,6 +636,10 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv) continue; ItemInst* inst = CreateBaseItem(item, charges); + + if (inst == nullptr) + continue; + inst->SetAttuned(instnodrop); if(row[11]) { @@ -1193,9 +1198,17 @@ ItemInst* SharedDatabase::CreateItem(uint32 item_id, int16 charges, uint32 aug1, { const Item_Struct* item = nullptr; ItemInst* inst = nullptr; + item = GetItem(item_id); if (item) { inst = CreateBaseItem(item, charges); + + if (inst == nullptr) { + LogFile->write(EQEMuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateItem()"); + LogFile->write(EQEMuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges); + return nullptr; + } + inst->PutAugment(this, 0, aug1); inst->PutAugment(this, 1, aug2); inst->PutAugment(this, 2, aug3); @@ -1215,6 +1228,13 @@ ItemInst* SharedDatabase::CreateItem(const Item_Struct* item, int16 charges, uin ItemInst* inst = nullptr; if (item) { inst = CreateBaseItem(item, charges); + + if (inst == nullptr) { + LogFile->write(EQEMuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateItem()"); + LogFile->write(EQEMuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges); + return nullptr; + } + inst->PutAugment(this, 0, aug1); inst->PutAugment(this, 1, aug2); inst->PutAugment(this, 2, aug3); @@ -1240,6 +1260,12 @@ ItemInst* SharedDatabase::CreateBaseItem(const Item_Struct* item, int16 charges) inst = new ItemInst(item, charges); + if (inst == nullptr) { + LogFile->write(EQEMuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateBaseItem()"); + LogFile->write(EQEMuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges); + return nullptr; + } + if(item->CharmFileID != 0 || (item->LoreGroup >= 1000 && item->LoreGroup != -1)) { inst->Initialize(this); } diff --git a/common/timer.cpp b/common/timer.cpp index c1c94a7f6..d5a90a0f2 100644 --- a/common/timer.cpp +++ b/common/timer.cpp @@ -141,11 +141,13 @@ uint32 Timer::GetRemainingTime() { } } -void Timer::SetAtTrigger(uint32 in_set_at_trigger, bool iEnableIfDisabled) { +void Timer::SetAtTrigger(uint32 in_set_at_trigger, bool iEnableIfDisabled, bool ChangeTimerTime) { set_at_trigger = in_set_at_trigger; if (!Enabled() && iEnableIfDisabled) { Enable(); } + if (ChangeTimerTime) + timer_time = set_at_trigger; } void Timer::Trigger() diff --git a/common/timer.h b/common/timer.h index 1e3ab97e0..c4d89fe11 100644 --- a/common/timer.h +++ b/common/timer.h @@ -43,7 +43,7 @@ public: inline const uint32& GetTimerTime() { return timer_time; } inline const uint32& GetSetAtTrigger() { return set_at_trigger; } void Trigger(); - void SetAtTrigger(uint32 set_at_trigger, bool iEnableIfDisabled = false); + void SetAtTrigger(uint32 set_at_trigger, bool iEnableIfDisabled = false, bool ChangeTimerTime = false); inline bool Enabled() { return enabled; } inline uint32 GetStartTime() { return(start_time); } diff --git a/common/version.h b/common/version.h index 461c26e23..48a600be1 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9062 +#define CURRENT_BINARY_DATABASE_VERSION 9066 #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ #ifndef WIN32 diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 60b94e87d..23bec152e 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -193,7 +193,7 @@ OP_Consent=0x1fd1 OP_ConsentDeny=0x7a45 OP_AutoFire=0x241e OP_PetCommands=0x0159 -OP_DeleteSpell=0x52e5 +OP_DeleteSpell=0x3358 OP_Surname=0x0423 OP_ClearSurname=0x3fb0 OP_FaceChange=0x5578 @@ -205,14 +205,14 @@ OP_CorpseDrag=0x0904 OP_CorpseDrop=0x7037 OP_Bug=0x73f4 OP_Feedback=0x5602 -OP_Report=0x1414 +OP_Report=0x6f14 OP_Damage=0x6f15 OP_ChannelMessage=0x2b2d OP_Assist=0x4478 OP_AssistGroup=0x27f8 OP_MoveCoin=0x0bcf OP_ZonePlayerToBind=0x08d8 -OP_KeyRing=0x6857 +OP_KeyRing=0x1219 OP_WhoAllRequest=0x674b OP_WhoAllResponse=0x578c OP_FriendsWho=0x3956 @@ -230,10 +230,10 @@ OP_TargetMouse=0x075d OP_MobHealth=0x37b1 OP_InitialMobHealth=0x0000 # Unused? OP_TargetHoTT=0x0272 -OP_XTargetResponse=0x672f -OP_XTargetRequest=0x45be -OP_XTargetAutoAddHaters=0x792c OP_TargetBuffs=0x4f4b +OP_XTargetResponse=0x4d59 +OP_XTargetRequest=0x3763 +OP_XTargetAutoAddHaters=0x672f OP_BuffCreate=0x3377 OP_BuffRemoveRequest=0x64f2 OP_DeleteSpawn=0x7280 @@ -249,7 +249,7 @@ OP_ItemLinkClick=0x4cef OP_ItemPreview=0x6b5c OP_NewSpawn=0x6097 OP_Track=0x17e5 -OP_TrackTarget=0x0029 +OP_TrackTarget=0x695e OP_TrackUnknown=0x4577 OP_ClickDoor=0x3a8f OP_MoveDoor=0x08e8 @@ -263,7 +263,7 @@ OP_SafeFallSuccess=0x2219 OP_RezzComplete=0x760d OP_RezzRequest=0x3c21 OP_RezzAnswer=0x701c -OP_Shielding=0x48c1 +OP_Shielding=0x52e5 OP_RequestDuel=0x3af1 OP_MobRename=0x2c57 OP_AugmentItem=0x661b @@ -309,7 +309,7 @@ OP_Sacrifice=0x1821 OP_PopupResponse=0x08a6 OP_OnLevelMessage=0x575b OP_AugmentInfo=0x0afb -OP_Petition=0x1901 +OP_Petition=0x3de3 OP_SomeItemPacketMaybe=0x747c OP_PVPStats=0x4b15 OP_PVPLeaderBoardRequest=0x04aa @@ -433,7 +433,7 @@ OP_ItemVerifyRequest=0x189c OP_ItemVerifyReply=0x097b # merchant stuff -OP_ShopPlayerSell=0x0000 +OP_ShopPlayerSell=0x791b OP_ShopRequest=0x4fed OP_ShopEnd=0x30a8 OP_ShopEndConfirm=0x3196 @@ -601,7 +601,7 @@ OP_MoveLogDisregard=0x0000 # gone I think # named unknowns, to make looking for real unknown easier OP_AnnoyingZoneUnknown=0x0000 -OP_Some6ByteHPUpdate=0x0000 seems to happen when you target group members +OP_Some6ByteHPUpdate=0x0000 #seems to happen when you target group members OP_QueryResponseThing=0x0000 @@ -610,9 +610,9 @@ OP_QueryResponseThing=0x0000 #OP_LoginUnknown2=0x040b # OP_SendSkillCapsChecksum # Petition Opcodes -OP_PetitionSearch=0x0000 search term for petition -OP_PetitionSearchResults=0x0000 (list of?) matches from search -OP_PetitionSearchText=0x0000 text results of search +OP_PetitionSearch=0x0000 #search term for petition +OP_PetitionSearchResults=0x0000 #(list of?) matches from search +OP_PetitionSearchText=0x0000 #text results of search OP_PetitionUpdate=0x0000 OP_PetitionCheckout=0x0000 diff --git a/utils/scripts/db_update.pl b/utils/scripts/db_update.pl index bf92ce60f..be1285fe4 100644 --- a/utils/scripts/db_update.pl +++ b/utils/scripts/db_update.pl @@ -155,6 +155,7 @@ sub ShowMenuPrompt { 2 => \&database_dump_compress, 3 => \&Run_Database_Check, 4 => \&AA_Fetch, + 5 => \&OpCodes_Fetch, 0 => \&Exit, ); @@ -204,6 +205,7 @@ Database Management Menu (Please Select): Ideal to perform before performing updates 3) $option[3] 4) AAs - Get Latest AA's from PEQ (This deletes AA's already in the database) + 5) OPCodes - Download latest opcodes from repository 0) Exit EO_MENU @@ -305,6 +307,36 @@ sub AA_Fetch{ print "\nDone...\n\n"; } +#::: Fetch Latest Opcodes +sub OpCodes_Fetch{ + print "Pulling down latest opcodes...\n"; + %opcodes = ( + 1 => ["opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/opcodes.conf"], + 2 => ["mail_opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/mail_opcodes.conf"], + 3 => ["Titanium", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_Titanium.conf"], + 4 => ["Secrets of Faydwer", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoF.conf"], + 5 => ["Seeds of Destruction", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoD.conf"], + 6 => ["Underfoot", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_Underfoot.conf"], + 7 => ["Rain of Fear", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF.conf"], + 8 => ["Rain of Fear 2", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF2.conf"], + ); + $loop = 1; + while($opcodes{$loop}[0]){ + #::: Split the URL by the patches folder to get the file name from URL + @real_file = split("patches/", $opcodes{$loop}[1]); + $find = 0; + while($real_file[$find]){ + $file_name = $real_file[$find]; + $find++; + } + + print "\nDownloading (" . $opcodes{$loop}[0] . ") File: '" . $file_name . "'...\n\n"; + GetRemoteFile($opcodes{$loop}[1], $file_name); + $loop++; + } + print "\nDone...\n\n"; +} + #::: Responsible for Database Upgrade Routines sub Run_Database_Check{ #::: Run 2 - Running pending updates... diff --git a/utils/scripts/parse_crashes.pl b/utils/scripts/parse_crashes.pl new file mode 100644 index 000000000..667a19b81 --- /dev/null +++ b/utils/scripts/parse_crashes.pl @@ -0,0 +1,39 @@ +opendir my $dir, "logs" or die "Cannot open directory: $!"; +my @files = readdir $dir; +closedir $dir; +$inc = 0; +foreach my $val (@files){ + if($val=~/crash_zone/i){ + $stl = 0; + $crash[$inc] = ""; + my $file = "logs/" . $val; + open my $info, $file or die "Could not open $file: $!"; + while( my $line = <$info>) { + if($line=~/CRTStartup/i){ $stl = 0; } + @data = split(']', $line); + if($stl == 1){ $crash[$inc] .= $data[1]; } + if($line=~/dbghelp.dll/i){ $stl = 1; } + } + close $info; + $inc++; + } +} + +#::: Count Crash Occurrence first +$i = 0; +while($crash[$i]){ + $crash_count[length($crash[$i])]++; + $unique_crash[length($crash[$i])] = $crash[$i]; + $i++; +} + +$i = 0; +while($crash[$i]){ + if($unique_crash_tracker[length($crash[$i])] != 1){ + print "Crash Occurrence " . $crash_count[length($crash[$i])] . " Time(s) Length (" . length($crash[$i]) . ") \n\n"; + print $crash[$i] . "\n"; + print "=========================================\n"; + } + $unique_crash_tracker[length($crash[$i])] = 1; + $i++; +} \ No newline at end of file diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 432d97183..1ba3048b8 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -316,6 +316,10 @@ 9060|2014_12_09_items_table_update.sql|SHOW COLUMNS FROM `items` LIKE 'herosforgemodel'|empty| 9061|2014_12_13_inventory_table_update.sql|SHOW COLUMNS FROM `inventory` LIKE 'ornament_hero_model'|empty| 9062|2014_12_15_multiple_table_updates.sql|SHOW COLUMNS FROM `items` LIKE 'augslot6type'|empty| +9063|2014_12_24_npc_types_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'd_melee_texture1'|empty| +9064|2014_12_24_npc_types_table_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'herosforgemodel'|empty| +9065|2014_12_26_merc_weaponinfo_table_update.sql|SHOW COLUMNS FROM `vwMercNpcTypes` LIKE 'd_melee_texture1'|empty| +9066|2014_12_31_npc_types_default_values_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'bodytype'|contains|YES # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2014_12_24_npc_types_table_update.sql b/utils/sql/git/required/2014_12_24_npc_types_table_update.sql new file mode 100644 index 000000000..c65749b36 --- /dev/null +++ b/utils/sql/git/required/2014_12_24_npc_types_table_update.sql @@ -0,0 +1 @@ +ALTER TABLE `npc_types` ADD `herosforgemodel` int( 11 ) NOT NULL DEFAULT '0' AFTER `helmtexture`; \ No newline at end of file diff --git a/utils/sql/git/required/2014_12_24_npc_types_update.sql b/utils/sql/git/required/2014_12_24_npc_types_update.sql new file mode 100644 index 000000000..a44d15c2d --- /dev/null +++ b/utils/sql/git/required/2014_12_24_npc_types_update.sql @@ -0,0 +1,2 @@ +ALTER TABLE `npc_types` CHANGE `d_meele_texture1` `d_melee_texture1` INT(11) DEFAULT NULL; +ALTER TABLE `npc_types` CHANGE `d_meele_texture2` `d_melee_texture2` INT(11) DEFAULT NULL; \ No newline at end of file diff --git a/utils/sql/git/required/2014_12_26_merc_weaponinfo_table_update.sql b/utils/sql/git/required/2014_12_26_merc_weaponinfo_table_update.sql new file mode 100644 index 000000000..3c8d291bb --- /dev/null +++ b/utils/sql/git/required/2014_12_26_merc_weaponinfo_table_update.sql @@ -0,0 +1,69 @@ +/* Drop the current Merc View */ +DROP VIEW vwMercNpcTypes; + +/* Rename fields to match the source changes */ +ALTER TABLE `merc_weaponinfo` CHANGE `d_meele_texture1` `d_melee_texture1` INT(11) NOT NULL DEFAULT 0; +ALTER TABLE `merc_weaponinfo` CHANGE `d_meele_texture2` `d_melee_texture2` INT(11) NOT NULL DEFAULT 0; + +/* Re-Create the Merc View with new field names */ +CREATE VIEW vwMercNpcTypes AS +SELECT + ms.merc_npc_type_id, + '' AS name, + ms.clientlevel, + ms.level, + mtyp.race_id, + mstyp.class_id, + ms.hp, + ms.mana, + 0 AS gender, + mai.texture, + mai.helmtexture, + ms.attack_speed, + ms.STR, + ms.STA, + ms.DEX, + ms.AGI, + ms._INT, + ms.WIS, + ms.CHA, + ms.MR, + ms.CR, + ms.DR, + ms.FR, + ms.PR, + ms.Corrup, + ms.mindmg, + ms.maxdmg, + ms.attack_count, + ms.special_abilities AS special_abilities, + mwi.d_melee_texture1, + mwi.d_melee_texture2, + mwi.prim_melee_type, + mwi.sec_melee_type, + ms.runspeed, + ms.hp_regen_rate, + ms.mana_regen_rate, + 1 AS bodytype, + mai.armortint_id, + mai.armortint_red, + mai.armortint_green, + mai.armortint_blue, + ms.AC, + ms.ATK, + ms.Accuracy, + ms.spellscale, + ms.healscale +FROM merc_stats ms +INNER JOIN merc_armorinfo mai +ON ms.merc_npc_type_id = mai.merc_npc_type_id +AND mai.minlevel <= ms.level AND mai.maxlevel >= ms.level +INNER JOIN merc_weaponinfo mwi +ON ms.merc_npc_type_id = mwi.merc_npc_type_id +AND mwi.minlevel <= ms.level AND mwi.maxlevel >= ms.level +INNER JOIN merc_templates mtem +ON mtem.merc_npc_type_id = ms.merc_npc_type_id +INNER JOIN merc_types mtyp +ON mtem.merc_type_id = mtyp.merc_type_id +INNER JOIN merc_subtypes mstyp +ON mtem.merc_subtype_id = mstyp.merc_subtype_id; \ No newline at end of file diff --git a/utils/sql/git/required/2014_12_31_npc_types_default_values_update.sql b/utils/sql/git/required/2014_12_31_npc_types_default_values_update.sql new file mode 100644 index 000000000..b75544981 --- /dev/null +++ b/utils/sql/git/required/2014_12_31_npc_types_default_values_update.sql @@ -0,0 +1,3 @@ +ALTER TABLE `npc_types` MODIFY `bodytype` INT(11) NOT NULL DEFAULT '1'; +ALTER TABLE `npc_types` MODIFY `d_melee_texture1` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `npc_types` MODIFY `d_melee_texture2` INT(11) NOT NULL DEFAULT '0'; diff --git a/zone/aa.cpp b/zone/aa.cpp index fc640ff92..02f00f84d 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -606,6 +606,9 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u //the target of these swarm pets will take offense to being cast on... if(targ != nullptr) targ->AddToHateList(this, 1, 0); + + // The other pointers we make are handled elsewhere. + delete made_npc; } void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) { @@ -698,6 +701,9 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid entity_list.AddNPC(npca, true, true); summon_count--; } + + // The other pointers we make are handled elsewhere. + delete made_npc; } void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) @@ -844,8 +850,8 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) make_npc->loottable_id = 0; make_npc->merchanttype = 0; - make_npc->d_meele_texture1 = 0; - make_npc->d_meele_texture2 = 0; + make_npc->d_melee_texture1 = 0; + make_npc->d_melee_texture2 = 0; NPC* npca = new NPC(make_npc, 0, GetX(), GetY(), GetZ(), GetHeading(), FlyMode3); diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 3e833aad9..a82586cb5 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -1298,7 +1298,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) { void Mob::RogueEvade(Mob *other) { int amount = other->GetHateAmount(this) - (GetLevel() * 13); - other->SetHate(this, std::max(1, amount)); + other->SetHateAmountOnEnt(this, std::max(1, amount)); return; } diff --git a/zone/attack.cpp b/zone/attack.cpp index 37827ec63..f41562e4c 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1519,7 +1519,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att } entity_list.RemoveFromTargets(this); - hate_list.RemoveEnt(this); + hate_list.RemoveEntFromHateList(this); RemoveAutoXTargets(); //remove ourself from all proximities @@ -2080,12 +2080,12 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack if (killerMob) { if(GetClass() != LDON_TREASURE) - hate_list.Add(killerMob, damage); + hate_list.AddEntToHateList(killerMob, damage); } safe_delete(app); - Mob *give_exp = hate_list.GetDamageTop(this); + Mob *give_exp = hate_list.GetDamageTopOnHateList(this); if(give_exp == nullptr) give_exp = killer; @@ -2415,7 +2415,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack return true; } -void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) { +void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/) +{ assert(other != nullptr); @@ -2428,7 +2429,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool wasengaged = IsEngaged(); Mob* owner = other->GetOwner(); - Mob* mypet = this->GetPet(); + Mob* mypet = this->GetPet(); Mob* myowner = this->GetOwner(); Mob* targetmob = this->GetTarget(); @@ -2503,7 +2504,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, && other && (buffs[spellbonuses.ImprovedTaunt[2]].casterid != other->GetID())) hate = (hate*spellbonuses.ImprovedTaunt[1])/100; - hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic); + hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic); if(other->IsClient()) other->CastToClient()->AddAutoXTarget(this); @@ -2515,8 +2516,8 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, AddFeignMemory(other->CastToBot()->GetBotOwner()->CastToClient()); } else { - if(!hate_list.IsOnHateList(other->CastToBot()->GetBotOwner())) - hate_list.Add(other->CastToBot()->GetBotOwner(), 0, 0, false, true); + if(!hate_list.IsEntOnHateList(other->CastToBot()->GetBotOwner())) + hate_list.AddEntToHateList(other->CastToBot()->GetBotOwner(), 0, 0, false, true); } } #endif //BOTS @@ -2527,8 +2528,8 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, AddFeignMemory(other->CastToMerc()->GetMercOwner()->CastToClient()); } else { - if(!hate_list.IsOnHateList(other->CastToMerc()->GetMercOwner())) - hate_list.Add(other->CastToMerc()->GetMercOwner(), 0, 0, false, true); + if(!hate_list.IsEntOnHateList(other->CastToMerc()->GetMercOwner())) + hate_list.AddEntToHateList(other->CastToMerc()->GetMercOwner(), 0, 0, false, true); } } //MERC @@ -2543,7 +2544,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, // owner must get on list, but he's not actually gained any hate yet if(!owner->GetSpecialAbility(IMMUNE_AGGRO)) { - hate_list.Add(owner, 0, 0, false, !iBuffTic); + hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic); if(owner->IsClient()) owner->CastToClient()->AddAutoXTarget(this); } @@ -2552,10 +2553,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, if (mypet && (!(GetAA(aaPetDiscipline) && mypet->IsHeld()))) { // I have a pet, add other to it if(!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO)) - mypet->hate_list.Add(other, 0, 0, bFrenzy); + mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy); } else if (myowner) { // I am a pet, add other to owner if it's NPC/LD if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO)) - myowner->hate_list.Add(other, 0, 0, bFrenzy); + myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy); } if (other->GetTempPetCount()) @@ -3905,6 +3906,7 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 h return ProcChance; } +// argument 'weapon' not used void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) { if (!on) { @@ -4947,7 +4949,7 @@ void Client::SetAttackTimer() // this is probably wrong if (quiver_haste > 0) speed *= quiver_haste; - TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true); + TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); if (i == MainPrimary) PrimaryWeapon = ItemToUse; @@ -4995,6 +4997,6 @@ void NPC::SetAttackTimer() } } - TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true); + TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); } } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index b9f35c9ff..a47c1f38b 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1420,7 +1420,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells. } -void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterId, bool item_bonus, uint32 ticsremaining, int buffslot, +void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, bool item_bonus, uint32 ticsremaining, int buffslot, bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max) { int i, effect_value, base2, max, effectid; @@ -1443,7 +1443,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne uint8 focus = IsFocusEffect(spell_id, i); if (focus) { - newbon->FocusEffects[focus] = spells[spell_id].effectid[i]; + new_bonus->FocusEffects[focus] = spells[spell_id].effectid[i]; continue; } @@ -1466,20 +1466,20 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne { case SE_CurrentHP: //regens if(effect_value > 0) { - newbon->HPRegen += effect_value; + new_bonus->HPRegen += effect_value; } break; case SE_CurrentEndurance: - newbon->EnduranceRegen += effect_value; + new_bonus->EnduranceRegen += effect_value; break; case SE_ChangeFrenzyRad: { // redundant to have level check here - if(newbon->AggroRange == -1 || effect_value < newbon->AggroRange) + if(new_bonus->AggroRange == -1 || effect_value < new_bonus->AggroRange) { - newbon->AggroRange = static_cast(effect_value); + new_bonus->AggroRange = static_cast(effect_value); } break; } @@ -1489,9 +1489,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne // Harmony effect as buff - kinda tricky // harmony could stack with a lull spell, which has better aggro range // take the one with less range in any case - if(newbon->AssistRange == -1 || effect_value < newbon->AssistRange) + if(new_bonus->AssistRange == -1 || effect_value < new_bonus->AssistRange) { - newbon->AssistRange = static_cast(effect_value); + new_bonus->AssistRange = static_cast(effect_value); } break; } @@ -1499,16 +1499,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_AttackSpeed: { if ((effect_value - 100) > 0) { // Haste - if (newbon->haste < 0) break; // Slowed - Don't apply haste - if ((effect_value - 100) > newbon->haste) { - newbon->haste = effect_value - 100; + if (new_bonus->haste < 0) break; // Slowed - Don't apply haste + if ((effect_value - 100) > new_bonus->haste) { + new_bonus->haste = effect_value - 100; } } else if ((effect_value - 100) < 0) { // Slow int real_slow_value = (100 - effect_value) * -1; real_slow_value -= ((real_slow_value * GetSlowMitigation()/100)); - if (real_slow_value < newbon->haste) - newbon->haste = real_slow_value; + if (real_slow_value < new_bonus->haste) + new_bonus->haste = real_slow_value; } break; } @@ -1516,16 +1516,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_AttackSpeed2: { if ((effect_value - 100) > 0) { // Haste V2 - Stacks with V1 but does not Overcap - if (newbon->hastetype2 < 0) break; //Slowed - Don't apply haste2 - if ((effect_value - 100) > newbon->hastetype2) { - newbon->hastetype2 = effect_value - 100; + if (new_bonus->hastetype2 < 0) break; //Slowed - Don't apply haste2 + if ((effect_value - 100) > new_bonus->hastetype2) { + new_bonus->hastetype2 = effect_value - 100; } } else if ((effect_value - 100) < 0) { // Slow int real_slow_value = (100 - effect_value) * -1; real_slow_value -= ((real_slow_value * GetSlowMitigation()/100)); - if (real_slow_value < newbon->hastetype2) - newbon->hastetype2 = real_slow_value; + if (real_slow_value < new_bonus->hastetype2) + new_bonus->hastetype2 = real_slow_value; } break; } @@ -1534,13 +1534,13 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne { if (effect_value < 0){ //Slow effect_value -= ((effect_value * GetSlowMitigation()/100)); - if (effect_value < newbon->hastetype3) - newbon->hastetype3 = effect_value; + if (effect_value < new_bonus->hastetype3) + new_bonus->hastetype3 = effect_value; } else if (effect_value > 0) { // Haste V3 - Stacks and Overcaps - if (effect_value > newbon->hastetype3) { - newbon->hastetype3 = effect_value; + if (effect_value > new_bonus->hastetype3) { + new_bonus->hastetype3 = effect_value; } } break; @@ -1556,10 +1556,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (effect_value < 0) //A few spells use negative values(Descriptions all indicate it should be a slow) effect_value = effect_value * -1; - if (effect_value > 0 && effect_value > newbon->inhibitmelee) { + if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) { effect_value -= ((effect_value * GetSlowMitigation()/100)); - if (effect_value > newbon->inhibitmelee) - newbon->inhibitmelee = effect_value; + if (effect_value > new_bonus->inhibitmelee) + new_bonus->inhibitmelee = effect_value; } break; @@ -1567,141 +1567,141 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_TotalHP: { - newbon->HP += effect_value; + new_bonus->HP += effect_value; break; } case SE_ManaRegen_v2: case SE_CurrentMana: { - newbon->ManaRegen += effect_value; + new_bonus->ManaRegen += effect_value; break; } case SE_ManaPool: { - newbon->Mana += effect_value; + new_bonus->Mana += effect_value; break; } case SE_Stamina: { - newbon->EnduranceReduction += effect_value; + new_bonus->EnduranceReduction += effect_value; break; } case SE_ACv2: case SE_ArmorClass: { - newbon->AC += effect_value; + new_bonus->AC += effect_value; break; } case SE_ATK: { - newbon->ATK += effect_value; + new_bonus->ATK += effect_value; break; } case SE_STR: { - newbon->STR += effect_value; + new_bonus->STR += effect_value; break; } case SE_DEX: { - newbon->DEX += effect_value; + new_bonus->DEX += effect_value; break; } case SE_AGI: { - newbon->AGI += effect_value; + new_bonus->AGI += effect_value; break; } case SE_STA: { - newbon->STA += effect_value; + new_bonus->STA += effect_value; break; } case SE_INT: { - newbon->INT += effect_value; + new_bonus->INT += effect_value; break; } case SE_WIS: { - newbon->WIS += effect_value; + new_bonus->WIS += effect_value; break; } case SE_CHA: { if (spells[spell_id].base[i] != 0) { - newbon->CHA += effect_value; + new_bonus->CHA += effect_value; } break; } case SE_AllStats: { - newbon->STR += effect_value; - newbon->DEX += effect_value; - newbon->AGI += effect_value; - newbon->STA += effect_value; - newbon->INT += effect_value; - newbon->WIS += effect_value; - newbon->CHA += effect_value; + new_bonus->STR += effect_value; + new_bonus->DEX += effect_value; + new_bonus->AGI += effect_value; + new_bonus->STA += effect_value; + new_bonus->INT += effect_value; + new_bonus->WIS += effect_value; + new_bonus->CHA += effect_value; break; } case SE_ResistFire: { - newbon->FR += effect_value; + new_bonus->FR += effect_value; break; } case SE_ResistCold: { - newbon->CR += effect_value; + new_bonus->CR += effect_value; break; } case SE_ResistPoison: { - newbon->PR += effect_value; + new_bonus->PR += effect_value; break; } case SE_ResistDisease: { - newbon->DR += effect_value; + new_bonus->DR += effect_value; break; } case SE_ResistMagic: { - newbon->MR += effect_value; + new_bonus->MR += effect_value; break; } case SE_ResistAll: { - newbon->MR += effect_value; - newbon->DR += effect_value; - newbon->PR += effect_value; - newbon->CR += effect_value; - newbon->FR += effect_value; + new_bonus->MR += effect_value; + new_bonus->DR += effect_value; + new_bonus->PR += effect_value; + new_bonus->CR += effect_value; + new_bonus->FR += effect_value; break; } case SE_ResistCorruption: { - newbon->Corrup += effect_value; + new_bonus->Corrup += effect_value; break; } @@ -1711,43 +1711,43 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne { //are these #define'd somewhere? case 0: //str - newbon->STRCapMod += effect_value; + new_bonus->STRCapMod += effect_value; break; case 1: //sta - newbon->STACapMod += effect_value; + new_bonus->STACapMod += effect_value; break; case 2: //agi - newbon->AGICapMod += effect_value; + new_bonus->AGICapMod += effect_value; break; case 3: //dex - newbon->DEXCapMod += effect_value; + new_bonus->DEXCapMod += effect_value; break; case 4: //wis - newbon->WISCapMod += effect_value; + new_bonus->WISCapMod += effect_value; break; case 5: //int - newbon->INTCapMod += effect_value; + new_bonus->INTCapMod += effect_value; break; case 6: //cha - newbon->CHACapMod += effect_value; + new_bonus->CHACapMod += effect_value; break; case 7: //mr - newbon->MRCapMod += effect_value; + new_bonus->MRCapMod += effect_value; break; case 8: //cr - newbon->CRCapMod += effect_value; + new_bonus->CRCapMod += effect_value; break; case 9: //fr - newbon->FRCapMod += effect_value; + new_bonus->FRCapMod += effect_value; break; case 10: //pr - newbon->PRCapMod += effect_value; + new_bonus->PRCapMod += effect_value; break; case 11: //dr - newbon->DRCapMod += effect_value; + new_bonus->DRCapMod += effect_value; break; case 12: // corruption - newbon->CorrupCapMod += effect_value; + new_bonus->CorrupCapMod += effect_value; break; } break; @@ -1756,82 +1756,82 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_CastingLevel2: case SE_CastingLevel: // Brilliance of Ro { - newbon->effective_casting_level += effect_value; + new_bonus->effective_casting_level += effect_value; break; } case SE_MovementSpeed: - newbon->movementspeed += effect_value; + new_bonus->movementspeed += effect_value; break; case SE_SpellDamageShield: - newbon->SpellDamageShield += effect_value; + new_bonus->SpellDamageShield += effect_value; break; case SE_DamageShield: { - newbon->DamageShield += effect_value; - newbon->DamageShieldSpellID = spell_id; + new_bonus->DamageShield += effect_value; + new_bonus->DamageShieldSpellID = spell_id; //When using npc_spells_effects MAX value can be set to determine DS Type if (IsAISpellEffect && max) - newbon->DamageShieldType = GetDamageShieldType(spell_id, max); + new_bonus->DamageShieldType = GetDamageShieldType(spell_id, max); else - newbon->DamageShieldType = GetDamageShieldType(spell_id); + new_bonus->DamageShieldType = GetDamageShieldType(spell_id); break; } case SE_ReverseDS: { - newbon->ReverseDamageShield += effect_value; - newbon->ReverseDamageShieldSpellID = spell_id; + new_bonus->ReverseDamageShield += effect_value; + new_bonus->ReverseDamageShieldSpellID = spell_id; if (IsAISpellEffect && max) - newbon->ReverseDamageShieldType = GetDamageShieldType(spell_id, max); + new_bonus->ReverseDamageShieldType = GetDamageShieldType(spell_id, max); else - newbon->ReverseDamageShieldType = GetDamageShieldType(spell_id); + new_bonus->ReverseDamageShieldType = GetDamageShieldType(spell_id); break; } case SE_Reflect: - newbon->reflect_chance += effect_value; + new_bonus->reflect_chance += effect_value; break; case SE_Amplification: - newbon->Amplification += effect_value; + new_bonus->Amplification += effect_value; break; case SE_ChangeAggro: - newbon->hatemod += effect_value; + new_bonus->hatemod += effect_value; break; case SE_MeleeMitigation: //for some reason... this value is negative for increased mitigation - newbon->MeleeMitigationEffect -= effect_value; + new_bonus->MeleeMitigationEffect -= effect_value; break; case SE_CriticalHitChance: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) { if(base2 == -1) - newbon->CriticalHitChance[HIGHEST_SKILL+1] += effect_value; + new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value; else - newbon->CriticalHitChance[base2] += effect_value; + new_bonus->CriticalHitChance[base2] += effect_value; } else if(effect_value < 0) { - if(base2 == -1 && newbon->CriticalHitChance[HIGHEST_SKILL+1] > effect_value) - newbon->CriticalHitChance[HIGHEST_SKILL+1] = effect_value; - else if(base2 != -1 && newbon->CriticalHitChance[base2] > effect_value) - newbon->CriticalHitChance[base2] = effect_value; + if(base2 == -1 && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] > effect_value) + new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value; + else if(base2 != -1 && new_bonus->CriticalHitChance[base2] > effect_value) + new_bonus->CriticalHitChance[base2] = effect_value; } - else if(base2 == -1 && newbon->CriticalHitChance[HIGHEST_SKILL+1] < effect_value) - newbon->CriticalHitChance[HIGHEST_SKILL+1] = effect_value; - else if(base2 != -1 && newbon->CriticalHitChance[base2] < effect_value) - newbon->CriticalHitChance[base2] = effect_value; + else if(base2 == -1 && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] < effect_value) + new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value; + else if(base2 != -1 && new_bonus->CriticalHitChance[base2] < effect_value) + new_bonus->CriticalHitChance[base2] = effect_value; break; } @@ -1839,13 +1839,13 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_CrippBlowChance: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->CrippBlowChance += effect_value; + new_bonus->CrippBlowChance += effect_value; - else if((effect_value < 0) && (newbon->CrippBlowChance > effect_value)) - newbon->CrippBlowChance = effect_value; + else if((effect_value < 0) && (new_bonus->CrippBlowChance > effect_value)) + new_bonus->CrippBlowChance = effect_value; - else if(newbon->CrippBlowChance < effect_value) - newbon->CrippBlowChance = effect_value; + else if(new_bonus->CrippBlowChance < effect_value) + new_bonus->CrippBlowChance = effect_value; break; } @@ -1853,65 +1853,65 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_AvoidMeleeChance: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->AvoidMeleeChanceEffect += effect_value; + new_bonus->AvoidMeleeChanceEffect += effect_value; - else if((effect_value < 0) && (newbon->AvoidMeleeChanceEffect > effect_value)) - newbon->AvoidMeleeChanceEffect = effect_value; + else if((effect_value < 0) && (new_bonus->AvoidMeleeChanceEffect > effect_value)) + new_bonus->AvoidMeleeChanceEffect = effect_value; - else if(newbon->AvoidMeleeChanceEffect < effect_value) - newbon->AvoidMeleeChanceEffect = effect_value; + else if(new_bonus->AvoidMeleeChanceEffect < effect_value) + new_bonus->AvoidMeleeChanceEffect = effect_value; break; } case SE_RiposteChance: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->RiposteChance += effect_value; + new_bonus->RiposteChance += effect_value; - else if((effect_value < 0) && (newbon->RiposteChance > effect_value)) - newbon->RiposteChance = effect_value; + else if((effect_value < 0) && (new_bonus->RiposteChance > effect_value)) + new_bonus->RiposteChance = effect_value; - else if(newbon->RiposteChance < effect_value) - newbon->RiposteChance = effect_value; + else if(new_bonus->RiposteChance < effect_value) + new_bonus->RiposteChance = effect_value; break; } case SE_DodgeChance: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->DodgeChance += effect_value; + new_bonus->DodgeChance += effect_value; - else if((effect_value < 0) && (newbon->DodgeChance > effect_value)) - newbon->DodgeChance = effect_value; + else if((effect_value < 0) && (new_bonus->DodgeChance > effect_value)) + new_bonus->DodgeChance = effect_value; - if(newbon->DodgeChance < effect_value) - newbon->DodgeChance = effect_value; + if(new_bonus->DodgeChance < effect_value) + new_bonus->DodgeChance = effect_value; break; } case SE_ParryChance: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->ParryChance += effect_value; + new_bonus->ParryChance += effect_value; - else if((effect_value < 0) && (newbon->ParryChance > effect_value)) - newbon->ParryChance = effect_value; + else if((effect_value < 0) && (new_bonus->ParryChance > effect_value)) + new_bonus->ParryChance = effect_value; - if(newbon->ParryChance < effect_value) - newbon->ParryChance = effect_value; + if(new_bonus->ParryChance < effect_value) + new_bonus->ParryChance = effect_value; break; } case SE_DualWieldChance: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->DualWieldChance += effect_value; + new_bonus->DualWieldChance += effect_value; - else if((effect_value < 0) && (newbon->DualWieldChance > effect_value)) - newbon->DualWieldChance = effect_value; + else if((effect_value < 0) && (new_bonus->DualWieldChance > effect_value)) + new_bonus->DualWieldChance = effect_value; - if(newbon->DualWieldChance < effect_value) - newbon->DualWieldChance = effect_value; + if(new_bonus->DualWieldChance < effect_value) + new_bonus->DualWieldChance = effect_value; break; } @@ -1919,13 +1919,13 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->DoubleAttackChance += effect_value; + new_bonus->DoubleAttackChance += effect_value; - else if((effect_value < 0) && (newbon->DoubleAttackChance > effect_value)) - newbon->DoubleAttackChance = effect_value; + else if((effect_value < 0) && (new_bonus->DoubleAttackChance > effect_value)) + new_bonus->DoubleAttackChance = effect_value; - if(newbon->DoubleAttackChance < effect_value) - newbon->DoubleAttackChance = effect_value; + if(new_bonus->DoubleAttackChance < effect_value) + new_bonus->DoubleAttackChance = effect_value; break; } @@ -1933,82 +1933,82 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->TripleAttackChance += effect_value; + new_bonus->TripleAttackChance += effect_value; - else if((effect_value < 0) && (newbon->TripleAttackChance > effect_value)) - newbon->TripleAttackChance = effect_value; + else if((effect_value < 0) && (new_bonus->TripleAttackChance > effect_value)) + new_bonus->TripleAttackChance = effect_value; - if(newbon->TripleAttackChance < effect_value) - newbon->TripleAttackChance = effect_value; + if(new_bonus->TripleAttackChance < effect_value) + new_bonus->TripleAttackChance = effect_value; break; } case SE_MeleeLifetap: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->MeleeLifetap += spells[spell_id].base[i]; + new_bonus->MeleeLifetap += spells[spell_id].base[i]; - else if((effect_value < 0) && (newbon->MeleeLifetap > effect_value)) - newbon->MeleeLifetap = effect_value; + else if((effect_value < 0) && (new_bonus->MeleeLifetap > effect_value)) + new_bonus->MeleeLifetap = effect_value; - else if(newbon->MeleeLifetap < effect_value) - newbon->MeleeLifetap = effect_value; + else if(new_bonus->MeleeLifetap < effect_value) + new_bonus->MeleeLifetap = effect_value; break; } case SE_Vampirism: - newbon->Vampirism += effect_value; + new_bonus->Vampirism += effect_value; break; case SE_AllInstrumentMod: { - if(effect_value > newbon->singingMod) - newbon->singingMod = effect_value; - if(effect_value > newbon->brassMod) - newbon->brassMod = effect_value; - if(effect_value > newbon->percussionMod) - newbon->percussionMod = effect_value; - if(effect_value > newbon->windMod) - newbon->windMod = effect_value; - if(effect_value > newbon->stringedMod) - newbon->stringedMod = effect_value; + if(effect_value > new_bonus->singingMod) + new_bonus->singingMod = effect_value; + if(effect_value > new_bonus->brassMod) + new_bonus->brassMod = effect_value; + if(effect_value > new_bonus->percussionMod) + new_bonus->percussionMod = effect_value; + if(effect_value > new_bonus->windMod) + new_bonus->windMod = effect_value; + if(effect_value > new_bonus->stringedMod) + new_bonus->stringedMod = effect_value; break; } case SE_ResistSpellChance: - newbon->ResistSpellChance += effect_value; + new_bonus->ResistSpellChance += effect_value; break; case SE_ResistFearChance: { if(effect_value == 100) // If we reach 100% in a single spell/item then we should be immune to negative fear resist effects until our immunity is over - newbon->Fearless = true; + new_bonus->Fearless = true; - newbon->ResistFearChance += effect_value; // these should stack + new_bonus->ResistFearChance += effect_value; // these should stack break; } case SE_Fearless: - newbon->Fearless = true; + new_bonus->Fearless = true; break; case SE_HundredHands: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->HundredHands += effect_value; + new_bonus->HundredHands += effect_value; - if (effect_value > 0 && effect_value > newbon->HundredHands) - newbon->HundredHands = effect_value; //Increase Weapon Delay - else if (effect_value < 0 && effect_value < newbon->HundredHands) - newbon->HundredHands = effect_value; //Decrease Weapon Delay + if (effect_value > 0 && effect_value > new_bonus->HundredHands) + new_bonus->HundredHands = effect_value; //Increase Weapon Delay + else if (effect_value < 0 && effect_value < new_bonus->HundredHands) + new_bonus->HundredHands = effect_value; //Decrease Weapon Delay break; } case SE_MeleeSkillCheck: { - if(newbon->MeleeSkillCheck < effect_value) { - newbon->MeleeSkillCheck = effect_value; - newbon->MeleeSkillCheckSkill = base2==-1?255:base2; + if(new_bonus->MeleeSkillCheck < effect_value) { + new_bonus->MeleeSkillCheck = effect_value; + new_bonus->MeleeSkillCheckSkill = base2==-1?255:base2; } break; } @@ -2018,29 +2018,29 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (RuleB(Spells, AdditiveBonusValues) && item_bonus){ if(base2 == -1) - newbon->HitChanceEffect[HIGHEST_SKILL+1] += effect_value; + new_bonus->HitChanceEffect[HIGHEST_SKILL+1] += effect_value; else - newbon->HitChanceEffect[base2] += effect_value; + new_bonus->HitChanceEffect[base2] += effect_value; } else if(base2 == -1){ - if ((effect_value < 0) && (newbon->HitChanceEffect[HIGHEST_SKILL+1] > effect_value)) - newbon->HitChanceEffect[HIGHEST_SKILL+1] = effect_value; + if ((effect_value < 0) && (new_bonus->HitChanceEffect[HIGHEST_SKILL+1] > effect_value)) + new_bonus->HitChanceEffect[HIGHEST_SKILL+1] = effect_value; - else if (!newbon->HitChanceEffect[HIGHEST_SKILL+1] || - ((newbon->HitChanceEffect[HIGHEST_SKILL+1] > 0) && (newbon->HitChanceEffect[HIGHEST_SKILL+1] < effect_value))) - newbon->HitChanceEffect[HIGHEST_SKILL+1] = effect_value; + else if (!new_bonus->HitChanceEffect[HIGHEST_SKILL+1] || + ((new_bonus->HitChanceEffect[HIGHEST_SKILL+1] > 0) && (new_bonus->HitChanceEffect[HIGHEST_SKILL+1] < effect_value))) + new_bonus->HitChanceEffect[HIGHEST_SKILL+1] = effect_value; } else { - if ((effect_value < 0) && (newbon->HitChanceEffect[base2] > effect_value)) - newbon->HitChanceEffect[base2] = effect_value; + if ((effect_value < 0) && (new_bonus->HitChanceEffect[base2] > effect_value)) + new_bonus->HitChanceEffect[base2] = effect_value; - else if (!newbon->HitChanceEffect[base2] || - ((newbon->HitChanceEffect[base2] > 0) && (newbon->HitChanceEffect[base2] < effect_value))) - newbon->HitChanceEffect[base2] = effect_value; + else if (!new_bonus->HitChanceEffect[base2] || + ((new_bonus->HitChanceEffect[base2] > 0) && (new_bonus->HitChanceEffect[base2] < effect_value))) + new_bonus->HitChanceEffect[base2] = effect_value; } break; @@ -2050,71 +2050,71 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_DamageModifier: { if(base2 == -1) - newbon->DamageModifier[HIGHEST_SKILL+1] += effect_value; + new_bonus->DamageModifier[HIGHEST_SKILL+1] += effect_value; else - newbon->DamageModifier[base2] += effect_value; + new_bonus->DamageModifier[base2] += effect_value; break; } case SE_DamageModifier2: { if(base2 == -1) - newbon->DamageModifier2[HIGHEST_SKILL+1] += effect_value; + new_bonus->DamageModifier2[HIGHEST_SKILL+1] += effect_value; else - newbon->DamageModifier2[base2] += effect_value; + new_bonus->DamageModifier2[base2] += effect_value; break; } case SE_MinDamageModifier: { if(base2 == -1) - newbon->MinDamageModifier[HIGHEST_SKILL+1] += effect_value; + new_bonus->MinDamageModifier[HIGHEST_SKILL+1] += effect_value; else - newbon->MinDamageModifier[base2] += effect_value; + new_bonus->MinDamageModifier[base2] += effect_value; break; } case SE_StunResist: { - if(newbon->StunResist < effect_value) - newbon->StunResist = effect_value; + if(new_bonus->StunResist < effect_value) + new_bonus->StunResist = effect_value; break; } case SE_ProcChance: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) - newbon->ProcChanceSPA += effect_value; + new_bonus->ProcChanceSPA += effect_value; - else if((effect_value < 0) && (newbon->ProcChanceSPA > effect_value)) - newbon->ProcChanceSPA = effect_value; + else if((effect_value < 0) && (new_bonus->ProcChanceSPA > effect_value)) + new_bonus->ProcChanceSPA = effect_value; - if(newbon->ProcChanceSPA < effect_value) - newbon->ProcChanceSPA = effect_value; + if(new_bonus->ProcChanceSPA < effect_value) + new_bonus->ProcChanceSPA = effect_value; break; } case SE_ExtraAttackChance: - newbon->ExtraAttackChance += effect_value; + new_bonus->ExtraAttackChance += effect_value; break; case SE_PercentXPIncrease: { - if(newbon->XPRateMod < effect_value) - newbon->XPRateMod = effect_value; + if(new_bonus->XPRateMod < effect_value) + new_bonus->XPRateMod = effect_value; break; } case SE_DeathSave: { - if(newbon->DeathSave[0] < effect_value) + if(new_bonus->DeathSave[0] < effect_value) { - newbon->DeathSave[0] = effect_value; //1='Partial' 2='Full' - newbon->DeathSave[1] = buffslot; + new_bonus->DeathSave[0] = effect_value; //1='Partial' 2='Full' + new_bonus->DeathSave[1] = buffslot; //These are used in later expansion spell effects. - newbon->DeathSave[2] = base2;//Min level for HealAmt - newbon->DeathSave[3] = max;//HealAmt + new_bonus->DeathSave[2] = base2;//Min level for HealAmt + new_bonus->DeathSave[3] = max;//HealAmt } break; } @@ -2122,44 +2122,44 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_DivineSave: { if (RuleB(Spells, AdditiveBonusValues) && item_bonus) { - newbon->DivineSaveChance[0] += effect_value; - newbon->DivineSaveChance[1] = 0; + new_bonus->DivineSaveChance[0] += effect_value; + new_bonus->DivineSaveChance[1] = 0; } - else if(newbon->DivineSaveChance[0] < effect_value) + else if(new_bonus->DivineSaveChance[0] < effect_value) { - newbon->DivineSaveChance[0] = effect_value; - newbon->DivineSaveChance[1] = base2; + new_bonus->DivineSaveChance[0] = effect_value; + new_bonus->DivineSaveChance[1] = base2; //SetDeathSaveChance(true); } break; } case SE_Flurry: - newbon->FlurryChance += effect_value; + new_bonus->FlurryChance += effect_value; break; case SE_Accuracy: { - if ((effect_value < 0) && (newbon->Accuracy[HIGHEST_SKILL+1] > effect_value)) - newbon->Accuracy[HIGHEST_SKILL+1] = effect_value; + if ((effect_value < 0) && (new_bonus->Accuracy[HIGHEST_SKILL+1] > effect_value)) + new_bonus->Accuracy[HIGHEST_SKILL+1] = effect_value; - else if (!newbon->Accuracy[HIGHEST_SKILL+1] || - ((newbon->Accuracy[HIGHEST_SKILL+1] > 0) && (newbon->Accuracy[HIGHEST_SKILL+1] < effect_value))) - newbon->Accuracy[HIGHEST_SKILL+1] = effect_value; + else if (!new_bonus->Accuracy[HIGHEST_SKILL+1] || + ((new_bonus->Accuracy[HIGHEST_SKILL+1] > 0) && (new_bonus->Accuracy[HIGHEST_SKILL+1] < effect_value))) + new_bonus->Accuracy[HIGHEST_SKILL+1] = effect_value; break; } case SE_MaxHPChange: - newbon->MaxHPChange += effect_value; + new_bonus->MaxHPChange += effect_value; break; case SE_EndurancePool: - newbon->Endurance += effect_value; + new_bonus->Endurance += effect_value; break; case SE_HealRate: - newbon->HealRate += effect_value; + new_bonus->HealRate += effect_value; break; case SE_SkillDamageTaken: @@ -2174,9 +2174,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne else { if(base2 == -1) - newbon->SkillDmgTaken[HIGHEST_SKILL+1] += effect_value; + new_bonus->SkillDmgTaken[HIGHEST_SKILL+1] += effect_value; else - newbon->SkillDmgTaken[base2] += effect_value; + new_bonus->SkillDmgTaken[base2] += effect_value; } break; @@ -2186,9 +2186,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne { for(int e = 0; e < MAX_SPELL_TRIGGER; e++) { - if(!newbon->SpellTriggers[e]) + if(!new_bonus->SpellTriggers[e]) { - newbon->SpellTriggers[e] = spell_id; + new_bonus->SpellTriggers[e] = spell_id; break; } } @@ -2196,44 +2196,44 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } case SE_SpellCritChance: - newbon->CriticalSpellChance += effect_value; + new_bonus->CriticalSpellChance += effect_value; break; case SE_CriticalSpellChance: { - newbon->CriticalSpellChance += effect_value; + new_bonus->CriticalSpellChance += effect_value; - if (base2 > newbon->SpellCritDmgIncNoStack) - newbon->SpellCritDmgIncNoStack = base2; + if (base2 > new_bonus->SpellCritDmgIncNoStack) + new_bonus->SpellCritDmgIncNoStack = base2; break; } case SE_SpellCritDmgIncrease: - newbon->SpellCritDmgIncrease += effect_value; + new_bonus->SpellCritDmgIncrease += effect_value; break; case SE_DotCritDmgIncrease: - newbon->DotCritDmgIncrease += effect_value; + new_bonus->DotCritDmgIncrease += effect_value; break; case SE_CriticalHealChance: - newbon->CriticalHealChance += effect_value; + new_bonus->CriticalHealChance += effect_value; break; case SE_CriticalHealOverTime: - newbon->CriticalHealOverTime += effect_value; + new_bonus->CriticalHealOverTime += effect_value; break; case SE_CriticalHealDecay: - newbon->CriticalHealDecay = true; + new_bonus->CriticalHealDecay = true; break; case SE_CriticalRegenDecay: - newbon->CriticalRegenDecay = true; + new_bonus->CriticalRegenDecay = true; break; case SE_CriticalDotDecay: - newbon->CriticalDotDecay = true; + new_bonus->CriticalDotDecay = true; break; case SE_MitigateDamageShield: @@ -2241,24 +2241,24 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (effect_value < 0) effect_value = effect_value*-1; - newbon->DSMitigationOffHand += effect_value; + new_bonus->DSMitigationOffHand += effect_value; break; } case SE_CriticalDoTChance: - newbon->CriticalDoTChance += effect_value; + new_bonus->CriticalDoTChance += effect_value; break; case SE_ProcOnKillShot: { for(int e = 0; e < MAX_SPELL_TRIGGER*3; e+=3) { - if(!newbon->SpellOnKill[e]) + if(!new_bonus->SpellOnKill[e]) { // Base2 = Spell to fire | Base1 = % chance | Base3 = min level - newbon->SpellOnKill[e] = base2; - newbon->SpellOnKill[e+1] = effect_value; - newbon->SpellOnKill[e+2] = max; + new_bonus->SpellOnKill[e] = base2; + new_bonus->SpellOnKill[e+1] = effect_value; + new_bonus->SpellOnKill[e+2] = max; break; } } @@ -2269,11 +2269,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne { for(int e = 0; e < MAX_SPELL_TRIGGER; e+=2) { - if(!newbon->SpellOnDeath[e]) + if(!new_bonus->SpellOnDeath[e]) { // Base2 = Spell to fire | Base1 = % chance - newbon->SpellOnDeath[e] = base2; - newbon->SpellOnDeath[e+1] = effect_value; + new_bonus->SpellOnDeath[e] = base2; + new_bonus->SpellOnDeath[e+1] = effect_value; break; } } @@ -2283,151 +2283,151 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_CriticalDamageMob: { if(base2 == -1) - newbon->CritDmgMob[HIGHEST_SKILL+1] += effect_value; + new_bonus->CritDmgMob[HIGHEST_SKILL+1] += effect_value; else - newbon->CritDmgMob[base2] += effect_value; + new_bonus->CritDmgMob[base2] += effect_value; break; } case SE_ReduceSkillTimer: { - if(newbon->SkillReuseTime[base2] < effect_value) - newbon->SkillReuseTime[base2] = effect_value; + if(new_bonus->SkillReuseTime[base2] < effect_value) + new_bonus->SkillReuseTime[base2] = effect_value; break; } case SE_SkillDamageAmount: { if(base2 == -1) - newbon->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value; + new_bonus->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value; else - newbon->SkillDamageAmount[base2] += effect_value; + new_bonus->SkillDamageAmount[base2] += effect_value; break; } case SE_GravityEffect: - newbon->GravityEffect = 1; + new_bonus->GravityEffect = 1; break; case SE_AntiGate: - newbon->AntiGate = true; + new_bonus->AntiGate = true; break; case SE_MagicWeapon: - newbon->MagicWeapon = true; + new_bonus->MagicWeapon = true; break; case SE_IncreaseBlockChance: - newbon->IncreaseBlockChance += effect_value; + new_bonus->IncreaseBlockChance += effect_value; break; case SE_PersistantCasting: - newbon->PersistantCasting += effect_value; + new_bonus->PersistantCasting += effect_value; break; case SE_LimitHPPercent: { - if(newbon->HPPercCap[0] != 0 && newbon->HPPercCap[0] > effect_value){ - newbon->HPPercCap[0] = effect_value; - newbon->HPPercCap[1] = base2; + if(new_bonus->HPPercCap[0] != 0 && new_bonus->HPPercCap[0] > effect_value){ + new_bonus->HPPercCap[0] = effect_value; + new_bonus->HPPercCap[1] = base2; } - else if(newbon->HPPercCap[0] == 0){ - newbon->HPPercCap[0] = effect_value; - newbon->HPPercCap[1] = base2; + else if(new_bonus->HPPercCap[0] == 0){ + new_bonus->HPPercCap[0] = effect_value; + new_bonus->HPPercCap[1] = base2; } break; } case SE_LimitManaPercent: { - if(newbon->ManaPercCap[0] != 0 && newbon->ManaPercCap[0] > effect_value){ - newbon->ManaPercCap[0] = effect_value; - newbon->ManaPercCap[1] = base2; + if(new_bonus->ManaPercCap[0] != 0 && new_bonus->ManaPercCap[0] > effect_value){ + new_bonus->ManaPercCap[0] = effect_value; + new_bonus->ManaPercCap[1] = base2; } - else if(newbon->ManaPercCap[0] == 0) { - newbon->ManaPercCap[0] = effect_value; - newbon->ManaPercCap[1] = base2; + else if(new_bonus->ManaPercCap[0] == 0) { + new_bonus->ManaPercCap[0] = effect_value; + new_bonus->ManaPercCap[1] = base2; } break; } case SE_LimitEndPercent: { - if(newbon->EndPercCap[0] != 0 && newbon->EndPercCap[0] > effect_value) { - newbon->EndPercCap[0] = effect_value; - newbon->EndPercCap[1] = base2; + if(new_bonus->EndPercCap[0] != 0 && new_bonus->EndPercCap[0] > effect_value) { + new_bonus->EndPercCap[0] = effect_value; + new_bonus->EndPercCap[1] = base2; } - else if(newbon->EndPercCap[0] == 0){ - newbon->EndPercCap[0] = effect_value; - newbon->EndPercCap[1] = base2; + else if(new_bonus->EndPercCap[0] == 0){ + new_bonus->EndPercCap[0] = effect_value; + new_bonus->EndPercCap[1] = base2; } break; } case SE_BlockNextSpellFocus: - newbon->BlockNextSpell = true; + new_bonus->BlockNextSpell = true; break; case SE_NegateSpellEffect: - newbon->NegateEffects = true; + new_bonus->NegateEffects = true; break; case SE_ImmuneFleeing: - newbon->ImmuneToFlee = true; + new_bonus->ImmuneToFlee = true; break; case SE_DelayDeath: - newbon->DelayDeath += effect_value; + new_bonus->DelayDeath += effect_value; break; case SE_SpellProcChance: - newbon->SpellProcChance += effect_value; + new_bonus->SpellProcChance += effect_value; break; case SE_CharmBreakChance: - newbon->CharmBreakChance += effect_value; + new_bonus->CharmBreakChance += effect_value; break; case SE_BardSongRange: - newbon->SongRange += effect_value; + new_bonus->SongRange += effect_value; break; case SE_HPToMana: { //Lower the ratio the more favorable - if((!newbon->HPToManaConvert) || (newbon->HPToManaConvert >= effect_value)) - newbon->HPToManaConvert = spells[spell_id].base[i]; + if((!new_bonus->HPToManaConvert) || (new_bonus->HPToManaConvert >= effect_value)) + new_bonus->HPToManaConvert = spells[spell_id].base[i]; break; } case SE_SkillDamageAmount2: { if(base2 == -1) - newbon->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value; + new_bonus->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value; else - newbon->SkillDamageAmount2[base2] += effect_value; + new_bonus->SkillDamageAmount2[base2] += effect_value; break; } case SE_NegateAttacks: { - if (!newbon->NegateAttacks[0] || - ((newbon->NegateAttacks[0] && newbon->NegateAttacks[2]) && (newbon->NegateAttacks[2] < max))){ - newbon->NegateAttacks[0] = 1; - newbon->NegateAttacks[1] = buffslot; - newbon->NegateAttacks[2] = max; + if (!new_bonus->NegateAttacks[0] || + ((new_bonus->NegateAttacks[0] && new_bonus->NegateAttacks[2]) && (new_bonus->NegateAttacks[2] < max))){ + new_bonus->NegateAttacks[0] = 1; + new_bonus->NegateAttacks[1] = buffslot; + new_bonus->NegateAttacks[2] = max; } break; } case SE_MitigateMeleeDamage: { - if (newbon->MitigateMeleeRune[0] < effect_value){ - newbon->MitigateMeleeRune[0] = effect_value; - newbon->MitigateMeleeRune[1] = buffslot; - newbon->MitigateMeleeRune[2] = base2; - newbon->MitigateMeleeRune[3] = max; + if (new_bonus->MitigateMeleeRune[0] < effect_value){ + new_bonus->MitigateMeleeRune[0] = effect_value; + new_bonus->MitigateMeleeRune[1] = buffslot; + new_bonus->MitigateMeleeRune[2] = base2; + new_bonus->MitigateMeleeRune[3] = max; } break; } @@ -2435,268 +2435,268 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_MeleeThresholdGuard: { - if (newbon->MeleeThresholdGuard[0] < effect_value){ - newbon->MeleeThresholdGuard[0] = effect_value; - newbon->MeleeThresholdGuard[1] = buffslot; - newbon->MeleeThresholdGuard[2] = base2; + if (new_bonus->MeleeThresholdGuard[0] < effect_value){ + new_bonus->MeleeThresholdGuard[0] = effect_value; + new_bonus->MeleeThresholdGuard[1] = buffslot; + new_bonus->MeleeThresholdGuard[2] = base2; } break; } case SE_SpellThresholdGuard: { - if (newbon->SpellThresholdGuard[0] < effect_value){ - newbon->SpellThresholdGuard[0] = effect_value; - newbon->SpellThresholdGuard[1] = buffslot; - newbon->SpellThresholdGuard[2] = base2; + if (new_bonus->SpellThresholdGuard[0] < effect_value){ + new_bonus->SpellThresholdGuard[0] = effect_value; + new_bonus->SpellThresholdGuard[1] = buffslot; + new_bonus->SpellThresholdGuard[2] = base2; } break; } case SE_MitigateSpellDamage: { - if (newbon->MitigateSpellRune[0] < effect_value){ - newbon->MitigateSpellRune[0] = effect_value; - newbon->MitigateSpellRune[1] = buffslot; - newbon->MitigateSpellRune[2] = base2; - newbon->MitigateSpellRune[3] = max; + if (new_bonus->MitigateSpellRune[0] < effect_value){ + new_bonus->MitigateSpellRune[0] = effect_value; + new_bonus->MitigateSpellRune[1] = buffslot; + new_bonus->MitigateSpellRune[2] = base2; + new_bonus->MitigateSpellRune[3] = max; } break; } case SE_MitigateDotDamage: { - if (newbon->MitigateDotRune[0] < effect_value){ - newbon->MitigateDotRune[0] = effect_value; - newbon->MitigateDotRune[1] = buffslot; - newbon->MitigateDotRune[2] = base2; - newbon->MitigateDotRune[3] = max; + if (new_bonus->MitigateDotRune[0] < effect_value){ + new_bonus->MitigateDotRune[0] = effect_value; + new_bonus->MitigateDotRune[1] = buffslot; + new_bonus->MitigateDotRune[2] = base2; + new_bonus->MitigateDotRune[3] = max; } break; } case SE_ManaAbsorbPercentDamage: { - if (newbon->ManaAbsorbPercentDamage[0] < effect_value){ - newbon->ManaAbsorbPercentDamage[0] = effect_value; - newbon->ManaAbsorbPercentDamage[1] = buffslot; + if (new_bonus->ManaAbsorbPercentDamage[0] < effect_value){ + new_bonus->ManaAbsorbPercentDamage[0] = effect_value; + new_bonus->ManaAbsorbPercentDamage[1] = buffslot; } break; } case SE_TriggerMeleeThreshold: - newbon->TriggerMeleeThreshold = true; + new_bonus->TriggerMeleeThreshold = true; break; case SE_TriggerSpellThreshold: - newbon->TriggerSpellThreshold = true; + new_bonus->TriggerSpellThreshold = true; break; case SE_ShieldBlock: - newbon->ShieldBlock += effect_value; + new_bonus->ShieldBlock += effect_value; break; case SE_ShieldEquipHateMod: - newbon->ShieldEquipHateMod += effect_value; + new_bonus->ShieldEquipHateMod += effect_value; break; case SE_ShieldEquipDmgMod: - newbon->ShieldEquipDmgMod[0] += effect_value; - newbon->ShieldEquipDmgMod[1] += base2; + new_bonus->ShieldEquipDmgMod[0] += effect_value; + new_bonus->ShieldEquipDmgMod[1] += base2; break; case SE_BlockBehind: - newbon->BlockBehind += effect_value; + new_bonus->BlockBehind += effect_value; break; case SE_Blind: - newbon->IsBlind = true; + new_bonus->IsBlind = true; break; case SE_Fear: - newbon->IsFeared = true; + new_bonus->IsFeared = true; break; //AA bonuses - implemented broadly into spell/item effects case SE_FrontalStunResist: - newbon->FrontalStunResist += effect_value; + new_bonus->FrontalStunResist += effect_value; break; case SE_ImprovedBindWound: - newbon->BindWound += effect_value; + new_bonus->BindWound += effect_value; break; case SE_MaxBindWound: - newbon->MaxBindWound += effect_value; + new_bonus->MaxBindWound += effect_value; break; case SE_BaseMovementSpeed: - newbon->BaseMovementSpeed += effect_value; + new_bonus->BaseMovementSpeed += effect_value; break; case SE_IncreaseRunSpeedCap: - newbon->IncreaseRunSpeedCap += effect_value; + new_bonus->IncreaseRunSpeedCap += effect_value; break; case SE_DoubleSpecialAttack: - newbon->DoubleSpecialAttack += effect_value; + new_bonus->DoubleSpecialAttack += effect_value; break; case SE_TripleBackstab: - newbon->TripleBackstab += effect_value; + new_bonus->TripleBackstab += effect_value; break; case SE_FrontalBackstabMinDmg: - newbon->FrontalBackstabMinDmg = true; + new_bonus->FrontalBackstabMinDmg = true; break; case SE_FrontalBackstabChance: - newbon->FrontalBackstabChance += effect_value; + new_bonus->FrontalBackstabChance += effect_value; break; case SE_ConsumeProjectile: - newbon->ConsumeProjectile += effect_value; + new_bonus->ConsumeProjectile += effect_value; break; case SE_ForageAdditionalItems: - newbon->ForageAdditionalItems += effect_value; + new_bonus->ForageAdditionalItems += effect_value; break; case SE_Salvage: - newbon->SalvageChance += effect_value; + new_bonus->SalvageChance += effect_value; break; case SE_ArcheryDamageModifier: - newbon->ArcheryDamageModifier += effect_value; + new_bonus->ArcheryDamageModifier += effect_value; break; case SE_DoubleRangedAttack: - newbon->DoubleRangedAttack += effect_value; + new_bonus->DoubleRangedAttack += effect_value; break; case SE_SecondaryDmgInc: - newbon->SecondaryDmgInc = true; + new_bonus->SecondaryDmgInc = true; break; case SE_StrikeThrough: case SE_StrikeThrough2: - newbon->StrikeThrough += effect_value; + new_bonus->StrikeThrough += effect_value; break; case SE_GiveDoubleAttack: - newbon->GiveDoubleAttack += effect_value; + new_bonus->GiveDoubleAttack += effect_value; break; case SE_PetCriticalHit: - newbon->PetCriticalHit += effect_value; + new_bonus->PetCriticalHit += effect_value; break; case SE_CombatStability: - newbon->CombatStability += effect_value; + new_bonus->CombatStability += effect_value; break; case SE_AddSingingMod: switch (base2) { case ItemTypeWindInstrument: - newbon->windMod += effect_value; + new_bonus->windMod += effect_value; break; case ItemTypeStringedInstrument: - newbon->stringedMod += effect_value; + new_bonus->stringedMod += effect_value; break; case ItemTypeBrassInstrument: - newbon->brassMod += effect_value; + new_bonus->brassMod += effect_value; break; case ItemTypePercussionInstrument: - newbon->percussionMod += effect_value; + new_bonus->percussionMod += effect_value; break; case ItemTypeSinging: - newbon->singingMod += effect_value; + new_bonus->singingMod += effect_value; break; } break; case SE_SongModCap: - newbon->songModCap += effect_value; + new_bonus->songModCap += effect_value; break; case SE_PetAvoidance: - newbon->PetAvoidance += effect_value; + new_bonus->PetAvoidance += effect_value; break; case SE_Ambidexterity: - newbon->Ambidexterity += effect_value; + new_bonus->Ambidexterity += effect_value; break; case SE_PetMaxHP: - newbon->PetMaxHP += effect_value; + new_bonus->PetMaxHP += effect_value; break; case SE_PetFlurry: - newbon->PetFlurry += effect_value; + new_bonus->PetFlurry += effect_value; break; case SE_GivePetGroupTarget: - newbon->GivePetGroupTarget = true; + new_bonus->GivePetGroupTarget = true; break; case SE_RootBreakChance: - newbon->RootBreakChance += effect_value; + new_bonus->RootBreakChance += effect_value; break; case SE_ChannelChanceItems: - newbon->ChannelChanceItems += effect_value; + new_bonus->ChannelChanceItems += effect_value; break; case SE_ChannelChanceSpells: - newbon->ChannelChanceSpells += effect_value; + new_bonus->ChannelChanceSpells += effect_value; break; case SE_UnfailingDivinity: - newbon->UnfailingDivinity += effect_value; + new_bonus->UnfailingDivinity += effect_value; break; case SE_ItemHPRegenCapIncrease: - newbon->ItemHPRegenCap += effect_value; + new_bonus->ItemHPRegenCap += effect_value; break; case SE_OffhandRiposteFail: - newbon->OffhandRiposteFail += effect_value; + new_bonus->OffhandRiposteFail += effect_value; break; case SE_ItemAttackCapIncrease: - newbon->ItemATKCap += effect_value; + new_bonus->ItemATKCap += effect_value; break; case SE_TwoHandBluntBlock: - newbon->TwoHandBluntBlock += effect_value; + new_bonus->TwoHandBluntBlock += effect_value; break; case SE_StunBashChance: - newbon->StunBashChance += effect_value; + new_bonus->StunBashChance += effect_value; break; case SE_IncreaseChanceMemwipe: - newbon->IncreaseChanceMemwipe += effect_value; + new_bonus->IncreaseChanceMemwipe += effect_value; break; case SE_CriticalMend: - newbon->CriticalMend += effect_value; + new_bonus->CriticalMend += effect_value; break; case SE_SpellEffectResistChance: { for(int e = 0; e < MAX_RESISTABLE_EFFECTS*2; e+=2) { - if(newbon->SEResist[e+1] && (newbon->SEResist[e] == base2) && (newbon->SEResist[e+1] < effect_value)){ - newbon->SEResist[e] = base2; //Spell Effect ID - newbon->SEResist[e+1] = effect_value; //Resist Chance + if(new_bonus->SEResist[e+1] && (new_bonus->SEResist[e] == base2) && (new_bonus->SEResist[e+1] < effect_value)){ + new_bonus->SEResist[e] = base2; //Spell Effect ID + new_bonus->SEResist[e+1] = effect_value; //Resist Chance break; } - else if (!newbon->SEResist[e+1]){ - newbon->SEResist[e] = base2; //Spell Effect ID - newbon->SEResist[e+1] = effect_value; //Resist Chance + else if (!new_bonus->SEResist[e+1]){ + new_bonus->SEResist[e] = base2; //Spell Effect ID + new_bonus->SEResist[e+1] = effect_value; //Resist Chance break; } } @@ -2705,110 +2705,110 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_MasteryofPast: { - if(newbon->MasteryofPast < effect_value) - newbon->MasteryofPast = effect_value; + if(new_bonus->MasteryofPast < effect_value) + new_bonus->MasteryofPast = effect_value; break; } case SE_DoubleRiposte: { - newbon->DoubleRiposte += effect_value; + new_bonus->DoubleRiposte += effect_value; } case SE_GiveDoubleRiposte: { //Only allow for regular double riposte chance. - if(newbon->GiveDoubleRiposte[base2] == 0){ - if(newbon->GiveDoubleRiposte[0] < effect_value) - newbon->GiveDoubleRiposte[0] = effect_value; + if(new_bonus->GiveDoubleRiposte[base2] == 0){ + if(new_bonus->GiveDoubleRiposte[0] < effect_value) + new_bonus->GiveDoubleRiposte[0] = effect_value; } break; } case SE_SlayUndead: { - if(newbon->SlayUndead[1] < effect_value) - newbon->SlayUndead[0] = effect_value; // Rate - newbon->SlayUndead[1] = base2; // Damage Modifier + if(new_bonus->SlayUndead[1] < effect_value) + new_bonus->SlayUndead[0] = effect_value; // Rate + new_bonus->SlayUndead[1] = base2; // Damage Modifier break; } case SE_TriggerOnReqTarget: case SE_TriggerOnReqCaster: - newbon->TriggerOnValueAmount = true; + new_bonus->TriggerOnValueAmount = true; break; case SE_DivineAura: - newbon->DivineAura = true; + new_bonus->DivineAura = true; break; case SE_ImprovedTaunt: - if (newbon->ImprovedTaunt[0] < effect_value) { - newbon->ImprovedTaunt[0] = effect_value; - newbon->ImprovedTaunt[1] = base2; - newbon->ImprovedTaunt[2] = buffslot; + if (new_bonus->ImprovedTaunt[0] < effect_value) { + new_bonus->ImprovedTaunt[0] = effect_value; + new_bonus->ImprovedTaunt[1] = base2; + new_bonus->ImprovedTaunt[2] = buffslot; } break; case SE_DistanceRemoval: - newbon->DistanceRemoval = true; + new_bonus->DistanceRemoval = true; break; case SE_FrenziedDevastation: - newbon->FrenziedDevastation += base2; + new_bonus->FrenziedDevastation += base2; break; case SE_Root: - if (newbon->Root[0] && (newbon->Root[1] > buffslot)){ - newbon->Root[0] = 1; - newbon->Root[1] = buffslot; + if (new_bonus->Root[0] && (new_bonus->Root[1] > buffslot)){ + new_bonus->Root[0] = 1; + new_bonus->Root[1] = buffslot; } - else if (!newbon->Root[0]){ - newbon->Root[0] = 1; - newbon->Root[1] = buffslot; + else if (!new_bonus->Root[0]){ + new_bonus->Root[0] = 1; + new_bonus->Root[1] = buffslot; } break; case SE_Rune: - if (newbon->MeleeRune[0] && (newbon->MeleeRune[1] > buffslot)){ + if (new_bonus->MeleeRune[0] && (new_bonus->MeleeRune[1] > buffslot)){ - newbon->MeleeRune[0] = effect_value; - newbon->MeleeRune[1] = buffslot; + new_bonus->MeleeRune[0] = effect_value; + new_bonus->MeleeRune[1] = buffslot; } - else if (!newbon->MeleeRune[0]){ - newbon->MeleeRune[0] = effect_value; - newbon->MeleeRune[1] = buffslot; + else if (!new_bonus->MeleeRune[0]){ + new_bonus->MeleeRune[0] = effect_value; + new_bonus->MeleeRune[1] = buffslot; } break; case SE_AbsorbMagicAtt: - if (newbon->AbsorbMagicAtt[0] && (newbon->AbsorbMagicAtt[1] > buffslot)){ - newbon->AbsorbMagicAtt[0] = effect_value; - newbon->AbsorbMagicAtt[1] = buffslot; + if (new_bonus->AbsorbMagicAtt[0] && (new_bonus->AbsorbMagicAtt[1] > buffslot)){ + new_bonus->AbsorbMagicAtt[0] = effect_value; + new_bonus->AbsorbMagicAtt[1] = buffslot; } - else if (!newbon->AbsorbMagicAtt[0]){ - newbon->AbsorbMagicAtt[0] = effect_value; - newbon->AbsorbMagicAtt[1] = buffslot; + else if (!new_bonus->AbsorbMagicAtt[0]){ + new_bonus->AbsorbMagicAtt[0] = effect_value; + new_bonus->AbsorbMagicAtt[1] = buffslot; } break; case SE_NegateIfCombat: - newbon->NegateIfCombat = true; + new_bonus->NegateIfCombat = true; break; case SE_Screech: - newbon->Screech = effect_value; + new_bonus->Screech = effect_value; break; case SE_AlterNPCLevel: if (IsNPC()){ - if (!newbon->AlterNPCLevel - || ((effect_value < 0) && (newbon->AlterNPCLevel > effect_value)) - || ((effect_value > 0) && (newbon->AlterNPCLevel < effect_value))) { + if (!new_bonus->AlterNPCLevel + || ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value)) + || ((effect_value > 0) && (new_bonus->AlterNPCLevel < effect_value))) { int tmp_lv = GetOrigLevel() + effect_value; if (tmp_lv < 1) @@ -2816,7 +2816,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne else if (tmp_lv > 255) tmp_lv = 255; if ((GetLevel() != tmp_lv)){ - newbon->AlterNPCLevel = effect_value; + new_bonus->AlterNPCLevel = effect_value; SetLevel(tmp_lv); } } @@ -2824,82 +2824,82 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; case SE_AStacker: - newbon->AStacker[0] = 1; - newbon->AStacker[1] = effect_value; + new_bonus->AStacker[0] = 1; + new_bonus->AStacker[1] = effect_value; break; case SE_BStacker: - newbon->BStacker[0] = 1; - newbon->BStacker[1] = effect_value; + new_bonus->BStacker[0] = 1; + new_bonus->BStacker[1] = effect_value; break; case SE_CStacker: - newbon->CStacker[0] = 1; - newbon->CStacker[1] = effect_value; + new_bonus->CStacker[0] = 1; + new_bonus->CStacker[1] = effect_value; break; case SE_DStacker: - newbon->DStacker[0] = 1; - newbon->DStacker[1] = effect_value; + new_bonus->DStacker[0] = 1; + new_bonus->DStacker[1] = effect_value; break; case SE_Berserk: - newbon->BerserkSPA = true; + new_bonus->BerserkSPA = true; break; case SE_Metabolism: - newbon->Metabolism += effect_value; + new_bonus->Metabolism += effect_value; break; case SE_ImprovedReclaimEnergy: { - if((effect_value < 0) && (newbon->ImprovedReclaimEnergy > effect_value)) - newbon->ImprovedReclaimEnergy = effect_value; + if((effect_value < 0) && (new_bonus->ImprovedReclaimEnergy > effect_value)) + new_bonus->ImprovedReclaimEnergy = effect_value; - else if(newbon->ImprovedReclaimEnergy < effect_value) - newbon->ImprovedReclaimEnergy = effect_value; + else if(new_bonus->ImprovedReclaimEnergy < effect_value) + new_bonus->ImprovedReclaimEnergy = effect_value; break; } case SE_HeadShot: { - if(newbon->HeadShot[1] < base2){ - newbon->HeadShot[0] = effect_value; - newbon->HeadShot[1] = base2; + if(new_bonus->HeadShot[1] < base2){ + new_bonus->HeadShot[0] = effect_value; + new_bonus->HeadShot[1] = base2; } break; } case SE_HeadShotLevel: { - if(newbon->HSLevel < effect_value) - newbon->HSLevel = effect_value; + if(new_bonus->HSLevel < effect_value) + new_bonus->HSLevel = effect_value; break; } case SE_Assassinate: { - if(newbon->Assassinate[1] < base2){ - newbon->Assassinate[0] = effect_value; - newbon->Assassinate[1] = base2; + if(new_bonus->Assassinate[1] < base2){ + new_bonus->Assassinate[0] = effect_value; + new_bonus->Assassinate[1] = base2; } break; } case SE_AssassinateLevel: { - if(newbon->AssassinateLevel < effect_value) - newbon->AssassinateLevel = effect_value; + if(new_bonus->AssassinateLevel < effect_value) + new_bonus->AssassinateLevel = effect_value; break; } case SE_FinishingBlow: { //base1 = chance, base2 = damage - if (newbon->FinishingBlow[1] < base2){ - newbon->FinishingBlow[0] = effect_value; - newbon->FinishingBlow[1] = base2; + if (new_bonus->FinishingBlow[1] < base2){ + new_bonus->FinishingBlow[0] = effect_value; + new_bonus->FinishingBlow[1] = base2; } break; } @@ -2907,42 +2907,42 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_FinishingBlowLvl: { //base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?) - if (newbon->FinishingBlowLvl[0] < effect_value){ - newbon->FinishingBlowLvl[0] = effect_value; - newbon->FinishingBlowLvl[1] = base2; + if (new_bonus->FinishingBlowLvl[0] < effect_value){ + new_bonus->FinishingBlowLvl[0] = effect_value; + new_bonus->FinishingBlowLvl[1] = base2; } break; } case SE_PetMeleeMitigation: - newbon->PetMeleeMitigation += effect_value; + new_bonus->PetMeleeMitigation += effect_value; break; case SE_MeleeVulnerability: - newbon->MeleeVulnerability += effect_value; + new_bonus->MeleeVulnerability += effect_value; break; case SE_Sanctuary: - newbon->Sanctuary = true; + new_bonus->Sanctuary = true; break; case SE_FactionModPct: { - if((effect_value < 0) && (newbon->FactionModPct > effect_value)) - newbon->FactionModPct = effect_value; + if((effect_value < 0) && (new_bonus->FactionModPct > effect_value)) + new_bonus->FactionModPct = effect_value; - else if(newbon->FactionModPct < effect_value) - newbon->FactionModPct = effect_value; + else if(new_bonus->FactionModPct < effect_value) + new_bonus->FactionModPct = effect_value; break; } case SE_IllusionPersistence: - newbon->IllusionPersistence = true; + new_bonus->IllusionPersistence = true; break; case SE_LimitToSkill:{ if (effect_value <= HIGHEST_SKILL){ - newbon->LimitToSkill[effect_value] = true; + new_bonus->LimitToSkill[effect_value] = true; } break; } @@ -2951,11 +2951,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne for(int e = 0; e < MAX_SKILL_PROCS; e++) { - if(newbon->SkillProc[e] && newbon->SkillProc[e] == spell_id) + if(new_bonus->SkillProc[e] && new_bonus->SkillProc[e] == spell_id) break; //Do not use the same spell id more than once. - else if(!newbon->SkillProc[e]){ - newbon->SkillProc[e] = spell_id; + else if(!new_bonus->SkillProc[e]){ + new_bonus->SkillProc[e] = spell_id; break; } } @@ -2966,11 +2966,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne for(int e = 0; e < MAX_SKILL_PROCS; e++) { - if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == spell_id) + if(new_bonus->SkillProcSuccess[e] && new_bonus->SkillProcSuccess[e] == spell_id) break; //Do not use the same spell id more than once. - else if(!newbon->SkillProcSuccess[e]){ - newbon->SkillProcSuccess[e] = spell_id; + else if(!new_bonus->SkillProcSuccess[e]){ + new_bonus->SkillProcSuccess[e] = spell_id; break; } } diff --git a/zone/bot.cpp b/zone/bot.cpp index ef40e1bcb..d41b6db11 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -234,45 +234,28 @@ void Bot::SetBotSpellID(uint32 newSpellID) { this->npc_spells_id = newSpellID; } -uint32 Bot::GetBotArcheryRange() { - uint32 result = 0; +uint32 Bot::GetBotArcheryRange() +{ + const ItemInst *range_inst = GetBotItem(MainRange); + const ItemInst *ammo_inst = GetBotItem(MainAmmo); - ItemInst* rangeItem = GetBotItem(MainRange); - - if(!rangeItem) + // empty slots + if (!range_inst || !ammo_inst) return 0; - const Item_Struct* botweapon = rangeItem->GetItem(); + const Item_Struct *range_item = range_inst->GetItem(); + const Item_Struct *ammo_item = ammo_inst->GetItem(); - uint32 archeryMaterial; - uint32 archeryColor; - uint32 archeryBowID; - uint32 archeryAmmoID; + // no item struct for whatever reason + if (!range_item || !ammo_item) + return 0; - if(botweapon && botweapon->ItemType == ItemTypeBow) { - uint32 range = 0; + // bad item types + if (range_item->ItemType != ItemTypeBow || ammo_item->ItemType != ItemTypeArrow) + return 0; - archeryMaterial = atoi(botweapon->IDFile + 2); - archeryBowID = botweapon->ID; - archeryColor = botweapon->Color; - range =+ botweapon->Range; - - rangeItem = GetBotItem(MainAmmo); - if(rangeItem) - botweapon = rangeItem->GetItem(); - - if(!botweapon || (botweapon->ItemType != ItemTypeArrow)) { - return 0; - } - - range += botweapon->Range; - - archeryAmmoID = botweapon->ID; - - result = range; - } - - return result; + // everything is good! + return range_item->Range + ammo_item->Range; } void Bot::ChangeBotArcherWeapons(bool isArcher) { @@ -386,8 +369,8 @@ NPCType Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::str BotNPCType.npc_id = 0; BotNPCType.texture = 0; - BotNPCType.d_meele_texture1 = 0; - BotNPCType.d_meele_texture2 = 0; + BotNPCType.d_melee_texture1 = 0; + BotNPCType.d_melee_texture2 = 0; BotNPCType.qglobal = false; BotNPCType.attack_speed = 0; BotNPCType.runspeed = 1.25; @@ -431,8 +414,8 @@ NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string b Result.hp_regen = 1; Result.mana_regen = 1; Result.texture = 0; - Result.d_meele_texture1 = 0; - Result.d_meele_texture2 = 0; + Result.d_melee_texture1 = 0; + Result.d_melee_texture2 = 0; Result.qglobal = false; Result.npc_spells_id = 0; Result.attack_speed = 0; @@ -3439,9 +3422,9 @@ void Bot::AI_Process() { rest_timer.Disable(); if(IsRooted()) - SetTarget(hate_list.GetClosest(this)); + SetTarget(hate_list.GetClosestEntOnHateList(this)); else - SetTarget(hate_list.GetTop(this)); + SetTarget(hate_list.GetEntWithMostHateOnList(this)); if(!GetTarget()) return; @@ -3808,9 +3791,9 @@ void Bot::PetAIProcess() { if (IsEngaged()) { if (botPet->IsRooted()) - botPet->SetTarget(hate_list.GetClosest(botPet)); + botPet->SetTarget(hate_list.GetClosestEntOnHateList(botPet)); else - botPet->SetTarget(hate_list.GetTop(botPet)); + botPet->SetTarget(hate_list.GetEntWithMostHateOnList(botPet)); // Let's check if we have a los with our target. // If we don't, our hate_list is wiped. @@ -5871,7 +5854,7 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, SkillUseTypes att Save(); - Mob *give_exp = hate_list.GetDamageTop(this); + Mob *give_exp = hate_list.GetDamageTopOnHateList(this); Client *give_exp_client = nullptr; if(give_exp && give_exp->IsClient()) @@ -6025,7 +6008,7 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, SkillUseTypes attack_ } } -void Bot::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) +void Bot::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/) { Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic); } @@ -11716,106 +11699,47 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) { const char* equipped[EmuConstants::EQUIPMENT_SIZE] = {"Charm", "Left Ear", "Head", "Face", "Right Ear", "Neck", "Shoulders", "Arms", "Back", "Left Wrist", "Right Wrist", "Range", "Hands", "Primary Hand", "Secondary Hand", "Left Finger", "Right Finger", "Chest", "Legs", "Feet", "Waist", "Ammo" }; - const ItemInst* item1 = nullptr; - const Item_Struct* item2 = nullptr; + + const ItemInst* inst = nullptr; + const Item_Struct* item = nullptr; bool is2Hweapon = false; - for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) - { + + std::string item_link; + Client::TextLink linker; + linker.SetLinkType(linker.linkItemInst); + linker.SetClientVersion(c->GetClientVersion()); + + for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) { if((i == MainSecondary) && is2Hweapon) { continue; } - item1 = b->CastToBot()->GetBotItem(i); - if(item1) - item2 = item1->GetItem(); + inst = b->CastToBot()->GetBotItem(i); + if (inst) + item = inst->GetItem(); else - item2 = nullptr; + item = nullptr; if(!TempErrorMessage.empty()) { c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); return; } - if(item2 == 0) { + if(item == nullptr) { c->Message(15, "I need something for my %s (Item %i)", equipped[i], i); continue; } - if((i == MainPrimary) && ((item2->ItemType == ItemType2HSlash) || (item2->ItemType == ItemType2HBlunt) || (item2->ItemType == ItemType2HPiercing))) { + if((i == MainPrimary) && ((item->ItemType == ItemType2HSlash) || (item->ItemType == ItemType2HBlunt) || (item->ItemType == ItemType2HPiercing))) { is2Hweapon = true; } - char* itemLink = 0; - if((i == MainCharm) || (i == MainRange) || (i == MainPrimary) || (i == MainSecondary) || (i == MainAmmo)) { - if (c->GetClientVersion() >= EQClientSoF) - { - MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X", - 0, - item2->ID, - item1->GetAugmentItemID(0), - item1->GetAugmentItemID(1), - item1->GetAugmentItemID(2), - item1->GetAugmentItemID(3), - item1->GetAugmentItemID(4), - 0, - 0, - 0, - 0, - 0 - ); - c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i); - } - else - { - MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X", - 0, - item2->ID, - item1->GetAugmentItemID(0), - item1->GetAugmentItemID(1), - item1->GetAugmentItemID(2), - item1->GetAugmentItemID(3), - item1->GetAugmentItemID(4), - 0, - 0, - 0, - 0); - c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i); - } - } - else { - if (c->GetClientVersion() >= EQClientSoF) - { - MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X", - 0, - item2->ID, - item1->GetAugmentItemID(0), - item1->GetAugmentItemID(1), - item1->GetAugmentItemID(2), - item1->GetAugmentItemID(3), - item1->GetAugmentItemID(4), - 0, - 0, - 0, - 0, - 0 - ); - c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i); - } - else - { - MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X", - 0, - item2->ID, - item1->GetAugmentItemID(0), - item1->GetAugmentItemID(1), - item1->GetAugmentItemID(2), - item1->GetAugmentItemID(3), - item1->GetAugmentItemID(4), - 0, - 0, - 0, - 0); - c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i); - } - } + // I could not find a difference between the criteria positive code and the criteria negative code.. + // ..so, I deleted the check (old criteria: i = { MainCharm, MainRange, MainPrimary, MainSecondary, MainAmmo }) + + linker.SetItemInst(inst); + + item_link = linker.GenerateLink(); + + c->Message(15, "Using %s in my %s (Item %i)", item_link.c_str(), equipped[i], i); } } else { @@ -14364,8 +14288,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) { return; } - std::list::iterator botGroupItr = botGroup.begin(); - for(botGroupItr; botGroupItr != botGroup.end(); ++botGroupItr) { + for(auto botGroupItr = botGroup.begin(); botGroupItr != botGroup.end(); ++botGroupItr) { // Don't try to re-spawn the botgroup's leader. if(botGroupItr->BotID == botGroupLeader->GetBotID()) { continue; } @@ -15474,7 +15397,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) { else { Mob *target = c->GetTarget(); - if(target->IsBot() && (c == target->GetOwner()->CastToClient())) { + if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) { const InspectMessage_Struct& playermessage = c->GetInspectMessage(); InspectMessage_Struct& botmessage = target->CastToBot()->GetInspectMessage(); @@ -15504,7 +15427,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) { Mob *target = c->GetTarget(); - if(target->IsBot() && (c == target->GetOwner()->CastToClient())) { + if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) { Bot* bardBot = target->CastToBot(); if(bardBot) { diff --git a/zone/bot.h b/zone/bot.h index 6e7b452af..40b505c84 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -208,7 +208,7 @@ public: bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic); void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color); void Camp(bool databaseSave = true); - virtual void AddToHateList(Mob* other, int32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false); + virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false); virtual void SetTarget(Mob* mob); virtual void Zone(); std::vector GetBotSpells() { return AIspells; } diff --git a/zone/client.cpp b/zone/client.cpp index 181589bf5..0ad34d752 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1817,45 +1817,8 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) } ns->spawn.size = 0; // Changing size works, but then movement stops! (wth?) ns->spawn.runspeed = (gmspeed == 0) ? runspeed : 3.125f; - if (!m_pp.showhelm) ns->spawn.showhelm = 0; + ns->spawn.showhelm = m_pp.showhelm ? 1 : 0; - /* - // Equipment/Weapons already set from Mob::FillSpawnStruct - // Commenting this out for now - const Item_Struct* item = nullptr; - const ItemInst* inst = nullptr; - int16 invslot; - - for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) - { - // Only Player Races Wear Armor - if (IsPlayerRace(race) || matslot > 6) - { - invslot = Inventory::CalcSlotFromMaterial(matslot); - if (invslot == INVALID_INDEX) - continue; - - if ((inst = m_inv[invslot]) && inst->IsType(ItemClassCommon)) - { - item = inst->GetItem(); - - if (matslot > 6) - { - // Weapon Models - ns->spawn.equipment[matslot].material = GetEquipmentMaterial(matslot); - } - else - { - // Armor Materials/Models - ns->spawn.equipment[matslot].material = item->Material; - ns->spawn.equipment[matslot].elitematerial = item->EliteMaterial; - ns->spawn.equipment[matslot].heroforgemodel = GetHerosForgeModel(matslot); - ns->spawn.colors[matslot].color = m_pp.item_tint[matslot].rgb.use_tint ? m_pp.item_tint[matslot].color : item->Color; - } - } - } - } - */ } bool Client::GMHideMe(Client* client) { @@ -6305,8 +6268,8 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid made_npc->drakkin_heritage = GetDrakkinHeritage(); made_npc->drakkin_tattoo = GetDrakkinTattoo(); made_npc->drakkin_details = GetDrakkinDetails(); - made_npc->d_meele_texture1 = GetEquipmentMaterial(MaterialPrimary); - made_npc->d_meele_texture2 = GetEquipmentMaterial(MaterialSecondary); + made_npc->d_melee_texture1 = GetEquipmentMaterial(MaterialPrimary); + made_npc->d_melee_texture2 = GetEquipmentMaterial(MaterialSecondary); for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) { made_npc->armor_tint[i] = GetEquipmentColor(i); } @@ -8295,3 +8258,236 @@ void Client::SendColoredText(uint32 color, std::string message) safe_delete(outapp); } + +// +// class Client::TextLink +// +std::string Client::TextLink::GenerateLink() +{ + m_Link.clear(); + m_LinkBody.clear(); + m_LinkText.clear(); + + generate_body(); + generate_text(); + + if (m_LinkBody.length() && m_LinkText.length()) { + m_Link.append(StringFormat("%c", 0x12)); + m_Link.append(m_LinkBody); + m_Link.append(m_LinkText); + m_Link.append(StringFormat("%c", 0x12)); + } + + if ((m_Link.length() == 0) || (m_Link.length() > 250)) { + m_Error = true; + m_Link = ""; + _log(CHANNELS__ERROR, "TextLink::GenerateLink() failed to generate a useable text link (LinkType: %i, Lengths: {l: %u, b: %u, t: %u})", + m_LinkType, m_Link.length(), m_LinkBody.length(), m_LinkText.length()); + } + + return m_Link; +} + +const char* Client::TextLink::GetLink() +{ + if (m_Link.length() == 0) + return nullptr; + + return m_Link.c_str(); +} + +const char* Client::TextLink::GetLinkBody() +{ + if (m_LinkBody.length() == 0) + return nullptr; + + return m_LinkBody.c_str(); +} + +const char* Client::TextLink::GetLinkText() +{ + if (m_LinkText.length() == 0) + return nullptr; + + return m_LinkText.c_str(); +} + +std::string Client::TextLink::GetLinkString() +{ + if (m_Link.length() == 0) + return ""; + + return m_Link; +} + +std::string Client::TextLink::GetLinkBodyString() +{ + if (m_LinkBody.length() == 0) + return ""; + + return m_LinkBody; +} + +std::string Client::TextLink::GetLinkTextString() +{ + if (m_LinkText.length() == 0) + return ""; + + return m_LinkText; +} + +void Client::TextLink::Reset() +{ + m_LinkType = linkBlank; + m_ItemData = nullptr; + m_LootData = nullptr; + m_ItemInst = nullptr; + m_ProxyItemID = NOT_USED; + m_ProxyText = nullptr; + m_TaskUse = false; + m_Link.clear(); + m_LinkBody.clear(); + m_LinkText.clear(); + m_ClientVersion = EQClientUnknown; + m_Error = false; +} + +void Client::TextLink::generate_body() +{ + enum { field_0 = 0, field_1, field_2, field_3, field_4, field_5, field_6, field_7, field_8, field_9, field_10, field_11, field_12, field_13 }; + static const int field_count = 14; + static const bool field_use[_EQClientCount][field_count] = { + // 6.2: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X" + // SoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" + // RoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" + // RoF2: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X" + +//(RoF2) %01x %05x %05x %05x %05x %05x %05x %05x %01x %01x %04x %01x %05x %08x + { true, true, true, true, true, true, true, true, true, true, true, true, true, true }, // EQClientUnknown + { true, true, true, true, true, true, true, false, false, true, true, true, false, true }, // EQClient6.2 + { true, true, true, true, true, true, true, false, false, true, true, true, false, true }, // EQClientTitanium + { true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientSoF + { true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientSoD + { true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientUnderfoot + { true, true, true, true, true, true, true, true, false, true, true, true, true, true }, // EQClientRoF + { true, true, true, true, true, true, true, true, true, true, true, true, true, true } // EQClientRoF2 + }; + +/*%01X*/ uint8 unknown_0 = NOT_USED; +/*%05X*/ uint32 item_id = NOT_USED; +/*%05X*/ uint32 augment_0 = NOT_USED; +/*%05X*/ uint32 augment_1 = NOT_USED; +/*%05X*/ uint32 augment_2 = NOT_USED; +/*%05X*/ uint32 augment_3 = NOT_USED; +/*%05X*/ uint32 augment_4 = NOT_USED; +/*%05X*/ uint32 augment_5 = NOT_USED; +/*%01X*/ uint8 unknown_8 = NOT_USED; +/*%01X*/ uint8 unknown_9 = NOT_USED; +/*%04X*/ uint32 unknown_10 = NOT_USED; +/*%01X*/ uint8 unknown_11 = NOT_USED; +/*%05X*/ uint32 unknown_12 = NOT_USED; +/*%08X*/ int hash = NOT_USED; + + switch (m_LinkType) { + case linkBlank: + break; + case linkItemData: + if (m_ItemData != nullptr) { + item_id = m_ItemData->ID; + // TODO: add hash call + } + break; + case linkLootItem: + if (m_LootData != nullptr) { + const Item_Struct* item_data = database.GetItem(m_LootData->item_id); + if (item_data == nullptr) { break; } + item_id = item_data->ID; + augment_0 = m_LootData->aug_1; + augment_1 = m_LootData->aug_2; + augment_2 = m_LootData->aug_3; + augment_3 = m_LootData->aug_4; + augment_4 = m_LootData->aug_5; + augment_5 = m_LootData->aug_6; + // TODO: add hash call + } + break; + case linkItemInst: + if (m_ItemInst != nullptr) { + if (m_ItemInst->GetItem() == nullptr) { break; } + item_id = m_ItemInst->GetItem()->ID; + augment_0 = m_ItemInst->GetAugmentItemID(0); + augment_1 = m_ItemInst->GetAugmentItemID(1); + augment_2 = m_ItemInst->GetAugmentItemID(2); + augment_3 = m_ItemInst->GetAugmentItemID(3); + augment_4 = m_ItemInst->GetAugmentItemID(4); + augment_5 = m_ItemInst->GetAugmentItemID(5); + // TODO: add hash call + } + break; + default: + break; + } + + if (m_ProxyItemID != NOT_USED) { + item_id = m_ProxyItemID; + } + + if (m_TaskUse) { + hash = 0x0000000014505DC2; + } + + if (field_use[m_ClientVersion][field_0]) { m_LinkBody.append(StringFormat("%01x", unknown_0)); } + if (field_use[m_ClientVersion][field_1]) { m_LinkBody.append(StringFormat("%05x", item_id)); } + if (field_use[m_ClientVersion][field_2]) { m_LinkBody.append(StringFormat("%05x", augment_0)); } + if (field_use[m_ClientVersion][field_3]) { m_LinkBody.append(StringFormat("%05x", augment_1)); } + if (field_use[m_ClientVersion][field_4]) { m_LinkBody.append(StringFormat("%05x", augment_2)); } + if (field_use[m_ClientVersion][field_5]) { m_LinkBody.append(StringFormat("%05x", augment_3)); } + if (field_use[m_ClientVersion][field_6]) { m_LinkBody.append(StringFormat("%05x", augment_4)); } + if (field_use[m_ClientVersion][field_7]) { m_LinkBody.append(StringFormat("%05x", augment_5)); } + if (field_use[m_ClientVersion][field_8]) { m_LinkBody.append(StringFormat("%01x", unknown_8)); } + if (field_use[m_ClientVersion][field_9]) { m_LinkBody.append(StringFormat("%01x", unknown_9)); } + if (field_use[m_ClientVersion][field_10]) { m_LinkBody.append(StringFormat("%04x", unknown_10)); } + if (field_use[m_ClientVersion][field_11]) { m_LinkBody.append(StringFormat("%01x", unknown_11)); } + if (field_use[m_ClientVersion][field_12]) { m_LinkBody.append(StringFormat("%05x", unknown_12)); } + if (field_use[m_ClientVersion][field_13]) { m_LinkBody.append(StringFormat("%08x", hash)); } +} + +void Client::TextLink::generate_text() +{ + if (m_ProxyText != nullptr) { + m_LinkText = m_ProxyText; + return; + } + + switch (m_LinkType) { + case linkBlank: + break; + case linkItemData: + if (m_ItemData != nullptr) { + m_LinkText = m_ItemData->Name; + return; + } + break; + case linkLootItem: + if (m_LootData != nullptr) { + const Item_Struct* item_data = database.GetItem(m_LootData->item_id); + if (item_data != nullptr) { + m_LinkText = item_data->Name; + return; + } + } + break; + case linkItemInst: + if (m_ItemInst != nullptr) { + if (m_ItemInst->GetItem() != nullptr) { + m_LinkText = m_ItemInst->GetItem()->Name; + return; + } + } + break; + default: + break; + } + + m_LinkText = "null"; +} diff --git a/zone/client.h b/zone/client.h index be503fccc..b7bb8f6a5 100644 --- a/zone/client.h +++ b/zone/client.h @@ -804,6 +804,7 @@ public: int32 GetAugmentIDAt(int16 slot_id, uint8 augslot); bool PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update = false); bool PushItemOnCursor(const ItemInst& inst, bool client_update = false); + void SendCursorBuffer(); void DeleteItemInInventory(int16 slot_id, int8 quantity = 0, bool client_update = false, bool update_db = true); bool SwapItem(MoveItem_Struct* move_in); void SwapItemResync(MoveItem_Struct* move_slots); @@ -814,8 +815,57 @@ public: void SetStats(uint8 type,int16 set_val); void IncStats(uint8 type,int16 increase_val); void DropItem(int16 slot_id); - bool MakeItemLink(char* &ret_link, const ItemInst* inst); - int GetItemLinkHash(const ItemInst* inst); + + // + // class Client::TextLink + // + class TextLink { + public: + enum LinkType { linkBlank = 0, linkItemData, linkLootItem, linkItemInst }; + + TextLink() { Reset(); } + + void SetLinkType(LinkType linkType) { m_LinkType = linkType; } + void SetItemData(const Item_Struct* itemData) { m_ItemData = itemData; } + void SetLootData(const ServerLootItem_Struct* lootData) { m_LootData = lootData; } + void SetItemInst(const ItemInst* itemInst) { m_ItemInst = itemInst; } + void SetProxyItemID(uint32 proxyItemID) { m_ProxyItemID = proxyItemID; } // mainly for saylinks..but, not limited to + void SetProxyText(const char* proxyText) { m_ProxyText = proxyText; } // overrides standard text use + void SetTaskUse() { m_TaskUse = true; } + void SetClientVersion(EQClientVersion clientVersion) { m_ClientVersion = EQLimits::ValidateClientVersion(clientVersion); } + + std::string GenerateLink(); + bool LinkError() { return m_Error; } + + const char* GetLink(); // contains full format: '/12x' '' '' '/12x' + const char* GetLinkBody(); // contains format: '' + const char* GetLinkText(); // contains format: '' + std::string GetLinkString(); + std::string GetLinkBodyString(); + std::string GetLinkTextString(); + + void Reset(); + + private: + void generate_body(); + void generate_text(); + + int m_LinkType; + const Item_Struct* m_ItemData; + const ServerLootItem_Struct* m_LootData; + const ItemInst* m_ItemInst; + uint32 m_ProxyItemID; + const char* m_ProxyText; + bool m_TaskUse; + std::string m_Link; + std::string m_LinkBody; + std::string m_LinkText; + EQClientVersion m_ClientVersion; + bool m_Error; + }; + + int GetItemLinkHash(const ItemInst* inst); // move to Item_Struct..or make use of the pre-calculated database field + void SendItemLink(const ItemInst* inst, bool sendtoall=false); void SendLootItemInPacket(const ItemInst* inst, int16 slot_id); void SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type); @@ -832,11 +882,11 @@ public: bool Hungry() const {if (GetGM()) return false; return m_pp.hunger_level <= 3000;} bool Thirsty() const {if (GetGM()) return false; return m_pp.thirst_level <= 3000;} -int32 GetHunger() const { return m_pp.hunger_level; } -int32 GetThirst() const { return m_pp.thirst_level; } -void SetHunger(int32 in_hunger); -void SetThirst(int32 in_thirst); -void SetConsumption(int32 in_hunger, int32 in_thirst); + int32 GetHunger() const { return m_pp.hunger_level; } + int32 GetThirst() const { return m_pp.thirst_level; } + void SetHunger(int32 in_hunger); + void SetThirst(int32 in_thirst); + void SetConsumption(int32 in_hunger, int32 in_thirst); bool CheckTradeLoreConflict(Client* other); void LinkDead(); @@ -937,7 +987,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst); inline bool IsTaskActive(int TaskID) { return (taskstate ? taskstate->IsTaskActive(TaskID) : false); } inline bool IsTaskActivityActive(int TaskID, int ActivityID) { return (taskstate ? taskstate->IsTaskActivityActive(TaskID, ActivityID) : false); } inline ActivityState GetTaskActivityState(int index, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityState(index, ActivityID) : ActivityHidden); } - inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count) { if(taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count); } + inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count, bool ignore_quest_update = false) { if (taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count, ignore_quest_update); } inline void ResetTaskActivity(int TaskID, int ActivityID) { if(taskstate) taskstate->ResetTaskActivity(this, TaskID, ActivityID); } inline void UpdateTasksOnKill(int NPCTypeID) { if(taskstate) taskstate->UpdateTasksOnKill(this, NPCTypeID); } inline void UpdateTasksForItem(ActivityType Type, int ItemID, int Count=1) { if(taskstate) taskstate->UpdateTasksForItem(this, Type, ItemID, Count); } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 5c07a839c..2576815b4 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1364,7 +1364,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) database.LoadCharacterFactionValues(cid, factionvalues); /* Load Character Account Data: Temp until I move */ - query = StringFormat("SELECT `status`, `name`, `lsaccount_id`, `gmspeed`, `revoked`, `hideme` FROM `account` WHERE `id` = %u", this->AccountID()); + query = StringFormat("SELECT `status`, `name`, `lsaccount_id`, `gmspeed`, `revoked`, `hideme`, `time_creation` FROM `account` WHERE `id` = %u", this->AccountID()); auto results = database.QueryDatabase(query); for (auto row = results.begin(); row != results.end(); ++row) { admin = atoi(row[0]); @@ -1373,7 +1373,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) gmspeed = atoi(row[3]); revoked = atoi(row[4]); gmhideme = atoi(row[5]); - if (account_creation){ account_creation = atoul(row[6]); } + account_creation = atoul(row[6]); } /* Load Character Data */ @@ -1388,7 +1388,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (LFP){ LFP = atoi(row[0]); } if (LFG){ LFG = atoi(row[1]); } - if (firstlogon){ firstlogon = atoi(row[3]); } + if (row[3]) + firstlogon = atoi(row[3]); } if (RuleB(Character, SharedBankPlat)) @@ -3090,7 +3091,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) // Adding augment if (in_augment->augment_action == 0) { - ItemInst *tobe_auged, *auged_with = nullptr; + ItemInst *tobe_auged = nullptr, *auged_with = nullptr; int8 slot = -1; Inventory& user_inv = GetInv(); @@ -3160,7 +3161,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) } else if (in_augment->augment_action == 1) { - ItemInst *tobe_auged, *auged_with = nullptr; + ItemInst *tobe_auged = nullptr, *auged_with = nullptr; int8 slot = -1; Inventory& user_inv = GetInv(); @@ -5258,7 +5259,7 @@ void Client::Handle_OP_DeleteSpawn(const EQApplicationPacket *app) entity_list.QueueClients(this, outapp, false); safe_delete(outapp); - hate_list.RemoveEnt(this->CastToMob()); + hate_list.RemoveEntFromHateList(this->CastToMob()); Disconnect(); return; @@ -7009,37 +7010,28 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) if (!CursorItem->NoDrop || CursorItemInst->IsAttuned()) { - Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT); - Allowed = false; } else if (CursorItemInst->IsNoneEmptyContainer()) { - Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT); - Allowed = false; } else if (CursorItemInst->IsAugmented()) { - Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT); - Allowed = false; } else if (CursorItem->NoRent == 0) { - Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT); - Allowed = false; } else if (CursorItem->LoreFlag && GuildBanks->HasItem(GuildID(), CursorItem->ID)) { - Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT); - Allowed = false; } if (!Allowed) { + Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT); GuildBankDepositAck(true); return; @@ -9210,12 +9202,6 @@ void Client::Handle_OP_LootItem(const EQApplicationPacket *app) LogFile->write(EQEMuLog::Error, "Wrong size: OP_LootItem, size=%i, expected %i", app->size, sizeof(LootingItem_Struct)); return; } - /* - ** fixed the looting code so that it sends the correct opcodes - ** and now correctly removes the looted item the player selected - ** as well as gives the player the proper item. - ** Also fixed a few UI lock ups that would occur. - */ EQApplicationPacket* outapp = 0; Entity* entity = entity_list.GetID(*((uint16*)app->pBuffer)); @@ -9802,7 +9788,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) } } - // Illegal bagslot useage checks. Currently, user only receives a message if this check is triggered. + // Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered. bool mi_hack = false; if (mi->from_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->from_slot <= EmuConstants::CURSOR_BAG_END) { @@ -9825,7 +9811,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) } } - if (mi_hack) { Message(15, "Caution: Illegal use of inaccessable bag slots!"); } + if (mi_hack) { Message(15, "Caution: Illegal use of inaccessible bag slots!"); } if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) { SwapItemResync(mi); @@ -12361,22 +12347,30 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app) int freeslot = 0; if (charges > 0 && (freeslot = zone->SaveTempItem(vendor->CastToNPC()->MerchantType, vendor->GetNPCTypeID(), itemid, charges, true)) > 0){ ItemInst* inst2 = inst->Clone(); - if (RuleB(Merchant, UsePriceMod)){ - inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(vendor, false)); + + while (true) { + if (inst2 == nullptr) + break; + + if (RuleB(Merchant, UsePriceMod)){ + inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(vendor, false)); + } + else + inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate); + inst2->SetMerchantSlot(freeslot); + + uint32 MerchantQuantity = zone->GetTempMerchantQuantity(vendor->GetNPCTypeID(), freeslot); + + if (inst2->IsStackable()) { + inst2->SetCharges(MerchantQuantity); + } + inst2->SetMerchantCount(MerchantQuantity); + + SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant); + safe_delete(inst2); + + break; } - else - inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate); - inst2->SetMerchantSlot(freeslot); - - uint32 MerchantQuantity = zone->GetTempMerchantQuantity(vendor->GetNPCTypeID(), freeslot); - - if (inst2->IsStackable()) { - inst2->SetCharges(MerchantQuantity); - } - inst2->SetMerchantCount(MerchantQuantity); - - SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant); - safe_delete(inst2); } // start QS code diff --git a/zone/command.cpp b/zone/command.cpp index d5d781e02..d31ea97b7 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -247,7 +247,7 @@ int command_init(void) { command_add("reloadstatic","- Reload Static Zone Data",150,command_reloadstatic) || command_add("reloadquest"," - Clear quest cache (any argument causes it to also stop all timers)",150,command_reloadqst) || command_add("reloadqst"," - Clear quest cache (any argument causes it to also stop all timers)",150,command_reloadqst) || - command_add("reloadworld",nullptr,255,command_reloadworld) || + command_add("reloadworld","[0|1] - Clear quest cache (0 - no repop, 1 - repop)",255,command_reloadworld) || command_add("reloadlevelmods",nullptr,255,command_reloadlevelmods) || command_add("reloadzonepoints","- Reload zone points from database",150,command_reloadzps) || command_add("reloadzps",nullptr,0,command_reloadzps) || @@ -2280,7 +2280,7 @@ void command_castspell(Client *c, const Seperator *sep) void command_setlanguage(Client *c, const Seperator *sep) { - if ( strcasecmp( sep->arg[1], "list" ) == 0 ) + if (strcasecmp(sep->arg[1], "list" ) == 0 ) { c->Message(0, "Languages:"); c->Message(0, "(0) Common Tongue"); @@ -2615,117 +2615,93 @@ void command_peekinv(Client *c, const Seperator *sep) } Client* targetClient = c->GetTarget()->CastToClient(); - const ItemInst* instMain = nullptr; - const ItemInst* instSub = nullptr; - const Item_Struct* itemData = nullptr; - char* itemLinkCore = nullptr; - std::string itemLink; + const ItemInst* inst_main = nullptr; + const ItemInst* inst_sub = nullptr; + const Item_Struct* item_data = nullptr; + std::string item_link; + Client::TextLink linker; + linker.SetLinkType(linker.linkItemInst); + linker.SetClientVersion(c->GetClientVersion()); c->Message(0, "Displaying inventory for %s...", targetClient->GetName()); // worn for (int16 indexMain = EmuConstants::EQUIPMENT_BEGIN; (scopeWhere & peekWorn) && (indexMain <= EmuConstants::EQUIPMENT_END); ++indexMain) { - instMain = targetClient->GetInv().GetItem(indexMain); - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; + inst_main = targetClient->GetInv().GetItem(indexMain); + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); + item_link = linker.GenerateLink(); - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), "WornSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); - - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i", + indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); } if ((scopeWhere & peekWorn) && (targetClient->GetClientVersion() >= EQClientSoF)) { - instMain = targetClient->GetInv().GetItem(MainPowerSource); - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; - - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null"); + inst_main = targetClient->GetInv().GetItem(MainPowerSource); + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - c->Message((itemData == 0), "WornSlot: %i, Item: %i (%s), Charges: %i", - MainPowerSource, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i", + MainPowerSource, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); } // inv for (int16 indexMain = EmuConstants::GENERAL_BEGIN; (scopeWhere & peekInv) && (indexMain <= EmuConstants::GENERAL_END); ++indexMain) { - instMain = targetClient->GetInv().GetItem(indexMain); - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; + inst_main = targetClient->GetInv().GetItem(indexMain); + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), "InvSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), "InvSlot: %i, Item: %i (%s), Charges: %i", + indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - for (uint8 indexSub = SUB_BEGIN; instMain && instMain->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { - instSub = instMain->GetItem(indexSub); - itemData = (instSub ? instSub->GetItem() : nullptr); - itemLinkCore = nullptr; + for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + inst_sub = inst_main->GetItem(indexSub); + item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); + linker.SetItemInst(inst_sub); - if (itemData) - c->MakeItemLink(itemLinkCore, instSub); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instSub->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), " InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instSub->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), " InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", + Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } // cursor if (scopeWhere & peekCursor) { if (targetClient->GetInv().CursorEmpty()) { + linker.SetItemInst(nullptr); + + item_link = linker.GenerateLink(); + c->Message(1, "CursorSlot: %i, Item: %i (%s), Charges: %i", - MainCursor, 0, "null", 0); + MainCursor, 0, item_link.c_str(), 0); } else { int cursorDepth = 0; for (iter_queue it = targetClient->GetInv().cursor_begin(); (it != targetClient->GetInv().cursor_end()); ++it, ++cursorDepth) { - instMain = *it; - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; + inst_main = *it; + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), "CursorSlot: %i, Depth: %i, Item: %i (%s), Charges: %i", - MainCursor, cursorDepth, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), "CursorSlot: %i, Depth: %i, Item: %i (%s), Charges: %i", + MainCursor, cursorDepth, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - for (uint8 indexSub = SUB_BEGIN; (cursorDepth == 0) && instMain && instMain->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { - instSub = instMain->GetItem(indexSub); - itemData = (instSub ? instSub->GetItem() : nullptr); - itemLinkCore = nullptr; + for (uint8 indexSub = SUB_BEGIN; (cursorDepth == 0) && inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + inst_sub = inst_main->GetItem(indexSub); + item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); + linker.SetItemInst(inst_sub); - if (itemData) - c->MakeItemLink(itemLinkCore, instSub); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instSub->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), " CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - Inventory::CalcSlotId(MainCursor, indexSub), MainCursor, indexSub, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instSub->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), " CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", + Inventory::CalcSlotId(MainCursor, indexSub), MainCursor, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } } @@ -2733,116 +2709,81 @@ void command_peekinv(Client *c, const Seperator *sep) // trib for (int16 indexMain = EmuConstants::TRIBUTE_BEGIN; (scopeWhere & peekTrib) && (indexMain <= EmuConstants::TRIBUTE_END); ++indexMain) { - instMain = targetClient->GetInv().GetItem(indexMain); - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; + inst_main = targetClient->GetInv().GetItem(indexMain); + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), "TributeSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), "TributeSlot: %i, Item: %i (%s), Charges: %i", + indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); } // bank for (int16 indexMain = EmuConstants::BANK_BEGIN; (scopeWhere & peekBank) && (indexMain <= EmuConstants::BANK_END); ++indexMain) { - instMain = targetClient->GetInv().GetItem(indexMain); - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; + inst_main = targetClient->GetInv().GetItem(indexMain); + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null" ); - - c->Message((itemData == 0), "BankSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), "BankSlot: %i, Item: %i (%s), Charges: %i", + indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - for (uint8 indexSub = SUB_BEGIN; instMain && instMain->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { - instSub = instMain->GetItem(indexSub); - itemData = (instSub ? instSub->GetItem() : nullptr); - itemLinkCore = nullptr; + for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + inst_sub = inst_main->GetItem(indexSub); + item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); + linker.SetItemInst(inst_sub); - if (itemData) - c->MakeItemLink(itemLinkCore, instSub); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instSub->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), " BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instSub->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), " BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", + Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } for (int16 indexMain = EmuConstants::SHARED_BANK_BEGIN; (scopeWhere & peekBank) && (indexMain <= EmuConstants::SHARED_BANK_END); ++indexMain) { - instMain = targetClient->GetInv().GetItem(indexMain); - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; + inst_main = targetClient->GetInv().GetItem(indexMain); + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); + item_link = linker.GenerateLink(); - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), "SharedBankSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); + c->Message((item_data == nullptr), "SharedBankSlot: %i, Item: %i (%s), Charges: %i", + indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - safe_delete_array(itemLinkCore); + for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + inst_sub = inst_main->GetItem(indexSub); + item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); + linker.SetItemInst(inst_sub); - for (uint8 indexSub = SUB_BEGIN; instMain && instMain->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { - instSub = instMain->GetItem(indexSub); - itemData = (instSub ? instSub->GetItem() : nullptr); - itemLinkCore = nullptr; + item_link = linker.GenerateLink(); - if (itemData) - c->MakeItemLink(itemLinkCore, instSub); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instSub->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), " SharedBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instSub->GetCharges())); - - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), " SharedBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", + Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } // trade for (int16 indexMain = EmuConstants::TRADE_BEGIN; (scopeWhere & peekTrade) && (indexMain <= EmuConstants::TRADE_END); ++indexMain) { - instMain = targetClient->GetInv().GetItem(indexMain); - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; + inst_main = targetClient->GetInv().GetItem(indexMain); + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), "TradeSlot: %i, Item: %i (%s), Charges: %i", - indexMain, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), "TradeSlot: %i, Item: %i (%s), Charges: %i", + indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - for (uint8 indexSub = SUB_BEGIN; instMain && instMain->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { - instSub = instMain->GetItem(indexSub); - itemData = (instSub ? instSub->GetItem() : nullptr); - itemLinkCore = nullptr; + for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + inst_sub = inst_main->GetItem(indexSub); + item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); + linker.SetItemInst(inst_sub); - if (itemData) - c->MakeItemLink(itemLinkCore, instSub); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instSub->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), " TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instSub->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), " TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", + Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } @@ -2857,34 +2798,24 @@ void command_peekinv(Client *c, const Seperator *sep) c->Message(0, "[WorldObject DBID: %i (entityid: %i)]", objectTradeskill->GetDBID(), objectTradeskill->GetID()); for (int16 indexMain = MAIN_BEGIN; indexMain < EmuConstants::MAP_WORLD_SIZE; ++indexMain) { - instMain = objectTradeskill->GetItem(indexMain); - itemData = (instMain ? instMain->GetItem() : nullptr); - itemLinkCore = nullptr; + inst_main = objectTradeskill->GetItem(indexMain); + item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); + linker.SetItemInst(inst_main); - if (itemData) - c->MakeItemLink(itemLinkCore, instMain); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instMain->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), "WorldSlot: %i, Item: %i (%s), Charges: %i", - (EmuConstants::WORLD_BEGIN + indexMain), ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instMain->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), "WorldSlot: %i, Item: %i (%s), Charges: %i", + (EmuConstants::WORLD_BEGIN + indexMain), ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - for (uint8 indexSub = SUB_BEGIN; instMain && instMain->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { - instSub = instMain->GetItem(indexSub); - itemData = (instSub ? instSub->GetItem() : nullptr); - itemLinkCore = nullptr; + for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + inst_sub = inst_main->GetItem(indexSub); + item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem(); + linker.SetItemInst(inst_sub); - if (itemData) - c->MakeItemLink(itemLinkCore, instSub); - - itemLink = (itemLinkCore ? StringFormat("%c%s%s%c", 0x12, itemLinkCore, instSub->GetItem()->Name, 0x12) : "null"); - - c->Message((itemData == 0), " WorldBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - INVALID_INDEX, indexMain, indexSub, ((itemData == 0) ? 0 : itemData->ID), itemLink.c_str(), ((itemData == 0) ? 0 : instSub->GetCharges())); + item_link = linker.GenerateLink(); - safe_delete_array(itemLinkCore); + c->Message((item_data == nullptr), " WorldBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", + INVALID_INDEX, indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } } @@ -3096,15 +3027,12 @@ void command_reloadqst(Client *c, const Seperator *sep) void command_reloadworld(Client *c, const Seperator *sep) { - if (sep->arg[1][0] == 0) - { - c->Message(0, "Reloading quest cache and repopping zones worldwide."); - ServerPacket* pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); - ReloadWorld_Struct* RW = (ReloadWorld_Struct*) pack->pBuffer; - RW->Option = 1; - worldserver.SendPacket(pack); - safe_delete(pack); - } + c->Message(0, "Reloading quest cache and repopping zones worldwide."); + ServerPacket* pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); + ReloadWorld_Struct* RW = (ReloadWorld_Struct*) pack->pBuffer; + RW->Option = ((atoi(sep->arg[1]) == 1) ? 1 : 0); + worldserver.SendPacket(pack); + safe_delete(pack); } void command_reloadlevelmods(Client *c, const Seperator *sep) @@ -5635,75 +5563,64 @@ void command_givemoney(Client *c, const Seperator *sep) void command_itemsearch(Client *c, const Seperator *sep) { - if (sep->arg[1][0] == 0) + if (sep->arg[1][0] == 0) { c->Message(0, "Usage: #itemsearch [search string]"); + } else { const char *search_criteria=sep->argplus[1]; - const Item_Struct* item = 0; + const Item_Struct* item = nullptr; + std::string item_link; + Client::TextLink linker; + linker.SetLinkType(linker.linkItemData); + linker.SetClientVersion(c->GetClientVersion()); + if (Seperator::IsNumber(search_criteria)) { item = database.GetItem(atoi(search_criteria)); - if (item) - if (c->GetClientVersion() >= EQClientRoF2) - { - c->Message(0, " %i: %c%06X00000000000000000000000000000000000000000000000000%s%c", (int)item->ID, 0x12, item->ID, item->Name, 0x12); - } - else if (c->GetClientVersion() >= EQClientRoF) - { - c->Message(0, " %i: %c%06X0000000000000000000000000000000000000000000000000%s%c",(int) item->ID,0x12, item->ID, item->Name, 0x12); - } - else if (c->GetClientVersion() >= EQClientSoF) - { - c->Message(0, " %i: %c%06X00000000000000000000000000000000000000000000%s%c",(int) item->ID,0x12, item->ID, item->Name, 0x12); - } - else - { - c->Message(0, " %i: %c%06X000000000000000000000000000000000000000%s%c",(int) item->ID,0x12, item->ID, item->Name, 0x12); - } - else + if (item) { + linker.SetItemData(item); + + item_link = linker.GenerateLink(); + + c->Message(0, "%u: %s", item->ID, item_link.c_str()); + } + else { c->Message(0, "Item #%s not found", search_criteria); + } + return; } - int count = 0; + int count = NOT_USED; char sName[64]; char sCriteria[255]; strn0cpy(sCriteria, search_criteria, sizeof(sCriteria)); strupr(sCriteria); char* pdest; - uint32 it = 0; + uint32 it = NOT_USED; while ((item = database.IterateItems(&it))) { strn0cpy(sName, item->Name, sizeof(sName)); strupr(sName); pdest = strstr(sName, sCriteria); if (pdest != nullptr) { - if (c->GetClientVersion() >= EQClientRoF2) - { - c->Message(0, " %i: %c%06X00000000000000000000000000000000000000000000000000%s%c", (int)item->ID, 0x12, item->ID, item->Name, 0x12); - } - else if (c->GetClientVersion() >= EQClientRoF) - { - c->Message(0, " %i: %c%06X0000000000000000000000000000000000000000000000000%s%c",(int) item->ID,0x12, item->ID, item->Name, 0x12); - } - else if (c->GetClientVersion() >= EQClientSoF) - { - c->Message(0, " %i: %c%06X00000000000000000000000000000000000000000000%s%c",(int) item->ID,0x12, item->ID, item->Name, 0x12); - } - else - { - c->Message(0, " %i: %c%06X000000000000000000000000000000000000000%s%c",(int) item->ID,0x12, item->ID, item->Name, 0x12); - } - count++; + linker.SetItemData(item); + + item_link = linker.GenerateLink(); + + c->Message(0, "%u: %s", item->ID, item_link.c_str()); + + ++count; } + if (count == 50) break; } + if (count == 50) c->Message(0, "50 items shown...too many results."); else c->Message(0, "%i items found", count); - } } @@ -6093,7 +6010,7 @@ void command_npcedit(Client *c, const Seperator *sep) return; } - if ( strcasecmp( sep->arg[1], "help" ) == 0 ) { + if (strcasecmp(sep->arg[1], "help") == 0) { c->Message(0, "Help File for #npcedit. Syntax for commands are:"); c->Message(0, "#npcedit Name - Sets an NPC's name"); @@ -6106,7 +6023,13 @@ void command_npcedit(Client *c, const Seperator *sep) c->Message(0, "#npcedit HP - Sets an NPC's hitpoints"); c->Message(0, "#npcedit Gender - Sets an NPC's gender"); c->Message(0, "#npcedit Texture - Sets an NPC's texture"); - c->Message(0, "#npcedit Helmtexture - Sets an NPC's helmtexture"); + c->Message(0, "#npcedit Helmtexture - Sets an NPC's helmet texture"); + c->Message(0, "#npcedit Armtexture - Sets an NPC's arm texture"); + c->Message(0, "#npcedit Bracertexture - Sets an NPC's bracer texture"); + c->Message(0, "#npcedit Handtexture - Sets an NPC's hand texture"); + c->Message(0, "#npcedit Legtexture - Sets an NPC's leg texture"); + c->Message(0, "#npcedit Feettexture - Sets an NPC's feettexture"); + c->Message(0, "#npcedit Herosforgemodel - Sets an NPC's Hero's Forge Model"); c->Message(0, "#npcedit Size - Sets an NPC's size"); c->Message(0, "#npcedit Hpregen - Sets an NPC's hitpoint regen rate per tick"); c->Message(0, "#npcedit Manaregen - Sets an NPC's mana regen rate per tick"); @@ -6119,12 +6042,15 @@ void command_npcedit(Client *c, const Seperator *sep) c->Message(0, "#npcedit special_abilities - Sets the NPC's Special Abilities"); c->Message(0, "#npcedit Spell - Sets the npc spells list ID for an NPC"); c->Message(0, "#npcedit Faction - Sets the NPC's faction id"); - c->Message(0, "#npcedit Mindmg - Sets an NPC's minimum damage"); - c->Message(0, "#npcedit Maxdmg - Sets an NPC's maximum damage"); + c->Message(0, "#npcedit Damage - Sets an NPC's damage"); + c->Message(0, "#npcedit Meleetype - Sets an NPC's melee types"); + c->Message(0, "#npcedit Rangedtype - Sets an NPC's ranged type"); + c->Message(0, "#npcedit Ammoidfile - Sets an NPC's ammo id file"); c->Message(0, "#npcedit Aggroradius - Sets an NPC's aggro radius"); c->Message(0, "#npcedit Assistradius - Sets an NPC's assist radius"); c->Message(0, "#npcedit Social - Set to 1 if an NPC should assist others on its faction"); c->Message(0, "#npcedit Runspeed - Sets an NPC's run speed"); + c->Message(0, "#npcedit Walkspeed - Sets an NPC's walk speed"); c->Message(0, "#npcedit AGI - Sets an NPC's Agility"); c->Message(0, "#npcedit CHA - Sets an NPC's Charisma"); c->Message(0, "#npcedit DEX - Sets an NPC's Dexterity"); @@ -6136,7 +6062,7 @@ void command_npcedit(Client *c, const Seperator *sep) c->Message(0, "#npcedit PR - Sets an NPC's Poison Resistance"); c->Message(0, "#npcedit DR - Sets an NPC's Disease Resistance"); c->Message(0, "#npcedit FR - Sets an NPC's Fire Resistance"); - c->Message(0, "#npcedit CR - Sets an NPC's cold resistance"); + c->Message(0, "#npcedit CR - Sets an NPC's Cold Resistance"); c->Message(0, "#npcedit Corrup - Sets an NPC's Corruption Resistance"); c->Message(0, "#npcedit PhR - Sets and NPC's Physical Resistance"); c->Message(0, "#npcedit Seeinvis - Sets an NPC's ability to see invis"); @@ -6146,14 +6072,16 @@ void command_npcedit(Client *c, const Seperator *sep) c->Message(0, "#npcedit AC - Sets an NPC's Armor Class"); c->Message(0, "#npcedit ATK - Sets an NPC's Attack"); c->Message(0, "#npcedit Accuracy - Sets an NPC's Accuracy"); + c->Message(0, "#npcedit Avoidance - Sets an NPC's Avoidance"); c->Message(0, "#npcedit npcaggro - Sets an NPC's npc_aggro flag"); c->Message(0, "#npcedit qglobal - Sets an NPC's quest global flag"); - c->Message(0, "#npcedit limit - Sets an NPC's spawn limit counter"); + c->Message(0, "#npcedit spawn_limit - Sets an NPC's spawn limit counter"); c->Message(0, "#npcedit Attackspeed - Sets an NPC's attack speed modifier"); c->Message(0, "#npcedit Attackdelay - Sets an NPC's attack delay"); + c->Message(0, "#npcedit Attackcount - Sets an NPC's attack count"); c->Message(0, "#npcedit findable - Sets an NPC's findable flag"); - c->Message(0, "#npcedit wep1 - Sets an NPC's primary weapon model"); - c->Message(0, "#npcedit wep2 - Sets an NPC's secondary weapon model"); + c->Message(0, "#npcedit trackable - Sets an NPC's trackable flag"); + c->Message(0, "#npcedit weapon - Sets an NPC's primary and secondary weapon model"); c->Message(0, "#npcedit featuresave - Saves all current facial features to the database"); c->Message(0, "#npcedit color - Sets an NPC's red, green, and blue armor tint"); c->Message(0, "#npcedit armortint_id - Set an NPC's Armor tint ID"); @@ -6163,602 +6091,566 @@ void command_npcedit(Client *c, const Seperator *sep) c->Message(0, "#npcedit spellscale - Set an NPC's spell scaling rate"); c->Message(0, "#npcedit no_target - Set an NPC's ability to be targeted with the target hotkey"); c->Message(0, "#npcedit version - Set an NPC's version"); + c->Message(0, "#npcedit slow_mitigation - Set an NPC's slow mitigation"); } uint32 npcTypeID = c->GetTarget()->CastToNPC()->GetNPCTypeID(); - - if ( strcasecmp( sep->arg[1], "name" ) == 0 ) { + if (strcasecmp(sep->arg[1], "name") == 0) { c->Message(15,"NPCID %u now has the name %s.",npcTypeID, sep->argplus[2]); - - std::string query = StringFormat("UPDATE npc_types SET name = '%s' WHERE id = %i", - sep->argplus[2],npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET name = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "lastname" ) == 0 ) { + if (strcasecmp(sep->arg[1], "lastname") == 0) { c->Message(15,"NPCID %u now has the lastname %s.",npcTypeID, sep->argplus[2]); - - std::string query = StringFormat("UPDATE npc_types SET lastname = '%s' WHERE id = %i", - sep->argplus[2],npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET lastname = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "race" ) == 0 ) { + if (strcasecmp(sep->arg[1], "race") == 0) { c->Message(15,"NPCID %u now has the race %i.",npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET race = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET race = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "class" ) == 0 ) { + if (strcasecmp(sep->arg[1], "class") == 0) { c->Message(15,"NPCID %u is now class %i.",npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET class = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET class = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "bodytype" ) == 0 ) { + if (strcasecmp(sep->arg[1], "bodytype") == 0) { c->Message(15,"NPCID %u now has type %i bodytype.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET bodytype = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET bodytype = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "hp" ) == 0 ) { + if (strcasecmp(sep->arg[1], "hp") == 0) { c->Message(15,"NPCID %u now has %i Hitpoints.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET hp = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET hp = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "gender" ) == 0 ) { + if (strcasecmp(sep->arg[1], "gender") == 0) { c->Message(15,"NPCID %u is now gender %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET gender = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET gender = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "texture" ) == 0 ) { + if (strcasecmp(sep->arg[1], "texture") == 0) { c->Message(15,"NPCID %u now uses texture %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET texture = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET texture = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "helmtexture" ) == 0 ) { + if (strcasecmp(sep->arg[1], "helmtexture") == 0) { c->Message(15,"NPCID %u now uses helmtexture %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET helmtexture = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET helmtexture = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "size" ) == 0 ) { + if (strcasecmp(sep->arg[1], "armtexture") == 0) { + c->Message(15,"NPCID %u now uses armtexture %i.", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET armtexture = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "bracertexture") == 0) { + c->Message(15,"NPCID %u now uses bracertexture %i.", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET bracertexture = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "handtexture") == 0) { + c->Message(15,"NPCID %u now uses handtexture %i.", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET handtexture = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "legtexture") == 0) { + c->Message(15,"NPCID %u now uses legtexture %i.", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET legtexture = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "feettexture") == 0) { + c->Message(15,"NPCID %u now uses feettexture %i.", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET feettexture = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "herosforgemodel") == 0) { + c->Message(15,"NPCID %u now uses herosforgemodel %i.", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET herosforgemodel = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "size") == 0) { c->Message(15,"NPCID %u is now size %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET size = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET size = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "hpregen" ) == 0 ) { + if (strcasecmp(sep->arg[1], "hpregen") == 0) { c->Message(15,"NPCID %u now regens %i hitpoints per tick.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET hp_regen_rate = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET hp_regen_rate = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "manaregen" ) == 0 ) { + if (strcasecmp(sep->arg[1], "manaregen") == 0) { c->Message(15,"NPCID %u now regens %i mana per tick.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET mana_regen_rate = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET mana_regen_rate = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "loottable" ) == 0 ) { + if (strcasecmp(sep->arg[1], "loottable") == 0) { c->Message(15,"NPCID %u is now on loottable_id %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET loottable_id = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET loottable_id = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "merchantid" ) == 0 ) { + if (strcasecmp(sep->arg[1], "merchantid") == 0) { c->Message(15,"NPCID %u is now merchant_id %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET merchant_id = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET merchant_id = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "alt_currency_id" ) == 0 ) { + if (strcasecmp(sep->arg[1], "alt_currency_id") == 0) { c->Message(15,"NPCID %u now has field 'alt_currency_id' set to %s.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET alt_currency_id = '%s' WHERE id = %i", - sep->argplus[2],npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET alt_currency_id = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "npc_spells_effects_id" ) == 0 ) { + if (strcasecmp(sep->arg[1], "npc_spells_effects_id") == 0) { c->Message(15,"NPCID %u now has field 'npc_spells_effects_id' set to %s.", npcTypeID, sep->argplus[2]); - - std::string query = StringFormat("UPDATE npc_types SET npc_spells_effects_id = '%s' WHERE id = %i", - sep->argplus[2],npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET npc_spells_effects_id = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "adventure_template_id" ) == 0 ) { + if (strcasecmp(sep->arg[1], "adventure_template_id") == 0) { c->Message(15,"NPCID %u now has field 'adventure_template_id' set to %s.", npcTypeID, sep->argplus[2]); - - std::string query = StringFormat("UPDATE npc_types SET adventure_template_id = '%s' WHERE id = %i", - sep->argplus[2],npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET adventure_template_id = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "trap_template" ) == 0 ) { + if (strcasecmp(sep->arg[1], "trap_template") == 0) { c->Message(15,"NPCID %u now has field 'trap_template' set to %s.", npcTypeID, sep->argplus[2]); - - std::string query = StringFormat("UPDATE npc_types SET trap_template = '%s' WHERE id = %i", - sep->argplus[2],npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET trap_template = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "special_abilities" ) == 0 ) { + if (strcasecmp(sep->arg[1], "special_abilities") == 0) { c->Message(15,"NPCID %u now has field 'special_abilities' set to %s.", npcTypeID, sep->argplus[2]); - - std::string query = StringFormat("UPDATE npc_types SET special_abilities = '%s' WHERE id = %i", - sep->argplus[2],npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET special_abilities = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "spell" ) == 0 ) { + if (strcasecmp(sep->arg[1], "spell") == 0) { c->Message(15,"NPCID %u now uses spell list %i", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET npc_spells_id = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET npc_spells_id = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "faction" ) == 0 ) { + if (strcasecmp(sep->arg[1], "faction") == 0) { c->Message(15,"NPCID %u is now faction %i", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET npc_faction_id = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET npc_faction_id = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "mindmg" ) == 0 ) { - c->Message(15,"NPCID %u now hits for a min of %i", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET mindmg = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); + if (strcasecmp(sep->arg[1], "damage") == 0) { + c->Message(15,"NPCID %u now hits from %i to %i", npcTypeID, atoi(sep->arg[2]), atoi(sep->arg[3])); + std::string query = StringFormat("UPDATE npc_types SET mindmg = %i, maxdmg = %i WHERE id = %i", atoi(sep->arg[2]), atoi(sep->arg[3]), npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "meleetype") == 0) { + c->Message(15,"NPCID %u now has a primary melee type of %i and a secondary melee type of %i.", npcTypeID, atoi(sep->arg[2]), atoi(sep->arg[3])); + std::string query = StringFormat("UPDATE npc_types SET prim_melee_type = %i, sec_melee_type = %i WHERE id = %i", atoi(sep->arg[2]), atoi(sep->arg[3]), npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "rangedtype") == 0) { + c->Message(15,"NPCID %u now has a ranged type of %i.", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET rangedtype = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "ammoidfile") == 0) { + c->Message(15,"NPCID %u's ammo id file is now %i", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET ammoidfile = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "maxdmg" ) == 0 ) { - c->Message(15,"NPCID %u now hits for a max of %i", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET maxdmg = %i WHERE id = %i", - atoi(sep->argplus[2]),npcTypeID); - database.QueryDatabase(query); - c->LogSQL(query.c_str()); - return; - } - - if ( strcasecmp( sep->arg[1], "aggroradius" ) == 0 ) { + if (strcasecmp(sep->arg[1], "aggroradius") == 0) { c->Message(15,"NPCID %u now has an aggro radius of %i", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET aggroradius = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET aggroradius = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "assistradius" ) == 0 ) { + if (strcasecmp(sep->arg[1], "assistradius") == 0) { c->Message(15,"NPCID %u now has an assist radius of %i", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET assistradius = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET assistradius = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "social" ) == 0 ) { + if (strcasecmp(sep->arg[1], "social") == 0) { c->Message(15,"NPCID %u social status is now %i", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET social = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET social = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "runspeed" ) == 0 ) { + if (strcasecmp(sep->arg[1], "runspeed") == 0) { c->Message(15,"NPCID %u now runs at %f", npcTypeID, atof(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET runspeed = %f WHERE id = %i", - atof(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET runspeed = %f WHERE id = %i", atof(sep->argplus[2]), npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "walkspeed") == 0) { + c->Message(15,"NPCID %u now walks at %f", npcTypeID, atof(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET walkspeed = %f WHERE id = %i", atof(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "AGI" ) == 0 ) { + if (strcasecmp(sep->arg[1], "AGI") == 0) { c->Message(15,"NPCID %u now has %i Agility.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET AGI = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET AGI = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "CHA" ) == 0 ) { + if (strcasecmp(sep->arg[1], "CHA") == 0) { c->Message(15,"NPCID %u now has %i Charisma.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET CHA = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET CHA = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "DEX" ) == 0 ) { + if (strcasecmp(sep->arg[1], "DEX") == 0) { c->Message(15,"NPCID %u now has %i Dexterity.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET DEX = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET DEX = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "INT" ) == 0 ) { + if (strcasecmp(sep->arg[1], "INT") == 0) { c->Message(15,"NPCID %u now has %i Intelligence.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET _INT = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET _INT = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "STA" ) == 0 ) { + if (strcasecmp(sep->arg[1], "STA") == 0) { c->Message(15,"NPCID %u now has %i Stamina.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET STA = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET STA = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "STR" ) == 0 ) { + if (strcasecmp(sep->arg[1], "STR") == 0) { c->Message(15,"NPCID %u now has %i Strength.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET STR = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET STR = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "WIS" ) == 0 ) { + if (strcasecmp(sep->arg[1], "WIS") == 0) { c->Message(15,"NPCID %u now has a Magic Resistance of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET WIS = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET WIS = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "MR" ) == 0 ) { + if (strcasecmp(sep->arg[1], "MR") == 0) { c->Message(15,"NPCID %u now has a Magic Resistance of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET MR = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET MR = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "DR" ) == 0 ) { + if (strcasecmp(sep->arg[1], "DR") == 0) { c->Message(15,"NPCID %u now has a Disease Resistance of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET DR = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET DR = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "CR" ) == 0 ) { + if (strcasecmp(sep->arg[1], "CR") == 0) { c->Message(15,"NPCID %u now has a Cold Resistance of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET CR = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET CR = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "FR" ) == 0 ) { + if (strcasecmp(sep->arg[1], "FR") == 0) { c->Message(15,"NPCID %u now has a Fire Resistance of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET FR = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET FR = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "PR" ) == 0 ) { + if (strcasecmp(sep->arg[1], "PR") == 0) { c->Message(15,"NPCID %u now has a Poison Resistance of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET PR = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET PR = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "Corrup" ) == 0 ) { + if (strcasecmp(sep->arg[1], "Corrup") == 0) { c->Message(15,"NPCID %u now has a Corruption Resistance of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET corrup = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET corrup = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "PhR" ) == 0 ) { + if (strcasecmp(sep->arg[1], "PhR") == 0) { c->Message(15,"NPCID %u now has a Physical Resistance of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET PhR = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET PhR = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "seeinvis" ) == 0 ) { + if (strcasecmp(sep->arg[1], "seeinvis") == 0) { c->Message(15,"NPCID %u now has seeinvis set to %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET see_invis = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET see_invis = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "seeinvisundead" ) == 0 ) { + if (strcasecmp(sep->arg[1], "seeinvisundead") == 0) { c->Message(15,"NPCID %u now has seeinvisundead set to %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET see_invis_undead = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET see_invis_undead = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "seehide" ) == 0 ) { + if (strcasecmp(sep->arg[1], "seehide") == 0) { c->Message(15,"NPCID %u now has seehide set to %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET see_hide = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET see_hide = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "seeimprovedhide" ) == 0 ) { + if (strcasecmp(sep->arg[1], "seeimprovedhide") == 0) { c->Message(15,"NPCID %u now has seeimprovedhide set to %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET see_improved_hide = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET see_improved_hide = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "AC" ) == 0 ) { + if (strcasecmp(sep->arg[1], "AC") == 0) { c->Message(15,"NPCID %u now has %i Armor Class.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET ac = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET ac = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "ATK" ) == 0 ) { + if (strcasecmp(sep->arg[1], "ATK") == 0) { c->Message(15,"NPCID %u now has %i Attack.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET atk = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET atk = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "Accuracy" ) == 0 ) { + if (strcasecmp(sep->arg[1], "Accuracy") == 0) { c->Message(15,"NPCID %u now has %i Accuracy.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET accuracy = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET accuracy = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "Avoidance") == 0) { + c->Message(15,"NPCID %u now has %i Avoidance.", npcTypeID, atoi(sep->argplus[2])); + std::string query = StringFormat("UPDATE npc_types SET avoidance = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "level" ) == 0 ) { + if (strcasecmp(sep->arg[1], "level") == 0) { c->Message(15,"NPCID %u is now level %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET level = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET level = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "maxlevel" ) == 0 ) { + if (strcasecmp(sep->arg[1], "maxlevel") == 0) { c->Message(15,"NPCID %u now has a maximum level of %i.", npcTypeID, atoi(sep->argplus[2])); - - std::string query = StringFormat("UPDATE npc_types SET maxlevel = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET maxlevel = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "qglobal" ) == 0 ) { - c->Message(15,"Quest globals have been %s for NPCID %u", - atoi(sep->arg[2]) == 0 ? "disabled" : "enabled", npcTypeID); - - std::string query = StringFormat("UPDATE npc_types SET qglobal = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "qglobal") == 0) { + c->Message(15,"Quest globals have been %s for NPCID %u", atoi(sep->arg[2]) == 0 ? "disabled" : "enabled", npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET qglobal = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "npcaggro" ) == 0 ) { - c->Message(15,"NPCID %u will now %s other NPCs with negative faction npc_value", - npcTypeID, atoi(sep->arg[2]) == 0? "not aggro": "aggro"); - - std::string query = StringFormat("UPDATE npc_types SET npc_aggro = %i WHERE id = %i", - atoi(sep->argplus[2]) == 0? 0: 1, npcTypeID); + if (strcasecmp(sep->arg[1], "npcaggro") == 0) { + c->Message(15,"NPCID %u will now %s other NPCs with negative faction npc_value", npcTypeID, atoi(sep->arg[2]) == 0? "not aggro": "aggro"); + std::string query = StringFormat("UPDATE npc_types SET npc_aggro = %i WHERE id = %i", atoi(sep->argplus[2]) == 0? 0: 1, npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "limit" ) == 0 ) { - c->Message(15,"NPCID %u now has a spawn limit of %i", - npcTypeID, atoi(sep->arg[2])); - - std::string query = StringFormat("UPDATE npc_types SET limit = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "spawn_limit") == 0) { + c->Message(15,"NPCID %u now has a spawn limit of %i", npcTypeID, atoi(sep->arg[2])); + std::string query = StringFormat("UPDATE npc_types SET spawn_limit = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "Attackspeed" ) == 0 ) { - c->Message(15,"NPCID %u now has attack_speed set to %f", - npcTypeID, atof(sep->arg[2])); - - std::string query = StringFormat("UPDATE npc_types SET attack_speed = %f WHERE id = %i", - atof(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "Attackspeed") == 0) { + c->Message(15,"NPCID %u now has attack_speed set to %f", npcTypeID, atof(sep->arg[2])); + std::string query = StringFormat("UPDATE npc_types SET attack_speed = %f WHERE id = %i", atof(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "Attackdelay" ) == 0 ) { + if (strcasecmp(sep->arg[1], "Attackdelay") == 0) { c->Message(15,"NPCID %u now has attack_delay set to %i",npcTypeID,atoi(sep->arg[2])); - std::string query = StringFormat("UPDATE npc_types SET attack_delay = %i WHERE id = %i",atoi(sep->argplus[2]),npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } + + if (strcasecmp(sep->arg[1], "Attackcount") == 0) { + c->Message(15,"NPCID %u now has attack_count set to %i",npcTypeID,atoi(sep->arg[2])); + std::string query = StringFormat("UPDATE npc_types SET attack_count = %i WHERE id = %i",atoi(sep->argplus[2]),npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } - if ( strcasecmp( sep->arg[1], "findable" ) == 0 ) { + if (strcasecmp(sep->arg[1], "findable") == 0) { c->Message(15,"NPCID %u is now %s", npcTypeID, atoi(sep->arg[2]) == 0? "not findable": "findable"); - - std::string query = StringFormat("UPDATE npc_types SET findable = %i WHERE id = %i", - atoi(sep->argplus[2]) == 0? 0: 1, npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET findable = %i WHERE id = %i", atoi(sep->argplus[2]) == 0? 0: 1, npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "wep1" ) == 0 ) { - c->Message(15,"NPCID %u will have item graphic %i set to his primary on repop.", - npcTypeID, atoi(sep->arg[2])); - - std::string query = StringFormat("UPDATE npc_types SET d_meele_texture1 = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "trackable") == 0) { + c->Message(15,"NPCID %u is now %s", npcTypeID, atoi(sep->arg[2]) == 0? "not trackable": "trackable"); + std::string query = StringFormat("UPDATE npc_types SET trackable = %i WHERE id = %i", atoi(sep->argplus[2]) == 0? 0: 1, npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "wep2" ) == 0 ) { - c->Message(15,"NPCID %u will have item graphic %i set to his secondary on repop.", - npcTypeID, atoi(sep->arg[2])); - - std::string query = StringFormat("UPDATE npc_types SET d_meele_texture2 = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "weapon") == 0) { + c->Message(15,"NPCID %u will have item graphic %i set to his primary and item graphic %i set to his secondary on repop.", npcTypeID, atoi(sep->arg[2]), atoi(sep->arg[3])); + std::string query = StringFormat("UPDATE npc_types SET d_melee_texture1 = %i, d_melee_texture2 = %i WHERE id = %i", atoi(sep->arg[2]), atoi(sep->arg[3]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "featuresave" ) == 0 ) { - c->Message(15,"NPCID %u saved with all current facial feature settings", - npcTypeID); - + if (strcasecmp(sep->arg[1], "featuresave") == 0) { + c->Message(15,"NPCID %u saved with all current facial feature settings", npcTypeID); Mob* target = c->GetTarget(); - std::string query = StringFormat("UPDATE npc_types " "SET luclin_haircolor = %i, luclin_beardcolor = %i, " "luclin_hairstyle = %i, luclin_beard = %i, " @@ -6775,45 +6667,36 @@ void command_npcedit(Client *c, const Seperator *sep) return; } - if ( strcasecmp( sep->arg[1], "color" ) == 0 ) { - c->Message(15,"NPCID %u now has %i red, %i green, and %i blue tinting on their armor.", - npcTypeID, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); - - std::string query = StringFormat("UPDATE npc_types " - "SET armortint_red = %i, armortint_green = %i, armortint_blue = %i " - "WHERE id = %i", - atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), npcTypeID); + if (strcasecmp(sep->arg[1], "color") == 0) { + c->Message(15,"NPCID %u now has %i red, %i green, and %i blue tinting on their armor.", npcTypeID, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); + std::string query = StringFormat("UPDATE npc_types SET armortint_red = %i, armortint_green = %i, armortint_blue = %i WHERE id = %i", atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "armortint_id" ) == 0 ) { - c->Message(15,"NPCID %u now has field 'armortint_id' set to %s", - npcTypeID, sep->arg[2]); - - std::string query = StringFormat("UPDATE npc_types SET armortint_id = '%s' WHERE id = %i", - sep->argplus[2], npcTypeID); + if (strcasecmp(sep->arg[1], "armortint_id") == 0) { + c->Message(15,"NPCID %u now has field 'armortint_id' set to %s", npcTypeID, sep->arg[2]); + std::string query = StringFormat("UPDATE npc_types SET armortint_id = '%s' WHERE id = %i", sep->argplus[2], npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "setanimation" ) == 0 ) { + if (strcasecmp(sep->arg[1], "setanimation") == 0) { int animation = 0; if(sep->arg[2] && atoi(sep->arg[2]) <= 4) { - if((strcasecmp( sep->arg[2], "stand" ) == 0) || atoi(sep->arg[2]) == 0) + if((strcasecmp(sep->arg[2], "stand" ) == 0) || atoi(sep->arg[2]) == 0) animation = 0; //Stand - if((strcasecmp( sep->arg[2], "sit" ) == 0) || atoi(sep->arg[2]) == 1) + if((strcasecmp(sep->arg[2], "sit" ) == 0) || atoi(sep->arg[2]) == 1) animation = 1; //Sit - if((strcasecmp( sep->arg[2], "crouch" ) == 0) || atoi(sep->arg[2]) == 2) + if((strcasecmp(sep->arg[2], "crouch" ) == 0) || atoi(sep->arg[2]) == 2) animation = 2; //Crouch - if((strcasecmp( sep->arg[2], "dead" ) == 0) || atoi(sep->arg[2]) == 3) + if((strcasecmp(sep->arg[2], "dead" ) == 0) || atoi(sep->arg[2]) == 3) animation = 3; //Dead - if((strcasecmp( sep->arg[2], "loot" ) == 0) || atoi(sep->arg[2]) == 4) + if((strcasecmp(sep->arg[2], "loot" ) == 0) || atoi(sep->arg[2]) == 4) animation = 4; //Looting Animation - } - else { + } else { c->Message(0, "You must specifiy an animation stand, sit, crouch, dead, loot (0-4)"); c->Message(0, "Example: #npcedit setanimation sit"); c->Message(0, "Example: #npcedit setanimation 0"); @@ -6821,10 +6704,7 @@ void command_npcedit(Client *c, const Seperator *sep) } c->Message(15,"NPCID %u now has the animation set to %i on spawn with spawngroup %i", npcTypeID, animation, c->GetTarget()->CastToNPC()->GetSp2() ); - - std::string query = StringFormat("UPDATE spawn2 SET animation = %i " - "WHERE spawngroupID = %i", - animation, c->GetTarget()->CastToNPC()->GetSp2()); + std::string query = StringFormat("UPDATE spawn2 SET animation = %i " "WHERE spawngroupID = %i", animation, c->GetTarget()->CastToNPC()->GetSp2()); database.QueryDatabase(query); c->LogSQL(query.c_str()); @@ -6832,56 +6712,49 @@ void command_npcedit(Client *c, const Seperator *sep) return; } - if ( strcasecmp( sep->arg[1], "scalerate" ) == 0 ) { - c->Message(15,"NPCID %u now has a scaling rate of %i.", - npcTypeID, atoi(sep->arg[2])); - - std::string query = StringFormat("UPDATE npc_types SET scalerate = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "scalerate") == 0) { + c->Message(15,"NPCID %u now has a scaling rate of %i.", npcTypeID, atoi(sep->arg[2])); + std::string query = StringFormat("UPDATE npc_types SET scalerate = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "healscale" ) == 0 ) { - c->Message(15, "NPCID %u now has a heal scaling rate of %i.", - npcTypeID, atoi(sep->arg[2])); - - std::string query = StringFormat("UPDATE npc_types SET healscale = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "healscale") == 0) { + c->Message(15, "NPCID %u now has a heal scaling rate of %i.", npcTypeID, atoi(sep->arg[2])); + std::string query = StringFormat("UPDATE npc_types SET healscale = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "spellscale" ) == 0 ) { - c->Message(15, "NPCID %u now has a spell scaling rate of %i.", - npcTypeID, atoi(sep->arg[2])); - - std::string query = StringFormat("UPDATE npc_types SET spellscale = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "spellscale") == 0) { + c->Message(15, "NPCID %u now has a spell scaling rate of %i.", npcTypeID, atoi(sep->arg[2])); + std::string query = StringFormat("UPDATE npc_types SET spellscale = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "no_target" ) == 0 ) { - c->Message(15, "NPCID %u is now %s.", - npcTypeID, atoi(sep->arg[2]) == 0? "targetable": "untargetable"); - - std::string query = StringFormat("UPDATE npc_types SET no_target_hotkey = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "no_target") == 0) { + c->Message(15, "NPCID %u is now %s.", npcTypeID, atoi(sep->arg[2]) == 0? "targetable": "untargetable"); + std::string query = StringFormat("UPDATE npc_types SET no_target_hotkey = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; } - if ( strcasecmp( sep->arg[1], "version" ) == 0 ) { - c->Message(15, "NPCID %u is now version %i.", - npcTypeID, atoi(sep->arg[2])); - - std::string query = StringFormat("UPDATE npc_types SET version = %i WHERE id = %i", - atoi(sep->argplus[2]), npcTypeID); + if (strcasecmp(sep->arg[1], "version") == 0) { + c->Message(15, "NPCID %u is now version %i.", npcTypeID, atoi(sep->arg[2])); + std::string query = StringFormat("UPDATE npc_types SET version = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); + database.QueryDatabase(query); + c->LogSQL(query.c_str()); + return; + } + + if (strcasecmp(sep->arg[1], "slow_mitigation") == 0) { + c->Message(15, "NPCID %u's slow mitigation limit is now %i.", npcTypeID, atoi(sep->arg[2])); + std::string query = StringFormat("UPDATE npc_types SET slow_mitigation = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); c->LogSQL(query.c_str()); return; @@ -6913,14 +6786,14 @@ void command_profilereset(Client *c, const Seperator *sep) { #endif void command_opcode(Client *c, const Seperator *sep) { - if(!strcasecmp( sep->arg[1], "reload" )) { + if(!strcasecmp(sep->arg[1], "reload" )) { ReloadAllPatches(); c->Message(0, "Opcodes for all patches have been reloaded"); } } void command_logsql(Client *c, const Seperator *sep) { - if(!strcasecmp( sep->arg[1], "off" )) { + if(!strcasecmp(sep->arg[1], "off" )) { c->ChangeSQLLog(nullptr); } else if(sep->arg[1][0] != '\0') { c->ChangeSQLLog(sep->argplus[1]); @@ -6937,17 +6810,17 @@ void command_logs(Client *c, const Seperator *sep) t = c->GetTarget()->CastToClient(); } - if(!strcasecmp( sep->arg[1], "status" ) ) + if(!strcasecmp(sep->arg[1], "status" ) ) client_logs.subscribe(EQEMuLog::Status, t); - else if(!strcasecmp( sep->arg[1], "normal" ) ) + else if(!strcasecmp(sep->arg[1], "normal" ) ) client_logs.subscribe(EQEMuLog::Normal, t); - else if(!strcasecmp( sep->arg[1], "error" ) ) + else if(!strcasecmp(sep->arg[1], "error" ) ) client_logs.subscribe(EQEMuLog::Error, t); - else if(!strcasecmp( sep->arg[1], "debug" ) ) + else if(!strcasecmp(sep->arg[1], "debug" ) ) client_logs.subscribe(EQEMuLog::Debug, t); - else if(!strcasecmp( sep->arg[1], "quest" ) ) + else if(!strcasecmp(sep->arg[1], "quest" ) ) client_logs.subscribe(EQEMuLog::Quest, t); - else if(!strcasecmp( sep->arg[1], "all" ) ) + else if(!strcasecmp(sep->arg[1], "all" ) ) client_logs.subscribeAll(t); else { c->Message(0, "Usage: #logs [status|normal|error|debug|quest|all]"); @@ -6969,17 +6842,17 @@ void command_nologs(Client *c, const Seperator *sep) t = c; } - if(!strcasecmp( sep->arg[1], "status" ) ) + if(!strcasecmp(sep->arg[1], "status" ) ) client_logs.unsubscribe(EQEMuLog::Status, t); - else if(!strcasecmp( sep->arg[1], "normal" ) ) + else if(!strcasecmp(sep->arg[1], "normal" ) ) client_logs.unsubscribe(EQEMuLog::Normal, t); - else if(!strcasecmp( sep->arg[1], "error" ) ) + else if(!strcasecmp(sep->arg[1], "error" ) ) client_logs.unsubscribe(EQEMuLog::Error, t); - else if(!strcasecmp( sep->arg[1], "debug" ) ) + else if(!strcasecmp(sep->arg[1], "debug" ) ) client_logs.unsubscribe(EQEMuLog::Debug, t); - else if(!strcasecmp( sep->arg[1], "quest" ) ) + else if(!strcasecmp(sep->arg[1], "quest" ) ) client_logs.unsubscribe(EQEMuLog::Quest, t); - else if(!strcasecmp( sep->arg[1], "all" ) ) + else if(!strcasecmp(sep->arg[1], "all" ) ) client_logs.unsubscribeAll(t); else { c->Message(0, "Usage: #logs [status|normal|error|debug|quest|all]"); @@ -8703,8 +8576,8 @@ void command_aggrozone(Client *c, const Seperator *sep) { if (!m) return; - int hate = atoi(sep->arg[1]); //should default to 0 if we don't enter anything - entity_list.AggroZone(m,hate); + uint32 hate = atoi(sep->arg[1]); //should default to 0 if we don't enter anything + entity_list.AggroZone(m, hate); c->Message(0, "Train to you! Last chance to go invulnerable..."); } @@ -10505,7 +10378,7 @@ void command_mysql(Client *c, const Seperator *sep) return; } - if ( strcasecmp( sep->arg[1], "help" ) == 0 ) { + if (strcasecmp(sep->arg[1], "help") == 0) { c->Message(0, "MYSQL In-Game CLI Interface:"); c->Message(0, "Example: #mysql query \"Query goes here quoted\" -s -h"); c->Message(0, "To use 'like \"%%something%%\" replace the %% with #"); @@ -10515,7 +10388,7 @@ void command_mysql(Client *c, const Seperator *sep) return; } - if ( strcasecmp( sep->arg[1], "query" ) == 0 ) { + if (strcasecmp(sep->arg[1], "query") == 0) { ///Parse switches here int argnum = 3; bool optionS = false; diff --git a/zone/common.h b/zone/common.h index aa24964fd..45f3bdb09 100644 --- a/zone/common.h +++ b/zone/common.h @@ -135,7 +135,8 @@ enum { NPC_CHASE_DISTANCE = 40, ALLOW_TO_TANK = 41, IGNORE_ROOT_AGGRO_RULES = 42, - MAX_SPECIAL_ATTACK = 43 + CASTING_RESIST_DIFF = 43, + MAX_SPECIAL_ATTACK = 44 }; typedef enum { //fear states diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 1a40befa8..c15ed6dac 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -1214,7 +1214,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args); parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0); - if ((RuleB(Character, EnableDiscoveredItems))) { + if (!IsPlayerCorpse() && RuleB(Character, EnableDiscoveredItems)) { if (client && !client->GetGM() && !client->IsDiscovered(inst->GetItem()->ID)) client->DiscoverItem(inst->GetItem()->ID); } @@ -1261,33 +1261,38 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { } } - if (GetPlayerKillItem() != -1){ + if (GetPlayerKillItem() != -1) { SetPlayerKillItemID(0); } /* Send message with item link to groups and such */ - char *link = 0, *link2 = 0; //just like a db query :-) - client->MakeItemLink(link2, inst); - MakeAnyLenString(&link, "%c" "%s" "%s" "%c", - 0x12, - link2, - item->Name, - 0x12); - safe_delete_array(link2); + Client::TextLink linker; + linker.SetLinkType(linker.linkItemInst); + linker.SetItemInst(inst); + linker.SetClientVersion(client->GetClientVersion()); + + auto item_link = linker.GenerateLink(); + + client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str()); - client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, link); if(!IsPlayerCorpse()) { + // When sending to multiple/unknown client types, we set for the highest client.. + // ..which is processed when 'EQClientUnknown,' or default value, is selected. + // This should help with any current issues..or it may create more! O.o + linker.SetClientVersion(EQClientUnknown); + item_link = linker.GenerateLink(); + Group *g = client->GetGroup(); if(g != nullptr) { - g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link); - } else { + g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str()); + } + else { Raid *r = client->GetRaid(); if(r != nullptr) { - r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link); + r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str()); } } } - safe_delete_array(link); } else { SendEndLootErrorPacket(client); diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 3a27fc42f..bfac13660 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -232,6 +232,7 @@ int PerlembParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::stri int PerlembParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { + // needs pointer validation on 'item' argument return EventCommon(evt, item->GetID(), nullptr, nullptr, item, client, extra_data, false, extra_pointers); } @@ -335,6 +336,9 @@ bool PerlembParser::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) { if(!perl) return false; + if (itm == nullptr) + return false; + if(evt >= _LargestEventID) return false; @@ -449,6 +453,9 @@ void PerlembParser::LoadGlobalPlayerScript(std::string filename) { } void PerlembParser::LoadItemScript(std::string filename, ItemInst *item) { + if (item == nullptr) + return; + std::stringstream package_name; package_name << "qst_item_" << item->GetID(); @@ -855,6 +862,7 @@ void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlaye } } else if(isItemQuest) { + // need a valid ItemInst pointer check here..unsure how to cancel this process -U const Item_Struct* item = iteminst->GetItem(); package_name = "qst_item_"; package_name += itoa(item->ID); @@ -1292,6 +1300,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID case EVENT_SCALE_CALC: case EVENT_ITEM_ENTER_ZONE: { + // need a valid ItemInst pointer check here..unsure how to cancel this process -U ExportVar(package_name.c_str(), "itemid", objid); ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name); break; @@ -1299,6 +1308,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID case EVENT_ITEM_CLICK_CAST: case EVENT_ITEM_CLICK: { + // need a valid ItemInst pointer check here..unsure how to cancel this process -U ExportVar(package_name.c_str(), "itemid", objid); ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name); ExportVar(package_name.c_str(), "slotid", extradata); diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index e0866083b..76ed3bee7 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2277,18 +2277,20 @@ XS(XS__updatetaskactivity); XS(XS__updatetaskactivity) { dXSARGS; - unsigned int task, activity; + unsigned int task, activity, ignore_quest_update; int count = 1; + ignore_quest_update = 0; if(items == 2) { task = (int)SvIV(ST(0)); activity = (int)SvIV(ST(1)); - quest_manager.updatetaskactivity(task, activity, count); + quest_manager.updatetaskactivity(task, activity, count, false); } else if(items == 3) { task = (int)SvIV(ST(0)); activity = (int)SvIV(ST(1)); count = (int)SvIV(ST(2)); - quest_manager.updatetaskactivity(task, activity, count); + bool ignore_quest_update = (bool)SvTRUE(ST(3)); + quest_manager.updatetaskactivity(task, activity, count, ignore_quest_update); } else { Perl_croak(aTHX_ "Usage: updatetaskactivity(task, activity [,count])"); } diff --git a/zone/embperl.cpp b/zone/embperl.cpp index 9f05d8711..92a59d075 100644 --- a/zone/embperl.cpp +++ b/zone/embperl.cpp @@ -210,6 +210,8 @@ Embperl::~Embperl() " if(tied *STDERR) { untie(*STDERR); }" ,FALSE); #endif + PL_perl_destruct_level = 1; + perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM(); my_perl = NULL; diff --git a/zone/entity.cpp b/zone/entity.cpp index 085e9bdb5..e25c4d961 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2043,13 +2043,16 @@ void EntityList::RemoveAllNPCs() void EntityList::RemoveAllMercs() { + // doesn't clear the data merc_list.clear(); } void EntityList::RemoveAllGroups() { - while (group_list.size()) + while (group_list.size()) { + safe_delete(group_list.front()); group_list.pop_front(); + } #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif @@ -2057,8 +2060,10 @@ void EntityList::RemoveAllGroups() void EntityList::RemoveAllRaids() { - while (raid_list.size()) + while (raid_list.size()) { + safe_delete(raid_list.front()); raid_list.pop_front(); + } } void EntityList::RemoveAllDoors() @@ -2268,7 +2273,8 @@ bool EntityList::RemoveGroup(uint32 delete_id) while(iterator != group_list.end()) { if((*iterator)->GetID() == delete_id) { - group_list.remove (*iterator); + safe_delete(*iterator); + group_list.remove(*iterator); #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif @@ -2291,7 +2297,8 @@ bool EntityList::RemoveRaid(uint32 delete_id) while(iterator != raid_list.end()) { if((*iterator)->GetID() == delete_id) { - raid_list.remove (*iterator); + safe_delete(*iterator); + raid_list.remove(*iterator); return true; } ++iterator; @@ -2462,7 +2469,7 @@ void EntityList::RemoveFromHateLists(Mob *mob, bool settoone) if (!settoone) it->second->RemoveFromHateList(mob); else - it->second->SetHate(mob, 1); + it->second->SetHateAmountOnEnt(mob, 1); } ++it; } @@ -2846,7 +2853,7 @@ void EntityList::DoubleAggro(Mob *who) auto it = npc_list.begin(); while (it != npc_list.end()) { if (it->second->CheckAggro(who)) - it->second->SetHate(who, it->second->CastToNPC()->GetHateAmount(who), + it->second->SetHateAmountOnEnt(who, it->second->CastToNPC()->GetHateAmount(who), it->second->CastToNPC()->GetHateAmount(who) * 2); ++it; } @@ -2857,7 +2864,7 @@ void EntityList::HalveAggro(Mob *who) auto it = npc_list.begin(); while (it != npc_list.end()) { if (it->second->CastToNPC()->CheckAggro(who)) - it->second->CastToNPC()->SetHate(who, it->second->CastToNPC()->GetHateAmount(who) / 2); + it->second->CastToNPC()->SetHateAmountOnEnt(who, it->second->CastToNPC()->GetHateAmount(who) / 2); ++it; } } @@ -2872,9 +2879,9 @@ void EntityList::Evade(Mob *who) amt = it->second->CastToNPC()->GetHateAmount(who); amt -= flatval; if (amt > 0) - it->second->CastToNPC()->SetHate(who, amt); + it->second->CastToNPC()->SetHateAmountOnEnt(who, amt); else - it->second->CastToNPC()->SetHate(who, 0); + it->second->CastToNPC()->SetHateAmountOnEnt(who, 0); } ++it; } @@ -2942,7 +2949,7 @@ void EntityList::ClearZoneFeignAggro(Client *targ) } } -void EntityList::AggroZone(Mob *who, int hate) +void EntityList::AggroZone(Mob *who, uint32 hate) { auto it = npc_list.begin(); while (it != npc_list.end()) { @@ -2963,11 +2970,6 @@ void EntityList::SignalMobsByNPCID(uint32 snpc, int signal_id) } } -bool tracking_compare(const std::pair &a, const std::pair &b) -{ - return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp(); -} - bool EntityList::MakeTrackPacket(Client *client) { std::list > tracking_list; @@ -2985,8 +2987,6 @@ bool EntityList::MakeTrackPacket(Client *client) if (distance < 300) distance = 300; - Group *g = client->GetGroup(); - for (auto it = mob_list.cbegin(); it != mob_list.cend(); ++it) { if (!it->second || it->second == client || !it->second->IsTrackable() || it->second->IsInvisible(client)) @@ -2999,7 +2999,10 @@ bool EntityList::MakeTrackPacket(Client *client) tracking_list.push_back(std::make_pair(it->second, MobDistance)); } - tracking_list.sort(tracking_compare); + tracking_list.sort( + [](const std::pair &a, const std::pair &b) { + return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp(); + }); EQApplicationPacket *outapp = new EQApplicationPacket(OP_Track, sizeof(Track_Struct) * tracking_list.size()); Tracking_Struct *outtrack = (Tracking_Struct *)outapp->pBuffer; outapp->priority = 6; @@ -3007,15 +3010,13 @@ bool EntityList::MakeTrackPacket(Client *client) int index = 0; for (auto it = tracking_list.cbegin(); it != tracking_list.cend(); ++it, ++index) { Mob *cur_entity = it->first; - outtrack->Entrys[index].entityid = cur_entity->GetID(); + outtrack->Entrys[index].entityid = (uint32)cur_entity->GetID(); outtrack->Entrys[index].distance = it->second; outtrack->Entrys[index].level = cur_entity->GetLevel(); - outtrack->Entrys[index].NPC = !cur_entity->IsClient(); - if (g && cur_entity->IsClient() && g->IsGroupMember(cur_entity->CastToMob())) - outtrack->Entrys[index].GroupMember = 1; - else - outtrack->Entrys[index].GroupMember = 0; + outtrack->Entrys[index].is_npc = !cur_entity->IsClient(); strn0cpy(outtrack->Entrys[index].name, cur_entity->GetName(), sizeof(outtrack->Entrys[index].name)); + outtrack->Entrys[index].is_pet = cur_entity->IsPet(); + outtrack->Entrys[index].is_merc = cur_entity->IsMerc(); } client->QueuePacket(outapp); @@ -3681,7 +3682,7 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy) if (n->GetSwarmInfo()) { if (n->GetSwarmInfo()->owner_id == owner->GetID()) { if (!n->GetSpecialAbility(IMMUNE_AGGRO)) - n->hate_list.Add(other, 0, 0, bFrenzy); + n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy); } } ++it; diff --git a/zone/entity.h b/zone/entity.h index fd4f0b5a8..88f5257f7 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -355,7 +355,7 @@ public: void ClearAggro(Mob* targ); void ClearFeignAggro(Mob* targ); void ClearZoneFeignAggro(Client* targ); - void AggroZone(Mob* who, int hate = 0); + void AggroZone(Mob* who, uint32 hate = 0); bool Fighting(Mob* targ); void RemoveFromHateLists(Mob* mob, bool settoone = false); diff --git a/zone/forage.cpp b/zone/forage.cpp index 7e2f7d457..8476ceaad 100644 --- a/zone/forage.cpp +++ b/zone/forage.cpp @@ -249,7 +249,7 @@ void Client::GoFish() Bait = m_inv.GetItem(bslot); //if the bait isnt equipped, need to add its skill bonus - if(bslot >= EmuConstants::GENERAL_BEGIN && Bait->GetItem()->SkillModType == SkillFishing) { + if(bslot >= EmuConstants::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == SkillFishing) { fishing_skill += Bait->GetItem()->SkillModValue; } diff --git a/zone/groups.cpp b/zone/groups.cpp index 3395833bf..a6d8be42b 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -122,7 +122,8 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu uint32 i; uint8 membercount = 0; for (i = 0; i < MAX_GROUP_MEMBERS; i++) { - if (members[i] != nullptr) { + // Don't split with Mercs or Bots + if (members[i] != nullptr && members[i]->IsClient()) { membercount++; } } diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index c8c1308aa..c62dbdab1 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -1,19 +1,19 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) +Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) - 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 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. +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 +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "client.h" @@ -36,7 +36,7 @@ extern Zone *zone; HateList::HateList() { - owner = nullptr; + hate_owner = nullptr; } HateList::~HateList() @@ -45,29 +45,29 @@ HateList::~HateList() // added for frenzy support // checks if target still is in frenzy mode -void HateList::CheckFrenzyHate() +void HateList::IsEntityInFrenzyMode() { auto iterator = list.begin(); - while(iterator != list.end()) + while (iterator != list.end()) { - if ((*iterator)->ent->GetHPRatio() >= 20) - (*iterator)->bFrenzy = false; + if ((*iterator)->entity_on_hatelist->GetHPRatio() >= 20) + (*iterator)->is_entity_frenzy = false; ++iterator; } } -void HateList::Wipe() +void HateList::WipeHateList() { auto iterator = list.begin(); - while(iterator != list.end()) + while (iterator != list.end()) { - Mob* m = (*iterator)->ent; - if(m) + Mob* m = (*iterator)->entity_on_hatelist; + if (m) { - parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), m, "0", 0); + parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0); - if(m->IsClient()) + if (m->IsClient()) m->CastToClient()->DecrementAggroCount(); } delete (*iterator); @@ -76,38 +76,38 @@ void HateList::Wipe() } } -bool HateList::IsOnHateList(Mob *mob) +bool HateList::IsEntOnHateList(Mob *mob) { - if(Find(mob)) + if (Find(mob)) return true; return false; } -tHateEntry *HateList::Find(Mob *ent) +struct_HateList *HateList::Find(Mob *in_entity) { auto iterator = list.begin(); - while(iterator != list.end()) + while (iterator != list.end()) { - if((*iterator)->ent == ent) + if ((*iterator)->entity_on_hatelist == in_entity) return (*iterator); ++iterator; } return nullptr; } -void HateList::Set(Mob* other, uint32 in_hate, uint32 in_dam) +void HateList::SetHateAmountOnEnt(Mob* other, uint32 in_hate, uint32 in_damage) { - tHateEntry *p = Find(other); - if(p) + struct_HateList *entity = Find(other); + if (entity) { - if(in_dam > 0) - p->damage = in_dam; - if(in_hate > 0) - p->hate = in_hate; + if (in_damage > 0) + entity->hatelist_damage = in_damage; + if (in_hate > 0) + entity->stored_hate_amount = in_hate; } } -Mob* HateList::GetDamageTop(Mob* hater) +Mob* HateList::GetDamageTopOnHateList(Mob* hater) { Mob* current = nullptr; Group* grp = nullptr; @@ -115,119 +115,117 @@ Mob* HateList::GetDamageTop(Mob* hater) uint32 dmg_amt = 0; auto iterator = list.begin(); - while(iterator != list.end()) + while (iterator != list.end()) { grp = nullptr; r = nullptr; - if((*iterator)->ent && (*iterator)->ent->IsClient()){ - r = entity_list.GetRaidByClient((*iterator)->ent->CastToClient()); + if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient()){ + r = entity_list.GetRaidByClient((*iterator)->entity_on_hatelist->CastToClient()); } - grp = entity_list.GetGroupByMob((*iterator)->ent); + grp = entity_list.GetGroupByMob((*iterator)->entity_on_hatelist); - if((*iterator)->ent && r){ - if(r->GetTotalRaidDamage(hater) >= dmg_amt) + if ((*iterator)->entity_on_hatelist && r){ + if (r->GetTotalRaidDamage(hater) >= dmg_amt) { - current = (*iterator)->ent; + current = (*iterator)->entity_on_hatelist; dmg_amt = r->GetTotalRaidDamage(hater); } } - else if ((*iterator)->ent != nullptr && grp != nullptr) + else if ((*iterator)->entity_on_hatelist != nullptr && grp != nullptr) { if (grp->GetTotalGroupDamage(hater) >= dmg_amt) { - current = (*iterator)->ent; + current = (*iterator)->entity_on_hatelist; dmg_amt = grp->GetTotalGroupDamage(hater); } } - else if ((*iterator)->ent != nullptr && (uint32)(*iterator)->damage >= dmg_amt) + else if ((*iterator)->entity_on_hatelist != nullptr && (uint32)(*iterator)->hatelist_damage >= dmg_amt) { - current = (*iterator)->ent; - dmg_amt = (*iterator)->damage; + current = (*iterator)->entity_on_hatelist; + dmg_amt = (*iterator)->hatelist_damage; } ++iterator; } return current; } -Mob* HateList::GetClosest(Mob *hater) { - Mob* close = nullptr; - float closedist = 99999.9f; - float thisdist; +Mob* HateList::GetClosestEntOnHateList(Mob *hater) { + Mob* close_entity = nullptr; + float close_distance = 99999.9f; + float this_distance; auto iterator = list.begin(); - while(iterator != list.end()) { - thisdist = (*iterator)->ent->DistNoRootNoZ(*hater); - if((*iterator)->ent != nullptr && thisdist <= closedist) { - closedist = thisdist; - close = (*iterator)->ent; + while (iterator != list.end()) { + this_distance = (*iterator)->entity_on_hatelist->DistNoRootNoZ(*hater); + if ((*iterator)->entity_on_hatelist != nullptr && this_distance <= close_distance) { + close_distance = this_distance; + close_entity = (*iterator)->entity_on_hatelist; } ++iterator; } - if ((!close && hater->IsNPC()) || (close && close->DivineAura())) - close = hater->CastToNPC()->GetHateTop(); + if ((!close_entity && hater->IsNPC()) || (close_entity && close_entity->DivineAura())) + close_entity = hater->CastToNPC()->GetHateTop(); - return close; + return close_entity; } - -// a few comments added, rearranged code for readability -void HateList::Add(Mob *ent, int32 in_hate, int32 in_dam, bool bFrenzy, bool iAddIfNotExist) +void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage, bool in_is_entity_frenzied, bool iAddIfNotExist) { - if(!ent) + if (!in_entity) return; - if(ent->IsCorpse()) + if (in_entity->IsCorpse()) return; - if(ent->IsClient() && ent->CastToClient()->IsDead()) + if (in_entity->IsClient() && in_entity->CastToClient()->IsDead()) return; - tHateEntry *p = Find(ent); - if (p) + struct_HateList *entity = Find(in_entity); + if (entity) { - p->damage+=(in_dam>=0)?in_dam:0; - p->hate+=in_hate; - p->bFrenzy = bFrenzy; + entity->hatelist_damage += (in_damage >= 0) ? in_damage : 0; + entity->stored_hate_amount += in_hate; + entity->is_entity_frenzy = in_is_entity_frenzied; } else if (iAddIfNotExist) { - p = new tHateEntry; - p->ent = ent; - p->damage = (in_dam>=0)?in_dam:0; - p->hate = in_hate; - p->bFrenzy = bFrenzy; - list.push_back(p); - parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "1", 0); + entity = new struct_HateList; + entity->entity_on_hatelist = in_entity; + entity->hatelist_damage = (in_damage >= 0) ? in_damage : 0; + entity->stored_hate_amount = in_hate; + entity->is_entity_frenzy = in_is_entity_frenzied; + list.push_back(entity); + parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "1", 0); - if (ent->IsClient()) { - if (owner->CastToNPC()->IsRaidTarget()) - ent->CastToClient()->SetEngagedRaidTarget(true); - ent->CastToClient()->IncrementAggroCount(); + if (in_entity->IsClient()) { + if (hate_owner->CastToNPC()->IsRaidTarget()) + in_entity->CastToClient()->SetEngagedRaidTarget(true); + in_entity->CastToClient()->IncrementAggroCount(); } } } -bool HateList::RemoveEnt(Mob *ent) +bool HateList::RemoveEntFromHateList(Mob *in_entity) { - if (!ent) + if (!in_entity) return false; - bool found = false; + bool is_found = false; auto iterator = list.begin(); - while(iterator != list.end()) + while (iterator != list.end()) { - if((*iterator)->ent == ent) + if ((*iterator)->entity_on_hatelist == in_entity) { - if(ent) - parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "0", 0); - found = true; + if (in_entity) + parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0); + is_found = true; - - if(ent && ent->IsClient()) - ent->CastToClient()->DecrementAggroCount(); + + if (in_entity && in_entity->IsClient()) + in_entity->CastToClient()->DecrementAggroCount(); delete (*iterator); iterator = list.erase(iterator); @@ -236,123 +234,127 @@ bool HateList::RemoveEnt(Mob *ent) else ++iterator; } - return found; + return is_found; } -void HateList::DoFactionHits(int32 nfl_id) { - if (nfl_id <= 0) +void HateList::DoFactionHits(int32 npc_faction_level_id) { + if (npc_faction_level_id <= 0) return; auto iterator = list.begin(); - while(iterator != list.end()) + while (iterator != list.end()) { - Client *p; + Client *client; - if ((*iterator)->ent && (*iterator)->ent->IsClient()) - p = (*iterator)->ent->CastToClient(); + if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient()) + client = (*iterator)->entity_on_hatelist->CastToClient(); else - p = nullptr; + client = nullptr; - if (p) - p->SetFactionLevel(p->CharacterID(), nfl_id, p->GetBaseClass(), p->GetBaseRace(), p->GetDeity()); + if (client) + client->SetFactionLevel(client->CharacterID(), npc_faction_level_id, client->GetBaseClass(), client->GetBaseRace(), client->GetDeity()); ++iterator; } } -int HateList::SummonedPetCount(Mob *hater) { +int HateList::GetSummonedPetCountOnHateList(Mob *hater) { //Function to get number of 'Summoned' pets on a targets hate list to allow calculations for certian spell effects. //Unclear from description that pets are required to be 'summoned body type'. Will not require at this time. - int petcount = 0; + int pet_count = 0; auto iterator = list.begin(); - while(iterator != list.end()) { + while (iterator != list.end()) { - if((*iterator)->ent != nullptr && (*iterator)->ent->IsNPC() && ((*iterator)->ent->CastToNPC()->IsPet() || ((*iterator)->ent->CastToNPC()->GetSwarmOwner() > 0))) + if ((*iterator)->entity_on_hatelist != nullptr && (*iterator)->entity_on_hatelist->IsNPC() && ((*iterator)->entity_on_hatelist->CastToNPC()->IsPet() || ((*iterator)->entity_on_hatelist->CastToNPC()->GetSwarmOwner() > 0))) { - ++petcount; + ++pet_count; } - + ++iterator; } - return petcount; + return pet_count; } -Mob *HateList::GetTop(Mob *center) +Mob *HateList::GetEntWithMostHateOnList(Mob *center) { - Mob* top = nullptr; - int32 hate = -1; - - if(center == nullptr) + // hack fix for zone shutdown crashes on some servers + if (!zone->IsLoaded()) return nullptr; - if (RuleB(Aggro,SmartAggroList)){ - Mob* topClientTypeInRange = nullptr; - int32 hateClientTypeInRange = -1; + Mob* top_hate = nullptr; + int32 hate = -1; + + if (center == nullptr) + return nullptr; + + if (RuleB(Aggro, SmartAggroList)){ + Mob* top_client_type_in_range = nullptr; + int32 hate_client_type_in_range = -1; int skipped_count = 0; auto iterator = list.begin(); - while(iterator != list.end()) + while (iterator != list.end()) { - tHateEntry *cur = (*iterator); - int16 aggroMod = 0; + struct_HateList *cur = (*iterator); + int16 aggro_mod = 0; - if(!cur){ + if (!cur){ ++iterator; continue; } - if(!cur->ent){ + if (!cur->entity_on_hatelist){ ++iterator; continue; } - if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) { - if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) { + if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) { + if (!zone->watermap->InLiquid(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ())) { skipped_count++; ++iterator; continue; } } - if (cur->ent->Sanctuary()) { - if(hate == -1) + if (cur->entity_on_hatelist->Sanctuary()) { + if (hate == -1) { - top = cur->ent; + top_hate = cur->entity_on_hatelist; hate = 1; } ++iterator; continue; } - if(cur->ent->DivineAura() || cur->ent->IsMezzed() || cur->ent->IsFeared()){ - if(hate == -1) + if (cur->entity_on_hatelist->DivineAura() || cur->entity_on_hatelist->IsMezzed() || cur->entity_on_hatelist->IsFeared()){ + if (hate == -1) { - top = cur->ent; + top_hate = cur->entity_on_hatelist; hate = 0; } ++iterator; continue; } - int32 currentHate = cur->hate; + int32 current_hate = cur->stored_hate_amount; - if(cur->ent->IsClient()){ + if (cur->entity_on_hatelist->IsClient()){ - if(cur->ent->CastToClient()->IsSitting()){ - aggroMod += RuleI(Aggro, SittingAggroMod); + if (cur->entity_on_hatelist->CastToClient()->IsSitting()){ + aggro_mod += RuleI(Aggro, SittingAggroMod); } - if(center){ - if(center->GetTarget() == cur->ent) - aggroMod += RuleI(Aggro, CurrentTargetAggroMod); - if(RuleI(Aggro, MeleeRangeAggroMod) != 0) + if (center){ + if (center->GetTarget() == cur->entity_on_hatelist) + aggro_mod += RuleI(Aggro, CurrentTargetAggroMod); + if (RuleI(Aggro, MeleeRangeAggroMod) != 0) { - if(center->CombatRange(cur->ent)){ - aggroMod += RuleI(Aggro, MeleeRangeAggroMod); + if (center->CombatRange(cur->entity_on_hatelist)){ + aggro_mod += RuleI(Aggro, MeleeRangeAggroMod); - if(currentHate > hateClientTypeInRange || cur->bFrenzy){ - hateClientTypeInRange = currentHate; - topClientTypeInRange = cur->ent; + if (current_hate > hate_client_type_in_range || cur->is_entity_frenzy){ + hate_client_type_in_range = current_hate; + top_client_type_in_range = cur->entity_on_hatelist; } } } @@ -360,112 +362,112 @@ Mob *HateList::GetTop(Mob *center) } else{ - if(center){ - if(center->GetTarget() == cur->ent) - aggroMod += RuleI(Aggro, CurrentTargetAggroMod); - if(RuleI(Aggro, MeleeRangeAggroMod) != 0) + if (center){ + if (center->GetTarget() == cur->entity_on_hatelist) + aggro_mod += RuleI(Aggro, CurrentTargetAggroMod); + if (RuleI(Aggro, MeleeRangeAggroMod) != 0) { - if(center->CombatRange(cur->ent)){ - aggroMod += RuleI(Aggro, MeleeRangeAggroMod); + if (center->CombatRange(cur->entity_on_hatelist)){ + aggro_mod += RuleI(Aggro, MeleeRangeAggroMod); } } } } - if(cur->ent->GetMaxHP() != 0 && ((cur->ent->GetHP()*100/cur->ent->GetMaxHP()) < 20)){ - aggroMod += RuleI(Aggro, CriticallyWoundedAggroMod); + if (cur->entity_on_hatelist->GetMaxHP() != 0 && ((cur->entity_on_hatelist->GetHP() * 100 / cur->entity_on_hatelist->GetMaxHP()) < 20)){ + aggro_mod += RuleI(Aggro, CriticallyWoundedAggroMod); } - if(aggroMod){ - currentHate += (currentHate * aggroMod / 100); + if (aggro_mod){ + current_hate += (current_hate * aggro_mod / 100); } - if(currentHate > hate || cur->bFrenzy){ - hate = currentHate; - top = cur->ent; + if (current_hate > hate || cur->is_entity_frenzy){ + hate = current_hate; + top_hate = cur->entity_on_hatelist; } ++iterator; } - if(topClientTypeInRange != nullptr && top != nullptr) { - bool isTopClientType = top->IsClient(); + if (top_client_type_in_range != nullptr && top_hate != nullptr) { + bool isTopClientType = top_hate->IsClient(); #ifdef BOTS - if(!isTopClientType) { - if(top->IsBot()) { + if (!isTopClientType) { + if (top_hate->IsBot()) { isTopClientType = true; - topClientTypeInRange = top; + top_client_type_in_range = top_hate; } } #endif //BOTS - if(!isTopClientType) { - if(top->IsMerc()) { + if (!isTopClientType) { + if (top_hate->IsMerc()) { isTopClientType = true; - topClientTypeInRange = top; + top_client_type_in_range = top_hate; } } if (!isTopClientType) { - if (top->GetSpecialAbility(ALLOW_TO_TANK)){ + if (top_hate->GetSpecialAbility(ALLOW_TO_TANK)){ isTopClientType = true; - topClientTypeInRange = top; + top_client_type_in_range = top_hate; } } - if(!isTopClientType) - return topClientTypeInRange ? topClientTypeInRange : nullptr; + if (!isTopClientType) + return top_client_type_in_range ? top_client_type_in_range : nullptr; - return top ? top : nullptr; + return top_hate ? top_hate : nullptr; } else { - if(top == nullptr && skipped_count > 0) { + if (top_hate == nullptr && skipped_count > 0) { return center->GetTarget() ? center->GetTarget() : nullptr; } - return top ? top : nullptr; + return top_hate ? top_hate : nullptr; } } else{ auto iterator = list.begin(); int skipped_count = 0; - while(iterator != list.end()) + while (iterator != list.end()) { - tHateEntry *cur = (*iterator); - if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) { - if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) { + struct_HateList *cur = (*iterator); + if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) { + if (!zone->watermap->InLiquid(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ())) { skipped_count++; ++iterator; continue; } } - if(cur->ent != nullptr && ((cur->hate > hate) || cur->bFrenzy )) + if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy)) { - top = cur->ent; - hate = cur->hate; + top_hate = cur->entity_on_hatelist; + hate = cur->stored_hate_amount; } ++iterator; } - if(top == nullptr && skipped_count > 0) { + if (top_hate == nullptr && skipped_count > 0) { return center->GetTarget() ? center->GetTarget() : nullptr; } - return top ? top : nullptr; + return top_hate ? top_hate : nullptr; } return nullptr; } -Mob *HateList::GetMostHate(){ +Mob *HateList::GetEntWithMostHateOnList(){ Mob* top = nullptr; int32 hate = -1; auto iterator = list.begin(); - while(iterator != list.end()) + while (iterator != list.end()) { - tHateEntry *cur = (*iterator); - if(cur->ent != nullptr && (cur->hate > hate)) + struct_HateList *cur = (*iterator); + if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate)) { - top = cur->ent; - hate = cur->hate; + top = cur->entity_on_hatelist; + hate = cur->stored_hate_amount; } ++iterator; } @@ -473,16 +475,16 @@ Mob *HateList::GetMostHate(){ } -Mob *HateList::GetRandom() +Mob *HateList::GetRandomEntOnHateList() { int count = list.size(); - if(count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position. + if (count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position. return NULL; - if(count == 1) //No need to do all that extra work if we only have one hate entry + if (count == 1) //No need to do all that extra work if we only have one hate entry { - if(*list.begin()) // Just in case tHateEntry is invalidated somehow... - return (*list.begin())->ent; + if (*list.begin()) // Just in case tHateEntry is invalidated somehow... + return (*list.begin())->entity_on_hatelist; return NULL; } @@ -492,38 +494,36 @@ Mob *HateList::GetRandom() for (int i = 0; i < random; i++) ++iterator; - return (*iterator)->ent; + return (*iterator)->entity_on_hatelist; } -int32 HateList::GetEntHate(Mob *ent, bool damage) +int32 HateList::GetEntHateAmount(Mob *in_entity, bool damage) { - tHateEntry *p; + struct_HateList *entity; - p = Find(ent); + entity = Find(in_entity); - if ( p && damage) - return p->damage; - else if (p) - return p->hate; + if (entity && damage) + return entity->hatelist_damage; + else if (entity) + return entity->stored_hate_amount; else return 0; } -//looking for any mob with hate > -1 -bool HateList::IsEmpty() { +bool HateList::IsHateListEmpty() { return(list.size() == 0); } -// Prints hate list to a client -void HateList::PrintToClient(Client *c) +void HateList::PrintHateListToClient(Client *c) { auto iterator = list.begin(); while (iterator != list.end()) { - tHateEntry *e = (*iterator); + struct_HateList *e = (*iterator); c->Message(0, "- name: %s, damage: %d, hate: %d", - (e->ent && e->ent->GetName()) ? e->ent->GetName() : "(null)", - e->damage, e->hate); + (e->entity_on_hatelist && e->entity_on_hatelist->GetName()) ? e->entity_on_hatelist->GetName() : "(null)", + e->hatelist_damage, e->stored_hate_amount); ++iterator; } @@ -531,7 +531,7 @@ void HateList::PrintToClient(Client *c) int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts) { - if(!target || !caster) + if (!target || !caster) return 0; int ret = 0; @@ -539,25 +539,25 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption auto iterator = list.begin(); while (iterator != list.end()) { - tHateEntry *h = (*iterator); + struct_HateList *h = (*iterator); ++iterator; - if(h && h->ent && h->ent != caster) + if (h && h->entity_on_hatelist && h->entity_on_hatelist != caster) { - if(caster->CombatRange(h->ent)) + if (caster->CombatRange(h->entity_on_hatelist)) { - id_list.push_back(h->ent->GetID()); + id_list.push_back(h->entity_on_hatelist->GetID()); ++ret; } } } std::list::iterator iter = id_list.begin(); - while(iter != id_list.end()) + while (iter != id_list.end()) { Mob *cur = entity_list.GetMobID((*iter)); - if(cur) + if (cur) { - for(int i = 0; i < count; ++i) { + for (int i = 0; i < count; ++i) { caster->Attack(cur, MainPrimary, false, false, false, opts); } } @@ -569,7 +569,7 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_center) { - if(!caster) + if (!caster) return; Mob* center = caster; @@ -588,33 +588,32 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent auto iterator = list.begin(); while (iterator != list.end()) { - tHateEntry *h = (*iterator); - if(range > 0) + struct_HateList *h = (*iterator); + if (range > 0) { - dist_targ = center->DistNoRoot(*h->ent); - if(dist_targ <= range && dist_targ >= min_range2) + dist_targ = center->DistNoRoot(*h->entity_on_hatelist); + if (dist_targ <= range && dist_targ >= min_range2) { - id_list.push_back(h->ent->GetID()); - h->ent->CalcSpellPowerDistanceMod(spell_id, dist_targ); + id_list.push_back(h->entity_on_hatelist->GetID()); + h->entity_on_hatelist->CalcSpellPowerDistanceMod(spell_id, dist_targ); } } else { - id_list.push_back(h->ent->GetID()); - h->ent->CalcSpellPowerDistanceMod(spell_id, 0, caster); + id_list.push_back(h->entity_on_hatelist->GetID()); + h->entity_on_hatelist->CalcSpellPowerDistanceMod(spell_id, 0, caster); } ++iterator; } std::list::iterator iter = id_list.begin(); - while(iter != id_list.end()) + while (iter != id_list.end()) { Mob *cur = entity_list.GetMobID((*iter)); - if(cur) + if (cur) { caster->SpellOnTarget(spell_id, cur); } iter++; } } - diff --git a/zone/hate_list.h b/zone/hate_list.h index 97f16f9d7..dda8cb21d 100644 --- a/zone/hate_list.h +++ b/zone/hate_list.h @@ -1,19 +1,19 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) +Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) - 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 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. +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 +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 */ #ifndef HATELIST_H @@ -25,11 +25,12 @@ class Mob; class Raid; struct ExtraAttackOptions; -struct tHateEntry +struct struct_HateList { - Mob *ent; - int32 damage, hate; - bool bFrenzy; + Mob *entity_on_hatelist; + int32 hatelist_damage; + uint32 stored_hate_amount; + bool is_entity_frenzy; }; class HateList @@ -38,53 +39,38 @@ public: HateList(); ~HateList(); - // adds a mob to the hatelist - void Add(Mob *ent, int32 in_hate=0, int32 in_dam=0, bool bFrenzy = false, bool iAddIfNotExist = true); - // sets existing hate - void Set(Mob *other, uint32 in_hate, uint32 in_dam); - // removes mobs from hatelist - bool RemoveEnt(Mob *ent); - // Remove all - void Wipe(); - // ??? - void DoFactionHits(int32 nfl_id); - // Gets Hate amount for mob - int32 GetEntHate(Mob *ent, bool damage = false); - // gets top hated mob - Mob *GetTop(Mob *center); - // gets any on the list - Mob *GetRandom(); - // get closest mob or nullptr if list empty - Mob *GetClosest(Mob *hater); - // gets top mob or nullptr if hate list empty - Mob *GetDamageTop(Mob *hater); - // used to check if mob is on hatelist - bool IsOnHateList(Mob *); - // used to remove or add frenzy hate - void CheckFrenzyHate(); - //Gets the target with the most hate regardless of things like frenzy etc. - Mob* GetMostHate(); - // Count 'Summoned' pets on hatelist - int SummonedPetCount(Mob *hater); + Mob *GetClosestEntOnHateList(Mob *hater); + Mob *GetDamageTopOnHateList(Mob *hater); + Mob *GetEntWithMostHateOnList(Mob *center); + Mob *GetRandomEntOnHateList(); + Mob* GetEntWithMostHateOnList(); + + bool IsEntOnHateList(Mob *mob); + bool IsHateListEmpty(); + bool RemoveEntFromHateList(Mob *ent); int AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts); + int GetSummonedPetCountOnHateList(Mob *hater); - void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr); + int32 GetEntHateAmount(Mob *ent, bool in_damage = false); - bool IsEmpty(); - void PrintToClient(Client *c); + std::list& GetHateList() { return list; } - //For accessing the hate list via perl; don't use for anything else - std::list& GetHateList() { return list; } + void AddEntToHateList(Mob *ent, int32 in_hate = 0, int32 in_damage = 0, bool in_is_frenzied = false, bool add_to_hate_list_if_not_exist = true); + void DoFactionHits(int32 npc_faction_level_id); + void IsEntityInFrenzyMode(); + void PrintHateListToClient(Client *c); + void SetHateAmountOnEnt(Mob *other, uint32 in_hate, uint32 in_damage); + void SetHateOwner(Mob *new_hate_owner) { hate_owner = new_hate_owner; } + void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr); + void WipeHateList(); - //setting owner - void SetOwner(Mob *newOwner) { owner = newOwner; } protected: - tHateEntry* Find(Mob *ent); + struct_HateList* Find(Mob *ent); private: - std::list list; - Mob *owner; + std::list list; + Mob *hate_owner; }; -#endif +#endif \ No newline at end of file diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 343f6e337..fed4dde3b 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -617,6 +617,7 @@ void Client::DropItem(int16 slot_id) // Save client inventory change to database if (slot_id == MainCursor) { + SendCursorBuffer(); std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); database.SaveCursor(CharacterID(), s, e); } else { @@ -678,6 +679,23 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) { return INVALID_ID; } +void Client::SendCursorBuffer() { + // Temporary work-around for the RoF+ Client Buffer + // Instead of dealing with client moving items in cursor buffer, + // we can just send the next item in the cursor buffer to the cursor. + if (GetClientVersion() >= EQClientRoF) + { + if (!GetInv().CursorEmpty()) + { + const ItemInst* inst = GetInv().GetCursorItem(); + if (inst) + { + SendItemPacket(MainCursor, inst, ItemPacketSummonItem); + } + } + } +} + // Remove item from inventory void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_update, bool update_db) { #if (EQDEBUG >= 5) @@ -794,10 +812,6 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd } } -// Puts an item into the person's inventory -// Any items already there will be removed from user's inventory -// (Also saves changes back to the database: this may be optimized in the future) -// client_update: Sends packet to client bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update) { mlog(INVENTORY__SLOTS, "Putting item %s (%d) on the cursor", inst.GetItem()->Name, inst.GetItem()->ID); @@ -811,6 +825,10 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update) return database.SaveCursor(CharacterID(), s, e); } +// Puts an item into the person's inventory +// Any items already there will be removed from user's inventory +// (Also saves changes back to the database: this may be optimized in the future) +// client_update: Sends packet to client bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) { mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id); @@ -908,7 +926,7 @@ bool Client::TryStacking(ItemInst* item, uint8 type, bool try_worn, bool try_cur bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_cursor, ServerLootItem_Struct** bag_item_data) { // #1: Try to auto equip - if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && !inst.GetItem()->Attuneable && inst.GetItem()->ItemType != ItemTypeAugmentation) + if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && (!inst.GetItem()->Attuneable || inst.IsAttuned()) && inst.GetItem()->ItemType != ItemTypeAugmentation) { // too messy as-is... for (int16 i = EmuConstants::EQUIPMENT_BEGIN; i < MainPowerSource; i++) // originally (i < 22) @@ -1009,105 +1027,113 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type) } } -bool Client::MakeItemLink(char* &ret_link, const ItemInst *inst) { +// TODO: needs clean-up to save references +bool MakeItemLink(char* &ret_link, const Item_Struct *item, uint32 aug0, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint8 evolving, uint8 evolvedlevel) { //we're sending back the entire "link", minus the null characters & item name //that way, we can use it for regular links & Task links //note: initiator needs to pass us ret_link -/* + /* --- Usage --- Chat: "%c" "%s" "%s" "%c", 0x12, ret_link, inst->GetItem()->name, 0x12 Task: "" "%s" "", ret_link, inst->GetItem()->name - Master's Book of Wood Elven Culture - http://eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510 -*/ + Master's Book of Wood Elven Culture + http://eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510 + */ - if (!inst) //have to have an item to make the link + if (!item) //have to have an item to make the link return false; - const Item_Struct* item = inst->GetItem(); //format: //0 itemid aug1 aug2 aug3 aug4 aug5 evolving? loregroup evolved level hash //0 00000 00000 00000 00000 00000 00000 0 0000 0 00000000 //length: //1 5 5 5 5 5 5 1 4 1 8 = 45 //evolving item info: http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=145#558 - uint8 evolving = 0; - uint16 loregroup = 0; - uint8 evolvedlevel = 0; - int hash = 0; + //int hash = GetItemLinkHash(inst); //eventually this will work (currently crashes zone), but for now we'll skip the extra overhead - if (GetClientVersion() >= EQClientRoF2) - { - MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%01X" "%1X" "%04X" "%1X" "%05X" "%08X", + int hash = NOT_USED; + + // Tested with UF and RoF..there appears to be a problem with using non-augment arguments below... + // Currently, enabling them causes misalignments in what the client expects. I haven't looked + // into it further to determine the cause..but, the function is setup to accept the parameters. + // Note: some links appear with '00000' in front of the name..so, it's likely we need to send + // some additional information when certain parameters are true -U + //switch (GetClientVersion()) { + switch (0) { + case EQClientRoF2: + // This operator contains 14 parameter masks..but, only 13 parameter values. + // Even so, the client link appears ok... Need to figure out the discrepancy -U + MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X", 0, item->ID, - inst->GetAugmentItemID(0), - inst->GetAugmentItemID(1), - inst->GetAugmentItemID(2), - inst->GetAugmentItemID(3), - inst->GetAugmentItemID(4), - inst->GetAugmentItemID(5), - evolving, - loregroup, - evolvedlevel, + aug0, + aug1, + aug2, + aug3, + aug4, + aug5, + 0,//evolving, + 0,//item->LoreGroup, + 0,//evolvedlevel, 0, hash ); - } - else if (GetClientVersion() >= EQClientRoF) - { + return true; + case EQClientRoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X", 0, item->ID, - inst->GetAugmentItemID(0), - inst->GetAugmentItemID(1), - inst->GetAugmentItemID(2), - inst->GetAugmentItemID(3), - inst->GetAugmentItemID(4), - inst->GetAugmentItemID(5), - evolving, - loregroup, - evolvedlevel, + aug0, + aug1, + aug2, + aug3, + aug4, + aug5, + 0,//evolving, + 0,//item->LoreGroup, + 0,//evolvedlevel, 0, hash - ); - } - else if (GetClientVersion() >= EQClientSoF) - { + ); + return true; + case EQClientUnderfoot: + case EQClientSoD: + case EQClientSoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X", 0, item->ID, - inst->GetAugmentItemID(0), - inst->GetAugmentItemID(1), - inst->GetAugmentItemID(2), - inst->GetAugmentItemID(3), - inst->GetAugmentItemID(4), - evolving, - loregroup, - evolvedlevel, + aug0, + aug1, + aug2, + aug3, + aug4, + 0,//evolving, + 0,//item->LoreGroup, + 0,//evolvedlevel, 0, hash - ); - } - else - { + ); + return true; + case EQClientTitanium: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X", 0, item->ID, - inst->GetAugmentItemID(0), - inst->GetAugmentItemID(1), - inst->GetAugmentItemID(2), - inst->GetAugmentItemID(3), - inst->GetAugmentItemID(4), - evolving, - loregroup, - evolvedlevel, + aug0, + aug1, + aug2, + aug3, + aug4, + 0,//evolving, + 0,//item->LoreGroup, + 0,//evolvedlevel, hash - ); + ); + return true; + case EQClient62: + default: + return false; } - - return true; } int Client::GetItemLinkHash(const ItemInst* inst) { @@ -1198,6 +1224,7 @@ int Client::GetItemLinkHash(const ItemInst* inst) { return hash; } +// This appears to still be in use... The core of this should be incorporated into class Client::TextLink void Client::SendItemLink(const ItemInst* inst, bool send_to_all) { /* @@ -1299,7 +1326,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { // This could be expounded upon at some point to let the server know that // the client has moved a buffered cursor item onto the active cursor -U - if (move_in->from_slot == move_in->to_slot) { // Item summon, no further proccessing needed + if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit return true; } @@ -1315,13 +1342,15 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } DeleteItemInInventory(move_in->from_slot); + SendCursorBuffer(); + return true; // Item destroyed by client } else { mlog(INVENTORY__SLOTS, "Deleted item from slot %d as a result of an inventory container tradeskill combine.", move_in->from_slot); if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit DeleteItemInInventory(move_in->from_slot); - return true; // Item deletetion + return true; // Item deletion } } if(auto_attack && (move_in->from_slot == MainPrimary || move_in->from_slot == MainSecondary || move_in->from_slot == MainRange)) @@ -1363,7 +1392,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { //SetTint(dst_slot_id,src_inst->GetColor()); if (src_inst->GetCharges() > 0 && (src_inst->GetCharges() < (int16)move_in->number_in_stack || move_in->number_in_stack > src_inst->GetItem()->StackSize)) { - Message(13,"Error: Insufficent number in stack."); + Message(13,"Error: Insufficient number in stack."); return false; } } @@ -1520,11 +1549,19 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } safe_delete(world_inst); - if (src_slot_id == MainCursor) { - std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); + if (src_slot_id == MainCursor) + { + if (dstitemid == 0) + { + SendCursorBuffer(); + } + std::list::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end(); database.SaveCursor(character_id, s, e); - } else + } + else + { database.SaveInventory(character_id, m_inv[src_slot_id], src_slot_id); + } if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in, true); } // QS Audit @@ -1551,6 +1588,10 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit trade->AddEntity(dst_slot_id, move_in->number_in_stack); + if (dstitemid == 0) + { + SendCursorBuffer(); + } return true; } else { @@ -1563,6 +1604,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } } + bool all_to_stack = false; // Step 5: Swap (or stack) items if (move_in->number_in_stack > 0) { // Determine if charged items can stack @@ -1593,6 +1635,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) was entirely consumed. (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, usedcharges); database.SaveInventory(CharacterID(),nullptr,src_slot_id); m_inv.DeleteItem(src_slot_id); + all_to_stack = true; } else { mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) has %d (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, src_inst->GetCharges(), usedcharges); } @@ -1666,6 +1709,11 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { // Step 7: Save change to the database if (src_slot_id == MainCursor){ + // If not swapping another item to cursor and stacking items were depleted + if (dstitemid == 0 || all_to_stack == true) + { + SendCursorBuffer(); + } std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); database.SaveCursor(character_id, s, e); } else @@ -1968,7 +2016,7 @@ void Client::DyeArmor(DyeStruct* dye){ bool Client::DecreaseByID(uint32 type, uint8 amt) { const Item_Struct* TempItem = 0; - ItemInst* ins; + ItemInst* ins = nullptr; int x; int num = 0; for(x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++) @@ -2104,6 +2152,7 @@ void Client::RemoveNoRent(bool client_update) { std::list::iterator iter = local.begin(); while (iter != local.end()) { inst = *iter; + // should probably put a check here for valid pointer..but, that was checked when the item was put into inventory -U if (!inst->GetItem()->NoRent) mlog(INVENTORY__SLOTS, "NoRent Timer Lapse: Deleting %s from `Limbo`", inst->GetItem()->Name); else @@ -2229,6 +2278,7 @@ void Client::RemoveDuplicateLore(bool client_update) { std::list::iterator iter = local.begin(); while (iter != local.end()) { inst = *iter; + // probably needs a valid pointer check -U if (CheckLoreConflict(inst->GetItem())) { mlog(INVENTORY__ERROR, "Lore Duplication Error: Deleting %s from `Limbo`", inst->GetItem()->Name); safe_delete(*iter); @@ -2431,8 +2481,8 @@ void Client::CreateBandolier(const EQApplicationPacket *app) { _log(INVENTORY__BANDOLIER, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->number, bs->name); strcpy(m_pp.bandoliers[bs->number].name, bs->name); - const ItemInst* InvItem; - const Item_Struct *BaseItem; + const ItemInst* InvItem = nullptr; + const Item_Struct *BaseItem = nullptr; int16 WeaponSlot; for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) { diff --git a/zone/loottables.cpp b/zone/loottables.cpp index b6a2c8092..000bb9bb1 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -324,7 +324,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge what was this about??? if (((npc->GetRace()==127) && (npc->CastToMob()->GetOwnerID()!=0)) && (item2->Slots==24576) || (item2->Slots==8192) || (item2->Slots==16384)){ - npc->d_meele_texture2=atoi(newid); + npc->d_melee_texture2=atoi(newid); wc->wear_slot_id=8; if (item2->Material >0) wc->material=item2->Material; diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 83c07e604..9975995d9 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1354,8 +1354,8 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float LuaCreateNPCParse(max_dmg, uint32, 4); LuaCreateNPCParse(attack_count, int16, 0); LuaCreateNPCParseString(special_abilities, 512, ""); - LuaCreateNPCParse(d_meele_texture1, uint16, 0); - LuaCreateNPCParse(d_meele_texture2, uint16, 0); + LuaCreateNPCParse(d_melee_texture1, uint16, 0); + LuaCreateNPCParse(d_melee_texture2, uint16, 0); LuaCreateNPCParseString(ammo_idfile, 32, ""); LuaCreateNPCParse(prim_melee_type, uint8, 0); LuaCreateNPCParse(sec_melee_type, uint8, 0); diff --git a/zone/lua_hate_list.cpp b/zone/lua_hate_list.cpp index edca6ee11..e8c6a52df 100644 --- a/zone/lua_hate_list.cpp +++ b/zone/lua_hate_list.cpp @@ -12,42 +12,42 @@ Lua_Mob Lua_HateEntry::GetEnt() { Lua_Safe_Call_Class(Lua_Mob); - return Lua_Mob(self->ent); + return Lua_Mob(self->entity_on_hatelist); } void Lua_HateEntry::SetEnt(Lua_Mob e) { Lua_Safe_Call_Void(); - self->ent = e; + self->entity_on_hatelist = e; } int Lua_HateEntry::GetDamage() { Lua_Safe_Call_Int(); - return self->damage; + return self->hatelist_damage; } void Lua_HateEntry::SetDamage(int value) { Lua_Safe_Call_Void(); - self->damage = value; + self->hatelist_damage = value; } int Lua_HateEntry::GetHate() { Lua_Safe_Call_Int(); - return self->hate; + return self->stored_hate_amount; } void Lua_HateEntry::SetHate(int value) { Lua_Safe_Call_Void(); - self->hate = value; + self->stored_hate_amount = value; } int Lua_HateEntry::GetFrenzy() { Lua_Safe_Call_Int(); - return self->bFrenzy; + return self->is_entity_frenzy; } void Lua_HateEntry::SetFrenzy(bool value) { Lua_Safe_Call_Void(); - self->bFrenzy = value; + self->is_entity_frenzy = value; } luabind::scope lua_register_hate_entry() { diff --git a/zone/lua_hate_list.h b/zone/lua_hate_list.h index 4dc6502f3..41d5d75f9 100644 --- a/zone/lua_hate_list.h +++ b/zone/lua_hate_list.h @@ -5,17 +5,17 @@ #include "lua_ptr.h" class Lua_Mob; -struct tHateEntry; +struct struct_HateList; luabind::scope lua_register_hate_entry(); luabind::scope lua_register_hate_list(); -class Lua_HateEntry : public Lua_Ptr +class Lua_HateEntry : public Lua_Ptr { - typedef tHateEntry NativeType; + typedef struct_HateList NativeType; public: Lua_HateEntry() : Lua_Ptr(nullptr) { } - Lua_HateEntry(tHateEntry *d) : Lua_Ptr(d) { } + Lua_HateEntry(struct_HateList *d) : Lua_Ptr(d) { } virtual ~Lua_HateEntry() { } Lua_Mob GetEnt(); diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 50a8b50a7..92afdd8b3 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -895,17 +895,17 @@ void Lua_Mob::AddToHateList(Lua_Mob other, int hate, int damage, bool yell_for_h void Lua_Mob::SetHate(Lua_Mob other) { Lua_Safe_Call_Void(); - self->SetHate(other); + self->SetHateAmountOnEnt(other); } void Lua_Mob::SetHate(Lua_Mob other, int hate) { Lua_Safe_Call_Void(); - self->SetHate(other, hate); + self->SetHateAmountOnEnt(other, hate); } void Lua_Mob::SetHate(Lua_Mob other, int hate, int damage) { Lua_Safe_Call_Void(); - self->SetHate(other, hate, damage); + self->SetHateAmountOnEnt(other, hate, damage); } void Lua_Mob::HalveAggro(Lua_Mob other) { diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index b05e7619f..1b1bfb8e8 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -695,6 +695,9 @@ bool LuaParser::SpellHasQuestSub(uint32 spell_id, QuestEventID evt) { } bool LuaParser::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) { + if (itm == nullptr) { + return false; + } evt = ConvertLuaEvent(evt); if(evt >= _LargestEventID) { return false; @@ -738,6 +741,8 @@ void LuaParser::LoadGlobalPlayerScript(std::string filename) { } void LuaParser::LoadItemScript(std::string filename, ItemInst *item) { + if (item == nullptr) + return; std::string package_name = "item_"; package_name += std::to_string(static_cast(item->GetID())); diff --git a/zone/map.cpp b/zone/map.cpp index b6f4de2b5..5c917b955 100644 --- a/zone/map.cpp +++ b/zone/map.cpp @@ -58,6 +58,7 @@ Map::Map() { Map::~Map() { if(imp) { imp->rm->release(); + safe_delete(imp); } } @@ -887,4 +888,4 @@ void Map::TranslateVertex(Vertex &v, float tx, float ty, float tz) { v.x = v.x + tx; v.y = v.y + ty; v.z = v.z + tz; -} \ No newline at end of file +} diff --git a/zone/merc.cpp b/zone/merc.cpp index 76167382f..b82a22fda 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1385,7 +1385,7 @@ void Merc::AI_Process() { rest_timer.Disable(); if(IsRooted()) - SetTarget(hate_list.GetClosest(this)); + SetTarget(hate_list.GetClosestEntOnHateList(this)); else FindTarget(); @@ -2454,11 +2454,11 @@ void Merc::CheckHateList() { Mob* groupMember = g->members[counter]; if(groupMember) { if(npc->IsOnHatelist(groupMember)) { - if(!hate_list.IsOnHateList(npc)) { + if(!hate_list.IsEntOnHateList(npc)) { float range = g->HasRole(groupMember, RolePuller) ? RuleI(Mercs, AggroRadiusPuller) : RuleI(Mercs, AggroRadius); range *= range; if(npc->DistNoRootNoZ(*this) < range) { - hate_list.Add(npc, 1); + hate_list.AddEntToHateList(npc, 1); } } } @@ -4644,13 +4644,6 @@ const char* Merc::GetRandomName(){ return name; } -bool Compare_Merc_Spells(MercSpell i, MercSpell j); - -bool Compare_Merc_Spells(MercSpell i, MercSpell j) -{ - return(i.slot > j.slot); -} - bool Merc::LoadMercSpells() { // loads mercs spells into list merc_spells.clear(); @@ -4683,7 +4676,9 @@ bool Merc::LoadMercSpells() { AddProcToWeapon(mercSpellEntryItr->spellid, true, mercSpellEntryItr->proc_chance); } } - std::sort(merc_spells.begin(), merc_spells.end(), Compare_Merc_Spells); + std::sort(merc_spells.begin(), merc_spells.end(), [](const MercSpell& a, const MercSpell& b) { + return a.slot > b.slot; + }); if (merc_spells.size() == 0) AIautocastspell_timer->Disable(); diff --git a/zone/merc.h b/zone/merc.h index f604d485c..3d181a82e 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -287,8 +287,8 @@ protected: uint16 skills[HIGHEST_SKILL+1]; uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs - uint16 d_meele_texture1; //this is an item Material value - uint16 d_meele_texture2; //this is an item Material value (offhand) + uint16 d_melee_texture1; //this is an item Material value + uint16 d_melee_texture2; //this is an item Material value (offhand) uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation diff --git a/zone/mob.cpp b/zone/mob.cpp index 270ca5dc6..66c72e865 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -401,7 +401,7 @@ Mob::Mob(const char* in_name, PathingRouteUpdateTimerLong = new Timer(RuleI(Pathing, RouteUpdateFrequencyLong)); DistractedFromGrid = false; PathingTraversedNodes = 0; - hate_list.SetOwner(this); + hate_list.SetHateOwner(this); m_AllowBeneficial = false; m_DisableMelee = false; @@ -925,7 +925,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) ns->spawn.animation = 0; ns->spawn.findable = findable?1:0; ns->spawn.light = light; - ns->spawn.showhelm = 1; + ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0; ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players ns->spawn.NPC = IsClient() ? 0 : 1; @@ -945,11 +945,11 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) ns->spawn.drakkin_heritage = drakkin_heritage; ns->spawn.drakkin_tattoo = drakkin_tattoo; ns->spawn.drakkin_details = drakkin_details; - ns->spawn.equip_chest2 = texture; + ns->spawn.equip_chest2 = GetHerosForgeModel(1) != 0 ? 0xff : texture; // ns->spawn.invis2 = 0xff;//this used to be labeled beard.. if its not FF it will turn mob invis - if(helmtexture && helmtexture != 0xFF) + if (helmtexture && helmtexture != 0xFF && GetHerosForgeModel(0) == 0) { ns->spawn.helm=helmtexture; } else { @@ -978,7 +978,8 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName)); - for (i = 0; i < _MaterialCount; i++) + //for (i = 0; i < _MaterialCount; i++) + for (i = 0; i < 9; i++) { // Only Player Races Wear Armor if (Mob::IsPlayerRace(race) || i > 6) @@ -2571,8 +2572,8 @@ bool Mob::RemoveFromHateList(Mob* mob) bool bFound = false; if(IsEngaged()) { - bFound = hate_list.RemoveEnt(mob); - if(hate_list.IsEmpty()) + bFound = hate_list.RemoveEntFromHateList(mob); + if(hate_list.IsHateListEmpty()) { AI_Event_NoLongerEngaged(); zone->DelAggroMob(); @@ -2580,7 +2581,7 @@ bool Mob::RemoveFromHateList(Mob* mob) } if(GetTarget() == mob) { - SetTarget(hate_list.GetTop(this)); + SetTarget(hate_list.GetEntWithMostHateOnList(this)); } return bFound; @@ -2590,12 +2591,12 @@ void Mob::WipeHateList() { if(IsEngaged()) { - hate_list.Wipe(); + hate_list.WipeHateList(); AI_Event_NoLongerEngaged(); } else { - hate_list.Wipe(); + hate_list.WipeHateList(); } } @@ -2749,7 +2750,6 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const int32 Mob::GetHerosForgeModel(uint8 material_slot) const { - uint32 HeroModel = 0; if (material_slot >= 0 && material_slot < MaterialPrimary) { @@ -2760,7 +2760,7 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const if (item != 0 && invslot != INVALID_INDEX) { - if (this->IsClient()) + if (IsClient()) { const ItemInst* inst = CastToClient()->m_inv[invslot]; if (inst) @@ -2782,9 +2782,22 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const 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; + } + } } - if (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; @@ -3504,7 +3517,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP } else if (IsPet){ - int count = hate_list.SummonedPetCount(this); + int count = hate_list.GetSummonedPetCountOnHateList(this); if ((base2 >= 220 && base2 <= 250) && count >= (base2 - 220)){ use_spell = true; } diff --git a/zone/mob.h b/zone/mob.h index 431b3ac31..47d2cca2f 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -452,19 +452,19 @@ public: static uint32 GetLevelCon(uint8 mylevel, uint8 iOtherLevel); inline uint32 GetLevelCon(uint8 iOtherLevel) const { return this ? GetLevelCon(GetLevel(), iOtherLevel) : CON_GREEN; } - virtual void AddToHateList(Mob* other, int32 hate = 0, int32 damage = 0, bool iYellForHelp = true, + virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false); bool RemoveFromHateList(Mob* mob); - void SetHate(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.Set(other,hate,damage);} - void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate > 1 ? in_hate / 2 : 1)); } - void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate ? in_hate * 2 : 1)); } - uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHate(tmob,is_dam);} - uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHate(tmob, true);} - Mob* GetHateTop() { return hate_list.GetTop(this);} - Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTop(other);} - Mob* GetHateRandom() { return hate_list.GetRandom();} - Mob* GetHateMost() { return hate_list.GetMostHate();} - bool IsEngaged() { return(!hate_list.IsEmpty()); } + void SetHateAmountOnEnt(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.SetHateAmountOnEnt(other,hate,damage);} + void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate > 1 ? in_hate / 2 : 1)); } + void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate ? in_hate * 2 : 1)); } + uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHateAmount(tmob,is_dam);} + uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHateAmount(tmob, true);} + Mob* GetHateTop() { return hate_list.GetEntWithMostHateOnList(this);} + Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTopOnHateList(other);} + Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();} + Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();} + bool IsEngaged() { return(!hate_list.IsHateListEmpty()); } bool HateSummon(); void FaceTarget(Mob* MobToFace = 0); void SetHeading(float iHeading) { if(heading != iHeading) { pLastChange = Timer::GetCurrentTime(); @@ -473,8 +473,8 @@ public: void AddFeignMemory(Client* attacker); void RemoveFromFeignMemory(Client* attacker); void ClearFeignMemory(); - void PrintHateListToClient(Client *who) { hate_list.PrintToClient(who); } - std::list& GetHateList() { return hate_list.GetHateList(); } + void PrintHateListToClient(Client *who) { hate_list.PrintHateListToClient(who); } + std::list& GetHateList() { return hate_list.GetHateList(); } bool CheckLosFN(Mob* other); bool CheckLosFN(float posX, float posY, float posZ, float mobSize); inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); } @@ -798,7 +798,7 @@ public: void CheckFlee(); inline bool IsBlind() { return spellbonuses.IsBlind; } - inline bool CheckAggro(Mob* other) {return hate_list.IsOnHateList(other);} + inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);} float CalculateHeadingToTarget(float in_x, float in_y); bool CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false); virtual bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 253073d44..910814410 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -493,7 +493,7 @@ void Mob::AI_Start(uint32 iMoveDelay) { pAggroRange = 70; if (GetAssistRange() == 0) pAssistRange = 70; - hate_list.Wipe(); + hate_list.WipeHateList(); delta_heading = 0; delta_x = 0; @@ -553,7 +553,7 @@ void Mob::AI_Stop() { safe_delete(AIscanarea_timer); safe_delete(AIfeignremember_timer); - hate_list.Wipe(); + hate_list.WipeHateList(); } void NPC::AI_Stop() { @@ -816,12 +816,12 @@ void Client::AI_Process() if (engaged) { if (IsRooted()) - SetTarget(hate_list.GetClosest(this)); + SetTarget(hate_list.GetClosestEntOnHateList(this)); else { if(AItarget_check_timer->Check()) { - SetTarget(hate_list.GetTop(this)); + SetTarget(hate_list.GetEntWithMostHateOnList(this)); } } @@ -1041,7 +1041,7 @@ void Mob::AI_Process() { // if(RuleB(Combat, EnableFearPathing)){ if(curfp) { - if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosest(this)))) { + if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) { //make sure everybody knows were not moving, for appearance sake if(IsMoving()) { @@ -1091,18 +1091,18 @@ void Mob::AI_Process() { // we are prevented from getting here if we are blind and don't have a target in range // from above, so no extra blind checks needed if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind()) - SetTarget(hate_list.GetClosest(this)); + SetTarget(hate_list.GetClosestEntOnHateList(this)); else { if(AItarget_check_timer->Check()) { if (IsFocused()) { if (!target) { - SetTarget(hate_list.GetTop(this)); + SetTarget(hate_list.GetEntWithMostHateOnList(this)); } } else { if (!ImprovedTaunt()) - SetTarget(hate_list.GetTop(this)); + SetTarget(hate_list.GetEntWithMostHateOnList(this)); } } @@ -1376,7 +1376,7 @@ void Mob::AI_Process() { //underwater stuff only works with water maps in the zone! if(IsNPC() && CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) { if(!zone->watermap->InLiquid(target->GetX(), target->GetY(), target->GetZ())) { - Mob *tar = hate_list.GetTop(this); + Mob *tar = hate_list.GetEntWithMostHateOnList(this); if(tar == target) { WipeHateList(); Heal(); @@ -2354,7 +2354,6 @@ create table npc_spells_entries ( bool IsSpellInList(DBnpcspells_Struct* spell_list, int16 iSpellID); bool IsSpellEffectInList(DBnpcspellseffects_Struct* spelleffect_list, uint16 iSpellEffectID, int32 base, int32 limit, int32 max); -bool Compare_AI_Spells(AISpells_Struct i, AISpells_Struct j); bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { // ok, this function should load the list, and the parent list then shove them into the struct and sort @@ -2479,7 +2478,9 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { spell_list->entries[i].resist_adjust); } } - std::sort(AIspells.begin(), AIspells.end(), Compare_AI_Spells); + std::sort(AIspells.begin(), AIspells.end(), [](const AISpells_Struct& a, const AISpells_Struct& b) { + return a.priority > b.priority; + }); if (IsValidSpell(attack_proc_spell)) AddProcToWeapon(attack_proc_spell, true, proc_chance); @@ -2619,11 +2620,6 @@ bool IsSpellInList(DBnpcspells_Struct* spell_list, int16 iSpellID) { return false; } -bool Compare_AI_Spells(AISpells_Struct i, AISpells_Struct j) -{ - return(i.priority > j.priority); -} - // adds a spell to the list, taking into account priority and resorting list as needed. void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint16 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust) diff --git a/zone/npc.cpp b/zone/npc.cpp index ddfd1b243..a478e3b51 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -261,8 +261,10 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float if(!IsMerc()) AI_Start(); - d_meele_texture1 = d->d_meele_texture1; - d_meele_texture2 = d->d_meele_texture2; + d_melee_texture1 = d->d_melee_texture1; + d_melee_texture2 = d->d_melee_texture2; + herosforgemodel = d->herosforgemodel; + ammo_idfile = d->ammo_idfile; memset(equipment, 0, sizeof(equipment)); prim_melee_type = d->prim_melee_type; @@ -270,9 +272,9 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float ranged_type = d->ranged_type; // If Melee Textures are not set, set attack type to Hand to Hand as default - if(!d_meele_texture1) + if(!d_melee_texture1) prim_melee_type = 28; - if(!d_meele_texture2) + if(!d_melee_texture2) sec_melee_type = 28; //give NPCs skill values... @@ -498,32 +500,28 @@ void NPC::ClearItemList() { itemlist.clear(); } -void NPC::QueryLoot(Client* to) { - int x = 0; +void NPC::QueryLoot(Client* to) +{ to->Message(0, "Coin: %ip %ig %is %ic", platinum, gold, silver, copper); - ItemList::iterator cur,end; - cur = itemlist.begin(); - end = itemlist.end(); - for(; cur != end; ++cur) { + int x = 0; + for(ItemList::iterator cur = itemlist.begin(); cur != itemlist.end(); ++cur, ++x) { const Item_Struct* item = database.GetItem((*cur)->item_id); - if (item) - if (to->GetClientVersion() >= EQClientRoF) - { - to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X0000000000000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12); - } - else if (to->GetClientVersion() >= EQClientSoF) - { - to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X00000000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12); - } - else - { - to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12); - } - else + if (item == nullptr) { LogFile->write(EQEMuLog::Error, "Database error, invalid item"); - x++; + continue; + } + + Client::TextLink linker; + linker.SetLinkType(linker.linkItemData); + linker.SetItemData(item); + linker.SetClientVersion(to->GetClientVersion()); + + auto item_link = linker.GenerateLink(); + + to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), item->ID, (*cur)->min_level, (*cur)->max_level); } + to->Message(0, "%i items on %s.", x, GetName()); } @@ -924,8 +922,8 @@ NPC* NPC::SpawnNPC(const char* spawncommand, float in_x, float in_y, float in_z, npc_type->texture = atoi(sep.arg[3]); npc_type->light = 0; npc_type->runspeed = 1.25; - npc_type->d_meele_texture1 = atoi(sep.arg[7]); - npc_type->d_meele_texture2 = atoi(sep.arg[8]); + npc_type->d_melee_texture1 = atoi(sep.arg[7]); + npc_type->d_melee_texture2 = atoi(sep.arg[8]); npc_type->merchanttype = atoi(sep.arg[9]); npc_type->bodytype = atoi(sep.arg[10]); @@ -957,7 +955,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, float in_x, float in_y, float in_z, client->Message(0, "Current/Max HP: %i", npc->max_hp); client->Message(0, "Gender: %u", npc->gender); client->Message(0, "Class: %u", npc->class_); - client->Message(0, "Weapon Item Number: %u/%u", npc->d_meele_texture1, npc->d_meele_texture2); + client->Message(0, "Weapon Item Number: %u/%u", npc->d_melee_texture1, npc->d_melee_texture2); client->Message(0, "MerchantID: %u", npc->MerchantType); client->Message(0, "Bodytype: %u", npc->bodytype); } @@ -1335,9 +1333,9 @@ int32 NPC::GetEquipmentMaterial(uint8 material_slot) const case MaterialChest: return texture; case MaterialPrimary: - return d_meele_texture1; + return d_melee_texture1; case MaterialSecondary: - return d_meele_texture2; + return d_melee_texture2; default: //they have nothing in the slot, and its not a special slot... they get nothing. return(0); @@ -2136,10 +2134,10 @@ uint32 NPC::GetSpawnPointID() const void NPC::NPCSlotTexture(uint8 slot, uint16 texture) { if (slot == 7) { - d_meele_texture1 = texture; + d_melee_texture1 = texture; } else if (slot == 8) { - d_meele_texture2 = texture; + d_melee_texture2 = texture; } else if (slot < 6) { // Reserved for texturing individual armor slots diff --git a/zone/npc.h b/zone/npc.h index 59fbcc3fd..72cc7f38c 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -249,8 +249,8 @@ public: inline int32 GetNPCFactionID() const { return npc_faction_id; } inline int32 GetPrimaryFaction() const { return primary_faction; } - int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHate(in_ent);} - bool IsOnHatelist(Mob*p) { return hate_list.IsOnHateList(p);} + int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHateAmount(in_ent);} + bool IsOnHatelist(Mob*p) { return hate_list.IsEntOnHateList(p);} void SetNPCFactionID(int32 in) { npc_faction_id = in; database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction); } @@ -403,6 +403,9 @@ public: void mod_npc_killed(Mob* oos); void AISpellsList(Client *c); + uint32 GetHeroForgeModel() const { return herosforgemodel; } + void SetHeroForgeModel(uint32 model) { herosforgemodel = model; } + bool IsRaidTarget() const { return raid_target; }; protected: @@ -492,8 +495,10 @@ protected: uint16 skills[HIGHEST_SKILL+1]; uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs - uint16 d_meele_texture1; //this is an item Material value - uint16 d_meele_texture2; //this is an item Material value (offhand) + + uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203) + uint16 d_melee_texture1; //this is an item Material value + uint16 d_melee_texture2; //this is an item Material value (offhand) const char* ammo_idfile; //this determines projectile graphic "IT###" (see item field 'idfile') uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation diff --git a/zone/object.cpp b/zone/object.cpp index fa7598d39..97832a6f8 100644 --- a/zone/object.cpp +++ b/zone/object.cpp @@ -118,7 +118,15 @@ Object::Object(Client* client, const ItemInst* inst) m_data.heading = client->GetHeading(); m_data.x = client->GetX(); m_data.y = client->GetY(); - m_data.z = client->GetZ(); + if (client->GetClientVersion() >= EQClientRoF2) + { + // RoF2 places items at player's Z, which is 0.625 of their height. + m_data.z = client->GetZ() - (client->GetSize() * 0.625f); + } + else + { + m_data.z = client->GetZ(); + } m_data.zone_id = zone->GetZoneID(); decay_timer.Start(); diff --git a/zone/pathing.cpp b/zone/pathing.cpp index 2ddd7d94b..b58e4ae2e 100644 --- a/zone/pathing.cpp +++ b/zone/pathing.cpp @@ -345,10 +345,10 @@ bool CheckLOSBetweenPoints(Map::Vertex start, Map::Vertex end) { return true; } -bool SortPathNodesByDistance(PathNodeSortStruct n1, PathNodeSortStruct n2) +auto path_compare = [](const PathNodeSortStruct& a, const PathNodeSortStruct& b) { - return n1.Distance < n2.Distance; -} + return a.Distance < b.Distance; +}; std::deque PathManager::FindRoute(Map::Vertex Start, Map::Vertex End) { @@ -382,7 +382,7 @@ std::deque PathManager::FindRoute(Map::Vertex Start, Map::Vertex End) } } - std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance); + std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) { @@ -420,7 +420,7 @@ std::deque PathManager::FindRoute(Map::Vertex Start, Map::Vertex End) } } - std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance); + std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) { @@ -573,8 +573,8 @@ void PathManager::SpawnPathNodes() npc_type->texture = 1; npc_type->light = 0; npc_type->runspeed = 0; - npc_type->d_meele_texture1 = 1; - npc_type->d_meele_texture2 = 1; + npc_type->d_melee_texture1 = 1; + npc_type->d_melee_texture2 = 1; npc_type->merchanttype = 1; npc_type->bodytype = 1; @@ -1120,7 +1120,7 @@ int PathManager::FindNearestPathNode(Map::Vertex Position) } } - std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance); + std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) { @@ -1561,8 +1561,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques npc_type->texture = 1; npc_type->light = 0; npc_type->runspeed = 0; - npc_type->d_meele_texture1 = 1; - npc_type->d_meele_texture2 = 1; + npc_type->d_melee_texture1 = 1; + npc_type->d_melee_texture2 = 1; npc_type->merchanttype = 1; npc_type->bodytype = 1; npc_type->STR = 150; @@ -1621,8 +1621,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques npc_type->texture = 1; npc_type->light = 0; npc_type->runspeed = 0; - npc_type->d_meele_texture1 = 1; - npc_type->d_meele_texture2 = 1; + npc_type->d_melee_texture1 = 1; + npc_type->d_melee_texture2 = 1; npc_type->merchanttype = 1; npc_type->bodytype = 1; npc_type->STR = 150; diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index e2dae6f35..d3cec99e2 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -5057,14 +5057,21 @@ XS(XS_Client_UpdateTaskActivity); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_UpdateTaskActivity) { dXSARGS; - if (items != 4) - Perl_croak(aTHX_ "Usage: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count)"); + if (items < 4) + Perl_croak(aTHX_ "Usage: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count, [ignore_quest_update])"); { + bool ignore_quest_update = false; + Client * THIS; + int TaskID = (int)SvIV(ST(1)); int ActivityID = (int)SvIV(ST(2)); int Count = (int)SvUV(ST(3)); + if (items == 5){ + ignore_quest_update = (bool)SvTRUE(ST(4)); + } + if (sv_derived_from(ST(0), "Client")) { IV tmp = SvIV((SV*)SvRV(ST(0))); THIS = INT2PTR(Client *,tmp); @@ -5074,7 +5081,7 @@ XS(XS_Client_UpdateTaskActivity) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->UpdateTaskActivity(TaskID, ActivityID, Count); + THIS->UpdateTaskActivity(TaskID, ActivityID, Count, ignore_quest_update); } XSRETURN_EMPTY; } @@ -6305,7 +6312,7 @@ XS(boot_Client) newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, file, "$"); newXSproto(strcpy(buf, "GetFreeSpellBookSlot"), XS_Client_GetFreeSpellBookSlot, file, "$;$"); newXSproto(strcpy(buf, "GetSpellBookSlotBySpellID"), XS_Client_GetSpellBookSlotBySpellID, file, "$$"); - newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$"); + newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$;$"); newXSproto(strcpy(buf, "AssignTask"), XS_Client_AssignTask, file, "$$$"); newXSproto(strcpy(buf, "FailTask"), XS_Client_FailTask, file, "$$"); newXSproto(strcpy(buf, "IsTaskCompleted"), XS_Client_IsTaskCompleted, file, "$$"); diff --git a/zone/perl_hateentry.cpp b/zone/perl_hateentry.cpp index fa65e8b39..6e8b2de9e 100644 --- a/zone/perl_hateentry.cpp +++ b/zone/perl_hateentry.cpp @@ -40,19 +40,19 @@ XS(XS_HateEntry_GetEnt) if (items != 1) Perl_croak(aTHX_ "Usage: HateEntry::GetData(THIS)"); { - tHateEntry * THIS; + struct_HateList * THIS; Mob * RETVAL; if (sv_derived_from(ST(0), "HateEntry")) { IV tmp = SvIV((SV*)SvRV(ST(0))); - THIS = INT2PTR(tHateEntry *,tmp); + THIS = INT2PTR(struct_HateList *,tmp); } else Perl_croak(aTHX_ "THIS is not of type tHateEntry"); if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->ent; + RETVAL = THIS->entity_on_hatelist; ST(0) = sv_newmortal(); sv_setref_pv(ST(0), "Mob", (void*)RETVAL); } @@ -66,20 +66,20 @@ XS(XS_HateEntry_GetHate) if (items != 1) Perl_croak(aTHX_ "Usage: HateEntry::GetHate(THIS)"); { - tHateEntry * THIS; + struct_HateList * THIS; int32 RETVAL; dXSTARG; if (sv_derived_from(ST(0), "HateEntry")) { IV tmp = SvIV((SV*)SvRV(ST(0))); - THIS = INT2PTR(tHateEntry *,tmp); + THIS = INT2PTR(struct_HateList *,tmp); } else Perl_croak(aTHX_ "THIS is not of type tHateEntry"); if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->hate; + RETVAL = THIS->stored_hate_amount; XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); @@ -92,20 +92,20 @@ XS(XS_HateEntry_GetDamage) if (items != 1) Perl_croak(aTHX_ "Usage: HateEntry::GetDamage(THIS)"); { - tHateEntry * THIS; + struct_HateList * THIS; int32 RETVAL; dXSTARG; if (sv_derived_from(ST(0), "HateEntry")) { IV tmp = SvIV((SV*)SvRV(ST(0))); - THIS = INT2PTR(tHateEntry *,tmp); + THIS = INT2PTR(struct_HateList *,tmp); } else Perl_croak(aTHX_ "THIS is not of type tHateEntry"); if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->damage; + RETVAL = THIS->hatelist_damage; XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 4351fb89f..7977c3dd1 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -5354,7 +5354,7 @@ XS(XS_Mob_SetHate) damage = (int32)SvIV(ST(3)); } - THIS->SetHate(other, hate, damage); + THIS->SetHateAmountOnEnt(other, hate, damage); } XSRETURN_EMPTY; } @@ -6599,7 +6599,7 @@ XS(XS_Mob_GetHateList) while(iter != hate_list.end()) { - tHateEntry *entry = (*iter); + struct_HateList *entry = (*iter); ST(0) = sv_newmortal(); sv_setref_pv(ST(0), "HateEntry", (void*)entry); XPUSHs(ST(0)); diff --git a/zone/pets.cpp b/zone/pets.cpp index 5c1f4e0cd..6bd92cdca 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -393,6 +393,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, npc_type->gender = monster->gender; npc_type->luclinface = monster->luclinface; npc_type->helmtexture = monster->helmtexture; + npc_type->herosforgemodel = monster->herosforgemodel; } else LogFile->write(EQEMuLog::Error, "Error loading NPC data for monster summoning pet (NPC ID %d)", monsterid); diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index c0680b43f..d3bde0d5b 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -200,6 +200,9 @@ bool QuestParserCollection::SpellHasQuestSub(uint32 spell_id, QuestEventID evt) } bool QuestParserCollection::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) { + if (itm == nullptr) + return false; + std::string item_script; if(itm->GetItem()->ScriptFileID != 0) { item_script = "script_"; @@ -350,6 +353,8 @@ int QuestParserCollection::EventPlayerGlobal(QuestEventID evt, Client *client, s int QuestParserCollection::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { + // needs pointer validation check on 'item' argument + std::string item_script; if(item->GetItem()->ScriptFileID != 0) { item_script = "script_"; diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index ab68f8361..3fb714d7e 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -1227,13 +1227,18 @@ void QuestManager::settime(uint8 new_hour, uint8 new_min) { void QuestManager::itemlink(int item_id) { QuestManagerCurrentQuestVars(); if (initiator) { - const ItemInst* inst = database.CreateItem(item_id); - char* link = 0; - if (initiator->MakeItemLink(link, inst)) - initiator->Message(0, "%s tells you, %c%s%s%c", owner->GetCleanName(), - 0x12, link, inst->GetItem()->Name, 0x12); - safe_delete_array(link); - safe_delete(inst); + const Item_Struct* item = database.GetItem(item_id); + if (item == nullptr) + return; + + Client::TextLink linker; + linker.SetLinkType(linker.linkItemData); + linker.SetItemData(item); + linker.SetClientVersion(initiator->GetClientVersion()); + + auto item_link = linker.GenerateLink(); + + initiator->Message(0, "%s tells you, %s", owner->GetCleanName(), item_link.c_str()); } } @@ -2103,11 +2108,12 @@ int QuestManager::gettaskactivitydonecount(int task, int activity) { } -void QuestManager::updatetaskactivity(int task, int activity, int count) { +void QuestManager::updatetaskactivity(int task, int activity, int count, bool ignore_quest_update /*= false*/) +{ QuestManagerCurrentQuestVars(); if(RuleB(TaskSystem, EnableTaskSystem) && initiator) - initiator->UpdateTaskActivity(task, activity, count); + initiator->UpdateTaskActivity(task, activity, count, ignore_quest_update); } void QuestManager::resettaskactivity(int task, int activity) { @@ -2336,7 +2342,7 @@ int QuestManager::collectitems_processSlot(int16 slot_id, uint32 item_id, bool remove) { QuestManagerCurrentQuestVars(); - ItemInst *item; + ItemInst *item = nullptr; int quantity = 0; item = initiator->GetInv().GetItem(slot_id); @@ -2461,16 +2467,19 @@ uint32 QuestManager::MerchantCountItem(uint32 NPCid, uint32 itemid) { // Item Link for use in Variables - "my $example_link = quest::varlink(item_id);" const char* QuestManager::varlink(char* perltext, int item_id) { QuestManagerCurrentQuestVars(); - const ItemInst* inst = database.CreateItem(item_id); - if (!inst) + const Item_Struct* item = database.GetItem(item_id); + if (!item) return "INVALID ITEM ID IN VARLINK"; - char* link = 0; - char* tempstr = 0; - if (initiator->MakeItemLink(link, inst)) { // make a link to the item - snprintf(perltext, 250, "%c%s%s%c", 0x12, link, inst->GetItem()->Name, 0x12); - } - safe_delete_array(link); // MakeItemLink() uses new also - safe_delete(inst); + + Client::TextLink linker; + linker.SetLinkType(linker.linkItemData); + linker.SetItemData(item); + if (initiator) + linker.SetClientVersion(initiator->GetClientVersion()); + + auto item_link = linker.GenerateLink(); + strcpy(perltext, item_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink() + return perltext; } @@ -2656,24 +2665,16 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam sayid = sayid + 500000; //Create the say link as an item link hash - char linktext[250]; + Client::TextLink linker; + linker.SetProxyItemID(sayid); + linker.SetProxyText(LinkName); + if (initiator) + linker.SetClientVersion(initiator->GetClientVersion()); - if (initiator) { - if (initiator->GetClientVersion() >= EQClientRoF2) - sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000000000", LinkName, 0x12); - else if (initiator->GetClientVersion() >= EQClientRoF) - sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "0000000000000000000000000000000000000000000000000", LinkName, 0x12); - else if (initiator->GetClientVersion() >= EQClientSoF) - sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000", LinkName, 0x12); - else - sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "000000000000000000000000000000000000000", LinkName, 0x12); - } else { // If no initiator, create an RoF2 saylink, since older clients handle RoF2 ones better than RoF2 handles older ones. - sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000000000", LinkName, 0x12); - } + auto say_link = linker.GenerateLink(); + strcpy(Phrase, say_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink() - strcpy(Phrase,linktext); return Phrase; - } const char* QuestManager::getguildnamebyid(int guild_id) { diff --git a/zone/questmgr.h b/zone/questmgr.h index 4749599ad..14a6c429c 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -183,7 +183,7 @@ public: bool istaskactive(int task); bool istaskactivityactive(int task, int activity); int gettaskactivitydonecount(int task, int activity); - void updatetaskactivity(int task, int activity, int count); + void updatetaskactivity(int task, int activity, int count, bool ignore_quest_update = false); void resettaskactivity(int task, int activity); void taskexploredarea(int exploreid); void assigntask(int taskid); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index f74949a0b..94da26e45 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -106,7 +106,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, if(who->GetInvul() || who->GetSpecialAbility(IMMUNE_MELEE) || who->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)) return; //-5? - int32 hate = max_damage; + uint32 hate = max_damage; if(hate_override > -1) hate = hate_override; @@ -583,7 +583,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) int32 ndamage = 0; int32 max_hit = 0; int32 min_hit = 0; - int32 hate = 0; + uint32 hate = 0; int32 primaryweapondamage = 0; int32 backstab_dmg = 0; @@ -889,7 +889,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite if (HeadShot_Dmg) HeadShot = true; - int32 hate = 0; + uint32 hate = 0; int32 TotalDmg = 0; int16 WDmg = 0; int16 ADmg = 0; @@ -2354,7 +2354,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse = SkillOffense; int damage = 0; - int32 hate = 0; + uint32 hate = 0; int Hand = MainPrimary; if (hate == 0 && weapon_damage > 1) hate = weapon_damage; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 56611024b..6b9eed9c0 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1897,10 +1897,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (CalculatePoisonCounters(buffs[j].spellid) == 0) continue; if (effect_value >= static_cast(buffs[j].counters)) { - if (caster) + if (caster) { caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name); caster->CastOnCurer(buffs[j].spellid); CastOnCure(buffs[j].spellid); + } effect_value -= buffs[j].counters; buffs[j].counters = 0; BuffFadeBySlot(j); @@ -1930,10 +1931,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) continue; if (effect_value >= static_cast(buffs[j].counters)) { - if (caster) + if (caster) { caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name); caster->CastOnCurer(buffs[j].spellid); CastOnCure(buffs[j].spellid); + } effect_value -= buffs[j].counters; buffs[j].counters = 0; BuffFadeBySlot(j); @@ -1965,10 +1967,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) continue; if (effect_value >= static_cast(buffs[j].counters)) { - if (caster) + if (caster) { caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name); caster->CastOnCurer(buffs[j].spellid); CastOnCure(buffs[j].spellid); + } effect_value -= buffs[j].counters; buffs[j].counters = 0; BuffFadeBySlot(j); @@ -1999,10 +2002,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (CalculateCorruptionCounters(buffs[j].spellid) == 0) continue; if (effect_value >= static_cast(buffs[j].counters)) { - if (caster) + if (caster) { caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name); caster->CastOnCurer(buffs[j].spellid); CastOnCure(buffs[j].spellid); + } effect_value -= buffs[j].counters; buffs[j].counters = 0; BuffFadeBySlot(j); @@ -2658,7 +2662,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) caster->Taunt(this->CastToNPC(), false, static_cast(spell.base[i])); if (spell.base2[i] > 0) - CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i])); + CastToNPC()->SetHateAmountOnEnt(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i])); } break; } @@ -2689,7 +2693,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (new_hate <= 0) new_hate = 1; - CastToNPC()->SetHate(caster, new_hate); + CastToNPC()->SetHateAmountOnEnt(caster, new_hate); } break; } @@ -2710,9 +2714,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) }else{ int32 newhate = GetHateAmount(caster) + effect_value; if (newhate < 1) - SetHate(caster,1); + SetHateAmountOnEnt(caster,1); else - SetHate(caster,newhate); + SetHateAmountOnEnt(caster,newhate); } } break; @@ -3542,9 +3546,9 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste }else{ int32 newhate = GetHateAmount(caster) + effect_value; if (newhate < 1) { - SetHate(caster,1); + SetHateAmountOnEnt(caster,1); } else { - SetHate(caster,newhate); + SetHateAmountOnEnt(caster,newhate); } } } @@ -3724,11 +3728,11 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste case SE_AddHateOverTimePct: { if (IsNPC()){ - int32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100; + uint32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100; if (new_hate <= 0) new_hate = 1; - CastToNPC()->SetHate(caster, new_hate); + CastToNPC()->SetHateAmountOnEnt(caster, new_hate); } break; } @@ -6420,7 +6424,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama //Limit to amount of pets if (value >= 221 && value <= 249){ - int count = hate_list.SummonedPetCount(this); + int count = hate_list.GetSummonedPetCountOnHateList(this); for (int base2_value = 221; base2_value <= 249; ++base2_value){ if (value == base2_value){ diff --git a/zone/spells.cpp b/zone/spells.cpp index 0828d6388..ce5d9df8d 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1195,22 +1195,29 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, uint32 recastdelay = 0; uint32 recasttype = 0; - for (int r = 0; r < EmuConstants::ITEM_COMMON_SIZE; r++) { - const ItemInst* aug_i = inst->GetAugment(r); - - if(!aug_i) - continue; - const Item_Struct* aug = aug_i->GetItem(); - if(!aug) - continue; - - if ( aug->Click.Effect == spell_id ) - { - recastdelay = aug_i->GetItem()->RecastDelay; - recasttype = aug_i->GetItem()->RecastType; - fromaug = true; + while (true) { + if (inst == nullptr) break; + + for (int r = AUG_BEGIN; r < EmuConstants::ITEM_COMMON_SIZE; r++) { + const ItemInst* aug_i = inst->GetAugment(r); + + if (!aug_i) + continue; + const Item_Struct* aug = aug_i->GetItem(); + if (!aug) + continue; + + if (aug->Click.Effect == spell_id) + { + recastdelay = aug_i->GetItem()->RecastDelay; + recasttype = aug_i->GetItem()->RecastType; + fromaug = true; + break; + } } + + break; } //Test the aug recast delay @@ -3649,11 +3656,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r spelltar->AddToHateList(this, aggro); } else{ - int32 newhate = spelltar->GetHateAmount(this) + aggro; + uint32 newhate = spelltar->GetHateAmount(this) + aggro; if (newhate < 1) { - spelltar->SetHate(this,1); + spelltar->SetHateAmountOnEnt(this,1); } else { - spelltar->SetHate(this,newhate); + spelltar->SetHateAmountOnEnt(this,newhate); } } } @@ -3681,9 +3688,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r spelltar->AddToHateList(this, aggro_amount); else{ int32 newhate = spelltar->GetHateAmount(this) + aggro_amount; if (newhate < 1) { - spelltar->SetHate(this,1); + spelltar->SetHateAmountOnEnt(this,1); } else { - spelltar->SetHate(this,newhate); + spelltar->SetHateAmountOnEnt(this,newhate); } } } @@ -3896,6 +3903,8 @@ void Mob::BuffFadeDetrimental() { BuffFadeBySlot(j, false); } } + //we tell BuffFadeBySlot not to recalc, so we can do it only once when were done + CalcBonuses(); } void Mob::BuffFadeDetrimentalByCaster(Mob *caster) @@ -3916,6 +3925,8 @@ void Mob::BuffFadeDetrimentalByCaster(Mob *caster) } } } + //we tell BuffFadeBySlot not to recalc, so we can do it only once when were done + CalcBonuses(); } void Mob::BuffFadeBySitModifier() @@ -4195,6 +4206,10 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use //Get resist modifier and adjust it based on focus 2 resist about eq to 1% resist chance int resist_modifier = (use_resist_override) ? resist_override : spells[spell_id].ResistDiff; + + if(caster->GetSpecialAbility(CASTING_RESIST_DIFF)) + resist_modifier += caster->GetSpecialAbilityParam(CASTING_RESIST_DIFF, 0); + int focus_resist = caster->GetFocusEffect(focusResistRate, spell_id); resist_modifier -= 2 * focus_resist; diff --git a/zone/tasks.cpp b/zone/tasks.cpp index 1e73e3150..79efb1115 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -1786,7 +1786,7 @@ void ClientTaskState::UpdateTasksOnTouch(Client *c, int ZoneID) { return; } -void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int TaskIndex, int ActivityID, int Count) { +void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int TaskIndex, int ActivityID, int Count, bool ignore_quest_update) { _log(TASKS__UPDATE, "IncrementDoneCount"); @@ -1795,10 +1795,12 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T if(ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount > Task->Activity[ActivityID].GoalCount) ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount = Task->Activity[ActivityID].GoalCount; - char buf[24]; - snprintf(buf, 23, "%d %d %d", ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].TaskID); - buf[23] = '\0'; - parse->EventPlayer(EVENT_TASK_UPDATE, c, buf, 0); + if (!ignore_quest_update){ + char buf[24]; + snprintf(buf, 23, "%d %d %d", ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].TaskID); + buf[23] = '\0'; + parse->EventPlayer(EVENT_TASK_UPDATE, c, buf, 0); + } ActiveTasks[TaskIndex].Activity[ActivityID].Updated=true; // Have we reached the goal count for this activity ? @@ -1821,11 +1823,12 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T c->Message(0, "Your task '%s' has been updated.", Task->Title); if(Task->Activity[ActivityID].GoalMethod != METHODQUEST) { - char buf[24]; - snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID); - buf[23] = '\0'; - parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0); - + if (!ignore_quest_update){ + char buf[24]; + snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID); + buf[23] = '\0'; + parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0); + } /* QS: PlayerLogTaskUpdates :: Update */ if (RuleB(QueryServ, PlayerLogTaskUpdates)){ std::string event_desc = StringFormat("Task Stage Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID()); @@ -2039,7 +2042,8 @@ bool ClientTaskState::IsTaskActivityActive(int TaskID, int ActivityID) { } -void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count) { +void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count, bool ignore_quest_update /*= false*/) +{ _log(TASKS__UPDATE, "ClientTaskState UpdateTaskActivity(%i, %i, %i).", TaskID, ActivityID, Count); @@ -2048,8 +2052,8 @@ void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int ActiveTaskIndex = -1; - for(int i=0; i=MAXTASKS) || !Tasks[TaskID]) return; +void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceNumber, int StartTime, int Duration, bool BringUpTaskJournal) +{ + if ((TaskID < 1) || (TaskID >= MAXTASKS) || !Tasks[TaskID]) + return; int PacketLength = sizeof(TaskDescriptionHeader_Struct) + strlen(Tasks[TaskID]->Title) + 1 + sizeof(TaskDescriptionData1_Struct) + strlen(Tasks[TaskID]->Description) + 1 + sizeof(TaskDescriptionData2_Struct) + 1 + sizeof(TaskDescriptionTrailer_Struct); std::string RewardText; - int ItemID = 0; + int ItemID = NOT_USED; // If there is an item make the Reward text into a link to the item (only the first item if a list // is specified). I have been unable to get multiple item links to work. @@ -2768,62 +2772,20 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN if(ItemID < 0) ItemID = 0; } + if(ItemID) { - char *RewardTmp = 0; - if(strlen(Tasks[TaskID]->Reward) != 0) { + const Item_Struct* reward_item = database.GetItem(ItemID); - switch(c->GetClientVersion()) { - case EQClientTitanium: - { - MakeAnyLenString(&RewardTmp, "%c%06X000000000000000000000000000000014505DC2%s%c", - 0x12, ItemID, Tasks[TaskID]->Reward,0x12); - break; - } - case EQClientRoF: - { - MakeAnyLenString(&RewardTmp, "%c%06X0000000000000000000000000000000000000000014505DC2%s%c", - 0x12, ItemID, Tasks[TaskID]->Reward,0x12); - break; - } - default: - { - // All clients after Titanium - MakeAnyLenString(&RewardTmp, "%c%06X00000000000000000000000000000000000014505DC2%s%c", - 0x12, ItemID, Tasks[TaskID]->Reward,0x12); - } - } + Client::TextLink linker; + linker.SetLinkType(linker.linkItemData); + linker.SetItemData(reward_item); + linker.SetClientVersion(c->GetClientVersion()); + linker.SetTaskUse(); + if (strlen(Tasks[TaskID]->Reward) != 0) + linker.SetProxyText(Tasks[TaskID]->Reward); - } - else { - const Item_Struct *Item = database.GetItem(ItemID); - - if(Item) { - - switch(c->GetClientVersion()) { - case EQClientTitanium: - { - MakeAnyLenString(&RewardTmp, "%c%06X000000000000000000000000000000014505DC2%s%c", - 0x12, ItemID, Item->Name ,0x12); - break; - } - case EQClientRoF: - { - MakeAnyLenString(&RewardTmp, "%c%06X0000000000000000000000000000000000000000014505DC2%s%c", - 0x12, ItemID, Item->Name ,0x12); - break; - } - default: - { - // All clients after Titanium - MakeAnyLenString(&RewardTmp, "%c%06X00000000000000000000000000000000000014505DC2%s%c", - 0x12, ItemID, Item->Name ,0x12); - } - } - } - } - - if(RewardTmp) RewardText += RewardTmp; - safe_delete_array(RewardTmp); + auto reward_link = linker.GenerateLink(); + RewardText += reward_link.c_str(); } else { RewardText += Tasks[TaskID]->Reward; diff --git a/zone/tasks.h b/zone/tasks.h index 6298fcb5c..c525bbcd8 100644 --- a/zone/tasks.h +++ b/zone/tasks.h @@ -175,7 +175,7 @@ public: bool IsTaskActive(int TaskID); bool IsTaskActivityActive(int TaskID, int ActivityID); ActivityState GetTaskActivityState(int index, int ActivityID); - void UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count); + void UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count, bool ignore_quest_update = false); void ResetTaskActivity(Client *c, int TaskID, int ActivityID); void CancelTask(Client *c, int SequenceNumber, bool RemoveFromDB = true); void CancelAllTasks(Client *c); @@ -204,7 +204,7 @@ public: private: bool UnlockActivities(int CharID, int TaskIndex); - void IncrementDoneCount(Client *c, TaskInformation *Task, int TaskIndex, int ActivityID, int Count=1); + void IncrementDoneCount(Client *c, TaskInformation *Task, int TaskIndex, int ActivityID, int Count = 1, bool ignore_quest_update = false); int ActiveTaskCount; ClientTaskInformation ActiveTasks[MAXACTIVETASKS]; std::vectorEnabledTasks; diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index f6112b560..453a8474b 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -94,7 +94,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme return; } - ItemInst *tobe_auged, *auged_with = nullptr; + ItemInst *tobe_auged = nullptr, *auged_with = nullptr; int8 slot=-1; // Verify 2 items in the augmentation device @@ -1185,6 +1185,8 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec) { + if (container == nullptr) + return false; std::string containers;// make where clause segment for container(s) if (some_id == 0) diff --git a/zone/trading.cpp b/zone/trading.cpp index b9b582bfe..7d66adb30 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -159,6 +159,9 @@ Mob* Trade::With() // Private Method: Send item data for trade item to other person involved in trade void Trade::SendItemData(const ItemInst* inst, int16 dest_slot_id) { + if (inst == nullptr) + return; + // @merth: This needs to be redone with new item classes Mob* mob = With(); if (!mob->IsClient()) diff --git a/zone/trap.cpp b/zone/trap.cpp index 27b12c26d..182cc8915 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -315,8 +315,8 @@ void Trap::CreateHiddenTrigger() make_npc->gender = 0; make_npc->loottable_id = 0; make_npc->npc_spells_id = 0; - make_npc->d_meele_texture1 = 0; - make_npc->d_meele_texture2 = 0; + make_npc->d_melee_texture1 = 0; + make_npc->d_melee_texture2 = 0; make_npc->trackable = 0; make_npc->level = level; strcpy(make_npc->special_abilities, "19,1^20,1^24,1^25,1"); diff --git a/zone/water_map.h b/zone/water_map.h index 2141a3000..cc1887f10 100644 --- a/zone/water_map.h +++ b/zone/water_map.h @@ -21,15 +21,15 @@ class WaterMap { public: WaterMap() { } - ~WaterMap() { } - + virtual ~WaterMap() { } + static WaterMap* LoadWaterMapfile(std::string zone_name); virtual WaterRegionType ReturnRegionType(float y, float x, float z) const { return RegionTypeNormal; } virtual bool InWater(float y, float x, float z) const { return false; } virtual bool InVWater(float y, float x, float z) const { return false; } virtual bool InLava(float y, float x, float z) const { return false; } virtual bool InLiquid(float y, float x, float z) const { return false; } - + protected: virtual bool Load(FILE *fp) { return false; } }; diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index e2604a3af..da5ecb7bc 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -391,7 +391,9 @@ void NPC::GetClosestWaypoint(std::list &wp_list, int count, float m_x, f w_dist.index = i; distances.push_back(w_dist); } - distances.sort(wp_distance_pred); + distances.sort([](const wp_distance& a, const wp_distance& b) { + return a.dist < b.dist; + }); std::list::iterator iter = distances.begin(); for(int i = 0; i < count; ++i) @@ -694,7 +696,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b { Map::Vertex dest(x_pos, y_pos, z_pos); - float newz = zone->zonemap->FindBestZ(dest, nullptr); + 2.0f; + float newz = zone->zonemap->FindBestZ(dest, nullptr); mlog(AI__WAYPOINTS, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,x_pos,y_pos,z_pos); diff --git a/zone/zone.cpp b/zone/zone.cpp index 8d8085f22..a5a91c620 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -2234,7 +2234,10 @@ void Zone::LoadNPCEmotes(LinkedList* NPCEmoteList) } void Zone::ReloadWorld(uint32 Option){ - if(Option == 1){ + if (Option == 0) { + entity_list.ClearAreas(); + parse->ReloadQuests(); + } else if(Option == 1) { zone->Repop(0); entity_list.ClearAreas(); parse->ReloadQuests(); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index deff17e91..d067411e6 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1740,15 +1740,15 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { // according to spawn2. std::string query = StringFormat("SELECT npc_types.id, npc_types.name, npc_types.level, npc_types.race, " "npc_types.class, npc_types.hp, npc_types.mana, npc_types.gender, " - "npc_types.texture, npc_types.helmtexture, npc_types.size, " + "npc_types.texture, npc_types.helmtexture, npc_types.herosforgemodel, npc_types.size, " "npc_types.loottable_id, npc_types.merchant_id, npc_types.alt_currency_id, " "npc_types.adventure_template_id, npc_types.trap_template, npc_types.attack_speed, " "npc_types.STR, npc_types.STA, npc_types.DEX, npc_types.AGI, npc_types._INT, " "npc_types.WIS, npc_types.CHA, npc_types.MR, npc_types.CR, npc_types.DR, " "npc_types.FR, npc_types.PR, npc_types.Corrup, npc_types.PhR," "npc_types.mindmg, npc_types.maxdmg, npc_types.attack_count, npc_types.special_abilities," - "npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_meele_texture1," - "npc_types.d_meele_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type," + "npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_melee_texture1," + "npc_types.d_melee_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type," "npc_types.sec_melee_type, npc_types.ranged_type, npc_types.runspeed, npc_types.findable," "npc_types.trackable, npc_types.hp_regen_rate, npc_types.mana_regen_rate, " "npc_types.aggroradius, npc_types.assistradius, npc_types.bodytype, npc_types.npc_faction_id, " @@ -1790,88 +1790,86 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { tmpNPCType->gender = atoi(row[7]); tmpNPCType->texture = atoi(row[8]); tmpNPCType->helmtexture = atoi(row[9]); - tmpNPCType->size = atof(row[10]); - tmpNPCType->loottable_id = atoi(row[11]); - tmpNPCType->merchanttype = atoi(row[12]); - tmpNPCType->alt_currency_type = atoi(row[13]); - tmpNPCType->adventure_template = atoi(row[14]); - tmpNPCType->trap_template = atoi(row[15]); - tmpNPCType->attack_speed = atof(row[16]); - tmpNPCType->STR = atoi(row[17]); - tmpNPCType->STA = atoi(row[18]); - tmpNPCType->DEX = atoi(row[19]); - tmpNPCType->AGI = atoi(row[20]); - tmpNPCType->INT = atoi(row[21]); - tmpNPCType->WIS = atoi(row[22]); - tmpNPCType->CHA = atoi(row[23]); - tmpNPCType->MR = atoi(row[24]); - tmpNPCType->CR = atoi(row[25]); - tmpNPCType->DR = atoi(row[26]); - tmpNPCType->FR = atoi(row[27]); - tmpNPCType->PR = atoi(row[28]); - tmpNPCType->Corrup = atoi(row[29]); - tmpNPCType->PhR = atoi(row[30]); - tmpNPCType->min_dmg = atoi(row[31]); - tmpNPCType->max_dmg = atoi(row[32]); - tmpNPCType->attack_count = atoi(row[33]); + tmpNPCType->herosforgemodel = atoul(row[10]); + tmpNPCType->size = atof(row[11]); + tmpNPCType->loottable_id = atoi(row[12]); + tmpNPCType->merchanttype = atoi(row[13]); + tmpNPCType->alt_currency_type = atoi(row[14]); + tmpNPCType->adventure_template = atoi(row[15]); + tmpNPCType->trap_template = atoi(row[16]); + tmpNPCType->attack_speed = atof(row[17]); + tmpNPCType->STR = atoi(row[18]); + tmpNPCType->STA = atoi(row[19]); + tmpNPCType->DEX = atoi(row[20]); + tmpNPCType->AGI = atoi(row[21]); + tmpNPCType->INT = atoi(row[22]); + tmpNPCType->WIS = atoi(row[23]); + tmpNPCType->CHA = atoi(row[24]); + tmpNPCType->MR = atoi(row[25]); + tmpNPCType->CR = atoi(row[26]); + tmpNPCType->DR = atoi(row[27]); + tmpNPCType->FR = atoi(row[28]); + tmpNPCType->PR = atoi(row[29]); + tmpNPCType->Corrup = atoi(row[30]); + tmpNPCType->PhR = atoi(row[31]); + tmpNPCType->min_dmg = atoi(row[32]); + tmpNPCType->max_dmg = atoi(row[33]); + tmpNPCType->attack_count = atoi(row[34]); - if (row[34] != nullptr) - strn0cpy(tmpNPCType->special_abilities, row[34], 512); + if (row[35] != nullptr) + strn0cpy(tmpNPCType->special_abilities, row[35], 512); else tmpNPCType->special_abilities[0] = '\0'; - tmpNPCType->npc_spells_id = atoi(row[35]); - tmpNPCType->npc_spells_effects_id = atoi(row[36]); - tmpNPCType->d_meele_texture1 = atoi(row[37]); - tmpNPCType->d_meele_texture2 = atoi(row[38]); - strn0cpy(tmpNPCType->ammo_idfile, row[39], 30); - tmpNPCType->prim_melee_type = atoi(row[40]); - tmpNPCType->sec_melee_type = atoi(row[41]); - tmpNPCType->ranged_type = atoi(row[42]); - tmpNPCType->runspeed= atof(row[43]); - tmpNPCType->findable = atoi(row[44]) == 0? false : true; - tmpNPCType->trackable = atoi(row[45]) == 0? false : true; - tmpNPCType->hp_regen = atoi(row[46]); - tmpNPCType->mana_regen = atoi(row[47]); + tmpNPCType->npc_spells_id = atoi(row[36]); + tmpNPCType->npc_spells_effects_id = atoi(row[37]); + tmpNPCType->d_melee_texture1 = atoi(row[38]); + tmpNPCType->d_melee_texture2 = atoi(row[39]); + strn0cpy(tmpNPCType->ammo_idfile, row[40], 30); + tmpNPCType->prim_melee_type = atoi(row[41]); + tmpNPCType->sec_melee_type = atoi(row[42]); + tmpNPCType->ranged_type = atoi(row[43]); + tmpNPCType->runspeed= atof(row[44]); + tmpNPCType->findable = atoi(row[45]) == 0? false : true; + tmpNPCType->trackable = atoi(row[46]) == 0? false : true; + tmpNPCType->hp_regen = atoi(row[47]); + tmpNPCType->mana_regen = atoi(row[48]); - // set defaultvalue for aggroradius - tmpNPCType->aggroradius = (int32)atoi(row[48]); + // set default value for aggroradius + tmpNPCType->aggroradius = (int32)atoi(row[49]); if (tmpNPCType->aggroradius <= 0) tmpNPCType->aggroradius = 70; - tmpNPCType->assistradius = (int32)atoi(row[49]); + tmpNPCType->assistradius = (int32)atoi(row[50]); if (tmpNPCType->assistradius <= 0) tmpNPCType->assistradius = tmpNPCType->aggroradius; - if (row[50] && strlen(row[50])) - tmpNPCType->bodytype = (uint8)atoi(row[50]); + if (row[51] && strlen(row[51])) + tmpNPCType->bodytype = (uint8)atoi(row[51]); else tmpNPCType->bodytype = 0; - tmpNPCType->npc_faction_id = atoi(row[51]); + tmpNPCType->npc_faction_id = atoi(row[52]); - tmpNPCType->luclinface = atoi(row[52]); - tmpNPCType->hairstyle = atoi(row[53]); - tmpNPCType->haircolor = atoi(row[54]); - tmpNPCType->eyecolor1 = atoi(row[55]); - tmpNPCType->eyecolor2 = atoi(row[56]); - tmpNPCType->beardcolor = atoi(row[57]); - tmpNPCType->beard = atoi(row[58]); - tmpNPCType->drakkin_heritage = atoi(row[59]); - tmpNPCType->drakkin_tattoo = atoi(row[60]); - tmpNPCType->drakkin_details = atoi(row[61]); + tmpNPCType->luclinface = atoi(row[53]); + tmpNPCType->hairstyle = atoi(row[54]); + tmpNPCType->haircolor = atoi(row[55]); + tmpNPCType->eyecolor1 = atoi(row[56]); + tmpNPCType->eyecolor2 = atoi(row[57]); + tmpNPCType->beardcolor = atoi(row[58]); + tmpNPCType->beard = atoi(row[59]); + tmpNPCType->drakkin_heritage = atoi(row[60]); + tmpNPCType->drakkin_tattoo = atoi(row[61]); + tmpNPCType->drakkin_details = atoi(row[62]); - uint32 armor_tint_id = atoi(row[62]); + uint32 armor_tint_id = atoi(row[63]); - tmpNPCType->armor_tint[0] = (atoi(row[63]) & 0xFF) << 16; - tmpNPCType->armor_tint[0] |= (atoi(row[64]) & 0xFF) << 8; - tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF); + tmpNPCType->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16; + tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8; + tmpNPCType->armor_tint[0] |= (atoi(row[66]) & 0xFF); tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0; - if (armor_tint_id == 0) - for (int index = MaterialChest; index <= EmuConstants::MATERIAL_END; index++) - tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0]; - else if (tmpNPCType->armor_tint[0] == 0) + if (armor_tint_id != 0) { std::string armortint_query = StringFormat("SELECT red1h, grn1h, blu1h, " "red2c, grn2c, blu2c, " @@ -1886,46 +1884,57 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { armor_tint_id); auto armortint_results = QueryDatabase(armortint_query); if (!armortint_results.Success() || armortint_results.RowCount() == 0) - armor_tint_id = 0; - else { + { + armor_tint_id = 0; + } + else + { auto armorTint_row = armortint_results.begin(); - for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) { + for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) + { tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16; tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8; tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]); tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0; } } - } else - armor_tint_id = 0; + } + // Try loading npc_types tint fields if armor tint is 0 or query failed to get results + if (armor_tint_id == 0) + { + for (int index = MaterialChest; index < _MaterialCount; index++) + { + tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0]; + } + } - tmpNPCType->see_invis = atoi(row[66]); - tmpNPCType->see_invis_undead = atoi(row[67]) == 0? false: true; // Set see_invis_undead flag - if (row[68] != nullptr) - strn0cpy(tmpNPCType->lastname, row[68], 32); + tmpNPCType->see_invis = atoi(row[67]); + tmpNPCType->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag + if (row[69] != nullptr) + strn0cpy(tmpNPCType->lastname, row[69], 32); - tmpNPCType->qglobal = atoi(row[69]) == 0? false: true; // qglobal - tmpNPCType->AC = atoi(row[70]); - tmpNPCType->npc_aggro = atoi(row[71]) == 0? false: true; - tmpNPCType->spawn_limit = atoi(row[72]); - tmpNPCType->see_hide = atoi(row[73]) == 0? false: true; - tmpNPCType->see_improved_hide = atoi(row[74]) == 0? false: true; - tmpNPCType->ATK = atoi(row[75]); - tmpNPCType->accuracy_rating = atoi(row[76]); - tmpNPCType->avoidance_rating = atoi(row[77]); - tmpNPCType->slow_mitigation = atoi(row[78]); - tmpNPCType->maxlevel = atoi(row[79]); - tmpNPCType->scalerate = atoi(row[80]); - tmpNPCType->private_corpse = atoi(row[81]) == 1 ? true: false; - tmpNPCType->unique_spawn_by_name = atoi(row[82]) == 1 ? true: false; - tmpNPCType->underwater = atoi(row[83]) == 1 ? true: false; - tmpNPCType->emoteid = atoi(row[84]); - tmpNPCType->spellscale = atoi(row[85]); - tmpNPCType->healscale = atoi(row[86]); - tmpNPCType->no_target_hotkey = atoi(row[87]) == 1 ? true: false; - tmpNPCType->raid_target = atoi(row[88]) == 0 ? false: true; - tmpNPCType->attack_delay = atoi(row[89]); + tmpNPCType->qglobal = atoi(row[70]) == 0? false: true; // qglobal + tmpNPCType->AC = atoi(row[71]); + tmpNPCType->npc_aggro = atoi(row[72]) == 0? false: true; + tmpNPCType->spawn_limit = atoi(row[73]); + tmpNPCType->see_hide = atoi(row[74]) == 0? false: true; + tmpNPCType->see_improved_hide = atoi(row[75]) == 0? false: true; + tmpNPCType->ATK = atoi(row[76]); + tmpNPCType->accuracy_rating = atoi(row[77]); + tmpNPCType->avoidance_rating = atoi(row[78]); + tmpNPCType->slow_mitigation = atoi(row[79]); + tmpNPCType->maxlevel = atoi(row[80]); + tmpNPCType->scalerate = atoi(row[81]); + tmpNPCType->private_corpse = atoi(row[82]) == 1 ? true: false; + tmpNPCType->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false; + tmpNPCType->underwater = atoi(row[84]) == 1 ? true: false; + tmpNPCType->emoteid = atoi(row[85]); + tmpNPCType->spellscale = atoi(row[86]); + tmpNPCType->healscale = atoi(row[87]); + tmpNPCType->no_target_hotkey = atoi(row[88]) == 1 ? true: false; + tmpNPCType->raid_target = atoi(row[89]) == 0 ? false: true; + tmpNPCType->attack_delay = atoi(row[90]); // If NPC with duplicate NPC id already in table, // free item we attempted to add. @@ -1968,7 +1977,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client "vwMercNpcTypes.CR, vwMercNpcTypes.DR, vwMercNpcTypes.FR, vwMercNpcTypes.PR, " "vwMercNpcTypes.Corrup, vwMercNpcTypes.mindmg, vwMercNpcTypes.maxdmg, " "vwMercNpcTypes.attack_count, vwMercNpcTypes.special_abilities, " - "vwMercNpcTypes.d_meele_texture1, vwMercNpcTypes.d_meele_texture2, " + "vwMercNpcTypes.d_melee_texture1, vwMercNpcTypes.d_melee_texture2, " "vwMercNpcTypes.prim_melee_type, vwMercNpcTypes.sec_melee_type, " "vwMercNpcTypes.runspeed, vwMercNpcTypes.hp_regen_rate, vwMercNpcTypes.mana_regen_rate, " "vwMercNpcTypes.bodytype, vwMercNpcTypes.armortint_id, " @@ -2027,8 +2036,8 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client else tmpNPCType->special_abilities[0] = '\0'; - tmpNPCType->d_meele_texture1 = atoi(row[28]); - tmpNPCType->d_meele_texture2 = atoi(row[29]); + tmpNPCType->d_melee_texture1 = atoi(row[28]); + tmpNPCType->d_melee_texture2 = atoi(row[29]); tmpNPCType->prim_melee_type = atoi(row[30]); tmpNPCType->sec_melee_type = atoi(row[31]); tmpNPCType->runspeed= atof(row[32]); diff --git a/zone/zonedump.h b/zone/zonedump.h index deebf9b19..3dd6d4569 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -49,6 +49,7 @@ struct NPCType uint32 npc_id; uint8 texture; uint8 helmtexture; + uint32 herosforgemodel; uint32 loottable_id; uint32 npc_spells_id; uint32 npc_spells_effects_id; @@ -90,8 +91,8 @@ struct NPCType uint32 max_dmg; int16 attack_count; char special_abilities[512]; - uint16 d_meele_texture1; - uint16 d_meele_texture2; + uint16 d_melee_texture1; + uint16 d_melee_texture2; char ammo_idfile[30]; uint8 prim_melee_type; uint8 sec_melee_type;