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