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
110 changes: 103 additions & 7 deletions Py4GWCoreLib/Inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import PyInventory
from typing import TypedDict, cast

from Py4GWCoreLib.enums_src.Item_enums import Bags
from Py4GWCoreLib.enums_src.Item_enums import (
Bags,
)

from .Item import Item
from .ItemArray import ItemArray
Expand Down Expand Up @@ -317,6 +319,106 @@ def IdentifyItem (item_id, id_kit_id):
inventory = PyInventory.PyInventory()
inventory.IdentifyItem(id_kit_id, item_id)

@staticmethod
def GetInventoryIDFromAgent(agent_id: int) -> int:
"""
Purpose: Resolve the native inventory ID used by the equipment panel for a player or hero agent.
Args:
agent_id (int): Agent ID of the player or hero.
Returns: int: Native inventory ID, or 0 if unavailable.
"""
return int(Inventory.inventory_instance().GetInventoryIDFromAgent(agent_id))

@staticmethod
def IsInventoryIDValid(inventory_id: int) -> bool:
"""
Purpose: Check whether a native inventory ID exists in the client's inventory table.
Args:
inventory_id (int): Native inventory ID.
Returns: bool: True if the inventory ID can be used by native inventory calls.
"""
return bool(Inventory.inventory_instance().IsInventoryIDValid(inventory_id))

@staticmethod
def GetEquippedItemID(inventory_id: int, equip_slot: int) -> int:
"""
Purpose: Return the item ID equipped in a native equipment slot.
Args:
inventory_id (int): Native inventory ID.
equip_slot (int): Native equipment slot.
Returns: int: Equipped item ID, or 0 if unavailable.
"""
return int(Inventory.inventory_instance().GetEquippedItemID(inventory_id, equip_slot))

@staticmethod
def GetUpgradeSlot(upgrade_item_id: int) -> int:
"""
Purpose: Return the native upgrade slot encoded by an upgrade item's interaction flags.
Args:
upgrade_item_id (int): Rune/upgrade item ID.
Returns: int: Native upgrade slot, or 0 if the item is not a supported upgrade.
"""
return int(Inventory.inventory_instance().GetUpgradeSlot(upgrade_item_id))

@staticmethod
def ValidateUpgrade(target_item_id: int, upgrade_item_id: int) -> bool:
"""
Purpose: Ask the native client whether an upgrade item can be applied to a target item.
Args:
target_item_id (int): Target armor/weapon item ID.
upgrade_item_id (int): Rune/upgrade item ID.
Returns: bool: True if the native validation accepts the pair.
"""
return bool(Inventory.inventory_instance().ValidateUpgrade(target_item_id, upgrade_item_id))

@staticmethod
def ApplyUpgrade(
inventory_id: int,
target_item_id: int,
upgrade_item_id: int,
upgrade_slot: int | None = None,
target_agent_id: int = 0,
) -> bool:
"""
Purpose: Request the native UI upgrade flow for a target item.
Args:
inventory_id (int): Native inventory ID containing the target item.
target_item_id (int): Target armor/weapon item ID.
upgrade_item_id (int): Rune/upgrade item ID.
upgrade_slot (int | None, optional): Native upgrade slot. None lets this helper derive it;
explicit 0 is forwarded for native insignia upgrade orders.
target_agent_id (int, optional): Agent ID that owns the target inventory.
Returns: bool: True if the native UI order request was sent.
"""
try:
inventory_id = int(inventory_id or 0)
target_item_id = int(target_item_id or 0)
upgrade_item_id = int(upgrade_item_id or 0)
derive_upgrade_slot = upgrade_slot is None
upgrade_slot = 0 if derive_upgrade_slot else int(upgrade_slot or 0)
target_agent_id = int(target_agent_id or 0)
except Exception:
return False

if not (inventory_id and target_item_id and upgrade_item_id and target_agent_id):
return False
if target_item_id == upgrade_item_id:
return False
if not Inventory.IsInventoryIDValid(inventory_id):
return False
if derive_upgrade_slot:
upgrade_slot = Inventory.GetUpgradeSlot(upgrade_item_id)
if not upgrade_slot:
return False
if not Inventory.ValidateUpgrade(target_item_id, upgrade_item_id):
return False
return bool(Inventory.inventory_instance().ApplyUpgrade(
inventory_id,
target_item_id,
upgrade_item_id,
upgrade_slot,
))

