#include "stdafx.h" #include "./SCItemSlotContainer.h" #include "./SCItemSlot.h" #include //================================================================================================== SCItemSlotContainer::SCItemSlotContainer(void) : valid_state_(false) { } SCItemSlotContainer::~SCItemSlotContainer(void) { } void SCItemSlotContainer::ClearAll() { SCSlotContainer::ClearAll(); valid_state_ = true; } SCSlot* SCItemSlotContainer::CreateSlot() { return new SCItemSlot; } void SCItemSlotContainer::Init(POSTYPE max_slot_size, SLOTIDX slot_index) { SCSlotContainer::Init(max_slot_size, slot_index); valid_state_ = true; } void SCItemSlotContainer::UpdateSlot(POSTYPE at_pos, int changed_num) { // (f100308.2) change logic to solve GetSlot problem // slot_in_container SCSlot* slot = GetValidSlotPtr(NULL, at_pos); if (slot == NULL || IsEmpty(at_pos)) { return; } // SCItemSlot* item_slot = static_cast(slot); int calculated = item_slot->GetNum() + changed_num; if (calculated > item_slot->GetMaxNum()) { return; } // SCSlotContainer::UpdateSlot(at_pos, changed_num); } BOOL SCItemSlotContainer::IsLocked(POSTYPE at_pos) { // (f100308.2) change logic to solve GetSlot problem // slot_in_container SCSlot* slot = GetValidSlotPtr(NULL, at_pos); if (slot == NULL) { // (WARNING) (f100311.3) changed policy for securable operation of a invalid slot. // traditional custom logic is returns no-locked state \ // (or returns unknown result by garbage data), changes to locked state return true; } // (NOTE) that means of 'IsLocked' in a container, present internal locking mechanism // (CHANGES) item slot has been so enabled that multi-locking concept. // so that add the 'UserBlocked' check routine. SCItemSlot* item_slot = static_cast(slot); if (item_slot->IsLocked() || item_slot->IsBlocked()) { return true; // internal locking mechanism, related with server inter-process communications } // (f100317.1L) changes to rollback version. //// added (f100311.4) //if (item_slot->IsUserBlocked()) { // return true; // related with summoning for pet or mount (presented by rider) //} // stacked lock to support ether-device, etc... it is multi-purpose lock based on case research // (NOTE) I don't know this lock whether act exactly. if (item_slot->GetLaxLock()->IsLock()) { return true; } return false; } void SCItemSlotContainer::SetLock(POSTYPE at_pos, BOOL is_setup) { // (f100308.2) change logic to solve GetSlot problem // slot_in_container SCSlot* slot = GetValidSlotPtr(NULL, at_pos); const bool if_fails_slot_pos_is_occurred_index_out_of_range = (slot != NULL); if (FlowControl::FCAssert(if_fails_slot_pos_is_occurred_index_out_of_range) == false) { return; } // SCItemSlot* item_slot = static_cast(slot); item_slot->SetLock(!!is_setup); } // implemented by _SOLAR_SLOT_INTEGRITY_CONTAINER_PROCESS_ SCItemSlotContainer::SameSetItemSlotsResult SCItemSlotContainer::GetSameSetItemSlots(SCItemSlot** result_of_set_items, const POSTYPE number_of_result_array, const BASE_ITEMINFO* related_reference_item, BOOL bEquip) { // premise #1: current call stack is called in ApplySetItem... blah~ // premise #2: special accessory can apply only in full set items equipped status SameSetItemSlotsResult result = { 0, }; // (CHANGES) the querying special accessory must be the item using set item script, // even if the querying special accessory are not matched 'set item group' related real set items. result.set_item_code = related_reference_item->set_group_code; // enable changes in calculating if (result.set_item_code == 0) { return result; } const bool is_special_accessory = related_reference_item->m_bySetOptionType == related_reference_item->eSetItem_Special; bool changeable_state = is_special_accessory; bool retry_state = false; const SLOT_LINEAR_LIST& slots = GetSlotList(); // (f100311.4) SLOT_LINEAR_LIST::const_iterator it = slots.begin(), end = slots.end(); for (; it != end; (retry_state == false ? ++it : it)) { retry_state = false; //if (IsEmpty(pos)) { continue; } const SlotNode& slot_node = *it; SCItemSlot* item_slot = static_cast(slot_node.slot); if (item_slot->GetItemCode() == 0) { // SCItemSlot is empty if code equals zero. that's enough don't have call 'IsEmpty' continue; } // purpose : ÇöÀç ¼¼Æ® ¾ÆÀÌÅÛÀÌ È°¼ºÈ­ µÇ¾î ÀÖ°í, °°Àº ¼¼Æ® ¾ÆÀÌÅÛ Å¸ÀÔÀ» °¡Áö°í ¿Â´Ù. // find related set item, and \ // do loop process which had O(2) time complexity to support special accessory multi-link const BASE_ITEMINFO* item_info = item_slot->GetItemInfo(); if (item_info->set_group_code == 0) { continue; } // if (item_info->m_bySetOptionType == item_info->eSetItem_Active) { // current : skipped if no set items if (item_info->set_group_code == result.set_item_code) { // µ¿ÀÏÇÑ ¾ÆÀÌÅÛÀ» µÎ °³ ÀÌ»ó ÀåºñÇÑ °ÍÀº ¼¼Æ® ÀåÂøÀ¸·Î ÀÎÁ¤ÇÏÁö ¾Ê´Â´Ù if(bEquip) { POSTYPE i = 0; for ( ; i < result.number_of_same_set_items; ++i) { if (item_info->m_Code == result_of_set_items[i]->GetItemCode()) { break; } } if (i >= result.number_of_same_set_items) { result_of_set_items[result.number_of_same_set_items] = item_slot; ++result.number_of_same_set_items; } } else { if (item_info->m_Code != related_reference_item->m_Code) { result_of_set_items[result.number_of_same_set_items] = item_slot; ++result.number_of_same_set_items; } } } else if (changeable_state && is_special_accessory) { // entered if special accessory different set item group. // find linked accessory code in set item information const SETITEM_OPTION_INFO* set_option = \ SetItemOptionInfoParser::Instance()->Find(item_info->set_group_code); if (set_option == NULL) { continue; } changeable_state = false; if (related_reference_item->m_Code == set_option->m_SpecialEquipOptionItem.m_wItemCode) { // enabled state: the special accessory of 2nd elite is matched 1st elite's it. result.set_item_code = item_info->set_group_code; result.number_of_same_set_items = 0; ZeroMemory(result_of_set_items, sizeof(SCItemSlot*) * number_of_result_array); it = slots.begin(); retry_state = true; // start researching continue; } } } //end true condition if activated set item condition' } return result; } SCItemSlotContainer::SameSetItemSlotsResult SCItemSlotContainer::GetSameSetItemTotalSlots( SCItemSlot** result_of_set_items, const POSTYPE number_of_result_array, const BASE_ITEMINFO* related_reference_item, BOOL bEquip /*= TRUE*/ ) { // premise #2: special accessory can apply only in full set items equipped status SameSetItemSlotsResult result = { 0, }; // (CHANGES) the querying special accessory must be the item using set item script, // even if the querying special accessory are not matched 'set item group' related real set items. result.set_item_code = related_reference_item->set_group_code; // enable changes in calculating if (result.set_item_code == 0) { return result; } const bool is_special_accessory = related_reference_item->m_bySetOptionType == related_reference_item->eSetItem_Special; bool changeable_state = is_special_accessory; bool retry_state = false; const SLOT_LINEAR_LIST& slots = GetSlotList(); // (f100311.4) SLOT_LINEAR_LIST::const_iterator it = slots.begin(), end = slots.end(); for (; it != end; (retry_state == false ? ++it : it)) { retry_state = false; //if (IsEmpty(pos)) { continue; } const SlotNode& slot_node = *it; SCItemSlot* item_slot = static_cast(slot_node.slot); if (item_slot->GetItemCode() == 0) { // SCItemSlot is empty if code equals zero. that's enough don't have call 'IsEmpty' continue; } // purpose : ÇöÀç ¼¼Æ® ¾ÆÀÌÅÛÀÌ È°¼ºÈ­ µÇ¾î ÀÖ°í, °°Àº ¼¼Æ® ¾ÆÀÌÅÛ Å¸ÀÔÀ» °¡Áö°í ¿Â´Ù. // find related set item, and \ // do loop process which had O(2) time complexity to support special accessory multi-link const BASE_ITEMINFO* item_info = item_slot->GetItemInfo(); if (item_info->set_group_code == 0) { continue; } // if (item_info->m_bySetOptionType == item_info->eSetItem_Active) { // current : skipped if no set items if (item_info->set_group_code == result.set_item_code) { //Âø¿ëÁß ÀåºñÁß¿¡ °°Àº ¼ÂÆ®°¡ ¸î°³°¡ Á¸ÀçÇϴ°¡? if(bEquip) { result_of_set_items[result.number_of_same_set_items] = item_slot; ++result.number_of_same_set_items; } } //½ºÅ×ÀÌÆ® º¯°æ¹× ½ºÆÐ¼È ¾Ç¼¼»ç¸® °æ¿ìÀÓ. else if (changeable_state && is_special_accessory) { // entered if special accessory different set item group. // find linked accessory code in set item information const SETITEM_OPTION_INFO* set_option = \ SetItemOptionInfoParser::Instance()->Find(item_info->set_group_code); if (set_option == NULL) { continue; } changeable_state = false; if (related_reference_item->m_Code == set_option->m_SpecialEquipOptionItem.m_wItemCode) { // enabled state: the special accessory of 2nd elite is matched 1st elite's it. result.set_item_code = item_info->set_group_code; result.number_of_same_set_items = 0; ZeroMemory(result_of_set_items, sizeof(SCItemSlot*) * number_of_result_array); it = slots.begin(); retry_state = true; // start researching continue; } } } //end true condition if activated set item condition' } return result; } //================================================================================================== // implemented by _NA_0_20100517_ITEMSLOTCONTAINER_EQUIPGROUP_DETECTION namespace nsSlot { ; // ÀåÂø ¾ÆÀÌÅÛÀ» À¯Çüº°·Î °Ë»öÇϱâ À§ÇÑ °Ë»ö ¹üÀ§¸¦ Á¦°øÇÏ´Â À¯Æ¿¸®Æ¼ Ŭ·¡½º // CHANGES: f110418.4L, f101124.1L, The used algorithm to search equipment groups is changed // from O(nlogn) time complexity to O(1) time complexity class EquipSearchspace { public: enum EquipGroup // Àåºñ ±×·ì »ó¼ö { EQUIPGROUP_INVALID = 0, // À¯È¿ÇÏÁö ¾ÊÀº Àåºñ ±×·ì EQUIPGROUP_WEAPON, // ¹«±â EQUIPGROUP_ARMOR, // ¹æ¾î±¸ EQUIPGROUP_RING, // ¹ÝÁö EQUIPGROUP_SPECIAL_ACCESSORY, // Ư¼ö¾Ç¼¼»ç¸® EQUIPGROUP_CASH_ITEM, // ij½Ã ¾ÆÀÌÅÛ EQUIPGROUP_PC_ROOM_ITEM, // PC¹æ ¾ÆÀÌÅÛ EQUIPGROUP_MAX }; struct SearchList { POSTYPE* first; POSTYPE* second; }; // // »ý¼ºÀÚ¿¡¼­ Àåºñ ±×·ì ±¸¼º ÃʱâÈ­ EquipSearchspace() { ZeroMemory(search_list_, sizeof(search_list_)); memset(data_list_, eEQUIPCONTAINER_MAX, sizeof(data_list_)); // POSTYPE* dest_it = data_list_; if (SearchList* node = &search_list_[EQUIPGROUP_INVALID]) { node->first = node->second = dest_it; }; if (SearchList* node = &search_list_[EQUIPGROUP_WEAPON]) { node->first = dest_it; *dest_it++ = eEQUIPCONTAINER_WEAPON; node->second = dest_it; }; if (SearchList* node = &search_list_[EQUIPGROUP_ARMOR]) { node->first = dest_it; *dest_it++ = eEQUIPCONTAINER_ARMOR; *dest_it++ = eEQUIPCONTAINER_PROTECTOR; *dest_it++ = eEQUIPCONTAINER_HELMET; *dest_it++ = eEQUIPCONTAINER_PANTS; *dest_it++ = eEQUIPCONTAINER_BOOTS; *dest_it++ = eEQUIPCONTAINER_GLOVE; *dest_it++ = eEQUIPCONTAINER_BELT; *dest_it++ = eEQUIPCONTAINER_SHIRTS; node->second = dest_it; }; if (SearchList* node = &search_list_[EQUIPGROUP_RING]) { node->first = dest_it; *dest_it++ = eEQUIPCONTAINER_RING1; *dest_it++ = eEQUIPCONTAINER_RING2; node->second = dest_it; }; if (SearchList* node = &search_list_[EQUIPGROUP_SPECIAL_ACCESSORY]) { node->first = dest_it; *dest_it++ = eEQUIPCONTAINER_SACCESSORY1; *dest_it++ = eEQUIPCONTAINER_SACCESSORY2; *dest_it++ = eEQUIPCONTAINER_SACCESSORY3; node->second = dest_it; }; if (SearchList* node = &search_list_[EQUIPGROUP_CASH_ITEM]) { node->first = dest_it; *dest_it++ = eEQUIPCONTAINER_CHARGE1; *dest_it++ = eEQUIPCONTAINER_CHARGE2; *dest_it++ = eEQUIPCONTAINER_CHARGE3; *dest_it++ = eEQUIPCONTAINER_CHARGE4; *dest_it++ = eEQUIPCONTAINER_CHARGE5; node->second = dest_it; }; if (SearchList* node = &search_list_[EQUIPGROUP_PC_ROOM_ITEM]) { node->first = dest_it; *dest_it++ = eEQUIPCONTAINER_PC_ROOM1; *dest_it++ = eEQUIPCONTAINER_PC_ROOM2; *dest_it++ = eEQUIPCONTAINER_PC_ROOM3; node->second = dest_it; }; // if (FlowControl::FCAssert(dest_it <= &data_list_[_countof(data_list_)]) == false) { __debugbreak(); }; } // ÁÖ¾îÁø ÂüÁ¶ ÀåÂø À§Ä¡¿Í °°Àº ±×·ì ¾ÆÀÌÅÛµéÀÇ ÀåÂø À§Ä¡ º¤Å͸¦ ¸®ÅÏ const SearchList& GetSearchVector(POSTYPE reference_pos) const { if (bool in_range = (reference_pos < _countof(data_list_))) { EquipGroup equip_group = static_cast(kConvertPosToEquipGroup[reference_pos]); return search_list_[equip_group]; } return search_list_[EQUIPGROUP_INVALID]; } private: // SearchList search_list_[EQUIPGROUP_MAX]; POSTYPE data_list_[eEQUIPCONTAINER_MAX]; static const uint8_t kConvertPosToEquipGroup[eEQUIPCONTAINER_MAX]; }; const uint8_t EquipSearchspace::kConvertPosToEquipGroup[eEQUIPCONTAINER_MAX] = { EQUIPGROUP_WEAPON, // eEQUIPCONTAINER_WEAPON = 0, EQUIPGROUP_ARMOR, // eEQUIPCONTAINER_ARMOR = 1, EQUIPGROUP_ARMOR, // eEQUIPCONTAINER_PROTECTOR = 2, EQUIPGROUP_ARMOR, // eEQUIPCONTAINER_HELMET = 3, EQUIPGROUP_ARMOR, // eEQUIPCONTAINER_PANTS = 4, EQUIPGROUP_ARMOR, // eEQUIPCONTAINER_BOOTS = 5, EQUIPGROUP_ARMOR, // eEQUIPCONTAINER_GLOVE = 6, EQUIPGROUP_ARMOR, // eEQUIPCONTAINER_BELT = 7, EQUIPGROUP_ARMOR, // eEQUIPCONTAINER_SHIRTS = 8, EQUIPGROUP_RING, // eEQUIPCONTAINER_RING1 = 9, EQUIPGROUP_RING, // eEQUIPCONTAINER_RING2 = 10, EQUIPGROUP_INVALID, // eEQUIPCONTAINER_NECKLACE = 11, EQUIPGROUP_INVALID, // eEQUIPCONTAINER_BOW = 12, EQUIPGROUP_SPECIAL_ACCESSORY, // eEQUIPCONTAINER_SACCESSORY1 = 13, EQUIPGROUP_SPECIAL_ACCESSORY, // eEQUIPCONTAINER_SACCESSORY2 = 14, EQUIPGROUP_SPECIAL_ACCESSORY, // eEQUIPCONTAINER_SACCESSORY3 = 15, EQUIPGROUP_CASH_ITEM, // eEQUIPCONTAINER_CHARGE1 = 16, EQUIPGROUP_CASH_ITEM, // eEQUIPCONTAINER_CHARGE2 = 17, EQUIPGROUP_CASH_ITEM, // eEQUIPCONTAINER_CHARGE3 = 18, EQUIPGROUP_CASH_ITEM, // eEQUIPCONTAINER_CHARGE4 = 19, EQUIPGROUP_CASH_ITEM, // eEQUIPCONTAINER_CHARGE5 = 20, EQUIPGROUP_PC_ROOM_ITEM, // eEQUIPCONTAINER_PC_ROOM1 = 21, EQUIPGROUP_PC_ROOM_ITEM, // eEQUIPCONTAINER_PC_ROOM2 = 22, EQUIPGROUP_PC_ROOM_ITEM, // eEQUIPCONTAINER_PC_ROOM3 = 23, //// }; }; //end of namespace //================================================================================================== const SCItemSlot& SCItemSlotContainer::GetItemOfType(POSTYPE reference_pos, SLOTCODE item_code) { // Note that this lazy static initialization is NOT thread-safe. static const nsSlot::EquipSearchspace search_space; typedef nsSlot::EquipSearchspace::SearchList SearchList; const SearchList& search_vector = search_space.GetSearchVector(reference_pos); for (POSTYPE* it = search_vector.first; it != search_vector.second; ++it) { const SCItemSlot& item_slot = static_cast(GetSlot(*it)); if (item_slot.GetItemCode() == item_code) { return item_slot; }; }; // can't find or exist group ;{ const SCItemSlot& item_slot = static_cast(GetSlot(reference_pos)); return item_slot; }; }