use crate::core::logic::*; use crate::core::enums::*; use std::collections::HashMap; fn create_test_db() -> CardDatabase { CardDatabase { members: HashMap::new(), lives: HashMap::new(), members_vec: vec![None; 1000], lives_vec: vec![None; 40000], } } fn create_test_state() -> GameState { let mut state = GameState::default(); state.players[0].player_id = 0; state.players[1].player_id = 1; state.phase = Phase::Main; state } #[test] fn test_opcode_draw_discard() { let db = create_test_db(); let mut state = create_test_state(); state.players[0].deck = vec![1, 2, 3, 4, 5]; let ctx = AbilityContext { player_id: 0, ..Default::default() }; // O_DRAW 2 let bc = vec![O_DRAW, 2, 0, 0, O_RETURN, 0, 0, 0]; state.resolve_bytecode(&db, &bc, &ctx); assert_eq!(state.players[0].hand.len(), 2); assert_eq!(state.players[0].deck.len(), 3); assert_eq!(state.phase, Phase::Main); // Phase should not change // O_MOVE_TO_DISCARD 1 (attr 2 = Hand) let bc = vec![O_MOVE_TO_DISCARD, 1, 2, 0, O_RETURN, 0, 0, 0]; state.resolve_bytecode(&db, &bc, &ctx); assert_eq!(state.players[0].hand.len(), 1); assert_eq!(state.players[0].discard.len(), 1); assert_eq!(state.phase, Phase::Main); } #[test] fn test_opcode_stats_boost() { let db = create_test_db(); let mut state = create_test_state(); state.players[0].stage[0] = 10; let ctx = AbilityContext { player_id: 0, area_idx: 0, ..Default::default() }; // O_BLADES 2 to SELF (Slot 4) let bc = vec![O_BLADES, 2, 0, 4, O_RETURN, 0, 0, 0]; state.resolve_bytecode(&db, &bc, &ctx); assert_eq!(state.players[0].blade_buffs[0], 2); // O_HEARTS 3 (Pink=0) to SELF (Slot 4) let bc = vec![O_HEARTS, 3, 0, 4, O_RETURN, 0, 0, 0]; state.resolve_bytecode(&db, &bc, &ctx); assert_eq!(state.players[0].heart_buffs[0][0], 3); // O_BOOST 5 to SELF let bc = vec![O_BOOST, 5, 0, 0, O_RETURN, 0, 0, 0]; state.resolve_bytecode(&db, &bc, &ctx); assert_eq!(state.players[0].live_score_bonus, 5); } #[test] fn test_opcode_tap_untap() { let db = create_test_db(); let mut state = create_test_state(); state.players[0].stage[1] = 20; state.players[0].tapped_members[1] = false; let ctx = AbilityContext { player_id: 0, area_idx: 1, ..Default::default() }; // O_SET_TAPPED 1 SELF let bc = vec![O_SET_TAPPED, 1, 0, 4, O_RETURN, 0, 0, 0]; state.resolve_bytecode(&db, &bc, &ctx); assert!(state.players[0].tapped_members[1]); // O_SET_TAPPED 0 SELF let bc = vec![O_SET_TAPPED, 0, 0, 4, O_RETURN, 0, 0, 0]; state.resolve_bytecode(&db, &bc, &ctx); assert!(!state.players[0].tapped_members[1]); } #[test] fn test_conditions_basic() { let db = create_test_db(); let mut state = create_test_state(); state.players[0].hand = vec![1, 2, 3]; let ctx = AbilityContext { player_id: 0, ..Default::default() }; // C_HND GE 3 -> Draw 1 // Bytecode: [C_HND, 3, 0, 0, O_JUMP_F, 1, 0, 0, O_DRAW, 1, 0, 0, O_RETURN, 0, 0, 0] let bc = vec![ C_HND, 3, 0, 0, O_JUMP_F, 1, 0, 0, O_DRAW, 1, 0, 0, O_RETURN, 0, 0, 0 ]; state.players[0].deck = vec![100]; state.resolve_bytecode(&db, &bc, &ctx); assert_eq!(state.players[0].hand.len(), 4); // C_HND GE 5 (False) -> Draw 1 let mut state = create_test_state(); state.players[0].hand = vec![1, 2, 3]; state.players[0].deck = vec![100]; let bc = vec![ C_HND, 5, 0, 0, O_JUMP_F, 1, 0, 0, O_DRAW, 1, 0, 0, O_RETURN, 0, 0, 0 ]; state.resolve_bytecode(&db, &bc, &ctx); assert_eq!(state.players[0].hand.len(), 3); } // TODO: test_modal_select_mode requires understanding of the exact SELECT_MODE bytecode format. // The jump table calculation in logic.rs line 1576: // jump_ip = (ip / 4) + 1 + choice // offset = cur_bc[jump_ip * 4 + 1] // new_ip = (jump_ip + offset) * 4 // This test is commented out until the bytecode format is confirmed. /* #[test] fn test_modal_select_mode() { // ... test code ... } */