Crafting always adds worth: hardware rounds up, planks, provisions, barrels, fittings +20%

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-28 23:16:34 +00:00
parent 3df9f29b1d
commit 4e54c65503
2 changed files with 16 additions and 15 deletions

17
game.py
View file

@ -22,6 +22,7 @@ BASE_STACK = 1000
CLASS_SPEED = 0.8
LUCKY_CHANCE = 0.1
OVERFLOW_FAVOUR = 0.5 # favour for items a full bank spills to the city, vs. giving on purpose
CRAFT_MARKUP = 1.2 # what making something adds to the worth of its materials
MAX_LOG = 200
PLAYER_LOG = 60 # lines in each player's own ledger
REGEN_PER_HOUR = 0.25 # share of max HP recovered per game hour
@ -79,7 +80,7 @@ ITEMS = {
"flax": {"name": "Flax", "icon": "🌿", "value": 2},
"rope": {"name": "Rope", "icon": "🪢", "value": 8},
"hide_glue": {"name": "Hide glue", "icon": "🍯", "value": 7},
"provisions": {"name": "Provisions", "icon": "🎒", "value": 10},
"provisions": {"name": "Provisions", "icon": "🎒", "value": 12},
}
# --- tier ladders -----------------------------------------------------------
@ -343,13 +344,13 @@ HARDWARE = [
("rune_lock", "Rune lock", "Rune locks", 2, 1),
]
for (_id, _name, _plural, _bars, _made), _metal in zip(HARDWARE, METALS):
ITEMS[_id] = {"name": _name, "plural": _plural, "icon": "🔩", "value": max(1, round(_bars * _metal[5] * 1.2 / _made)),
ITEMS[_id] = {"name": _name, "plural": _plural, "icon": "🔩", "value": math.ceil(round(_bars * _metal[5] * CRAFT_MARKUP / _made, 6)),
"tier": METALS.index(_metal)}
PLANKS = [("plank", "Plank"), ("oak_plank", "Oak plank"), ("willow_plank", "Willow plank"),
("maple_plank", "Maple plank"), ("yew_plank", "Yew plank"), ("magic_plank", "Enchanted plank")]
for (_log, _name, _icon, _value, _action_id, _verb), (_plank, _plank_name) in zip(TREES, PLANKS):
ITEMS[_log] = {"name": _name, "icon": _icon, "value": _value}
ITEMS[_plank] = {"name": _plank_name, "icon": "🪚", "value": _value * 2 + 1}
ITEMS[_plank] = {"name": _plank_name, "icon": "🪚", "value": round(_value * 2 * CRAFT_MARKUP) + 1}
# Weapons: four styles, one per trade. The sword pairs with a shield; the
# warhammer, staff and bow take both hands, so they carry the shield's power too.
SWORD_POWER = next(piece[5] for piece in PIECES if piece[0] == "sword")
@ -5421,9 +5422,10 @@ PROBLEM_ACTIONS = [
]
ACTIONS.extend(PROBLEM_ACTIONS)
ACTION_BY_ID.update({action["id"]: action for action in PROBLEM_ACTIONS})
ITEMS["water_barrel"] = {"name": "Water barrel", "icon": "🛢️", "value": 20}
_barrel = _action("cooper_barrel", "construction", "Water barrel", 10, 35, 18,
{"oak_plank": 2, "iron_nails": 4}, {"water_barrel": 1}, group="Supplies")
ITEMS["water_barrel"] = {"name": "Water barrel", "icon": "🛢️",
"value": round(sum(ITEMS[i]["value"] * q for i, q in _barrel["inputs"].items()) * CRAFT_MARKUP)}
ACTIONS.append(_barrel)
ACTION_BY_ID[_barrel["id"]] = _barrel
@ -5466,18 +5468,17 @@ for _jewel in [*_jewel_actions(), *_storage_actions()]:
ACTION_BY_ID[_jewel["id"]] = _jewel
# Gear and guard kit are worth everything that went into them, trophies and reagents
# included, so crafting one never loses its maker favour or gold.
GEAR_MARKUP = 1.2
for _craft in ACTIONS:
_made = next(iter(_craft["outputs"]), None)
if _made in ITEMS and (ITEMS[_made].get("slot") in ("weapon", "shield", "helmet", "body", "legs")
or "kit" in ITEMS[_made]):
ITEMS[_made]["value"] = round(sum(ITEMS[i]["value"] * q for i, q in _craft["inputs"].items()) * GEAR_MARKUP)
ITEMS[_made]["value"] = round(sum(ITEMS[i]["value"] * q for i, q in _craft["inputs"].items()) * CRAFT_MARKUP)
_dungeon_loot() # masterworks are reforged from all of the above
FITTING_BY_ID = {}
for _id, _name, _building, _blevel, _level, _inputs, _effect, _glyph, _tint in FITTINGS:
FITTING_BY_ID[_id] = {"id": _id, "name": _name, "building": _building, "level": _blevel, "effect": _effect}
ITEMS[_id] = {"name": _name, "plural": _name, "icon": "🪚", "value": sum(ITEMS[i]["value"] * q for i, q in _inputs.items()),
"fitting": _building}
ITEMS[_id] = {"name": _name, "plural": _name, "icon": "🪚", "fitting": _building,
"value": round(sum(ITEMS[i]["value"] * q for i, q in _inputs.items()) * CRAFT_MARKUP)}
_fitting = _action(f"make_{_id}", "construction", _name, _level, 120 + _level * 2, 40 + _level * 4,
_inputs, {_id: 1}, group="Fittings")
ACTIONS.append(_fitting)

View file

@ -2697,10 +2697,10 @@ class WorkOrderTest(unittest.TestCase):
self.fred["bank"] = {"oak_plank": 1, "clay_core": 3}
self.assertIsNone(game.work_order(self.world, self.fred, order["id"], T0))
game.process_player(self.world, self.fred, T0 + 600, random.Random(1))
# Reagents are worth 84 a run; Dave's 2 bars (20) earn 20/84 of half the reward.
self.assertEqual(self.dave["gold"], 17)
self.assertEqual(self.fred["gold"], 123) # the requester's own bar leaves its share with the crafter
self.assertEqual(order["earned"], {"dave": 17})
# Reagents are worth 86 a run; Dave's 2 bars (20) earn 20/86 of half the reward.
self.assertEqual(self.dave["gold"], 16)
self.assertEqual(self.fred["gold"], 124) # the requester's own bar leaves its share with the crafter
self.assertEqual(order["earned"], {"dave": 16})
def test_crafter_tops_up_a_short_pool(self):
self.mike["gold"] = 200
@ -2750,9 +2750,9 @@ class WorkOrderTest(unittest.TestCase):
self.assertEqual(order["status"], "done")
self.assertEqual(self.world["city"]["stockpile"].get("iron_warhammer"), 1)
self.assertEqual(self.fred["bank"], {})
# Hammer 101: Dave's bars 20 and Mike's cores 45 as if donated, Fred the other 36.
self.assertEqual(order["favour"], {"dave": 20, "mike": 45, "fred": 36})
self.assertEqual((self.dave["favour"], self.mike["favour"], self.fred["favour"]), (20, 45, 36))
# Hammer 103: Dave's bars 20 and Mike's cores 45 as if donated, Fred the other 38.
self.assertEqual(order["favour"], {"dave": 20, "mike": 45, "fred": 38})
self.assertEqual((self.dave["favour"], self.mike["favour"], self.fred["favour"]), (20, 45, 38))
line = self.mike["ledger"][-1]
self.assertEqual((line["verb"], line["item"], line["qty"], line["label"]), ("Donated", "clay_core", 3, "City order"))