diff --git a/changelog.txt b/changelog.txt index 0091a7583..79b156c0b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,34 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 01/15/2015 == +Uleat: Attempted fix for elusive inventory bug: + - Removed 'iter_queue' typedef and converted lcast to explicit or auto defines + - Reworked several functions that manipulate the cursor queue + - Found/corrected one occurrence of post-processing iterator incrementing in an ItemInstQueue handler + - Added many scope declarations in code that handles inventory manipulation (loose macros are bad...) +Uleat: Added Item_Struct pointer checks to ItemInst methods that did not have them +Uleat: Changed IsEquippable(race,class) to use bit-wise 'and' (&) over '(x%2)==1' in conditional check. +Uleat: Changed DyeArmor() assignment of 'armor_color' to use bit-wise 'or' and bit-shifting (|,<<) over multiplication and addition (*,+). + +== 01/13/2015 == +Uleat: Placed an upper limit on the cursor queue save loop. +Trevius: (RoF2) Guild invites now add new members as members instead of recruits, and /guild chat works properly. +Trevius: (RoF2) Guild Promote is now functional. + +== 01/12/2015 == +Uleat: Fix for OP_FormattedMessage text link server crashes +Uleat: Added text link translators for OP_TaskDescription (RoF+ -- all clients current) +Uleat: Fix for load_bots.sql using '\\' as a delimiter (Changed to '$$') + +== 01/11/2015 == +Uleat: Added text link translators for OP_TaskDescription (Ti thru UF..RoF+ in-work) + +== 01/10/2015 == +Uleat: Added text link translators for OP_Emote + +== 01/09/2015 == +Uleat: Added text link translators for OP_FormattedMessage + == 01/08/2015 == Trevius: Added some extra checks and clean-up related to Groups and Mercenaries. diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 0c91d96f8..4ca5fa59c 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -2388,7 +2388,7 @@ struct AugmentItem_Struct { // OP_Emote struct Emote_Struct { -/*0000*/ uint32 unknown01; +/*0000*/ uint32 type; // 0 - custom, 0xffffffff - command (/dance, /flip, etc...) /*0004*/ char message[1024]; /*1028*/ }; diff --git a/common/item.cpp b/common/item.cpp index af0921ce0..9897c9165 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -55,13 +55,10 @@ static inline int32 GetNextItemInstSerialNumber() { // // class ItemInstQueue // -ItemInstQueue::~ItemInstQueue() { - iter_queue cur, end; - cur = m_list.begin(); - end = m_list.end(); - for (; cur != end; ++cur) { - ItemInst *tmp = *cur; - safe_delete(tmp); +ItemInstQueue::~ItemInstQueue() +{ + for (auto iter = m_list.begin(); iter != m_list.end(); ++iter) { + safe_delete(*iter); } m_list.clear(); } @@ -81,7 +78,7 @@ void ItemInstQueue::push_front(ItemInst* inst) // Remove item from front of queue ItemInst* ItemInstQueue::pop() { - if (m_list.size() == 0) + if (m_list.empty()) return nullptr; ItemInst* inst = m_list.front(); @@ -92,7 +89,7 @@ ItemInst* ItemInstQueue::pop() // Remove item from back of queue ItemInst* ItemInstQueue::pop_back() { - if (m_list.size() == 0) + if (m_list.empty()) return nullptr; ItemInst* inst = m_list.back(); @@ -103,53 +100,37 @@ ItemInst* ItemInstQueue::pop_back() // Look at item at front of queue ItemInst* ItemInstQueue::peek_front() const { - return (m_list.size() == 0) ? nullptr : m_list.front(); + return (m_list.empty()) ? nullptr : m_list.front(); } // // class Inventory // -Inventory::~Inventory() { - std::map::iterator cur, end; - - cur = m_worn.begin(); - end = m_worn.end(); - for (; cur != end; ++cur) { - ItemInst *tmp = cur->second; - safe_delete(tmp); +Inventory::~Inventory() +{ + for (auto iter = m_worn.begin(); iter != m_worn.end(); ++iter) { + safe_delete(iter->second); } m_worn.clear(); - cur = m_inv.begin(); - end = m_inv.end(); - for (; cur != end; ++cur) { - ItemInst *tmp = cur->second; - safe_delete(tmp); + for (auto iter = m_inv.begin(); iter != m_inv.end(); ++iter) { + safe_delete(iter->second); } m_inv.clear(); - cur = m_bank.begin(); - end = m_bank.end(); - for (; cur != end; ++cur) { - ItemInst *tmp = cur->second; - safe_delete(tmp); + for (auto iter = m_bank.begin(); iter != m_bank.end(); ++iter) { + safe_delete(iter->second); } m_bank.clear(); - cur = m_shbank.begin(); - end = m_shbank.end(); - for (; cur != end; ++cur) { - ItemInst *tmp = cur->second; - safe_delete(tmp); + for (auto iter = m_shbank.begin(); iter != m_shbank.end(); ++iter) { + safe_delete(iter->second); } m_shbank.clear(); - cur = m_trade.begin(); - end = m_trade.end(); - for (; cur != end; ++cur) { - ItemInst *tmp = cur->second; - safe_delete(tmp); + for (auto iter = m_trade.begin(); iter != m_trade.end(); ++iter) { + safe_delete(iter->second); } m_trade.clear(); } @@ -309,7 +290,8 @@ bool Inventory::DeleteItem(int16 slot_id, uint8 quantity) // the item is not stackable, and is not a charged item, or is expendable, delete it if (item_to_delete->IsStackable() || (!item_to_delete->IsStackable() && - ((item_to_delete->GetItem()->MaxCharges == 0) || item_to_delete->IsExpendable()))) { + ((item_to_delete->GetItem()->MaxCharges == 0) || item_to_delete->IsExpendable())) + ) { // Item can now be destroyed Inventory::MarkDirty(item_to_delete); return true; @@ -334,7 +316,8 @@ bool Inventory::CheckNoDrop(int16 slot_id) { if (inst->GetItem()->ItemClass == 1) { for (uint8 i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) { ItemInst* bagitem = GetItem(Inventory::CalcSlotId(slot_id, i)); - if (bagitem && !bagitem->GetItem()->NoDrop) return true; + if (bagitem && !bagitem->GetItem()->NoDrop) + return true; } } return false; @@ -638,8 +621,7 @@ int16 Inventory::FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size, boo if (!for_bag) { for (int16 i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { const ItemInst* inst = GetItem(i); - if (inst && inst->IsType(ItemClassContainer) - && inst->GetItem()->BagSize >= min_size) + if (inst && inst->IsType(ItemClassContainer) && inst->GetItem()->BagSize >= min_size) { if (inst->GetItem()->BagType == BagTypeQuiver && inst->GetItem()->ItemType != ItemTypeArrow) { @@ -651,18 +633,20 @@ int16 Inventory::FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size, boo uint8 slots = inst->GetItem()->BagSlots; uint8 j; for (j = SUB_BEGIN; jIsType(ItemClassContainer)) { - for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) + for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { if (!m_inv[free_slot]) return free_slot; + } return MainCursor; // return cursor since bags do not stack and will not fit inside other bags..yet...) } @@ -727,9 +712,10 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { if (!main_inst || (main_inst->GetItem()->BagType != BagTypeQuiver) || !main_inst->IsType(ItemClassContainer)) continue; - for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) + for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) { if (!main_inst->GetItem(free_bag_slot)) return Inventory::CalcSlotId(free_slot, free_bag_slot); + } } } @@ -741,9 +727,10 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { if (!main_inst || (main_inst->GetItem()->BagType != BagTypeBandolier) || !main_inst->IsType(ItemClassContainer)) continue; - for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) + for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) { if (!main_inst->GetItem(free_bag_slot)) return Inventory::CalcSlotId(free_slot, free_bag_slot); + } } } @@ -762,9 +749,10 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == BagTypeBandolier) || (main_inst->GetItem()->BagType == BagTypeQuiver)) continue; - for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) + for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) { if (!main_inst->GetItem(free_bag_slot)) return Inventory::CalcSlotId(free_slot, free_bag_slot); + } } } @@ -776,27 +764,26 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { int16 Inventory::CalcSlotId(int16 slot_id) { int16 parent_slot_id = INVALID_INDEX; - if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END) - parent_slot_id = EmuConstants::GENERAL_BEGIN + (slot_id - EmuConstants::GENERAL_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; - - else if (slot_id >= EmuConstants::CURSOR_BAG_BEGIN && slot_id <= EmuConstants::CURSOR_BAG_END) - parent_slot_id = MainCursor; - - /* // this is not a bag range... using this risks over-writing existing items - else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) - parent_slot_id = EmuConstants::BANK_BEGIN + (slot_id - EmuConstants::BANK_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; - */ - - else if (slot_id >= EmuConstants::BANK_BAGS_BEGIN && slot_id <= EmuConstants::BANK_BAGS_END) - parent_slot_id = EmuConstants::BANK_BEGIN + (slot_id - EmuConstants::BANK_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; - - else if (slot_id >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) - parent_slot_id = EmuConstants::SHARED_BANK_BEGIN + (slot_id - EmuConstants::SHARED_BANK_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; - + //else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) + // parent_slot_id = EmuConstants::BANK_BEGIN + (slot_id - EmuConstants::BANK_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; //else if (slot_id >= 3100 && slot_id <= 3179) should be {3031..3110}..where did this range come from!!? (verified db save range) - else if (slot_id >= EmuConstants::TRADE_BAGS_BEGIN && slot_id <= EmuConstants::TRADE_BAGS_END) + + if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END) { + parent_slot_id = EmuConstants::GENERAL_BEGIN + (slot_id - EmuConstants::GENERAL_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; + } + else if (slot_id >= EmuConstants::CURSOR_BAG_BEGIN && slot_id <= EmuConstants::CURSOR_BAG_END) { + parent_slot_id = MainCursor; + } + else if (slot_id >= EmuConstants::BANK_BAGS_BEGIN && slot_id <= EmuConstants::BANK_BAGS_END) { + parent_slot_id = EmuConstants::BANK_BEGIN + (slot_id - EmuConstants::BANK_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; + } + else if (slot_id >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) { + parent_slot_id = EmuConstants::SHARED_BANK_BEGIN + (slot_id - EmuConstants::SHARED_BANK_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; + } + else if (slot_id >= EmuConstants::TRADE_BAGS_BEGIN && slot_id <= EmuConstants::TRADE_BAGS_END) { parent_slot_id = EmuConstants::TRADE_BEGIN + (slot_id - EmuConstants::TRADE_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; + } return parent_slot_id; } @@ -808,20 +795,21 @@ int16 Inventory::CalcSlotId(int16 bagslot_id, uint8 bagidx) { int16 slot_id = INVALID_INDEX; - if (bagslot_id == MainCursor || bagslot_id == 8000) + if (bagslot_id == MainCursor || bagslot_id == 8000) { slot_id = EmuConstants::CURSOR_BAG_BEGIN + bagidx; - - else if (bagslot_id >= EmuConstants::GENERAL_BEGIN && bagslot_id <= EmuConstants::GENERAL_END) + } + else if (bagslot_id >= EmuConstants::GENERAL_BEGIN && bagslot_id <= EmuConstants::GENERAL_END) { slot_id = EmuConstants::GENERAL_BAGS_BEGIN + (bagslot_id - EmuConstants::GENERAL_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE + bagidx; - - else if (bagslot_id >= EmuConstants::BANK_BEGIN && bagslot_id <= EmuConstants::BANK_END) + } + else if (bagslot_id >= EmuConstants::BANK_BEGIN && bagslot_id <= EmuConstants::BANK_END) { slot_id = EmuConstants::BANK_BAGS_BEGIN + (bagslot_id - EmuConstants::BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE + bagidx; - - else if (bagslot_id >= EmuConstants::SHARED_BANK_BEGIN && bagslot_id <= EmuConstants::SHARED_BANK_END) + } + else if (bagslot_id >= EmuConstants::SHARED_BANK_BEGIN && bagslot_id <= EmuConstants::SHARED_BANK_END) { slot_id = EmuConstants::SHARED_BANK_BAGS_BEGIN + (bagslot_id - EmuConstants::SHARED_BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE + bagidx; - - else if (bagslot_id >= EmuConstants::TRADE_BEGIN && bagslot_id <= EmuConstants::TRADE_END) + } + else if (bagslot_id >= EmuConstants::TRADE_BEGIN && bagslot_id <= EmuConstants::TRADE_END) { slot_id = EmuConstants::TRADE_BAGS_BEGIN + (bagslot_id - EmuConstants::TRADE_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE + bagidx; + } return slot_id; } @@ -829,30 +817,28 @@ int16 Inventory::CalcSlotId(int16 bagslot_id, uint8 bagidx) { uint8 Inventory::CalcBagIdx(int16 slot_id) { uint8 index = 0; - if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END) - index = (slot_id - EmuConstants::GENERAL_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; - - else if (slot_id >= EmuConstants::CURSOR_BAG_BEGIN && slot_id <= EmuConstants::CURSOR_BAG_END) - index = (slot_id - EmuConstants::CURSOR_BAG_BEGIN); // % EmuConstants::ITEM_CONTAINER_SIZE; - not needed since range is 10 slots - - /* // this is not a bag range... using this risks over-writing existing items - else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) - index = (slot_id - EmuConstants::BANK_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; - */ + //else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) + // index = (slot_id - EmuConstants::BANK_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; - else if (slot_id >= EmuConstants::BANK_BAGS_BEGIN && slot_id <= EmuConstants::BANK_BAGS_END) + if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END) { + index = (slot_id - EmuConstants::GENERAL_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; + } + else if (slot_id >= EmuConstants::CURSOR_BAG_BEGIN && slot_id <= EmuConstants::CURSOR_BAG_END) { + index = (slot_id - EmuConstants::CURSOR_BAG_BEGIN); // % EmuConstants::ITEM_CONTAINER_SIZE; - not needed since range is 10 slots + } + else if (slot_id >= EmuConstants::BANK_BAGS_BEGIN && slot_id <= EmuConstants::BANK_BAGS_END) { index = (slot_id - EmuConstants::BANK_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; - - else if (slot_id >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) + } + else if (slot_id >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) { index = (slot_id - EmuConstants::SHARED_BANK_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; - - else if (slot_id >= EmuConstants::TRADE_BAGS_BEGIN && slot_id <= EmuConstants::TRADE_BAGS_END) + } + else if (slot_id >= EmuConstants::TRADE_BAGS_BEGIN && slot_id <= EmuConstants::TRADE_BAGS_END) { index = (slot_id - EmuConstants::TRADE_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; - - // odd..but, ok... (probably a range-slot conversion for ItemInst* Object::item - else if (slot_id >= EmuConstants::WORLD_BEGIN && slot_id <= EmuConstants::WORLD_END) + } + else if (slot_id >= EmuConstants::WORLD_BEGIN && slot_id <= EmuConstants::WORLD_END) { index = (slot_id - EmuConstants::WORLD_BEGIN); // % EmuConstants::ITEM_CONTAINER_SIZE; - not needed since range is 10 slots + } return index; } @@ -914,13 +900,17 @@ uint8 Inventory::CalcMaterialFromSlot(int16 equipslot) bool Inventory::CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_Struct *Container) { - if (!ItemToTry || !Container) return false; + if (!ItemToTry || !Container) + return false; - if (ItemToTry->Size > Container->BagSize) return false; + if (ItemToTry->Size > Container->BagSize) + return false; - if ((Container->BagType == BagTypeQuiver) && (ItemToTry->ItemType != ItemTypeArrow)) return false; + if ((Container->BagType == BagTypeQuiver) && (ItemToTry->ItemType != ItemTypeArrow)) + return false; - if ((Container->BagType == BagTypeBandolier) && (ItemToTry->ItemType != ItemTypeSmallThrowing)) return false; + if ((Container->BagType == BagTypeBandolier) && (ItemToTry->ItemType != ItemTypeSmallThrowing)) + return false; return true; } @@ -956,8 +946,11 @@ bool Inventory::SupportsContainers(int16 slot_id) (slot_id >= EmuConstants::GENERAL_BEGIN && slot_id <= EmuConstants::GENERAL_END) || (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) || (slot_id >= EmuConstants::SHARED_BANK_BEGIN && slot_id <= EmuConstants::SHARED_BANK_END) || - (slot_id >= EmuConstants::TRADE_BEGIN && slot_id <= EmuConstants::TRADE_END)) + (slot_id >= EmuConstants::TRADE_BEGIN && slot_id <= EmuConstants::TRADE_END) + ) { return true; + } + return false; } @@ -1140,8 +1133,7 @@ int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst) m_trade[slot_id] = inst; result = slot_id; } - else - { + else { // Slot must be within a bag parentSlot = Inventory::CalcSlotId(slot_id); ItemInst* baginst = GetItem(parentSlot); // Get parent bag @@ -1163,246 +1155,233 @@ int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst) // Internal Method: Checks an inventory bucket for a particular item int16 Inventory::_HasItem(std::map& bucket, uint32 item_id, uint8 quantity) { - iter_inst it; - iter_contents itb; - ItemInst* inst = nullptr; uint8 quantity_found = 0; - // Check item: After failed checks, check bag contents (if bag) - for (it = bucket.begin(); it != bucket.end(); ++it) { - inst = it->second; - if (inst) { - if (inst->GetID() == item_id) { - quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); - if (quantity_found >= quantity) - return it->first; - } + for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) { + auto inst = iter->second; + if (inst == nullptr) { continue; } - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - if (inst->GetAugmentItemID(i) == item_id && quantity <= 1) - return legacy::SLOT_AUGMENT; // Only one augment per slot. - } + if (inst->GetID() == item_id) { + quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); + if (quantity_found >= quantity) + return iter->first; } - // Go through bag, if bag - if (inst && inst->IsType(ItemClassContainer)) { - for (itb = inst->_begin(); itb != inst->_end(); ++itb) { - ItemInst* baginst = itb->second; - 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 && baginst->GetAugmentItemID(i) == item_id && quantity <= 1) - return legacy::SLOT_AUGMENT; // Only one augment per slot. - } + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + if (inst->GetAugmentItemID(index) == item_id && quantity <= 1) + return legacy::SLOT_AUGMENT; + } + + if (!inst->IsType(ItemClassContainer)) { continue; } + + for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + auto bag_inst = bag_iter->second; + if (bag_inst == nullptr) { continue; } + + if (bag_inst->GetID() == item_id) { + quantity_found += (bag_inst->GetCharges() <= 0) ? 1 : bag_inst->GetCharges(); + if (quantity_found >= quantity) + return Inventory::CalcSlotId(iter->first, bag_iter->first); + } + + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + if (bag_inst->GetAugmentItemID(index) == item_id && quantity <= 1) + return legacy::SLOT_AUGMENT; } } } - // Not found return INVALID_INDEX; } // Internal Method: Checks an inventory queue type bucket for a particular item int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) { - iter_queue it; - iter_contents itb; + // The downfall of this (these) queue procedure is that callers presume that when an item is + // found, it is presented as being available on the cursor. In cases of a parity check, this + // is sufficient. However, in cases where referential criteria is considered, this can lead + // to unintended results. Funtionality should be observed when referencing the return value + // of this query -U + uint8 quantity_found = 0; - // Read-only iteration of queue - for (it = iqueue.begin(); it != iqueue.end(); ++it) { - ItemInst* inst = *it; - if (inst) - { - if (inst->GetID() == item_id) { - quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); - if (quantity_found >= quantity) - return MainCursor; - } - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - if (inst->GetAugmentItemID(i) == item_id && quantity <= 1) - return legacy::SLOT_AUGMENT; // Only one augment per slot. - } + for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) { + auto inst = *iter; + if (inst == nullptr) { continue; } + + if (inst->GetID() == item_id) { + quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); + if (quantity_found >= quantity) + return MainCursor; } - // Go through bag, if bag - if (inst && inst->IsType(ItemClassContainer)) { - for (itb = inst->_begin(); itb != inst->_end(); ++itb) { - ItemInst* baginst = itb->second; - 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 && baginst->GetAugmentItemID(i) == item_id && quantity <= 1) - return legacy::SLOT_AUGMENT; // Only one augment per slot. - } + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + if (inst->GetAugmentItemID(index) == item_id && quantity <= 1) + return legacy::SLOT_AUGMENT; + } + if (!inst->IsType(ItemClassContainer)) { continue; } + + for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + auto bag_inst = bag_iter->second; + if (bag_inst == nullptr) { continue; } + + if (bag_inst->GetID() == item_id) { + quantity_found += (bag_inst->GetCharges() <= 0) ? 1 : bag_inst->GetCharges(); + if (quantity_found >= quantity) + return Inventory::CalcSlotId(MainCursor, bag_iter->first); + } + + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + if (bag_inst->GetAugmentItemID(index) == item_id && quantity <= 1) + return legacy::SLOT_AUGMENT; } } } - // Not found return INVALID_INDEX; } // Internal Method: Checks an inventory bucket for a particular item int16 Inventory::_HasItemByUse(std::map& bucket, uint8 use, uint8 quantity) { - iter_inst it; - iter_contents itb; - ItemInst* inst = nullptr; uint8 quantity_found = 0; - // Check item: After failed checks, check bag contents (if bag) - for (it = bucket.begin(); it != bucket.end(); ++it) { - inst = it->second; - if (inst && inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) { + for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) { + auto inst = iter->second; + if (inst == nullptr) { continue; } + + if (inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) { quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) - return it->first; + return iter->first; } - // Go through bag, if bag - if (inst && inst->IsType(ItemClassContainer)) { + if (!inst->IsType(ItemClassContainer)) { continue; } - for (itb = inst->_begin(); itb != inst->_end(); itb++) { - ItemInst* baginst = itb->second; - if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->ItemType == use) { - quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges(); - if (quantity_found >= quantity) - return Inventory::CalcSlotId(it->first, itb->first); - } + for (auto bag_iter = bucket.begin(); bag_iter != bucket.end(); ++bag_iter) { + auto bag_inst = bag_iter->second; + if (bag_inst == nullptr) { continue; } + + if (bag_inst->IsType(ItemClassCommon) && bag_inst->GetItem()->ItemType == use) { + quantity_found += (bag_inst->GetCharges() <= 0) ? 1 : bag_inst->GetCharges(); + if (quantity_found >= quantity) + return Inventory::CalcSlotId(iter->first, bag_iter->first); } } } - // Not found return INVALID_INDEX; } // Internal Method: Checks an inventory queue type bucket for a particular item int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity) { - iter_queue it; - iter_contents itb; uint8 quantity_found = 0; - // Read-only iteration of queue - for (it = iqueue.begin(); it != iqueue.end(); ++it) { - ItemInst* inst = *it; - if (inst && inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) { + for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) { + auto inst = *iter; + if (inst == nullptr) { continue; } + + if (inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) { quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return MainCursor; } - // Go through bag, if bag - if (inst && inst->IsType(ItemClassContainer)) { + if (!inst->IsType(ItemClassContainer)) { continue; } - for (itb = inst->_begin(); itb != inst->_end(); ++itb) { - ItemInst* baginst = itb->second; - if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->ItemType == use) { - quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges(); - if (quantity_found >= quantity) - return Inventory::CalcSlotId(MainCursor, itb->first); - } + for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + auto bag_inst = bag_iter->second; + if (bag_inst == nullptr) { continue; } + + if (bag_inst->IsType(ItemClassCommon) && bag_inst->GetItem()->ItemType == use) { + quantity_found += (bag_inst->GetCharges() <= 0) ? 1 : bag_inst->GetCharges(); + if (quantity_found >= quantity) + return Inventory::CalcSlotId(MainCursor, bag_iter->first); } } } - // Not found return INVALID_INDEX; } int16 Inventory::_HasItemByLoreGroup(std::map& bucket, uint32 loregroup) { - iter_inst it; - iter_contents itb; - ItemInst* inst = nullptr; + for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) { + auto inst = iter->second; + if (inst == nullptr) { continue; } - // Check item: After failed checks, check bag contents (if bag) - for (it = bucket.begin(); it != bucket.end(); ++it) { - inst = it->second; - if (inst) { - if (inst->GetItem()->LoreGroup == loregroup) - return it->first; + if (inst->GetItem()->LoreGroup == loregroup) + return iter->first; - ItemInst* Aug = nullptr; - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - Aug = inst->GetAugment(i); - if (Aug && Aug->GetItem()->LoreGroup == loregroup) - return legacy::SLOT_AUGMENT; // Only one augment per slot. - } + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + auto aug_inst = inst->GetAugment(index); + if (aug_inst == nullptr) { continue; } + + if (aug_inst->GetItem()->LoreGroup == loregroup) + return legacy::SLOT_AUGMENT; } - // Go through bag, if bag - if (inst && inst->IsType(ItemClassContainer)) { - for (itb = inst->_begin(); itb != inst->_end(); ++itb) { - ItemInst* baginst = itb->second; - if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup) - return Inventory::CalcSlotId(it->first, itb->first); + if (!inst->IsType(ItemClassContainer)) { continue; } - ItemInst* Aug2 = nullptr; - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - Aug2 = baginst->GetAugment(i); - if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup) - return legacy::SLOT_AUGMENT; // Only one augment per slot. - } + for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + auto bag_inst = bag_iter->second; + if (bag_inst == nullptr) { continue; } + + if (bag_inst->IsType(ItemClassCommon) && bag_inst->GetItem()->LoreGroup == loregroup) + return Inventory::CalcSlotId(iter->first, bag_iter->first); + + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + auto aug_inst = bag_inst->GetAugment(index); + if (aug_inst == nullptr) { continue; } + + if (aug_inst->GetItem()->LoreGroup == loregroup) + return legacy::SLOT_AUGMENT; } } } - // Not found return INVALID_INDEX; } // Internal Method: Checks an inventory queue type bucket for a particular item int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) { - iter_queue it; - iter_contents itb; + for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) { + auto inst = *iter; + if (inst == nullptr) { continue; } - // Read-only iteration of queue - for (it = iqueue.begin(); it != iqueue.end(); ++it) { - ItemInst* inst = *it; - if (inst) - { - if (inst->GetItem()->LoreGroup == loregroup) - return MainCursor; + if (inst->GetItem()->LoreGroup == loregroup) + return MainCursor; - ItemInst* Aug = nullptr; - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - Aug = inst->GetAugment(i); - if (Aug && Aug->GetItem()->LoreGroup == loregroup) - return legacy::SLOT_AUGMENT; // Only one augment per slot. - } + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + auto aug_inst = inst->GetAugment(index); + if (aug_inst == nullptr) { continue; } + + if (aug_inst->GetItem()->LoreGroup == loregroup) + return legacy::SLOT_AUGMENT; } - // Go through bag, if bag - if (inst && inst->IsType(ItemClassContainer)) { - for (itb = inst->_begin(); itb != inst->_end(); ++itb) { - ItemInst* baginst = itb->second; - if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup) - return Inventory::CalcSlotId(MainCursor, itb->first); + if (!inst->IsType(ItemClassContainer)) { continue; } + for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + auto bag_inst = bag_iter->second; + if (bag_inst == nullptr) { continue; } - ItemInst* Aug2 = nullptr; - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - Aug2 = baginst->GetAugment(i); - if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup) - return legacy::SLOT_AUGMENT; // Only one augment per slot. - } + if (bag_inst->IsType(ItemClassCommon) && bag_inst->GetItem()->LoreGroup == loregroup) + return Inventory::CalcSlotId(MainCursor, bag_iter->first); + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + auto aug_inst = bag_inst->GetAugment(index); + if (aug_inst == nullptr) { continue; } + + if (aug_inst->GetItem()->LoreGroup == loregroup) + return legacy::SLOT_AUGMENT; } } } - - // Not found + return INVALID_INDEX; } @@ -1544,10 +1523,12 @@ ItemInst::~ItemInst() // Query item type bool ItemInst::IsType(ItemClassTypes item_class) const { + // IsType() does not protect against 'm_item = nullptr' + // Check usage type if ((m_use_type == ItemInstWorldContainer) && (item_class == ItemClassContainer)) - return true; + if (!m_item) return false; @@ -1557,11 +1538,17 @@ bool ItemInst::IsType(ItemClassTypes item_class) const // Is item stackable? bool ItemInst::IsStackable() const { + if (!m_item) + return false; + return m_item->Stackable; } bool ItemInst::IsCharged() const { + if (!m_item) + return false; + if (m_item->MaxCharges > 1) return true; else @@ -1584,16 +1571,25 @@ bool ItemInst::IsEquipable(int16 slot_id) const return false; // another "shouldn't do" fix..will be fixed in future updates (requires code and database work) - if (slot_id == MainPowerSource) { - slot_id = MainGeneral1; - uint32 slot_mask = (1 << slot_id); - if (slot_mask & m_item->Slots) + int16 use_slot = INVALID_INDEX; + if (slot_id == MainPowerSource) { use_slot = MainGeneral1; } + if ((uint16)slot_id <= EmuConstants::EQUIPMENT_END) { use_slot = slot_id; } + + if (use_slot != INVALID_INDEX) { + if (m_item->Slots & (1 << use_slot)) return true; } - if ((uint16)slot_id <= EmuConstants::EQUIPMENT_END) { - uint32 slot_mask = (1 << slot_id); - if (slot_mask & m_item->Slots) + return false; +} + +bool ItemInst::IsAugmentable() const +{ + if (!m_item) + return false; + + for (int index = 0; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + if (m_item->AugSlotType[index] != NO_ITEM) return true; } @@ -1603,39 +1599,38 @@ bool ItemInst::IsEquipable(int16 slot_id) const bool ItemInst::AvailableWearSlot(uint32 aug_wear_slots) const { // TODO: check to see if incoming 'aug_wear_slots' "switches" bit assignments like above... // (if wrong, would only affect MainAmmo and MainPowerSource augments) - if (m_item->ItemClass != ItemClassCommon || !m_item) + if (!m_item || m_item->ItemClass != ItemClassCommon) return false; - int i; - for (i = EmuConstants::EQUIPMENT_BEGIN; i <= MainGeneral1; i++) { // MainGeneral1 should be EmuConstants::EQUIPMENT_END - if (m_item->Slots & (1 << i)) { - if (aug_wear_slots & (1 << i)) + int index = EmuConstants::EQUIPMENT_BEGIN; + for (; index <= MainGeneral1; ++index) { // MainGeneral1 should be EmuConstants::EQUIPMENT_END + if (m_item->Slots & (1 << index)) { + if (aug_wear_slots & (1 << index)) break; } } - return (i<23) ? true : false; + return (index < 23) ? true : false; } int8 ItemInst::AvailableAugmentSlot(int32 augtype) const { - if (m_item->ItemClass != ItemClassCommon || !m_item) - return -1; - - int i; - for (i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - if (!GetItem(i)) { - if (augtype == -1 || (m_item->AugSlotType[i] && ((1 << (m_item->AugSlotType[i] - 1)) & augtype))) - break; - } + if (!m_item || m_item->ItemClass != ItemClassCommon) + return INVALID_INDEX; + int index = AUG_BEGIN; + for (; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + if (GetItem(index)) { continue; } + if (augtype == -1 || (m_item->AugSlotType[index] && ((1 << (m_item->AugSlotType[index] - 1)) & augtype))) + break; } - return (i < EmuConstants::ITEM_COMMON_SIZE) ? i : INVALID_INDEX; + return (index < EmuConstants::ITEM_COMMON_SIZE) ? index : INVALID_INDEX; } -bool ItemInst::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const { - if (m_item->ItemClass != ItemClassCommon || !m_item) +bool ItemInst::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const +{ + if (!m_item || m_item->ItemClass != ItemClassCommon) return false; if ((!GetItem(slot) && m_item->AugSlotVisible[slot]) && augtype == -1 || (m_item->AugSlotType[slot] && ((1 << (m_item->AugSlotType[slot] - 1)) & augtype))) { @@ -1649,8 +1644,7 @@ ItemInst* ItemInst::GetItem(uint8 index) const { iter_contents it = m_contents.find(index); if (it != m_contents.end()) { - ItemInst* inst = it->second; - return inst; + return it->second; } return nullptr; @@ -1658,12 +1652,11 @@ ItemInst* ItemInst::GetItem(uint8 index) const uint32 ItemInst::GetItemID(uint8 slot) const { - const ItemInst *item; - uint32 id = NO_ITEM; - if ((item = GetItem(slot)) != nullptr) - id = item->GetItem()->ID; + ItemInst *item = GetItem(slot); + if (item) + return item->GetID(); - return id; + return NO_ITEM; } void ItemInst::PutItem(uint8 index, const ItemInst& inst) @@ -1671,7 +1664,6 @@ void ItemInst::PutItem(uint8 index, const ItemInst& inst) // Clean up item already in slot (if exists) DeleteItem(index); - // Delegate to internal method _PutItem(index, inst.Clone()); } @@ -1687,14 +1679,13 @@ void ItemInst::DeleteItem(uint8 index) // Hands over memory ownership to client of this function call ItemInst* ItemInst::PopItem(uint8 index) { - iter_contents it = m_contents.find(index); - if (it != m_contents.end()) { - ItemInst* inst = it->second; + auto iter = m_contents.find(index); + if (iter != m_contents.end()) { + ItemInst* inst = iter->second; m_contents.erase(index); - return inst; + return inst; // Return pointer that needs to be deleted (or otherwise managed) } - - // Return pointer that needs to be deleted (or otherwise managed) + return nullptr; } @@ -1702,12 +1693,8 @@ ItemInst* ItemInst::PopItem(uint8 index) void ItemInst::Clear() { // Destroy container contents - iter_contents cur, end; - cur = m_contents.begin(); - end = m_contents.end(); - for (; cur != end; ++cur) { - ItemInst* inst = cur->second; - safe_delete(inst); + for (auto iter = m_contents.begin(); iter != m_contents.end(); ++iter) { + safe_delete(iter->second); } m_contents.clear(); } @@ -1715,6 +1702,8 @@ void ItemInst::Clear() // Remove all items from container void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent) { + // TODO: This needs work... + // Destroy container contents iter_contents cur, end, del; cur = m_contents.begin(); @@ -1765,6 +1754,9 @@ void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent) uint8 ItemInst::FirstOpenSlot() const { + if (!m_item) + return INVALID_INDEX; + uint8 slots = m_item->BagSlots, i; for (i = SUB_BEGIN; i < slots; i++) { if (!GetItem(i)) @@ -1778,21 +1770,22 @@ uint8 ItemInst::GetTotalItemCount() const { uint8 item_count = 1; - if (m_item->ItemClass != ItemClassContainer) { return item_count; } + if (m_item && m_item->ItemClass != ItemClassContainer) { return item_count; } - for (int idx = SUB_BEGIN; idx < m_item->BagSlots; idx++) { if (GetItem(idx)) { item_count++; } } + for (int index = SUB_BEGIN; index < m_item->BagSlots; ++index) { if (GetItem(index)) { ++item_count; } } return item_count; } bool ItemInst::IsNoneEmptyContainer() { - if (m_item->ItemClass != ItemClassContainer) + if (!m_item || m_item->ItemClass != ItemClassContainer) return false; - for (int i = SUB_BEGIN; i < m_item->BagSlots; ++i) - if (GetItem(i)) + for (int index = SUB_BEGIN; index < m_item->BagSlots; ++index) { + if (GetItem(index)) return true; + } return false; } @@ -1800,7 +1793,7 @@ bool ItemInst::IsNoneEmptyContainer() // Retrieve augment inside item ItemInst* ItemInst::GetAugment(uint8 slot) const { - if (m_item->ItemClass == ItemClassCommon) + if (m_item && m_item->ItemClass == ItemClassCommon) return GetItem(slot); return nullptr; @@ -1808,23 +1801,23 @@ ItemInst* ItemInst::GetAugment(uint8 slot) const ItemInst* ItemInst::GetOrnamentationAug(int32 ornamentationAugtype) const { - if (ornamentationAugtype > 0) + if (!m_item || m_item->ItemClass != ItemClassCommon) { return nullptr; } + if (ornamentationAugtype == 0) { return nullptr; } + + for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) + if (GetAugment(i) && m_item->AugSlotType[i] == ornamentationAugtype) { - if (GetAugment(i) && m_item->AugSlotType[i] == ornamentationAugtype) + const char *item_IDFile = GetAugment(i)->GetItem()->IDFile; + if ( + (strncmp(item_IDFile, "IT64", strlen(item_IDFile)) == 0 + || strncmp(item_IDFile, "IT63", strlen(item_IDFile)) == 0) + && GetAugment(i)->GetItem()->HerosForgeModel == 0 + ) { - const char *item_IDFile = GetAugment(i)->GetItem()->IDFile; - if ( - (strncmp(item_IDFile, "IT64", strlen(item_IDFile)) == 0 - || strncmp(item_IDFile, "IT63", strlen(item_IDFile)) == 0) - && GetAugment(i)->GetItem()->HerosForgeModel == 0 - ) - { - continue; - } - return this->GetAugment(i); + continue; } + return this->GetAugment(i); } } @@ -1845,37 +1838,38 @@ uint32 ItemInst::GetOrnamentHeroModel(int32 material_slot) const { } bool ItemInst::UpdateOrnamentationInfo() { + if (!m_item || m_item->ItemClass != ItemClassCommon) + return false; + bool ornamentSet = false; - if (IsType(ItemClassCommon)) + int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); + if (GetOrnamentationAug(ornamentationAugtype)) { - int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - if (GetOrnamentationAug(ornamentationAugtype)) + const Item_Struct* ornamentItem; + ornamentItem = GetOrnamentationAug(ornamentationAugtype)->GetItem(); + if (ornamentItem != nullptr) { - const Item_Struct* ornamentItem; - ornamentItem = GetOrnamentationAug(ornamentationAugtype)->GetItem(); - if (ornamentItem != nullptr) + SetOrnamentIcon(ornamentItem->Icon); + SetOrnamentHeroModel(ornamentItem->HerosForgeModel); + if (strlen(ornamentItem->IDFile) > 2) { - SetOrnamentIcon(ornamentItem->Icon); - SetOrnamentHeroModel(ornamentItem->HerosForgeModel); - if (strlen(ornamentItem->IDFile) > 2) - { - SetOrnamentationIDFile(atoi(&ornamentItem->IDFile[2])); - } - else - { - SetOrnamentationIDFile(0); - } - ornamentSet = true; + SetOrnamentationIDFile(atoi(&ornamentItem->IDFile[2])); } - } - else - { - SetOrnamentIcon(0); - SetOrnamentHeroModel(0); - SetOrnamentationIDFile(0); + else + { + SetOrnamentationIDFile(0); + } + ornamentSet = true; } } + else + { + SetOrnamentIcon(0); + SetOrnamentHeroModel(0); + SetOrnamentationIDFile(0); + } + return ornamentSet; } @@ -1927,54 +1921,60 @@ bool ItemInst::CanTransform(const Item_Struct *ItemToTry, const Item_Struct *Con uint32 ItemInst::GetAugmentItemID(uint8 slot) const { - uint32 id = NO_ITEM; - if (m_item->ItemClass == ItemClassCommon) { - return GetItemID(slot); - } + if (!m_item || m_item->ItemClass != ItemClassCommon) + return NO_ITEM; - return id; + return GetItemID(slot); } // Add an augment to the item void ItemInst::PutAugment(uint8 slot, const ItemInst& augment) { - if (m_item->ItemClass == ItemClassCommon) - PutItem(slot, augment); + if (!m_item || m_item->ItemClass != ItemClassCommon) + return; + + PutItem(slot, augment); } void ItemInst::PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id) { - if (item_id != NO_ITEM) { - const ItemInst* aug = db->CreateItem(item_id); - if (aug) - { - PutAugment(slot, *aug); - safe_delete(aug); - } - } + if (item_id == NO_ITEM) { return; } + if (db == nullptr) { return; /* TODO: add log message for nullptr */ } + + const ItemInst* aug = db->CreateItem(item_id); + if (aug) { + PutAugment(slot, *aug); + safe_delete(aug); + } } // Remove augment from item and destroy it void ItemInst::DeleteAugment(uint8 index) { - if (m_item->ItemClass == ItemClassCommon) - DeleteItem(index); + if (!m_item || m_item->ItemClass != ItemClassCommon) + return; + + DeleteItem(index); } // Remove augment from item and return it ItemInst* ItemInst::RemoveAugment(uint8 index) { - if (m_item->ItemClass == ItemClassCommon) - return PopItem(index); - - return nullptr; + if (!m_item || m_item->ItemClass != ItemClassCommon) + return nullptr; + + return PopItem(index); } bool ItemInst::IsAugmented() { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; ++i) - if (GetAugmentItemID(i)) + if (!m_item || m_item->ItemClass != ItemClassCommon) + return false; + + for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + if (GetAugmentItemID(index)) return true; + } return false; } @@ -1984,33 +1984,43 @@ bool ItemInst::IsWeapon() const { if (!m_item || m_item->ItemClass != ItemClassCommon) return false; + if (m_item->ItemType == ItemTypeArrow && m_item->Damage != 0) return true; else return ((m_item->Damage != 0) && (m_item->Delay != 0)); } -bool ItemInst::IsAmmo() const { - - if (!m_item) return false; +bool ItemInst::IsAmmo() const +{ + if (!m_item) + return false; if ((m_item->ItemType == ItemTypeArrow) || (m_item->ItemType == ItemTypeLargeThrowing) || - (m_item->ItemType == ItemTypeSmallThrowing)) + (m_item->ItemType == ItemTypeSmallThrowing) + ) { return true; + } return false; } -const Item_Struct* ItemInst::GetItem() const { - if (!m_scaledItem) - return m_item; - else +const Item_Struct* ItemInst::GetItem() const +{ + if (!m_item) + return nullptr; + + if (m_scaledItem) return m_scaledItem; + + return m_item; } -const Item_Struct* ItemInst::GetUnscaledItem() const { +const Item_Struct* ItemInst::GetUnscaledItem() const +{ + // No operator calls and defaults to nullptr return m_item; } @@ -2112,6 +2122,9 @@ void ItemInst::Initialize(SharedDatabase *db) { } void ItemInst::ScaleItem() { + if (!m_item) + return; + if (m_scaledItem) { memcpy(m_scaledItem, m_item, sizeof(Item_Struct)); } @@ -2255,6 +2268,7 @@ EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 } EvolveInfo::~EvolveInfo() { + } @@ -2267,18 +2281,13 @@ bool Item_Struct::IsEquipable(uint16 Race, uint16 Class_) const bool IsClass = false; uint32 Classes_ = Classes; - uint32 Races_ = Races; - uint32 Race_ = GetArrayRace(Race); - for (int CurrentClass = 1; CurrentClass <= PLAYER_CLASS_COUNT; ++CurrentClass) - { - if (Classes_ % 2 == 1) - { - if (CurrentClass == Class_) - { - IsClass = true; + for (int CurrentClass = 1; CurrentClass <= PLAYER_CLASS_COUNT; ++CurrentClass) { + if (Classes_ & 1) { + if (CurrentClass == Class_) { + IsClass = true; break; } } @@ -2287,17 +2296,15 @@ bool Item_Struct::IsEquipable(uint16 Race, uint16 Class_) const Race_ = (Race_ == 18 ? 16 : Race_); - for (unsigned int CurrentRace = 1; CurrentRace <= PLAYER_RACE_COUNT; ++CurrentRace) - { - if (Races_ % 2 == 1) - { - if (CurrentRace == Race_) - { - IsRace = true; + for (unsigned int CurrentRace = 1; CurrentRace <= PLAYER_RACE_COUNT; ++CurrentRace) { + if (Races_ & 1) { + if (CurrentRace == Race_) { + IsRace = true; break; } } Races_ >>= 1; } + return (IsRace && IsClass); } diff --git a/common/item.h b/common/item.h index 03182e4dd..888d47d2b 100644 --- a/common/item.h +++ b/common/item.h @@ -34,7 +34,6 @@ class EvolveInfo; // Stores information about an evolving item family #include // Helper typedefs -typedef std::list::const_iterator iter_queue; typedef std::map::const_iterator iter_inst; typedef std::map::const_iterator iter_contents; @@ -87,15 +86,17 @@ public: // Public Methods ///////////////////////// - inline iter_queue begin() { return m_list.begin(); } - inline iter_queue end() { return m_list.end(); } + inline std::list::const_iterator begin() { return m_list.begin(); } + inline std::list::const_iterator end() { return m_list.end(); } + + inline int size() { return static_cast(m_list.size()); } // TODO: change to size_t + inline bool empty() { return m_list.empty(); } 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()); } protected: ///////////////////////// @@ -103,7 +104,6 @@ protected: ///////////////////////// std::list m_list; - }; // ######################################## @@ -140,9 +140,11 @@ public: ItemInst* GetItem(int16 slot_id) const; ItemInst* GetItem(int16 slot_id, uint8 bagidx) const; - inline iter_queue cursor_begin() { return m_cursor.begin(); } - inline iter_queue cursor_end() { return m_cursor.end(); } - inline bool CursorEmpty() { return (m_cursor.size() == 0); } + inline std::list::const_iterator cursor_begin() { return m_cursor.begin(); } + inline std::list::const_iterator cursor_end() { return m_cursor.end(); } + + inline int CursorSize() { return m_cursor.size(); } + inline bool CursorEmpty() { return m_cursor.empty(); } // Retrieve a read-only item from inventory inline const ItemInst* operator[](int16 slot_id) const { return GetItem(slot_id); } @@ -291,15 +293,15 @@ public: bool IsEquipable(int16 slot_id) const; // - // Augements + // Augments // - inline bool IsAugmentable() const { return m_item->AugSlotType[0] != 0 || m_item->AugSlotType[1] != 0 || m_item->AugSlotType[2] != 0 || m_item->AugSlotType[3] != 0 || m_item->AugSlotType[4] != 0 || m_item->AugSlotType[5] != 0; } + bool IsAugmentable() const; bool AvailableWearSlot(uint32 aug_wear_slots) const; int8 AvailableAugmentSlot(int32 augtype) const; bool IsAugmentSlotAvailable(int32 augtype, uint8 slot) const; - inline int32 GetAugmentType() const { return m_item->AugType; } + inline int32 GetAugmentType() const { return ((m_item) ? m_item->AugType : NO_ITEM); } - inline bool IsExpendable() const { return ((m_item->Click.Type == ET_Expendable ) || (m_item->ItemType == ItemTypePotion)); } + inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == ET_Expendable ) || (m_item->ItemType == ItemTypePotion)) : false); } // // Contents @@ -337,8 +339,8 @@ public: bool IsAmmo() const; // Accessors - const uint32 GetID() const { return m_item->ID; } - const uint32 GetItemScriptID() const { return m_item->ScriptFileID; } + const uint32 GetID() const { return ((m_item) ? m_item->ID : NO_ITEM); } + const uint32 GetItemScriptID() const { return ((m_item) ? m_item->ScriptFileID : NO_ITEM); } const Item_Struct* GetItem() const; const Item_Struct* GetUnscaledItem() const; @@ -351,18 +353,18 @@ public: void SetColor(uint32 color) { m_color = color; } uint32 GetColor() const { return m_color; } - uint32 GetMerchantSlot() const { return m_merchantslot; } + uint32 GetMerchantSlot() const { return m_merchantslot; } void SetMerchantSlot(uint32 slot) { m_merchantslot = slot; } - int32 GetMerchantCount() const { return m_merchantcount; } + int32 GetMerchantCount() const { return m_merchantcount; } void SetMerchantCount(int32 count) { m_merchantcount = count; } int16 GetCurrentSlot() const { return m_currentslot; } void SetCurrentSlot(int16 curr_slot) { m_currentslot = curr_slot; } // Is this item already attuned? - bool IsAttuned() const { return m_attuned; } - void SetAttuned(bool flag) { m_attuned=flag; } + bool IsAttuned() const { return m_attuned; } + void SetAttuned(bool flag) { m_attuned=flag; } std::string GetCustomDataString() const; std::string GetCustomData(std::string identifier); diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 6a575ca13..1068a6d47 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -831,6 +831,34 @@ namespace RoF FINISH_ENCODE(); } + ENCODE(OP_Emote) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + Emote_Struct *emu = (Emote_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + std::string old_message = emu->message; + std::string new_message; + ServerToRoFTextLink(new_message, old_message); + + //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) + // new_message = new_message.substr(0, 512); + + in->size = new_message.length() + 5; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_ExpansionInfo) { ENCODE_LENGTH_EXACT(ExpansionInfo_Struct); @@ -841,6 +869,55 @@ namespace RoF FINISH_ENCODE(); } + ENCODE(OP_FormattedMessage) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + FormattedMessage_Struct *emu = (FormattedMessage_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + char *old_message_ptr = (char *)in->pBuffer; + old_message_ptr += sizeof(FormattedMessage_Struct); + + std::string old_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (*old_message_ptr == 0) { break; } + old_message_array[i] = old_message_ptr; + old_message_ptr += old_message_array[i].length() + 1; + } + + uint32 new_message_size = 0; + std::string new_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (old_message_array[i].length() == 0) { break; } + ServerToRoFTextLink(new_message_array[i], old_message_array[i]); + new_message_size += new_message_array[i].length() + 1; + } + + in->size = sizeof(FormattedMessage_Struct) + new_message_size + 1; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->unknown0); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->string_id); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + + for (int i = 0; i < 9; ++i) { + if (new_message_array[i].length() == 0) { break; } + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message_array[i].c_str()); + } + + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_GMLastName) { ENCODE_LENGTH_EXACT(GMLastName_Struct); @@ -3118,10 +3195,11 @@ namespace RoF std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; + ServerToRoFTextLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = 25 + strlen(emu->sayer) + new_message.length(); + in->size = strlen(emu->sayer) + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -3135,9 +3213,18 @@ namespace RoF VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); @@ -3164,6 +3251,51 @@ namespace RoF EQApplicationPacket *in = *p; *p = nullptr; + unsigned char *__emu_buffer = in->pBuffer; + + char *InBuffer = (char *)in->pBuffer; + char *block_start = InBuffer; + + InBuffer += sizeof(TaskDescriptionHeader_Struct); + uint32 title_size = strlen(InBuffer) + 1; + InBuffer += title_size; + + TaskDescriptionData1_Struct *emu_tdd1 = (TaskDescriptionData1_Struct *)InBuffer; + emu_tdd1->StartTime = (time(nullptr) - emu_tdd1->StartTime); // RoF has elapsed time here rather than start time + + InBuffer += sizeof(TaskDescriptionData1_Struct); + uint32 description_size = strlen(InBuffer) + 1; + InBuffer += description_size; + InBuffer += sizeof(TaskDescriptionData2_Struct); + + std::string old_message = InBuffer; // start 'Reward' as string + std::string new_message; + ServerToRoFTextLink(new_message, old_message); + + in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ + sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ + title_size + description_size + new_message.length() + 1; + + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + memcpy(OutBuffer, block_start, (InBuffer - block_start)); + OutBuffer += (InBuffer - block_start); + + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + InBuffer += strlen(InBuffer) + 1; + + memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct)); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + +#if 0 // original code + EQApplicationPacket *in = *p; + *p = nullptr; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_TaskDescription, in->size + 1); // Set the Write pointer as we don't know what has been done with the packet before we get it. in->SetReadPosition(0); @@ -3187,6 +3319,7 @@ namespace RoF delete in; dest->FastQueuePacket(&outapp, ack_req); +#endif } ENCODE(OP_TaskHistoryReply) @@ -4220,6 +4353,27 @@ namespace RoF FINISH_DIRECT_DECODE(); } + DECODE(OP_Emote) + { + unsigned char *__eq_buffer = __packet->pBuffer; + + std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset + std::string new_message; + RoFToServerTextLink(new_message, old_message); + + __packet->size = sizeof(Emote_Struct); + __packet->pBuffer = new unsigned char[__packet->size]; + + char *InBuffer = (char *)__packet->pBuffer; + + memcpy(InBuffer, __eq_buffer, 4); + InBuffer += 4; + strcpy(InBuffer, new_message.substr(0, 1023).c_str()); + InBuffer[1023] = '\0'; + + delete[] __eq_buffer; + } + DECODE(OP_EnvDamage) { DECODE_LENGTH_EXACT(structs::EnvDamage2_Struct); @@ -5644,73 +5798,73 @@ namespace RoF static inline void ServerToRoFTextLink(std::string& rofTextLink, const std::string& serverTextLink) { - const char delimiter = 0x12; - - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) { + if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { rofTextLink = serverTextLink; return; } - auto segments = SplitString(serverTextLink, delimiter); + auto segments = SplitString(serverTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + rofTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // RoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (55) // Diff: ^ - new_segment.append(segments[segment_iter].substr(0, 41).c_str()); + rofTextLink.push_back('\x12'); + rofTextLink.append(segments[segment_iter].substr(0, 41)); - if (segments[segment_iter].substr(41, 1) == "0") - new_segment.append(segments[segment_iter].substr(42, 1).c_str()); + if (segments[segment_iter][41] == '0') + rofTextLink.push_back(segments[segment_iter][42]); else - new_segment.append("F"); + rofTextLink.push_back('F'); - new_segment.append(segments[segment_iter].substr(43).c_str()); - - rofTextLink.push_back(delimiter); - rofTextLink.append(new_segment.c_str()); - rofTextLink.push_back(delimiter); + rofTextLink.append(segments[segment_iter].substr(43)); + rofTextLink.push_back('\x12'); } else { - rofTextLink.append(segments[segment_iter].c_str()); + rofTextLink.append(segments[segment_iter]); } } } static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink) { - const char delimiter = 0x12; - - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rofTextLink.find(delimiter) == std::string::npos)) { + if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rofTextLink.find('\x12') == std::string::npos)) { serverTextLink = rofTextLink; return; } - auto segments = SplitString(rofTextLink, delimiter); + auto segments = SplitString(rofTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + serverTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 36 37 41 42 47 (Source) // RoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (55) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^ - new_segment.append(segments[segment_iter].substr(0, 41).c_str()); - new_segment.append("0"); - new_segment.append(segments[segment_iter].substr(41).c_str()); - - serverTextLink.push_back(delimiter); - serverTextLink.append(new_segment.c_str()); - serverTextLink.push_back(delimiter); + serverTextLink.push_back('\x12'); + serverTextLink.append(segments[segment_iter].substr(0, 41)); + serverTextLink.push_back('0'); + serverTextLink.append(segments[segment_iter].substr(41)); + serverTextLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter].c_str()); + serverTextLink.append(segments[segment_iter]); } } } diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 0c61145d0..8dd07286a 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -897,6 +897,34 @@ namespace RoF2 FINISH_ENCODE(); } + ENCODE(OP_Emote) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + Emote_Struct *emu = (Emote_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + std::string old_message = emu->message; + std::string new_message; + ServerToRoF2TextLink(new_message, old_message); + + //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) + // new_message = new_message.substr(0, 512); + + in->size = new_message.length() + 5; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_ExpansionInfo) { ENCODE_LENGTH_EXACT(ExpansionInfo_Struct); @@ -907,6 +935,55 @@ namespace RoF2 FINISH_ENCODE(); } + ENCODE(OP_FormattedMessage) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + FormattedMessage_Struct *emu = (FormattedMessage_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + char *old_message_ptr = (char *)in->pBuffer; + old_message_ptr += sizeof(FormattedMessage_Struct); + + std::string old_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (*old_message_ptr == 0) { break; } + old_message_array[i] = old_message_ptr; + old_message_ptr += old_message_array[i].length() + 1; + } + + uint32 new_message_size = 0; + std::string new_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (old_message_array[i].length() == 0) { break; } + ServerToRoF2TextLink(new_message_array[i], old_message_array[i]); + new_message_size += new_message_array[i].length() + 1; + } + + in->size = sizeof(FormattedMessage_Struct) + new_message_size + 1; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->unknown0); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->string_id); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + + for (int i = 0; i < 9; ++i) { + if (new_message_array[i].length() == 0) { break; } + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message_array[i].c_str()); + } + + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_GMLastName) { ENCODE_LENGTH_EXACT(GMLastName_Struct); @@ -3184,10 +3261,11 @@ namespace RoF2 std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; + ServerToRoF2TextLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = 25 + strlen(emu->sayer) + new_message.length(); + in->size = strlen(emu->sayer) + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -3201,9 +3279,18 @@ namespace RoF2 VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); @@ -3230,6 +3317,51 @@ namespace RoF2 EQApplicationPacket *in = *p; *p = nullptr; + unsigned char *__emu_buffer = in->pBuffer; + + char *InBuffer = (char *)in->pBuffer; + char *block_start = InBuffer; + + InBuffer += sizeof(TaskDescriptionHeader_Struct); + uint32 title_size = strlen(InBuffer) + 1; + InBuffer += title_size; + + TaskDescriptionData1_Struct *emu_tdd1 = (TaskDescriptionData1_Struct *)InBuffer; + emu_tdd1->StartTime = (time(nullptr) - emu_tdd1->StartTime); // RoF2 has elapsed time here rather than start time + + InBuffer += sizeof(TaskDescriptionData1_Struct); + uint32 description_size = strlen(InBuffer) + 1; + InBuffer += description_size; + InBuffer += sizeof(TaskDescriptionData2_Struct); + + std::string old_message = InBuffer; // start 'Reward' as string + std::string new_message; + ServerToRoF2TextLink(new_message, old_message); + + in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ + sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ + title_size + description_size + new_message.length() + 1; + + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + memcpy(OutBuffer, block_start, (InBuffer - block_start)); + OutBuffer += (InBuffer - block_start); + + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + InBuffer += strlen(InBuffer) + 1; + + memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct)); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + +#if 0 // original code + EQApplicationPacket *in = *p; + *p = nullptr; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_TaskDescription, in->size + 1); // Set the Write pointer as we don't know what has been done with the packet before we get it. in->SetReadPosition(0); @@ -3253,6 +3385,7 @@ namespace RoF2 delete in; dest->FastQueuePacket(&outapp, ack_req); +#endif } ENCODE(OP_TaskHistoryReply) @@ -4292,6 +4425,27 @@ namespace RoF2 FINISH_DIRECT_DECODE(); } + DECODE(OP_Emote) + { + unsigned char *__eq_buffer = __packet->pBuffer; + + std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset + std::string new_message; + RoF2ToServerTextLink(new_message, old_message); + + __packet->size = sizeof(Emote_Struct); + __packet->pBuffer = new unsigned char[__packet->size]; + + char *InBuffer = (char *)__packet->pBuffer; + + memcpy(InBuffer, __eq_buffer, 4); + InBuffer += 4; + strcpy(InBuffer, new_message.substr(0, 1023).c_str()); + InBuffer[1023] = '\0'; + + delete[] __eq_buffer; + } + DECODE(OP_EnvDamage) { DECODE_LENGTH_EXACT(structs::EnvDamage2_Struct); @@ -5738,64 +5892,64 @@ namespace RoF2 static inline void ServerToRoF2TextLink(std::string& rof2TextLink, const std::string& serverTextLink) { - const char delimiter = 0x12; - - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) { + if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { rof2TextLink = serverTextLink; return; } - auto segments = SplitString(serverTextLink, delimiter); + auto segments = SplitString(serverTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + rof2TextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: - new_segment.append(segments[segment_iter]); - - rof2TextLink.push_back(delimiter); - rof2TextLink.append(new_segment.c_str()); - rof2TextLink.push_back(delimiter); + rof2TextLink.push_back('\x12'); + rof2TextLink.append(segments[segment_iter]); + rof2TextLink.push_back('\x12'); } else { - rof2TextLink.append(segments[segment_iter].c_str()); + rof2TextLink.append(segments[segment_iter]); } } } static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink) { - const char delimiter = 0x12; - - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rof2TextLink.find(delimiter) == std::string::npos)) { + if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rof2TextLink.find('\x12') == std::string::npos)) { serverTextLink = rof2TextLink; return; } - auto segments = SplitString(rof2TextLink, delimiter); + auto segments = SplitString(rof2TextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + serverTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: - new_segment.append(segments[segment_iter]); - - serverTextLink.push_back(delimiter); - serverTextLink.append(new_segment.c_str()); - serverTextLink.push_back(delimiter); + serverTextLink.push_back('\x12'); + serverTextLink.append(segments[segment_iter]); + serverTextLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter].c_str()); + serverTextLink.append(segments[segment_iter]); } } } diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 66b86d756..c2a1bb5e6 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -42,7 +42,9 @@ E(OP_DzExpeditionList) E(OP_DzJoinExpeditionConfirm) E(OP_DzLeaderStatus) E(OP_DzMemberList) +E(OP_Emote) E(OP_ExpansionInfo) +E(OP_FormattedMessage) E(OP_GMLastName) E(OP_GMTrainSkillConfirm) E(OP_GroundSpawn) @@ -133,6 +135,7 @@ D(OP_ConsiderCorpse) D(OP_Consume) D(OP_Damage) D(OP_DeleteItem) +D(OP_Emote) D(OP_EnvDamage) D(OP_FaceChange) D(OP_FindPersonRequest) diff --git a/common/patches/rof_ops.h b/common/patches/rof_ops.h index ef97dda99..ce994ea11 100644 --- a/common/patches/rof_ops.h +++ b/common/patches/rof_ops.h @@ -31,7 +31,9 @@ E(OP_DzExpeditionList) E(OP_DzJoinExpeditionConfirm) E(OP_DzLeaderStatus) E(OP_DzMemberList) +E(OP_Emote) E(OP_ExpansionInfo) +E(OP_FormattedMessage) E(OP_GMLastName) E(OP_GMTrainSkillConfirm) E(OP_GroundSpawn) @@ -122,6 +124,7 @@ D(OP_ConsiderCorpse) D(OP_Consume) D(OP_Damage) D(OP_DeleteItem) +D(OP_Emote) D(OP_EnvDamage) D(OP_FaceChange) D(OP_FindPersonRequest) diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index eb53b333d..8b85a5dd2 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -600,6 +600,34 @@ namespace SoD FINISH_ENCODE(); } + ENCODE(OP_Emote) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + Emote_Struct *emu = (Emote_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + std::string old_message = emu->message; + std::string new_message; + ServerToSoDTextLink(new_message, old_message); + + //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) + // new_message = new_message.substr(0, 512); + + in->size = new_message.length() + 5; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_ExpansionInfo) { ENCODE_LENGTH_EXACT(ExpansionInfo_Struct); @@ -610,6 +638,55 @@ namespace SoD FINISH_ENCODE(); } + ENCODE(OP_FormattedMessage) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + FormattedMessage_Struct *emu = (FormattedMessage_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + char *old_message_ptr = (char *)in->pBuffer; + old_message_ptr += sizeof(FormattedMessage_Struct); + + std::string old_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (*old_message_ptr == 0) { break; } + old_message_array[i] = old_message_ptr; + old_message_ptr += old_message_array[i].length() + 1; + } + + uint32 new_message_size = 0; + std::string new_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (old_message_array[i].length() == 0) { break; } + ServerToSoDTextLink(new_message_array[i], old_message_array[i]); + new_message_size += new_message_array[i].length() + 1; + } + + in->size = sizeof(FormattedMessage_Struct) + new_message_size + 1; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->unknown0); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->string_id); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + + for (int i = 0; i < 9; ++i) { + if (new_message_array[i].length() == 0) { break; } + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message_array[i].c_str()); + } + + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_GroundSpawn) { ENCODE_LENGTH_EXACT(Object_Struct); @@ -2010,10 +2087,11 @@ namespace SoD std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; + ServerToSoDTextLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = 25 + strlen(emu->sayer) + new_message.length(); + in->size = strlen(emu->sayer) + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -2027,9 +2105,18 @@ namespace SoD VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); @@ -2096,6 +2183,49 @@ namespace SoD FINISH_ENCODE(); } + ENCODE(OP_TaskDescription) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *__emu_buffer = in->pBuffer; + + char *InBuffer = (char *)in->pBuffer; + char *block_start = InBuffer; + + InBuffer += sizeof(TaskDescriptionHeader_Struct); + uint32 title_size = strlen(InBuffer) + 1; + InBuffer += title_size; + InBuffer += sizeof(TaskDescriptionData1_Struct); + uint32 description_size = strlen(InBuffer) + 1; + InBuffer += description_size; + InBuffer += sizeof(TaskDescriptionData2_Struct); + + std::string old_message = InBuffer; // start 'Reward' as string + std::string new_message; + ServerToSoDTextLink(new_message, old_message); + + in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ + sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ + title_size + description_size + new_message.length() + 1; + + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + memcpy(OutBuffer, block_start, (InBuffer - block_start)); + OutBuffer += (InBuffer - block_start); + + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + InBuffer += strlen(InBuffer) + 1; + + memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct)); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_Track) { EQApplicationPacket *in = *p; @@ -2917,6 +3047,27 @@ namespace SoD FINISH_DIRECT_DECODE(); } + DECODE(OP_Emote) + { + unsigned char *__eq_buffer = __packet->pBuffer; + + std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset + std::string new_message; + SoDToServerTextLink(new_message, old_message); + + __packet->size = sizeof(Emote_Struct); + __packet->pBuffer = new unsigned char[__packet->size]; + + char *InBuffer = (char *)__packet->pBuffer; + + memcpy(InBuffer, __eq_buffer, 4); + InBuffer += 4; + strcpy(InBuffer, new_message.substr(0, 1023).c_str()); + InBuffer[1023] = '\0'; + + delete[] __eq_buffer; + } + DECODE(OP_FaceChange) { DECODE_LENGTH_EXACT(structs::FaceChange_Struct); @@ -3862,76 +4013,76 @@ namespace SoD static inline void ServerToSoDTextLink(std::string& sodTextLink, const std::string& serverTextLink) { - const char delimiter = 0x12; - - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) { + if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { sodTextLink = serverTextLink; return; } - auto segments = SplitString(serverTextLink, delimiter); + auto segments = SplitString(serverTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + sodTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // Diff: ^^^^^ ^ - new_segment.append(segments[segment_iter].substr(0, 31).c_str()); - new_segment.append(segments[segment_iter].substr(36, 5).c_str()); + sodTextLink.push_back('\x12'); + sodTextLink.append(segments[segment_iter].substr(0, 31)); + sodTextLink.append(segments[segment_iter].substr(36, 5)); - if (segments[segment_iter].substr(41, 1) == "0") - new_segment.append(segments[segment_iter].substr(42, 1).c_str()); + if (segments[segment_iter][41] == '0') + sodTextLink.push_back(segments[segment_iter][42]); else - new_segment.append("F"); + sodTextLink.push_back('F'); - new_segment.append(segments[segment_iter].substr(43).c_str()); - - sodTextLink.push_back(delimiter); - sodTextLink.append(new_segment.c_str()); - sodTextLink.push_back(delimiter); + sodTextLink.append(segments[segment_iter].substr(43)); + sodTextLink.push_back('\x12'); } else { - sodTextLink.append(segments[segment_iter].c_str()); + sodTextLink.append(segments[segment_iter]); } } } static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink) { - const char delimiter = 0x12; - - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sodTextLink.find(delimiter) == std::string::npos)) { + if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sodTextLink.find('\x12') == std::string::npos)) { serverTextLink = sodTextLink; return; } - auto segments = SplitString(sodTextLink, delimiter); + auto segments = SplitString(sodTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + serverTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source) // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^^^^^ ^ - new_segment.append(segments[segment_iter].substr(0, 31).c_str()); - new_segment.append("00000"); - new_segment.append(segments[segment_iter].substr(31, 5).c_str()); - new_segment.append("0"); - new_segment.append(segments[segment_iter].substr(36).c_str()); - - serverTextLink.push_back(delimiter); - serverTextLink.append(new_segment.c_str()); - serverTextLink.push_back(delimiter); + serverTextLink.push_back('\x12'); + serverTextLink.append(segments[segment_iter].substr(0, 31)); + serverTextLink.append("00000"); + serverTextLink.append(segments[segment_iter].substr(31, 5)); + serverTextLink.push_back('0'); + serverTextLink.append(segments[segment_iter].substr(36)); + serverTextLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter].c_str()); + serverTextLink.append(segments[segment_iter]); } } } diff --git a/common/patches/sod_ops.h b/common/patches/sod_ops.h index 0a0a8a4d5..3ce2ac2cb 100644 --- a/common/patches/sod_ops.h +++ b/common/patches/sod_ops.h @@ -22,7 +22,9 @@ E(OP_DzExpeditionList) E(OP_DzJoinExpeditionConfirm) E(OP_DzLeaderStatus) E(OP_DzMemberList) +E(OP_Emote) E(OP_ExpansionInfo) +E(OP_FormattedMessage) E(OP_GroundSpawn) E(OP_GroupCancelInvite) E(OP_GroupFollow) @@ -61,6 +63,7 @@ E(OP_SpawnDoor) E(OP_SpecialMesg) E(OP_Stun) E(OP_TargetBuffs) +E(OP_TaskDescription) E(OP_Track) E(OP_Trader) E(OP_TraderBuy) @@ -90,6 +93,7 @@ D(OP_Consider) D(OP_ConsiderCorpse) D(OP_Consume) D(OP_DeleteItem) +D(OP_Emote) D(OP_FaceChange) D(OP_FindPersonRequest) D(OP_GroupCancelInvite) diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 4d3c61da7..7899d6681 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -587,6 +587,34 @@ namespace SoF FINISH_ENCODE(); } + ENCODE(OP_Emote) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + Emote_Struct *emu = (Emote_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + std::string old_message = emu->message; + std::string new_message; + ServerToSoFTextLink(new_message, old_message); + + //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) + // new_message = new_message.substr(0, 512); + + in->size = new_message.length() + 5; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_ExpansionInfo) { ENCODE_LENGTH_EXACT(ExpansionInfo_Struct); @@ -597,6 +625,55 @@ namespace SoF FINISH_ENCODE(); } + ENCODE(OP_FormattedMessage) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + FormattedMessage_Struct *emu = (FormattedMessage_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + char *old_message_ptr = (char *)in->pBuffer; + old_message_ptr += sizeof(FormattedMessage_Struct); + + std::string old_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (*old_message_ptr == 0) { break; } + old_message_array[i] = old_message_ptr; + old_message_ptr += old_message_array[i].length() + 1; + } + + uint32 new_message_size = 0; + std::string new_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (old_message_array[i].length() == 0) { break; } + ServerToSoFTextLink(new_message_array[i], old_message_array[i]); + new_message_size += new_message_array[i].length() + 1; + } + + in->size = sizeof(FormattedMessage_Struct) + new_message_size + 1; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->unknown0); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->string_id); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + + for (int i = 0; i < 9; ++i) { + if (new_message_array[i].length() == 0) { break; } + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message_array[i].c_str()); + } + + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_GroundSpawn) { ENCODE_LENGTH_EXACT(Object_Struct); @@ -1656,10 +1733,11 @@ namespace SoF std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; + ServerToSoFTextLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = 25 + strlen(emu->sayer) + new_message.length(); + in->size = strlen(emu->sayer) + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -1673,9 +1751,18 @@ namespace SoF VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); @@ -1695,6 +1782,49 @@ namespace SoF FINISH_ENCODE(); } + ENCODE(OP_TaskDescription) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *__emu_buffer = in->pBuffer; + + char *InBuffer = (char *)in->pBuffer; + char *block_start = InBuffer; + + InBuffer += sizeof(TaskDescriptionHeader_Struct); + uint32 title_size = strlen(InBuffer) + 1; + InBuffer += title_size; + InBuffer += sizeof(TaskDescriptionData1_Struct); + uint32 description_size = strlen(InBuffer) + 1; + InBuffer += description_size; + InBuffer += sizeof(TaskDescriptionData2_Struct); + + std::string old_message = InBuffer; // start 'Reward' as string + std::string new_message; + ServerToSoFTextLink(new_message, old_message); + + in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ + sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ + title_size + description_size + new_message.length() + 1; + + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + memcpy(OutBuffer, block_start, (InBuffer - block_start)); + OutBuffer += (InBuffer - block_start); + + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + InBuffer += strlen(InBuffer) + 1; + + memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct)); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_Track) { EQApplicationPacket *in = *p; @@ -2317,6 +2447,27 @@ namespace SoF FINISH_DIRECT_DECODE(); } + DECODE(OP_Emote) + { + unsigned char *__eq_buffer = __packet->pBuffer; + + std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset + std::string new_message; + SoFToServerTextLink(new_message, old_message); + + __packet->size = sizeof(Emote_Struct); + __packet->pBuffer = new unsigned char[__packet->size]; + + char *InBuffer = (char *)__packet->pBuffer; + + memcpy(InBuffer, __eq_buffer, 4); + InBuffer += 4; + strcpy(InBuffer, new_message.substr(0, 1023).c_str()); + InBuffer[1023] = '\0'; + + delete[] __eq_buffer; + } + DECODE(OP_FaceChange) { DECODE_LENGTH_EXACT(structs::FaceChange_Struct); @@ -3184,76 +3335,76 @@ namespace SoF static inline void ServerToSoFTextLink(std::string& sofTextLink, const std::string& serverTextLink) { - const char delimiter = 0x12; - - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) { + if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { sofTextLink = serverTextLink; return; } - auto segments = SplitString(serverTextLink, delimiter); + auto segments = SplitString(serverTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + sofTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // Diff: ^^^^^ ^ - new_segment.append(segments[segment_iter].substr(0, 31).c_str()); - new_segment.append(segments[segment_iter].substr(36, 5).c_str()); + sofTextLink.push_back('\x12'); + sofTextLink.append(segments[segment_iter].substr(0, 31)); + sofTextLink.append(segments[segment_iter].substr(36, 5)); - if (segments[segment_iter].substr(41, 1) == "0") - new_segment.append(segments[segment_iter].substr(42, 1).c_str()); + if (segments[segment_iter][41] == '0') + sofTextLink.push_back(segments[segment_iter][42]); else - new_segment.append("F"); + sofTextLink.push_back('F'); - new_segment.append(segments[segment_iter].substr(43).c_str()); - - sofTextLink.push_back(delimiter); - sofTextLink.append(new_segment.c_str()); - sofTextLink.push_back(delimiter); + sofTextLink.append(segments[segment_iter].substr(43)); + sofTextLink.push_back('\x12'); } else { - sofTextLink.append(segments[segment_iter].c_str()); + sofTextLink.append(segments[segment_iter]); } } } static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink) { - const char delimiter = 0x12; - - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sofTextLink.find(delimiter) == std::string::npos)) { + if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sofTextLink.find('\x12') == std::string::npos)) { serverTextLink = sofTextLink; return; } - auto segments = SplitString(sofTextLink, delimiter); + auto segments = SplitString(sofTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + serverTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source) // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^^^^^ ^ - new_segment.append(segments[segment_iter].substr(0, 31).c_str()); - new_segment.append("00000"); - new_segment.append(segments[segment_iter].substr(31, 5).c_str()); - new_segment.append("0"); - new_segment.append(segments[segment_iter].substr(36).c_str()); - - serverTextLink.push_back(delimiter); - serverTextLink.append(new_segment.c_str()); - serverTextLink.push_back(delimiter); + serverTextLink.push_back('\x12'); + serverTextLink.append(segments[segment_iter].substr(0, 31)); + serverTextLink.append("00000"); + serverTextLink.append(segments[segment_iter].substr(31, 5)); + serverTextLink.push_back('0'); + serverTextLink.append(segments[segment_iter].substr(36)); + serverTextLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter].c_str()); + serverTextLink.append(segments[segment_iter]); } } } diff --git a/common/patches/sof_ops.h b/common/patches/sof_ops.h index 9cfd400e3..14ad69a8b 100644 --- a/common/patches/sof_ops.h +++ b/common/patches/sof_ops.h @@ -23,7 +23,9 @@ E(OP_DzExpeditionList) E(OP_DzJoinExpeditionConfirm) E(OP_DzLeaderStatus) E(OP_DzMemberList) +E(OP_Emote) E(OP_ExpansionInfo) +E(OP_FormattedMessage) E(OP_GroundSpawn) E(OP_GuildMemberList) E(OP_Illusion) @@ -53,6 +55,7 @@ E(OP_SomeItemPacketMaybe) E(OP_SpawnDoor) E(OP_SpecialMesg) E(OP_Stun) +E(OP_TaskDescription) E(OP_Track) E(OP_Trader) E(OP_TraderBuy) @@ -79,6 +82,7 @@ D(OP_Consider) D(OP_ConsiderCorpse) D(OP_Consume) D(OP_DeleteItem) +D(OP_Emote) D(OP_FaceChange) D(OP_FindPersonRequest) D(OP_GroupFollow) diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 21701de7e..122e93bf3 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -456,6 +456,83 @@ namespace Titanium FINISH_ENCODE(); } + ENCODE(OP_Emote) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + Emote_Struct *emu = (Emote_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + std::string old_message = emu->message; + std::string new_message; + ServerToTitaniumTextLink(new_message, old_message); + + //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) + // new_message = new_message.substr(0, 512); + + in->size = new_message.length() + 5; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_FormattedMessage) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + FormattedMessage_Struct *emu = (FormattedMessage_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + char *old_message_ptr = (char *)in->pBuffer; + old_message_ptr += sizeof(FormattedMessage_Struct); + + std::string old_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (*old_message_ptr == 0) { break; } + old_message_array[i] = old_message_ptr; + old_message_ptr += old_message_array[i].length() + 1; + } + + uint32 new_message_size = 0; + std::string new_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (old_message_array[i].length() == 0) { break; } + ServerToTitaniumTextLink(new_message_array[i], old_message_array[i]); + new_message_size += new_message_array[i].length() + 1; + } + + in->size = sizeof(FormattedMessage_Struct) + new_message_size + 1; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->unknown0); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->string_id); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + + for (int i = 0; i < 9; ++i) { + if (new_message_array[i].length() == 0) { break; } + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message_array[i].c_str()); + } + + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_GuildMemberList) { //consume the packet @@ -1118,10 +1195,11 @@ namespace Titanium std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; + ServerToTitaniumTextLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = 25 + strlen(emu->sayer) + new_message.length(); + in->size = strlen(emu->sayer) + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -1135,12 +1213,64 @@ namespace Titanium VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); + + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_TaskDescription) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *__emu_buffer = in->pBuffer; + + char *InBuffer = (char *)in->pBuffer; + char *block_start = InBuffer; + + InBuffer += sizeof(TaskDescriptionHeader_Struct); + uint32 title_size = strlen(InBuffer) + 1; + InBuffer += title_size; + InBuffer += sizeof(TaskDescriptionData1_Struct); + uint32 description_size = strlen(InBuffer) + 1; + InBuffer += description_size; + InBuffer += sizeof(TaskDescriptionData2_Struct); + + std::string old_message = InBuffer; // start 'Reward' as string + std::string new_message; + ServerToTitaniumTextLink(new_message, old_message); + + in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct) + + sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct) + + title_size + description_size + new_message.length() + 1; + + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + memcpy(OutBuffer, block_start, (InBuffer - block_start)); + OutBuffer += (InBuffer - block_start); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + InBuffer += strlen(InBuffer) + 1; + + memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct)); + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -1518,6 +1648,27 @@ namespace Titanium FINISH_DIRECT_DECODE(); } + DECODE(OP_Emote) + { + unsigned char *__eq_buffer = __packet->pBuffer; + + std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset + std::string new_message; + TitaniumToServerTextLink(new_message, old_message); + + __packet->size = sizeof(Emote_Struct); + __packet->pBuffer = new unsigned char[__packet->size]; + + char *InBuffer = (char *)__packet->pBuffer; + + memcpy(InBuffer, __eq_buffer, 4); + InBuffer += 4; + strcpy(InBuffer, new_message.substr(0, 1023).c_str()); + InBuffer[1023] = '\0'; + + delete[] __eq_buffer; + } + DECODE(OP_FaceChange) { DECODE_LENGTH_EXACT(structs::FaceChange_Struct); @@ -1943,78 +2094,78 @@ namespace Titanium static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink) { - const char delimiter = 0x12; - - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) { + if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { titaniumTextLink = serverTextLink; return; } - auto segments = SplitString(serverTextLink, delimiter); + auto segments = SplitString(serverTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + titaniumTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45) // Diff: ^^^^^ ^ ^^^^^ - new_segment.append(segments[segment_iter].substr(0, 31).c_str()); - new_segment.append(segments[segment_iter].substr(36, 5).c_str()); + titaniumTextLink.push_back('\x12'); + titaniumTextLink.append(segments[segment_iter].substr(0, 31)); + titaniumTextLink.append(segments[segment_iter].substr(36, 5)); - if (segments[segment_iter].substr(41, 1) == "0") - new_segment.append(segments[segment_iter].substr(42, 1).c_str()); + if (segments[segment_iter][41] == '0') + titaniumTextLink.push_back(segments[segment_iter][42]); else - new_segment.append("F"); + titaniumTextLink.push_back('F'); - new_segment.append(segments[segment_iter].substr(48).c_str()); - - titaniumTextLink.push_back(delimiter); - titaniumTextLink.append(new_segment.c_str()); - titaniumTextLink.push_back(delimiter); + titaniumTextLink.append(segments[segment_iter].substr(48)); + titaniumTextLink.push_back('\x12'); } else { - titaniumTextLink.append(segments[segment_iter].c_str()); + titaniumTextLink.append(segments[segment_iter]); } } } static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink) { - const char delimiter = 0x12; - - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (titaniumTextLink.find(delimiter) == std::string::npos)) { + if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (titaniumTextLink.find('\x12') == std::string::npos)) { serverTextLink = titaniumTextLink; return; } - auto segments = SplitString(titaniumTextLink, delimiter); + auto segments = SplitString(titaniumTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + serverTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 32 36 37 (Source) // 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^^^^^ ^ ^^^^^ - new_segment.append(segments[segment_iter].substr(0, 31).c_str()); - new_segment.append("00000"); - new_segment.append(segments[segment_iter].substr(31, 5).c_str()); - new_segment.append("0"); - new_segment.append(segments[segment_iter].substr(36, 1).c_str()); - new_segment.append("00000"); - new_segment.append(segments[segment_iter].substr(37).c_str()); - - serverTextLink.push_back(delimiter); - serverTextLink.append(new_segment.c_str()); - serverTextLink.push_back(delimiter); + serverTextLink.push_back('\x12'); + serverTextLink.append(segments[segment_iter].substr(0, 31)); + serverTextLink.append("00000"); + serverTextLink.append(segments[segment_iter].substr(31, 5)); + serverTextLink.push_back('0'); + serverTextLink.push_back(segments[segment_iter][36]); + serverTextLink.append("00000"); + serverTextLink.append(segments[segment_iter].substr(37)); + serverTextLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter].c_str()); + serverTextLink.append(segments[segment_iter]); } } } diff --git a/common/patches/titanium_ops.h b/common/patches/titanium_ops.h index 4ddcae630..88c12e3ac 100644 --- a/common/patches/titanium_ops.h +++ b/common/patches/titanium_ops.h @@ -16,6 +16,8 @@ E(OP_DzExpeditionList) E(OP_DzJoinExpeditionConfirm) E(OP_DzLeaderStatus) E(OP_DzMemberList) +E(OP_Emote) +E(OP_FormattedMessage) E(OP_GuildMemberLevelUpdate) E(OP_GuildMemberList) E(OP_Illusion) @@ -37,6 +39,7 @@ E(OP_SendCharInfo) E(OP_SendAATable) E(OP_ShopPlayerSell) E(OP_SpecialMesg) +E(OP_TaskDescription) E(OP_Track) E(OP_Trader) E(OP_TraderBuy) @@ -55,6 +58,7 @@ D(OP_ChannelMessage) D(OP_CharacterCreate) D(OP_Consume) D(OP_DeleteItem) +D(OP_Emote) D(OP_FaceChange) D(OP_InspectAnswer) D(OP_InspectRequest) diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index d0ae81fb5..2779f07eb 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -744,6 +744,34 @@ namespace Underfoot FINISH_ENCODE(); } + ENCODE(OP_Emote) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + Emote_Struct *emu = (Emote_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + std::string old_message = emu->message; + std::string new_message; + ServerToUnderfootTextLink(new_message, old_message); + + //if (new_message.length() > 512) // length restricted in packet building function due vari-length name size (no nullterm) + // new_message = new_message.substr(0, 512); + + in->size = new_message.length() + 5; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_ExpansionInfo) { ENCODE_LENGTH_EXACT(ExpansionInfo_Struct); @@ -754,6 +782,55 @@ namespace Underfoot FINISH_ENCODE(); } + ENCODE(OP_FormattedMessage) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + FormattedMessage_Struct *emu = (FormattedMessage_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + char *old_message_ptr = (char *)in->pBuffer; + old_message_ptr += sizeof(FormattedMessage_Struct); + + std::string old_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (*old_message_ptr == 0) { break; } + old_message_array[i] = old_message_ptr; + old_message_ptr += old_message_array[i].length() + 1; + } + + uint32 new_message_size = 0; + std::string new_message_array[9]; + + for (int i = 0; i < 9; ++i) { + if (old_message_array[i].length() == 0) { break; } + ServerToUnderfootTextLink(new_message_array[i], old_message_array[i]); + new_message_size += new_message_array[i].length() + 1; + } + + in->size = sizeof(FormattedMessage_Struct) + new_message_size + 1; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->unknown0); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->string_id); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->type); + + for (int i = 0; i < 9; ++i) { + if (new_message_array[i].length() == 0) { break; } + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message_array[i].c_str()); + } + + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_GroundSpawn) { // We are not encoding the spawn_id field here, or a size but it doesn't appear to matter. @@ -2321,10 +2398,11 @@ namespace Underfoot std::string old_message = &emu->message[strlen(emu->sayer)]; std::string new_message; + ServerToUnderfootTextLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = 25 + strlen(emu->sayer) + new_message.length(); + in->size = strlen(emu->sayer) + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -2338,9 +2416,18 @@ namespace Underfoot VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); @@ -2362,6 +2449,49 @@ namespace Underfoot ENCODE(OP_TargetBuffs) { ENCODE_FORWARD(OP_BuffCreate); } + ENCODE(OP_TaskDescription) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *__emu_buffer = in->pBuffer; + + char *InBuffer = (char *)in->pBuffer; + char *block_start = InBuffer; + + InBuffer += sizeof(TaskDescriptionHeader_Struct); + uint32 title_size = strlen(InBuffer) + 1; + InBuffer += title_size; + InBuffer += sizeof(TaskDescriptionData1_Struct); + uint32 description_size = strlen(InBuffer) + 1; + InBuffer += description_size; + InBuffer += sizeof(TaskDescriptionData2_Struct); + + std::string old_message = InBuffer; // start 'Reward' as string + std::string new_message; + ServerToUnderfootTextLink(new_message, old_message); + + in->size = sizeof(TaskDescriptionHeader_Struct) + sizeof(TaskDescriptionData1_Struct)+ + sizeof(TaskDescriptionData2_Struct) + sizeof(TaskDescriptionTrailer_Struct)+ + title_size + description_size + new_message.length() + 1; + + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + memcpy(OutBuffer, block_start, (InBuffer - block_start)); + OutBuffer += (InBuffer - block_start); + + VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); + + InBuffer += strlen(InBuffer) + 1; + + memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct)); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + ENCODE(OP_Track) { EQApplicationPacket *in = *p; @@ -3216,6 +3346,27 @@ namespace Underfoot FINISH_DIRECT_DECODE(); } + DECODE(OP_Emote) + { + unsigned char *__eq_buffer = __packet->pBuffer; + + std::string old_message = (char *)&__eq_buffer[4]; // unknown01 offset + std::string new_message; + UnderfootToServerTextLink(new_message, old_message); + + __packet->size = sizeof(Emote_Struct); + __packet->pBuffer = new unsigned char[__packet->size]; + + char *InBuffer = (char *)__packet->pBuffer; + + memcpy(InBuffer, __eq_buffer, 4); + InBuffer += 4; + strcpy(InBuffer, new_message.substr(0, 1023).c_str()); + InBuffer[1023] = '\0'; + + delete[] __eq_buffer; + } + DECODE(OP_EnvDamage) { DECODE_LENGTH_EXACT(structs::EnvDamage2_Struct); @@ -4165,76 +4316,76 @@ namespace Underfoot static inline void ServerToUnderfootTextLink(std::string& underfootTextLink, const std::string& serverTextLink) { - const char delimiter = 0x12; - - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) { + if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { underfootTextLink = serverTextLink; return; } - auto segments = SplitString(serverTextLink, delimiter); + auto segments = SplitString(serverTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + underfootTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // Diff: ^^^^^ ^ - new_segment.append(segments[segment_iter].substr(0, 31).c_str()); - new_segment.append(segments[segment_iter].substr(36, 5).c_str()); + underfootTextLink.push_back('\x12'); + underfootTextLink.append(segments[segment_iter].substr(0, 31)); + underfootTextLink.append(segments[segment_iter].substr(36, 5)); - if (segments[segment_iter].substr(41, 1) == "0") - new_segment.append(segments[segment_iter].substr(42, 1).c_str()); + if (segments[segment_iter][41] == '0') + underfootTextLink.push_back(segments[segment_iter][42]); else - new_segment.append("F"); + underfootTextLink.push_back('F'); - new_segment.append(segments[segment_iter].substr(43).c_str()); - - underfootTextLink.push_back(delimiter); - underfootTextLink.append(new_segment.c_str()); - underfootTextLink.push_back(delimiter); + underfootTextLink.append(segments[segment_iter].substr(43)); + underfootTextLink.push_back('\x12'); } else { - underfootTextLink.append(segments[segment_iter].c_str()); + underfootTextLink.append(segments[segment_iter]); } } } static inline void UnderfootToServerTextLink(std::string& serverTextLink, const std::string& underfootTextLink) { - const char delimiter = 0x12; - - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (underfootTextLink.find(delimiter) == std::string::npos)) { + if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (underfootTextLink.find('\x12') == std::string::npos)) { serverTextLink = underfootTextLink; return; } - auto segments = SplitString(underfootTextLink, delimiter); + auto segments = SplitString(underfootTextLink, '\x12'); for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - std::string new_segment; + if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + serverTextLink.append(segments[segment_iter]); + // TODO: log size mismatch error + continue; + } // Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source) // SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50) // RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56) // Diff: ^^^^^ ^ - new_segment.append(segments[segment_iter].substr(0, 31).c_str()); - new_segment.append("00000"); - new_segment.append(segments[segment_iter].substr(31, 5).c_str()); - new_segment.append("0"); - new_segment.append(segments[segment_iter].substr(36).c_str()); - - serverTextLink.push_back(delimiter); - serverTextLink.append(new_segment.c_str()); - serverTextLink.push_back(delimiter); + serverTextLink.push_back('\x12'); + serverTextLink.append(segments[segment_iter].substr(0, 31)); + serverTextLink.append("00000"); + serverTextLink.append(segments[segment_iter].substr(31, 5)); + serverTextLink.push_back('0'); + serverTextLink.append(segments[segment_iter].substr(36)); + serverTextLink.push_back('\x12'); } else { - serverTextLink.append(segments[segment_iter].c_str()); + serverTextLink.append(segments[segment_iter]); } } } diff --git a/common/patches/underfoot_ops.h b/common/patches/underfoot_ops.h index 61f4f1c0f..188cf3d9e 100644 --- a/common/patches/underfoot_ops.h +++ b/common/patches/underfoot_ops.h @@ -25,7 +25,9 @@ E(OP_DzExpeditionList) E(OP_DzJoinExpeditionConfirm) E(OP_DzLeaderStatus) E(OP_DzMemberList) +E(OP_Emote) E(OP_ExpansionInfo) +E(OP_FormattedMessage) E(OP_GroundSpawn) E(OP_GroupCancelInvite) E(OP_GroupFollow) @@ -68,6 +70,7 @@ E(OP_SpawnDoor) E(OP_SpecialMesg) E(OP_Stun) E(OP_TargetBuffs) +E(OP_TaskDescription) E(OP_Track) E(OP_Trader) E(OP_TraderBuy) @@ -98,6 +101,7 @@ D(OP_ConsiderCorpse) D(OP_Consume) D(OP_Damage) D(OP_DeleteItem) +D(OP_Emote) D(OP_EnvDamage) D(OP_FaceChange) D(OP_FindPersonRequest) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index ddd792e6a..969ca2d58 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -105,9 +105,12 @@ bool SharedDatabase::SaveCursor(uint32 char_id, std::list::const_iter int i = 8000; for(auto it = start; it != end; ++it, i++) { + if (i > 8999) { break; } // shouldn't be anything in the queue that indexes this high ItemInst *inst = *it; - if (!SaveInventory(char_id,inst,(i == 8000) ? MainCursor : i)) - return false; + int16 use_slot = (i == 8000) ? MainCursor : i; + if (!SaveInventory(char_id, inst, use_slot)) { + return false; + } } return true; @@ -166,8 +169,9 @@ bool SharedDatabase::SaveInventory(uint32 char_id, const ItemInst* inst, int16 s else return UpdateSharedBankSlot(char_id, inst, slot_id); } - else if (!inst) // All other inventory - return DeleteInventorySlot(char_id, slot_id); + else if (!inst) { // All other inventory + return DeleteInventorySlot(char_id, slot_id); + } return UpdateInventorySlot(char_id, inst, slot_id); } @@ -176,11 +180,12 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i // 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)) - for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - ItemInst *auginst=inst->GetItem(i); - augslot[i]=(auginst && auginst->GetItem()) ? auginst->GetItem()->ID : NO_ITEM; + if (inst->IsType(ItemClassCommon)) { + for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + ItemInst *auginst = inst->GetItem(i); + augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : NO_ITEM; } + } uint16 charges = 0; if(inst->GetCharges() >= 0) @@ -220,11 +225,12 @@ bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst, // 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)) - for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - ItemInst *auginst=inst->GetItem(i); - augslot[i]=(auginst && auginst->GetItem()) ? auginst->GetItem()->ID : NO_ITEM; + if (inst->IsType(ItemClassCommon)) { + for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + ItemInst *auginst = inst->GetItem(i); + augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : NO_ITEM; } + } // Update/Insert item uint32 account_id = GetAccountIDByChar(char_id); @@ -246,11 +252,12 @@ bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst, auto results = QueryDatabase(query); // Save bag contents, if slot supports bag contents - if (inst->IsType(ItemClassContainer) && Inventory::SupportsContainers(slot_id)) + if (inst->IsType(ItemClassContainer) && Inventory::SupportsContainers(slot_id)) { for (uint8 idx = SUB_BEGIN; idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) { const ItemInst* baginst = inst->GetItem(idx); SaveInventory(char_id, baginst, Inventory::CalcSlotId(slot_id, idx)); } + } if (!results.Success()) { return false; @@ -422,9 +429,8 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) { ItemInst* inst = CreateBaseItem(item, charges); if (inst && item->ItemClass == ItemClassCommon) { for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - if (aug[i]) { - inst->PutAugment(this, i, aug[i]); - } + if (aug[i]) + inst->PutAugment(this, i, aug[i]); } } @@ -562,10 +568,12 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) { else inst->SetCharges(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]); + if (item->ItemClass == ItemClassCommon) { + for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + if (aug[i]) + inst->PutAugment(this, i, aug[i]); + } + } if (slot_id >= 8000 && slot_id <= 8999) { @@ -676,10 +684,12 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv) inst->SetCharges(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]); + if (item->ItemClass == ItemClassCommon) { + for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + if (aug[i]) + inst->PutAugment(this, i, aug[i]); + } + } if (slot_id>=8000 && slot_id <= 8999) put_slot_id = inv->PushCursor(*inst); @@ -1950,7 +1960,7 @@ void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMes std::string query = StringFormat("SELECT `inspect_message` FROM `character_inspect_messages` WHERE `id` = %u LIMIT 1", character_id); auto results = QueryDatabase(query); auto row = results.begin(); - memcpy(message, "", sizeof(InspectMessage_Struct)); + memset(message, '\0', sizeof(InspectMessage_Struct)); for (auto row = results.begin(); row != results.end(); ++row) { memcpy(message, row[0], sizeof(InspectMessage_Struct)); } diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 23bec152e..7159dcce5 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -126,7 +126,7 @@ OP_GuildLeader=0x7e09 OP_GuildDelete=0x3708 OP_GuildInviteAccept=0x7053 OP_GuildDemote=0x2d4e -OP_GuildPromote=0x0000 +OP_GuildPromote=0x6a98 OP_GuildPublicNote=0x5053 OP_GuildManageBanker=0x748f OP_GuildBank=0x5134 diff --git a/utils/scripts/db_update.pl b/utils/scripts/db_update.pl index be1285fe4..1cb0f46e8 100644 --- a/utils/scripts/db_update.pl +++ b/utils/scripts/db_update.pl @@ -240,17 +240,17 @@ sub Exit{ } #::: Returns Tab Delimited MySQL Result from Command Line sub GetMySQLResult{ my $run_query = $_[0]; - if($OS eq "Windows"){ return `"$path" --user $user --password="$pass" $db -N -B -e "$run_query"`; } + if($OS eq "Windows"){ return `"$path" --host $host --user $user --password="$pass" $db -N -B -e "$run_query"`; } if($OS eq "Linux"){ $run_query =~s/`//g; - return `$path --user="$user" --password="$pass" $db -N -B -e "$run_query"`; + return `$path --user="$user" --host $host --password="$pass" $db -N -B -e "$run_query"`; } } sub GetMySQLResultFromFile{ my $update_file = $_[0]; - if($OS eq "Windows"){ return `"$path" --user $user --password="$pass" --force $db < $update_file`; } - if($OS eq "Linux"){ return `"$path" --user $user --password="$pass" --force $db < $update_file`; } + if($OS eq "Windows"){ return `"$path" --host $host --user $user --password="$pass" --force $db < $update_file`; } + if($OS eq "Linux"){ return `"$path" --host $host --user $user --password="$pass" --force $db < $update_file`; } } #::: Gets Remote File based on URL (1st Arg), and saves to destination file (2nd Arg) diff --git a/utils/sql/git/bots/deprecated/load_bots_old.sql b/utils/sql/git/bots/deprecated/load_bots_old.sql index 44d1c1b90..5d88a8088 100644 --- a/utils/sql/git/bots/deprecated/load_bots_old.sql +++ b/utils/sql/git/bots/deprecated/load_bots_old.sql @@ -194,7 +194,7 @@ CREATE TABLE `botguildmembers` ( PRIMARY KEY (`char_id`) ) ENGINE=InnoDB; -DELIMITER // +DELIMITER $$ CREATE FUNCTION `GetMobType` (mobname VARCHAR(64)) RETURNS CHAR(1) BEGIN @@ -209,7 +209,7 @@ BEGIN END IF; RETURN Result; -END// +END$$ DELIMITER ; diff --git a/utils/sql/git/bots/load_bots.sql b/utils/sql/git/bots/load_bots.sql index 9957b882a..0dd030545 100644 --- a/utils/sql/git/bots/load_bots.sql +++ b/utils/sql/git/bots/load_bots.sql @@ -194,7 +194,7 @@ CREATE TABLE `botguildmembers` ( PRIMARY KEY (`char_id`) ) ENGINE=InnoDB; -DELIMITER \\ +DELIMITER $$ CREATE FUNCTION `GetMobType` (mobname VARCHAR(64)) RETURNS CHAR(1) BEGIN @@ -209,7 +209,7 @@ BEGIN END IF; RETURN Result; -END\\ +END$$ DELIMITER ; diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index d6c18bae0..aeaa86094 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -109,6 +109,7 @@ SET(zone_sources trading.cpp trap.cpp tribute.cpp + tune.cpp water_map.cpp water_map_v1.cpp water_map_v2.cpp diff --git a/zone/client.cpp b/zone/client.cpp index 85d4b61dd..559f2d04f 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2802,8 +2802,8 @@ void Client::Message_StringID(uint32 type, uint32 string_id, const char* message if (GetFilter(FilterDamageShields) == FilterHide && type == MT_DS) return; - int i, argcount, length; - char *bufptr; + int i = 0, argcount = 0, length = 0; + char *bufptr = nullptr; const char *message_arg[9] = {0}; if(type==MT_Emote) @@ -2815,7 +2815,6 @@ void Client::Message_StringID(uint32 type, uint32 string_id, const char* message return; } - i = 0; message_arg[i++] = message1; message_arg[i++] = message2; message_arg[i++] = message3; @@ -2826,10 +2825,12 @@ void Client::Message_StringID(uint32 type, uint32 string_id, const char* message message_arg[i++] = message8; message_arg[i++] = message9; - for(argcount = length = 0; message_arg[argcount]; argcount++) + for(; message_arg[argcount]; ++argcount) length += strlen(message_arg[argcount]) + 1; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_FormattedMessage, length+13); + length += 1; + + EQApplicationPacket* outapp = new EQApplicationPacket(OP_FormattedMessage, sizeof(FormattedMessage_Struct) + length); FormattedMessage_Struct *fm = (FormattedMessage_Struct *)outapp->pBuffer; fm->string_id = string_id; fm->type = type; @@ -2840,6 +2841,8 @@ void Client::Message_StringID(uint32 type, uint32 string_id, const char* message bufptr += strlen(message_arg[i]) + 1; } + // since we're moving the pointer the 0 offset is correct + bufptr[0] = '\0'; if(distance>0) entity_list.QueueCloseClients(this,outapp,false,distance); @@ -2914,8 +2917,8 @@ void Client::FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType fil if (!FilteredMessageCheck(sender, filter)) return; - int i, argcount, length; - char *bufptr; + int i = 0, argcount = 0, length = 0; + char *bufptr = nullptr; const char *message_arg[9] = {0}; if (type == MT_Emote) @@ -2926,7 +2929,6 @@ void Client::FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType fil return; } - i = 0; message_arg[i++] = message1; message_arg[i++] = message2; message_arg[i++] = message3; @@ -2937,10 +2939,12 @@ void Client::FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType fil message_arg[i++] = message8; message_arg[i++] = message9; - for (argcount = length = 0; message_arg[argcount]; argcount++) + for (; message_arg[argcount]; ++argcount) length += strlen(message_arg[argcount]) + 1; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_FormattedMessage, length+13); + length += 1; + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_FormattedMessage, sizeof(FormattedMessage_Struct) + length); FormattedMessage_Struct *fm = (FormattedMessage_Struct *)outapp->pBuffer; fm->string_id = string_id; fm->type = type; @@ -2950,6 +2954,9 @@ void Client::FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType fil bufptr += strlen(message_arg[i]) + 1; } + // since we're moving the pointer the 0 offset is correct + bufptr[0] = '\0'; + QueuePacket(outapp); safe_delete(outapp); } diff --git a/zone/client.h b/zone/client.h index 22b413b50..288eb2afb 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1247,6 +1247,10 @@ public: bool InterrogateInventory(Client* requester, bool log, bool silent, bool allowtrip, bool& error, bool autolog = true); + //Command #Tune functions + virtual int32 Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); + int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false); + protected: friend class Mob; void CalcItemBonuses(StatBonuses* newbon); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 5a7d78fc1..2b95f4dc1 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1838,12 +1838,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (loaditems) { /* Dont load if a length error occurs */ BulkSendInventoryItems(); /* Send stuff on the cursor which isnt sent in bulk */ - iter_queue it; - for (it = m_inv.cursor_begin(); it != m_inv.cursor_end(); ++it) { + for (auto iter = m_inv.cursor_begin(); iter != m_inv.cursor_end(); ++iter) { /* First item cursor is sent in bulk inventory packet */ - if (it == m_inv.cursor_begin()) + if (iter == m_inv.cursor_begin()) continue; - const ItemInst *inst = *it; + const ItemInst *inst = *iter; SendItemPacket(MainCursor, inst, ItemPacketSummonItem); } } @@ -5462,13 +5461,13 @@ void Client::Handle_OP_Emote(const EQApplicationPacket *app) in->message[512] = '\0'; len_msg = 512; } - uint32 len_packet = sizeof(in->unknown01) + len_name + uint32 len_packet = sizeof(in->type) + len_name + len_msg + 1; // Construct outgoing packet EQApplicationPacket* outapp = new EQApplicationPacket(OP_Emote, len_packet); Emote_Struct* out = (Emote_Struct*)outapp->pBuffer; - out->unknown01 = in->unknown01; + out->type = in->type; memcpy(out->message, name, len_name); memcpy(&out->message[len_name], in->message, len_msg); @@ -7477,7 +7476,7 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) uint32 guildrank = gj->response; - if (GetClientVersion() == EQClientRoF) + if (GetClientVersion() >= EQClientRoF) { if (gj->response == 8) { @@ -7652,7 +7651,10 @@ void Client::Handle_OP_GuildPromote(const EQApplicationPacket *app) uint8 rank = gci.rank + 1; if (rank > GUILD_OFFICER) + { + Message(0, "You cannot promote someone to be guild leader. You must use /guildleader."); return; + } Log.Out(Logs::Detail, Logs::Guilds, "Promoting %s (%d) from rank %s (%d) to %s (%d) in %s (%d)", diff --git a/zone/command.cpp b/zone/command.cpp index 65144d8f1..3c5d3c3a7 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -425,7 +425,7 @@ int command_init(void) { command_add("open_shop", nullptr, 100, command_merchantopenshop) || command_add("merchant_close_shop", "Closes a merchant shop", 100, command_merchantcloseshop) || command_add("close_shop", nullptr, 100, command_merchantcloseshop) || - command_add("shownumhits", "Shows buffs numhits for yourself.", 0, command_shownumhits) || + command_add("tune", "Calculate ideal statical values related to combat.", 100, command_tune) command_add("crashtest", "- Crash the zoneserver", 255, command_crashtest) || command_add("logtest", "Performs log performance testing.", 250, command_logtest) || command_add("logs", "Manage anything to do with logs", 250, command_logs) @@ -2628,7 +2628,7 @@ void command_peekinv(Client *c, const Seperator *sep) } else { int cursorDepth = 0; - for (iter_queue it = targetClient->GetInv().cursor_begin(); (it != targetClient->GetInv().cursor_end()); ++it, ++cursorDepth) { + for (auto it = targetClient->GetInv().cursor_begin(); (it != targetClient->GetInv().cursor_end()); ++it, ++cursorDepth) { inst_main = *it; item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); linker.SetItemInst(inst_main); @@ -6599,7 +6599,7 @@ void command_npcedit(Client *c, const Seperator *sep) "SET luclin_haircolor = %i, luclin_beardcolor = %i, " "luclin_hairstyle = %i, luclin_beard = %i, " "face = %i, drakkin_heritage = %i, " - "drakkin_tattoo = %i, drakkin_details = %i, " + "drakkin_tattoo = %i, drakkin_details = %i " "WHERE id = %i", target->GetHairColor(), target->GetBeardColor(), target->GetHairStyle(), target->GetBeard(), @@ -10001,7 +10001,6 @@ void command_camerashake(Client *c, const Seperator *sep) if(sep->arg[1][0] && sep->arg[2][0]) { ServerPacket *pack = new ServerPacket(ServerOP_CameraShake, sizeof(ServerCameraShake_Struct)); - memset(pack->pBuffer, 0, sizeof(pack->pBuffer)); ServerCameraShake_Struct* scss = (ServerCameraShake_Struct*) pack->pBuffer; scss->duration = atoi(sep->arg[1]); scss->intensity = atoi(sep->arg[2]); @@ -10389,6 +10388,215 @@ void command_shownumhits(Client *c, const Seperator *sep) return; } +void command_tune(Client *c, const Seperator *sep) +{ + //Work in progress - Kayen + + if(sep->arg[1][0] == '\0' || !strcasecmp(sep->arg[1], "help")) { + c->Message(0, "Syntax: #tune [subcommand]."); + c->Message(0, "-- Tune System Commands --"); + c->Message(0, "-- Usage: Returning recommended combat statistical values based on a desired outcome."); + c->Message(0, "-- Note: If targeted mob does not have a target (ie not engaged in combat), YOU will be considered the target."); + c->Message(0, "-- Warning: The calculations done in this process are intense and can potentially cause zone crashes depending on parameters set, use with caution!"); + c->Message(0, "-- Below are OPTIONAL parameters."); + c->Message(0, "-- Note: [interval] Determines how fast the stat being checked increases/decreases till it finds the best result. Default [ATK/AC 50][Acc/Avoid 10] "); + c->Message(0, "-- Note: [loop_max] Determines how many iterations are done to increases/decreases the stat till it finds the best result. Default [ATK/AC 100][Acc/Avoid 1000]"); + c->Message(0, "-- Note: [Stat Override] Will override that stat on mob being checkd with the specified value. Default=0"); + c->Message(0, "-- Note: [Info Level] How much statistical detail is displayed[0 - 3]. Default=0 "); + c->Message(0, "-- Note: Results are only approximations usually accurate to +/- 2 intervals."); + + c->Message(0, "... "); + c->Message(0, "...### Category A ### Target = ATTACKER ### YOU or Target's Target = DEFENDER ###"); + c->Message(0, "...### Category B ### Target = DEFENDER ### YOU or Target's Target = ATTACKER ###"); + c->Message(0, "... "); + c->Message(0, "...#Returns recommended ATK adjustment +/- on ATTACKER that will result in an average mitigation pct on DEFENDER. "); + c->Message(0, "...tune FindATK [A/B] [pct mitigation] [interval][loop_max][AC Overwride][Info Level]"); + c->Message(0, "... "); + c->Message(0, "...#Returns recommended AC adjustment +/- on DEFENDER for an average mitigation pct from ATTACKER. "); + c->Message(0, "...tune FindAC [A/B] [pct mitigation] [interval][loop_max][ATK Overwride][Info Level] "); + c->Message(0, "... "); + c->Message(0, "...#Returns recommended Accuracy adjustment +/- on ATTACKER that will result in a hit chance pct on DEFENDER. "); + c->Message(0, "...tune FindAccuracy [A/B] [hit chance] [interval][loop_max][Avoidance Overwride][Info Level]"); + c->Message(0, "... "); + c->Message(0, "...#Returns recommended Avoidance adjustment +/- on DEFENDER for in a hit chance pct from ATTACKER. "); + c->Message(0, "...tune FindAvoidance [A/B] [pct mitigation] [interval][loop_max][Accuracy Overwride][Info Level] "); + + return; + } + //Default is category A for attacker/defender settings, which then are swapped under category B. + Mob* defender = c; + Mob* attacker = c->GetTarget(); + + if (!attacker) + { + c->Message(0, "#Tune - Error no target selected. [#Tune help]"); + return; + } + + Mob* ttarget = attacker->GetTarget(); + + if (ttarget) + defender = ttarget; + + if(!strcasecmp(sep->arg[1], "FindATK")) + { + float pct_mitigation = atof(sep->arg[3]); + int interval = atoi(sep->arg[4]); + int max_loop = atoi(sep->arg[5]); + int ac_override = atoi(sep->arg[6]); + int info_level = atoi(sep->arg[7]); + + if (!pct_mitigation) + { + c->Message(13, "#Tune - Error must enter the desired percent mitigation on defender. Ie. Defender to mitigate on average 20 pct of max damage."); + return; + } + + if (!interval) + interval = 50; + if (!max_loop) + max_loop = 100; + if(!ac_override) + ac_override = 0; + if (!info_level) + info_level = 1; + + if(!strcasecmp(sep->arg[2], "A")) + c->Tune_FindATKByPctMitigation(defender, attacker, pct_mitigation, interval, max_loop,ac_override,info_level); + else if(!strcasecmp(sep->arg[2], "B")) + c->Tune_FindATKByPctMitigation(attacker,defender, pct_mitigation, interval, max_loop,ac_override,info_level); + else { + c->Message(0, "#Tune - Error no category selcted. [#Tune help]"); + c->Message(0, "Usage #tune FindATK [A/B] [pct mitigation] [interval][loop_max][AC Overwride][Info Level] "); + c->Message(0, "Example #tune FindATK A 60"); + } + return; + } + + if(!strcasecmp(sep->arg[1], "FindAC")) + { + float pct_mitigation = atof(sep->arg[3]); + int interval = atoi(sep->arg[4]); + int max_loop = atoi(sep->arg[5]); + int atk_override = atoi(sep->arg[6]); + int info_level = atoi(sep->arg[7]); + + if (!pct_mitigation) + { + c->Message(13, "#Tune - Error must enter the desired percent mitigation on defender. Ie. Defender to mitigate on average 20 pct of max damage."); + return; + } + + if (!interval) + interval = 50; + if (!max_loop) + max_loop = 100; + if(!atk_override) + atk_override = 0; + if (!info_level) + info_level = 1; + + if(!strcasecmp(sep->arg[2], "A")) + c->Tune_FindACByPctMitigation(defender, attacker, pct_mitigation, interval, max_loop,atk_override,info_level); + else if(!strcasecmp(sep->arg[2], "B")) + c->Tune_FindACByPctMitigation(attacker, defender, pct_mitigation, interval, max_loop,atk_override,info_level); + else { + c->Message(0, "#Tune - Error no category selcted. [#Tune help]"); + c->Message(0, "Usage #tune FindAC [A/B] [pct mitigation] [interval][loop_max][ATK Overwride][Info Level] "); + c->Message(0, "Example #tune FindAC A 60"); + } + + return; + } + + if(!strcasecmp(sep->arg[1], "FindAccuracy")) + { + float hit_chance = atof(sep->arg[3]); + int interval = atoi(sep->arg[4]); + int max_loop = atoi(sep->arg[5]); + int avoid_override = atoi(sep->arg[6]); + int info_level = atoi(sep->arg[7]); + + if (!hit_chance) + { + c->Message(10, "#Tune - Error must enter the desired percent mitigation on defender. Ie. Defender to mitigate on average 20 pct of max damage."); + return; + } + + if (!interval) + interval = 10; + if (!max_loop) + max_loop = 1000; + if(!avoid_override) + avoid_override = 0; + if (!info_level) + info_level = 1; + + if (hit_chance > RuleR(Combat,MaxChancetoHit) || hit_chance < RuleR(Combat,MinChancetoHit)) + { + c->Message(10, "#Tune - Error hit chance out of bounds. [Max %.2f Min .2f]", RuleR(Combat,MaxChancetoHit),RuleR(Combat,MinChancetoHit)); + return; + } + + if(!strcasecmp(sep->arg[2], "A")) + c->Tune_FindAccuaryByHitChance(defender, attacker, hit_chance, interval, max_loop,avoid_override,info_level); + else if(!strcasecmp(sep->arg[2], "B")) + c->Tune_FindAccuaryByHitChance(attacker, defender, hit_chance, interval, max_loop,avoid_override,info_level); + else { + c->Message(0, "#Tune - Error no category selcted. [#Tune help]"); + c->Message(0, "Usage #tune FindAcccuracy [A/B] [hit chance] [interval][loop_max][Avoidance Overwride][Info Level]"); + c->Message(0, "Exampled #tune FindAccuracy B 30"); + } + + return; + } + + if(!strcasecmp(sep->arg[1], "FindAvoidance")) + { + float hit_chance = atof(sep->arg[3]); + int interval = atoi(sep->arg[4]); + int max_loop = atoi(sep->arg[5]); + int acc_override = atoi(sep->arg[6]); + int info_level = atoi(sep->arg[7]); + + if (!hit_chance) + { + c->Message(0, "#Tune - Error must enter the desired hit chance on defender. Ie. Defender to have hit chance of 40 pct."); + return; + } + + if (!interval) + interval = 10; + if (!max_loop) + max_loop = 1000; + if(!acc_override) + acc_override = 0; + if (!info_level) + info_level = 1; + + if (hit_chance > RuleR(Combat,MaxChancetoHit) || hit_chance < RuleR(Combat,MinChancetoHit)) + { + c->Message(10, "#Tune - Error hit chance out of bounds. [Max %.2f Min .2f]", RuleR(Combat,MaxChancetoHit),RuleR(Combat,MinChancetoHit)); + return; + } + + if(!strcasecmp(sep->arg[2], "A")) + c->Tune_FindAvoidanceByHitChance(defender, attacker, hit_chance, interval, max_loop,acc_override, info_level); + else if(!strcasecmp(sep->arg[2], "B")) + c->Tune_FindAvoidanceByHitChance(attacker, defender, hit_chance, interval, max_loop,acc_override, info_level); + else { + c->Message(0, "#Tune - Error no category selcted. [#Tune help]"); + c->Message(0, "Usage #tune FindAvoidance [A/B] [hit chance] [interval][loop_max][Accuracy Overwride][Info Level]"); + c->Message(0, "Exampled #tune FindAvoidance B 30"); + } + + return; + } + + + return; +} + void command_logtest(Client *c, const Seperator *sep){ clock_t t = std::clock(); /* Function timer start */ if (sep->IsNumber(1)){ diff --git a/zone/command.h b/zone/command.h index dbbd7e770..61025f2bc 100644 --- a/zone/command.h +++ b/zone/command.h @@ -322,6 +322,7 @@ void command_npctype_cache(Client *c, const Seperator *sep); void command_merchantopenshop(Client *c, const Seperator *sep); void command_merchantcloseshop(Client *c, const Seperator *sep); void command_shownumhits(Client *c, const Seperator *sep); +void command_tune(Client *c, const Seperator *sep); void command_logtest(Client *c, const Seperator *sep); void command_logs(Client *c, const Seperator *sep); diff --git a/zone/corpse.cpp b/zone/corpse.cpp index b42906d20..74b2dfaec 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -364,9 +364,10 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( // solar: TODO soulbound items need not be added to corpse, but they need // to go into the regular slots on the player, out of bags - // worn + inventory + cursor + // possessions + // TODO: accomodate soul-bound items std::list removed_list; - bool cursor = false; + //bool cursor = false; for(i = MAIN_BEGIN; i < EmuConstants::MAP_POSSESSIONS_SIZE; i++) { if(i == MainAmmo && client->GetClientVersion() >= EQClientSoF) { item = client->GetInv().GetItem(MainPowerSource); @@ -384,14 +385,18 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( } } +#if 0 + // This will either be re-enabled or deleted at some point. The client doesn't appear + // to like to have items deleted from it's buffer..or, I just haven't figure out how -U + // (Besides, the 'corpse' slots equal the size of MapPossessions..not MapPossessions + MapCorpse) + // cursor queue // (change to first client that supports 'death hover' mode, if not SoF.) if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < EQClientSoF) { // bumped starting assignment to 8001 because any in-memory 'slot 8000' item was moved above as 'slot 30' // this was mainly for client profile state reflection..should match db player inventory entries now. - - iter_queue it; - for (it = client->GetInv().cursor_begin(), i = 8001; it != client->GetInv().cursor_end(); ++it, i++) { + i = 8001; + for (auto it = client->GetInv().cursor_begin(); it != client->GetInv().cursor_end(); ++it, i++) { item = *it; if ((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) { std::list slot_list = MoveItemToCorpse(client, item, i); @@ -400,6 +405,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( } } } +#endif database.TransactionBegin(); if (removed_list.size() != 0) { @@ -422,6 +428,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( database.QueryDatabase(ss.str().c_str()); } +#if 0 if (cursor) { // all cursor items should be on corpse (client < SoF or RespawnFromHover = false) while (!client->GetInv().CursorEmpty()) client->DeleteItemInInventory(MainCursor, 0, false, false); @@ -431,8 +438,13 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( std::list::const_iterator finish = client->GetInv().cursor_end(); database.SaveCursor(client->CharacterID(), start, finish); } +#endif - client->CalcBonuses(); // will only affect offline profile viewing of dead characters..unneeded overhead + auto start = client->GetInv().cursor_begin(); + auto finish = client->GetInv().cursor_end(); + database.SaveCursor(client->CharacterID(), start, finish); + + client->CalcBonuses(); client->Save(); IsRezzed(false); diff --git a/zone/entity.cpp b/zone/entity.cpp index 717986bd6..ae84e995f 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4621,3 +4621,10 @@ Mob *EntityList::GetTargetForVirus(Mob *spreader, int range) return TargetsInRange[zone->random.Int(0, TargetsInRange.size() - 1)]; } +void EntityList::StopMobAI() +{ + for (auto &mob : mob_list) { + mob.second->AI_Stop(); + mob.second->AI_ShutDown(); + } +} diff --git a/zone/entity.h b/zone/entity.h index 69cb0208b..68609adf3 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -268,6 +268,8 @@ public: Entity *GetEntityMob(const char *name); Entity *GetEntityCorpse(const char *name); + void StopMobAI(); + void DescribeAggro(Client *towho, NPC *from_who, float dist, bool verbose); void Message(uint32 to_guilddbid, uint32 type, const char* message, ...); diff --git a/zone/inventory.cpp b/zone/inventory.cpp index ab753f1e4..35b6aec8f 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -619,7 +619,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(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); database.SaveCursor(CharacterID(), s, e); } else { database.SaveInventory(CharacterID(), nullptr, slot_id); @@ -669,12 +669,12 @@ int32 Client::GetItemIDAt(int16 slot_id) { } // Returns an augment's ID that's in an item (returns INVALID_ID if not found) -// Pass in the slot ID of the item and which augslot you want to check (0-4) +// Pass in the slot ID of the item and which augslot you want to check (0-5) int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) { const ItemInst* inst = m_inv[slot_id]; - if (inst) - if (inst->GetAugmentItemID(augslot)) - return inst->GetAugmentItemID(augslot); + if (inst && inst->GetAugmentItemID(augslot)) { + return inst->GetAugmentItemID(augslot); + } // None found return INVALID_ID; @@ -770,9 +770,9 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd bool isDeleted = m_inv.DeleteItem(slot_id, quantity); - const ItemInst* inst=nullptr; + const ItemInst* inst = nullptr; if (slot_id == MainCursor) { - std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); if(update_db) database.SaveCursor(character_id, s, e); } @@ -784,22 +784,25 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd } if(client_update && IsValidSlot(slot_id)) { - EQApplicationPacket* outapp; + EQApplicationPacket* outapp = nullptr; if(inst) { - if(!inst->IsStackable() && !isDeleted) + if (!inst->IsStackable() && !isDeleted) { // Non stackable item with charges = Item with clicky spell effect ? Delete a charge. outapp = new EQApplicationPacket(OP_DeleteCharge, sizeof(MoveItem_Struct)); - else + } + else { // Stackable, arrows, etc ? Delete one from the stack outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(MoveItem_Struct)); + } - DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer; - delitem->from_slot = slot_id; - delitem->to_slot = 0xFFFFFFFF; - delitem->number_in_stack = 0xFFFFFFFF; - for(int loop=0;looppBuffer; + delitem->from_slot = slot_id; + delitem->to_slot = 0xFFFFFFFF; + delitem->number_in_stack = 0xFFFFFFFF; + + for(int loop=0;loopfrom_slot = slot_id; delitem->to_slot = 0xFFFFFFFF; delitem->number_in_stack = 0xFFFFFFFF; + QueuePacket(outapp); safe_delete(outapp); } @@ -822,7 +826,7 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update) SendItemPacket(MainCursor, &inst, ItemPacketSummonItem); } - std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); return database.SaveCursor(CharacterID(), s, e); } @@ -833,10 +837,12 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update) bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) { Log.Out(Logs::Detail, Logs::Inventory, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id); - if (slot_id == MainCursor) + if (slot_id == MainCursor) { // don't trust macros before conditional statements... return PushItemOnCursor(inst, client_update); - else + } + else { m_inv.PutItem(slot_id, inst); + } if (client_update) { @@ -844,9 +850,8 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client //SendWearChange(Inventory::CalcMaterialFromSlot(slot_id)); } - if (slot_id == MainCursor) { - std::list::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); return database.SaveCursor(this->CharacterID(), s, e); } else { @@ -854,6 +859,7 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client } CalcBonuses(); + // a lot of wasted checks and calls coded above... } void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data) @@ -864,17 +870,17 @@ void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootI SendLootItemInPacket(&inst, slot_id); if (slot_id == MainCursor) { - std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); database.SaveCursor(this->CharacterID(), s, e); - } else + } + else { database.SaveInventory(this->CharacterID(), &inst, slot_id); + } - if(bag_item_data) // bag contents - { + if(bag_item_data) { // bag contents int16 interior_slot; // solar: our bag went into slot_id, now let's pack the contents in - for(int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) - { + for(int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) { if(bag_item_data[i] == nullptr) continue; const ItemInst *bagitem = database.CreateItem(bag_item_data[i]->item_id, bag_item_data[i]->charges, bag_item_data[i]->aug_1, bag_item_data[i]->aug_2, bag_item_data[i]->aug_3, bag_item_data[i]->aug_4, bag_item_data[i]->aug_5, bag_item_data[i]->aug_6, bag_item_data[i]->attuned); @@ -892,86 +898,74 @@ bool Client::TryStacking(ItemInst* item, uint8 type, bool try_worn, bool try_cur return false; int16 i; uint32 item_id = item->GetItem()->ID; - for (i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) - { + for (i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { ItemInst* tmp_inst = m_inv.GetItem(i); if(tmp_inst && tmp_inst->GetItem()->ID == item_id && tmp_inst->GetCharges() < tmp_inst->GetItem()->StackSize){ MoveItemCharges(*item, i, type); CalcBonuses(); - if(item->GetCharges()) // we didn't get them all + if (item->GetCharges()) { // we didn't get them all return AutoPutLootInInventory(*item, try_worn, try_cursor, 0); + } return true; } } - for (i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) - { - for (uint8 j = SUB_BEGIN; j < EmuConstants::ITEM_CONTAINER_SIZE; j++) - { + for (i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { + for (uint8 j = SUB_BEGIN; j < EmuConstants::ITEM_CONTAINER_SIZE; j++) { uint16 slotid = Inventory::CalcSlotId(i, j); ItemInst* tmp_inst = m_inv.GetItem(slotid); - if(tmp_inst && tmp_inst->GetItem()->ID == item_id && tmp_inst->GetCharges() < tmp_inst->GetItem()->StackSize){ + if(tmp_inst && tmp_inst->GetItem()->ID == item_id && tmp_inst->GetCharges() < tmp_inst->GetItem()->StackSize) { MoveItemCharges(*item, slotid, type); CalcBonuses(); - if(item->GetCharges()) // we didn't get them all + if (item->GetCharges()) { // we didn't get them all return AutoPutLootInInventory(*item, try_worn, try_cursor, 0); + } return true; } } } return false; } + // Locate an available space in inventory to place an item // and then put the item there // The change will be saved to the database 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.IsAttuned()) && 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) - { + for (int16 i = EmuConstants::EQUIPMENT_BEGIN; i < MainPowerSource; i++) { // originally (i < 22) if (i == EmuConstants::GENERAL_BEGIN) { - if(this->GetClientVersion() >= EQClientSoF) { i = MainPowerSource; } // added power source check for SoF+ clients - else { break; } + // added power source check for SoF+ clients + if (this->GetClientVersion() >= EQClientSoF) + i = MainPowerSource; + else + break; } - if (!m_inv[i]) - { - if( i == MainPrimary && inst.IsWeapon() ) // If item is primary slot weapon - { - if( (inst.GetItem()->ItemType == ItemType2HSlash) || (inst.GetItem()->ItemType == ItemType2HBlunt) || (inst.GetItem()->ItemType == ItemType2HPiercing) ) // and uses 2hs \ 2hb \ 2hp - { - if( m_inv[MainSecondary] ) // and if secondary slot is not empty - { + if (!m_inv[i]) { + if (i == MainPrimary && inst.IsWeapon()) { // If item is primary slot weapon + if ((inst.GetItem()->ItemType == ItemType2HSlash) || (inst.GetItem()->ItemType == ItemType2HBlunt) || (inst.GetItem()->ItemType == ItemType2HPiercing)) { // and uses 2hs \ 2hb \ 2hp + if (m_inv[MainSecondary]) { // and if secondary slot is not empty continue; // Can't auto-equip } } } - if( i== MainSecondary && m_inv[MainPrimary]) // check to see if primary slot is a two hander - { + if (i == MainSecondary && m_inv[MainPrimary]) { // check to see if primary slot is a two hander uint8 use = m_inv[MainPrimary]->GetItem()->ItemType; - if(use == ItemType2HSlash || use == ItemType2HBlunt || use == ItemType2HPiercing) + if (use == ItemType2HSlash || use == ItemType2HBlunt || use == ItemType2HPiercing) continue; } - if - ( - i == MainSecondary && - inst.IsWeapon() && - !CanThisClassDualWield() - ) - { + if (i == MainSecondary && inst.IsWeapon() && !CanThisClassDualWield()) { continue; } - if (inst.IsEquipable(i)) // Equippable at this slot? - { + if (inst.IsEquipable(i)) { // Equippable at this slot? //send worn to everyone... PutLootInInventory(i, inst); uint8 worn_slot_material = Inventory::CalcMaterialFromSlot(i); - if(worn_slot_material != _MaterialInvalid) - { + if (worn_slot_material != _MaterialInvalid) { SendWearChange(worn_slot_material); } @@ -983,17 +977,15 @@ bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_curs } // #2: Stackable item? - if (inst.IsStackable()) - { - if(TryStacking(&inst, ItemPacketTrade, try_worn, try_cursor)) + if (inst.IsStackable()) { + if (TryStacking(&inst, ItemPacketTrade, try_worn, try_cursor)) return true; } // #3: put it in inventory bool is_arrow = (inst.GetItem()->ItemType == ItemTypeArrow) ? true : false; int16 slot_id = m_inv.FindFreeSlot(inst.IsType(ItemClassContainer), try_cursor, inst.GetItem()->Size, is_arrow); - if (slot_id != INVALID_INDEX) - { + if (slot_id != INVALID_INDEX) { PutLootInInventory(slot_id, inst, bag_item_data); return true; } @@ -1006,28 +998,27 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type) { ItemInst *tmp_inst = m_inv.GetItem(to_slot); - if(tmp_inst && tmp_inst->GetCharges() < tmp_inst->GetItem()->StackSize) - { + if(tmp_inst && tmp_inst->GetCharges() < tmp_inst->GetItem()->StackSize) { // this is how much room is left on the item we're stacking onto int charge_slots_left = tmp_inst->GetItem()->StackSize - tmp_inst->GetCharges(); // this is how many charges we can move from the looted item to // the item in the inventory - int charges_to_move = - from.GetCharges() < charge_slots_left ? - from.GetCharges() : - charge_slots_left; + int charges_to_move = (from.GetCharges() < charge_slots_left) ? from.GetCharges() : charge_slots_left; tmp_inst->SetCharges(tmp_inst->GetCharges() + charges_to_move); from.SetCharges(from.GetCharges() - charges_to_move); SendLootItemInPacket(tmp_inst, to_slot); - if (to_slot == MainCursor){ - std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); + if (to_slot == MainCursor) { + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); database.SaveCursor(this->CharacterID(), s, e); - } else + } + else { database.SaveInventory(this->CharacterID(), tmp_inst, to_slot); + } } } +#if 0 // 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 @@ -1136,6 +1127,7 @@ bool MakeItemLink(char* &ret_link, const Item_Struct *item, uint32 aug0, uint32 return false; } } +#endif int Client::GetItemLinkHash(const ItemInst* inst) { //pre-Titanium: http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=70&postdays=0&postorder=asc @@ -1282,10 +1274,13 @@ bool Client::IsValidSlot(uint32 slot) { (slot >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot <= EmuConstants::SHARED_BANK_BAGS_END) || (slot >= EmuConstants::TRADE_BEGIN && slot <= EmuConstants::TRADE_END) || (slot >= EmuConstants::WORLD_BEGIN && slot <= EmuConstants::WORLD_END) || - (slot == MainPowerSource)) + (slot == MainPowerSource) + ) { return true; - else + } + else { return false; + } } bool Client::IsBankSlot(uint32 slot) @@ -1362,11 +1357,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { int16 src_slot_id = (int16)move_in->from_slot; int16 dst_slot_id = (int16)move_in->to_slot; - if(IsBankSlot(src_slot_id) || - IsBankSlot(dst_slot_id) || - IsBankSlot(src_slot_check) || - IsBankSlot(dst_slot_check)) - { + if(IsBankSlot(src_slot_id) || IsBankSlot(dst_slot_id) || IsBankSlot(src_slot_check) || IsBankSlot(dst_slot_check)) { uint32 distance = 0; NPC *banker = entity_list.GetClosestBanker(this, distance); @@ -1556,7 +1547,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { { SendCursorBuffer(); } - std::list::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); database.SaveCursor(character_id, s, e); } else @@ -1709,22 +1700,26 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } // Step 7: Save change to the database - if (src_slot_id == MainCursor){ + 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(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); database.SaveCursor(character_id, s, e); - } else + } + else { database.SaveInventory(character_id, m_inv.GetItem(src_slot_id), src_slot_id); + } if (dst_slot_id == MainCursor) { - std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); database.SaveCursor(character_id, s, e); - } else + } + else { database.SaveInventory(character_id, m_inv.GetItem(dst_slot_id), dst_slot_id); + } if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in, true); } // QS Audit @@ -1929,16 +1924,17 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) { void Client::DyeArmor(DyeStruct* dye){ int16 slot=0; for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) { - if(m_pp.item_tint[i].rgb.blue!=dye->dye[i].rgb.blue || - m_pp.item_tint[i].rgb.red!=dye->dye[i].rgb.red || - m_pp.item_tint[i].rgb.green != dye->dye[i].rgb.green){ + if (m_pp.item_tint[i].rgb.blue != dye->dye[i].rgb.blue || + m_pp.item_tint[i].rgb.red != dye->dye[i].rgb.red || + m_pp.item_tint[i].rgb.green != dye->dye[i].rgb.green + ) { slot = m_inv.HasItem(32557, 1, invWherePersonal); if (slot != INVALID_INDEX){ DeleteItemInInventory(slot,1,true); uint8 slot2=SlotConvert(i); ItemInst* inst = this->m_inv.GetItem(slot2); if(inst){ - uint32 armor_color = (dye->dye[i].rgb.red * 65536) + (dye->dye[i].rgb.green * 256) + (dye->dye[i].rgb.blue); + uint32 armor_color = ((uint32)dye->dye[i].rgb.red << 16) | ((uint32)dye->dye[i].rgb.green << 8) | ((uint32)dye->dye[i].rgb.blue); inst->SetColor(armor_color); database.SaveCharacterMaterialColor(this->CharacterID(), i, armor_color); database.SaveInventory(CharacterID(),inst,slot2); @@ -1964,7 +1960,8 @@ void Client::DyeArmor(DyeStruct* dye){ } -/*bool Client::DecreaseByItemType(uint32 type, uint8 amt) { +#if 0 +bool Client::DecreaseByItemType(uint32 type, uint8 amt) { const Item_Struct* TempItem = 0; ItemInst* ins; int x; @@ -2013,10 +2010,11 @@ void Client::DyeArmor(DyeStruct* dye){ } } return false; -}*/ +} +#endif bool Client::DecreaseByID(uint32 type, uint8 amt) { - const Item_Struct* TempItem = 0; + const Item_Struct* TempItem = nullptr; ItemInst* ins = nullptr; int x; int num = 0; @@ -2024,7 +2022,7 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) { { if (x == MainCursor + 1) x = EmuConstants::GENERAL_BAGS_BEGIN; - TempItem = 0; + TempItem = nullptr; ins = GetInv().GetItem(x); if (ins) TempItem = ins->GetItem(); @@ -2041,7 +2039,7 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) { { if (x == MainCursor + 1) x = EmuConstants::GENERAL_BAGS_BEGIN; - TempItem = 0; + TempItem = nullptr; ins = GetInv().GetItem(x); if (ins) TempItem = ins->GetItem(); @@ -2064,148 +2062,130 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) { return true; } -void Client::RemoveNoRent(bool client_update) { - int16 slot_id = 0; - - // equipment - for(slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; +void Client::RemoveNoRent(bool client_update) +{ + for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) { + auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); DeleteItemInInventory(slot_id, 0, client_update); } } - // general - for (slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; + for (auto slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; ++slot_id) { + auto inst = m_inv[slot_id]; if (inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); DeleteItemInInventory(slot_id, 0, client_update); } } - // power source if (m_inv[MainPowerSource]) { - const ItemInst* inst = m_inv[MainPowerSource]; + auto inst = m_inv[MainPowerSource]; if (inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, MainPowerSource); DeleteItemInInventory(MainPowerSource, 0, (GetClientVersion() >= EQClientSoF) ? client_update : false); // Ti slot non-existent } } - // containers - for(slot_id = EmuConstants::GENERAL_BAGS_BEGIN; slot_id <= EmuConstants::CURSOR_BAG_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; + for (auto slot_id = EmuConstants::GENERAL_BAGS_BEGIN; slot_id <= EmuConstants::CURSOR_BAG_END; ++slot_id) { + auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); DeleteItemInInventory(slot_id, 0, client_update); } } - // bank - for(slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; + for (auto slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; ++slot_id) { + auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); DeleteItemInInventory(slot_id, 0, false); // Can't delete from client Bank slots } } - // bank containers - for(slot_id = EmuConstants::BANK_BAGS_BEGIN; slot_id <= EmuConstants::BANK_BAGS_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; + for (auto slot_id = EmuConstants::BANK_BAGS_BEGIN; slot_id <= EmuConstants::BANK_BAGS_END; ++slot_id) { + auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); DeleteItemInInventory(slot_id, 0, false); // Can't delete from client Bank Container slots } } - // shared bank - for(slot_id = EmuConstants::SHARED_BANK_BEGIN; slot_id <= EmuConstants::SHARED_BANK_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; + for (auto slot_id = EmuConstants::SHARED_BANK_BEGIN; slot_id <= EmuConstants::SHARED_BANK_END; ++slot_id) { + auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); DeleteItemInInventory(slot_id, 0, false); // Can't delete from client Shared Bank slots } } - // shared bank containers - for(slot_id = EmuConstants::SHARED_BANK_BAGS_BEGIN; slot_id <= EmuConstants::SHARED_BANK_BAGS_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; + for (auto slot_id = EmuConstants::SHARED_BANK_BAGS_BEGIN; slot_id <= EmuConstants::SHARED_BANK_BAGS_END; ++slot_id) { + auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); DeleteItemInInventory(slot_id, 0, false); // Can't delete from client Shared Bank Container slots } } - // cursor & limbo if (!m_inv.CursorEmpty()) { std::list local; - ItemInst* inst = nullptr; while (!m_inv.CursorEmpty()) { - inst = m_inv.PopItem(MainCursor); - if (inst) - local.push_back(inst); + auto inst = m_inv.PopItem(MainCursor); + if (inst == nullptr) { continue; } + local.push_back(inst); } - 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) + for (auto iter = local.begin(); iter != local.end(); ++iter) { + auto inst = *iter; + if (inst == nullptr) { continue; } + if (!inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from `Limbo`", inst->GetItem()->Name); - else - m_inv.PushCursor(**iter); - - safe_delete(*iter); - iter = local.erase(iter); + } + else { + m_inv.PushCursor(*inst); + } + safe_delete(inst); } - - std::list::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end(); - database.SaveCursor(this->CharacterID(), s, e); local.clear(); + + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + database.SaveCursor(this->CharacterID(), s, e); } } // Two new methods to alleviate perpetual login desyncs -void Client::RemoveDuplicateLore(bool client_update) { - int16 slot_id = 0; - - // equipment - for(slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; slot_id++) { - ItemInst* inst = m_inv.PopItem(slot_id); - if(inst) { - if(CheckLoreConflict(inst->GetItem())) { - Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); - database.SaveInventory(character_id, nullptr, slot_id); - } - else { - m_inv.PutItem(slot_id, *inst); - } - safe_delete(inst); +void Client::RemoveDuplicateLore(bool client_update) +{ + for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) { + auto inst = m_inv.PopItem(slot_id); + if (inst == nullptr) { continue; } + if(CheckLoreConflict(inst->GetItem())) { + Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); + database.SaveInventory(character_id, nullptr, slot_id); } + else { + m_inv.PutItem(slot_id, *inst); + } + safe_delete(inst); + } + + for (auto slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; ++slot_id) { + auto inst = m_inv.PopItem(slot_id); + if (inst == nullptr) { continue; } + if (CheckLoreConflict(inst->GetItem())) { + Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); + database.SaveInventory(character_id, nullptr, slot_id); + } + else { + m_inv.PutItem(slot_id, *inst); + } + safe_delete(inst); } - // general - for (slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; slot_id++) { - ItemInst* inst = m_inv.PopItem(slot_id); - if (inst) { - if (CheckLoreConflict(inst->GetItem())) { - Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); - database.SaveInventory(character_id, nullptr, slot_id); - } - else { - m_inv.PutItem(slot_id, *inst); - } - safe_delete(inst); - } - } - - // power source if (m_inv[MainPowerSource]) { - ItemInst* inst = m_inv.PopItem(MainPowerSource); + auto inst = m_inv.PopItem(MainPowerSource); if (inst) { if (CheckLoreConflict(inst->GetItem())) { Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); @@ -2218,108 +2198,96 @@ void Client::RemoveDuplicateLore(bool client_update) { } } - // containers - for(slot_id = EmuConstants::GENERAL_BAGS_BEGIN; slot_id <= EmuConstants::CURSOR_BAG_END; slot_id++) { - ItemInst* inst = m_inv.PopItem(slot_id); - if(inst) { - if(CheckLoreConflict(inst->GetItem())) { - Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); - database.SaveInventory(character_id, nullptr, slot_id); - } - else { - m_inv.PutItem(slot_id, *inst); - } - safe_delete(inst); + for (auto slot_id = EmuConstants::GENERAL_BAGS_BEGIN; slot_id <= EmuConstants::CURSOR_BAG_END; ++slot_id) { + auto inst = m_inv.PopItem(slot_id); + if (inst == nullptr) { continue; } + if(CheckLoreConflict(inst->GetItem())) { + Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); + database.SaveInventory(character_id, nullptr, slot_id); } + else { + m_inv.PutItem(slot_id, *inst); + } + safe_delete(inst); } - // bank - for(slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; slot_id++) { - ItemInst* inst = m_inv.PopItem(slot_id); - if(inst) { - if(CheckLoreConflict(inst->GetItem())) { - Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); - database.SaveInventory(character_id, nullptr, slot_id); - } - else { - m_inv.PutItem(slot_id, *inst); - } - safe_delete(inst); + for (auto slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; ++slot_id) { + auto inst = m_inv.PopItem(slot_id); + if (inst == nullptr) { continue; } + if(CheckLoreConflict(inst->GetItem())) { + Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); + database.SaveInventory(character_id, nullptr, slot_id); } + else { + m_inv.PutItem(slot_id, *inst); + } + safe_delete(inst); } - // bank containers - for(slot_id = EmuConstants::BANK_BAGS_BEGIN; slot_id <= EmuConstants::BANK_BAGS_END; slot_id++) { - ItemInst* inst = m_inv.PopItem(slot_id); - if(inst) { - if(CheckLoreConflict(inst->GetItem())) { - Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); - database.SaveInventory(character_id, nullptr, slot_id); - } - else { - m_inv.PutItem(slot_id, *inst); - } - safe_delete(inst); + for (auto slot_id = EmuConstants::BANK_BAGS_BEGIN; slot_id <= EmuConstants::BANK_BAGS_END; ++slot_id) { + auto inst = m_inv.PopItem(slot_id); + if (inst == nullptr) { continue; } + if(CheckLoreConflict(inst->GetItem())) { + Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); + database.SaveInventory(character_id, nullptr, slot_id); } + else { + m_inv.PutItem(slot_id, *inst); + } + safe_delete(inst); } // Shared Bank and Shared Bank Containers are not checked due to their allowing duplicate lore items -U - // cursor & limbo if (!m_inv.CursorEmpty()) { - std::list local; - ItemInst* inst = nullptr; + std::list local_1; + std::list local_2; while (!m_inv.CursorEmpty()) { - inst = m_inv.PopItem(MainCursor); - if (inst) - local.push_back(inst); + auto inst = m_inv.PopItem(MainCursor); + if (inst == nullptr) { continue; } + local_1.push_back(inst); } - std::list::iterator iter = local.begin(); - while (iter != local.end()) { - inst = *iter; - // probably needs a valid pointer check -U + for (auto iter = local_1.begin(); iter != local_1.end(); ++iter) { + auto inst = *iter; + if (inst == nullptr) { continue; } if (CheckLoreConflict(inst->GetItem())) { Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from `Limbo`", inst->GetItem()->Name); - safe_delete(*iter); - iter = local.erase(iter); + safe_delete(inst); } else { - ++iter; + local_2.push_back(inst); } } + local_1.clear(); - iter = local.begin(); - while (iter != local.end()) { - inst = *iter; + for (auto iter = local_2.begin(); iter != local_2.end(); ++iter) { + auto inst = *iter; + if (inst == nullptr) { continue; } if (!inst->GetItem()->LoreFlag || ((inst->GetItem()->LoreGroup == -1) && (m_inv.HasItem(inst->GetID(), 0, invWhereCursor) == INVALID_INDEX)) || - (inst->GetItem()->LoreGroup && ~inst->GetItem()->LoreGroup && (m_inv.HasItemByLoreGroup(inst->GetItem()->LoreGroup, invWhereCursor) == INVALID_INDEX))) { - - m_inv.PushCursor(**iter); + (inst->GetItem()->LoreGroup && (~inst->GetItem()->LoreGroup) && (m_inv.HasItemByLoreGroup(inst->GetItem()->LoreGroup, invWhereCursor) == INVALID_INDEX)) + ) { + m_inv.PushCursor(*inst); } else { Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from `Limbo`", inst->GetItem()->Name); } - - safe_delete(*iter); - iter = local.erase(iter); + safe_delete(inst); } + local_2.clear(); - std::list::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); database.SaveCursor(this->CharacterID(), s, e); - local.clear(); } } -void Client::MoveSlotNotAllowed(bool client_update) { - int16 slot_id = 0; - - // equipment - for(slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; slot_id++) { +void Client::MoveSlotNotAllowed(bool client_update) +{ + for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) { if(m_inv[slot_id] && !m_inv[slot_id]->IsSlotAllowed(slot_id)) { - ItemInst* inst = m_inv.PopItem(slot_id); + auto inst = m_inv.PopItem(slot_id); bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false; int16 free_slot_id = m_inv.FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow); Log.Out(Logs::Detail, Logs::Inventory, "Slot Assignment Error: Moving %s from slot %i to %i", inst->GetItem()->Name, slot_id, free_slot_id); @@ -2329,15 +2297,13 @@ void Client::MoveSlotNotAllowed(bool client_update) { } } - // power source - slot_id = MainPowerSource; - if(m_inv[slot_id] && !m_inv[slot_id]->IsSlotAllowed(slot_id)) { - ItemInst* inst = m_inv.PopItem(slot_id); + if (m_inv[MainPowerSource] && !m_inv[MainPowerSource]->IsSlotAllowed(MainPowerSource)) { + auto inst = m_inv.PopItem(MainPowerSource); bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false; int16 free_slot_id = m_inv.FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow); Log.Out(Logs::Detail, Logs::Inventory, "Slot Assignment Error: Moving %s from slot %i to %i", inst->GetItem()->Name, slot_id, free_slot_id); PutItemInInventory(free_slot_id, *inst, (GetClientVersion() >= EQClientSoF) ? client_update : false); - database.SaveInventory(character_id, nullptr, slot_id); + database.SaveInventory(character_id, nullptr, MainPowerSource); safe_delete(inst); } @@ -2372,7 +2338,7 @@ uint32 Client::GetEquipment(uint8 material_slot) const return 0; } -/* +#if 0 int32 Client::GetEquipmentMaterial(uint8 material_slot) { const Item_Struct *item; @@ -2385,24 +2351,16 @@ int32 Client::GetEquipmentMaterial(uint8 material_slot) return 0; } -*/ +#endif uint32 Client::GetEquipmentColor(uint8 material_slot) const { - const Item_Struct *item; - - if(material_slot > EmuConstants::MATERIAL_END) - { + if (material_slot > EmuConstants::MATERIAL_END) return 0; - } - item = database.GetItem(GetEquipment(material_slot)); - if(item != 0) - { - return m_pp.item_tint[material_slot].rgb.use_tint ? - m_pp.item_tint[material_slot].color : - item->Color; - } + const Item_Struct *item = database.GetItem(GetEquipment(material_slot)); + if(item != nullptr) + return ((m_pp.item_tint[material_slot].rgb.use_tint) ? m_pp.item_tint[material_slot].color : item->Color); return 0; } @@ -2436,7 +2394,7 @@ void Client::SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType EQApplicationPacket* Client::ReturnItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type) { if (!inst) - return 0; + return nullptr; // Serialize item into |-delimited string std::string packet = inst->Serialize(slot_id); @@ -2542,8 +2500,9 @@ void Client::SetBandolier(const EQApplicationPacket *app) { if (slot == INVALID_INDEX) { if (m_inv.GetItem(MainCursor)) { if (m_inv.GetItem(MainCursor)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id && - m_inv.GetItem(MainCursor)->GetCharges() >= 1) // '> 0' the same, but this matches Inventory::_HasItem conditional check + m_inv.GetItem(MainCursor)->GetCharges() >= 1) { // '> 0' the same, but this matches Inventory::_HasItem conditional check slot = MainCursor; + } else if (m_inv.GetItem(MainCursor)->GetItem()->ItemClass == 1) { for(int16 CursorBagSlot = EmuConstants::CURSOR_BAG_BEGIN; CursorBagSlot <= EmuConstants::CURSOR_BAG_END; CursorBagSlot++) { if (m_inv.GetItem(CursorBagSlot)) { @@ -2576,11 +2535,13 @@ void Client::SetBandolier(const EQApplicationPacket *app) { database.SaveInventory(character_id, BandolierItems[BandolierSlot], slot); BandolierItems[BandolierSlot]->SetCharges(1); } - else // Remove the item from the inventory + else { // Remove the item from the inventory database.SaveInventory(character_id, 0, slot); + } } - else // Remove the item from the inventory + else { // Remove the item from the inventory database.SaveInventory(character_id, 0, slot); + } } else { // The player doesn't have the required weapon with them. BandolierItems[BandolierSlot] = 0; @@ -2590,15 +2551,17 @@ void Client::SetBandolier(const EQApplicationPacket *app) { if(InvItem) { // If there was an item in that weapon slot, put it in the inventory Log.Out(Logs::Detail, Logs::Inventory, "returning item %s in weapon slot %i to inventory", - InvItem->GetItem()->Name, WeaponSlot); - if(MoveItemToInventory(InvItem)) + InvItem->GetItem()->Name, WeaponSlot); + _log(INVENTORY__BANDOLIER, "returning item %s in weapon slot %i to inventory", InvItem->GetItem()->Name, WeaponSlot); + if (MoveItemToInventory(InvItem)) { database.SaveInventory(character_id, 0, WeaponSlot); - else Log.Out(Logs::General, Logs::Error, "Char: %s, ERROR returning %s to inventory", GetName(), - InvItem->GetItem()->Name); + } + else { + _log(INVENTORY__BANDOLIER, "Char: %s, ERROR returning %s to inventory", GetName(), InvItem->GetItem()->Name); + } safe_delete(InvItem); } - } } } @@ -2628,9 +2591,9 @@ void Client::SetBandolier(const EQApplicationPacket *app) { if(InvItem) { // If there was already an item in that weapon slot that we replaced, find a place to put it - if(!MoveItemToInventory(InvItem)) - Log.Out(Logs::General, Logs::Error, "Char: %s, ERROR returning %s to inventory", GetName(), - InvItem->GetItem()->Name); + if (!MoveItemToInventory(InvItem)) { + Log.Out(Logs::General, Logs::Error, "Char: %s, ERROR returning %s to inventory", GetName(), InvItem->GetItem()->Name); + } safe_delete(InvItem); } } @@ -2640,14 +2603,14 @@ void Client::SetBandolier(const EQApplicationPacket *app) { // put it in the player's inventory. ItemInst *InvItem = m_inv.PopItem(WeaponSlot); if(InvItem) { - Log.Out(Logs::Detail, Logs::Inventory, "Bandolier has no item for slot %i, returning item %s to inventory", - WeaponSlot, InvItem->GetItem()->Name); + Log.Out(Logs::Detail, Logs::Inventory, "Bandolier has no item for slot %i, returning item %s to inventory", WeaponSlot, InvItem->GetItem()->Name); // If there was an item in that weapon slot, put it in the inventory - if(MoveItemToInventory(InvItem)) + if (MoveItemToInventory(InvItem)) { database.SaveInventory(character_id, 0, WeaponSlot); - else - Log.Out(Logs::General, Logs::Error, "Char: %s, ERROR returning %s to inventory", GetName(), - InvItem->GetItem()->Name); + } + else { + Log.Out(Logs::General, Logs::Error, "Char: %s, ERROR returning %s to inventory", GetName(), InvItem->GetItem()->Name); + } safe_delete(InvItem); } } @@ -2675,7 +2638,9 @@ bool Client::MoveItemToInventory(ItemInst *ItemToReturn, bool UpdateClient) { // depends on current behaviour, this routine operates the same as the client when moving items back to inventory when // swapping bandolier sets. - if(!ItemToReturn) return false; + if (!ItemToReturn) { + return false; + } Log.Out(Logs::Detail, Logs::Inventory,"Char: %s Returning %s to inventory", GetName(), ItemToReturn->GetItem()->Name); @@ -2693,8 +2658,7 @@ bool Client::MoveItemToInventory(ItemInst *ItemToReturn, bool UpdateClient) { int ChargeSlotsLeft = InvItem->GetItem()->StackSize - InvItem->GetCharges(); - int ChargesToMove = ItemToReturn->GetCharges() < ChargeSlotsLeft ? ItemToReturn->GetCharges() : - ChargeSlotsLeft; + int ChargesToMove = ItemToReturn->GetCharges() < ChargeSlotsLeft ? ItemToReturn->GetCharges() : ChargeSlotsLeft; InvItem->SetCharges(InvItem->GetCharges() + ChargesToMove); @@ -2724,17 +2688,14 @@ bool Client::MoveItemToInventory(ItemInst *ItemToReturn, bool UpdateClient) { int ChargeSlotsLeft = InvItem->GetItem()->StackSize - InvItem->GetCharges(); - int ChargesToMove = ItemToReturn->GetCharges() < ChargeSlotsLeft - ? ItemToReturn->GetCharges() : ChargeSlotsLeft; + int ChargesToMove = ItemToReturn->GetCharges() < ChargeSlotsLeft ? ItemToReturn->GetCharges() : ChargeSlotsLeft; InvItem->SetCharges(InvItem->GetCharges() + ChargesToMove); if(UpdateClient) - SendItemPacket(BaseSlotID + BagSlot, m_inv.GetItem(BaseSlotID + BagSlot), - ItemPacketTrade); + SendItemPacket(BaseSlotID + BagSlot, m_inv.GetItem(BaseSlotID + BagSlot), ItemPacketTrade); - database.SaveInventory(character_id, m_inv.GetItem(BaseSlotID + BagSlot), - BaseSlotID + BagSlot); + database.SaveInventory(character_id, m_inv.GetItem(BaseSlotID + BagSlot), BaseSlotID + BagSlot); ItemToReturn->SetCharges(ItemToReturn->GetCharges() - ChargesToMove); @@ -2809,30 +2770,45 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool std::map instmap; // build reference map - for (int16 index = MAIN_BEGIN; index < EmuConstants::MAP_POSSESSIONS_SIZE; ++index) - if (m_inv[index]) - instmap[index] = m_inv[index]; - for (int16 index = EmuConstants::TRIBUTE_BEGIN; index <= EmuConstants::TRIBUTE_END; ++index) - if (m_inv[index]) - instmap[index] = m_inv[index]; - for (int16 index = EmuConstants::BANK_BEGIN; index <= EmuConstants::BANK_END; ++index) - if (m_inv[index]) - instmap[index] = m_inv[index]; - for (int16 index = EmuConstants::SHARED_BANK_BEGIN; index <= EmuConstants::SHARED_BANK_END; ++index) - if (m_inv[index]) - instmap[index] = m_inv[index]; - for (int16 index = EmuConstants::TRADE_BEGIN; index <= EmuConstants::TRADE_END; ++index) - if (m_inv[index]) - instmap[index] = m_inv[index]; + for (int16 index = MAIN_BEGIN; index < EmuConstants::MAP_POSSESSIONS_SIZE; ++index) { + auto inst = m_inv[index]; + if (inst == nullptr) { continue; } + instmap[index] = inst; + } + for (int16 index = EmuConstants::TRIBUTE_BEGIN; index <= EmuConstants::TRIBUTE_END; ++index) { + auto inst = m_inv[index]; + if (inst == nullptr) { continue; } + instmap[index] = inst; + } + for (int16 index = EmuConstants::BANK_BEGIN; index <= EmuConstants::BANK_END; ++index) { + auto inst = m_inv[index]; + if (inst == nullptr) { continue; } + instmap[index] = inst; + } + for (int16 index = EmuConstants::SHARED_BANK_BEGIN; index <= EmuConstants::SHARED_BANK_END; ++index) { + auto inst = m_inv[index]; + if (inst == nullptr) { continue; } + instmap[index] = inst; + } + for (int16 index = EmuConstants::TRADE_BEGIN; index <= EmuConstants::TRADE_END; ++index) { + auto inst = m_inv[index]; + if (inst == nullptr) { continue; } + instmap[index] = inst; + } - if (Object* tsobject = GetTradeskillObject()) - for (int16 index = MAIN_BEGIN; index < EmuConstants::MAP_WORLD_SIZE; ++index) - if (tsobject->GetItem(index)) - instmap[EmuConstants::WORLD_BEGIN + index] = tsobject->GetItem(index); + auto tsobject = GetTradeskillObject(); + if (tsobject != nullptr) { + for (int16 index = MAIN_BEGIN; index < EmuConstants::MAP_WORLD_SIZE; ++index) { + auto inst = tsobject->GetItem(index); + if (inst == nullptr) { continue; } + instmap[EmuConstants::WORLD_BEGIN + index] = inst; + } + } int limbo = 0; - for (iter_queue cursor_itr = m_inv.cursor_begin(); cursor_itr != m_inv.cursor_end(); ++cursor_itr, ++limbo) { - if (cursor_itr == m_inv.cursor_begin()) // m_inv.cursor_begin() is referenced as MainCursor in MapPossessions above + for (auto cursor_itr = m_inv.cursor_begin(); cursor_itr != m_inv.cursor_end(); ++cursor_itr, ++limbo) { + // m_inv.cursor_begin() is referenced as MainCursor in MapPossessions above + if (cursor_itr == m_inv.cursor_begin()) continue; instmap[8000 + limbo] = *cursor_itr; @@ -2842,18 +2818,24 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool instmap[MainPowerSource] = m_inv[MainPowerSource]; // call InterrogateInventory_ for error check - for (std::map::iterator instmap_itr = instmap.begin(); (instmap_itr != instmap.end()) && (!error); ++instmap_itr) + for (std::map::iterator instmap_itr = instmap.begin(); (instmap_itr != instmap.end()) && (!error); ++instmap_itr) { InterrogateInventory_(true, requester, instmap_itr->first, INVALID_INDEX, instmap_itr->second, nullptr, log, silent, error, 0); + } if (autolog && error && (!log)) log = true; - if (!silent) + if (log) { + _Log.Out(Logs::General, Logs::Error, "Client::InterrogateInventory() called for %s by %s with an error state of %s", GetName(), requester->GetName(), (error ? "TRUE" : "FALSE")); + } + if (!silent) { requester->Message(1, "--- Inventory Interrogation Report for %s (requested by: %s, error state: %s) ---", GetName(), requester->GetName(), (error ? "TRUE" : "FALSE")); + } // call InterrogateInventory_ for report - for (std::map::iterator instmap_itr = instmap.begin(); (instmap_itr != instmap.end()); ++instmap_itr) + for (std::map::iterator instmap_itr = instmap.begin(); (instmap_itr != instmap.end()); ++instmap_itr) { InterrogateInventory_(false, requester, instmap_itr->first, INVALID_INDEX, instmap_itr->second, nullptr, log, silent, error, 0); + } if (error) { Message(13, "An error has been discovered in your inventory!"); @@ -2890,10 +2872,12 @@ void Client::InterrogateInventory_(bool errorcheck, Client* requester, int16 hea error = true; } else { - if (inst) - for (int16 sub = SUB_BEGIN; (sub < EmuConstants::ITEM_CONTAINER_SIZE) && (!error); ++sub) // treat any ItemInst as having the max internal slots available + if (inst) { + for (int16 sub = SUB_BEGIN; (sub < EmuConstants::ITEM_CONTAINER_SIZE) && (!error); ++sub) { // treat any ItemInst as having the max internal slots available if (inst->GetItem(sub)) InterrogateInventory_(true, requester, head, sub, inst->GetItem(sub), inst, log, silent, error, depth + 1); + } + } } } else { @@ -2902,24 +2886,28 @@ void Client::InterrogateInventory_(bool errorcheck, Client* requester, int16 hea std::string p; std::string e; - if (inst) { i = StringFormat("%s (class: %u | augtype: %u)", inst->GetItem()->Name, inst->GetItem()->ItemClass, inst->GetItem()->AugType); } + if (inst) { i = StringFormat("%s (id: %u, cls: %u, aug_t: %u)", inst->GetItem()->Name, inst->GetItem()->ID, inst->GetItem()->ItemClass, inst->GetItem()->AugType); } else { i = "NONE"; } - if (parent) { p = StringFormat("%s (class: %u | augtype: %u), index: %i", parent->GetItem()->Name, parent->GetItem()->ItemClass, parent->GetItem()->AugType, index); } + if (parent) { p = StringFormat("%s (id: %u, cls: %u, aug_t: %u), index: %i", parent->GetItem()->Name, parent->GetItem()->ID, parent->GetItem()->ItemClass, parent->GetItem()->AugType, index); } else { p = "NONE"; } if (localerror) { e = " [ERROR]"; } else { e = ""; } - if (log) + if (log) { Log.Out(Logs::General, Logs::Error, "Head: %i, Depth: %i, Instance: %s, Parent: %s%s", - head, depth, i.c_str(), p.c_str(), e.c_str()); - if (!silent) - requester->Message(1, "%i:%i - inst: %s - parent: %s%s", - head, depth, i.c_str(), p.c_str(), e.c_str()); + head, depth, i.c_str(), p.c_str(), e.c_str()); + } + if (!silent) { + requester->Message(6, "%i:%i - inst: %s - parent: %s%s", + head, depth, i.c_str(), p.c_str(), e.c_str()); + } - if (inst) - for (int16 sub = SUB_BEGIN; (sub < EmuConstants::ITEM_CONTAINER_SIZE); ++sub) + if (inst) { + for (int16 sub = SUB_BEGIN; (sub < EmuConstants::ITEM_CONTAINER_SIZE); ++sub) { if (inst->GetItem(sub)) InterrogateInventory_(false, requester, head, sub, inst->GetItem(sub), inst, log, silent, error, depth + 1); + } + } } return; diff --git a/zone/maxskill.h b/zone/maxskill.h index 8979d4814..e37cccac0 100644 --- a/zone/maxskill.h +++ b/zone/maxskill.h @@ -1,2340 +1,2906 @@ // This file needs more than just 'std' updates -uint16 Mob::MaxSkill_weapon(uint16 skillid, uint16 class_, uint16 level) const{ - if (skillid > HIGHEST_SKILL) +uint16 Mob::MaxSkill_weapon(uint16 skillid, uint16 class_, uint16 level) const +{ + if (skillid > HIGHEST_SKILL) { return 0; - uint16 r_value = 0; - switch(skillid) { - case _1H_BLUNT: - case _2H_BLUNT: - case PIERCING: - case HAND_TO_HAND: - case _1H_SLASHING: - case _2H_SLASHING:{ - switch (class_) { - // Pure melee classes - case WARRIOR: case WARRIORGM:{ - r_value = 5 + (level*5); - if ( level < 51 && r_value > 200) - r_value = 200; - if ( level > 50 && r_value > 250 ) - r_value = 250; - switch (skillid) { - case PIERCING:{ - if ( r_value > 240 ) - r_value = 240; - break; - } - case HAND_TO_HAND:{ - if ( r_value > 100 ) - r_value = 100; - break; - } - default: break; - } - break; - } - case MONK: case MONKGM:{ - r_value = 5 + (level*5); - if ( level < 51 && r_value > 240) - if ( r_value > 240 ) - r_value = 240; - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 225 && level < 51 ) - r_value = 225; - break; - } - case PIERCING: - case _1H_SLASHING: - case _2H_SLASHING:{ - r_value = 0; - break; - } - default: break; - } - break; - } - case ROGUE: case ROGUEGM:{ - r_value = 5 + (level*5); - if ( level > 50 && r_value > 250 ) - r_value = 250; - if ( level < 51 ){ - if ( r_value > 200 && skillid != PIERCING ) - r_value = 200; - if ( r_value > 210 && skillid == PIERCING ) - r_value = 210; - } - if (skillid == HAND_TO_HAND && r_value > 100) - r_value = 100; - break; - } - case BERSERKER: case BERSERKERGM:{ - r_value = 5 + (level*5); - if ( level < 51 && r_value > 240) - r_value = 240; - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 198) - r_value = 198; - break; - } - case PIERCING:{ - if ( r_value > 240) - r_value = 240; - break; - } - case _2H_BLUNT: - case _2H_SLASHING:{ - if ( r_value > 252 ) - r_value = 252; - break; - } - default: - r_value = 0; - break; - } - break; - } - // Priest classes - case CLERIC: case CLERICGM:{ - r_value = 4 + (level*4); - if ( r_value > 175 ){ - r_value = 175; - } - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 75 ) - r_value = 75; - break; - } - case PIERCING: - case _1H_SLASHING: - case _2H_SLASHING:{ - r_value = 0; - break; - } - default: break; - } - break; - } - case DRUID: case DRUIDGM:{ - r_value = 4 + (level*4); - if ( r_value > 175 ){ - r_value = 175; - } - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 75 ) - r_value = 75; - } - case PIERCING: - case _2H_SLASHING:{ - r_value = 0; - break; - - } - default: break; - } - break; - } - case SHAMAN: case SHAMANGM:{ - r_value = 4 + (level*4); - if ( r_value > 200 ){ - r_value = 200; - } - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 75 ) - r_value = 75; - } - case _1H_SLASHING: - case _2H_SLASHING:{ - r_value = 0; - break; - } - default: break; - } - break; - } - // Hybrids - case RANGER: case RANGERGM:{ - r_value = 5 + (level*5); - if ( level > 50 ){ - if ( r_value > 250 ) - r_value = 250; - switch (skillid) { - case PIERCING:{ - if ( r_value > 240 ) - r_value = 240; - break; - } - default: break; - } - } - else if ( level < 51 ){ - if ( r_value > 200 ) - r_value = 200; - } - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 100 ) - r_value = 100; - break; - } - default: break; - } - break; - } - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - r_value = 5 + (level*5); - if ( level > 50 && r_value > 225 ){ - r_value = 225; - } - if ( level < 51 && r_value > 200 ){ - r_value = 200; - } - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 100 ) - r_value = 100; - break; - } - default: break; - } - break; - } - case BARD: case BARDGM:{ - r_value = 5 + (level*5); - if ( level > 51 && r_value > 225 ) - r_value = 225; - if ( level < 51 && r_value > 200 ) - r_value = 200; - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 100 ) - r_value = 100; - break; - } - case _2H_BLUNT: - case _2H_SLASHING:{ - r_value = 0; - } - default: break; - } - break; - } - case BEASTLORD: case BEASTLORDGM:{ - r_value = 4 + (level*4); - if ( level > 51 ){ - if ( r_value > 225 ) - r_value = 225; - } - if ( level < 51 && r_value > 200 ) - r_value = 200; - switch (skillid) { - case HAND_TO_HAND:{ - r_value = 5 + (level*5); // Beastlords use different max skill formula only for h2h 200/250 - if ( level < 51 ) - r_value = 200; - break; - } - case _1H_SLASHING: - case _2H_SLASHING:{ - r_value = 0; - break; - } - default: break; - } - if ( r_value > 250 ) - r_value = 250; - break; - } - // Pure casters - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM:{ - r_value = 3 + (level*3); - if ( r_value > 110 ) - r_value = 110; - switch (skillid) { - case HAND_TO_HAND:{ - if ( r_value > 75 ) - r_value = 75; - } - case _1H_SLASHING: - case _2H_SLASHING:{ - r_value = 0; - break; - } - default: break; - } - break; - } - default: -#if EQDEBUG - std::cout<<"MaxSkill_Weapon() Unknown class: "< 252) - r_value = 252; - return r_value; + } + uint16 r_value = 0; + switch (skillid) { + case _1H_BLUNT: + case _2H_BLUNT: + case PIERCING: + case HAND_TO_HAND: + case _1H_SLASHING: + case _2H_SLASHING: { + switch (class_) { + // Pure melee classes + case WARRIOR: + case WARRIORGM: { + r_value = 5 + (level * 5); + if ( level < 51 && r_value > 200) { + r_value = 200; + } + if ( level > 50 && r_value > 250 ) { + r_value = 250; + } + switch (skillid) { + case PIERCING: { + if ( r_value > 240 ) { + r_value = 240; + } + break; + } + case HAND_TO_HAND: { + if ( r_value > 100 ) { + r_value = 100; + } + break; + } + default: + break; + } + break; + } + case MONK: + case MONKGM: { + r_value = 5 + (level * 5); + if ( level < 51 && r_value > 240) + if ( r_value > 240 ) { + r_value = 240; + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 225 && level < 51 ) { + r_value = 225; + } + break; + } + case PIERCING: + case _1H_SLASHING: + case _2H_SLASHING: { + r_value = 0; + break; + } + default: + break; + } + break; + } + case ROGUE: + case ROGUEGM: { + r_value = 5 + (level * 5); + if ( level > 50 && r_value > 250 ) { + r_value = 250; + } + if ( level < 51 ) { + if ( r_value > 200 && skillid != PIERCING ) { + r_value = 200; + } + if ( r_value > 210 && skillid == PIERCING ) { + r_value = 210; + } + } + if (skillid == HAND_TO_HAND && r_value > 100) { + r_value = 100; + } + break; + } + case BERSERKER: + case BERSERKERGM: { + r_value = 5 + (level * 5); + if ( level < 51 && r_value > 240) { + r_value = 240; + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 198) { + r_value = 198; + } + break; + } + case PIERCING: { + if ( r_value > 240) { + r_value = 240; + } + break; + } + case _2H_BLUNT: + case _2H_SLASHING: { + if ( r_value > 252 ) { + r_value = 252; + } + break; + } + default: + r_value = 0; + break; + } + break; + } + // Priest classes + case CLERIC: + case CLERICGM: { + r_value = 4 + (level * 4); + if ( r_value > 175 ) { + r_value = 175; + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 75 ) { + r_value = 75; + } + break; + } + case PIERCING: + case _1H_SLASHING: + case _2H_SLASHING: { + r_value = 0; + break; + } + default: + break; + } + break; + } + case DRUID: + case DRUIDGM: { + r_value = 4 + (level * 4); + if ( r_value > 175 ) { + r_value = 175; + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 75 ) { + r_value = 75; + } + } + case PIERCING: + case _2H_SLASHING: { + r_value = 0; + break; + } + default: + break; + } + break; + } + case SHAMAN: + case SHAMANGM: { + r_value = 4 + (level * 4); + if ( r_value > 200 ) { + r_value = 200; + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 75 ) { + r_value = 75; + } + } + case _1H_SLASHING: + case _2H_SLASHING: { + r_value = 0; + break; + } + default: + break; + } + break; + } + // Hybrids + case RANGER: + case RANGERGM: { + r_value = 5 + (level * 5); + if ( level > 50 ) { + if ( r_value > 250 ) { + r_value = 250; + } + switch (skillid) { + case PIERCING: { + if ( r_value > 240 ) { + r_value = 240; + } + break; + } + default: + break; + } + } else if ( level < 51 ) { + if ( r_value > 200 ) { + r_value = 200; + } + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 100 ) { + r_value = 100; + } + break; + } + default: + break; + } + break; + } + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + r_value = 5 + (level * 5); + if ( level > 50 && r_value > 225 ) { + r_value = 225; + } + if ( level < 51 && r_value > 200 ) { + r_value = 200; + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 100 ) { + r_value = 100; + } + break; + } + default: + break; + } + break; + } + case BARD: + case BARDGM: { + r_value = 5 + (level * 5); + if ( level > 51 && r_value > 225 ) { + r_value = 225; + } + if ( level < 51 && r_value > 200 ) { + r_value = 200; + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 100 ) { + r_value = 100; + } + break; + } + case _2H_BLUNT: + case _2H_SLASHING: { + r_value = 0; + } + default: + break; + } + break; + } + case BEASTLORD: + case BEASTLORDGM: { + r_value = 4 + (level * 4); + if ( level > 51 ) { + if ( r_value > 225 ) { + r_value = 225; + } + } + if ( level < 51 && r_value > 200 ) { + r_value = 200; + } + switch (skillid) { + case HAND_TO_HAND: { + r_value = 5 + (level * 5); // Beastlords use different max skill formula only for h2h 200/250 + if ( level < 51 ) { + r_value = 200; + } + break; + } + case _1H_SLASHING: + case _2H_SLASHING: { + r_value = 0; + break; + } + default: + break; + } + if ( r_value > 250 ) { + r_value = 250; + } + break; + } + // Pure casters + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: { + r_value = 3 + (level * 3); + if ( r_value > 110 ) { + r_value = 110; + } + switch (skillid) { + case HAND_TO_HAND: { + if ( r_value > 75 ) { + r_value = 75; + } + } + case _1H_SLASHING: + case _2H_SLASHING: { + r_value = 0; + break; + } + default: + break; + } + break; + } + default: + #if EQDEBUG + std::cout << "MaxSkill_Weapon() Unknown class: " << class_ << std::endl; + #endif + break; + } + break;// Switch Class + } + default: + #if EQDEBUG + std::cout << "Unknown weapon skill: " << skillid << std::endl; + #endif + break; + }// Switch skill + if (r_value > 252) { + r_value = 252; + } + return r_value; } -uint16 Mob::MaxSkill_offensive(uint16 skillid, uint16 class_, uint16 level) const{ - uint16 r_value = 0; - switch(skillid) { - - case OFFENSE:{ - switch (class_) { - // Melee - case WARRIOR: case WARRIORGM: - case BERSERKER: case BERSERKERGM: - case ROGUE: case ROGUEGM:{ - // 210 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 210) - r_value = 210; - } - if (r_value > 252) - r_value = 252; - break; - } - case MONK: case MONKGM:{ - // 230 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 230) - - r_value = 230; - } - if (r_value > 252) - r_value = 252; - break; - } - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM:{ - // 200 200 4*level+4 - r_value = ((level*4) + 4); - if (r_value > 200) - r_value = 200; - break; - } - // Hybrid - case BEASTLORD: case BEASTLORDGM:{ - // 200 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 252) - r_value = 252; - break; - } - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM: - case BARD: case BARDGM:{ - // 200 225 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 225) - r_value = 225; - break; - } - case RANGER: case RANGERGM:{ - // 210 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 210) - r_value = 210; - } - if (r_value > 252) - r_value = 252; - break; - } - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM:{ - // 140 140 level*4 - r_value = (level*4); - if (r_value > 140) - r_value = 140; - break; - } - default: break; - } - break; - } - case THROWING:{ - switch (class_) { - // Melee - case BERSERKER: case BERSERKERGM: - case ROGUE: case ROGUEGM:{ - // 220 250 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 220) - r_value = 220; - } - if (r_value > 250) - r_value = 250; - break; - } - case WARRIOR: case WARRIORGM: - case MONK: case MONKGM:{ - // 113 200 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 113) - r_value = 113; - } - if (r_value > 200) - r_value = 200; - break; - } - // Hybrid - case BEASTLORD: case BEASTLORDGM: - - case BARD: case BARDGM: - case RANGER: case RANGERGM:{ - // 113 - r_value = ((level*5) + 5); - if ( r_value > 113 ) - r_value = 113; - break; - } - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - - case ENCHANTER: case ENCHANTERGM:{ - // 75 - r_value = ((level*3) + 3); - if ( r_value > 75 ) - r_value = 75; - break; - } - // No skill classes - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM: - default: - r_value = 0; - break; - } - break; - } +uint16 Mob::MaxSkill_offensive(uint16 skillid, uint16 class_, uint16 level) const +{ + uint16 r_value = 0; + switch (skillid) { + case OFFENSE: { + switch (class_) { + // Melee + case WARRIOR: + case WARRIORGM: + case BERSERKER: + case BERSERKERGM: + case ROGUE: + case ROGUEGM: { + // 210 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 210) { + r_value = 210; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + case MONK: + case MONKGM: { + // 230 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 230) { + r_value = 230; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: { + // 200 200 4*level+4 + r_value = ((level * 4) + 4); + if (r_value > 200) { + r_value = 200; + } + break; + } + // Hybrid + case BEASTLORD: + case BEASTLORDGM: { + // 200 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: + case BARD: + case BARDGM: { + // 200 225 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 225) { + r_value = 225; + } + break; + } + case RANGER: + case RANGERGM: { + // 210 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 210) { + r_value = 210; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: { + // 140 140 level*4 + r_value = (level * 4); + if (r_value > 140) { + r_value = 140; + } + break; + } + default: + break; + } + break; + } + case THROWING: { + switch (class_) { + // Melee + case BERSERKER: + case BERSERKERGM: + case ROGUE: + case ROGUEGM: { + // 220 250 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 220) { + r_value = 220; + } + } + if (r_value > 250) { + r_value = 250; + } + break; + } + case WARRIOR: + case WARRIORGM: + case MONK: + case MONKGM: { + // 113 200 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 113) { + r_value = 113; + } + } + if (r_value > 200) { + r_value = 200; + } + break; + } + // Hybrid + case BEASTLORD: + case BEASTLORDGM: + case BARD: + case BARDGM: + case RANGER: + case RANGERGM: { + // 113 + r_value = ((level * 5) + 5); + if ( r_value > 113 ) { + r_value = 113; + } + break; + } + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: { + // 75 + r_value = ((level * 3) + 3); + if ( r_value > 75 ) { + r_value = 75; + } + break; + } + // No skill classes + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: + default: + r_value = 0; + break; + } + break; + } ///////////////////////////////////////////////// - case ARCHERY:{ - switch (class_) { - // Melee - case ROGUE: case ROGUEGM: - case WARRIOR: case WARRIORGM:{ - // 200 240 - r_value = ((level*5) + 5); - if ( level < 51 && r_value > 200) - r_value = 200; - if (r_value > 240) - r_value = 240; - break; - } - // Hybrid - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 75 75 - r_value = ((level*5) + 5); - if ( r_value > 75 ) - r_value = 75; - break; - } - case RANGER: case RANGERGM:{ - // 240 240 - r_value = ((level*5) + 5); - if ( r_value > 240 ) - r_value = 240; - break; - } - // Pure - // No skill classes - // Melee - case MONK: case MONKGM: - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - case BEASTLORD: case BEASTLORDGM: - case BARD: case BARDGM: - default: - r_value = 0; - break; - } - break; - } + case ARCHERY: { + switch (class_) { + // Melee + case ROGUE: + case ROGUEGM: + case WARRIOR: + case WARRIORGM: { + // 200 240 + r_value = ((level * 5) + 5); + if ( level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 240) { + r_value = 240; + } + break; + } + // Hybrid + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 75 75 + r_value = ((level * 5) + 5); + if ( r_value > 75 ) { + r_value = 75; + } + break; + } + case RANGER: + case RANGERGM: { + // 240 240 + r_value = ((level * 5) + 5); + if ( r_value > 240 ) { + r_value = 240; + } + break; + } + // Pure + // No skill classes + // Melee + case MONK: + case MONKGM: + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + case BEASTLORD: + case BEASTLORDGM: + case BARD: + case BARDGM: + default: + r_value = 0; + break; + } + break; + } ///////////////////////////////////////////////// - case DOUBLE_ATTACK:{ - switch (class_) { - // Melee - case ROGUE: case ROGUEGM:{ - // 16 200 240 - r_value = ((level*5) + 5); - if ( level < 16 ) - r_value = 0; - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 240) - r_value = 240; - break; - } - case BERSERKER: case BERSERKERGM: - case WARRIOR: case WARRIORGM:{ - // 15 205 245 - r_value = ((level*5) + 5); - if ( level < 15 ) - r_value = 0; - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 245) - r_value = 245; - break; - } - case MONK: case MONKGM:{ - // 15 210 250 - r_value = ((level*5) + 5); - if ( level < 15 ) - r_value = 0; - if ( level < 51 ) { - if (r_value > 210) - r_value = 210; - } - if (r_value > 250) - r_value = 250; - break; - } - // Hybrid - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 20 200 235 - r_value = ((level*5) + 5); - if ( level < 20 ) - r_value = 0; - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 235) - r_value = 235; - break; - } - case RANGER: case RANGERGM:{ - // 20 200 245 - r_value = ((level*5) + 5); - if ( level < 20 ) - r_value = 0; - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 245) - r_value = 245; - break; - } - // Pure - // No skill classes - // Melee - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - case BEASTLORD: case BEASTLORDGM: - case BARD: case BARDGM: - default: - r_value = 0; - break; - } - break; - } + case DOUBLE_ATTACK: { + switch (class_) { + // Melee + case ROGUE: + case ROGUEGM: { + // 16 200 240 + r_value = ((level * 5) + 5); + if ( level < 16 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 240) { + r_value = 240; + } + break; + } + case BERSERKER: + case BERSERKERGM: + case WARRIOR: + case WARRIORGM: { + // 15 205 245 + r_value = ((level * 5) + 5); + if ( level < 15 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 245) { + r_value = 245; + } + break; + } + case MONK: + case MONKGM: { + // 15 210 250 + r_value = ((level * 5) + 5); + if ( level < 15 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 210) { + r_value = 210; + } + } + if (r_value > 250) { + r_value = 250; + } + break; + } + // Hybrid + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 20 200 235 + r_value = ((level * 5) + 5); + if ( level < 20 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 235) { + r_value = 235; + } + break; + } + case RANGER: + case RANGERGM: { + // 20 200 245 + r_value = ((level * 5) + 5); + if ( level < 20 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 245) { + r_value = 245; + } + break; + } + // Pure + // No skill classes + // Melee + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + case BEASTLORD: + case BEASTLORDGM: + case BARD: + case BARDGM: + default: + r_value = 0; + break; + } + break; + } ///////////////////////////////////////////////// case DUAL_WIELD: { - switch (class_) { - // Melee - case MONK: case MONKGM:{ - // 1 252 252 - r_value = level*7; // This can't be right can it? - break -; - } - case WARRIOR: case WARRIORGM: - case ROGUE: case ROGUEGM: { - // 15 210 245 - r_value = ((level*5) + 5); - if ( level < 13 ) + switch (class_) { + // Melee + case MONK: + case MONKGM: { + // 1 252 252 + r_value = level * 7; // This can't be right can it? + break + ; + } + case WARRIOR: + case WARRIORGM: + case ROGUE: + case ROGUEGM: { + // 15 210 245 + r_value = ((level * 5) + 5); + if ( level < 13 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 210) { + r_value = 210; + } + } + if (r_value > 245) { + r_value = 245; + } + break; + } + // Hybrid + case BEASTLORD: + case BEASTLORDGM: + // 17 210 245 + case RANGER: + case RANGERGM: { + // 17 210 245 + r_value = ((level * 5) + 5); + if ( level < 17 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 210) { + r_value = 210; + } + } + if (r_value > 245) { + r_value = 245; + } + break; + } + case BARD: + case BARDGM: { + // 17 210 210 + r_value = ((level * 5) + 5); + if ( level < 17 ) { + r_value = 0; + } + if (r_value > 210) { + r_value = 210; + } + break; + } + // No skill classes + // Melee + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: + default: { + r_value = 0; + break; + } + }// end Class switch + break; + } // end case DUAL_WIELD: +//////////////////////////////////////////////////////// + case KICK: { + switch (class_) { + // Melee + case BERSERKER: + case BERSERKERGM: + case WARRIOR: + case WARRIORGM: { + // 1 149 210 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 149) { + r_value = 149; + } + } + if (r_value > 210) { + r_value = 210; + } + break; + } + case MONK: + case MONKGM: { + // 1 200 250 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 250) { + r_value = 250; + } + break; + } + // Hybrid + case RANGER: + case RANGERGM: { + // 5 149 205 + r_value = ((level * 5) + 5); + if ( level < 5 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 149) { + r_value = 149; + } + } + if (r_value > 205) { + r_value = 205; + } + break; + } + case BEASTLORD: + case BEASTLORDGM: { + // 5 180 230 + r_value = ((level * 5) + 5); + if ( level < 5 ) { + r_value = 0; + } + if ( level < 51 ) { + if (r_value > 180) { + r_value = 180; + } + } + if (r_value > 230) { + r_value = 230; + } + break; + } + // Pure + // No skill classes + case ROGUE: + case ROGUEGM: + // Melee + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: + case BARD: + case BARDGM: + default: r_value = 0; - if ( level < 51 ) { - if (r_value > 210) - r_value = 210; - } - if (r_value > 245) - r_value = 245; - break; + break; } - // Hybrid - case BEASTLORD: case BEASTLORDGM: - // 17 210 245 - case RANGER: case RANGERGM:{ - // 17 210 245 - r_value = ((level*5) + 5); - if ( level < 17 ) - r_value = 0; - if ( level < 51 ) { - if (r_value > 210) - r_value = 210; - } - if (r_value > 245) - r_value = 245; - break; + break; + } +//////////////////////////////////////////////////////// + case BASH: { + r_value = ((level * 5) + 5); + switch (class_) { + // Melee + case WARRIOR: + case WARRIORGM: { + // 6 220 240 + if (level < 6) { + r_value = 0; + } + if (level < 51 && r_value > 220) { + r_value = 220; + } + if (r_value > 240) { + r_value = 240; + } + break; + } + // Priest + case CLERIC: + case CLERICGM: { + // 25 180 200 + if (level < 25) { + r_value = 0; + } + if (level < 51 && r_value > 180) { + r_value = 180; + } + if (r_value > 200) { + r_value = 200; + } + break; + } + // Hybrid + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 6 175 200 + if (level < 6) { + r_value = 0; + } + if (level < 51 && r_value > 175) { + r_value = 175; + } + if (r_value > 200) { + r_value = 200; + } + break; + } + // Pure + // No skill classes + // Melee + case MONK: + case MONKGM: + case ROGUE: + case ROGUEGM: + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + case BEASTLORD: + case BEASTLORDGM: + case RANGER: + case RANGERGM: + case BARD: + case BARDGM: { + // switch (race) { + // case BARBARIAN: + // case TROLL: + //case OGRE:{ + // r_value = 50; + //break; + //} + //default: break; + //} + r_value = 0; + break; + } } - case BARD: case BARDGM:{ - // 17 210 210 - r_value = ((level*5) + 5); - if ( level < 17 ) - r_value = 0; - if (r_value > 210) - r_value = 210; - break; - } - // No skill classes - // Melee - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM: - default: { - r_value = 0; - break; - } - }// end Class switch + break; + } +//////////////////////////////////////////////////////// + default: + #if EQDEBUG >= 1 + std::cout << "Unknown Offensive skill: " << skillid << std::endl; + #endif break; - } // end case DUAL_WIELD: -//////////////////////////////////////////////////////// - case KICK:{ - switch (class_) { - // Melee - case BERSERKER: case BERSERKERGM: - case WARRIOR: case WARRIORGM:{ - // 1 149 210 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 149) - r_value = 149; - } - if (r_value > 210) - r_value = 210; - break; - } - case MONK: case MONKGM:{ - // 1 200 250 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 250) - r_value = 250; - break; - } - // Hybrid - case RANGER: case RANGERGM:{ - // 5 149 205 - r_value = ((level*5) + 5); - if ( level < 5 ) - r_value = 0; - if ( level < 51 ) { - if (r_value > 149) - r_value = 149; - } - if (r_value > 205) - r_value = 205; - break; - } - case BEASTLORD: case BEASTLORDGM:{ - // 5 180 230 - r_value = ((level*5) + 5); - if ( level < 5 ) - r_value = 0; - if ( level < 51 ) { - if (r_value > 180) - r_value = 180; - } - if (r_value > 230) - r_value = 230; - break; - } - // Pure - // No skill classes - case ROGUE: case ROGUEGM: - // Melee - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM: - case BARD: case BARDGM: - default: - r_value = 0; - break; - } - break; - } -//////////////////////////////////////////////////////// - case BASH:{ - r_value = ((level*5)+5); - switch (class_) { - // Melee - case WARRIOR: case WARRIORGM:{ - // 6 220 240 - if (level < 6) - r_value = 0; - if (level < 51 && r_value > 220) - r_value = 220; - if (r_value > 240) - r_value = 240; - break; - } - // Priest - case CLERIC: case CLERICGM:{ - // 25 180 200 - - if (level < 25) - r_value = 0; - if (level < 51 && r_value > 180) - r_value = 180; - if (r_value > 200) - r_value = 200; - break; - } - // Hybrid - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 6 175 200 - if (level < 6) - r_value = 0; - if (level < 51 && r_value > 175) - r_value = 175; - if (r_value > 200) - r_value = 200; - break; - } - // Pure - // No skill classes - // Melee - case MONK: case MONKGM: - case ROGUE: case ROGUEGM: - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - case BEASTLORD: case BEASTLORDGM: - case RANGER: case RANGERGM: - case BARD: case BARDGM:{ - // switch (race) { - // case BARBARIAN: - // case TROLL: - //case OGRE:{ - // r_value = 50; - - //break; - //} - //default: break; - //} - r_value = 0; - break; - } - } - break; - } -//////////////////////////////////////////////////////// - default: -#if EQDEBUG >= 1 - std::cout<<"Unknown Offensive skill: "< 252) - r_value = 252; - return r_value; -} - -uint16 Mob::MaxSkill_defensive(uint16 skillid, uint16 class_, uint16 level) const{ - uint16 r_value = 0; - switch(skillid) { - case DEFENSE:{ - switch (class_) { - // Melee - case WARRIOR: case WARRIORGM:{ - // 210 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 210) - r_value = 210; - } - if (r_value > 252) - r_value = 252; - break; - } - case ROGUE: case ROGUEGM:{ - // 200 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 252) - r_value = 252; - break; - } - case MONK: case MONKGM:{ - // 230 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 230) - r_value = 230; - } - if (r_value > 252) - r_value = 252; - break; - } - case BERSERKER: case BERSERKERGM:{ - // 230 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 230) - r_value = 230; - } - if (r_value > 252) - r_value = 252; - break; - } - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM:{ - // 200 200 4*level+4 - r_value = ((level*4) + 4); - if (r_value > 200) - r_value = 200; - break; - } - // Hybrid - case BEASTLORD: case BEASTLORDGM:{ - // 210 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 210) - r_value = 210; - } - if (r_value > 252) - r_value = 252; - break; - } - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 210 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 210) - r_value = 210; - } - if (r_value > 252) - r_value = 252; - break; - } - case BARD: case BARDGM:{ - // 200 252 5*level+5 - r_value = ((level*5) + 5); - if ( level < 51 ) { - if (r_value > 200) - r_value = 200; - } - if (r_value > 252) - r_value = 252; - break; - } - case RANGER: case RANGERGM:{ - // 200 200 5*level+5 - r_value = ((level*5) + 5); - if (r_value > 200) - r_value = 200; - break; - } - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM:{ - // 145 145 level*4 - r_value = (level*4); - if (r_value > 140) - r_value = 140; - break; - - } - default: break; - } - break; - } - case PARRY:{ - switch (class_) { - // Melee - case ROGUE: case ROGUEGM:{ - // 12 200 230 - r_value = ((level*5) + 5); - if ( level < 12 ) - r_value = 0; - if (r_value > 200 && level < 51 ) - - r_value = 200; - if (r_value > 230) - r_value = 230; - break; - } - case WARRIOR: case WARRIORGM:{ - // 10 200 230 - r_value = ((level*5) + 5); - if ( level < 10 ) - r_value = 0; - if (r_value > 200 && level < 51 ) - r_value = 200; - if (r_value > 230) - r_value = 230; - break; - } - case BERSERKER: case BERSERKERGM:{ - r_value = ((level*5) + 5); - if ( level < 10 ) - r_value = 0; - if (r_value > 175) - r_value = 175; - break; - } - - // Hybrid - case BARD: case BARDGM:{ - // 53 0 75 - r_value = ((level*5) + 5); - if ( level < 53 ) - r_value = 0; - if (r_value > 75) - r_value = 75; - break; - } - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 17 175 205 - r_value = ((level*5) + 5); - if ( level < 17 ) - r_value = 0; - if (r_value > 175 && level < 51 ) - r_value = 175; - if (r_value > 205) - r_value = 205; - break; - } - case RANGER: case RANGERGM:{ - // 18 185 220 - r_value = ((level*5) + 5); - if ( level < 18 ) - r_value = 0; - if (r_value > 185 && level < 51 ) - r_value = 185; - if (r_value > 220) - r_value = 220; - break; - } - // Pure - // No skill classes - // Melee - case MONK: case MONKGM: - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - case BEASTLORD: case BEASTLORDGM: - default: - r_value = 0; - break; - } - break; - } - case RIPOSTE:{ - switch (class_) { - // Melee - case BERSERKER: case BERSERKERGM: - case WARRIOR: case WARRIORGM:{ - // 25 200 225 - r_value = ((level*5) + 5); - if ( level < 25 ) - r_value = 0; - if (r_value > 200 && level < 51 ) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - case ROGUE: case ROGUEGM:{ - // 30 200 225 - r_value = ((level*5) + 5); - if ( level < 30 ) - r_value = 0; - if (r_value > 200 && level < 51 ) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - case MONK: case MONKGM:{ - // 35 200 225 - r_value = ((level*5) + 5); - if ( level < 35 ) - r_value = 0; - if (r_value > 200 && level < 51 ) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - // Hybrid - case BEASTLORD: case BEASTLORDGM:{ - // 40 150 185 - r_value = ((level*5) + 5); - if ( level < 40 ) - r_value = 0; - if (r_value > 150 && level < 51 ) - r_value = 150; - if (r_value > 185) - r_value = 185; - break; - } - case BARD: case BARDGM:{ - // 58 75 75 - r_value = ((level*5) + 5); - if ( level < 58 ) - r_value = 0; - if (r_value > 75) - r_value = 75; - break; - } - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 30 175 200 - r_value = ((level*5) + 5); - if ( level < 30 ) - r_value = 0; - if (r_value > 175 && level < 51 ) - r_value = 175; - if (r_value > 200) - r_value = 200; - break; - } - case RANGER: case RANGERGM:{ - // 35 150 150 - r_value = ((level*5) + 5); - if ( level < 35 ) - r_value = 0; - if (r_value > 150) - r_value = 150; - break; - } - // Pure - // No skill classes - // Melee - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - default: - r_value = 0; - break; - - } - break; - } - case DODGE:{ - switch (class_) { - // Melee - case BERSERKER: case BERSERKERGM: - case WARRIOR: case WARRIORGM:{ - // 6 140 175 - r_value = ((level*5) + 5); - if ( level < 6 ) - r_value = 0; - if (r_value > 140 && level < 51 ) - r_value = 140; - if (r_value > 175) - r_value = 175; - break; - } - case ROGUE: case ROGUEGM:{ - // 4 150 210 - r_value = ((level*5) + 5); - if ( level < 4 ) - r_value = 0; - if (r_value > 150 && level < 51 ) - r_value = 150; - if (r_value > 210) - r_value = 210; - break; - } - case MONK: case MONKGM:{ - // 1 200 230 - r_value = ((level*5) + 5); - if (r_value > 200) - r_value = 200; - if (r_value > 230) - r_value = 230; - break; - } - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM:{ - // 15 75 75 4*level+4 - r_value = ((level*4) + 4); - if ( level < 15 ) - r_value = 0; - if (r_value > 75) - r_value = 75; - break; - } - // Hybrid - case BEASTLORD: case BEASTLORDGM: - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM: - case BARD: case BARDGM:{ - // 10 125 155 5*level+5 - r_value = ((level*5) + 5); - if ( level < 10 ) - r_value = 0; - if (r_value > 125 && level < 51 ) - r_value = 125; - if (r_value > 155) - r_value = 155; - break; - } - case RANGER: case RANGERGM:{ - // 8 137 170 5*level+5 - r_value = ((level*5) + 5); - if ( level < 8 ) - r_value = 0; - if (r_value > 137 && level < 51 ) - r_value = 137; - if (r_value > 170) - r_value = 170; - break; - } - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM:{ - // 22 75 75 3*level+3 - r_value = ((level*3) + 3); - if ( level < 22 ) - r_value = 0; - if (r_value > 75) - r_value = 75; - break; - } - // No skill classes - // Melee - // Priest - // Pure - // Hybrid - default: break; - } - break; - } - // Other - case TAUNT:{ - switch (class_) { - // Melee - case WARRIOR: case WARRIORGM:{ - // 1 200 200 - r_value = ((level*5) + 5); - if (r_value > 200) - r_value = 200; - break; - } - // Priest - // Hybrid - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 1 180 180 - r_value = ((level*5) + 5); - if (r_value > 180) - r_value = 180; - - break; - } - case RANGER: case RANGERGM:{ - // 1 150 150 - r_value = ((level*5) + 5); - if (r_value > 150) - r_value = 150; - break; - - } - // Pure - - // No skill classes - // Melee - case ROGUE: case ROGUEGM: - case MONK: case MONKGM: - // Priest - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - case BEASTLORD: case BEASTLORDGM: - case BARD: case BARDGM: - default: break; - } - break; - } - case DISARM:{ - switch (class_) { - // Melee - case WARRIOR: case WARRIORGM:{ - // 35 200 200 - r_value = ((level*5) + 5); - if (level < 35) - r_value = 0; - if (r_value > 200) - r_value = 200; - break; - } - case ROGUE: case ROGUEGM: - case MONK: case MONKGM:{ - // 27 200 200 - r_value = ((level*5) + 5); - if (level < 27) - r_value = 0; - if (r_value > 200) - r_value = 200; - break; - } - case BERSERKER: case BERSERKERGM:{ - // 35 65 65 - r_value = ((level*5) + 5); - if (level < 35) - r_value = 0; - if (r_value > 65) - r_value = 65; - break; - } - // Priest - // Hybrid - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 40 70 70 - r_value = ((level*5) + 5); - if (level < 40) - r_value = 0; - if (r_value > 70) - r_value = 70; - break; - } - case RANGER: case RANGERGM:{ - // 35 55 55 - r_value = ((level*5) + 5); - if (level < 35) - r_value = 0; - if (r_value > 55) - r_value = 55; - break; - } - // Pure - - // No skill classes - // Melee - // Priest - - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - case CLERIC: case CLERICGM: - // Pure - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM: - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - // Hybrid - case BARD: case BARDGM: - case BEASTLORD: case BEASTLORDGM: - default: break; - } - break; - } -//////////////////////////////////////////////////////// - - default: -#if EQDEBUG - std::cout<<"Unknown Defensive skill: "< 252) - r_value = 252; - return r_value; -} - -uint16 Mob::MaxSkill_arcane(uint16 skillid, uint16 class_, uint16 level) const{ - uint16 r_value = 0; - switch(skillid) { - case MEDITATE: - case ABJURE: - case ALTERATION: - case CHANNELING: - case CONJURATION: - case DIVINATION: - case EVOCATION:{ - r_value = ((level*5) + 5); - switch(class_){ - // Hybrid - case RANGER: case RANGERGM:{ - // 9 235 235 - // Channel 9 200 215 - // Med 12 185 235 - if (level < 9) - r_value = 0; - if (level < 12 && skillid == MEDITATE) - r_value = 0; - if (r_value > 0 && skillid == CHANNELING) { - if ( level < 51 && r_value > 200) - r_value = 200; - if (r_value > 215) - r_value = 215; - } - if (r_value > 0 && skillid == MEDITATE) { - if ( level < 51 && r_value > 185) - r_value = 185; - if (r_value > 235) - r_value = 235; - } - break; - } - case BEASTLORD: case BEASTLORDGM: - case PALADIN: case PALADINGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ - // 9 235 235 - // Channel 9 200 220 - // Med 12 185 235 - if (level < 9) - r_value = 0; - if (level < 12 && skillid == MEDITATE) - r_value = 0; - if (r_value > 0 && skillid == CHANNELING) { - if ( level < 51 && r_value > 185) - r_value = 185; - if (r_value > 220) - r_value = 220; - } - if (r_value > 0 && skillid == MEDITATE) { - if ( level < 51 && r_value > 185) - r_value = 185; - if (r_value > 235) - - r_value = 235; - } - break; - } - // Priest - case CLERIC: case CLERICGM: - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM:{ - // 1 235 235 - // Channel 4 200 220 - // Med 8 235 252 - - if (level < 4 && skillid == CHANNELING) - r_value = 0; - if (level < 8 && skillid == MEDITATE) - r_value = 0; - if (r_value > 0 && skillid == CHANNELING) { - if ( level < 51 && r_value > 200) - r_value = 200; - if (r_value > 220) - r_value = 220; - } - if (r_value > 0 && skillid == MEDITATE) { - if ( level < 51 && r_value > 235) - r_value = 235; - if (r_value > 252) - r_value = 252; - } - break; - } - // Int caster - case ENCHANTER: case ENCHANTERGM: - case MAGICIAN: case MAGICIANGM: - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM:{ - // 1 235 235 - // Channel 1 200 220 - // Med 4 235 252 - if (level < 4 && skillid == MEDITATE) - r_value = 0; - if (r_value > 0 && skillid == CHANNELING) { - if ( level < 51 && r_value > 200) - r_value = 200; - if (r_value > 220) - r_value = 220; - } - if (r_value > 0 && skillid == MEDITATE) { - if ( level < 51 && r_value > 235) - r_value = 235; - if (r_value > 252) - r_value = 252; - } - break; - } - case BARD: case BARDGM:{ - r_value = 0; - if (level > 9 && skillid == MEDITATE) - r_value = 1; - break; - } - default: - // Unknown class - r_value = 0; - break; - }// Class Switch - break; - } - - case SPECIALIZE_ABJURE: - case SPECIALIZE_ALTERATION: - case SPECIALIZE_CONJURATION: - case SPECIALIZE_DIVINATION: - case SPECIALIZE_EVOCATION: - { - r_value = ((level*5) + 5); - switch(class_){ - // Non-int casters - case CLERIC: case CLERICGM: - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM: - if(level < 30) { - r_value = 0; - break; - } - - // Int caster - case ENCHANTER: case ENCHANTERGM: - case MAGICIAN: case MAGICIANGM: - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM:{ - if (level < 20) { - r_value = 0; - break; - } - - //make sure only 1 skill can be over 50 - uint16 hskill = 0; - uint16 high = 0; - uint16 cur; - cur = GetSkill(SPECIALIZE_ABJURE); - if(cur > high) { - hskill = SPECIALIZE_ABJURE; - high = cur; - } - cur = GetSkill(SPECIALIZE_ALTERATION); - if(cur > high) { - hskill = SPECIALIZE_ALTERATION; - high = cur; - } - cur = GetSkill(SPECIALIZE_CONJURATION); - if(cur > high) { - hskill = SPECIALIZE_CONJURATION; - high = cur; - } - cur = GetSkill(SPECIALIZE_DIVINATION); - if(cur > high) { - hskill = SPECIALIZE_DIVINATION; - high = cur; - } - cur = GetSkill(SPECIALIZE_EVOCATION); - if(cur > high) { - hskill = SPECIALIZE_EVOCATION; - high = cur; - } - if(high > 50 && hskill != skillid) { - r_value = 50; - break; - } - - if (r_value > 200) - r_value = 200; - break; - } - default:{ - r_value = 0; - break; - } - }// Class Switch - break; - } - case RESEARCH:{ - r_value = ((level*5) + 5); - switch(class_){ - // Int caster - case ENCHANTER: case ENCHANTERGM: - case MAGICIAN: case MAGICIANGM: - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM:{ - // Res 16 200 200 - if (level < 16) - r_value = 0; - if (r_value > 200) - r_value = 200; - // FIXME Only let one SPEC go above what ever limit theres supposed to be - break; - } - default:{ - r_value = 0; - break; - } - }// Class Switch - break; - } - - case BRASS_INSTRUMENTS: - case SINGING: - case STRINGED_INSTRUMENTS: - case WIND_INSTRUMENTS: - case PERCUSSION_INSTRUMENTS:{ - switch(class_){ - case BARD: case BARDGM:{ - r_value = ((level*5) + 5); - if (level < 5 && skillid == PERCUSSION_INSTRUMENTS){ - r_value = 0; - } - if (level < 8 && skillid == STRINGED_INSTRUMENTS){ - r_value = 0; - } - if (level < 11 && skillid == BRASS_INSTRUMENTS){ - r_value = 0; - } - if (level < 14 && skillid == WIND_INSTRUMENTS){ - r_value = 0; - } - if (r_value > 235) - r_value = 235; - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } -//////////////////////////////////////////////////////// - default: -#if EQDEBUG - std::cout<<"Unknown arcane skill: "< 252) - r_value = 252; - return r_value; -} - -uint16 Mob::MaxSkill_class(uint16 skillid, uint16 class_, uint16 level) const{ - uint16 r_value = 0; - switch(skillid) { - // Rogue - case APPLY_POISON: - case MAKE_POISON: - case PICK_POCKETS: - case BACKSTAB:{ - switch (class_) { - // Melee - case ROGUE: case ROGUEGM: { - r_value = ((level*5) + 5); - switch (skillid){ - case APPLY_POISON:{ - // 18 200 200 - if (level < 18) - r_value = 0; - if (r_value > 200) - r_value = 200; - break; - } - case MAKE_POISON:{ - // 20 200 250 - if (level < 20) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 250) - r_value = 250; - break; - } - case PICK_POCKETS:{ - // 7 200 210 - if (level < 7) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 210) - r_value = 210; - break; - } - case BACKSTAB:{ - // 10 200 225 - if (level < 10) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - default: - r_value = 0; - break; - } - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } - // Monk - case BLOCKSKILL: { - switch(class_){ - case BEASTLORD: case BEASTLORDGM:{ - r_value = (((level-25)*5) + 5); - // 12 200 230 - if (level < 25) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 230) - r_value = 230; - break; - } - case MONK: case MONKGM:{ - r_value = ((level*5) + 5); - // 12 200 230 - if (level < 12) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 230) - r_value = 230; - break; - } - } - break; - } - case FEIGN_DEATH: - case MEND: - case DRAGON_PUNCH: - case EAGLE_STRIKE: - case FLYING_KICK: - case ROUND_KICK: - case TIGER_CLAW:{ - switch(class_){ - case MONK: case MONKGM:{ - r_value = ((level*5) + 5); - switch (skillid){ - case MEND:{ - // 1 200 200 - if (r_value > 200) - r_value = 200; - break; - } - case ROUND_KICK:{ - // 5 200 225 - if (level < 5) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - case TIGER_CLAW:{ - - // 10 200 225 - if (level < 10) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - case FEIGN_DEATH:{ - // 17 200 200 - if (level < 17) - r_value = 0; - if (r_value > 200) - - r_value = 200; - break; - } - case EAGLE_STRIKE:{ - // 20 200 225 - if (level < 20) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - case DRAGON_PUNCH:{ - // 25 200 225 - if (level < 25) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - case FLYING_KICK:{ - // 30 200 225 - if (level < 30) - r_value = 0; - if (level < 51 && r_value > 200) - r_value = 200; - if (r_value > 225) - r_value = 225; - break; - } - default: - r_value = 0; - break; - } - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } - - //Berzerkers - case BERSERKING: { - switch(class_){ - case BERSERKER: case BERSERKERGM: { - r_value = ((level*5) + 5); - if(r_value > 200) - r_value = 200; - } - default: - r_value = 0; - break; - } - break; + }// Switch skill + if (r_value > 252) { + r_value = 252; } + return r_value; +} - // Shaman - case ALCHEMY:{ - switch(class_){ - case SHAMAN: case SHAMANGM:{ - // 25 130 180 - r_value = ((level*5) + 5); - if (level < 25) - r_value = 0; - if (level < 51 && r_value > 130) - r_value = 130; - if (r_value > 180) - r_value = 180; - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } +uint16 Mob::MaxSkill_defensive(uint16 skillid, uint16 class_, uint16 level) const +{ + uint16 r_value = 0; + switch (skillid) { + case DEFENSE: { + switch (class_) { + // Melee + case WARRIOR: + case WARRIORGM: { + // 210 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 210) { + r_value = 210; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + case ROGUE: + case ROGUEGM: { + // 200 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + case MONK: + case MONKGM: { + // 230 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 230) { + r_value = 230; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + case BERSERKER: + case BERSERKERGM: { + // 230 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 230) { + r_value = 230; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: { + // 200 200 4*level+4 + r_value = ((level * 4) + 4); + if (r_value > 200) { + r_value = 200; + } + break; + } + // Hybrid + case BEASTLORD: + case BEASTLORDGM: { + // 210 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 210) { + r_value = 210; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 210 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 210) { + r_value = 210; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + case BARD: + case BARDGM: { + // 200 252 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 51 ) { + if (r_value > 200) { + r_value = 200; + } + } + if (r_value > 252) { + r_value = 252; + } + break; + } + case RANGER: + case RANGERGM: { + // 200 200 5*level+5 + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + break; + } + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: { + // 145 145 level*4 + r_value = (level * 4); + if (r_value > 140) { + r_value = 140; + } + break; + } + default: + break; + } + break; + } + case PARRY: { + switch (class_) { + // Melee + case ROGUE: + case ROGUEGM: { + // 12 200 230 + r_value = ((level * 5) + 5); + if ( level < 12 ) { + r_value = 0; + } + if (r_value > 200 && level < 51 ) { + r_value = 200; + } + if (r_value > 230) { + r_value = 230; + } + break; + } + case WARRIOR: + case WARRIORGM: { + // 10 200 230 + r_value = ((level * 5) + 5); + if ( level < 10 ) { + r_value = 0; + } + if (r_value > 200 && level < 51 ) { + r_value = 200; + } + if (r_value > 230) { + r_value = 230; + } + break; + } + case BERSERKER: + case BERSERKERGM: { + r_value = ((level * 5) + 5); + if ( level < 10 ) { + r_value = 0; + } + if (r_value > 175) { + r_value = 175; + } + break; + } + // Hybrid + case BARD: + case BARDGM: { + // 53 0 75 + r_value = ((level * 5) + 5); + if ( level < 53 ) { + r_value = 0; + } + if (r_value > 75) { + r_value = 75; + } + break; + } + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 17 175 205 + r_value = ((level * 5) + 5); + if ( level < 17 ) { + r_value = 0; + } + if (r_value > 175 && level < 51 ) { + r_value = 175; + } + if (r_value > 205) { + r_value = 205; + } + break; + } + case RANGER: + case RANGERGM: { + // 18 185 220 + r_value = ((level * 5) + 5); + if ( level < 18 ) { + r_value = 0; + } + if (r_value > 185 && level < 51 ) { + r_value = 185; + } + if (r_value > 220) { + r_value = 220; + } + break; + } + // Pure + // No skill classes + // Melee + case MONK: + case MONKGM: + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + case BEASTLORD: + case BEASTLORDGM: + default: + r_value = 0; + break; + } + break; + } + case RIPOSTE: { + switch (class_) { + // Melee + case BERSERKER: + case BERSERKERGM: + case WARRIOR: + case WARRIORGM: { + // 25 200 225 + r_value = ((level * 5) + 5); + if ( level < 25 ) { + r_value = 0; + } + if (r_value > 200 && level < 51 ) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + case ROGUE: + case ROGUEGM: { + // 30 200 225 + r_value = ((level * 5) + 5); + if ( level < 30 ) { + r_value = 0; + } + if (r_value > 200 && level < 51 ) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + case MONK: + case MONKGM: { + // 35 200 225 + r_value = ((level * 5) + 5); + if ( level < 35 ) { + r_value = 0; + } + if (r_value > 200 && level < 51 ) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + // Hybrid + case BEASTLORD: + case BEASTLORDGM: { + // 40 150 185 + r_value = ((level * 5) + 5); + if ( level < 40 ) { + r_value = 0; + } + if (r_value > 150 && level < 51 ) { + r_value = 150; + } + if (r_value > 185) { + r_value = 185; + } + break; + } + case BARD: + case BARDGM: { + // 58 75 75 + r_value = ((level * 5) + 5); + if ( level < 58 ) { + r_value = 0; + } + if (r_value > 75) { + r_value = 75; + } + break; + } + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 30 175 200 + r_value = ((level * 5) + 5); + if ( level < 30 ) { + r_value = 0; + } + if (r_value > 175 && level < 51 ) { + r_value = 175; + } + if (r_value > 200) { + r_value = 200; + } + break; + } + case RANGER: + case RANGERGM: { + // 35 150 150 + r_value = ((level * 5) + 5); + if ( level < 35 ) { + r_value = 0; + } + if (r_value > 150) { + r_value = 150; + } + break; + } + // Pure + // No skill classes + // Melee + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + default: + r_value = 0; + break; + } + break; + } + case DODGE: { + switch (class_) { + // Melee + case BERSERKER: + case BERSERKERGM: + case WARRIOR: + case WARRIORGM: { + // 6 140 175 + r_value = ((level * 5) + 5); + if ( level < 6 ) { + r_value = 0; + } + if (r_value > 140 && level < 51 ) { + r_value = 140; + } + if (r_value > 175) { + r_value = 175; + } + break; + } + case ROGUE: + case ROGUEGM: { + // 4 150 210 + r_value = ((level * 5) + 5); + if ( level < 4 ) { + r_value = 0; + } + if (r_value > 150 && level < 51 ) { + r_value = 150; + } + if (r_value > 210) { + r_value = 210; + } + break; + } + case MONK: + case MONKGM: { + // 1 200 230 + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + if (r_value > 230) { + r_value = 230; + } + break; + } + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: { + // 15 75 75 4*level+4 + r_value = ((level * 4) + 4); + if ( level < 15 ) { + r_value = 0; + } + if (r_value > 75) { + r_value = 75; + } + break; + } + // Hybrid + case BEASTLORD: + case BEASTLORDGM: + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: + case BARD: + case BARDGM: { + // 10 125 155 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 10 ) { + r_value = 0; + } + if (r_value > 125 && level < 51 ) { + r_value = 125; + } + if (r_value > 155) { + r_value = 155; + } + break; + } + case RANGER: + case RANGERGM: { + // 8 137 170 5*level+5 + r_value = ((level * 5) + 5); + if ( level < 8 ) { + r_value = 0; + } + if (r_value > 137 && level < 51 ) { + r_value = 137; + } + if (r_value > 170) { + r_value = 170; + } + break; + } + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: { + // 22 75 75 3*level+3 + r_value = ((level * 3) + 3); + if ( level < 22 ) { + r_value = 0; + } + if (r_value > 75) { + r_value = 75; + } + break; + } + // No skill classes + // Melee + // Priest + // Pure + // Hybrid + default: + break; + } + break; + } + // Other + case TAUNT: { + switch (class_) { + // Melee + case WARRIOR: + case WARRIORGM: { + // 1 200 200 + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + break; + } + // Priest + // Hybrid + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 1 180 180 + r_value = ((level * 5) + 5); + if (r_value > 180) { + r_value = 180; + } + break; + } + case RANGER: + case RANGERGM: { + // 1 150 150 + r_value = ((level * 5) + 5); + if (r_value > 150) { + r_value = 150; + } + break; + } + // Pure + // No skill classes + // Melee + case ROGUE: + case ROGUEGM: + case MONK: + case MONKGM: + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + case BEASTLORD: + case BEASTLORDGM: + case BARD: + case BARDGM: + default: + break; + } + break; + } + case DISARM: { + switch (class_) { + // Melee + case WARRIOR: + case WARRIORGM: { + // 35 200 200 + r_value = ((level * 5) + 5); + if (level < 35) { + r_value = 0; + } + if (r_value > 200) { + r_value = 200; + } + break; + } + case ROGUE: + case ROGUEGM: + case MONK: + case MONKGM: { + // 27 200 200 + r_value = ((level * 5) + 5); + if (level < 27) { + r_value = 0; + } + if (r_value > 200) { + r_value = 200; + } + break; + } + case BERSERKER: + case BERSERKERGM: { + // 35 65 65 + r_value = ((level * 5) + 5); + if (level < 35) { + r_value = 0; + } + if (r_value > 65) { + r_value = 65; + } + break; + } + // Priest + // Hybrid + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 40 70 70 + r_value = ((level * 5) + 5); + if (level < 40) { + r_value = 0; + } + if (r_value > 70) { + r_value = 70; + } + break; + } + case RANGER: + case RANGERGM: { + // 35 55 55 + r_value = ((level * 5) + 5); + if (level < 35) { + r_value = 0; + } + if (r_value > 55) { + r_value = 55; + } + break; + } + // Pure + // No skill classes + // Melee + // Priest + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + case CLERIC: + case CLERICGM: + // Pure + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + // Hybrid + case BARD: + case BARDGM: + case BEASTLORD: + case BEASTLORDGM: + default: + break; + } + break; + } +//////////////////////////////////////////////////////// + default: + #if EQDEBUG + std::cout << "Unknown Defensive skill: " << skillid << std::endl; + #endif + break; + }// Switch skill + if (r_value > 252) { + r_value = 252; + } + return r_value; +} + +uint16 Mob::MaxSkill_arcane(uint16 skillid, uint16 class_, uint16 level) const +{ + uint16 r_value = 0; + switch (skillid) { + case MEDITATE: + case ABJURE: + case ALTERATION: + case CHANNELING: + case CONJURATION: + case DIVINATION: + case EVOCATION: { + r_value = ((level * 5) + 5); + switch (class_) { + // Hybrid + case RANGER: + case RANGERGM: { + // 9 235 235 + // Channel 9 200 215 + // Med 12 185 235 + if (level < 9) { + r_value = 0; + } + if (level < 12 && skillid == MEDITATE) { + r_value = 0; + } + if (r_value > 0 && skillid == CHANNELING) { + if ( level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 215) { + r_value = 215; + } + } + if (r_value > 0 && skillid == MEDITATE) { + if ( level < 51 && r_value > 185) { + r_value = 185; + } + if (r_value > 235) { + r_value = 235; + } + } + break; + } + case BEASTLORD: + case BEASTLORDGM: + case PALADIN: + case PALADINGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + // 9 235 235 + // Channel 9 200 220 + // Med 12 185 235 + if (level < 9) { + r_value = 0; + } + if (level < 12 && skillid == MEDITATE) { + r_value = 0; + } + if (r_value > 0 && skillid == CHANNELING) { + if ( level < 51 && r_value > 185) { + r_value = 185; + } + if (r_value > 220) { + r_value = 220; + } + } + if (r_value > 0 && skillid == MEDITATE) { + if ( level < 51 && r_value > 185) { + r_value = 185; + } + if (r_value > 235) { + r_value = 235; + } + } + break; + } + // Priest + case CLERIC: + case CLERICGM: + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: { + // 1 235 235 + // Channel 4 200 220 + // Med 8 235 252 + if (level < 4 && skillid == CHANNELING) { + r_value = 0; + } + if (level < 8 && skillid == MEDITATE) { + r_value = 0; + } + if (r_value > 0 && skillid == CHANNELING) { + if ( level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 220) { + r_value = 220; + } + } + if (r_value > 0 && skillid == MEDITATE) { + if ( level < 51 && r_value > 235) { + r_value = 235; + } + if (r_value > 252) { + r_value = 252; + } + } + break; + } + // Int caster + case ENCHANTER: + case ENCHANTERGM: + case MAGICIAN: + case MAGICIANGM: + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: { + // 1 235 235 + // Channel 1 200 220 + // Med 4 235 252 + if (level < 4 && skillid == MEDITATE) { + r_value = 0; + } + if (r_value > 0 && skillid == CHANNELING) { + if ( level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 220) { + r_value = 220; + } + } + if (r_value > 0 && skillid == MEDITATE) { + if ( level < 51 && r_value > 235) { + r_value = 235; + } + if (r_value > 252) { + r_value = 252; + } + } + break; + } + case BARD: + case BARDGM: { + r_value = 0; + if (level > 9 && skillid == MEDITATE) { + r_value = 1; + } + break; + } + default: + // Unknown class + r_value = 0; + break; + }// Class Switch + break; + } + case SPECIALIZE_ABJURE: + case SPECIALIZE_ALTERATION: + case SPECIALIZE_CONJURATION: + case SPECIALIZE_DIVINATION: + case SPECIALIZE_EVOCATION: { + r_value = ((level * 5) + 5); + switch (class_) { + // Non-int casters + case CLERIC: + case CLERICGM: + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: + if (level < 30) { + r_value = 0; + break; + } + // Int caster + case ENCHANTER: + case ENCHANTERGM: + case MAGICIAN: + case MAGICIANGM: + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: { + if (level < 20) { + r_value = 0; + break; + } + //make sure only 1 skill can be over 50 + uint16 hskill = 0; + uint16 high = 0; + uint16 cur; + cur = GetSkill(SPECIALIZE_ABJURE); + if (cur > high) { + hskill = SPECIALIZE_ABJURE; + high = cur; + } + cur = GetSkill(SPECIALIZE_ALTERATION); + if (cur > high) { + hskill = SPECIALIZE_ALTERATION; + high = cur; + } + cur = GetSkill(SPECIALIZE_CONJURATION); + if (cur > high) { + hskill = SPECIALIZE_CONJURATION; + high = cur; + } + cur = GetSkill(SPECIALIZE_DIVINATION); + if (cur > high) { + hskill = SPECIALIZE_DIVINATION; + high = cur; + } + cur = GetSkill(SPECIALIZE_EVOCATION); + if (cur > high) { + hskill = SPECIALIZE_EVOCATION; + high = cur; + } + if (high > 50 && hskill != skillid) { + r_value = 50; + break; + } + if (r_value > 200) { + r_value = 200; + } + break; + } + default: { + r_value = 0; + break; + } + }// Class Switch + break; + } + case RESEARCH: { + r_value = ((level * 5) + 5); + switch (class_) { + // Int caster + case ENCHANTER: + case ENCHANTERGM: + case MAGICIAN: + case MAGICIANGM: + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: { + // Res 16 200 200 + if (level < 16) { + r_value = 0; + } + if (r_value > 200) { + r_value = 200; + } + // FIXME Only let one SPEC go above what ever limit theres supposed to be + break; + } + default: { + r_value = 0; + break; + } + }// Class Switch + break; + } + case BRASS_INSTRUMENTS: + case SINGING: + case STRINGED_INSTRUMENTS: + case WIND_INSTRUMENTS: + case PERCUSSION_INSTRUMENTS: { + switch (class_) { + case BARD: + case BARDGM: { + r_value = ((level * 5) + 5); + if (level < 5 && skillid == PERCUSSION_INSTRUMENTS) { + r_value = 0; + } + if (level < 8 && skillid == STRINGED_INSTRUMENTS) { + r_value = 0; + } + if (level < 11 && skillid == BRASS_INSTRUMENTS) { + r_value = 0; + } + if (level < 14 && skillid == WIND_INSTRUMENTS) { + r_value = 0; + } + if (r_value > 235) { + r_value = 235; + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } +//////////////////////////////////////////////////////// + default: + #if EQDEBUG + std::cout << "Unknown arcane skill: " << skillid << std::endl; + #endif + break; + }// Switch skill + if (r_value > 252) { + r_value = 252; + } + return r_value; +} + +uint16 Mob::MaxSkill_class(uint16 skillid, uint16 class_, uint16 level) const +{ + uint16 r_value = 0; + switch (skillid) { + // Rogue + case APPLY_POISON: + case MAKE_POISON: + case PICK_POCKETS: + case BACKSTAB: { + switch (class_) { + // Melee + case ROGUE: + case ROGUEGM: { + r_value = ((level * 5) + 5); + switch (skillid) { + case APPLY_POISON: { + // 18 200 200 + if (level < 18) { + r_value = 0; + } + if (r_value > 200) { + r_value = 200; + } + break; + } + case MAKE_POISON: { + // 20 200 250 + if (level < 20) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 250) { + r_value = 250; + } + break; + } + case PICK_POCKETS: { + // 7 200 210 + if (level < 7) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 210) { + r_value = 210; + } + break; + } + case BACKSTAB: { + // 10 200 225 + if (level < 10) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + default: + r_value = 0; + break; + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } + // Monk + case BLOCKSKILL: { + switch (class_) { + case BEASTLORD: + case BEASTLORDGM: { + r_value = (((level - 25) * 5) + 5); + // 12 200 230 + if (level < 25) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 230) { + r_value = 230; + } + break; + } + case MONK: + case MONKGM: { + r_value = ((level * 5) + 5); + // 12 200 230 + if (level < 12) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 230) { + r_value = 230; + } + break; + } + } + break; + } + case FEIGN_DEATH: + case MEND: + case DRAGON_PUNCH: + case EAGLE_STRIKE: + case FLYING_KICK: + case ROUND_KICK: + case TIGER_CLAW: { + switch (class_) { + case MONK: + case MONKGM: { + r_value = ((level * 5) + 5); + switch (skillid) { + case MEND: { + // 1 200 200 + if (r_value > 200) { + r_value = 200; + } + break; + } + case ROUND_KICK: { + // 5 200 225 + if (level < 5) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + case TIGER_CLAW: { + // 10 200 225 + if (level < 10) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + case FEIGN_DEATH: { + // 17 200 200 + if (level < 17) { + r_value = 0; + } + if (r_value > 200) { + r_value = 200; + } + break; + } + case EAGLE_STRIKE: { + // 20 200 225 + if (level < 20) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + case DRAGON_PUNCH: { + // 25 200 225 + if (level < 25) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + case FLYING_KICK: { + // 30 200 225 + if (level < 30) { + r_value = 0; + } + if (level < 51 && r_value > 200) { + r_value = 200; + } + if (r_value > 225) { + r_value = 225; + } + break; + } + default: + r_value = 0; + break; + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } + //Berzerkers + case BERSERKING: { + switch (class_) { + case BERSERKER: + case BERSERKERGM: { + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + } + default: + r_value = 0; + break; + } + break; + } + // Shaman + case ALCHEMY: { + switch (class_) { + case SHAMAN: + case SHAMANGM: { + // 25 130 180 + r_value = ((level * 5) + 5); + if (level < 25) { + r_value = 0; + } + if (level < 51 && r_value > 130) { + r_value = 130; + } + if (r_value > 180) { + r_value = 180; + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } /////////////////////////////////////////// ////////////////////////////////////////// // Shared skill - // Shared Rogue - case HIDE:{ - switch(class_){ - // True class - case ROGUE: case ROGUEGM:{ - r_value = ((level*5) + 5); - if(r_value > 200) - r_value = 200; - break; - } - // Hybrids - case RANGER: case RANGERGM: - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ //75 cap - if(level >= 35) { - r_value = (((level-35)*5) + 5); - if(r_value > 75) - r_value = 75; - } - break; - } - case BARD: case BARDGM:{ //40 cap - if(level > 25) { - r_value = (((level-25)*5) + 5); - if(r_value > 40) - r_value = 40; - } - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } - - case SNEAK:{ - switch(class_){ - // True class - case ROGUE: case ROGUEGM:{ - r_value = ((level*5) + 5); - if(r_value > 200) - r_value = 200; - break; - } - // Hybrids - case MONK: case MONKGM:{ //113 cap - if(level >= 8) { - r_value = (((level-8)*5) + 5); - if(r_value > 113) - r_value = 113; - } - break; - } - case RANGER: case RANGERGM:{ //75 cap - if(level >= 10) { - r_value = (((level-10)*5) + 5); - if(r_value > 75) - r_value = 75; - } - break; - } - case BARD: case BARDGM:{ //75 cap - if(level >= 17) { - r_value = (((level-17)*5) + 5); - if(r_value > 75) - r_value = 75; - } - break; - } - case BEASTLORD: case BEASTLORDGM:{ //50 cap - if(level >= 50) { - r_value = (((level-50)*5) + 5); - if(r_value > 50) - r_value = 50; - } - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } - - case SENSE_TRAPS: - case PICK_LOCK: - case DISARM_TRAPS:{ - switch(class_){ - // True class - case ROGUE: case ROGUEGM:{ - r_value = ((level*5) + 5); - if(r_value > 200) - r_value = 200; - break; - } - // Hybrids - case BARD: case BARDGM:{ //100 cap - if(level >= 30) { //this is wrong I think... - r_value = (((level-30)*5) + 5); - if(r_value > 100) - r_value = 100; - } - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } - case SAFE_FALL:{ - switch(class_){ - // Hybrids - case BARD: case BARDGM:{ //40 cap - if(level >= 24) { - r_value = (((level-24)*5) + 5); - if(r_value > 40) - r_value = 40; - } - break; - } - // Melee - case MONK: case MONKGM:{ - if(level >= 3) { - r_value = (((level-3)*5) + 5); - if(r_value > 200) - r_value = 200; - } - break; - } - case ROGUE: case ROGUEGM:{ //100 cap - if(level >= 12) { - r_value = (((level-12)*5) + 5); - if(r_value > 100) - r_value = 100; - } - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } - case INTIMIDATION:{ - switch(class_){ - case BARD: case BARDGM:{ //100 cap - if(level >= 26) { - r_value = (((level-26)*5) + 5); - if(r_value > 100) - r_value = 100; - } - break; - } - // Melee - case MONK: case MONKGM:{ - if(level >= 18) { - r_value = (((level-18)*5) + 5); - if(r_value > 200) - r_value = 200; - } - break; - } - case BERSERKER: case BERSERKERGM:{ - if(level >= 20) { - r_value = (((level-20)*5) + 5); - if(r_value > 200) - r_value = 200; - } - break; - } - case ROGUE: case ROGUEGM:{ - if(level >= 22) { - r_value = (((level-22)*5) + 5); - if(r_value > 200) - r_value = 200; - } - break; - } - default: - r_value = 0; - break; - }// Class Switch - break; - } - // Druid/Ranger/Bard - case FORAGE:{ - switch(class_) { - case RANGER: case RANGERGM:{ - if(level > 3) { - r_value = (((level-3)*5) + 5); - if (r_value > 200) - r_value = 200; - } - break; - } - case DRUID: case DRUIDGM:{ - r_value = ((level*5) + 5); - if (r_value > 200) - r_value = 200; - break; - } - case MONK: case MONKGM: - case BARD: case BARDGM: - r_value = 55; - break; - default: - r_value = 50; - break; - }// Class Switch - break; - } - case TRACKING:{ - switch(class_){ - case RANGER: case RANGERGM: - case BARD: case BARDGM: - case DRUID: case DRUIDGM: - r_value=200; - break; - default: - r_value = 0; - break; - }// Class Switch - break; - } + // Shared Rogue + case HIDE: { + switch (class_) { + // True class + case ROGUE: + case ROGUEGM: { + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + break; + } + // Hybrids + case RANGER: + case RANGERGM: + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { //75 cap + if (level >= 35) { + r_value = (((level - 35) * 5) + 5); + if (r_value > 75) { + r_value = 75; + } + } + break; + } + case BARD: + case BARDGM: { //40 cap + if (level > 25) { + r_value = (((level - 25) * 5) + 5); + if (r_value > 40) { + r_value = 40; + } + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } + case SNEAK: { + switch (class_) { + // True class + case ROGUE: + case ROGUEGM: { + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + break; + } + // Hybrids + case MONK: + case MONKGM: { //113 cap + if (level >= 8) { + r_value = (((level - 8) * 5) + 5); + if (r_value > 113) { + r_value = 113; + } + } + break; + } + case RANGER: + case RANGERGM: { //75 cap + if (level >= 10) { + r_value = (((level - 10) * 5) + 5); + if (r_value > 75) { + r_value = 75; + } + } + break; + } + case BARD: + case BARDGM: { //75 cap + if (level >= 17) { + r_value = (((level - 17) * 5) + 5); + if (r_value > 75) { + r_value = 75; + } + } + break; + } + case BEASTLORD: + case BEASTLORDGM: { //50 cap + if (level >= 50) { + r_value = (((level - 50) * 5) + 5); + if (r_value > 50) { + r_value = 50; + } + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } + case SENSE_TRAPS: + case PICK_LOCK: + case DISARM_TRAPS: { + switch (class_) { + // True class + case ROGUE: + case ROGUEGM: { + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + break; + } + // Hybrids + case BARD: + case BARDGM: { //100 cap + if (level >= 30) { //this is wrong I think... + r_value = (((level - 30) * 5) + 5); + if (r_value > 100) { + r_value = 100; + } + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } + case SAFE_FALL: { + switch (class_) { + // Hybrids + case BARD: + case BARDGM: { //40 cap + if (level >= 24) { + r_value = (((level - 24) * 5) + 5); + if (r_value > 40) { + r_value = 40; + } + } + break; + } + // Melee + case MONK: + case MONKGM: { + if (level >= 3) { + r_value = (((level - 3) * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + } + break; + } + case ROGUE: + case ROGUEGM: { //100 cap + if (level >= 12) { + r_value = (((level - 12) * 5) + 5); + if (r_value > 100) { + r_value = 100; + } + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } + case INTIMIDATION: { + switch (class_) { + case BARD: + case BARDGM: { //100 cap + if (level >= 26) { + r_value = (((level - 26) * 5) + 5); + if (r_value > 100) { + r_value = 100; + } + } + break; + } + // Melee + case MONK: + case MONKGM: { + if (level >= 18) { + r_value = (((level - 18) * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + } + break; + } + case BERSERKER: + case BERSERKERGM: { + if (level >= 20) { + r_value = (((level - 20) * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + } + break; + } + case ROGUE: + case ROGUEGM: { + if (level >= 22) { + r_value = (((level - 22) * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + } + break; + } + default: + r_value = 0; + break; + }// Class Switch + break; + } + // Druid/Ranger/Bard + case FORAGE: { + switch (class_) { + case RANGER: + case RANGERGM: { + if (level > 3) { + r_value = (((level - 3) * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + } + break; + } + case DRUID: + case DRUIDGM: { + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + break; + } + case MONK: + case MONKGM: + case BARD: + case BARDGM: + r_value = 55; + break; + default: + r_value = 50; + break; + }// Class Switch + break; + } + case TRACKING: { + switch (class_) { + case RANGER: + case RANGERGM: + case BARD: + case BARDGM: + case DRUID: + case DRUIDGM: + r_value = 200; + break; + default: + r_value = 0; + break; + }// Class Switch + break; + } //////////////////////////////////////////////////////// - default: -#if EQDEBUG - std::cout<<"Unknown class skill: "< 252) - r_value = 252; - return r_value; + default: + #if EQDEBUG + std::cout << "Unknown class skill: " << skillid << std::endl; + #endif + break; + }// Switch skill + if (r_value > 252) { + r_value = 252; + } + return r_value; } -uint16 Mob::MaxSkill(uint16 skillid, uint16 class_, uint16 level) const { - uint16 r_value = 0; - switch (skillid) { - case _1H_BLUNT: - case _2H_BLUNT: - case PIERCING: - case HAND_TO_HAND: - case _1H_SLASHING: - case _2H_SLASHING:{ - r_value = MaxSkill_weapon(skillid, class_, level); - break; - } - case OFFENSE: - case THROWING: - case ARCHERY: - case DOUBLE_ATTACK: - case DUAL_WIELD: - case KICK: - case BASH:{ - r_value = MaxSkill_offensive(skillid, class_, level); - break; - } - case DEFENSE: - case PARRY: - case RIPOSTE: - case DODGE: - case TAUNT: - case DISARM:{ - r_value = MaxSkill_defensive(skillid,class_,level); - break; - } - case MEDITATE: - case ABJURE: - case ALTERATION: - case CHANNELING: - case CONJURATION: - case DIVINATION: - case EVOCATION: - case SPECIALIZE_ABJURE: - case SPECIALIZE_ALTERATION: - case SPECIALIZE_CONJURATION: - case SPECIALIZE_DIVINATION: - case SPECIALIZE_EVOCATION: - case RESEARCH: - case BRASS_INSTRUMENTS: - case SINGING: - case STRINGED_INSTRUMENTS: - case WIND_INSTRUMENTS: - case PERCUSSION_INSTRUMENTS:{ - r_value = MaxSkill_arcane(skillid,class_,level); - break; - } +uint16 Mob::MaxSkill(uint16 skillid, uint16 class_, uint16 level) const +{ + uint16 r_value = 0; + switch (skillid) { + case _1H_BLUNT: + case _2H_BLUNT: + case PIERCING: + case HAND_TO_HAND: + case _1H_SLASHING: + case _2H_SLASHING: { + r_value = MaxSkill_weapon(skillid, class_, level); + break; + } + case OFFENSE: + case THROWING: + case ARCHERY: + case DOUBLE_ATTACK: + case DUAL_WIELD: + case KICK: + case BASH: { + r_value = MaxSkill_offensive(skillid, class_, level); + break; + } + case DEFENSE: + case PARRY: + case RIPOSTE: + case DODGE: + case TAUNT: + case DISARM: { + r_value = MaxSkill_defensive(skillid, class_, level); + break; + } + case MEDITATE: + case ABJURE: + case ALTERATION: + case CHANNELING: + case CONJURATION: + case DIVINATION: + case EVOCATION: + case SPECIALIZE_ABJURE: + case SPECIALIZE_ALTERATION: + case SPECIALIZE_CONJURATION: + case SPECIALIZE_DIVINATION: + case SPECIALIZE_EVOCATION: + case RESEARCH: + case BRASS_INSTRUMENTS: + case SINGING: + case STRINGED_INSTRUMENTS: + case WIND_INSTRUMENTS: + case PERCUSSION_INSTRUMENTS: { + r_value = MaxSkill_arcane(skillid, class_, level); + break; + } /////////////////////////////////////////// /////////////////////////////////////////// // Class skills - // Rogue - case APPLY_POISON: - case MAKE_POISON: - case PICK_POCKETS: - case BACKSTAB: - // Monk - case FEIGN_DEATH: - case MEND: - case DRAGON_PUNCH: - case EAGLE_STRIKE: - case FLYING_KICK: - case ROUND_KICK: - case TIGER_CLAW: - case BLOCKSKILL: - case ALCHEMY: - case HIDE: - case SNEAK: - case SENSE_TRAPS: - case PICK_LOCK: - case DISARM_TRAPS: - case SAFE_FALL: - case INTIMIDATION: - // Druid/Ranger/Bard - case FORAGE: - case TRACKING:{ - r_value = MaxSkill_class(skillid,class_,level); - break; - } + // Rogue + case APPLY_POISON: + case MAKE_POISON: + case PICK_POCKETS: + case BACKSTAB: + // Monk + case FEIGN_DEATH: + case MEND: + case DRAGON_PUNCH: + case EAGLE_STRIKE: + case FLYING_KICK: + case ROUND_KICK: + case TIGER_CLAW: + case BLOCKSKILL: + case ALCHEMY: + case HIDE: + case SNEAK: + case SENSE_TRAPS: + case PICK_LOCK: + case DISARM_TRAPS: + case SAFE_FALL: + case INTIMIDATION: + // Druid/Ranger/Bard + case FORAGE: + case TRACKING: { + r_value = MaxSkill_class(skillid, class_, level); + break; + } /////////////////////////////////////////// /////////////////////////////////////////// // Tradeskills - case BAKING: - case TAILORING: - case BLACKSMITHING: - case FLETCHING: - case BREWING: - case JEWELRY_MAKING: - case POTTERY: - case FISHING:{ - // Check for Any Trade above 200, check for X (aa skill) Trades above 200 - r_value = 250; - break; - } + case BAKING: + case TAILORING: + case BLACKSMITHING: + case FLETCHING: + case BREWING: + case JEWELRY_MAKING: + case POTTERY: + case FISHING: { + // Check for Any Trade above 200, check for X (aa skill) Trades above 200 + r_value = 250; + break; + } ///////////////////////////////////// ///////////////////////////////////// - // Gnome - case TINKERING:{ - if ( race == GNOME && level > 24 ) { - r_value = ((level*5)+5); - break; - } - r_value = 0; - break; - } - + // Gnome + case TINKERING: { + if ( race == GNOME && level > 24 ) { + r_value = ((level * 5) + 5); + break; + } + r_value = 0; + break; + } ///////////////////////////////////////// // Common ///////////////////////////////////////// - case BIND_WOUND:{ - switch(class_){ - case BARD: case BARDGM:{ - r_value = ((level*5)+5); - if(level >= 50) { - if(r_value > 210) - r_value = 210; - } else { - if(r_value > 200) - r_value = 200; - } - break; - } - case CLERIC: case CLERICGM:{ - r_value = ((level*5)+5); - if(level >= 50) { - if(r_value > 201) - r_value = 201; - } else { - if(r_value > 200) - r_value = 200; - } - break; - } - - case DRUID: case DRUIDGM: - case SHAMAN: case SHAMANGM:{ - r_value = ((level*5) + 5); - if(r_value > 200) - r_value = 200; - break; - } - case MAGICIAN: case MAGICIANGM: - case ENCHANTER: case ENCHANTERGM: - case NECROMANCER: case NECROMANCERGM: - case WIZARD: case WIZARDGM:{ - r_value = ((level*5) + 5); - if(r_value > 100) - r_value = 100; - break; - } - case BEASTLORD: case BEASTLORDGM: - case BERSERKER: case BERSERKERGM: - case MONK: case MONKGM: { - r_value = ((level*5)+5); - if(level >= 50) { - if(r_value > 210) - r_value = 210; - } else { - if(r_value > 200) - r_value = 200; - } - break; - } - case PALADIN: case PALADINGM: { - if (level > 10) { - r_value = (((level-10)*5)+5); - if(level >= 50) { - if(r_value > 210) - r_value = 210; - } else { - if(r_value > 200) + case BIND_WOUND: { + switch (class_) { + case BARD: + case BARDGM: { + r_value = ((level * 5) + 5); + if (level >= 50) { + if (r_value > 210) { + r_value = 210; + } + } else { + if (r_value > 200) { + r_value = 200; + } + } + break; + } + case CLERIC: + case CLERICGM: { + r_value = ((level * 5) + 5); + if (level >= 50) { + if (r_value > 201) { + r_value = 201; + } + } else { + if (r_value > 200) { + r_value = 200; + } + } + break; + } + case DRUID: + case DRUIDGM: + case SHAMAN: + case SHAMANGM: { + r_value = ((level * 5) + 5); + if (r_value > 200) { + r_value = 200; + } + break; + } + case MAGICIAN: + case MAGICIANGM: + case ENCHANTER: + case ENCHANTERGM: + case NECROMANCER: + case NECROMANCERGM: + case WIZARD: + case WIZARDGM: { + r_value = ((level * 5) + 5); + if (r_value > 100) { + r_value = 100; + } + break; + } + case BEASTLORD: + case BEASTLORDGM: + case BERSERKER: + case BERSERKERGM: + case MONK: + case MONKGM: { + r_value = ((level * 5) + 5); + if (level >= 50) { + if (r_value > 210) { + r_value = 210; + } + } else { + if (r_value > 200) { + r_value = 200; + } + } + break; + } + case PALADIN: + case PALADINGM: { + if (level > 10) { + r_value = (((level - 10) * 5) + 5); + if (level >= 50) { + if (r_value > 210) { + r_value = 210; + } + } else { + if (r_value > 200) { + r_value = 200; + } + } + } + break; + } + case RANGER: + case RANGERGM: { + if (level > 15) { + r_value = (((level - 15) * 5) + 5); + if (level >= 50) { + if (r_value > 200) { + r_value = 200; + } + } else { + if (r_value > 150) { + r_value = 150; + } + } + } + break; + } + case ROGUE: + case ROGUEGM: { + r_value = ((level * 5) + 5); + if (level >= 50) { + if (r_value > 210) { + r_value = 210; + } + } else { + if (r_value > 176) { + r_value = 176; + } + } + break; + } + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { + r_value = ((level * 5) + 5); + if (level >= 50) { + if (r_value > 200) { + r_value = 200; + } + } else { + if (r_value > 150) { + r_value = 150; + } + } + break; + } + case WARRIOR: + case WARRIORGM: { + if (level > 5) { + r_value = (((level - 5) * 5) + 5); + if (level >= 50) { + if (r_value > 210) { + r_value = 210; + } + } else { + if (r_value > 175) { + r_value = 175; + } + } + } + break; + } + default: + r_value = 0; + break; + } + break; + } + case SENSE_HEADING: + case SWIMMING: + case ALCOHOL_TOLERANCE: + case BEGGING: { + r_value = 5 + (level * 5); + if (r_value > 200) { r_value = 200; + } + break; } - } - break; - } - case RANGER: case RANGERGM: { - if (level > 15) { - r_value = (((level-15)*5)+5); - if(level >= 50) { - if(r_value > 200) - r_value = 200; - } else { - if(r_value > 150) - r_value = 150; + //case BERSERKING: + default: { + // Unknown skill we should like print something to a log/debug here + r_value = 0; + break; } - } - break; - } - - case ROGUE: case ROGUEGM: { - r_value = ((level*5)+5); - if(level >= 50) { - if(r_value > 210) - r_value = 210; - } else { - if(r_value > 176) - r_value = 176; - } - break; - } - case SHADOWKNIGHT: case SHADOWKNIGHTGM: { - r_value = ((level*5)+5); - if(level >= 50) { - if(r_value > 200) - r_value = 200; - } else { - if(r_value > 150) - r_value = 150; - } - break; - } - case WARRIOR: case WARRIORGM: { - if (level > 5) { - r_value = (((level-5)*5)+5); - if(level >= 50) { - if(r_value > 210) - r_value = 210; - } else { - if(r_value > 175) - r_value = 175; - } - } - break; - } - - default: r_value = 0; - break; - } - break; } - case SENSE_HEADING: - case SWIMMING: - case ALCOHOL_TOLERANCE: - case BEGGING:{ - r_value = 5 + (level*5); - if (r_value > 200) - r_value = 200; - break; - } - //case BERSERKING: - default: { - - // Unknown skill we should like print something to a log/debug here - r_value = 0; - break; - } - - } - if (r_value >= 253) - r_value = 252; - return r_value; + if (r_value >= 253) { + r_value = 252; + } + return r_value; } diff --git a/zone/mob.h b/zone/mob.h index b994f519b..f9ef4ec9c 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -924,6 +924,16 @@ public: void mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc); bool mod_will_aggro(Mob *attacker, Mob *on); + //Command #Tune functions + int32 Tune_MeleeMitigation(Mob* GM, Mob *attacker, int32 damage, int32 minhit, ExtraAttackOptions *opts = nullptr, int Msg =0, int ac_override=0, int atk_override=0, int add_ac=0, int add_atk = 0); + virtual int32 Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); + uint32 Tune_GetMeanDamage(Mob* GM, Mob *attacker, int32 damage, int32 minhit, ExtraAttackOptions *opts = nullptr, int Msg = 0,int ac_override=0, int atk_override=0, int add_ac=0, int add_atk = 0); + void Tune_FindATKByPctMitigation(Mob* defender, Mob *attacker, float pct_mitigation, int interval = 50, int max_loop = 100, int ac_override=0,int Msg =0); + void Tune_FindACByPctMitigation(Mob* defender, Mob *attacker, float pct_mitigation, int interval = 50, int max_loop = 100, int atk_override=0,int Msg =0); + float Tune_CheckHitChance(Mob* defender, Mob* attacker, SkillUseTypes skillinuse, int Hand, int16 chance_mod, int Msg = 1,int acc_override=0, int avoid_override=0, int add_acc=0, int add_avoid = 0); + void Tune_FindAccuaryByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int avoid_override, int Msg = 0); + void Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int acc_override, int Msg = 0); + protected: void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic); static uint16 GetProcID(uint16 spell_id, uint8 effect_index); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 65f318c46..a4621e432 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3472,14 +3472,16 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste { effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster, ticsremaining); //Handle client cast DOTs here. - if (caster && effect_value < 0 && IsDetrimentalSpell(spell_id)){ + if (caster && effect_value < 0){ - if (caster->IsClient()){ - if (!caster->CastToClient()->GetFeigned()) + if (IsDetrimentalSpell(spell_id)){ + if (caster->IsClient()){ + if (!caster->CastToClient()->GetFeigned()) + AddToHateList(caster, -effect_value); + } + else if (!IsClient()) //Allow NPC's to generate hate if casted on other NPC's. AddToHateList(caster, -effect_value); } - else if (!IsClient()) //Allow NPC's to generate hate if casted on other NPC's. - AddToHateList(caster, -effect_value); effect_value = caster->GetActDoTDamage(spell_id, effect_value, this); @@ -6569,33 +6571,32 @@ bool Mob::TrySpellProjectile(Mob* spell_target, uint16 spell_id, float speed){ DoAnim(anim, 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells); //Override the default projectile animation. return true; -} +} -void Mob::ResourceTap(int32 damage, uint16 spellid){ +void Mob::ResourceTap(int32 damage, uint16 spellid) +{ //'this' = caster if (!IsValidSpell(spellid)) return; - for (int i = 0; i <= EFFECT_COUNT; i++) - { - if (spells[spellid].effectid[i] == SE_ResourceTap){ - - damage += (damage * spells[spellid].base[i])/100; + for (int i = 0; i < EFFECT_COUNT; i++) { + if (spells[spellid].effectid[i] == SE_ResourceTap) { + damage += (damage * spells[spellid].base[i]) / 100; if (spells[spellid].max[i] && (damage > spells[spellid].max[i])) damage = spells[spellid].max[i]; - if (spells[spellid].base2[i] == 0){ //HP Tap + if (spells[spellid].base2[i] == 0) { // HP Tap if (damage > 0) HealDamage(damage); else - Damage(this, -damage,0, SkillEvocation,false); + Damage(this, -damage, 0, SkillEvocation, false); } - if (spells[spellid].base2[i] == 1) //Mana Tap + if (spells[spellid].base2[i] == 1) // Mana Tap SetMana(GetMana() + damage); - if (spells[spellid].base2[i] == 2 && IsClient()) //Endurance Tap + if (spells[spellid].base2[i] == 2 && IsClient()) // Endurance Tap CastToClient()->SetEndurance(CastToClient()->GetEndurance() + damage); } } diff --git a/zone/tasks.cpp b/zone/tasks.cpp index cb8e34696..01a44e652 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -2741,7 +2741,7 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN + sizeof(TaskDescriptionData1_Struct) + strlen(Tasks[TaskID]->Description) + 1 + sizeof(TaskDescriptionData2_Struct) + 1 + sizeof(TaskDescriptionTrailer_Struct); - std::string RewardText; + std::string reward_text; 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 @@ -2769,17 +2769,17 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN linker.SetProxyText(Tasks[TaskID]->Reward); auto reward_link = linker.GenerateLink(); - RewardText += reward_link.c_str(); + reward_text.append(reward_link); } else { - RewardText += Tasks[TaskID]->Reward; + reward_text.append(Tasks[TaskID]->Reward); } } else { - RewardText += Tasks[TaskID]->Reward; + reward_text.append(Tasks[TaskID]->Reward); } - PacketLength += strlen(RewardText.c_str()) + 1; + PacketLength += reward_text.length() + 1; char *Ptr; TaskDescriptionHeader_Struct* tdh; @@ -2835,7 +2835,7 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN tdd2->unknown3 = 0x0000; Ptr = (char *) tdd2 + sizeof(TaskDescriptionData2_Struct); - sprintf(Ptr, "%s", RewardText.c_str()); + sprintf(Ptr, "%s", reward_text.c_str()); Ptr = Ptr + strlen(Ptr) + 1; tdt = (TaskDescriptionTrailer_Struct*)Ptr; diff --git a/zone/tune.cpp b/zone/tune.cpp new file mode 100644 index 000000000..2f071e458 --- /dev/null +++ b/zone/tune.cpp @@ -0,0 +1,1089 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2002 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if EQDEBUG >= 5 +//#define TUNE_DEBUG 20 +#endif + +#include "../common/debug.h" +#include "../common/eq_constants.h" +#include "../common/eq_packet_structs.h" +#include "../common/rulesys.h" +#include "../common/skills.h" +#include "../common/spdat.h" +#include "../common/string_util.h" +#include "queryserv.h" +#include "quest_parser_collection.h" +#include "string_ids.h" +#include "water_map.h" +#include "worldserver.h" +#include "zone.h" + +#include +#include +#include + +#ifdef BOTS +#include "bot.h" +#endif + +extern QueryServ* QServ; +extern WorldServer worldserver; + +#ifdef _WINDOWS +#define snprintf _snprintf +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#endif + +extern EntityList entity_list; +extern Zone* zone; + +void Mob::Tune_FindATKByPctMitigation(Mob* defender,Mob *attacker, float pct_mitigation, int interval, int max_loop, int ac_override, int Msg) +{ + /*Find the amount of 'ATTACK' stat that has to be added/subtracted FROM ATTACKER to reach a specific average mitigation value on the TARGET. + Can use ac_override to find the value verse a hypothetical amount of worn AC */ + + int atk = 0; + uint32 total_damage = 0; + int32 damage = 0; + uint32 minhit = 0; + int mean_dmg = 0; + float tmp_pct_mitigated = 0.0f; + int end = 0; + + if (attacker->IsNPC()) + { + damage = static_cast(attacker->CastToNPC()->GetMaxDMG()); + minhit = attacker->CastToNPC()->GetMinDMG(); + } + else if (attacker->IsClient()) + { + damage = static_cast(attacker->CastToClient()->GetMeleeDamage(this)); + minhit = attacker->CastToClient()->GetMeleeDamage(this, true); + } + + if (damage == 0 || minhit == 0) + { + Message(0, "#Tune - Processing... Abort! Damage not found! [MaxDMG %i MinDMG %i]", damage,minhit); + return; + } + + mean_dmg = defender->Tune_GetMeanDamage(this, attacker, damage, minhit, nullptr, 0, ac_override, 0, 0,atk); + tmp_pct_mitigated = 100.0f - static_cast( mean_dmg * 100 /damage); + + Message(0, "#Tune - Begin Parse [Interval %i Max Loop Iterations %i]", interval, max_loop); + Message(0, "#Tune - Processing... Find ATK for attacker Mitigation (%.0f) pct on defender [MaxDMG %i MinDMG %i Current Mitigation %.2f]", pct_mitigation, damage, minhit,tmp_pct_mitigated); + + if (tmp_pct_mitigated < pct_mitigation) + interval = interval * -1; + + for (int j=0; j < max_loop; j++) + { + mean_dmg = defender->Tune_GetMeanDamage(this, attacker, damage, minhit, nullptr, 0, ac_override,0, 0,atk); + tmp_pct_mitigated = 100.0f - ( static_cast(mean_dmg) * 100.0f /static_cast(damage)); + + if (Msg >= 3) + Message(0, "#Tune - Processing... [%i] [ATK %i] Average Melee Hit %i | Pct Mitigated %.2f ",j,atk, mean_dmg, tmp_pct_mitigated); + + if (interval > 0 && tmp_pct_mitigated <= pct_mitigation) + end = 1; + + else if (interval < 0 && tmp_pct_mitigated >= pct_mitigation) + end = 1; + + else if (interval < 0 && mean_dmg == minhit) + end = 2; + + if (end >= 1){ + + defender->Tune_MeleeMitigation(this, attacker, damage, minhit, nullptr,Msg,ac_override, 0, 0, atk); + + if (end == 2) + Message(0, "#Tune - [WARNING] Mitigation can not be further decreased due to minium hit value (%i).",minhit); + + if (attacker->IsNPC()){ + Message(0, "#Tune - Recommended NPC ATK ADJUSTMENT ( %i ) on ' %s ' average mitigation of (%.0f) pct verse ' %s '. ",atk, attacker->GetCleanName(), pct_mitigation, defender->GetCleanName()); + Message(0, "#SET: [NPC Attack STAT] = [%i]",atk + defender->CastToNPC()->ATK); + } + if (attacker->IsClient()){ + Message(0, "#Tune - Recommended CLIENT ATK ADJUSTMENT ( %i ) on ' %s ' average mitigation of (%.0f) pct verse ' %s '. ", atk, attacker->GetCleanName(), pct_mitigation, defender->GetCleanName()); + Message(0, "#Modify (+/-): [Client Attack STAT/SE_ATK(2)] [%i]",atk); + } + + return; + } + + atk = atk + interval; + } + + Message(0, "#Tune - Error: Unable to find desired result for (%.0f) pct - Increase interval (%i) AND/OR max loop value (%i) and run again.", pct_mitigation, interval, max_loop); + Message(0, "#Tune - Parse ended at ATK ADJUSTMENT ( %i ) average target mitigation of (%.0f) pct.",atk,tmp_pct_mitigated); +} + +void Mob::Tune_FindACByPctMitigation(Mob* defender, Mob *attacker, float pct_mitigation, int interval, int max_loop, int atk_override, int Msg) +{ + + /*Find the amount of AC stat that has to be added/subtracted from TARGET to reach a specific average mitigation value based on ATTACKER's statistics. + Can use ac_override to find the value verse a hypothetical amount of worn AC */ + + int add_ac = 0; + uint32 total_damage = 0; + int32 damage = 0; + uint32 minhit = 0; + int mean_dmg = 0; + float tmp_pct_mitigated = 0.0f; + int end = 0; + + + if (attacker->IsNPC()) + { + damage = static_cast(attacker->CastToNPC()->GetMaxDMG()); + minhit = attacker->CastToNPC()->GetMinDMG(); + } + else if (attacker->IsClient()) + { + damage = static_cast(attacker->CastToClient()->GetMeleeDamage(this)); + minhit = attacker->CastToClient()->GetMeleeDamage(this, true); + } + + if (damage == 0 || minhit == 0) + { + Message(0, "#Tune - Processing... Abort! Damage not found! [MaxDMG %i MinDMG %i]", damage,minhit); + return; + } + + mean_dmg = defender->Tune_GetMeanDamage(this, attacker, damage, minhit, nullptr, 0, 0, atk_override); + tmp_pct_mitigated = 100.0f - static_cast( mean_dmg * 100 /damage); + + Message(0, "#Tune - Begin Parse [Interval %i Max Loop Iterations %i]", interval, max_loop); + Message(0, "#Tune - Processing... Find AC for defender Mitigation (%.0f) pct from attacker [MaxDMG %i MinDMG %i Current Mitigation %.2f]", pct_mitigation, damage, minhit,tmp_pct_mitigated); + + + if (tmp_pct_mitigated > pct_mitigation) + interval = interval * -1; + + for (int j=0; j < max_loop; j++) + { + mean_dmg = defender->Tune_GetMeanDamage(this, attacker, damage, minhit, nullptr, 0, 0,atk_override, add_ac, 0); + tmp_pct_mitigated = 100.0f - ( static_cast(mean_dmg) * 100.0f /static_cast(damage)); + + if (Msg >= 3) + Message(0, "#Tune - Processing... [%i] [AC %i] Average Melee Hit %i | Pct Mitigated %.2f ",j,add_ac, mean_dmg, tmp_pct_mitigated); + + if (interval > 0 && tmp_pct_mitigated >= pct_mitigation) + end = 1; + + else if (interval < 0 && tmp_pct_mitigated <= pct_mitigation) + end = 1; + + else if (interval < 0 && mean_dmg == minhit) + end = 2; + + if (end >= 1){ + + defender->Tune_MeleeMitigation(this, attacker, damage, minhit, nullptr,Msg,0,atk_override, add_ac, 0); + + if (end == 2) + Message(0, "#Tune - [WARNING] Mitigation can not be further decreased due to minium hit value (%i).",minhit); + + if (defender->IsNPC()){ + Message(7, "#Tune - Recommended NPC AC ADJUSTMENT ( %i ) on ' %s ' for an average mitigation of (+ %.0f) pct from attacker ' %s '.",add_ac,defender->GetCleanName(), pct_mitigation, attacker->GetCleanName()); + Message(0, "#SET: [NPC Attack STAT] = [%i]",add_ac + defender->CastToNPC()->GetRawAC()); + } + if (defender->IsClient()){ + Message(7, "#Tune - Recommended CLIENT AC ADJUSTMENT ( %i ) on ' %s ' for an average mitigation of (+ %.0f) pct from attacker ' %s '.",add_ac,defender->GetCleanName(), pct_mitigation, attacker->GetCleanName()); + Message(0, "#Modify (+/-): [Client AC STAT/SE_AC(1)] [%i]",add_ac); + } + + return; + } + + + + add_ac = add_ac + interval; + } + + Message(0, "#Tune - Error: Unable to find desired result for (%.0f) pct - Increase interval (%i) AND/OR max loop value (%i) and run again.", pct_mitigation, interval, max_loop); + Message(0, "#Tune - Parse ended at AC ADJUSTMENT ( %i ) at average mitigation of (%.0f) / (%.0f) pct.",add_ac,tmp_pct_mitigated / pct_mitigation); +} + +uint32 Mob::Tune_GetMeanDamage(Mob* GM, Mob *attacker, int32 damage, int32 minhit, ExtraAttackOptions *opts, int Msg, + int ac_override, int atk_override, int add_ac, int add_atk) +{ + uint32 total_damage = 0; + int loop_max = 1000; + + for (int i=0; i < loop_max ; i++) + { + total_damage += Tune_MeleeMitigation(GM, attacker, damage, minhit, nullptr,0,ac_override, atk_override, add_ac, add_atk); + } + + return(total_damage/loop_max); +} + +int32 Mob::Tune_MeleeMitigation(Mob* GM, Mob *attacker, int32 damage, int32 minhit, ExtraAttackOptions *opts, int Msg, + int ac_override, int atk_override, int add_ac, int add_atk) +{ + if (damage <= 0) + return 0; + + Mob* defender = this; + float aa_mit = (aabonuses.CombatStability + itembonuses.CombatStability + + spellbonuses.CombatStability) / 100.0f; + + if (Msg){ + + GM->Message(0, "######### Melee Mitigation Report: Start [Detail Level %i]#########", Msg); + GM->Message(0, "#ATTACKER: %s", attacker->GetCleanName()); + GM->Message(0, "#DEFENDER: %s", defender->GetCleanName()); + } + + if (RuleB(Combat, UseIntervalAC)) { + float softcap = (GetSkill(SkillDefense) + GetLevel()) * + RuleR(Combat, SoftcapFactor) * (1.0 + aa_mit); + float mitigation_rating = 0.0; + float attack_rating = 0.0; + int shield_ac = 0; + int armor = 0; + float weight = 0.0; + + if (Msg >= 2){ + GM->Message(0, " "); + GM->Message(0, "### Calculate Mitigation Rating ###"); + if (aabonuses.CombatStability) + GM->Message(0, "# %i #### DEFENDER SE_CombatStability(259) AA Bonus", aabonuses.CombatStability); + if (spellbonuses.CombatStability) + GM->Message(0, "# %i #### DEFENDER SE_CombatStability(259) Spell Bonus", spellbonuses.CombatStability); + if (itembonuses.CombatStability) + GM->Message(0, "# %i #### DEFENDER SE_CombatStability(259) Worn Bonus", itembonuses.CombatStability); + + GM->Message(0, "# %.2f #### DEFENDER Base Soft Cap", softcap); + } + + float monkweight = RuleI(Combat, MonkACBonusWeight); + monkweight = mod_monk_weight(monkweight, attacker); + + if (IsClient()) { + armor = CastToClient()->GetRawACNoShield(shield_ac) + add_ac; + weight = (CastToClient()->CalcCurrentWeight() / 10.0); + + if (ac_override) + armor = ac_override; + + if (Msg >=2 ){ + GM->Message(0, "# %i #### DEFENDER AC Equiped/Worn Bonus", itembonuses.AC); + GM->Message(0, "# %i #### DEFENDER SE_ArmorClass(1) AA Bonus", aabonuses.AC); + GM->Message(0, "# %i #### DEFENDER SE_ArmorClass(1) Spell Bonus", spellbonuses.AC); + GM->Message(0, "# %i #### DEFENDER Shield AC", shield_ac); + GM->Message(0, "# %i #### DEFENDER Total Client Armor - NO shield", armor); + } + + } else if (IsNPC()) { + armor = CastToNPC()->GetRawAC() + add_ac; + + if (ac_override) + armor = ac_override; + + if (Msg >=2 ){ + GM->Message(0, "# %i #### DEFENDER AC Equiped/Worn Bonus", itembonuses.AC); + GM->Message(0, "# %i #### DEFENDER SE_ArmorClass(1) Spell Bonus", spellbonuses.AC); + GM->Message(0, "# %i #### DEFENDER NPC AC Stat", CastToNPC()->GetRawAC()); + } + + int PetACBonus = 0; + + if (!IsPet()){ + armor = (armor / RuleR(Combat, NPCACFactor)); + if (Msg >=2 ) + GM->Message(0, "# %i #### DEFENDER NPC Armor after RuleR(Combat, NPCACFactor) %.2f", armor, RuleR(Combat, NPCACFactor)); + } + + Mob *owner = nullptr; + if (IsPet()) + owner = GetOwner(); + else if ((CastToNPC()->GetSwarmOwner())) + owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner()); + + if (owner){ + PetACBonus = owner->aabonuses.PetMeleeMitigation + owner->itembonuses.PetMeleeMitigation + owner->spellbonuses.PetMeleeMitigation; + + if (Msg >=2 ){ + if (owner->aabonuses.PetMeleeMitigation) + GM->Message(0, "# %i #### DEFENDER Pet Owner SE_PetMeleeMitigation(379) AA Bonus", owner->aabonuses.PetMeleeMitigation); + if (owner->spellbonuses.PetMeleeMitigation) + GM->Message(0, "# %i #### DEFENDER Pet Owner SE_PetMeleeMitigation(379) Spell Bonus",owner->spellbonuses.PetMeleeMitigation); + if (owner->itembonuses.PetMeleeMitigation) + GM->Message(0, "# %i #### DEFENDER Pet Owner SE_PetMeleeMitigation(379) Worn Bonus", owner->itembonuses.PetMeleeMitigation); + } + } + + armor += spellbonuses.AC + itembonuses.AC + PetACBonus + 1; + + if (Msg >= 2) + GM->Message(0, "# %i #### DEFENDER NPC Total Base Armor",armor); + } + + if (opts) { + armor *= (1.0f - opts->armor_pen_percent); + armor -= opts->armor_pen_flat; + } + + if (RuleB(Combat, OldACSoftcapRules)) { + if (GetClass() == WIZARD || GetClass() == MAGICIAN || + GetClass() == NECROMANCER || GetClass() == ENCHANTER) + softcap = RuleI(Combat, ClothACSoftcap); + else if (GetClass() == MONK && weight <= monkweight) + softcap = RuleI(Combat, MonkACSoftcap); + else if(GetClass() == DRUID || GetClass() == BEASTLORD || GetClass() == MONK) + softcap = RuleI(Combat, LeatherACSoftcap); + else if(GetClass() == SHAMAN || GetClass() == ROGUE || + GetClass() == BERSERKER || GetClass() == RANGER) + softcap = RuleI(Combat, ChainACSoftcap); + else + softcap = RuleI(Combat, PlateACSoftcap); + } + softcap += shield_ac; + armor += shield_ac; + + if (RuleB(Combat, OldACSoftcapRules)) + softcap += (softcap * (aa_mit * RuleR(Combat, AAMitigationACFactor))); + if (armor > softcap) { + int softcap_armor = armor - softcap; + if (RuleB(Combat, OldACSoftcapRules)) { + if (GetClass() == WARRIOR) + softcap_armor = softcap_armor * RuleR(Combat, WarriorACSoftcapReturn); + else if (GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || + (GetClass() == MONK && weight <= monkweight)) + softcap_armor = softcap_armor * RuleR(Combat, KnightACSoftcapReturn); + else if (GetClass() == CLERIC || GetClass() == BARD || + GetClass() == BERSERKER || GetClass() == ROGUE || + GetClass() == SHAMAN || GetClass() == MONK) + softcap_armor = softcap_armor * RuleR(Combat, LowPlateChainACSoftcapReturn); + else if (GetClass() == RANGER || GetClass() == BEASTLORD) + softcap_armor = softcap_armor * RuleR(Combat, LowChainLeatherACSoftcapReturn); + else if (GetClass() == WIZARD || GetClass() == MAGICIAN || + GetClass() == NECROMANCER || GetClass() == ENCHANTER || + GetClass() == DRUID) + softcap_armor = softcap_armor * RuleR(Combat, CasterACSoftcapReturn); + else + softcap_armor = softcap_armor * RuleR(Combat, MiscACSoftcapReturn); + } else { + if (GetClass() == WARRIOR) + softcap_armor *= RuleR(Combat, WarACSoftcapReturn); + else if (GetClass() == PALADIN || GetClass() == SHADOWKNIGHT) + softcap_armor *= RuleR(Combat, PalShdACSoftcapReturn); + else if (GetClass() == CLERIC || GetClass() == RANGER || + GetClass() == MONK || GetClass() == BARD) + softcap_armor *= RuleR(Combat, ClrRngMnkBrdACSoftcapReturn); + else if (GetClass() == DRUID || GetClass() == NECROMANCER || + GetClass() == WIZARD || GetClass() == ENCHANTER || + GetClass() == MAGICIAN) + softcap_armor *= RuleR(Combat, DruNecWizEncMagACSoftcapReturn); + else if (GetClass() == ROGUE || GetClass() == SHAMAN || + GetClass() == BEASTLORD || GetClass() == BERSERKER) + softcap_armor *= RuleR(Combat, RogShmBstBerACSoftcapReturn); + else + softcap_armor *= RuleR(Combat, MiscACSoftcapReturn); + } + + + armor = softcap + softcap_armor; + if (Msg >= 2) + GM->Message(0, "# %i #### DEFENDER Final Armor [Soft Cap %i Soft Cap Armor %i]",armor, softcap,softcap_armor); + } + int tmp_armor = armor; + if (GetClass() == WIZARD || GetClass() == MAGICIAN || + GetClass() == NECROMANCER || GetClass() == ENCHANTER){ + mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 4.0) + armor + 1; + if (Msg >= 2) + GM->Message(0, "# + %.2f #### DEFENDER Armor Bonus [Defense Skill %i Heroic Agi %i]", mitigation_rating - tmp_armor, GetSkill(SkillDefense), itembonuses.HeroicAGI); + } + else{ + mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 3.0) + (armor * 1.333333) + 1; + if (Msg >= 2) + GM->Message(0, "# + %.2f #### DEFENDER Armor Bonus [Defense Skill %i Heroic Agi %i]", mitigation_rating - tmp_armor, GetSkill(SkillDefense), itembonuses.HeroicAGI); + + } + mitigation_rating *= 0.847; + + if (Msg >= 1) + GM->Message(0, "# %.2f #### DEFENDER Final Mitigation Rating", mitigation_rating); + + + if (Msg >= 2){ + GM->Message(0, " "); + GM->Message(0, "### Mitigation Bonus Effects ###"); + if (itembonuses.MeleeMitigation) + GM->Message(0, "# %i #### DEFENDER Item Mod2 Shielding", itembonuses.MeleeMitigation); + if (aabonuses.MeleeMitigationEffect) + GM->Message(0, "# %i #### DEFENDER SE_MeleeMitigation(168) AA Bonus", aabonuses.MeleeMitigationEffect); + if (spellbonuses.MeleeMitigationEffect) + GM->Message(0, "# %i #### DEFENDER SE_MeleeMitigation(168) Spell Bonus", spellbonuses.MeleeMitigationEffect); + if (itembonuses.MeleeMitigationEffect) + GM->Message(0, "# %i #### DEFENDER SE_MeleeMitigation(168) Worn Bonus", itembonuses.MeleeMitigationEffect); + } + + mitigation_rating = mod_mitigation_rating(mitigation_rating, attacker); + + if (attacker->IsClient()){ + if (atk_override) + attack_rating = (atk_override + ((attacker->GetSTR()-66) * 0.9) + (attacker->GetSkill(SkillOffense)*1.345)); + else + attack_rating = ((attacker->CastToClient()->CalcATK() + add_atk) + ((attacker->GetSTR()-66) * 0.9) + (attacker->GetSkill(SkillOffense)*1.345)); + + } + else{ + if (atk_override) + attack_rating = (atk_override + (attacker->GetSkill(SkillOffense)*1.345) + ((attacker->GetSTR()-66) * 0.9)); + else + attack_rating = ((attacker->GetATK() + add_atk) + (attacker->GetSkill(SkillOffense)*1.345) + ((attacker->GetSTR()-66) * 0.9)); + } + + attack_rating = attacker->mod_attack_rating(attack_rating, this); + + if (Msg >= 2){ + GM->Message(0, " "); + GM->Message(0, "### Calculate Attack Rating ###"); + if (attacker->IsClient()){ + GM->Message(0, "# %i #### ATTACKER Worn/Equip ATK Bonus", attacker->itembonuses.ATK); + GM->Message(0, "# %i #### ATTACKER SE_ATK(2) AA Bonus", attacker->aabonuses.ATK); + GM->Message(0, "# %i #### ATTACKER SE_ATK(2) spell Bonus", attacker->spellbonuses.ATK); + GM->Message(0, "# %i #### ATTACKER Leadership Bonus", attacker->CastToClient()->GroupLeadershipAAOffenseEnhancement()); + GM->Message(0, "# %i #### ATTACKER Worn/Equip ATK Bonus", attacker->itembonuses.ATK); + GM->Message(0, "# %i #### ATTACKER Worn/Equip ATK Bonus", attacker->itembonuses.ATK); + GM->Message(0, "# %.2f #### ATTACKER Strength Stat ATK Bonus [Stat Amt: %i]", ((attacker->GetSTR()-66) * 0.9),attacker->GetSTR()); + GM->Message(0, "# %.2f #### ATTACKER Offensive Skill ATK Bonus [Stat Amt: %i]", (attacker->GetSkill(SkillOffense)*1.345) ,attacker->GetSkill(SkillOffense)); + } + + else{ + GM->Message(0, "# %i #### ATTACKER Worn/Equip ATK Bonus", attacker->itembonuses.ATK); + GM->Message(0, "# %i #### ATTACKER SE_ATK(2) spell Bonus", attacker->spellbonuses.ATK); + GM->Message(0, "# %i #### ATTACKER NPC ATK Stat", attacker->CastToNPC()->ATK); + GM->Message(0, "# %.2f #### ATTACKER Strength Stat ATK Bonus [Stat Amt: %i]", ((attacker->GetSTR()-66) * 0.9),attacker->GetSTR()); + GM->Message(0, "# %.2f #### ATTACKER Offensive Skill ATK Bonus [Stat Amt: %i]", (attacker->GetSkill(SkillOffense)*1.345) ,attacker->GetSkill(SkillOffense)); + } + } + + if (Msg >= 1){ + GM->Message(0, "# %.2f #### ATTACKER Final Attack Rating", attack_rating); + GM->Message(0, "######### Melee Mitigation Report: Complete #########", Msg); + } + + + damage = GetMeleeMitDmg(attacker, damage, minhit, mitigation_rating, attack_rating); + } + + if (damage < 0) + damage = 0; + + return damage; +} + +// This is called when the Mob is the one being hit +int32 Mob::Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, + float mit_rating, float atk_rating) +{ + float d = 10.0; + float mit_roll = zone->random.Real(0, mit_rating); + float atk_roll = zone->random.Real(0, atk_rating); + + if (atk_roll > mit_roll) { + float a_diff = atk_roll - mit_roll; + float thac0 = atk_rating * RuleR(Combat, ACthac0Factor); + float thac0cap = attacker->GetLevel() * 9 + 20; + if (thac0 > thac0cap) + thac0 = thac0cap; + + d -= 10.0 * (a_diff / thac0); + } else if (mit_roll > atk_roll) { + float m_diff = mit_roll - atk_roll; + float thac20 = mit_rating * RuleR(Combat, ACthac20Factor); + float thac20cap = GetLevel() * 9 + 20; + if (thac20 > thac20cap) + thac20 = thac20cap; + + d += 10.0 * (m_diff / thac20); + } + + if (d < 0.0) + d = 0.0; + else if (d > 20.0) + d = 20.0; + + float interval = (damage - minhit) / 20.0; + damage -= ((int)d * interval); + + damage -= (minhit * itembonuses.MeleeMitigation / 100); + damage -= (damage * (spellbonuses.MeleeMitigationEffect + itembonuses.MeleeMitigationEffect + aabonuses.MeleeMitigationEffect) / 100); + return damage; +} + +// This is called when the Client is the one being hit +int32 Client::Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, + float mit_rating, float atk_rating) +{ + if (!attacker->IsNPC() || RuleB(Combat, UseOldDamageIntervalRules)) + return Mob::GetMeleeMitDmg(attacker, damage, minhit, mit_rating, atk_rating); + int d = 10; + // floats for the rounding issues + float dmg_interval = (damage - minhit) / 19.0; + float dmg_bonus = minhit - dmg_interval; + float spellMeleeMit = (spellbonuses.MeleeMitigationEffect + itembonuses.MeleeMitigationEffect + aabonuses.MeleeMitigationEffect) / 100.0; + if (GetClass() == WARRIOR) + spellMeleeMit += 0.05; + dmg_bonus -= dmg_bonus * (itembonuses.MeleeMitigation / 100.0); + dmg_interval -= dmg_interval * spellMeleeMit; + + float mit_roll = zone->random.Real(0, mit_rating); + float atk_roll = zone->random.Real(0, atk_rating); + + if (atk_roll > mit_roll) { + float a_diff = atk_roll - mit_roll; + float thac0 = atk_rating * RuleR(Combat, ACthac0Factor); + float thac0cap = attacker->GetLevel() * 9 + 20; + if (thac0 > thac0cap) + thac0 = thac0cap; + + d += 10 * (a_diff / thac0); + } else if (mit_roll > atk_roll) { + float m_diff = mit_roll - atk_roll; + float thac20 = mit_rating * RuleR(Combat, ACthac20Factor); + float thac20cap = GetLevel() * 9 + 20; + if (thac20 > thac20cap) + thac20 = thac20cap; + + d -= 10 * (m_diff / thac20); + } + + if (d < 1) + d = 1; + else if (d > 20) + d = 20; + + return static_cast((dmg_bonus + dmg_interval * d)); +} + + +int32 Client::GetMeleeDamage(Mob* other, bool GetMinDamage) +{ + int Hand = MainPrimary; + + if (!other) + return 0; + + ItemInst* weapon; + weapon = GetInv().GetItem(MainPrimary); + + if(weapon != nullptr) { + if (!weapon->IsWeapon()) { + return(0); + } + } + + SkillUseTypes skillinuse; + AttackAnimation(skillinuse, Hand, weapon); + + int damage = 0; + uint8 mylevel = GetLevel() ? GetLevel() : 1; + uint32 hate = 0; + if (weapon) hate = weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt; + int weapon_damage = GetWeaponDamage(other, weapon, &hate); + if (hate == 0 && weapon_damage > 1) hate = weapon_damage; + + if(weapon_damage > 0){ + if(IsBerserk() && GetClass() == BERSERKER){ + int bonus = 3 + GetLevel()/10; //unverified + weapon_damage = weapon_damage * (100+bonus) / 100; + } + + int min_hit = 1; + int max_hit = (2*weapon_damage*GetDamageTable(skillinuse)) / 100; + + if(GetLevel() < 10 && max_hit > RuleI(Combat, HitCapPre10)) + max_hit = (RuleI(Combat, HitCapPre10)); + else if(GetLevel() < 20 && max_hit > RuleI(Combat, HitCapPre20)) + max_hit = (RuleI(Combat, HitCapPre20)); + + CheckIncreaseSkill(skillinuse, other, -15); + CheckIncreaseSkill(SkillOffense, other, -15); + + +#ifndef EQEMU_NO_WEAPON_DAMAGE_BONUS + + int ucDamageBonus = 0; + + if( Hand == MainPrimary && GetLevel() >= 28 && IsWarriorClass() ) + { + ucDamageBonus = GetWeaponDamageBonus( weapon ? weapon->GetItem() : (const Item_Struct*) nullptr ); + + min_hit += (int) ucDamageBonus; + max_hit += (int) ucDamageBonus; + hate += ucDamageBonus; + } +#endif + min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100; + + if(max_hit < min_hit) + max_hit = min_hit; + + if (GetMinDamage) + return min_hit; + else + return max_hit; + } + + return 0; +} + +void Mob::Tune_FindAccuaryByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int avoid_override, int Msg) +{ + + int add_acc = 0; + float tmp_hit_chance = 0.0f; + bool end = false; + + SkillUseTypes skillinuse = SkillHandtoHand; + if (attacker->IsClient()) + {//Will check first equiped weapon for skill. Ie. remove wepaons to assess bow. + ItemInst* weapon; + weapon = attacker->CastToClient()->GetInv().GetItem(MainPrimary); + + if(weapon && weapon->IsWeapon()){ + attacker->CastToClient()->AttackAnimation(skillinuse, MainPrimary, weapon); + } + else { + weapon = attacker->CastToClient()->GetInv().GetItem(MainSecondary); + if (weapon && weapon->IsWeapon()) + attacker->CastToClient()->AttackAnimation(skillinuse, MainSecondary, weapon); + else { + weapon = attacker->CastToClient()->GetInv().GetItem(MainRange); + if (weapon && weapon->IsWeapon()) + attacker->CastToClient()->AttackAnimation(skillinuse, MainRange, weapon); + } + } + } + + tmp_hit_chance = Tune_CheckHitChance(defender,attacker, skillinuse, MainPrimary,0,0,0, avoid_override); + + + Message(0, "#Tune - Begin Parse [Interval %i Max Loop Iterations %i]", interval, max_loop); + Message(0, "#Tune - Processing... Find Accuracy for hit chance on attacker of (%.0f) pct on defender [Current Hit Chance %.2f]", hit_chance, tmp_hit_chance); + + + if (tmp_hit_chance > hit_chance) + interval = interval * -1; + + for (int j=0; j < max_loop; j++) + { + tmp_hit_chance =Tune_CheckHitChance(defender,attacker, skillinuse, MainPrimary,0,false,0, avoid_override, add_acc); + + if (Msg >= 3) + Message(15, "#Tune - Processing... [%i] [ACCURACY %i] Hit Chance %.2f ",j,add_acc,tmp_hit_chance); + + if (interval > 0 && tmp_hit_chance >= hit_chance){ + end = true; + } + + else if (interval < 0 && tmp_hit_chance <= hit_chance){ + end = true; + } + + if (end){ + + Tune_CheckHitChance(defender,attacker, skillinuse, MainPrimary,0,Msg,0,avoid_override);//Display Stat Report + + Message(0, " "); + + if (attacker->IsNPC()){ + Message(0, "#Recommended NPC Accuracy Statistic adjustment of ( %i ) on ' %s ' for a hit chance of (+ %.0f) pct verse ' %s '. ",add_acc,defender->GetCleanName(), hit_chance, attacker->GetCleanName()); + Message(0, "#SET: [NPC Avoidance] = [%i]",add_acc + defender->CastToNPC()->GetAccuracyRating()); + } + else if (attacker->IsClient()){ + Message(0, "#Recommended Client Accuracy Bonus adjustment of ( %i ) on ' %s ' for a hit chance of (+ %.0f) pct verse ' %s '. ",add_acc,defender->GetCleanName(), hit_chance, attacker->GetCleanName()); + Message(0, "#Modify (+/-): [Item Mod2 Accuracy] [%i]",add_acc); + Message(0, "#Modify (+/-): [SE_Accuracy(216)] [%i]",add_acc); + Message(0, "#Modify (+/-): [SE_HitChance(184)] [%i]",add_acc / 15); + } + + return; + } + + + add_acc = add_acc + interval; + } + + Message(7, "#Tune - Error: Unable to find desired result for (%.0f) pct - Increase interval (%i) AND/OR max loop value (%i) and run again.", hit_chance, interval, max_loop); + Message(7, "#Tune - Parse ended at ACCURACY ADJUSTMENTT ( %i ) at hit chance of (%.0f) / (%.0f) pct.",add_acc,tmp_hit_chance / hit_chance); +} + +void Mob::Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int acc_override, int Msg) +{ + int add_avoid = 0; + float tmp_hit_chance = 0.0f; + bool end = false; + + SkillUseTypes skillinuse = SkillHandtoHand; + if (attacker->IsClient()) + {//Will check first equiped weapon for skill. Ie. remove wepaons to assess bow. + ItemInst* weapon; + weapon = attacker->CastToClient()->GetInv().GetItem(MainPrimary); + + if(weapon && weapon->IsWeapon()){ + attacker->CastToClient()->AttackAnimation(skillinuse, MainPrimary, weapon); + } + else { + weapon = attacker->CastToClient()->GetInv().GetItem(MainSecondary); + if (weapon && weapon->IsWeapon()) + attacker->CastToClient()->AttackAnimation(skillinuse, MainSecondary, weapon); + else { + weapon = attacker->CastToClient()->GetInv().GetItem(MainRange); + if (weapon && weapon->IsWeapon()) + attacker->CastToClient()->AttackAnimation(skillinuse, MainRange, weapon); + } + } + } + + tmp_hit_chance = Tune_CheckHitChance(defender, attacker, skillinuse, MainPrimary,0,0,acc_override, 0); + + Message(0, "#Tune - Begin Parse [Interval %i Max Loop Iterations %i]", interval, max_loop); + Message(0, "#Tune - Processing... Find Avoidance for hit chance on defender of (%.0f) pct from attacker. [Current Hit Chance %.2f]", hit_chance, tmp_hit_chance); + + if (tmp_hit_chance < hit_chance) + interval = interval * -1; + + for (int j=0; j < max_loop; j++) + { + tmp_hit_chance = Tune_CheckHitChance(defender, attacker, skillinuse, MainPrimary, 0,0, acc_override, 0,0,add_avoid); + + if (Msg >= 3) + Message(0, "#Tune - Processing... [%i] [AVOIDANCE %i] Hit Chance %.2f ",j,add_avoid,tmp_hit_chance); + + if (interval > 0 && tmp_hit_chance <= hit_chance){ + end = true; + } + + else if (interval < 0 && tmp_hit_chance >= hit_chance){ + end = true; + } + + if (end){ + + Tune_CheckHitChance(defender,attacker, skillinuse, MainPrimary,0,Msg,acc_override, 0);//Display Stat Report + + Message(0, " "); + + if (defender->IsNPC()){ + Message(0, "#Recommended NPC Avoidance Statistic adjustment of ( %i ) on ' %s ' for a hit chance of ( %.0f) pct from ' %s '. ",add_avoid,defender->GetCleanName(), hit_chance, attacker->GetCleanName()); + Message(0, "#SET: [NPC Avoidance] = [%i]",add_avoid + defender->CastToNPC()->GetAvoidanceRating()); + } + else if (defender->IsClient()){ + Message(0, "#Recommended Client Avoidance Bonus adjustment of ( %i ) on ' %s ' for a hit chance of ( %.0f) pct from ' %s '. ",add_avoid,defender->GetCleanName(), hit_chance, attacker->GetCleanName()); + Message(0, "#Modify (+/-): [Item Mod2 Avoidance] [%i]",add_avoid); + Message(0, "#Modify (+/-): [SE_AvoidMeleeChance(172)] [%i]",add_avoid / 10); + } + + return; + } + + add_avoid = add_avoid + interval; + } + + Message(0, "#Tune - Error: Unable to find desired result for (%.0f) pct - Increase interval (%i) AND/OR max loop value (%i) and run again.", hit_chance, interval, max_loop); + Message(0, "#Tune - Parse ended at AVOIDANCE ADJUSTMENT ( %i ) at hit chance of (%.0f) / (%.0f) pct.",add_avoid,tmp_hit_chance / hit_chance); +} + + +float Mob::Tune_CheckHitChance(Mob* defender, Mob* attacker, SkillUseTypes skillinuse, int Hand, int16 chance_mod, int Msg,int acc_override, int avoid_override, int add_acc, int add_avoid) +{ + + float chancetohit = RuleR(Combat, BaseHitChance); + + if(attacker->IsNPC() && !attacker->IsPet()) + chancetohit += RuleR(Combat, NPCBonusHitChance); + + if (Msg){ + + Message(0, "######### Hit Chance Report: Start [Detail Level %i]#########", Msg); + Message(0, "#ATTACKER: %s", attacker->GetCleanName()); + Message(0, "#DEFENDER: %s", defender->GetCleanName()); + if (Msg >= 2){ + Message(0, " "); + Message(0, "### Calculate Base Hit Chance ###"); + Message(0, "# + %.2f Total: %.2f #### RuleR(Combat, BaseHitChance)", RuleR(Combat, BaseHitChance), RuleR(Combat, BaseHitChance)); + if (attacker->IsNPC()) + Message(0, "# + %.2f Total: %.2f #### RuleR(Combat, NPCBonusHitChance)", RuleR(Combat, NPCBonusHitChance), chancetohit); + } + } + + float temp_chancetohit = chancetohit; + + bool pvpmode = false; + if(IsClient() && attacker->IsClient()) + pvpmode = true; + + if (chance_mod >= 10000) + return true; + + float avoidanceBonus = 0; + float hitBonus = 0; + + //////////////////////////////////////////////////////// + // To hit calcs go here + //////////////////////////////////////////////////////// + + uint8 attacker_level = attacker->GetLevel() ? attacker->GetLevel() : 1; + uint8 defender_level = defender->GetLevel() ? defender->GetLevel() : 1; + + //Calculate the level difference + + double level_difference = attacker_level - defender_level; + double range = defender->GetLevel(); + range = ((range / 4) + 3); + + if(level_difference < 0) + { + if(level_difference >= -range) + { + chancetohit += (level_difference / range) * RuleR(Combat,HitFalloffMinor); //5 + } + else if (level_difference >= -(range+3.0)) + { + chancetohit -= RuleR(Combat,HitFalloffMinor); + chancetohit += ((level_difference+range) / (3.0)) * RuleR(Combat,HitFalloffModerate); //7 + } + else + { + chancetohit -= (RuleR(Combat,HitFalloffMinor) + RuleR(Combat,HitFalloffModerate)); + chancetohit += ((level_difference+range+3.0)/12.0) * RuleR(Combat,HitFalloffMajor); //50 + } + } + else + { + chancetohit += (RuleR(Combat,HitBonusPerLevel) * level_difference); + } + + if (Msg >= 2) + Message(0, "# + %.2f Total: %.2f #### Level Modifers", chancetohit - temp_chancetohit, chancetohit); + + temp_chancetohit = chancetohit; + + chancetohit -= ((float)defender->GetAGI() * RuleR(Combat, AgiHitFactor)); + + if (Msg >= 2) + Message(0, "# - %.2f Total: %.2f #### DEFENDER Agility", ((float)defender->GetAGI() * RuleR(Combat, AgiHitFactor)), chancetohit); + + if(attacker->IsClient()) + { + chancetohit -= (RuleR(Combat,WeaponSkillFalloff) * (attacker->CastToClient()->MaxSkill(skillinuse) - attacker->GetSkill(skillinuse))); + if (Msg >= 2) + Message(0, "# - %.2f Total: %.2f ##### ATTACKER Wpn Skill Mod: ", (RuleR(Combat,WeaponSkillFalloff) * (attacker->CastToClient()->MaxSkill(skillinuse) - attacker->GetSkill(skillinuse))), chancetohit); + } + + if(defender->IsClient()) + { + chancetohit += (RuleR(Combat,WeaponSkillFalloff) * (defender->CastToClient()->MaxSkill(SkillDefense) - defender->GetSkill(SkillDefense))); + if (Msg >= 2) + Message(0, "# + %.2f Total: %.2f #### DEFENDER Defense Skill Mod", (RuleR(Combat,WeaponSkillFalloff) * (defender->CastToClient()->MaxSkill(SkillDefense) - defender->GetSkill(SkillDefense))), chancetohit); + } + + + //I dont think this is 100% correct, but at least it does something... + if(attacker->spellbonuses.MeleeSkillCheckSkill == skillinuse || attacker->spellbonuses.MeleeSkillCheckSkill == 255) { + chancetohit += attacker->spellbonuses.MeleeSkillCheck; + if (Msg >= 2) + Message(0, "# + %.2f Total: %.2f #### ATTACKER SE_MeleeSkillCheck(183) Spell Bonus", attacker->spellbonuses.MeleeSkillCheck , chancetohit); + } + if(attacker->itembonuses.MeleeSkillCheckSkill == skillinuse || attacker->itembonuses.MeleeSkillCheckSkill == 255) { + chancetohit += attacker->itembonuses.MeleeSkillCheck; + if (Msg >= 2) + Message(0, "# + %.2f Total: %.2f #### ATTACKER SE_MeleeSkillCheck(183) Worn Bonus", attacker->itembonuses.MeleeSkillCheck , chancetohit); + } + + if (Msg) + Message(0, "#FINAL Base Hit Chance: %.2f percent", chancetohit); + + if (Msg >= 2){ + Message(0, " "); + Message(0, "######### Calculate Avoidance Bonuses #########"); + } + + //Avoidance Bonuses on defender decreases baseline hit chance by percent. + avoidanceBonus = defender->spellbonuses.AvoidMeleeChanceEffect + + defender->itembonuses.AvoidMeleeChanceEffect + + defender->aabonuses.AvoidMeleeChanceEffect + + (defender->itembonuses.AvoidMeleeChance / 10.0f); //Item Mod 'Avoidence' + + if (Msg >= 2){ + if (defender->aabonuses.AvoidMeleeChanceEffect) + Message(0, "# %i #### DEFENDER SE_AvoidMeleeChance(172) AA Bonus", defender->aabonuses.AvoidMeleeChanceEffect); + if (defender->spellbonuses.AvoidMeleeChanceEffect) + Message(0, "# %i #### DEFENDER SE_AvoidMeleeChance(172) Spell Bonus", defender->spellbonuses.AvoidMeleeChanceEffect); + if (defender->itembonuses.AvoidMeleeChanceEffect) + Message(0, "# %i #### DEFENDER SE_AvoidMeleeChance(172) Worn Bonus", defender->itembonuses.AvoidMeleeChanceEffect); + if (defender->itembonuses.AvoidMeleeChance) + Message(0, "# %i #### DEFENDER Avoidance Item Mod2 Bonus[Amt: %i] ", defender->itembonuses.AvoidMeleeChance / 10.0f,defender->itembonuses.AvoidMeleeChance); + } + + + Mob *owner = nullptr; + if (defender->IsPet()) + owner = defender->GetOwner(); + else if ((defender->IsNPC() && defender->CastToNPC()->GetSwarmOwner())) + owner = entity_list.GetMobID(defender->CastToNPC()->GetSwarmOwner()); + + if (owner){ + avoidanceBonus += owner->aabonuses.PetAvoidance + owner->spellbonuses.PetAvoidance + owner->itembonuses.PetAvoidance; + + if (Msg >= 2){ + if (owner->aabonuses.PetAvoidance) + Message(0, "# %i #### DEFENDER SE_PetAvoidance(215) AA Bonus", owner->aabonuses.PetAvoidance); + if (owner->aabonuses.PetAvoidance) + Message(0, "# %i #### DEFENDER SE_PetAvoidance(215) Spell Bonus", owner->itembonuses.PetAvoidance); + if (owner->aabonuses.PetAvoidance) + Message(0, "# %i #### DEFENDER SE_PetAvoidance(215) Worn Bonus", owner->spellbonuses.PetAvoidance); + } + } + + if(defender->IsNPC()){ + avoidanceBonus += ((defender->CastToNPC()->GetAvoidanceRating() + add_avoid) / 10.0f); //Modifier from database + if (Msg >= 2) + Message(0, "# + %.2f #### DEFENDER NPC AVOIDANCE STAT [Stat Amt: %i] ", ((defender->CastToNPC()->GetAvoidanceRating() + add_avoid) / 10.0f),defender->CastToNPC()->GetAvoidanceRating()); + } + else if(defender->IsClient()){ + avoidanceBonus += (add_avoid / 10.0f); //Avoidance Item Mod + } + + //#tune override value + if (avoid_override){ + avoidanceBonus = (avoid_override / 10.0f); + if (Msg >= 2) + Message(0, "%.2f #### DEFENDER 'AVOIDANCE OVERRIDE'", avoidanceBonus); + } + + if (Msg) + Message(0, "#FINAL Avoidance Bonus': %.2f percent ", avoidanceBonus); + + if (Msg >= 2){ + Message(0, " "); + Message(0, "######### Calculate Accuracy Bonuses #########"); + } + + //Hit Chance Bonuses on attacker increases baseline hit chance by percent. + hitBonus += attacker->itembonuses.HitChanceEffect[skillinuse] + + attacker->spellbonuses.HitChanceEffect[skillinuse]+ + attacker->aabonuses.HitChanceEffect[skillinuse]+ + attacker->itembonuses.HitChanceEffect[HIGHEST_SKILL+1] + + attacker->spellbonuses.HitChanceEffect[HIGHEST_SKILL+1] + + attacker->aabonuses.HitChanceEffect[HIGHEST_SKILL+1]; + + if (Msg >= 2){ + if (attacker->aabonuses.HitChanceEffect[HIGHEST_SKILL+1]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) AA Bonus [All Skills]", attacker->aabonuses.HitChanceEffect[HIGHEST_SKILL+1]); + if (attacker->spellbonuses.HitChanceEffect[HIGHEST_SKILL+1]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) Spell Bonus [All Skills]", attacker->spellbonuses.HitChanceEffect[HIGHEST_SKILL+1]); + if (attacker->itembonuses.HitChanceEffect[HIGHEST_SKILL+1]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) Worn Bonus [All Skills]", attacker->itembonuses.HitChanceEffect[HIGHEST_SKILL+1]); + if (attacker->itembonuses.HitChanceEffect[skillinuse]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) AA Bonus [Skill]", attacker->aabonuses.HitChanceEffect[skillinuse]); + if (attacker->spellbonuses.HitChanceEffect[skillinuse]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) Spell Bonus [Skill]", attacker->spellbonuses.HitChanceEffect[skillinuse]); + if (attacker->itembonuses.HitChanceEffect[skillinuse]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) Worn Bonus [Skill]", attacker->itembonuses.HitChanceEffect[skillinuse]); + } + + //Accuracy = Spell Effect , HitChance = 'Accuracy' from Item Effect + //Only AA derived accuracy can be skill limited. ie (Precision of the Pathfinder, Dead Aim) + hitBonus += (attacker->itembonuses.Accuracy[HIGHEST_SKILL+1] + + attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1] + + attacker->aabonuses.Accuracy[HIGHEST_SKILL+1] + + attacker->aabonuses.Accuracy[skillinuse] + + attacker->itembonuses.HitChance) / 15.0f; //Item Mod 'Accuracy' + + if (Msg >= 2) { + if (attacker->aabonuses.Accuracy[HIGHEST_SKILL+1]) + Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) AA Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->aabonuses.Accuracy[HIGHEST_SKILL+1])/15.0f,attacker->aabonuses.Accuracy[HIGHEST_SKILL+1]); + if (attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1]) + Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) Spell Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1])/15.0f,attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1]); + if (attacker->itembonuses.Accuracy[HIGHEST_SKILL+1]) + Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) Worn Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->itembonuses.Accuracy[HIGHEST_SKILL+1])/15.0f,attacker->itembonuses.Accuracy[HIGHEST_SKILL+1]); + if (attacker->aabonuses.Accuracy[skillinuse]) + Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) AA Bonus [Skill] [Stat Amt: %i]", static_cast(attacker->aabonuses.Accuracy[skillinuse])/15.0f,attacker->aabonuses.Accuracy[skillinuse]); + if (attacker->itembonuses.HitChance) + Message(0, "# %.2f #### ATTACKER Accuracy Item Mod2 Bonus [Stat Amt: %i]", static_cast(attacker->itembonuses.HitChance)/15.0f,attacker->itembonuses.HitChance); + } + + hitBonus += chance_mod; //Modifier applied from casted/disc skill attacks. + + if(attacker->IsNPC()){ + if (acc_override){ + hitBonus = (acc_override / 10.0f); + if (Msg >= 2) + Message(0, "# %.2f #### ATTACKER 'ACCURACY OVERRIDE'", hitBonus); + } + else { + hitBonus += ((attacker->CastToNPC()->GetAccuracyRating() + add_acc) / 10.0f); //Modifier from database + if (Msg >= 2){ + Message(0, "# %.2f #### ATTACKER NPC ACCURACY STAT [Stat Amt: %i] ", ((attacker->CastToNPC()->GetAccuracyRating() + add_avoid) / 10.0f),attacker->CastToNPC()->GetAccuracyRating()); + } + } + } + else if(attacker->IsClient()){ + if (acc_override){ + hitBonus = (acc_override / 15.0f); + if (Msg >= 2) + Message(0, "# %.2f #### ATTACKER 'ACCURACY OVERRIDE': %.2f "); + } + else + hitBonus += (add_acc / 15.0f); //Modifier from database + } + + if(skillinuse == SkillArchery){ + hitBonus -= hitBonus*RuleR(Combat, ArcheryHitPenalty); + if (Msg >= 2) + Message(0, "# %.2f pct #### RuleR(Combat, ArcheryHitPenalty) ", RuleR(Combat, ArcheryHitPenalty)); + } + + //Calculate final chance to hit + chancetohit += ((chancetohit * (hitBonus - avoidanceBonus)) / 100.0f); + + if (Msg){ + Message(0, "#FINAL Accuracy Bonus': %.2f percent", hitBonus); + + if (Msg >= 2) + Message(0, " "); + + Message(0, "#FINAL Hit Chance: %.2f percent [Max: %.2f Min: %.2f] ", chancetohit, RuleR(Combat,MaxChancetoHit), RuleR(Combat,MinChancetoHit) ); + Message(0, "######### Hit Chance Report: Completed #########"); + } + + chancetohit = mod_hit_chance(chancetohit, skillinuse, attacker); + + // Chance to hit; Max 95%, Min 5% DEFAULTS + if(chancetohit > 1000 || chancetohit < -1000) { + //if chance to hit is crazy high, that means a discipline is in use, and let it stay there + } + else if(chancetohit > RuleR(Combat,MaxChancetoHit)) { + chancetohit = RuleR(Combat,MaxChancetoHit); + } + else if(chancetohit < RuleR(Combat,MinChancetoHit)) { + chancetohit = RuleR(Combat,MinChancetoHit); + } + + return(chancetohit); +} \ No newline at end of file diff --git a/zone/zone.cpp b/zone/zone.cpp index 2f7e00522..bc614cbdb 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -670,15 +670,7 @@ void Zone::Shutdown(bool quite) if (!ZoneLoaded) return; - std::list mob_list; - entity_list.GetMobList(mob_list); - std::list::iterator mob_itr = mob_list.begin(); - while (mob_itr != mob_list.end()) { - Mob* mob_inst = *mob_itr; - mob_inst->AI_Stop(); - mob_inst->AI_ShutDown(); - ++mob_itr; - } + entity_list.StopMobAI(); std::map::iterator itr; while(zone->npctable.size()) {