Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 56 additions & 3 deletions include/py_Inventory.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,62 @@ class Inventory {
return result;
}

int GetInventoryIDFromAgent(int agent_id) {
return static_cast<int>(GW::Items::GetInventoryIDFromAgent(static_cast<uint32_t>(agent_id)));
}

bool IsInventoryIDValid(int inventory_id) {
return GW::Items::IsInventoryIDValid(static_cast<uint32_t>(inventory_id));
}

int GetEquippedItemID(int inventory_id, int equip_slot) {
return static_cast<int>(GW::Items::GetEquippedItemID(
static_cast<uint32_t>(inventory_id),
static_cast<uint32_t>(equip_slot)));
}

int GetUpgradeSlot(int upgrade_item_id) {
GW::Item* item = GW::Items::GetItemById(static_cast<uint32_t>(upgrade_item_id));
return static_cast<int>(GW::Items::GetUpgradeSlot(item));
}

bool ValidateUpgrade(int target_item_id, int upgrade_item_id) {
if (target_item_id == upgrade_item_id)
return false;
return GW::Items::ValidateUpgrade(
static_cast<uint32_t>(target_item_id),
static_cast<uint32_t>(upgrade_item_id));
}

bool ApplyUpgrade(int inventory_id, int target_item_id, int upgrade_item_id, int upgrade_slot = -1) {
const uint32_t target_inventory_id = static_cast<uint32_t>(inventory_id);
const uint32_t target_item_id_u32 = static_cast<uint32_t>(target_item_id);
const uint32_t upgrade_item_id_u32 = static_cast<uint32_t>(upgrade_item_id);
const bool derive_upgrade_slot = upgrade_slot < 0;
uint32_t upgrade_slot_u32 = derive_upgrade_slot ? 0xffffffff : static_cast<uint32_t>(upgrade_slot);

if (!(target_inventory_id && target_item_id_u32 && upgrade_item_id_u32))
return false;
if (target_item_id_u32 == upgrade_item_id_u32)
return false;
if (!GW::Items::IsInventoryIDValid(target_inventory_id))
return false;
if (derive_upgrade_slot) {
const auto upgrade_item = GW::Items::GetItemById(upgrade_item_id_u32);
upgrade_slot_u32 = GW::Items::GetUpgradeSlot(upgrade_item);
if (!upgrade_slot_u32)
return false;
}
if (!GW::Items::ValidateUpgrade(target_item_id_u32, upgrade_item_id_u32))
return false;

return GW::Items::ApplyUpgrade(
target_inventory_id,
target_item_id_u32,
upgrade_item_id_u32,
upgrade_slot_u32);
}


