Combat HP, food and retreat; armour, leatherworking, fishing, tools

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-18 19:27:56 +01:00
parent 3716df7493
commit d2991ebf7a
6 changed files with 381 additions and 44 deletions

View file

@ -98,6 +98,7 @@ class ActionTest(unittest.TestCase):
def test_combat_pays_and_loses(self):
world = world_with(("wil", "warrior"))
p = world["players"]["wil"]
p["bank"] = {"bread": 500}
game.start_action(world, p, "fight_wolves", T0)
summary = game.process_player(world, p, T0 + 48 * 100, random.Random(5))
self.assertEqual(summary["done"], 100)
@ -329,6 +330,7 @@ class EventTest(unittest.TestCase):
world = world_with(("wil", "warrior"))
p = world["players"]["wil"]
p["xp"]["combat"] = game.XP_TABLE[40]
p["hp"] = game.max_hp(p)
raid = self.announce(world)
self.assertEqual(game.start_action(world, p, "sabotage", T0), "No bandit camp has been located")
raid["recon"] = 3 * game.RECON_PER_INTEL
@ -338,5 +340,106 @@ class EventTest(unittest.TestCase):
self.assertLessEqual(raid["sabotage"], 0.3)
class CombatTest(unittest.TestCase):
def fighter(self, level=10, **equip):
world = world_with(("wil", "warrior"))
p = world["players"]["wil"]
p["xp"]["combat"] = game.XP_TABLE[level]
p["hp"] = game.max_hp(p)
p["equip"].update(equip)
return world, p
def test_fights_hurt_and_food_heals(self):
world, p = self.fighter()
p["bank"] = {"bread": 50}
game.start_action(world, p, "fight_scouts", T0)
summary = game.process_player(world, p, T0 + 60 * 60, random.Random(4))
self.assertGreater(summary["damage"], 0)
self.assertGreater(summary["eaten"].get("bread", 0), 0)
self.assertEqual(p["bank"]["bread"], 50 - summary["eaten"]["bread"])
self.assertGreaterEqual(p["hp"], 1)
def test_out_of_food_means_retreat_and_nothing_lost(self):
world, p = self.fighter(level=10, weapon="copper_sword")
p["bank"] = {"stone": 10}
game.start_action(world, p, "fight_scouts", T0)
summary = game.process_player(world, p, T0 + 6 * 3600, random.Random(1))
self.assertIsNone(p["action"])
self.assertTrue(summary["stopped"].startswith("Retreated"))
self.assertEqual(p["equip"]["weapon"], "copper_sword")
self.assertEqual(p["bank"]["stone"], 10)
self.assertLess(p["hp"], game.max_hp(p) * game.TOO_HURT)
self.assertEqual(game.start_action(world, p, "fight_scouts", T0 + 6 * 3600), "Too hurt to fight. Rest, or bring food")
def test_rest_heals(self):
world, p = self.fighter()
p["hp"] = 1
game.regen(world, p, T0 + 4 * 3600)
self.assertEqual(p["hp"], game.max_hp(p))
def test_armour_and_levels_cut_damage(self):
world, bare = self.fighter(level=10)
_, armoured = self.fighter(level=10, helmet="iron_helmet", body="iron_body", legs="iron_legs")
_, veteran = self.fighter(level=60)
wolves = game.ACTION_BY_ID["fight_scouts"]
self.assertLess(game.fight_damage(armoured, wolves), game.fight_damage(bare, wolves) * 0.7)
self.assertLess(game.fight_damage(veteran, wolves), game.fight_damage(bare, wolves))
def test_preferred_food_is_eaten_first(self):
world, p = self.fighter()
p["bank"] = {"bread": 5, "cooked_salmon": 5}
self.assertEqual(game.edible(p), ["bread", "cooked_salmon"])
p["food"] = "cooked_salmon"
self.assertEqual(game.edible(p), ["cooked_salmon", "bread"])
class NewSkillsTest(unittest.TestCase):
def test_tools_speed_up_gathering(self):
world = world_with(("pia", "warrior"))
p = world["players"]["pia"]
plain = game.action_time(world, p, game.ACTION_BY_ID["mine_stone"])
p["equip"]["tool_mining"] = "iron_pickaxe"
self.assertAlmostEqual(game.action_time(world, p, game.ACTION_BY_ID["mine_stone"]), plain * 0.7)
self.assertEqual(game.action_time(world, p, game.ACTION_BY_ID["cut_logs"]), plain)
def test_fish_to_plate(self):
world = world_with(("sam", "scout"))
p = world["players"]["sam"]
game.start_action(world, p, "fish_shrimp", T0)
game.process_player(world, p, T0 + 200, random.Random(1))
self.assertEqual(p["bank"]["raw_shrimp"], 10) # 20s with the scout bonus
p["bank"]["logs"] = 10
game.start_action(world, p, "cook_shrimp", T0 + 200)
game.process_player(world, p, T0 + 1000, random.Random(1))
self.assertEqual(p["bank"]["cooked_shrimp"], 10)
self.assertIn("cooked_shrimp", game.FOOD_ORDER)
def test_hides_to_armour(self):
world = world_with(("kay", "artisan"))
p = world["players"]["kay"]
p["bank"] = {"hide": 4}
game.start_action(world, p, "tan_leather", T0)
game.process_player(world, p, T0 + 1000, random.Random(1))
self.assertGreaterEqual(p["bank"]["leather"], 4)
p["xp"]["leatherworking"] = game.XP_TABLE[12]
self.assertIsNone(game.start_action(world, p, "lw_body", T0 + 1000))
def test_v2_worlds_gain_hp_and_slots(self):
world = world_with(("fred", "pioneer"))
p = world["players"]["fred"]
world["version"] = 2
for key in ("hp", "hp_at", "food"):
del p[key]
p["equip"] = {"weapon": "copper_sword", "shield": None}
del p["xp"]["fishing"], p["xp"]["leatherworking"]
game.migrate(world)
self.assertEqual(world["version"], game.WORLD_VERSION)
self.assertEqual(p["hp"], game.max_hp(p))
self.assertEqual(p["equip"]["weapon"], "copper_sword")
self.assertIsNone(p["equip"]["tool_fishing"])
self.assertEqual(p["xp"]["fishing"], 0)
if __name__ == "__main__":
unittest.main()