Crafting cards: one-row buttons, list all missing reagents
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a205d429bd
commit
377f534f6b
3 changed files with 20 additions and 9 deletions
10
game.py
10
game.py
|
|
@ -3053,10 +3053,10 @@ def can_start(world: dict, player: dict, action: dict) -> str | None:
|
|||
if order is not None or "order" in (player["action"] or {}) and player["action"]["id"] == action["id"]:
|
||||
if not order or order["status"] != "open" or order["claimed"] != player["id"] and not order.get("city"):
|
||||
return "Work order done" if order and order["status"] == "done" else "Work order closed"
|
||||
for item, qty in fire_inputs(world, action).items():
|
||||
pooled = order["provided"].get(item, 0) if order else 0
|
||||
if pooled + player["bank"].get(item, 0) < qty:
|
||||
return f"Out of {ITEMS[item]['name'].lower()}"
|
||||
short = [ITEMS[item]["name"].lower() for item, qty in fire_inputs(world, action).items()
|
||||
if (order["provided"].get(item, 0) if order else 0) + player["bank"].get(item, 0) < qty]
|
||||
if short:
|
||||
return f"Out of: {', '.join(short)}"
|
||||
if action.get("special") == "tend" and not tend_target(world, player, action):
|
||||
return f"Your pile in the {FIRES[action['tend']]['name'].lower()} is full" if action["tend"] else "Your piles are all full"
|
||||
if action.get("special") == "sabotage":
|
||||
|
|
@ -6753,6 +6753,8 @@ 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": [
|
||||
("fix", "Crafting cards: buttons stay on one row on phones and narrow cards."),
|
||||
("new", "\"Out of:\" lists every missing reagent."),
|
||||
("new", "Updated guild roster layout"),
|
||||
("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."),
|
||||
|
|
|
|||
|
|
@ -225,7 +225,16 @@ span[data-goto]:not(.item-chip):hover, b[data-goto]:hover { text-decoration: und
|
|||
.bar.hp > span { background: var(--bad); }
|
||||
.warn { color: var(--warn); }
|
||||
select { background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 5px 8px; margin-left: 6px; }
|
||||
.action .foot { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-top: auto; }
|
||||
.action .foot { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px; margin-top: auto; }
|
||||
/* The reason gets its own line when it and the buttons don't fit side by side; the buttons stay one row. */
|
||||
.action .foot .why:empty { display: none; }
|
||||
.action .foot > .btns { flex-wrap: nowrap; }
|
||||
.action .foot > :last-child { margin-left: auto; }
|
||||
.action { container-type: inline-size; }
|
||||
@container (max-width: 270px) {
|
||||
.action .foot .btn { padding-inline: 9px; }
|
||||
.action .foot .make input { width: 48px; padding-inline: 6px; }
|
||||
}
|
||||
|
||||
/* --- bank ------------------------------------------------------------- */
|
||||
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ class ActionTest(unittest.TestCase):
|
|||
self.assertEqual(p["bank"]["copper_bar"], 3)
|
||||
self.assertNotIn("copper_ore", p["bank"])
|
||||
self.assertIsNone(p["action"])
|
||||
self.assertEqual(summary["stopped"], "Out of copper ore")
|
||||
self.assertEqual(summary["stopped"], "Out of: copper ore")
|
||||
|
||||
def test_crafting_stops_as_the_last_one_finishes(self):
|
||||
world = world_with(("ann", "commoner"))
|
||||
|
|
@ -254,7 +254,7 @@ class ActionTest(unittest.TestCase):
|
|||
duration = game.action_time(world, p, game.ACTION_BY_ID["smith_copper_bar"])
|
||||
summary = game.process_player(world, p, T0 + duration + 0.1, random.Random(1))
|
||||
self.assertIsNone(p["action"])
|
||||
self.assertEqual(summary["stopped"], "Out of copper ore")
|
||||
self.assertEqual(summary["stopped"], "Out of: copper ore")
|
||||
|
||||
def test_level_and_city_requirements(self):
|
||||
world = world_with(("ann", "commoner"))
|
||||
|
|
@ -2709,7 +2709,7 @@ class WorkOrderTest(unittest.TestCase):
|
|||
self.dave["bank"] = {"iron_bar": 1}
|
||||
game.provide_reagent(self.world, self.dave, order["id"], "iron_bar")
|
||||
self.fred["bank"] = {"iron_bar": 1, "oak_plank": 1, "clay_core": 3}
|
||||
self.assertEqual(game.work_order(self.world, self.fred, order["id"], T0), "Out of iron bar")
|
||||
self.assertEqual(game.work_order(self.world, self.fred, order["id"], T0), "Out of: iron bar")
|
||||
self.fred["bank"]["iron_bar"] = 2
|
||||
self.assertIsNone(game.work_order(self.world, self.fred, order["id"], T0))
|
||||
game.process_player(self.world, self.fred, T0 + 600, random.Random(1))
|
||||
|
|
@ -2850,7 +2850,7 @@ class JewelcraftingTest(unittest.TestCase):
|
|||
game.start_action(self.world, self.ann, "prospect_garnet", T0)
|
||||
summary = game.process_player(self.world, self.ann, T0 + 1000, Always())
|
||||
self.assertEqual(self.ann["bank"], {"iron_ore": 2, "garnet": 1})
|
||||
self.assertEqual(summary["stopped"], "Out of iron ore")
|
||||
self.assertEqual(summary["stopped"], "Out of: iron ore")
|
||||
self.assertGreater(self.ann["xp"]["jewelcrafting"], game.XP_TABLE[15])
|
||||
|
||||
def test_jewellery_bonuses(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue