Townsfolk mood: needs, kindling, clothes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
002e990dc4
commit
58a3e66454
6 changed files with 385 additions and 30 deletions
|
|
@ -3242,5 +3242,116 @@ class PartyTest(unittest.TestCase):
|
|||
self.assertEqual(world["parties"], {})
|
||||
|
||||
|
||||
|
||||
class TownsfolkTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.world = world_with()
|
||||
self.city = self.world["city"]
|
||||
self.city["population"] = 100.0
|
||||
self.city["stockpile"] = {}
|
||||
self.now = self.city["last_tick"]
|
||||
|
||||
def test_a_new_city_starts_content(self):
|
||||
self.assertEqual(self.city["happiness"], 0.5)
|
||||
self.assertEqual(game.mood(self.world)["name"], "Content")
|
||||
|
||||
def test_each_tier_adds_a_need(self):
|
||||
for tier, keys in enumerate([["food"], ["food", "warmth"], ["food", "warmth", "clothes"]]):
|
||||
self.city["tier"] = tier
|
||||
self.assertEqual(list(game.happiness(self.world, self.now)["needs"]), keys)
|
||||
|
||||
def test_food_counts_supply_and_kinds(self):
|
||||
# 100 people eat 50 meals a day; a hamlet wants 2 days stored and 4 kinds.
|
||||
self.city["stockpile"] = {"bread": 100, "cooked_meat": 49}
|
||||
food = game.happiness(self.world, self.now)["needs"]["food"]
|
||||
self.assertAlmostEqual(food["score"], 0.5 * 1 + 0.5 * 1 / 4) # meat is short of a day's worth
|
||||
self.city["starving"] = True
|
||||
self.assertEqual(game.happiness(self.world, self.now)["needs"]["food"]["score"], 0)
|
||||
|
||||
def test_the_biggest_pile_is_eaten_first(self):
|
||||
self.city["stockpile"] = {"bread": 10, "cooked_meat": 500}
|
||||
game._city_hour(self.world, self.now)
|
||||
self.assertEqual(self.city["stockpile"]["bread"], 10)
|
||||
self.assertLess(self.city["stockpile"]["cooked_meat"], 500)
|
||||
|
||||
def test_hearths_burn_kindling_first_and_only_from_a_village(self):
|
||||
self.city["stockpile"] = {"kindling": 10, "logs": 10}
|
||||
self.city["weather"]["kind"] = "clear"
|
||||
game._happenings_hour(self.world, self.now, random.Random(1))
|
||||
self.assertEqual(self.city["stockpile"], {"kindling": 10, "logs": 10}) # a hamlet has no hearths
|
||||
self.city["tier"] = 1
|
||||
game._happenings_hour(self.world, self.now, random.Random(1))
|
||||
self.assertLess(self.city["stockpile"]["kindling"], 10)
|
||||
self.assertEqual(self.city["stockpile"]["logs"], 10)
|
||||
|
||||
def test_no_fuel_means_cold_homes(self):
|
||||
self.city["tier"] = 1
|
||||
self.city["weather"]["kind"] = "clear"
|
||||
game._happenings_hour(self.world, self.now, random.Random(1))
|
||||
self.assertTrue(self.city["unheated"])
|
||||
self.assertFalse(self.city["cold"]) # no extra food unless it's snowing
|
||||
self.assertEqual(game.happiness(self.world, self.now)["needs"]["warmth"]["score"], 0)
|
||||
|
||||
def test_clothes_for_the_season_wear_out(self):
|
||||
self.city["tier"] = 2
|
||||
garment = game.SEASON_CLOTHES[game.season(self.world, self.now)["index"]]
|
||||
self.city["stockpile"] = {garment: 100}
|
||||
self.assertEqual(game.happiness(self.world, self.now)["needs"]["clothes"]["score"], 1)
|
||||
for _hour in range(24):
|
||||
game._townsfolk_hour(self.world, self.now, random.Random(1))
|
||||
# 100 people wear out 100 in a 7-day season: about 14 a day.
|
||||
self.assertEqual(self.city["stockpile"][garment], 100 - int(100 / game.SEASON_DAYS))
|
||||
|
||||
def test_mood_drifts_slowly(self):
|
||||
self.assertEqual(game.happiness(self.world, self.now)["target"], 0) # nothing to eat
|
||||
game._townsfolk_hour(self.world, self.now, random.Random(1))
|
||||
self.assertAlmostEqual(self.city["happiness"], 0.5 - game.MOOD_DRIFT)
|
||||
|
||||
def test_unsolved_problems_weigh_on_the_mood(self):
|
||||
self.city["stockpile"] = {"bread": 1000, "cooked_meat": 100, "stew": 100, "cooked_shrimp": 100}
|
||||
self.assertEqual(game.happiness(self.world, self.now)["target"], 1)
|
||||
self.city["problems"].append({"kind": "goblins", "started": self.now, "progress": {}, "work": 0})
|
||||
self.assertAlmostEqual(game.happiness(self.world, self.now)["target"], 1 - game.PROBLEM_MOOD)
|
||||
|
||||
def test_a_lost_raid_shocks_the_mood(self):
|
||||
event = {"strength": 10_000, "sabotage": 0, "group": "the Red Hand"}
|
||||
game._resolve_raid(self.world, event, self.now, random.Random(1))
|
||||
self.assertAlmostEqual(self.city["happiness"], 0.5 + game.MOOD_SHOCKS["raid_lost"])
|
||||
|
||||
def test_misery_drives_people_away_and_weakens_the_guards(self):
|
||||
self.city["buildings"]["barracks"]["level"] = 1
|
||||
self.city["wages"] = 10_000
|
||||
self.city["stockpile"] = {"bread": 1000}
|
||||
content = game.defence(self.world)["parts"]["militia"]
|
||||
self.city["happiness"] = 0.1
|
||||
self.assertAlmostEqual(game.defence(self.world)["parts"]["militia"], round(content * 0.8, 1))
|
||||
self.city["population"] = game.housing(self.world) # full: no growth to hide the leaving
|
||||
before = self.city["population"]
|
||||
game._city_hour(self.world, self.now)
|
||||
self.assertAlmostEqual(self.city["population"], before * (1 - 0.03 / 24))
|
||||
|
||||
def test_unhappy_halts_growth(self):
|
||||
self.city["stockpile"] = {"bread": 1000}
|
||||
self.city["happiness"] = 0.3
|
||||
self.city["population"] = game.housing(self.world) - 5.0 # room to grow
|
||||
before = self.city["population"]
|
||||
game._city_hour(self.world, self.now)
|
||||
self.assertEqual(self.city["population"], before)
|
||||
self.assertTrue(game.population_view(self.world)["halted"])
|
||||
|
||||
def test_misery_makes_trouble(self):
|
||||
self.city["happiness"] = 0.05
|
||||
rng = random.Random(1)
|
||||
rng.random = lambda: 0.0
|
||||
game._townsfolk_hour(self.world, self.now, rng)
|
||||
self.assertIn(self.world["events"][-1]["kind"], ("strike", "theft", "riot"))
|
||||
|
||||
def test_kindling_is_split_under_firekeeping(self):
|
||||
split = game.ACTION_BY_ID["split_willow_logs"]
|
||||
self.assertEqual((split["skill"], split["inputs"], split["outputs"]),
|
||||
("firekeeping", {"willow_logs": 1}, {"kindling": 4}))
|
||||
self.assertIn("the hearths", game.city_uses("kindling"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue