# Retail inventory weapon-switch pseudocode ## Scope Inventory double-click of a weapon while another primary weapon is equipped, in both peace and combat modes. The UI request sequence is shared; combat-mode animation remains server-authoritative. ## Retail oracle - `ItemHolder::DetermineUseResult @ 0x00588460` classifies an owned combat-use item as `WieldRight`. - `CPlayerSystem::UsingItem @ 0x00562F70` dispatches that result to `AutoWield(item, SLOT_SIDE_RIGHT, 0, 1, 0, 1)`. - `CPlayerSystem::AutoWield @ 0x00560A60` treats `0x03500000` (`MeleeWeapon | MissileWeapon | Held | TwoHanded`) as one weapon-ready group. If occupied, it records the requested item, sends the blocking weapon to the player container, and does not wield the requested item yet. - `CPlayerSystem::RecvNotice_ServerSaysMoveItem @ 0x00563260` retries `AutoWield` only after the server confirms the blocking item moved. - `ACCWeenieObject::UIAttemptWield @ 0x0058D590` sends `GetAndWieldItem(item, equipMask)`. - `ClientCombatSystem::OnQualityChanged @ 0x0056C1B0` reads player PropertyInt 40 (`CombatMode`) and applies it through `SetCombatMode`. Addresses are from `docs/research/named-retail/symbols.json`; pseudo-C is in `docs/research/named-retail/acclient_2013_pseudo_c.txt`. ## Cross-reference - ACE `Player_Inventory.cs` says the client normally sends the conflicting item's dequip before `GetAndWieldItem`. `TryShuffleStance` changes a player who is already in combat to Missile, Magic, or Melee after the new item is equipped; it leaves a player in peace mode in peace. - ACE `Creature_Combat.cs::SwitchCombatStyles` performs the visible old-stance -> peace -> new-stance motion chain and sends `PrivateUpdatePropertyInt(CombatMode, ...)`. - holtburger independently confirms the action/event shapes: `GetAndWieldItem { item_guid, equip_mask }`, `WieldObject`, and PropertyInt 40 as `CombatMode`. ## Faithful pseudocode ```text on inventory item double-click(item): decision = DetermineUseResult(item) if decision is WieldRight or WieldLeft or AutoSort: auto_wield(item) auto_wield(item): if another auto-wield transaction is waiting for the server: consume the request without sending another inventory action if item has no valid equip location or is already equipped: return false if item.validLocations intersects WEAPON_READY_MASK: desiredMask = item.validLocations & WEAPON_READY_MASK blocker = player's equipped item intersecting WEAPON_READY_MASK if blocker exists: pending = (requestedItem = item.id, blockingItem = blocker.id) send PutItemInContainer(blocker.id, player.id, placement = 0) return true send_wield(item, desiredMask) return true use the existing retail slot/auto-wear selection rules send_wield(item, selectedMask) on server-confirmed item move(blocker): if blocker matches pending.blockingItem and blocker is now loose in the player's main pack: requested = pending.requestedItem clear pending before re-entry auto_wield(requested) on server inventory-request failure(item, error): if item matches pending.blockingItem or pending.requestedItem: clear pending send_wield(item, mask): update the retained inventory/paperdoll projection optimistically send GetAndWieldItem(item.id, mask) on PrivateUpdatePropertyInt(property = CombatMode, value): if value is exactly NonCombat, Melee, Missile, or Magic: CombatState.SetCombatMode(value) ``` ## Animation ownership The client must not synthesize a local bow-to-sword animation. In peace mode, ACE leaves `CombatMode` as `NonCombat`. In combat mode, ACE selects the new weapon's stance and sends the authoritative motion stream plus PropertyInt 40. The inventory controller only sequences the two wire requests and waits for the old weapon's confirmed move; the existing motion and equipped-child render paths consume the server events. ## Known remaining retail surface This port covers the primary weapon-ready group requested here. Retail `AutoWield` also has extra blocker logic for incompatible shields and missile ammo, plus its full `AutoWieldIsLegal` requirement checks. Those pre-existing paperdoll/auto-wield gaps remain tracked by divergence row AP-108 rather than being guessed from incomplete item properties.