adventure: ask 7 — apply web equipment management (poll half)

Mirror of Pete's ask 7. gogobee polls the equip queue and applies the new
actions against the five standard gear slots:
  - equip: routes MasterworkGear/ArenaGear to applyMasterworkEquip (evicts
    any special occupant back to the pack; downgrade-blocked), else the
    existing applyMagicEquip.
  - unequip: EquipmentSlot vocabulary -> applyMasterworkUnequip (resets the
    slot to its tier-0 default, keeps the row), else applyMagicUnequip.
  - upgrade: purchaseEquipmentTier, euro-idempotent (DebitIdem keyed on the
    order GUID), downgrade + max-tier guarded.
  - repair: repair(), euro-idempotent, recomputes blacksmithRepairCost.

Detail push now carries Slots (EquipSlotView x5) + Balance; itemViews gives
masterwork/arena backpack rows an equip id; the compare decorator is guarded
to magic-only. buildDetailSnapshot is a method so it can read the euro balance.

Retry-safety: no CreditIdem refund on a later save fault (would double-pay a
guid-guarded retry) — we return retry=true and let the next poll re-run, since
the debit is guid-idempotent and the slot write is idempotent. Matches the
casino escrow precedent. Unit tests cover downgrade block, max-tier,
insufficient funds, idempotent replay, eviction, and take-off reset.

Deploy AFTER Pete: Pete's ingest must accept the new verdict strings before
this side emits them.
This commit is contained in:
prosolis
2026-07-17 20:34:56 -07:00
parent b29dcf4360
commit 68c8cdff2d
6 changed files with 716 additions and 6 deletions

View File

@@ -388,6 +388,31 @@ type PlayerDetail struct {
Equipped []ItemView `json:"equipped,omitempty"`
House HouseView `json:"house"`
Pets []PetView `json:"pets,omitempty"`
// Slots is the 5 standard equipment slots (weapon/armor/helmet/boots/tool) for
// the web management panel. Worn masterwork/arena pieces surface here (via
// CanTakeOff), not in Equipped, which stays magic-only (the DnD slots).
Slots []EquipSlotView `json:"slots,omitempty"`
// Balance is the owner's euro balance, for the web's upgrade/repair confirm.
Balance float64 `json:"balance,omitempty"`
}
// EquipSlotView is one of the 5 standard equipment slots, carrying what the web
// management panel needs: what's worn now, whether it round-trips to the pack
// (masterwork/arena), the next tier's name and price for an upgrade offer, and a
// repair cost when the piece is damaged. Pete renders it and trusts only these
// facts — a client-forged tier or price is resolved back against this view.
type EquipSlotView struct {
Slot string `json:"slot"` // weapon|armor|helmet|boots|tool
Name string `json:"name"`
Tier int `json:"tier"`
Condition int `json:"condition"`
Masterwork bool `json:"masterwork,omitempty"`
ArenaTier int `json:"arena_tier,omitempty"`
CanTakeOff bool `json:"can_take_off,omitempty"` // masterwork/arena → round-trippable
NextTier int `json:"next_tier,omitempty"` // 0 = at max tier (5)
NextName string `json:"next_name,omitempty"`
NextPrice float64 `json:"next_price,omitempty"`
RepairCost int `json:"repair_cost,omitempty"` // 0 = full condition
}
// ItemView is one item in the private panels — backpack, vault, or worn.
@@ -692,7 +717,8 @@ type EquipOrder struct {
ItemID int64 `json:"item_id"`
ItemName string `json:"item_name"`
Slot string `json:"slot"`
Action string `json:"action"`
Action string `json:"action"` // equip / unequip / upgrade / repair
Tier int `json:"tier"` // upgrade target tier (an EquipmentSlot tier); unused by the others
Status string `json:"status"`
CreatedAt int64 `json:"created_at"`
}