Dungeon loot: patterns, masterworks, relics, uniques

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-24 13:48:16 +01:00
parent 60b446acfd
commit 8afcba79fc
8 changed files with 358 additions and 18 deletions

View file

@ -944,6 +944,104 @@ class DungeonTest(unittest.TestCase):
self.assertGreaterEqual(joined[0][0], yell[0])
class LootTest(unittest.TestCase):
def smith(self, level=30):
world = world_with(("sam", "miner"))
p = world["players"]["sam"]
p["xp"]["smithing"] = game.XP_TABLE[level]
return world, p
def test_every_dungeon_has_relic_patterns_and_a_unique(self):
for key in game.DUNGEONS:
loot = game.ACTION_BY_ID[key]["loot"]
self.assertEqual(len(loot["patterns"]), 7)
self.assertTrue(game.ITEMS[loot["unique"]]["mods"])
for pattern in loot["patterns"]:
made = game.ITEMS[game.ITEMS[pattern]["pattern"]]
self.assertEqual(made["req"], ["combat", game.DUNGEONS[key]["level"]])
base = game.ITEMS[made["base"]]
for stat in ("power", "armour"):
if base.get(stat):
self.assertGreater(made[stat], base[stat])
def test_bosses_drop_relics_and_patterns(self):
ogre = game.DUNGEONS["dungeon_watchtower"]["pulls"][7][1]
fight = {"pack": [dict(ogre[0])], "kills": ["e0"]}
found = {}
for seed in range(200):
for item, qty in game.pack_loot(game.ACTION_BY_ID["dungeon_watchtower"], fight, random.Random(seed))[1].items():
found[item] = found.get(item, 0) + qty
self.assertEqual(found["watchtower_relic"], 400) # two, every time
patterns = sum(qty for item, qty in found.items() if item.startswith("pattern_"))
self.assertTrue(40 < patterns < 100) # about 35%
self.assertGreater(found.get("ogres_knuckle", 0), 0)
def test_learn_a_pattern_and_reforge(self):
world, p = self.smith()
reforge = game.ACTION_BY_ID["reforge_ogre_forged_warhammer"]
p["bank"] = {"iron_warhammer": 1, "watchtower_relic": 3}
self.assertEqual(game.can_start(world, p, reforge), "Learn its pattern first")
self.assertEqual(game.learn_pattern(p, "pattern_ogre_forged_warhammer"), "You don't have it")
p["bank"]["pattern_ogre_forged_warhammer"] = 1
p["xp"]["smithing"] = game.XP_TABLE[20]
self.assertEqual(game.learn_pattern(p, "pattern_ogre_forged_warhammer"), "Needs smithing level 29")
p["xp"]["smithing"] = game.XP_TABLE[30]
self.assertIsNone(game.learn_pattern(p, "pattern_ogre_forged_warhammer"))
self.assertNotIn("pattern_ogre_forged_warhammer", p["bank"])
self.assertEqual(game.learn_pattern(p, "pattern_ogre_forged_warhammer"), "You don't have it")
world["city"]["buildings"]["smithy"]["level"] = 5
self.assertIsNone(game.start_action(world, p, "reforge_ogre_forged_warhammer", T0, once=True))
game.process_player(world, p, T0 + 3600, random.Random(1))
self.assertEqual(p["bank"].get("ogre_forged_warhammer"), 1)
self.assertNotIn("watchtower_relic", p["bank"])
def ranger(self, *uniques):
world = world_with(("ash", "ranger"))
p = world["players"]["ash"]
p["xp"]["combat"] = game.XP_TABLE[85]
p["equip"].update(weapon="magic_bow", helmet="mammoth_leather_cap", body="mammoth_leather_body",
legs="mammoth_leather_legs")
for unique in uniques:
p["equip"][game.ITEMS[unique]["slot"]] = unique
p["hp"] = game.max_hp(p)
p["bank"] = {"arrows": 1000}
return world, p
def test_a_unique_changes_an_ability(self):
world, p = self.ranger()
self.assertEqual(game.fighter(p, game.NO_BLESSING, {})["mods"], {})
plain = game.simulate_fight(world, p, game.ACTION_BY_ID["fight_scouts"], random.Random(4))
world, p = self.ranger("wyrmscale_quiver")
mods = game.fighter(p, game.NO_BLESSING, {})["mods"]
self.assertEqual(mods["volley"], {"cost": 0, "c": 1.4})
quivered = game.simulate_fight(world, p, game.ACTION_BY_ID["fight_scouts"], random.Random(4))
self.assertGreater(game.member_of(plain, "ash")["shot"], 0)
self.assertEqual(game.member_of(quivered, "ash")["shot"], 0) # no arrows
def test_a_pendant_mends_a_second_ally(self):
world = world_with(("kay", "homesteader"), ("wil", "builder"), ("bo", "miner"))
players = list(world["players"].values())
for p in players:
p["xp"]["combat"] = game.XP_TABLE[40]
p["hp"] = game.max_hp(p)
kay = world["players"]["kay"]
kay["equip"].update(weapon="willow_staff", amulet="barrow_kings_pendant")
ogre = game.ACTION_BY_ID["fight_ruins"]
heals = 0
for seed in range(5):
fight = game.draw_fight(world, players, ogre, random.Random(seed))
mends = [e for e in fight["events"] if e[1] == "kay" and e[3] == "heal" and e[6] == "mend"]
heals += sum(1 for a, b in zip(mends, mends[1:]) if a[0] == b[0] and a[2] != b[2])
self.assertGreater(heals, 0) # one cast, two people healed
def test_old_worlds_get_patterns(self):
world, p = self.smith()
del p["patterns"]
world["version"] = 29
game.migrate(world, T0)
self.assertEqual(p["patterns"], [])
class NewSkillsTest(unittest.TestCase):
def test_tools_speed_up_gathering(self):
world = world_with(("pia", "commoner"))