File size: 4,739 Bytes
463f868
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use crate::core::enums::Phase;
use crate::core::logic::*;
use crate::test_helpers::{load_real_db, Action};
use smallvec::smallvec;

#[test]
fn verify_on_reveal_trigger() {
    let db = load_real_db();
    let mut state = GameState::default();
    state.ui.silent = true;

    // Card ID 454: ダイスキだったらダイジョウブ! (Live)
    // Ability: ON_REVEAL -> MOVE_TO_DISCARD etc.
    state.players[0].live_zone[0] = 454;
    state.players[0].set_revealed(0, false);

    // Start performance phase to trigger reveal
    state.phase = Phase::PerformanceP1;
    state.do_performance_phase(&db);

    assert!(
        state.players[0].is_revealed(0),
        "Live card should be revealed during performance phase"
    );
    // Trigger should have executed (it meets conditions if yelled revealed is empty)
}

#[test]
fn verify_manual_recovery_pattern() {
    let db = load_real_db();
    let mut state = GameState::default();
    state.ui.silent = true;

    // Card ID 406: 高海千歌 (Member)
    // Ability: ACTIVATED -> COST: MOVE_TO_DISCARD -> EFFECT: RECOVER_MEMBER(1)
    state.players[0].stage[0] = 406;
    state.players[0].discard.push(121); // Target Eli to recover
    state.players[0].deck = vec![123].into(); // Dummy
    state.phase = Phase::Main;

    // 1. Activate ability (Slot 0, Ability 0)
    let result = state.step(
        &db,
        Action::ActivateAbility {
            slot_idx: 0,
            ab_idx: 0,
        }
        .id() as i32,
    );
    result.unwrap();


    assert_eq!(
        state.players[0].stage[0], -1,
        "Member should be in discard after sacrifice (Cost processing)"
    );
    // SETUP: Put Card 121 (a member) in discard
    state.players[0].discard = vec![121].into();
    state.players[0].hand.clear();

    // EXECUTE: Trigger RECOVER_MEMBER (Card 120 Honoka has it at ab_idx 0)
    let ctx = AbilityContext { player_id: 0, source_card_id: 120, ..Default::default() };
    state.resolve_bytecode_cref(&db, &db.get_member(120).unwrap().abilities[0].bytecode, &ctx);

    // RESOLVE: The interactions (MOVE_TO_DISCARD then RecovM)
    let mut safety_counter = 0;
    while state.phase == Phase::Response && safety_counter < 5 {
        println!("[TEST] Resolving suspension. Interaction: {:?}", state.interaction_stack.last().unwrap().choice_type);
        state.step(&db, ACTION_BASE_CHOICE + 0).expect("Step failed to resolve recovery");
        state.process_trigger_queue(&db);
        safety_counter += 1;
    }

    println!("[TEST] Hand after recovery: {:?}", state.players[0].hand);
    assert!(state.players[0].hand.contains(&121), "Hand should contain card 121. Hand: {:?}", state.players[0].hand);
}

#[test]
fn verify_performance_transition_history() {
    let db = load_real_db();
    let mut state = GameState::default();
    state.ui.silent = true;

    // Use common live card ID 6
    state.players[0].live_zone[0] = 6;
    state.players[0].set_revealed(0, true);
    state.phase = Phase::PerformanceP1;

    // P0 Perform (Pass)
    state.step(&db, 0).expect("P0 pass failed");
    // P1 Perform (Pass)
    state.step(&db, 0).expect("P1 pass failed");

    assert_eq!(
        state.ui.performance_history.len(),
        2,
        "Should have 2 performance records"
    );
}

#[test]
fn verify_full_win_condition() {
    let db = load_real_db();
    let mut state = GameState::default();
    state.ui.silent = true;

    // ID 6: Score 3 card
    state.players[0].success_lives = smallvec![6, 6];
    state.players[0].score = 2; // Internal engine score (not display score)
    state.phase = Phase::LiveResult;
    state.players[0].live_zone[0] = 6;

    // Select the live card to win (Slot 0 maps to action 600)
    state.step(&db, 600).expect("Decision step failed");

    assert_eq!(state.phase, Phase::Terminal, "Game should end");
    assert_eq!(state.players[0].success_lives.len(), 3);
    assert_eq!(state.get_winner(), 0);
}

#[test]
fn verify_buff_logic() {
    let db = load_real_db();
    let mut state = GameState::default();
    state.ui.silent = true;

    // Card ID 120: PL!-sd1- 001-SD
    // Ability: TRIGGER: CONSTANT -> ADD_BLADES(1, PER_CARD=SUCCESS_PILE)
    // Core Blades: 3 (Actual DB value)
    state.players[0].stage[0] = 120;
    state.players[0].success_lives = smallvec![120, 120]; // 2 cards in success pile

    // Total should be 3 (base) + 2 (from ability: 1 * success_pile_count) = 5
    let blades = state.get_effective_blades(0, 0, &db, 0);
    assert_eq!(
        blades, 5,
        "Card 120 should have 3 (base) + 1 * 2 (success pile count) = 5 blades"
    );
}