"""Trait-Boni: Zählung, Stufen, Reichweite des Bonus.""" from tft.sim import battle, traits UNITS = { "A": {"traits": ["PANZER"], "stats": {"hp": 1000, "armor": 20, "damage": 50, "attackSpeed": 1.0, "range": 1}}, "B": {"traits": ["PANZER"], "stats": {"hp": 1000, "armor": 20, "damage": 50, "attackSpeed": 1.0, "range": 1}}, "C": {"traits": ["ANDERE"], "stats": {"hp": 1000, "armor": 20, "damage": 50, "attackSpeed": 1.0, "range": 1}}, } TRAITS = { "PANZER": {"breakpoints": [ {"min_units": 2, "variables": {"DefenderDefenseGain": 25}}, {"min_units": 3, "variables": {"DefenderDefenseGain": 60}}, ]}, "ANDERE": {"breakpoints": [ {"min_units": 1, "variables": {"TeamManaRegen": 2}}, ]}, } def board(*keys): return [{"api_name": k, "stars": 1} for k in keys] def fighters(*keys): return [battle.to_fighter({"api_name": k, "stars": 1, "col": 0, "row": 0}, "a", UNITS) for k in keys] def test_a_trait_needs_enough_units(): assert traits.active(board("A"), UNITS, TRAITS) == {} assert "PANZER" in traits.active(board("A", "B"), UNITS, TRAITS) def test_copies_of_the_same_champion_count_once(): """Zwei Kopien von A sind ein Trait-Träger, nicht zwei.""" assert traits.active(board("A", "A"), UNITS, TRAITS) == {} def test_the_highest_reached_step_wins(): step = traits.active(board("A", "B", "C"), UNITS, TRAITS)["PANZER"] assert step["variables"]["DefenderDefenseGain"] == 25 UNITS["C"]["traits"].append("PANZER") try: step = traits.active(board("A", "B", "C"), UNITS, TRAITS)["PANZER"] assert step["variables"]["DefenderDefenseGain"] == 60 finally: UNITS["C"]["traits"].remove("PANZER") def test_the_bonus_only_reaches_its_own_units(): fa, fb, fc = fighters("A", "B", "C") traits.apply([fa, fb, fc], board("A", "B", "C"), UNITS, TRAITS) assert fa.armor == 45 and fb.armor == 45 # 20 + 25 assert fc.armor == 20 def test_team_bonuses_reach_everyone(): """Steht "Team" im Namen, gilt der Bonus für das ganze Board.""" fa, fb, fc = fighters("A", "B", "C") traits.apply([fa, fb, fc], board("A", "B", "C"), UNITS, TRAITS) assert fa.mana_regen == 2 and fc.mana_regen == 2 def test_percent_and_flat_are_told_apart(): """Derselbe Name trägt beide Skalen — unter 1 Anteil, darüber flach.""" assert traits.effects_of({"ADAP": 0.3})["attack_damage_pct"] == 0.3 assert traits.effects_of({"ADAP": 30})["attack_damage_pct"] == 0.3 def test_unknown_variables_are_ignored(): assert traits.effects_of({"OverrunCombats": 3, "RengarGold": 5}) == {} def test_durability_reduces_incoming_damage(): gains = traits.effects_of({"JuggernautDurability": 0.2}) assert gains["durability"] == 0.2 def test_the_panel_and_the_fight_count_the_same(): """Zwei Kopien desselben Champions sind ein Trait-Träger. Zählt das UI anders als der Kampf, zeigt es Stufen an, die im Gefecht nicht wirken. """ board = [{"api_name": "A", "stars": 1}, {"api_name": "A", "stars": 2}, {"api_name": "B", "stars": 1}] assert traits.counts(board, UNITS)["PANZER"] == 2 step = traits.active(board, UNITS, TRAITS)["PANZER"] assert step["units"] == 2 and step["step"] == 1 def test_unknown_units_do_not_count(): board = [{"api_name": "GIBTS_NICHT", "stars": 1}] assert traits.counts(board, UNITS) == {}