Work orders keep the crafting queue
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
97ef606bbf
commit
70be493558
4 changed files with 52 additions and 13 deletions
2
app.py
2
app.py
|
|
@ -419,7 +419,7 @@ class Handler(BaseHTTPRequestHandler):
|
||||||
if path == "/api/order/work":
|
if path == "/api/order/work":
|
||||||
return game.work_order(world, player, body.get("id"), now)
|
return game.work_order(world, player, body.get("id"), now)
|
||||||
if path == "/api/order/drop":
|
if path == "/api/order/drop":
|
||||||
return game.claim_order(world, player, body.get("id"), claim=False)
|
return game.drop_order(world, player, body.get("id"), now)
|
||||||
if path == "/api/order/deliver":
|
if path == "/api/order/deliver":
|
||||||
return game.deliver_order(world, player, body.get("id"), now)
|
return game.deliver_order(world, player, body.get("id"), now)
|
||||||
if path == "/api/seen":
|
if path == "/api/seen":
|
||||||
|
|
|
||||||
38
game.py
38
game.py
|
|
@ -3253,7 +3253,8 @@ def process_player(world: dict, player: dict, now: float, rng: random.Random | N
|
||||||
burn_fires(world, current["start"] + duration)
|
burn_fires(world, current["start"] + duration)
|
||||||
reason = can_start(world, player, action)
|
reason = can_start(world, player, action)
|
||||||
if reason:
|
if reason:
|
||||||
if next_queued(world, player, current["start"], summary, skipped=current):
|
if 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"]
|
current = player["action"]
|
||||||
continue
|
continue
|
||||||
stop(player, reason)
|
stop(player, reason)
|
||||||
|
|
@ -3277,7 +3278,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.
|
# Out of materials: stop now, not once the next bar has filled.
|
||||||
reason = can_start(world, player, growing(player))
|
reason = can_start(world, player, growing(player))
|
||||||
if reason:
|
if reason:
|
||||||
if next_queued(world, player, current["start"], summary, skipped=current):
|
if 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"]
|
current = player["action"]
|
||||||
continue
|
continue
|
||||||
stop(player, reason)
|
stop(player, reason)
|
||||||
|
|
@ -3322,7 +3324,7 @@ def queue_add(world: dict, player: dict, action_id: str, qty: int, now: float) -
|
||||||
reason = queue_reason(world, player, action)
|
reason = queue_reason(world, player, action)
|
||||||
if reason:
|
if reason:
|
||||||
return reason
|
return reason
|
||||||
if not (player["action"] and "left" in player["action"]):
|
if not (player["action"] and ("left" in player["action"] or "order" in player["action"])):
|
||||||
return start_action(world, player, action_id, now, once=qty)
|
return start_action(world, player, action_id, now, once=qty)
|
||||||
player["queue"].append({"id": action_id, "n": qty})
|
player["queue"].append({"id": action_id, "n": qty})
|
||||||
return None
|
return None
|
||||||
|
|
@ -3985,16 +3987,10 @@ def remove_orders(world: dict, player: dict, order_id=None) -> str | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def claim_order(world: dict, player: dict, order_id, claim: bool = True) -> str | None:
|
def claim_order(world: dict, player: dict, order_id) -> str | None:
|
||||||
order = order_by_id(world, order_id)
|
order = order_by_id(world, order_id)
|
||||||
if not order or order["status"] != "open" or order["kind"] != "craft":
|
if not order or order["status"] != "open" or order["kind"] != "craft":
|
||||||
return "No such order"
|
return "No such order"
|
||||||
if not claim:
|
|
||||||
if order["claimed"] == player["id"]:
|
|
||||||
order["claimed"] = None
|
|
||||||
if (player["action"] or {}).get("order") == order["id"]:
|
|
||||||
stop(player)
|
|
||||||
return None
|
|
||||||
if order["by"] == player["id"]:
|
if order["by"] == player["id"]:
|
||||||
return "That's your own order"
|
return "That's your own order"
|
||||||
if order["claimed"] not in (None, player["id"]):
|
if order["claimed"] not in (None, player["id"]):
|
||||||
|
|
@ -4005,8 +4001,21 @@ def claim_order(world: dict, player: dict, order_id, claim: bool = True) -> str
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def drop_order(world: dict, player: dict, order_id, now: float) -> str | None:
|
||||||
|
"""Let go of an order you'd claimed. If you were crafting it: on with the queue, or back to what you were doing."""
|
||||||
|
order = order_by_id(world, order_id)
|
||||||
|
if not order or order["status"] != "open" or order["kind"] != "craft":
|
||||||
|
return "No such order"
|
||||||
|
if order["claimed"] == player["id"]:
|
||||||
|
order["claimed"] = None
|
||||||
|
if (player["action"] or {}).get("order") == order["id"]:
|
||||||
|
finish_once(world, player, now)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def work_order(world: dict, player: dict, order_id, now: float) -> str | None:
|
def work_order(world: dict, player: dict, order_id, now: float) -> str | None:
|
||||||
"""Claim a crafting order and start making it."""
|
"""Claim a crafting order and start making it. A make that was running goes back to the
|
||||||
|
front of the queue with what it had left; anything else is what comes after."""
|
||||||
order = order_by_id(world, order_id)
|
order = order_by_id(world, order_id)
|
||||||
had = order and order["claimed"] == player["id"]
|
had = order and order["claimed"] == player["id"]
|
||||||
error = claim_order(world, player, order_id)
|
error = claim_order(world, player, order_id)
|
||||||
|
|
@ -4022,6 +4031,12 @@ def work_order(world: dict, player: dict, order_id, now: float) -> str | None:
|
||||||
return reason
|
return reason
|
||||||
if previous and previous.get("party") in world["parties"]:
|
if previous and previous.get("party") in world["parties"]:
|
||||||
leave_party(world, player, previous["party"], now)
|
leave_party(world, player, previous["party"], now)
|
||||||
|
if previous and "order" not in previous:
|
||||||
|
if "left" in previous and queueable(ACTION_BY_ID[previous["id"]]):
|
||||||
|
player["queue"].insert(0, {"id": previous["id"], "n": previous["left"]})
|
||||||
|
elif "left" not in previous:
|
||||||
|
previous = {"resume": previous["id"], "resume_plot2": previous.get("plot2")}
|
||||||
|
player["action"].update({k: v for k, v in (previous or {}).items() if k in ("resume", "resume_plot2") and v})
|
||||||
player["stopped"] = None
|
player["stopped"] = None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -6576,6 +6591,7 @@ ORDER_RECIPES, ORDER_RAW = _order_sources()
|
||||||
# line here (new / balance / fix), and a new release a new entry on top.
|
# line here (new / balance / fix), and a new release a new entry on top.
|
||||||
PATCH_NOTES = [
|
PATCH_NOTES = [
|
||||||
{"date": "2026-10-28", "title": "Queue", "notes": [
|
{"date": "2026-10-28", "title": "Queue", "notes": [
|
||||||
|
("new", "Work orders no longer erase your crafting queue"),
|
||||||
("new", "Items link to where they're made: click to jump to the recipe."),
|
("new", "Items link to where they're made: click to jump to the recipe."),
|
||||||
("new", "Queue: ▲ on #1 swaps it with the current make."),
|
("new", "Queue: ▲ on #1 swaps it with the current make."),
|
||||||
("new", "Updated Guard kit, added recipes for crafting professions to contribute to defence of town without needing combat-related loot."),
|
("new", "Updated Guard kit, added recipes for crafting professions to contribute to defence of town without needing combat-related loot."),
|
||||||
|
|
|
||||||
|
|
@ -2489,7 +2489,7 @@ function orderCard(o) {
|
||||||
&& !S.me.blocked[o.action].startsWith("Out of") ? S.me.blocked[o.action] : "";
|
&& !S.me.blocked[o.action].startsWith("Out of") ? S.me.blocked[o.action] : "";
|
||||||
buttons = `${o.claimed === S.uid ? `<button class="btn" data-order-drop="${o.id}">Drop</button>` : ""}
|
buttons = `${o.claimed === S.uid ? `<button class="btn" data-order-drop="${o.id}">Drop</button>` : ""}
|
||||||
${have ? `<button class="btn" data-order-deliver="${o.id}">Deliver ${fmt(Math.min(have, left))}</button>` : ""}
|
${have ? `<button class="btn" data-order-deliver="${o.id}">Deliver ${fmt(Math.min(have, left))}</button>` : ""}
|
||||||
${working ? `<span class="tag gold">Crafting</span>` : `<button class="btn primary" data-order-work="${o.id}" ${why ? `disabled title="${esc(why)}"` : ""}>Craft it</button>`}`;
|
${working ? `<span class="tag gold">Crafting</span>` : `<button class="btn primary" data-order-work="${o.id}" ${why ? `disabled title="${esc(why)}"` : ""}>Craft</button>`}`;
|
||||||
}
|
}
|
||||||
const reward = o.kind === "gather" ? `${fmt(Math.round(o.reward / o.qty))} each` : fmt(o.reward);
|
const reward = o.kind === "gather" ? `${fmt(Math.round(o.reward / o.qty))} each` : fmt(o.reward);
|
||||||
return `<div class="action order">
|
return `<div class="action order">
|
||||||
|
|
|
||||||
|
|
@ -2610,6 +2610,29 @@ class WorkOrderTest(unittest.TestCase):
|
||||||
self.assertNotIn("oak_plank", self.fred["bank"]) # the crafter brings what wasn't provided
|
self.assertNotIn("oak_plank", self.fred["bank"]) # the crafter brings what wasn't provided
|
||||||
self.assertIsNone(self.fred["action"])
|
self.assertIsNone(self.fred["action"])
|
||||||
|
|
||||||
|
def test_an_order_mid_queue_puts_the_make_back_in_line(self):
|
||||||
|
self.post_hammer()
|
||||||
|
order = self.world["orders"][0]
|
||||||
|
self.fred["bank"] = {"oak_plank": 1, "copper_bar": 8}
|
||||||
|
game.start_action(self.world, self.fred, "mine_stone", T0)
|
||||||
|
game.start_action(self.world, self.fred, "smith_copper_helmet", T0, once=2)
|
||||||
|
game.queue_add(self.world, self.fred, "smith_copper_legs", 1, T0)
|
||||||
|
self.assertIsNone(game.work_order(self.world, self.fred, order["id"], T0))
|
||||||
|
self.assertEqual(self.fred["queue"], [{"id": "smith_copper_helmet", "n": 2}, {"id": "smith_copper_legs", "n": 1}])
|
||||||
|
summary = game.process_player(self.world, self.fred, T0 + 3600, random.Random(1))
|
||||||
|
self.assertEqual(order["status"], "done")
|
||||||
|
self.assertEqual((self.fred["bank"].get("copper_helmet"), self.fred["bank"].get("copper_legs")), (2, 1))
|
||||||
|
self.assertEqual((self.fred["action"]["id"], self.fred["queue"], summary["stopped"]), ("mine_stone", [], None))
|
||||||
|
|
||||||
|
def test_an_order_goes_back_to_what_you_were_doing(self):
|
||||||
|
self.post_hammer()
|
||||||
|
order = self.world["orders"][0]
|
||||||
|
self.fred["bank"] = {"oak_plank": 1}
|
||||||
|
game.start_action(self.world, self.fred, "mine_stone", T0)
|
||||||
|
self.assertIsNone(game.work_order(self.world, self.fred, order["id"], T0))
|
||||||
|
self.assertIsNone(game.drop_order(self.world, self.fred, order["id"], T0))
|
||||||
|
self.assertEqual((self.fred["action"]["id"], order["claimed"]), ("mine_stone", None))
|
||||||
|
|
||||||
def test_cancelling_refunds_what_is_left(self):
|
def test_cancelling_refunds_what_is_left(self):
|
||||||
self.post_hammer()
|
self.post_hammer()
|
||||||
order = self.world["orders"][0]
|
order = self.world["orders"][0]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue