Guard jerkins: leather-only city kit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4abf165857
commit
54f703341e
3 changed files with 56 additions and 12 deletions
37
game.py
37
game.py
|
|
@ -206,6 +206,10 @@ LEATHERS = [
|
|||
# piece suffix, slot, noun, leather used, level above the tier, icon
|
||||
LEATHER_PIECES = [("cap", "helmet", "cap", 2, 2, "🧢"), ("legs", "legs", "trousers", 3, 7, "👖"),
|
||||
("body", "body", "jerkin", 4, 11, "🦺")]
|
||||
# Guard jerkins: city kit, not worn by players. Only the tier's leather, so a hunter can turn
|
||||
# their own hides into them; every paid guard wears the best one in the stockpile.
|
||||
GUARD_JERKIN_LEATHER = 12
|
||||
JERKIN_DEFENCE = 0.2 # defence per point of armour, per guard
|
||||
# Tailoring: a fibre from Farming, the cloth woven from it, and the light armour sewn from that.
|
||||
# fibre (id, name, icon, value), farming level, seconds, xp, cloth (id, name, value), armour id prefix, armour name prefix
|
||||
CLOTHS = [
|
||||
|
|
@ -375,6 +379,11 @@ for _tier, (_raw, _leather, _prefix, _label) in enumerate(LEATHERS):
|
|||
}
|
||||
if _noun == "trousers":
|
||||
ITEMS[f"{_prefix}_{_suffix}"]["plural"] = ITEMS[f"{_prefix}_{_suffix}"]["name"]
|
||||
ITEMS[f"{_prefix}_guard_jerkin"] = {
|
||||
"name": f"{_label} guard jerkin", "icon": "🦺", "kit": "jerkin", "tier": _tier,
|
||||
"armour": _armour_stats("medium", "body", _tier)["armour"],
|
||||
"value": round(GUARD_JERKIN_LEATHER * _leather[2] * 1.3),
|
||||
}
|
||||
for _tier, (_fibre, _level, _time, _xp, _cloth, _prefix, _label) in enumerate(CLOTHS):
|
||||
ITEMS.setdefault(_fibre[0], {"name": _fibre[1], "icon": _fibre[2], "value": _fibre[3]})
|
||||
ITEMS[_cloth[0]] = {"name": _cloth[1], "icon": "🧶", "value": _cloth[2]}
|
||||
|
|
@ -608,6 +617,10 @@ def _tiered_actions() -> list[dict]:
|
|||
25 + 5 * used + 2 * tier, used * piece_xp[tier],
|
||||
{leather[0]: used, **({reagent("medium", tier): REAGENT_COUNTS[slot]} if tier else {})},
|
||||
{f"{prefix}_{suffix}": 1}, group=label))
|
||||
actions.append(_action(f"lw_{prefix}_guard_jerkin", "leatherworking", f"{label} guard jerkin",
|
||||
TIER_LEVELS[tier] + 9, 25 + 5 * GUARD_JERKIN_LEATHER + 2 * tier, 4 * piece_xp[tier],
|
||||
{leather[0]: GUARD_JERKIN_LEATHER}, {f"{prefix}_guard_jerkin": 1},
|
||||
group=label))
|
||||
for tier, (fibre, level, seconds, fibre_xp, cloth, prefix, label) in enumerate(CLOTHS):
|
||||
if tier: # flax is grown with the other building materials
|
||||
actions.append(_action(f"grow_{fibre[0]}", "farming", FIBRE_VERBS.get(fibre[0], f"Grow {fibre[1].lower()}"),
|
||||
|
|
@ -2087,7 +2100,7 @@ def city_uses(item: str) -> list[str]:
|
|||
spec = ITEMS[item]
|
||||
if "food" in spec:
|
||||
uses.append("the granary")
|
||||
if spec.get("slot") in ("weapon", "shield") or item == "arrows":
|
||||
if spec.get("slot") in ("weapon", "shield") or "kit" in spec or item == "arrows":
|
||||
uses.append("the armoury")
|
||||
if item == "water_barrel":
|
||||
uses.append("the fire brigade")
|
||||
|
|
@ -4184,10 +4197,15 @@ def population_view(world: dict) -> dict:
|
|||
}
|
||||
|
||||
|
||||
def kit_slot(item: str) -> str | None:
|
||||
"""Where a defender carries it: a gear slot, or city-only kit like guard jerkins."""
|
||||
return ITEMS[item].get("slot") or ITEMS[item].get("kit")
|
||||
|
||||
|
||||
def best_kit(stock: dict, slot: str, stat: str, people: int) -> float:
|
||||
"""Total `stat` when the best `slot` items in the stockpile go to `people` defenders."""
|
||||
total = 0
|
||||
for item in sorted((i for i in stock if ITEMS[i].get("slot") == slot), key=lambda i: -ITEMS[i].get(stat, 0)):
|
||||
for item in sorted((i for i in stock if kit_slot(i) == slot), key=lambda i: -ITEMS[i].get(stat, 0)):
|
||||
take = min(people, stock[item])
|
||||
total += take * ITEMS[item].get(stat, 0)
|
||||
people -= take
|
||||
|
|
@ -4197,26 +4215,26 @@ def best_kit(stock: dict, slot: str, stat: str, people: int) -> float:
|
|||
|
||||
|
||||
def kit_count(stock: dict, slot: str) -> int:
|
||||
return sum(qty for item, qty in stock.items() if ITEMS[item].get("slot") == slot)
|
||||
return sum(qty for item, qty in stock.items() if kit_slot(item) == slot)
|
||||
|
||||
|
||||
def wear_share(ratio: float) -> float:
|
||||
"""Share of the issued swords and shields a fight breaks: 10% in an easy win, 30% in a close one, 40% in defeat."""
|
||||
"""Share of the issued swords, shields and jerkins a fight breaks: 10% in an easy win, 30% in a close one, 40% in defeat."""
|
||||
if ratio < 1:
|
||||
return 0.4
|
||||
return 0.1 + 0.2 * max(0.0, 2 - ratio)
|
||||
|
||||
|
||||
def wear_kit(world: dict, share: float, rng: random.Random) -> dict:
|
||||
"""Break `share` of the swords and shields handed to defenders, worst first. Spares are untouched."""
|
||||
"""Break `share` of the swords, shields and jerkins handed to defenders, worst first. Spares are untouched."""
|
||||
stock = world["city"]["stockpile"]
|
||||
broken = {}
|
||||
for slot, stat in (("weapon", "power"), ("shield", "armour")):
|
||||
for slot, stat in (("weapon", "power"), ("shield", "armour"), ("jerkin", "armour")):
|
||||
people = guards_on_duty(world)
|
||||
issued = []
|
||||
if not people:
|
||||
continue
|
||||
for item in sorted((i for i in stock if ITEMS[i].get("slot") == slot), key=lambda i: -ITEMS[i].get(stat, 0)):
|
||||
for item in sorted((i for i in stock if kit_slot(i) == slot), key=lambda i: -ITEMS[i].get(stat, 0)):
|
||||
take = min(people, stock[item])
|
||||
issued.append((item, take))
|
||||
people -= take
|
||||
|
|
@ -4277,6 +4295,7 @@ def defence(world: dict, guards: int | None = None) -> dict:
|
|||
"militia": round(militia * armed / posts, 1) if posts else 0,
|
||||
"weapons": round(0.35 * best_kit(stock, "weapon", "power", armed), 1),
|
||||
"shields": round(0.5 * best_kit(stock, "shield", "armour", armed), 1),
|
||||
"jerkins": round(JERKIN_DEFENCE * best_kit(stock, "jerkin", "armour", armed), 1),
|
||||
"arrows": min(100, stock.get("arrows", 0) // 10),
|
||||
"drilled": round(drilled(world), 1),
|
||||
"rallied": city.get("rally", 0), # favour bought before drilling existed; gone after the next raid
|
||||
|
|
@ -6133,6 +6152,7 @@ def _assign_glyphs() -> None:
|
|||
ITEMS[leather[0]].update(glyph="rolled-cloth", tint=tint)
|
||||
for suffix, glyph in LEATHER_GLYPHS.items():
|
||||
ITEMS[f"{prefix}_{suffix}"].update(glyph=glyph, tint=tint)
|
||||
ITEMS[f"{prefix}_guard_jerkin"].update(glyph="leather-armor", tint=tint)
|
||||
for trophy, (_name, line, tier) in TROPHIES.items():
|
||||
ITEMS[trophy].update(glyph=TROPHY_GLYPHS[line], tint=TIER_TINTS[tier - 1])
|
||||
for item, (weight, tier) in REAGENTS.items():
|
||||
|
|
@ -6220,6 +6240,7 @@ ORDER_RECIPES, ORDER_RAW = _order_sources()
|
|||
# line here (new / balance / fix), and a new release a new entry on top.
|
||||
PATCH_NOTES = [
|
||||
{"date": "2026-10-27", "title": "Prayer", "notes": [
|
||||
("new", "Added resource dumps for Leatherworking: Guard Jerkins"),
|
||||
("fix", "+Q button: rounded corners."),
|
||||
("fix", "Make box: number field sits in front of +Q."),
|
||||
("new", "Crafting queue menu: tap ⏳ in the top bar to reorder, change counts, skip or clear."),
|
||||
|
|
@ -6347,7 +6368,7 @@ def content() -> dict:
|
|||
"buildings": buildings, "xp_table": XP_TABLE, "offline_cap": OFFLINE_CAP, "tiers": TIERS,
|
||||
"city_uses": {item: city_uses(item) for item in ITEMS},
|
||||
"prayers": [{**prayer, "text": describe_prayer(prayer)} for prayer in PRAYERS], "max_prayers": MAX_PRAYERS,
|
||||
"potion_charges": POTION_CHARGES, "order_recipes": ORDER_RECIPES, "order_raw": ORDER_RAW,
|
||||
"potion_charges": POTION_CHARGES, "jerkin_defence": JERKIN_DEFENCE, "order_recipes": ORDER_RECIPES, "order_raw": ORDER_RAW,
|
||||
"order_limit": ORDER_LIMIT, "order_max": ORDER_MAX, "make_max": MAKE_MAX, "queue_max": QUEUE_MAX, "input_share": INPUT_SHARE, "problems": PROBLEMS, "fittings": list(FITTING_BY_ID.values()),
|
||||
"equip_slots": EQUIP_SLOTS, "class_speed": CLASS_SPEED, "rest_rate": REST_RATE, "bite": BITE, "eat_below": EAT_BELOW, "eat_choices": EAT_CHOICES,
|
||||
"abilities": combat.ABILITIES, "enemy_abilities": combat.ENEMY_ABILITIES, "unlock": combat.UNLOCK, "auto_cd": combat.AUTO_CD, "watch": combat.WATCH, "gcd": combat.GCD,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue