Spaces:
Sleeping
Sleeping
| // Removed unused generated_constants import | |
| use crate::core::logic::*; | |
| fn test_exile_zone_exists() { | |
| let mut state = GameState::default(); | |
| // Test that we can access and modify the exile zone | |
| state.players[0].exile.push(100); | |
| assert_eq!(state.players[0].exile.len(), 1); | |
| assert_eq!(state.players[0].exile[0], 100); | |
| } | |
| fn test_rule_10_5_3_orphan_energy_cleanup() { | |
| let mut state = GameState::default(); | |
| let db = CardDatabase::default(); | |
| // Setup: Slot 0 has no member (-1) but has energy [10, 20] | |
| state.players[0].stage[0] = -1; | |
| state.players[0].stage_energy[0] = smallvec::smallvec![10, 20]; | |
| state.players[0].stage_energy_count[0] = 2; // Although count is derived or tracked separately, let's set it | |
| // Setup: Energy deck is empty | |
| state.players[0].energy_deck = smallvec::SmallVec::new(); | |
| // Ensure state before rule check | |
| assert!(!state.players[0].stage_energy[0].is_empty()); | |
| assert_eq!(state.players[0].energy_deck.len(), 0); | |
| // Execution | |
| state.process_rule_checks(&db); | |
| // Assertion | |
| // 1. Stage energy should be empty | |
| assert!( | |
| state.players[0].stage_energy[0].is_empty(), | |
| "Orphan energy should be removed from stage" | |
| ); | |
| assert_eq!( | |
| state.players[0].stage_energy_count[0], 0, | |
| "Energy count should be reset" | |
| ); | |
| // 2. Energy deck should contain the energy cards | |
| assert_eq!( | |
| state.players[0].energy_deck.len(), | |
| 2, | |
| "Energy deck should receive the orphan energy" | |
| ); | |
| // Since we shuffle, we check containment | |
| assert!(state.players[0].energy_deck.contains(&10)); | |
| assert!(state.players[0].energy_deck.contains(&20)); | |
| } | |
| fn test_play_member_from_hand_opcode_preserves_energy() { | |
| let mut state = GameState::default(); | |
| // Setup | |
| // Slot 0 has member 999 and Energy [10, 20] | |
| state.players[0].stage[0] = 999; | |
| state.players[0].stage_energy[0] = smallvec::smallvec![10, 20]; | |
| state.players[0].stage_energy_count[0] = 2; | |
| state.players[0].hand = smallvec::smallvec![888]; // Card to play | |
| state.players[0].deck = smallvec::smallvec![123]; | |
| let mut m888 = MemberCard::default(); | |
| m888.card_id = 888; | |
| let mut m999 = MemberCard::default(); | |
| m999.card_id = 999; | |
| let mut db = CardDatabase::default(); | |
| db.members.insert(888, m888.clone()); | |
| db.members.insert(999, m999.clone()); | |
| db.members_vec[888] = Some(m888); | |
| db.members_vec[999] = Some(m999); | |
| // Opcode: PLAY_MEMBER_FROM_HAND (57) | |
| // Args: none (uses ctx) | |
| let bytecode = vec![57, 0, 0, 0, 0, 1, 0, 0, 0, 0]; | |
| let mut ctx = AbilityContext::default(); | |
| ctx.player_id = 0; | |
| ctx.choice_index = 0; // Hand index 0 (Card 888) | |
| ctx.target_slot = 0; // Target Slot 0 | |
| // We only invoke resolve_bytecode to test the opcode directly. | |
| // Step 1: Select Card from Hand (choice_index=0) | |
| state.resolve_bytecode_cref(&db, &bytecode, &ctx); | |
| // Handler should have suspended for the slot. | |
| assert!(state.interaction_stack.len() > 0); | |
| let mut resumed_ctx = state.interaction_stack.pop().unwrap().ctx; | |
| assert_eq!(resumed_ctx.v_remaining, 1); | |
| // Step 2: Select Slot (choice_index=0) | |
| resumed_ctx.choice_index = 0; | |
| state.resolve_bytecode_cref(&db, &bytecode, &resumed_ctx); | |
| // Assertions | |
| // 1. Old member 999 should be in discard | |
| assert_eq!(state.players[0].discard.len(), 1); | |
| assert_eq!(state.players[0].discard[0], 999); | |
| // 2. New member 888 should be in slot 0 | |
| assert_eq!(state.players[0].stage[0], 888); | |
| // 3. Energy should remain! | |
| assert_eq!( | |
| state.players[0].stage_energy[0].len(), | |
| 2, | |
| "Energy should be preserved" | |
| ); | |
| assert_eq!(state.players[0].stage_energy[0][0], 10); | |
| assert_eq!(state.players[0].stage_energy[0][1], 20); | |
| assert_eq!(state.players[0].stage_energy_count[0], 2); | |
| } | |