Rings of precision become rings of haste

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-20 20:26:54 +01:00
parent 6883b707ad
commit 5facec9ee8
4 changed files with 43 additions and 12 deletions

33
game.py
View file

@ -221,7 +221,7 @@ PROSPECT = ["stone", "iron_ore", "coal", "mithril_ore", "adamantite_ore", "runit
# Rings for offence, amulets for defence, trinkets for everything else.
# key, slot, noun, stat, bonus by tier, bands, gems, shards, level above the tier, glyph
JEWELLERY = [
("precision", "ring", "ring of precision", "accuracy", [4, 8, 12, 16, 20, 25], 1, 1, 1, 2, "diamond-ring"),
("haste", "ring", "ring of haste", "haste", [5, 7, 8, 9, 10, 11], 1, 1, 1, 2, "diamond-ring"),
("fury", "ring", "ring of fury", "crit", [2, 3, 5, 6, 8, 10], 1, 1, 1, 2, "big-diamond-ring"),
("might", "ring", "ring of might", "power", [2, 4, 6, 9, 12, 15], 1, 1, 1, 2, "swirl-ring"),
("vigour", "amulet", "amulet of vigour", "hp", [5, 10, 16, 23, 31, 40], 2, 1, 2, 8, "heart-necklace"),
@ -231,9 +231,9 @@ JEWELLERY = [
("charm", "trinket", "lucky charm", "double", [2, 3, 4, 5, 6, 8], 1, 2, 1, 5, "clover"),
("loupe", "trinket", "loupe", "masterwork", [2, 3, 4, 4, 5, 6], 1, 2, 1, 5, "magnifying-glass"),
]
# How each jewellery bonus reads: name, unit, glyph, tint.
# How each jewellery bonus reads: name, unit, glyph, tint (and a sign, if it takes away).
JEWEL_STATS = {
"accuracy": {"name": "Accuracy", "unit": "%", "glyph": "archery-target", "tint": "#e0b04a"},
"haste": {"name": "Swing time", "unit": "%", "glyph": "stopwatch", "tint": "#9fb3c8", "sign": "-"},
"crit": {"name": "Crit chance", "unit": "%", "glyph": "striking-diamonds", "tint": "#e05a5a"},
"power": {"name": "Power", "unit": "", "glyph": "biceps", "tint": "#e06a6a"},
"hp": {"name": "Max HP", "unit": "", "glyph": "hearts", "tint": "#e06a8a"},
@ -1033,7 +1033,7 @@ RAID_TRAITS = ["lightly armoured, heavy on archers", "mounted and fast, few bows
# --- world ---------------------------------------------------------------
WORLD_VERSION = 19
WORLD_VERSION = 20
def new_world(now: float, speed: float = 1.0) -> dict:
@ -1187,9 +1187,29 @@ def migrate(world: dict, now: float | None = None) -> dict:
for player in world["players"].values():
player.setdefault("pinned", [])
world["version"] = 19
if world["version"] < 20:
_precision_to_haste(world)
world["version"] = 20
return world
def _precision_to_haste(world: dict) -> None:
"""Rings of precision became rings of haste: same gem, same slot."""
rename = lambda item: item.replace("_precision", "_haste") if item and item.endswith("_precision") else item
swap = lambda items: {rename(item): qty for item, qty in items.items()}
world["city"]["stockpile"] = swap(world["city"]["stockpile"])
for player in world["players"].values():
player["bank"] = swap(player["bank"])
player["equip"] = {slot: rename(item) for slot, item in player["equip"].items()}
action = player["action"]
if action:
for key in ("id", "resume"):
if key in action:
action[key] = rename(action[key])
for order in world.get("orders", []):
order["item"], order["action"] = rename(order["item"]), rename(order["action"])
# The combat rework: the old area monsters became races, their trophies carry over by
# weapon line and tier, dragonhide became the dragons' reagents, and the leathers past
# bear are hunted now.
@ -1578,8 +1598,9 @@ def fighter(player: dict, blessed: dict, brew: dict, enemy: dict | None = None)
damage = style["hit"] * (CLASS_STYLE_BONUS if CLASS_STYLE.get(player["cls"]) == style_id else 1)
lands = affinity(enemy, style["damage"]) if enemy else 1
taken = blessed["taken"] * (1 - brew.get("reduce", 0))
return {"style": style_id, "damage": style["damage"], "interval": style["interval"],
"accuracy": (10 + 2 * power) * style["accuracy"] * (1 + gear_bonus(player, "accuracy") / 100),
return {"style": style_id, "damage": style["damage"],
"interval": round(style["interval"] * (1 - gear_bonus(player, "haste") / 100), 2),
"accuracy": (10 + 2 * power) * style["accuracy"],
"max_hit": max(2, round((2 + power / 3) * damage * lands)),
"crit": style["crit"] + gear_bonus(player, "crit") / 100,
"first": style.get("first", False), "affinity": lands,