rabukasim / docs /ENGINE_LOGIC.md
trioskosmos's picture
Upload folder using huggingface_hub
463f868 verified

Engine Logic and Phases

This document provides a technical overview of how the game engine (Rust implementation in engine_rust_src/) manages the game lifecycle, phase transitions, and ability triggers.

Core Architecture

The engine is built around a GameState struct. The primary entry point for game progression is the step function, which maps player actions to state changes based on the current Phase.

GameState Struct

pub struct GameState {
    pub players: [PlayerState; 2],
    pub phase: Phase,
    pub current_player: u8,
    pub first_player: u8,
    pub turn: u32,
    pub seed: u64,
    // ... (internal state like pending contexts for Response phase)
}

Phase Enum

The game flows through discrete phases defined in logic.rs. These align with the Comprehensive Rules (v1.04).

Code Phase Rule Ref Description
-2 Setup 6.1 Initial state before decks are loaded.
-1, 0 Mulligan 6.2.1.6 Choosing cards to redraw.
1 Active 7.4 Untapping cards (7.4.1) and triggering TurnStart (7.4.2).
2 Energy 7.5 Playing energy from hand or energy deck.
3 Draw 7.6 Drawing the turn card.
4 Main 7.7 Main interaction window (Play/Activate).
5 LiveSet 8.2 Setting live cards (hidden) and drawing (8.2.2).
6, 7 Performance 8.3 Score calculation, Yell (8.3.11), and Judgment.
8 LiveResult 8.4 Victory determination (8.4.6) and cleanup.
10 Response N/A Internal: Engine waiting for selection input (Rule 9.6.2.2).

Game Lifecycle & Transitions

1. Typical Turn Flow

The standard turn sequence is implemented in the step function, which dispatches to phase-specific handlers:

// logic.rs: step() handles the high-level orchestration
match self.phase {
    Phase::Active => { self.do_active_phase(db); },
    Phase::Energy => { /* Handles action IDs 550-555 */ },
    Phase::Draw => { self.do_draw_phase(); },
    Phase::Main => { /* Handles play/activate actions */ },
    Phase::LiveSet => { self.set_live_cards(db, card_ids); },
    // ...
}

2. Live & Performance (Rule 8.3)

During the Performance phase, the engine calculates:

  • Total Blades: Sum of get_effective_blades from active members.
  • Yell (Rule 8.3.11): Moving cards from main deck to resolving area based on blades.
  • Total Hearts (Rule 8.3.14): Sum of member hearts and yelled hearts.
  • Icon Check: Volume icons added to the turn's total score.
// Rule 11.4: Trigger [ライブ開始時] (On Live Start)
self.trigger_abilities(db, TriggerType::OnLiveStart, &ctx);

Ability Trigger System

Abilities are triggered by the trigger_abilities function. It checks all members on stage and in specific contexts.

Trigger Timing

pub enum TriggerType {
    OnPlay,         // Rule 11.3: When played to stage slot
    OnLiveStart,    // Rule 11.4: [ライブ開始時]
    OnLiveSuccess,  // Rule 11.5: [ライブ成功時]
    TurnStart,      // Rule 7.4.2: Start of Active phase
    TurnEnd,        // Rule 8.4.10: [ターンの終わりに] (Placeholder)
    OnReveal,       // During Yell process (Rule 8.3.11)
    OnLeaves,       // When leaving stage (Placeholder)
    OnPositionChange,// During O_MOVE_MEMBER / O_SWAP_CARDS
    Activated,      // Manual activation in Main phase
    Constant,       // Passive effects (Rule 9.1.1.3)
}

The "Response" Mechanism (Rule 9.6.2.2)

When an ability requires user input (e.g. O_SELECT_MODE), the engine sets the phase to Response to pause execution:

// Rule 9.6.2.2: Pausing for choice
if self.phase != Phase::Response && bytecode_needs_early_pause(&ab.bytecode) {
    self.phase = Phase::Response;
    self.pending_ctx = Some(ctx.clone());
    return Ok(());
}

Implementation Nuances & Rule Divergences

While the engine follows the Rule 1.04 closely, there relate a few implementation-specific details:

1. First Player Toggle (Divergence)

According to Rule 8.4.13, the winner of a live performance becomes the first player for the next turn. If no player wins uniquely, the current first player continues.

  • Current Logic: The engine currently toggles first_player every turn in finalize_live_result for balance if no specific winner logic overrides it.

2. Placeholder Triggers

The following TriggerType variants are defined in enums.rs and labeled in logic.rs but are not yet actively fired by the main loop:

  • TurnEnd: Rule 8.4.10 logic is partially implemented but the explicit trigger call is pending.
  • OnLeaves: Reserved for future "Leaves Stage" abilities.

3. Opcode Availability

  • Active: O_DRAW, O_HEARTS, O_MOVE_MEMBER, O_SWAP_CARDS, O_BATON_MOD, O_SELECT_MODE, etc.
  • Reserved: O_META_RULE (currently a NO-OP), O_ADD_CONTINUOUS.

Special Logic: hardcoded.rs

Optimized implementations for complex card interactions are in hardcoded.rs. This allows the engine to handle edge cases that are difficult to represent in generic bytecode.

// hardcoded.rs example
match (card_id, ab_idx) {
    (0, 1) => {
        state.players[p_idx].live_score_bonus += 3;
        true
    },
}

Technical Resources