import numpy as np import pytest from engine.game.enums import Phase from engine.game.game_state import GameState from engine.models.ability import ( Ability, Condition, ConditionType, Effect, EffectType, TargetType, TriggerType, ) from engine.models.card import MemberCard @pytest.fixture def state(): gs = GameState() # Mock databases GameState.member_db = {} GameState.live_db = {} return gs def test_q171_live_end_expiry(state): """ Q171 Verification: Ruling: "Until end of live" effects expire at the end of Live Result phase. """ p0 = state.players[0] # 1. Apply a "until end of live" effect (e.g., +1 score bonus) # Note: BOOST_SCORE is usually handled in live result if it has UNTIL=LIVE_END effect = Effect(EffectType.BOOST_SCORE, 1, TargetType.PLAYER, params={"until": "live_end"}) p0.continuous_effects.append({"effect": effect, "expiry": "LIVE_END", "source_name": "Test Card"}) p0.live_score_bonus = 1 # 2. Advance through phases to LIVE_RESULT state.phase = Phase.LIVE_RESULT # 3. Complete live result and check if bonus is cleared # This should call _finish_live_result internally state._finish_live_result() # Verification assert p0.live_score_bonus == 0, "Q171 FAIL: live_score_bonus should be reset after live" # Check if continuous effect is gone has_live_end = any(e.get("expiry") == "LIVE_END" for e in p0.continuous_effects) assert not has_live_end, "Q171 FAIL: LIVE_END continuous effects should be cleared" def test_q129_cost_reduction_in_hand(state): """ Q129 Verification: Ruling: Cost-reducing constant abilities on cards in hand MUST be accounted for. Card: LL-bp2-001-R+ (Cost 10, reduced by 1 for each other card in hand) """ p0 = state.players[0] # Ability: [常時]手札にあるこのメンバーカードのコストは、このカード以外の自分の手札1枚につき、1少なくなる。 # This is a bit tricky to mock because the engine currently doesn't have a specific Hook for 'in hand constant' # But Q129 says it SHOULD work. # Setup card with cost 10 # Define the cost reduction ability cond = Condition( ConditionType.COUNT_HAND, params={"min": 0} ) # Logic check handled by effect param `per_hand_other` # NOTE: The engine fix looks for REDUCE_COST and then checks conditions. # The condition "1 for each other card" is usually implemented as a multiplier. eff = Effect(EffectType.REDUCE_COST, 1, TargetType.SELF, params={"multiplier": True, "per_hand_other": True}) ability = Ability(raw_text="Test Ability", trigger=TriggerType.CONSTANT, effects=[eff], conditions=[cond]) special_card = MemberCard( card_id=100, card_no="LL-bp2-001-R+", name="渡辺 曜&...", cost=10, hearts=np.zeros(6), blade_hearts=np.zeros(7), blades=0, abilities=[ability], ) state.member_db[100] = special_card # Add to hand with 4 other cards (total 5 cards) p0.hand = [100, 101, 102, 103, 104] # Current Engine check: get_member_cost effective_cost = p0.get_member_cost(100, state.member_db) # According to Q129, with 5 cards (4 other), cost should be 10 - 4 = 6. assert effective_cost == 6, f"Q129 FAIL: Effective cost should be 6 with 4 other cards, but got {effective_cost}"