Every crafting skill gets a tool and a station

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-20 21:20:25 +01:00
parent a86594594a
commit 91a5263acf
6 changed files with 90 additions and 29 deletions

37
game.py
View file

@ -120,14 +120,18 @@ def _armour_stats(weight: str, slot: str, tier: int) -> dict:
PLURALS = {"sword": "swords", "shield": "shields", "helmet": "helmets", "greaves": "greaves", "cuirass": "cuirasses"}
PIECE_ICONS = {"sword": "⚔️", "shield": "🛡️", "helmet": "🪖", "legs": "🦿", "body": "🦾"}
COPPER_ICONS = {"sword": "🗡️", "helmet": "⛑️", "legs": "🦵", "body": "🥋"}
# Gathering tools: one slot per skill, `speed` cuts the action time.
# Tools: one slot per skill, `speed` cuts the action time. Smiths make every tool.
TOOLS = {"mining": ("pickaxe", "⛏️"), "woodcutting": ("axe", "🪓"), "farming": ("hoe", "🪏"),
"fishing": ("fishing rod", "🎣"), "hunting": ("hunting knife", "🔪"), "construction": ("hammer", "🔨")}
"fishing": ("fishing rod", "🎣"), "hunting": ("hunting knife", "🔪"), "construction": ("hammer", "🔨"),
"smithing": ("chisel", "🔧"), "jewelcrafting": ("gem drill", "🪛"), "cooking": ("cleaver", "🔪"),
"herblore": ("mortar and pestle", "🥣"), "leatherworking": ("awl", "📍"), "tailoring": ("shears", "✂️")}
TOOL_SPEED = [0.15, 0.30, 0.38, 0.45, 0.52, 0.60]
# Crafting stations: the builder's tools for every crafting skill, as fast as the smith's
# tools for gathering. Each takes the tier's planks and hardware and a material from
# another trade. skill: (id suffix, noun, glyph, other material)
# Crafting stations: a second slot for every crafting skill, beside its tool, and as fast.
# Builders make every station, from the tier's planks and hardware and a material from
# another trade. A station speeds what's made at it, not work like the building site.
# skill: (id suffix, noun, glyph, other material)
STATIONS = {
"construction": ("workbench", "workbench", "toolbox", "bar"),
"smithing": ("anvil_stand", "anvil stand", "anvil-impact", "leather"),
"jewelcrafting": ("jewellers_bench", "jeweller's bench", "gem-chain", "cloth"),
"cooking": ("hearth", "hearth", "campfire", "bar"),
@ -315,7 +319,7 @@ def station_material(kind: str, tier: int) -> str:
for _tier, _wood in enumerate(WOODS):
for _skill, (_suffix, _noun, _glyph, _kind) in STATIONS.items():
ITEMS[f"{_wood}_{_suffix}"] = {
"name": f"{WOOD_NAMES[_tier]} {_noun}", "icon": "🪚", "tier": _tier, "slot": f"tool_{_skill}", "tool": _skill,
"name": f"{WOOD_NAMES[_tier]} {_noun}", "icon": "🪚", "tier": _tier, "slot": f"station_{_skill}", "station": _skill,
"speed": TOOL_SPEED[_tier], "req": [_skill, EQUIP_LEVELS[_tier]], "value": 0}
ITEMS[f"{_wood}_strongbox"] = {"name": f"{WOOD_NAMES[_tier]} strongbox", "plural": f"{WOOD_NAMES[_tier]} strongboxes",
"icon": "🧰", "tier": _tier, "slot": "storage", "slots": STRONGBOX_SLOTS[_tier], "value": 0}
@ -433,7 +437,7 @@ for _id, _name, _level, _herb, _second, _skill, _effect in POTIONS:
# What the city eats first: plain food before the good stuff.
FOOD_ORDER = tuple(sorted((item for item, spec in ITEMS.items() if "food" in spec), key=lambda i: ITEMS[i]["heal"]))
EQUIP_SLOTS = (["weapon", "shield", "helmet", "body", "legs", "ring", "amulet", "trinket", "storage", "bag"]
+ [f"tool_{skill}" for skill in [*TOOLS, *STATIONS]])
+ [f"tool_{skill}" for skill in TOOLS] + [f"station_{skill}" for skill in STATIONS])
SKILLS = [
{"id": "mining", "name": "Mining", "icon": "⛏️", "group": "Gathering"},
@ -1090,7 +1094,7 @@ RAID_TRAITS = ["lightly armoured, heavy on archers", "mounted and fast, few bows
# --- world ---------------------------------------------------------------
WORLD_VERSION = 22
WORLD_VERSION = 23
def new_world(now: float, speed: float = 1.0) -> dict:
@ -1257,6 +1261,17 @@ def migrate(world: dict, now: float | None = None) -> dict:
for player in world["players"].values():
player.setdefault("tracked", None)
world["version"] = 22
if world["version"] < 23:
# Stations got their own slot: crafting skills have a tool and a station now.
for player in world["players"].values():
equip = player["equip"]
for slot in EQUIP_SLOTS:
equip.setdefault(slot, None)
for skill in STATIONS:
item = equip.get(f"tool_{skill}")
if item and ITEMS[item].get("station"):
equip[f"tool_{skill}"], equip[f"station_{skill}"] = None, item
world["version"] = 23
return world
@ -1884,6 +1899,9 @@ def action_time(world: dict, player: dict, action: dict) -> float:
tool = player["equip"].get(f"tool_{action['skill']}")
if tool:
seconds *= 1 - ITEMS[tool]["speed"]
station = player["equip"].get(f"station_{action['skill']}")
if station and action["outputs"]:
seconds *= 1 - ITEMS[station]["speed"]
if action["skill"] == "smithing":
seconds *= 1 - 0.08 * building_level(world, "smithy")
seconds *= 0.9 if fitted(world, "bellows") else 1
@ -3990,7 +4008,8 @@ HERB_TINTS = {"guam_leaf": "#7fbf5a", "marrentill": "#e7c84a", "tarromin": "#d05
PIECE_GLYPHS = {"sword": "pointy-sword", "shield": "round-shield", "helmet": "visored-helm",
"legs": "leg-armor", "body": "breastplate"}
TOOL_GLYPHS = {"pickaxe": "war-pick", "axe": "wood-axe", "hoe": "sickle", "fishing rod": "fishing-pole",
"hunting knife": "bowie-knife", "hammer": "claw-hammer"}
"hunting knife": "bowie-knife", "hammer": "claw-hammer", "chisel": "chisel", "gem drill": "drill",
"cleaver": "meat-cleaver", "mortar and pestle": "mortar", "awl": "needle-drill", "shears": "shears"}
LEATHER_GLYPHS = {"cap": "hood", "legs": "trousers", "body": "leather-vest"}
CLOTH_GLYPHS = {"hood": "pointy-hat", "legs": "trousers", "body": "robe"}
FIBRE_GLYPHS = {"cotton": "cotton-flower", "silk_cocoons": "butterfly", "moonpetal": "lotus-flower",