Dungeons wait for the leader to start

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-25 19:21:37 +00:00
parent e43611e618
commit cf91cbce3c
4 changed files with 60 additions and 15 deletions

33
game.py
View file

@ -3177,7 +3177,7 @@ def joinable(world: dict, player: dict) -> bool:
action = ACTION_BY_ID[current["id"]]
if action.get("dungeon"):
party = world["parties"].get(current.get("party"))
return not party or (not party.get("run", {}).get("pull") and len(party["members"]) < DUNGEON_SIZE)
return not party or ("run" not in party and len(party["members"]) < DUNGEON_SIZE)
return "enemy" in action and not action.get("special")
@ -3198,7 +3198,7 @@ def join_fight(world: dict, player: dict, uid: str, now: float) -> str | None:
return "No one to join"
run = party_of(world, host)
if run and ACTION_BY_ID[run["action"]].get("dungeon") and run is not party_of(world, player):
if run.get("run", {}).get("pull") or (run["fight"] and now >= run["start"] + run["fight"]["rest"] / run["fight"]["pace"]):
if "run" in run:
return "The run has started"
if len(run["members"]) >= DUNGEON_SIZE:
return "The group is full"
@ -3282,14 +3282,14 @@ def process_party(world: dict, pid: str, now: float, rng: random.Random) -> None
break
members = [world["players"][uid] for uid in party["members"]]
if action.get("dungeon"):
# A run waits for anyone who's looked away: it's played together.
# A run waits for its leader to start it, then for anyone who's looked away: it's played together.
away = [p for p in members if p["last_active"] < party["start"] - DUNGEON_AWAY]
if away:
if "run" not in party or away:
party["start"] = max(party["start"], now)
for player in members:
player["action"]["start"] = party["start"]
break
party["fight"] = draw_pull(world, members, action, party.setdefault("run", {"pull": 0, "wipes": 0}),
party["fight"] = draw_pull(world, members, action, party["run"],
rng, party["start"])
else:
party["fight"] = draw_fight(world, members, action, rng, party["start"])
@ -3402,7 +3402,27 @@ def run_of(world: dict, player: dict) -> dict | None:
if world["players"][uid]["last_active"] < party["start"] - DUNGEON_AWAY]
return {"dungeon": spec["name"], "pull": run["pull"] + 1, "of": len(spec["pulls"]), "wipes": run["wipes"],
"next": spec["pulls"][min(run["pull"], len(spec["pulls"]) - 1)][0], "away": away,
"leader": party["members"][0], "size": len(party["members"])}
"leader": party["members"][0], "size": len(party["members"]), "started": "run" in party}
def start_run(world: dict, player: dict, now: float) -> str | None:
"""The leader takes the group in: no one else can join from here on."""
party = party_of(world, player)
if not party or not ACTION_BY_ID[party["action"]].get("dungeon"):
return "Not in a dungeon"
if party["members"][0] != player["id"]:
return "Only the leader starts"
if "run" in party:
return "Already started"
if len(party["members"]) < GROUP_SIZE:
return f"Needs {GROUP_SIZE} or more"
party["run"] = {"pull": 0, "wipes": 0}
party["start"] = now
for uid in party["members"]:
world["players"][uid]["action"]["start"] = now
spec = DUNGEONS[ACTION_BY_ID[party["action"]]["dungeon"]]
log(world, now, "party", f"{player['name']} led {len(party['members'])} into {spec['name']}", player["id"])
return None
def pull_now(world: dict, player: dict, now: float) -> str | None:
@ -5978,6 +5998,7 @@ PATCH_NOTES = [
{"date": "2026-10-25", "title": "Titles", "notes": [
("new", "Fishing 50 also earns a second title: Master baiter."),
("balance", "Boiling hide glue now uses the kitchen fire: while it's lit, glue costs no logs."),
("fix", "Dungeons wait for the leader to press Start, so groups of 3 and 4 can form. No one can join once it starts."),
]},
{"date": "2026-10-24", "title": "Dungeon loot", "notes": [
("new", "Masterwork patterns: every dungeon boss can drop one of 7 (15% from a mini-boss, 35% from the last boss, "