Herblore rework: tiered potion ladders per skill

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-19 21:28:00 +01:00
parent 632a12e8bc
commit f810e16eb8
4 changed files with 125 additions and 51 deletions

View file

@ -820,44 +820,52 @@ class HerbloreTest(unittest.TestCase):
def test_herbs_to_potion(self):
world, p = self.world, self.p
p["xp"]["farming"] = game.XP_TABLE[5]
game.start_action(world, p, "grow_guam_leaf", T0)
game.process_player(world, p, T0 + 450, random.Random(1))
self.assertEqual(p["bank"]["guam_leaf"], 10)
p["xp"]["herblore"] = game.XP_TABLE[6]
p["bank"]["logs"] = 3
game.start_action(world, p, "brew_lumberjacks_tonic", T0 + 450)
self.assertIsNone(game.start_action(world, p, "brew_woodcutting_potion_1", T0 + 450)) # tier I needs no Herblore
game.process_player(world, p, T0 + 1000, random.Random(1))
self.assertEqual(p["bank"]["lumberjacks_tonic"], 3)
self.assertEqual(p["bank"]["woodcutting_potion_1"], 3)
self.assertEqual(game.start_action(world, p, "brew_woodcutting_potion_2", T0 + 1000), "Needs level 15")
def test_potion_tiers_climb_the_ladders(self):
mining = [potion for potion in game.POTIONS if potion[0].startswith("mining_potion")]
self.assertEqual([(herb, second) for _id, _name, _level, herb, second, *_rest in mining[:2]],
[("guam_leaf", "copper_ore"), ("marrentill", "iron_ore")])
self.assertEqual([p[2] for p in mining], game.TIER_LEVELS)
self.assertEqual([p[6]["speed"] for p in mining], game.SPEEDS)
self.assertEqual(game.ITEMS["mining_potion_6"]["name"], "Mining potion VI")
self.assertFalse(any("heal" in p[6] or "double" in p[6] for p in game.POTIONS))
def test_skill_potion_speeds_up_and_uses_charges(self):
world, p = self.world, self.p
plain = game.action_time(world, p, game.ACTION_BY_ID["cut_logs"])
p["bank"] = {"lumberjacks_tonic": 1}
self.assertIsNone(game.use_potion(p, "lumberjacks_tonic"))
self.assertEqual(p["potions"]["woodcutting"], {"item": "lumberjacks_tonic", "charges": game.POTION_CHARGES})
p["bank"] = {"woodcutting_potion_3": 1}
self.assertIsNone(game.use_potion(p, "woodcutting_potion_3"))
self.assertEqual(p["potions"]["woodcutting"], {"item": "woodcutting_potion_3", "charges": game.POTION_CHARGES})
self.assertAlmostEqual(game.action_time(world, p, game.ACTION_BY_ID["cut_logs"]), plain * 0.8)
self.assertEqual(game.action_time(world, p, game.ACTION_BY_ID["mine_stone"]), plain)
game.start_action(world, p, "cut_logs", T0)
summary = game.process_player(world, p, T0 + 16 * 60, random.Random(1))
self.assertEqual(summary["potion_out"], ["lumberjacks_tonic"])
self.assertEqual(summary["potion_out"], ["woodcutting_potion_3"])
self.assertNotIn("woodcutting", p["potions"])
def test_empty_potion_is_replaced_from_the_bank(self):
world, p = self.world, self.p
p["bank"] = {"trackers_tincture": 2}
game.use_potion(p, "trackers_tincture")
p["bank"] = {"hunting_potion_1": 2}
game.use_potion(p, "hunting_potion_1")
p["potions"]["hunting"]["charges"] = 1
game.start_action(world, p, "hunt_birds", T0)
summary = game.process_player(world, p, T0 + 25, random.Random(1))
self.assertEqual(summary["potions_drunk"], {"trackers_tincture": 1})
self.assertEqual(summary["potions_drunk"], {"hunting_potion_1": 1})
self.assertEqual(p["potions"]["hunting"]["charges"], game.POTION_CHARGES)
self.assertNotIn("trackers_tincture", p["bank"])
self.assertNotIn("hunting_potion_1", p["bank"])
def test_keep_chance_saves_materials(self):
world, p = self.world, self.p
p["bank"] = {"copper_ore": 100, "logs": 100, "smiths_focus": 1}
game.use_potion(p, "smiths_focus")
p["bank"] = {"copper_ore": 100, "logs": 100, "smithing_potion_2": 1}
game.use_potion(p, "smithing_potion_2")
p["potions"]["smithing"]["charges"] = 1000
game.start_action(world, p, "smith_copper_bar", T0)
summary = game.process_player(world, p, T0 + 20 * 100, random.Random(2))
@ -868,15 +876,30 @@ class HerbloreTest(unittest.TestCase):
world, p = self.world, self.p
p["xp"]["combat"] = game.XP_TABLE[20]
p["hp"] = game.max_hp(p)
p["bank"] = {"defence_potion": 1, "bread": 500}
game.use_potion(p, "defence_potion")
p["bank"] = {"defence_potion_6": 1, "bread": 500}
game.use_potion(p, "defence_potion_6")
game.start_action(world, p, "fight_scouts", T0)
scouts = game.ACTION_BY_ID["fight_scouts"]
brewed = game.with_potion(game.NO_BLESSING, game.potion_effect(p, "combat"))
self.assertAlmostEqual(game.fight_damage(p, scouts, brewed), game.fight_damage(p, scouts) * 0.85)
self.assertAlmostEqual(game.fight_damage(p, scouts, brewed), game.fight_damage(p, scouts) * 0.70)
summary = game.process_player(world, p, T0 + 75 * 10, random.Random(1))
self.assertEqual(p["potions"]["combat"]["charges"], game.POTION_CHARGES - summary["done"])
def test_old_potions_become_their_tiers(self):
world, p = self.world, self.p
world["version"] = 10
p["bank"] = {"lumberjacks_tonic": 4, "woodcutting_potion_3": 1, "regeneration_potion": 2}
p["potions"] = {"mining": {"item": "prospectors_draught", "charges": 12}}
p["action"] = {"id": "brew_anglers_brew", "start": T0, "resume": "brew_smiths_focus"}
world["city"]["stockpile"]["super_strength"] = 1
game.migrate(world, T0)
self.assertEqual(p["bank"], {"woodcutting_potion_3": 5, "defence_potion_3": 2})
self.assertEqual(p["potions"]["mining"], {"item": "mining_potion_2", "charges": 12})
self.assertEqual((p["action"]["id"], p["action"]["resume"]), ("brew_fishing_potion_3", "brew_smithing_potion_2"))
self.assertEqual(world["city"]["stockpile"]["strength_potion_4"], 1)
for action in (p["action"]["id"], p["action"]["resume"]):
self.assertIn(action, game.ACTION_BY_ID)
def test_v5_worlds_get_herblore(self):
world = world_with(("fred", "pioneer"))
world["version"] = 5