Skip to content

01 Prototype 08 Item Manager

github-actions[bot] edited this page Jun 3, 2026 · 2 revisions

Runtime layer behind 08-items.md. Role logic lives in tech/06-roles.md, fixtures in 08-fixtures.md, kit passive friendship in 08-kit.md, balls in 08-balls.md.

Dependencies: Effect System (07), Items (08-items.md), Venue (08-venue.md), Shop Drag-and-Drop (04-shop-drag-drop.md).


Data model

Ownership lives on ProgressionData.item_levels. Court placement is a second field; kit membership is derived.

# role (ball/court/equipment) -> ordered array of item keys
var on_court: Dictionary[StringName, Array] = {}

var destroyed_items: Array[String] = []
var kit_accumulated_points: float = 0.0   # see 08-kit.md
var kit_last_tick_unix: int = 0

Destruction sets item_levels[key] = 0 and appends to destroyed_items.

Derived queries

func get_court_items() -> Array[String]
func get_kit_items() -> Array[String]
func is_on_court(item_key: String) -> bool
func role_occupants(role: StringName) -> Array[String]

Activate and deactivate

func activate(item_key: String) -> bool
func deactivate(item_key: String) -> bool

Both are called by drag-and-drop handlers (see 08-kit.md for the player-side flow per role).

Activate

  1. Reject if destroyed, not owned, or already on the court.
  2. Append to on_court[role].
  3. _effect_manager.register_source(item, level).
  4. If role == &"court", FixtureManager spawns the prop (see 08-fixtures.md). For ball and equipment, the parent scene (ball rack or paddle) hosts the prop directly; no fixture manager involvement.
  5. Save. Emit court_changed.

Activation has no friendship cost; the friction is the animation beat on equipment.

Deactivate

Applies to ball and equipment only. Reverse of activate: unregister effects, remove from on_court.

Court items never call deactivate. They leave the court only by entering the Tinkerer's queue (see 08-tinkerer.md); on return from a level-up commission, activate re-seats them.

_set_level refactor

  • purchase() writes item_levels only. If the item is on the court, re-register its effects at the new level.
  • take() stays inert.
  • activate is the only path that registers effects.

Dev panel uses purchase_and_place(key) to preserve the one-click flow.

SH-93

Closes when activate lands. TakeBox.accept stays inert by design; the player drags the item from BallRack or GearRack to activate it.


Signals

signal court_changed

Existing soul_balance_changed and item_level_changed are unchanged.


Testing

  • activate / deactivate state transitions and friendship debits.
  • Role occupancy (append, remove, overflow stack).
  • Kit passive friendship (see 08-kit.md).
  • Ball reconciliation (see 08-balls.md).

Rough ticket outline

Not filing yet.

  1. Court/kit data model, derived queries, signals.
  2. activate / deactivate, _set_level refactor, dev-panel update, SH-93 close-out.

Clone this wiki locally