@staticmethod
def IdentifyFirst():
"""
Expand Down Expand Up @@ -1590,9 +1692,3 @@ def WithdrawItemFromStorage(item_id, quantity=250):
return True

return moved_any






18 changes: 18 additions & 0 deletions Py4GWCoreLib/Party.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,24 @@ def GetHeroAgentIDByPartyPosition(hero_position):
"""
return Party.party_instance().GetHeroAgentID(hero_position)

@staticmethod
def GetInventorySelectedAgentID():
"""
Retrieve the agent ID currently selected in the inventory equipment panel.
Args: None
Returns: int
"""
return Party.party_instance().GetInventorySelectedAgentID()

@staticmethod
def GetInventoryEquipmentFrameID():
"""
Retrieve the native frame ID for the inventory equipment panel.
Args: None
Returns: int
"""
return Party.party_instance().GetInventoryEquipmentFrameID()

@staticmethod
@frame_cache(category="Party.Heroes", source_lib="GetHeroAgentIDByHeroID")
def GetHeroIDByAgentID(agent_id):
Expand Down
49 changes: 49 additions & 0 deletions Py4GWCoreLib/enums_src/Item_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,55 @@ def is_weapon_type_literal(item_type: ItemType) -> TypeIs[WeaponType]:
ArmorType: TypeAlias = Literal[ItemType.Headpiece, ItemType.Chestpiece, ItemType.Gloves, ItemType.Leggings, ItemType.Boots, ItemType.Salvage]
ARMOR_TYPES = frozenset(cast(tuple[ItemType, ...], get_args(ArmorType)))

RUNE_MOD_ITEM_TYPE = ItemType.Rune_Mod.value

ARMOR_RUNE_UPGRADE_SLOT = 1
ARMOR_INSIGNIA_UPGRADE_SLOT = 7
ARMOR_UPGRADE_SLOTS = frozenset((ARMOR_RUNE_UPGRADE_SLOT, ARMOR_INSIGNIA_UPGRADE_SLOT))
ARMOR_EQUIPMENT_SLOTS = (
("Chest", 2),
("Leggings", 3),
("Head", 4),
("Boots", 5),
("Gloves", 6),
)

EQUIPPED_WEAPON_SLOTS = (
("main hand", 0),
("offhand", 1),
)

WEAPON_UPGRADE_CLASSIFICATION_SLOT = 6
WEAPON_PREFIX_REQUEST_SLOT = 0
WEAPON_SUFFIX_REQUEST_SLOT = 1
WEAPON_INSCRIPTION_REQUEST_SLOT = 2
WEAPON_UPGRADE_REQUEST_SLOTS = {
"prefix": WEAPON_PREFIX_REQUEST_SLOT,
"suffix": WEAPON_SUFFIX_REQUEST_SLOT,
"inscription": WEAPON_INSCRIPTION_REQUEST_SLOT,
}

WEAPON_PREFIX_NAME_MARKERS = (
"axe haft",
"bowstring",
"bow string",
"dagger tang",
"hammer haft",
"scythe snathe",
"spearhead",
"spear head",
"staff head",
"sword hilt",
)

WEAPON_SUFFIX_NAME_MARKERS = (
"focus core",
"grip",
"handle",
"pommel",
"wrapping",
)

ITEM_TYPE_META_TYPES: dict[ItemType, list[ItemType]] = {
ItemType.Weapon: [
ItemType.Axe,
Expand Down
3 changes: 3 additions & 0 deletions Py4GWCoreLib/enums_src/UI_enums.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from enum import Enum
from enum import IntEnum

INVENTORY_EQUIPMENT_FRAME_LABEL = "Inventory-Equipment"
INVENTORY_SET_AGENT_FRAME_MESSAGE = 0x56


#region ImguiFonts
class ImguiFonts(IntEnum):
Expand Down
Loading