Work orders: fill a reagent slot after posting; no auto-reload while writing an order
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
326437ddf9
commit
1488692463
4 changed files with 39 additions and 3 deletions
2
app.py
2
app.py
|
|
@ -326,6 +326,8 @@ class Handler(BaseHTTPRequestHandler):
|
|||
if path == "/api/order":
|
||||
return game.post_order(world, player, body.get("kind"), str(item), qty, body.get("provide"),
|
||||
body.get("reward"), now)
|
||||
if path == "/api/order/provide":
|
||||
return game.provide_reagent(world, player, body.get("id"), str(item))
|
||||
if path == "/api/order/cancel":
|
||||
return game.cancel_order(world, player, body.get("id"), now)
|
||||
if path == "/api/order/work":
|
||||
|
|
|
|||
16
game.py
16
game.py
|
|
@ -2125,6 +2125,22 @@ def post_order(world: dict, player: dict, kind: str, item: str, qty, provide, re
|
|||
return None
|
||||
|
||||
|
||||
def provide_reagent(world: dict, player: dict, order_id, item: str) -> str | None:
|
||||
"""Put a reagent into your own order after posting it, enough for what's still to be made."""
|
||||
order = order_by_id(world, order_id)
|
||||
if not order or order["by"] != player["id"] or order["status"] != "open" or order["kind"] != "craft":
|
||||
return "No such order"
|
||||
action = ACTION_BY_ID[order["action"]]
|
||||
if item not in action["inputs"] or item in order["provided"]:
|
||||
return "Already provided" if item in order["provided"] else "That isn't in the recipe"
|
||||
need = action["inputs"][item] * _batches(action, order["item"], order["qty"] - order["delivered"])
|
||||
if player["bank"].get(item, 0) < need:
|
||||
return f"{ITEMS[item]['name']}: {player['bank'].get(item, 0)} / {need}"
|
||||
bank_take(player, item, need)
|
||||
order["provided"][item] = need
|
||||
return None
|
||||
|
||||
|
||||
def _refund(world: dict, order: dict, now: float) -> None:
|
||||
owner = world["players"].get(order["by"])
|
||||
if not owner:
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ async function refresh() {
|
|||
|
||||
function accept(state) {
|
||||
version ??= state.version;
|
||||
if (state.version !== version && !document.querySelector("[data-keep]:focus") && $("#modal").hidden) {
|
||||
if (state.version !== version && !document.querySelector("[data-keep]:focus") && $("#modal").hidden && !draft) {
|
||||
location.reload(); // a new build was deployed
|
||||
return;
|
||||
}
|
||||
|
|
@ -1197,8 +1197,12 @@ function orderSlots(o) {
|
|||
<span class="swap-qty">${fmt(per * all)}</span><span class="tick">✓</span></span></div>`;
|
||||
}
|
||||
const need = per * (o.status === "open" ? left : all), have = S.me.bank[id] || 0;
|
||||
return `<div class="ro-slot open" title="${esc(`${name}: crafter brings`)}"><span class="doll-slot empty-req">${item(id).icon}</span>
|
||||
<span class="ro-have ${o.by === S.uid ? "muted" : have < need ? "bad" : "good"}">${o.by === S.uid ? `×${fmt(need)}` : `${fmt(have)} / ${fmt(need)}`}</span></div>`;
|
||||
// On your own open order, an empty slot can still be filled from your bank.
|
||||
const fill = o.by === S.uid && o.status === "open";
|
||||
return `<div class="ro-slot open">${fill
|
||||
? `<button class="doll-slot empty-req" data-order-fill="${o.id}" data-item="${id}" ${have < need ? "disabled" : ""} title="${esc(`${name}: ${fmt(have)} / ${fmt(need)}`)}">${item(id).icon}</button>`
|
||||
: `<span class="doll-slot empty-req" title="${esc(`${name}: crafter brings`)}">${item(id).icon}</span>`}
|
||||
<span class="ro-have ${o.status !== "open" ? "muted" : have < need ? "bad" : "good"}">${o.status !== "open" ? `×${fmt(need)}` : `${fmt(have)} / ${fmt(need)}`}</span></div>`;
|
||||
}).join("");
|
||||
}
|
||||
|
||||
|
|
@ -1614,6 +1618,7 @@ document.addEventListener("click", (e) => {
|
|||
if (d.orderDrop) return act("/api/order/drop", { id: Number(d.orderDrop) });
|
||||
if (d.orderDeliver) return act("/api/order/deliver", { id: Number(d.orderDeliver) });
|
||||
if (d.orderCancel) return act("/api/order/cancel", { id: Number(d.orderCancel) });
|
||||
if (d.orderFill) return act("/api/order/provide", { id: Number(d.orderFill), item: d.item });
|
||||
if (d.doll) {
|
||||
dollPick = dollPick === d.doll ? null : d.doll;
|
||||
return render();
|
||||
|
|
|
|||
|
|
@ -1580,3 +1580,16 @@ class WorkOrderTest(unittest.TestCase):
|
|||
game.expire_orders(self.world, T0 + 4 * game.DAY)
|
||||
self.assertEqual(self.mike["gold"], 200)
|
||||
self.assertEqual(self.mike["bank"]["iron_bar"], 3)
|
||||
|
||||
def test_requester_can_fill_a_slot_after_posting(self):
|
||||
self.mike["gold"] = 200
|
||||
self.mike["bank"] = {"iron_bar": 3, "clay_core": 3}
|
||||
game.post_order(self.world, self.mike, "craft", "iron_warhammer", 1, [], 140, T0)
|
||||
order = self.world["orders"][0]
|
||||
self.assertIsNone(game.provide_reagent(self.world, self.mike, order["id"], "iron_bar"))
|
||||
self.assertEqual(order["provided"], {"iron_bar": 3})
|
||||
self.fred["bank"] = {"oak_plank": 1, "clay_core": 3}
|
||||
self.assertIsNone(game.work_order(self.world, self.fred, order["id"], T0))
|
||||
game.process_player(self.world, self.fred, T0 + 600, random.Random(1))
|
||||
self.assertEqual(self.mike["bank"].get("iron_warhammer"), 1)
|
||||
self.assertEqual(self.fred["bank"], {}) # used his own plank and cores, never needed bars
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue