diff --git a/backend/app/core/models/card.py b/backend/app/core/models/card.py index 2d3ac3a..3bb9395 100644 --- a/backend/app/core/models/card.py +++ b/backend/app/core/models/card.py @@ -122,20 +122,12 @@ class WeaknessResistance(BaseModel): mode=ModifierMode.ADDITIVE, value=40, # +40 damage instead of x2 ) - - Legacy Support: - The old 'modifier' field is deprecated but still works for backwards - compatibility. If 'modifier' is provided without 'value', it will be - used as the value. The mode will still default to CombatConfig. """ energy_type: EnergyType mode: ModifierMode | None = None value: int | None = None - # Legacy field for backwards compatibility - modifier: int | None = None - def get_value(self, default: int) -> int: """Get the modifier value, falling back to default if not specified. @@ -147,8 +139,6 @@ class WeaknessResistance(BaseModel): """ if self.value is not None: return self.value - if self.modifier is not None: - return self.modifier return default def get_mode(self, default: ModifierMode) -> ModifierMode: diff --git a/backend/tests/core/conftest.py b/backend/tests/core/conftest.py index 32d23de..c7ed69c 100644 --- a/backend/tests/core/conftest.py +++ b/backend/tests/core/conftest.py @@ -19,6 +19,7 @@ from app.core.config import RulesConfig from app.core.enums import ( CardType, EnergyType, + ModifierMode, PokemonStage, PokemonVariant, TrainerType, @@ -94,7 +95,9 @@ def pikachu_def() -> CardDefinition: effect_description="Flip a coin. If heads, the Defending Pokemon is now Paralyzed.", ), ], - weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), + weakness=WeaknessResistance( + energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), retreat_cost=1, rarity="common", set_id="base", @@ -123,7 +126,9 @@ def raichu_def() -> CardDefinition: damage=60, ), ], - weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), + weakness=WeaknessResistance( + energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), retreat_cost=1, rarity="rare", set_id="base", @@ -154,8 +159,12 @@ def charizard_def() -> CardDefinition: effect_params={"count": 2, "type": "fire"}, ), ], - weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2), - resistance=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=-30), + weakness=WeaknessResistance( + energy_type=EnergyType.WATER, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), + resistance=WeaknessResistance( + energy_type=EnergyType.FIGHTING, mode=ModifierMode.ADDITIVE, value=-30 + ), retreat_cost=3, rarity="rare_holo", set_id="base", @@ -185,7 +194,9 @@ def mewtwo_ex_def() -> CardDefinition: effect_params={"count": 1, "type": "any"}, ), ], - weakness=WeaknessResistance(energy_type=EnergyType.PSYCHIC, modifier=2), + weakness=WeaknessResistance( + energy_type=EnergyType.PSYCHIC, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), retreat_cost=2, rarity="ultra_rare", set_id="ex_series", @@ -215,7 +226,9 @@ def pikachu_v_def() -> CardDefinition: effect_params={"amount": 30}, ), ], - weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), + weakness=WeaknessResistance( + energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), retreat_cost=2, rarity="ultra_rare", set_id="v_series", @@ -244,7 +257,9 @@ def pikachu_vmax_def() -> CardDefinition: damage=270, ), ], - weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), + weakness=WeaknessResistance( + energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), retreat_cost=3, rarity="secret_rare", set_id="vmax_series", @@ -642,7 +657,9 @@ def charmander_def() -> CardDefinition: damage=10, ), ], - weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2), + weakness=WeaknessResistance( + energy_type=EnergyType.WATER, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), retreat_cost=1, rarity="common", set_id="base", @@ -671,7 +688,9 @@ def charmeleon_def() -> CardDefinition: damage=30, ), ], - weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2), + weakness=WeaknessResistance( + energy_type=EnergyType.WATER, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), retreat_cost=1, rarity="uncommon", set_id="base", diff --git a/backend/tests/core/test_effects/test_handlers.py b/backend/tests/core/test_effects/test_handlers.py index 45cad46..2007512 100644 --- a/backend/tests/core/test_effects/test_handlers.py +++ b/backend/tests/core/test_effects/test_handlers.py @@ -699,41 +699,6 @@ class TestAttackDamage: assert result.details["weakness"]["mode"] == "multiplicative" assert result.details["weakness"]["value"] == 3 - def test_legacy_modifier_field_still_works( - self, game_state: GameState, rng: SeededRandom - ) -> None: - """ - Verify backwards compatibility: old 'modifier' field still works. - """ - # Using legacy 'modifier' field instead of 'value' - game_state.card_registry["charmander-001"] = CardDefinition( - id="charmander-001", - name="Charmander", - card_type=CardType.POKEMON, - stage=PokemonStage.BASIC, - hp=70, - pokemon_type=EnergyType.FIRE, - weakness=WeaknessResistance( - energy_type=EnergyType.LIGHTNING, - modifier=2, # Legacy field - ), - ) - - ctx = make_context( - game_state, - rng, - source_card_id="pikachu-inst", - params={"amount": 30}, - ) - - result = resolve_effect("attack_damage", ctx) - - assert result.success - target = game_state.players["player2"].get_active_pokemon() - assert target is not None - assert target.damage == 60 # 30 * 2 (legacy modifier used as value) - assert result.details["weakness"]["value"] == 2 - def test_fails_with_no_target(self, game_state: GameState, rng: SeededRandom) -> None: """ Verify attack_damage fails when no valid target exists. diff --git a/backend/tests/core/test_models/test_card.py b/backend/tests/core/test_models/test_card.py index d13d80c..e4303d2 100644 --- a/backend/tests/core/test_models/test_card.py +++ b/backend/tests/core/test_models/test_card.py @@ -11,6 +11,7 @@ These tests verify: from app.core.enums import ( CardType, EnergyType, + ModifierMode, PokemonStage, PokemonVariant, StatusCondition, @@ -156,27 +157,31 @@ class TestWeaknessResistance: def test_weakness(self) -> None: """ - Verify weakness can be defined. + Verify weakness can be defined with multiplicative mode. """ weakness = WeaknessResistance( energy_type=EnergyType.FIGHTING, - modifier=2, + mode=ModifierMode.MULTIPLICATIVE, + value=2, ) assert weakness.energy_type == EnergyType.FIGHTING - assert weakness.modifier == 2 + assert weakness.mode == ModifierMode.MULTIPLICATIVE + assert weakness.value == 2 def test_resistance(self) -> None: """ - Verify resistance can be defined. + Verify resistance can be defined with additive mode. """ resistance = WeaknessResistance( energy_type=EnergyType.METAL, - modifier=-30, + mode=ModifierMode.ADDITIVE, + value=-30, ) assert resistance.energy_type == EnergyType.METAL - assert resistance.modifier == -30 + assert resistance.mode == ModifierMode.ADDITIVE + assert resistance.value == -30 class TestCardDefinitionPokemon: @@ -205,7 +210,9 @@ class TestCardDefinitionPokemon: effect_id="may_paralyze", ), ], - weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), + weakness=WeaknessResistance( + energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), retreat_cost=1, ) @@ -1112,8 +1119,12 @@ class TestCardDefinitionJsonRoundTrip: abilities=[ Ability(name="Static", effect_id="static_paralysis"), ], - weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), - resistance=WeaknessResistance(energy_type=EnergyType.METAL, modifier=-30), + weakness=WeaknessResistance( + energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2 + ), + resistance=WeaknessResistance( + energy_type=EnergyType.METAL, mode=ModifierMode.ADDITIVE, value=-30 + ), retreat_cost=1, rarity="common", set_id="base",