import json from engine_rust import PyCardDatabase, PyGameState from engine.models.ability import Ability, Effect, EffectType, TargetType, TriggerType from engine.models.opcodes import Opcode def create_mock_db_json(cards): """Create a JSON string for PyCardDatabase.""" db_data = {"members": {}, "lives": {}} for card in cards: card_data = { "card_id": card["card_id"], "card_no": card.get("card_no", "TEST-001"), "name": card.get("name", "Test Card"), "cost": card.get("cost", 1), "hearts": card.get("hearts", [0] * 7), "blade_hearts": card.get("blade_hearts", [0] * 7), "blades": card.get("blades", 0), "groups": card.get("groups", []), "units": card.get("units", []), "abilities": card.get("abilities", []), "volume_icons": card.get("volume_icons", 0), "draw_icons": card.get("draw_icons", 0), "img_path": "", "ability_text": "", } db_data["members"][str(card["card_id"])] = card_data return json.dumps(db_data) def test_on_reveal_trigger(): """Verify that OnReveal triggers when a card is yelled.""" ab = Ability( raw_text="OnReveal: Draw 1", trigger=TriggerType.ON_REVEAL, effects=[Effect(EffectType.DRAW, value=1, target=TargetType.SELF)], ) bytecode = ab.compile() cards = [ { "card_id": 101, "abilities": [ { "trigger": int(TriggerType.ON_REVEAL), "bytecode": bytecode, "conditions": [], "raw_text": "OnReveal: Draw 1", } ], } ] db = PyCardDatabase(create_mock_db_json(cards)) gs = PyGameState(db) # Setup Deck using PyGameState setter # PyGameState.initialize_game(p0_deck, p1_deck, p0_energy, p1_energy, p0_lives, p1_lives) gs.initialize_game( [302, 301, 101], # p0 deck (101 on top) [], [], [], [], [], ) # Action 1 = Yell gs.set_phase(4) # Main Phase p0 = gs.get_player(0) p0.set_blade_buffs([1, 0, 0]) gs.set_player(0, p0) gs.step(1) p0_after = gs.get_player(0) assert 301 in p0_after.hand def test_on_leaves_trigger(): """Verify that OnLeaves triggers when a card is replaced on stage.""" ab_leaves = Ability( raw_text="OnLeaves: Draw 1", trigger=TriggerType.ON_LEAVES, effects=[Effect(EffectType.DRAW, value=1, target=TargetType.SELF)], ) cards = [ { "card_id": 101, "abilities": [ { "trigger": int(TriggerType.ON_LEAVES), "bytecode": ab_leaves.compile(), "conditions": [], "raw_text": "OnLeaves: Draw 1", } ], }, {"card_id": 102, "abilities": []}, ] db = PyCardDatabase(create_mock_db_json(cards)) gs = PyGameState(db) gs.initialize_game( [301, 302], # p0 deck [], [], [], [], [], ) # Set stage and hand via PyGameState gs.set_stage_card(0, 0, 101) gs.set_hand_cards(0, [102]) # O_PLAY_MEMBER_FROM_HAND (57) bytecode = [Opcode.PLAY_MEMBER_FROM_HAND, 0, 0, 0, Opcode.RETURN, 0, 0, 0] gs.debug_execute_bytecode(bytecode, 0, 0, -1, 0, 0, 0) p0_after = gs.get_player(0) if p0_after.stage[0] != 102 or 301 not in p0_after.hand: raise Exception( f"DEBUG OnLeaves FAILED.\nStage: {p0_after.stage}\nHand: {p0_after.hand}\nDiscard: {p0_after.discard}\nLog: {gs.rule_log}" ) def test_on_position_change_trigger(): """Verify that OnPositionChange triggers when a card moves slots.""" ab_pos = Ability( raw_text="OnPosition: Draw 1", trigger=TriggerType.ON_POSITION_CHANGE, effects=[Effect(EffectType.DRAW, value=1, target=TargetType.SELF)], ) cards = [ { "card_id": 101, "abilities": [ { "trigger": int(TriggerType.ON_POSITION_CHANGE), "bytecode": ab_pos.compile(), "conditions": [], "raw_text": "OnPosition: Draw 1", } ], } ] db = PyCardDatabase(create_mock_db_json(cards)) gs = PyGameState(db) gs.initialize_game( [301, 302], # p0 deck [], [], [], [], [], ) gs.set_stage_card(0, 0, 101) # O_MOVE_MEMBER (20) bytecode = [Opcode.MOVE_MEMBER, 0, 0, 2, Opcode.RETURN, 0, 0, 0] gs.debug_execute_bytecode(bytecode, 0, 0, -1, 2, 0, 0) p0_after = gs.get_player(0) if p0_after.stage[2] != 101 or 301 not in p0_after.hand: raise Exception(f"DEBUG OnPosition FAILED.\nStage: {p0_after.stage}\nHand: {p0_after.hand}\nLog: {gs.rule_log}")