rabukasim / docs /interaction_patterns.md
trioskosmos's picture
chore: remove large files for HF Space
9bd4ce5
# LovecaSim: Interaction Cheat Sheet
> [!NOTE]
> This document details the interaction flow between the **Rust Engine** and the **Frontend**, specifically how abilities pause (suspend) for user input.
## Opcode Categorization
### 1. Automatic (Non-Interactive)
These opcodes resolve immediately without stopping the interpreter.
- `O_DRAW`: Draws cards to hand.
- `O_BOOST`: Adds to score bonus.
- `O_BUFF` / `O_BLADES`: Adds power/blades to members.
- `O_ACTIVATE_ENERGY`: Untaps energy cards.
- `O_NEGATE`: Marks triggers as negated.
- `O_CHARGE`: Untaps energy from deck.
### 2. Mandatory Choices (Suspends)
These opcodes **always** pause and wait for an `ACTION_ID` response.
- `O_SELECT_MODE`: Opens a modal for branching logic. (ID Range: `570+`)
- `O_COLOR_SELECT`: Opens a color picker. (ID Range: `580-585`)
- `O_TAP_O`: Requests selection of an opponent's stage slot. (ID Range: `600-602`)
### 3. Dynamic Choices (Context Dependent)
These opcodes may skip interaction if only one valid target exists, or if certain attributes are set.
- `O_PAY_ENERGY`:
- **Automatic**: If no optional bit is set, it auto-taps.
- **Interactive**: If `attr & 0x82` is set, it asks "Pay Energy?" (ID Range: `550-551`).
- `O_LOOK_AND_CHOOSE` (List Selection):
- Opens a card list overlay. (ID Range: `600+`)
- `O_TAP_M`:
- **Automatic**: If selecting "Self" or only one member.
- **Interactive**: If `attr & 0x02` is set, it asks for a specific member.
## Action ID Reference Table
| Range | Context | Usage |
| :--- | :--- | :--- |
| `0` | Global Skip | Discard remaining looked cards, skip optional cost, "No" to promt. |
| `500-559` | Hand | Selecting a card currently in hand. |
| `560-569` | Generic | Resumption signals. |
| `570-579` | Modal Mode | Choosing Option A/B/C from `SELECT_MODE`. |
| `580-585` | Modal Color | Pink(0), Red(1), Yellow(2), Green(3), Blue(4), Purple(5). |
| `600-602` | Stage Slots | Left, Mid, Right (Self or Opponent). |
| `600-659` | List Index | Choosing the N-th card in a "Looked Cards" or "Discard" list. |
## Resumption Logic in `interpreter.rs`
When an opcode calls `suspend_interaction`, the following happens:
1. `state.phase` shifts to `Phase::Response`.
2. A `PendingInteraction` is pushed to the stack containing the `program_counter` (IP) of the CURRENT instruction.
3. The engine returns controle to the caller.
4. The caller (Frontend/Server) must send a `step(action_id)` call to resume.
5. `resolve_bytecode` restarts from the stored IP, injecting the `action_id` into `ctx.choice_index`.
## State Transparency (The Visibility Gap)
The following engine states are **not** currently surfaced through the main Action serialization:
| Gap | Description | Impact |
| :--- | :--- | :--- |
| **Passive Stats** | Constant power/blade buffs from other members. | Card value in sidebar might not match calculated logic. |
| **Queue Depth** | How many abilities are still waiting to resolve. | Player doesn't know "one more popup is coming". |
| **Filter Logic** | Why a specific card is selectable (or not). | Debugging complex filters (e.g., "Member of Unit X with Cost >= 3"). |
| **Progress Count**| "Pick 1 of 3" status during multi-picks. | Action label is generic (e.g., "Select Slot 1"). |
### Recommended Verifications
- **For Passives**: Manually inspect `player.blade_buffs` or `player.heart_buffs` in the engine log.
- **For Filters**: Cross-reference the `filter_attr` bitmask with `logic.rs:card_matches_filter`.
- **For Queue**: Check `gs.pending_abilities.len()` in the debugger.