From c1cf1a141e5d83f6793af115f10e1bebbb674a8e Mon Sep 17 00:00:00 2001 From: d1str4ught <> Date: Mon, 9 Feb 2026 04:24:52 +0100 Subject: [PATCH] party.check_item(vnum, count) and party.remove_item(vnum, count) LUA functions --- src/game/char.h | 2 +- src/game/char_item.cpp | 72 +++++++++++++++---------------------- src/game/party.h | 3 ++ src/game/questlua_party.cpp | 66 ++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 45 deletions(-) diff --git a/src/game/char.h b/src/game/char.h index b7550e4..304079e 100644 --- a/src/game/char.h +++ b/src/game/char.h @@ -1129,7 +1129,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider int CountEmptyInventory() const; int CountSpecifyItem(DWORD vnum) const; - void RemoveSpecifyItem(DWORD vnum, DWORD count = 1); + bool RemoveSpecifyItem(DWORD vnum, DWORD count = 1); LPITEM FindSpecifyItem(DWORD vnum) const; LPITEM FindItemByID(DWORD id) const; diff --git a/src/game/char_item.cpp b/src/game/char_item.cpp index 36b04ec..b051fa5 100644 --- a/src/game/char_item.cpp +++ b/src/game/char_item.cpp @@ -6382,70 +6382,54 @@ LPITEM CHARACTER::FindItemByID(DWORD id) const int CHARACTER::CountSpecifyItem(DWORD vnum) const { int count = 0; - LPITEM item; - for (int i = 0; i < INVENTORY_MAX_NUM; ++i) - { - item = GetInventoryItem(i); - if (NULL != item && item->GetVnum() == vnum) - { - // 개인 상점에 등록된 물건이면 넘어간다. - if (m_pkMyShop && m_pkMyShop->IsSellingItem(item->GetID())) - { - continue; - } - else - { - count += item->GetCount(); - } - } + for (int i = 0; i < INVENTORY_MAX_NUM; ++i) { + LPITEM item = GetInventoryItem(i); + if (!item) continue; + + if (item->GetVnum() != vnum) + continue; + + if (m_pkMyShop && m_pkMyShop->IsSellingItem(item->GetID())) + continue; + + count += item->GetCount(); } return count; } -void CHARACTER::RemoveSpecifyItem(DWORD vnum, DWORD count) +bool CHARACTER::RemoveSpecifyItem(DWORD vnum, DWORD count) { if (0 == count) - return; + return false; - for (UINT i = 0; i < INVENTORY_MAX_NUM; ++i) - { - if (NULL == GetInventoryItem(i)) - continue; + for (UINT i = 0; i < INVENTORY_MAX_NUM; ++i) { + LPITEM item = GetInventoryItem(i); + if (!item) continue; - if (GetInventoryItem(i)->GetVnum() != vnum) + if (item->GetVnum() != vnum) continue; //개인 상점에 등록된 물건이면 넘어간다. (개인 상점에서 판매될때 이 부분으로 들어올 경우 문제!) - if(m_pkMyShop) - { - bool isItemSelling = m_pkMyShop->IsSellingItem(GetInventoryItem(i)->GetID()); - if (isItemSelling) - continue; - } + if (m_pkMyShop && m_pkMyShop->IsSellingItem(item->GetID())) + continue; if (vnum >= 80003 && vnum <= 80007) - LogManager::instance().GoldBarLog(GetPlayerID(), GetInventoryItem(i)->GetID(), QUEST, "RemoveSpecifyItem"); + LogManager::instance().GoldBarLog(GetPlayerID(), item->GetID(), QUEST, "RemoveSpecifyItem"); - if (count >= GetInventoryItem(i)->GetCount()) - { - count -= GetInventoryItem(i)->GetCount(); - GetInventoryItem(i)->SetCount(0); + DWORD item_count = std::min(count, item->GetCount()); + item->SetCount(item->GetCount() - item_count); + count -= item_count; - if (0 == count) - return; - } - else - { - GetInventoryItem(i)->SetCount(GetInventoryItem(i)->GetCount() - count); - return; - } + if (0 == count) return true; } + if (0 == count) return true; + // 예외처리가 약하다. - if (count) - sys_log(0, "CHARACTER::RemoveSpecifyItem cannot remove enough item vnum %u, still remain %d", vnum, count); + sys_log(0, "CHARACTER::RemoveSpecifyItem cannot remove enough item vnum %u, still remain %d", vnum, count); + return false; } int CHARACTER::CountSpecifyTypeItem(BYTE type) const diff --git a/src/game/party.h b/src/game/party.h index 460f275..339c0c6 100644 --- a/src/game/party.h +++ b/src/game/party.h @@ -152,6 +152,9 @@ class CParty inline int ComputePartyBonusAttackGrade(); inline int ComputePartyBonusDefenseGrade(); + TMemberMap::iterator MemberBegin() { return m_memberMap.begin(); } + TMemberMap::iterator MemberEnd() { return m_memberMap.end(); } + template void ForEachMember(Func & f); template void ForEachMemberPtr(Func & f); template void ForEachOnlineMember(Func & f); diff --git a/src/game/questlua_party.cpp b/src/game/questlua_party.cpp index 187ada8..b667aa4 100644 --- a/src/game/questlua_party.cpp +++ b/src/game/questlua_party.cpp @@ -388,6 +388,70 @@ namespace quest return f.vecPIDs.size(); } + int party_check_item(lua_State* L) + { + if (!lua_isnumber(L, 1) || lua_isnumber(L, 2)) { + lua_pushboolean(L, false); + return 1; + } + + uint32_t vnum = lua_tonumber(L, 1); + uint32_t count = lua_tonumber(L, 2); + + LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); + if(!ch) { + lua_pushboolean(L, false); + return 1; + } + + LPPARTY party = ch->GetParty(); + if (!party) { + lua_pushboolean(L, ch->CountSpecifyItem(vnum) >= count); + return 1; + } + + bool success = std::all_of(party->MemberBegin(), party->MemberEnd(), [vnum, count](const auto& pair) { + LPCHARACTER ch = pair.second.pCharacter; + if (!ch) return true; + return ch->CountSpecifyItem(vnum) >= count; + }); + + lua_pushboolean(L, success); + return 1; + } + + int party_remove_item(lua_State* L) + { + if (!lua_isnumber(L, 1) || lua_isnumber(L, 2)) { + lua_pushboolean(L, false); + return 1; + } + + uint32_t vnum = lua_tonumber(L, 1); + uint32_t count = lua_tonumber(L, 2); + + LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); + if (!ch) { + lua_pushboolean(L, false); + return 1; + } + + LPPARTY party = ch->GetParty(); + if (!party) { + lua_pushboolean(L, ch->RemoveSpecifyItem(vnum, count)); + return 1; + } + + bool success = std::all_of(party->MemberBegin(), party->MemberEnd(), [vnum, count](const auto& pair) { + LPCHARACTER ch = pair.second.pCharacter; + if (!ch) return true; + return ch->RemoveSpecifyItem(vnum, count); + }); + + lua_pushboolean(L, success); + return 1; + } + void RegisterPartyFunctionTable() { luaL_reg party_functions[] = @@ -409,6 +473,8 @@ namespace quest { "give_buff", party_give_buff }, { "is_map_member_flag_lt", party_is_map_member_flag_lt }, { "get_member_pids", party_get_member_pids }, // 파티원들의 pid를 return + { "check_item", party_check_item }, + { "remove_item", party_remove_item }, { NULL, NULL } };