File size: 3,559 Bytes
9bd4ce5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 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.