acdream/docs/superpowers/specs/2026-08-26-mosstank-autocombat-design.md

95 lines
3.9 KiB
Markdown

# MossTank autocombat design
Date: 2026-08-26
## Outcome
Ship the first VTank-class MossTank milestone: a polished in-client controller
that performs safe automatic melee, missile or direct-spell combat while all
policy remains in the plugin and all authoritative state/actions remain in
Runtime.
## Architecture
```text
Runtime canonical owners
entity directory + object table + selection + combat + spellbook
|
v
AppAutomationSurface (borrowed projection, no ownership)
PluginCombatTarget[] + PluginCombatSnapshot + attempt commands
|
v
MossTank CombatController (policy/state machine)
scan -> score/lock -> mode -> charge/cast -> wait -> repeat
|
v
retained plugin panel (bindings only)
```
`AcDream.Plugin.Abstractions` stays BCL-only. New interfaces use records,
enums, arrays/lists and primitives only. Existing interfaces gain default
members where needed so API v1 plugins remain loadable.
## API additions
- `PluginCombatTarget`: id, name, weenie class, distance, signed relative
angle, health-known and health fraction.
- `PluginCombatSnapshot`: selected id, mode, charge/request state, power and
server-pending state.
- `ICombatAutomation`: immutable hostile snapshot plus explicit mode,
begin/release/abort attempts.
- `ISpellCatalog.KnownAttackSpells`: learned, direct offensive spells.
- `IAutomationSurface.Combat`: the combat group.
Attempt results distinguish unavailable, invalid target, wrong mode, busy,
transition started and sent/started. This avoids `bool` APIs whose `false`
cannot tell a plugin whether to wait, retry, reselect or stop.
## Target snapshots
`RuntimeHostileTargetQuery` is extended with a snapshot capture method. It
borrows the same entity directory and `ClientObjectTable` used by gameplay,
filters with the same `CombatTargetPolicy`, and computes distance and relative
heading using retail's `MoveToMath` helpers. Hidden, no-draw, dead and
cell-less entities are excluded. The App surface refreshes at bounded cadence
and publishes one immutable list reference; retained UI reads do not scan the
world or allocate.
## Combat controller
States:
1. `Off`: no automation command may be emitted.
2. `Acquire`: keep a valid lock or choose the lowest score.
3. `Mode`: request the equipped default combat mode and wait for confirmation.
4. `PhysicalCharge`: select, set power, press height, then wait until the
canonical meter reaches desired power before release.
5. `MagicCast`: select and cast the chosen known offensive spell.
6. `Wait`: wait while physical server response, repeat state or magic busy is
active, then reacquire/repeat.
Target scoring first applies ordered rules (initial slice supplies a default
priority and an ignore-name list), then applies the configured selection
method. Target lock keeps the current target while it remains admissible.
The controller never fabricates success. Health and disappearance retire a
target; timeouts return to `Acquire`; session loss transitions to `Off` and
aborts an in-progress physical build.
## UI
The main window becomes a dashboard rather than a single force-buff button:
macro toggle, current target/mode, state, vitals, combat settings, buff action
and settings navigation. Generic markup gains bound child visibility/enabled
and color/style attributes so active controls read as active without App types
leaking into the plugin.
## Verification
- pure controller tests for selection policies, lock, mode transition,
charge/release, busy suppression, magic choice, disable and session loss;
- Runtime query tests for filter, range, distance, relative angle and health;
- App projection tests for caching and command mapping where practical;
- markup parser tests for new generic bindings;
- MossTank, Runtime, App and complete Release solution gates.