Remove legacy modifier field from WeaknessResistance
Migrate all usages to the proper mode/value fields: - Weakness: mode=MULTIPLICATIVE, value=2 - Resistance: mode=ADDITIVE, value=-30 Remove backwards compatibility code and legacy test. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f512c7b2b3
commit
f93f5b617a
@ -122,20 +122,12 @@ class WeaknessResistance(BaseModel):
|
|||||||
mode=ModifierMode.ADDITIVE,
|
mode=ModifierMode.ADDITIVE,
|
||||||
value=40, # +40 damage instead of x2
|
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
|
energy_type: EnergyType
|
||||||
mode: ModifierMode | None = None
|
mode: ModifierMode | None = None
|
||||||
value: int | None = None
|
value: int | None = None
|
||||||
|
|
||||||
# Legacy field for backwards compatibility
|
|
||||||
modifier: int | None = None
|
|
||||||
|
|
||||||
def get_value(self, default: int) -> int:
|
def get_value(self, default: int) -> int:
|
||||||
"""Get the modifier value, falling back to default if not specified.
|
"""Get the modifier value, falling back to default if not specified.
|
||||||
|
|
||||||
@ -147,8 +139,6 @@ class WeaknessResistance(BaseModel):
|
|||||||
"""
|
"""
|
||||||
if self.value is not None:
|
if self.value is not None:
|
||||||
return self.value
|
return self.value
|
||||||
if self.modifier is not None:
|
|
||||||
return self.modifier
|
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def get_mode(self, default: ModifierMode) -> ModifierMode:
|
def get_mode(self, default: ModifierMode) -> ModifierMode:
|
||||||
|
|||||||
@ -19,6 +19,7 @@ from app.core.config import RulesConfig
|
|||||||
from app.core.enums import (
|
from app.core.enums import (
|
||||||
CardType,
|
CardType,
|
||||||
EnergyType,
|
EnergyType,
|
||||||
|
ModifierMode,
|
||||||
PokemonStage,
|
PokemonStage,
|
||||||
PokemonVariant,
|
PokemonVariant,
|
||||||
TrainerType,
|
TrainerType,
|
||||||
@ -94,7 +95,9 @@ def pikachu_def() -> CardDefinition:
|
|||||||
effect_description="Flip a coin. If heads, the Defending Pokemon is now Paralyzed.",
|
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,
|
retreat_cost=1,
|
||||||
rarity="common",
|
rarity="common",
|
||||||
set_id="base",
|
set_id="base",
|
||||||
@ -123,7 +126,9 @@ def raichu_def() -> CardDefinition:
|
|||||||
damage=60,
|
damage=60,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2),
|
weakness=WeaknessResistance(
|
||||||
|
energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2
|
||||||
|
),
|
||||||
retreat_cost=1,
|
retreat_cost=1,
|
||||||
rarity="rare",
|
rarity="rare",
|
||||||
set_id="base",
|
set_id="base",
|
||||||
@ -154,8 +159,12 @@ def charizard_def() -> CardDefinition:
|
|||||||
effect_params={"count": 2, "type": "fire"},
|
effect_params={"count": 2, "type": "fire"},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2),
|
weakness=WeaknessResistance(
|
||||||
resistance=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=-30),
|
energy_type=EnergyType.WATER, mode=ModifierMode.MULTIPLICATIVE, value=2
|
||||||
|
),
|
||||||
|
resistance=WeaknessResistance(
|
||||||
|
energy_type=EnergyType.FIGHTING, mode=ModifierMode.ADDITIVE, value=-30
|
||||||
|
),
|
||||||
retreat_cost=3,
|
retreat_cost=3,
|
||||||
rarity="rare_holo",
|
rarity="rare_holo",
|
||||||
set_id="base",
|
set_id="base",
|
||||||
@ -185,7 +194,9 @@ def mewtwo_ex_def() -> CardDefinition:
|
|||||||
effect_params={"count": 1, "type": "any"},
|
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,
|
retreat_cost=2,
|
||||||
rarity="ultra_rare",
|
rarity="ultra_rare",
|
||||||
set_id="ex_series",
|
set_id="ex_series",
|
||||||
@ -215,7 +226,9 @@ def pikachu_v_def() -> CardDefinition:
|
|||||||
effect_params={"amount": 30},
|
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,
|
retreat_cost=2,
|
||||||
rarity="ultra_rare",
|
rarity="ultra_rare",
|
||||||
set_id="v_series",
|
set_id="v_series",
|
||||||
@ -244,7 +257,9 @@ def pikachu_vmax_def() -> CardDefinition:
|
|||||||
damage=270,
|
damage=270,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2),
|
weakness=WeaknessResistance(
|
||||||
|
energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2
|
||||||
|
),
|
||||||
retreat_cost=3,
|
retreat_cost=3,
|
||||||
rarity="secret_rare",
|
rarity="secret_rare",
|
||||||
set_id="vmax_series",
|
set_id="vmax_series",
|
||||||
@ -642,7 +657,9 @@ def charmander_def() -> CardDefinition:
|
|||||||
damage=10,
|
damage=10,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2),
|
weakness=WeaknessResistance(
|
||||||
|
energy_type=EnergyType.WATER, mode=ModifierMode.MULTIPLICATIVE, value=2
|
||||||
|
),
|
||||||
retreat_cost=1,
|
retreat_cost=1,
|
||||||
rarity="common",
|
rarity="common",
|
||||||
set_id="base",
|
set_id="base",
|
||||||
@ -671,7 +688,9 @@ def charmeleon_def() -> CardDefinition:
|
|||||||
damage=30,
|
damage=30,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2),
|
weakness=WeaknessResistance(
|
||||||
|
energy_type=EnergyType.WATER, mode=ModifierMode.MULTIPLICATIVE, value=2
|
||||||
|
),
|
||||||
retreat_cost=1,
|
retreat_cost=1,
|
||||||
rarity="uncommon",
|
rarity="uncommon",
|
||||||
set_id="base",
|
set_id="base",
|
||||||
|
|||||||
@ -699,41 +699,6 @@ class TestAttackDamage:
|
|||||||
assert result.details["weakness"]["mode"] == "multiplicative"
|
assert result.details["weakness"]["mode"] == "multiplicative"
|
||||||
assert result.details["weakness"]["value"] == 3
|
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:
|
def test_fails_with_no_target(self, game_state: GameState, rng: SeededRandom) -> None:
|
||||||
"""
|
"""
|
||||||
Verify attack_damage fails when no valid target exists.
|
Verify attack_damage fails when no valid target exists.
|
||||||
|
|||||||
@ -11,6 +11,7 @@ These tests verify:
|
|||||||
from app.core.enums import (
|
from app.core.enums import (
|
||||||
CardType,
|
CardType,
|
||||||
EnergyType,
|
EnergyType,
|
||||||
|
ModifierMode,
|
||||||
PokemonStage,
|
PokemonStage,
|
||||||
PokemonVariant,
|
PokemonVariant,
|
||||||
StatusCondition,
|
StatusCondition,
|
||||||
@ -156,27 +157,31 @@ class TestWeaknessResistance:
|
|||||||
|
|
||||||
def test_weakness(self) -> None:
|
def test_weakness(self) -> None:
|
||||||
"""
|
"""
|
||||||
Verify weakness can be defined.
|
Verify weakness can be defined with multiplicative mode.
|
||||||
"""
|
"""
|
||||||
weakness = WeaknessResistance(
|
weakness = WeaknessResistance(
|
||||||
energy_type=EnergyType.FIGHTING,
|
energy_type=EnergyType.FIGHTING,
|
||||||
modifier=2,
|
mode=ModifierMode.MULTIPLICATIVE,
|
||||||
|
value=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert weakness.energy_type == EnergyType.FIGHTING
|
assert weakness.energy_type == EnergyType.FIGHTING
|
||||||
assert weakness.modifier == 2
|
assert weakness.mode == ModifierMode.MULTIPLICATIVE
|
||||||
|
assert weakness.value == 2
|
||||||
|
|
||||||
def test_resistance(self) -> None:
|
def test_resistance(self) -> None:
|
||||||
"""
|
"""
|
||||||
Verify resistance can be defined.
|
Verify resistance can be defined with additive mode.
|
||||||
"""
|
"""
|
||||||
resistance = WeaknessResistance(
|
resistance = WeaknessResistance(
|
||||||
energy_type=EnergyType.METAL,
|
energy_type=EnergyType.METAL,
|
||||||
modifier=-30,
|
mode=ModifierMode.ADDITIVE,
|
||||||
|
value=-30,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert resistance.energy_type == EnergyType.METAL
|
assert resistance.energy_type == EnergyType.METAL
|
||||||
assert resistance.modifier == -30
|
assert resistance.mode == ModifierMode.ADDITIVE
|
||||||
|
assert resistance.value == -30
|
||||||
|
|
||||||
|
|
||||||
class TestCardDefinitionPokemon:
|
class TestCardDefinitionPokemon:
|
||||||
@ -205,7 +210,9 @@ class TestCardDefinitionPokemon:
|
|||||||
effect_id="may_paralyze",
|
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,
|
retreat_cost=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1112,8 +1119,12 @@ class TestCardDefinitionJsonRoundTrip:
|
|||||||
abilities=[
|
abilities=[
|
||||||
Ability(name="Static", effect_id="static_paralysis"),
|
Ability(name="Static", effect_id="static_paralysis"),
|
||||||
],
|
],
|
||||||
weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2),
|
weakness=WeaknessResistance(
|
||||||
resistance=WeaknessResistance(energy_type=EnergyType.METAL, modifier=-30),
|
energy_type=EnergyType.FIGHTING, mode=ModifierMode.MULTIPLICATIVE, value=2
|
||||||
|
),
|
||||||
|
resistance=WeaknessResistance(
|
||||||
|
energy_type=EnergyType.METAL, mode=ModifierMode.ADDITIVE, value=-30
|
||||||
|
),
|
||||||
retreat_cost=1,
|
retreat_cost=1,
|
||||||
rarity="common",
|
rarity="common",
|
||||||
set_id="base",
|
set_id="base",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user