Spaces:
Running
Running
| 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}") | |