diff --git a/game.py b/game.py
index cac025a..066fabd 100644
--- a/game.py
+++ b/game.py
@@ -3329,7 +3329,8 @@ def process_player(world: dict, player: dict, now: float, rng: random.Random | N
burn_fires(world, current["start"] + duration)
reason = can_start(world, player, action)
if reason:
- if next_queued(world, player, current["start"], summary, skipped=current) or \
+ if fills(action) and "left" in current and finish_once(world, player, current["start"], reason, summary) or \
+ next_queued(world, player, current["start"], summary, skipped=current) or \
"order" in current and finish_once(world, player, current["start"], reason, summary):
current = player["action"]
continue
@@ -3346,7 +3347,7 @@ def process_player(world: dict, player: dict, now: float, rng: random.Random | N
current["start"] += duration
if current.get("plot2"):
current["turn"] = 1 - current.get("turn", 0)
- if player["action"] is current and "left" in current:
+ if player["action"] is current and "left" in current and not fills(action):
current["left"] -= 1
if current["left"] <= 0 and finish_once(world, player, current["start"], summary=summary):
current = player["action"]
@@ -3354,7 +3355,8 @@ def process_player(world: dict, player: dict, now: float, rng: random.Random | N
# Out of materials: stop now, not once the next bar has filled.
reason = can_start(world, player, growing(player))
if reason:
- if next_queued(world, player, current["start"], summary, skipped=current) or \
+ if fills(action) and "left" in current and finish_once(world, player, current["start"], reason, summary) or \
+ next_queued(world, player, current["start"], summary, skipped=current) or \
"order" in current and finish_once(world, player, current["start"], reason, summary):
current = player["action"]
continue
@@ -3373,15 +3375,20 @@ def stop(player: dict, reason: str | None = None) -> None:
def queueable(action: dict) -> bool:
- """Crafting and gathering: makes or gathers something. Only these can be queued."""
- return bool(action["outputs"]) and not (
+ """Crafting, gathering and tending. Only these can be queued."""
+ return fills(action) or bool(action["outputs"]) and not (
action.get("enemy") or action.get("special") or action.get("together"))
+def fills(action: dict) -> bool:
+ """A queued tend has no count: it runs until your pile is full, then on with the queue."""
+ return action.get("special") == "tend"
+
+
def queue_reason(world: dict, player: dict, action: dict) -> str | None:
"""Why it can't go in the queue. Materials are checked when its turn comes."""
if not queueable(action):
- return "Only crafting and gathering can be queued"
+ return "Only crafting, gathering and tending can be queued"
if skill_level(player, action["skill"]) < action["level"]:
return f"Needs level {action['level']}"
if action.get("pattern") and action["pattern"] not in player.get("patterns", []):
@@ -6747,6 +6754,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-28", "title": "Queue", "notes": [
+ ("new", "Firekeeping: +Q next to ๐ฅ Tend all queues tending until your piles are full, then the queue moves on."),
("new", "City work orders: ๐๏ธ City when posting, or ๐จ on anything a building needs (goes straight into its fund). Anyone can craft them, several at once. Reagents earn their worth in favour, the maker the rest."),
("new", "Work orders: no size cap (was 500 crafted / 2,000 materials)."),
("new", "Work orders: no cap on open orders (was 5)."),
diff --git a/static/app.js b/static/app.js
index 460a8f0..880b986 100644
--- a/static/app.js
+++ b/static/app.js
@@ -800,7 +800,8 @@ function queuePanel() {
const a = recipe(e.id), why = me.blocked[e.id];
return `