int GetGoldAmount() {
return GW::Items::GetGoldAmountOnCharacter();
Expand All @@ -139,6 +195,3 @@ class Inventory {


};



2 changes: 2 additions & 0 deletions include/py_party.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ class PyParty {
float GetAllFlagY();
int GetHeroAgentID(int hero_index);
int GetAgentHeroID(int agent_id);
int GetInventorySelectedAgentID();
int GetInventoryEquipmentFrameID();
int GetAgentIDByLoginNumber(int login_number);
std::string GetPlayerNameByLoginNumber(int login_number);
bool SearchParty(uint32_t search_type, std::string advertisement);
Expand Down
7 changes: 6 additions & 1 deletion src/py_Inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ void bind_Inventory(py::module_& m) {
.def("UseItem", &Inventory::UseItem, py::arg("item_id")) // Use an item
.def("DestroyItem", &Inventory::DestroyItem, py::arg("item_id")) // Destroy an item
.def("IdentifyItem", &Inventory::IdentifyItem, py::arg("id_kit_id"), py::arg("item_id")) // Identify an item
.def("GetInventoryIDFromAgent", &Inventory::GetInventoryIDFromAgent, py::arg("agent_id"))
.def("IsInventoryIDValid", &Inventory::IsInventoryIDValid, py::arg("inventory_id"))
.def("GetEquippedItemID", &Inventory::GetEquippedItemID, py::arg("inventory_id"), py::arg("equip_slot"))
.def("GetUpgradeSlot", &Inventory::GetUpgradeSlot, py::arg("upgrade_item_id"))
.def("ValidateUpgrade", &Inventory::ValidateUpgrade, py::arg("target_item_id"), py::arg("upgrade_item_id"))
.def("ApplyUpgrade", &Inventory::ApplyUpgrade, py::arg("inventory_id"), py::arg("target_item_id"), py::arg("upgrade_item_id"), py::arg("upgrade_slot") = -1)

// Get item info
.def("GetHoveredItemID", &Inventory::GetHoveredItemId) // Get hovered item ID
Expand All @@ -139,4 +145,3 @@ PYBIND11_EMBEDDED_MODULE(PyInventory, m) {
bind_SafeBag(m);
bind_Inventory(m);
}

139 changes: 137 additions & 2 deletions src/py_party.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,133 @@

namespace py = pybind11;

namespace {
// Gw_05072026.exe FUN_008ea160 handles 0x100001A8 as the equipment selected-agent getter.
// Older GWCA enums and Gw.wasm still label the same local query as 0x100001A7, so keep fallback probing.
constexpr uint32_t INVENTORY_GET_AGENT_FRAME_MESSAGE_CURRENT = 0x100001A8;
constexpr uint32_t INVENTORY_GET_AGENT_FRAME_MESSAGE_LEGACY = 0x100001A7;
constexpr uint32_t INVENTORY_AGENT_SENTINEL = 0xFFFFFFFF;
constexpr const wchar_t* INVENTORY_EQUIPMENT_FRAME_LABEL = L"Inventory-Equipment";

bool CanProbeInventoryEquipmentFrame() {
const auto instance_type = GW::Map::GetInstanceType();
if (!GW::Map::GetIsMapLoaded()
|| GW::Map::GetIsObserving()
|| instance_type == GW::Constants::InstanceType::Loading) {
return false;
}

const GW::Inventory* inventory = GW::Items::GetInventory();
return inventory && inventory->equipped_items;
}

bool TryReadInventorySelectedAgent(
GW::UI::Frame* frame,
uint32_t get_message_id,
uint32_t* selected_agent_id) {
if (!frame || !selected_agent_id) {
return false;
}

uint32_t candidate_agent_id = INVENTORY_AGENT_SENTINEL;
GW::UI::SendFrameUIMessage(
frame,
static_cast<GW::UI::UIMessage>(get_message_id),
nullptr,
&candidate_agent_id);

if (candidate_agent_id == INVENTORY_AGENT_SENTINEL) {
return false;
}

*selected_agent_id = candidate_agent_id;
return true;
}

GW::UI::Frame* ProbeInventoryEquipmentFrame(
uint32_t* selected_agent_id = nullptr,
uint32_t* selected_frame_id = nullptr) {
if (!CanProbeInventoryEquipmentFrame()) {
return nullptr;
}

const auto try_frame = [&](
GW::UI::Frame* frame,
uint32_t get_message_id,
bool accept_zero_agent) -> bool {
if (!frame || !frame->IsCreated()) {
return false;
}

uint32_t candidate_agent_id = INVENTORY_AGENT_SENTINEL;
if (!TryReadInventorySelectedAgent(frame, get_message_id, &candidate_agent_id)) {
return false;
}
if (!accept_zero_agent && candidate_agent_id == 0) {
return false;
}

if (selected_agent_id) {
*selected_agent_id = candidate_agent_id;
}
if (selected_frame_id) {
*selected_frame_id = frame->frame_id;
}
return true;
};

GW::UI::Frame* labeled_frame = GW::UI::GetFrameByLabel(INVENTORY_EQUIPMENT_FRAME_LABEL);
if (try_frame(labeled_frame, INVENTORY_GET_AGENT_FRAME_MESSAGE_CURRENT, true)
|| try_frame(labeled_frame, INVENTORY_GET_AGENT_FRAME_MESSAGE_LEGACY, true)) {
return labeled_frame;
}

const std::vector<uint32_t> frame_ids = GW::UI::GetFrameArray();
const auto scan_message = [&](uint32_t get_message_id, bool accept_zero_agent) -> GW::UI::Frame* {
for (const uint32_t frame_id : frame_ids) {
GW::UI::Frame* frame = GW::UI::GetFrameById(frame_id);
if (try_frame(frame, get_message_id, accept_zero_agent)) {
if (selected_frame_id) {
*selected_frame_id = frame_id;
}
return frame;
}
}
return nullptr;
};

GW::UI::Frame* frame = scan_message(INVENTORY_GET_AGENT_FRAME_MESSAGE_CURRENT, true);
if (frame) {
return frame;
}

// Legacy getter can return zero from unrelated root frames; require a real agent there.
return scan_message(INVENTORY_GET_AGENT_FRAME_MESSAGE_LEGACY, false);
}

uint32_t ReadInventorySelectedAgent() {
if (!CanProbeInventoryEquipmentFrame()) {
return 0;
}

uint32_t selected_agent_id = INVENTORY_AGENT_SENTINEL;
if (ProbeInventoryEquipmentFrame(&selected_agent_id) && selected_agent_id != INVENTORY_AGENT_SENTINEL) {
return selected_agent_id;
}
return 0;
}

uint32_t ResolveInventoryEquipmentFrameID() {
if (!CanProbeInventoryEquipmentFrame()) {
return 0;
}

uint32_t frame_id = 0;
ProbeInventoryEquipmentFrame(nullptr, &frame_id);
return frame_id;
}
}

const std::unordered_map<int, std::pair<std::string, int>> Hero::hero_data = {
{0, {"None", static_cast<int>(ProfessionType::None)}},
{1, {"Norgu", static_cast<int>(ProfessionType::Mesmer)}},
Expand Down Expand Up @@ -370,6 +497,14 @@ int PyParty::GetHeroAgentID(int hero_index) {
return GW::PartyMgr::GetHeroAgentID(hero_index);
}

int PyParty::GetInventorySelectedAgentID() {
return static_cast<int>(ReadInventorySelectedAgent());
}

int PyParty::GetInventoryEquipmentFrameID() {
return static_cast<int>(ResolveInventoryEquipmentFrameID());
}

int PyParty::GetAgentHeroID(int agent_id) {
return GW::PartyMgr::GetAgentHeroID(agent_id);
}
Expand Down Expand Up @@ -586,6 +721,8 @@ void bind_PyParty(py::module_& m) {
.def("GetAllFlagX", &PyParty::GetAllFlagX) // Bind GetAllFlagX method
.def("GetAllFlagY", &PyParty::GetAllFlagY) // Bind GetAllFlagY method
.def("GetHeroAgentID", &PyParty::GetHeroAgentID, py::arg("hero_index")) // Bind GetHeroAgentID method
.def("GetInventorySelectedAgentID", &PyParty::GetInventorySelectedAgentID)
.def("GetInventoryEquipmentFrameID", &PyParty::GetInventoryEquipmentFrameID)
.def("GetAgentHeroID", &PyParty::GetAgentHeroID, py::arg("agent_id")) // Bind GetAgentHeroID method
.def("GetAgentIDByLoginNumber", &PyParty::GetAgentIDByLoginNumber, py::arg("login_number"))
.def("GetPlayerNameByLoginNumber", &PyParty::GetPlayerNameByLoginNumber, py::arg("login_number")) // Bind GetPlayerNameByLoginNumber method
Expand Down Expand Up @@ -628,5 +765,3 @@ PYBIND11_EMBEDDED_MODULE(PyParty, m) {
BindPetInfo(m);
bind_PyParty(m);
}


16 changes: 16 additions & 0 deletions vendor/gwca/Include/GWCA/Managers/ItemMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,22 @@ namespace GW {
// Identify an item
GWCA_API bool IdentifyItem(uint32_t identification_kit_id, uint32_t item_id);

// Resolve the player or hero inventory id backing an agent's equipment panel.
GWCA_API uint32_t GetInventoryIDFromAgent(uint32_t agent_id);

// Returns whether a native inventory id is present in the client's inventory table.
GWCA_API bool IsInventoryIDValid(uint32_t inventory_id);

// Returns the item id equipped in a native equipment slot for an inventory id.
GWCA_API uint32_t GetEquippedItemID(uint32_t inventory_id, uint32_t equip_slot, bool* active = nullptr);

// Returns the native upgrade slot encoded by an upgrade item's interaction flags.
GWCA_API uint32_t GetUpgradeSlot(const Item* upgrade_item);

// Validate and apply a rune/upgrade component to a target item.
GWCA_API bool ValidateUpgrade(uint32_t target_item_id, uint32_t upgrade_item_id);
GWCA_API bool ApplyUpgrade(uint32_t inventory_id, uint32_t target_item_id, uint32_t upgrade_item_id, uint32_t upgrade_slot = 0xffffffff);

// Cancel the current salvage session
GWCA_API bool SalvageSessionCancel();

Expand Down
Loading