Files
Sun1602/SolarSlot/SCItemSlotContainer.cpp
T
2022-10-26 12:25:11 +08:00

455 lines
17 KiB
C++

#include "stdafx.h"
#include "./SCItemSlotContainer.h"
#include "./SCItemSlot.h"
#include <SetItemOptionInfoParser.h>
//==================================================================================================
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<SCItemSlot*>(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<SCItemSlot*>(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<SCItemSlot*>(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<SCItemSlot*>(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<SCItemSlot*>(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, // 캐시 아이템
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<EquipGroup>(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<SCItemSlot&>(GetSlot(*it));
if (item_slot.GetItemCode() == item_code) {
return item_slot;
};
};
// can't find or exist group
;{
const SCItemSlot& item_slot = static_cast<SCItemSlot&>(GetSlot(reference_pos));
return item_slot;
};
}