Spaces:
Sleeping
Sleeping
| use crate::core::logic::card_db::LOGIC_ID_MASK; | |
| use crate::core::logic::*; | |
| // use std::collections::HashMap; | |
| fn create_mini_db_with_bytecode(bc: Vec<i32>) -> CardDatabase { | |
| let mut db = CardDatabase::default(); | |
| let mut m = MemberCard { | |
| card_id: 101, | |
| card_no: "MINI-101".to_string(), | |
| name: "Mini Card".to_string(), | |
| cost: 2, | |
| ..Default::default() | |
| }; | |
| m.abilities.push(Ability { | |
| trigger: TriggerType::Activated, | |
| bytecode: bc, | |
| ..Default::default() | |
| }); | |
| db.members.insert(101, m.clone()); | |
| db.members_vec[(101 as usize) & LOGIC_ID_MASK as usize] = Some(m); | |
| db | |
| } | |
| fn create_mini_state() -> GameState { | |
| let mut state = GameState::default(); | |
| state.players[0].player_id = 0; | |
| state.players[1].player_id = 1; | |
| state.phase = Phase::Main; | |
| state.ui.silent = false; | |
| // Place the card on stage so activate_ability_with_choice can find it | |
| state.players[0].stage[0] = 101; | |
| state | |
| } | |
| fn mini_test_o_pay_energy_resumption() { | |
| // Bytecode: PAY_ENERGY(1), DRAW(1), RETURN | |
| let bc = vec![64, 1, 0, 0, 10, 1, 0, 1, 1, 0, 0, 0]; | |
| let db = create_mini_db_with_bytecode(bc); | |
| let mut state = create_mini_state(); | |
| // Setup energy (2 untapped, need 1 -> should suspend for choice) | |
| state.players[0].tapped_energy_mask = 0; | |
| // Populate deck so DRAW works | |
| state.players[0].deck.extend(vec![1, 2, 3, 4, 5]); | |
| // Activate the ability at slot 0, ability 0 | |
| state.activate_ability_with_choice(&db, 0, 0, -1, 0).unwrap(); | |
| assert_eq!(state.phase, Phase::Response, "Should suspend for PAY_ENERGY selection"); | |
| assert_eq!(state.interaction_stack.last().map(|i| i.effect_opcode).unwrap_or(0), 64, "Pending opcode should be O_PAY_ENERGY"); | |
| // Resume with SelectResponseSlot action | |
| state.step(&db, Action::SelectResponseSlot { slot_idx: 0 }.id() as i32).unwrap(); | |
| assert!(state.players[0].is_energy_tapped(0), "Energy should be tapped"); | |
| assert_eq!(state.players[0].hand.len(), 1, "Should have resumed and drawn a card"); | |
| assert_eq!(state.phase, Phase::Main, "Should return to Main phase"); | |
| } | |
| fn mini_test_o_select_mode_resumption() { | |
| // Bytecode: SELECT_MODE(2 choices), jump targets, Option 1: DRAW(1)+RETURN, Option 2: DRAW(2)+RETURN | |
| let bc = vec![ | |
| 30, 2, 12, 20, // SELECT_MODE, v=2, Jmp0=12, Jmp1=20 | |
| 3, 0, 0, 0, // Option 1 -> instruction 3 (*4 = IP 12) | |
| 5, 0, 0, 0, // Option 2 -> instruction 5 (*4 = IP 20) | |
| 10, 1, 0, 1, // IP 12: DRAW(1) | |
| 1, 0, 0, 0, // IP 16: RETURN | |
| 10, 2, 0, 1, // IP 20: DRAW(2) | |
| 1, 0, 0, 0 // IP 24: RETURN | |
| ]; | |
| let db = create_mini_db_with_bytecode(bc); | |
| let mut state = create_mini_state(); | |
| // Populate deck so DRAW works | |
| state.players[0].deck.extend(vec![1, 2, 3, 4, 5]); | |
| // Activate the ability at slot 0, ability 0 | |
| state.activate_ability_with_choice(&db, 0, 0, -1, 0).unwrap(); | |
| assert_eq!(state.phase, Phase::Response, "Should suspend for SELECT_MODE"); | |
| assert_eq!(state.interaction_stack.last().map(|i| i.effect_opcode).unwrap_or(0), 30, "Pending opcode should be O_SELECT_MODE"); | |
| // Pick Option 2 (choice_idx=1) | |
| state.step(&db, Action::SelectChoice { choice_idx: 1 }.id() as i32).unwrap(); | |
| assert_eq!(state.players[0].hand.len(), 2, "Should have picked Option 2 and drawn 2 cards"); | |
| assert_eq!(state.phase, Phase::Main, "Should return to Main phase"); | |
| } | |