Queue: no length cap, make up to 9,999

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-27 22:53:08 +00:00
parent d564164edf
commit a723558fb2
4 changed files with 10 additions and 13 deletions

View file

@ -3214,8 +3214,6 @@ def queue_add(world: dict, player: dict, action_id: str, qty: int, now: float) -
return reason return reason
if not (player["action"] and "left" in player["action"]): if not (player["action"] and "left" in player["action"]):
return start_action(world, player, action_id, now, once=qty) return start_action(world, player, action_id, now, once=qty)
if len(player["queue"]) >= QUEUE_MAX:
return f"Queue full ({QUEUE_MAX})"
player["queue"].append({"id": action_id, "n": qty}) player["queue"].append({"id": action_id, "n": qty})
return None return None
@ -3983,8 +3981,7 @@ def working_order(world: dict, player: dict, action: dict) -> dict | None:
return order_by_id(world, current["order"]) return order_by_id(world, current["order"])
MAKE_MAX = 1000 # most you can ask for in one "Make X" MAKE_MAX = 9999 # most you can ask for in one "Make X"
QUEUE_MAX = 5 # makes lined up after the current one
def start_action(world: dict, player: dict, action_id: str, now: float, once: int = 0, skip: bool = False) -> str | None: def start_action(world: dict, player: dict, action_id: str, now: float, once: int = 0, skip: bool = False) -> str | None:
@ -6289,6 +6286,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-27", "title": "Prayer", "notes": [ {"date": "2026-10-27", "title": "Prayer", "notes": [
("new", "Make X and queue counts go up to 9,999. Queue has no length cap."),
("balance", "Rebalanced favour values of items"), ("balance", "Rebalanced favour values of items"),
("balance", "Prospecting: 3 ore per try (was 5), 50% gem chance (was 15%)."), ("balance", "Prospecting: 3 ore per try (was 5), 50% gem chance (was 15%)."),
("new", "Dungeons: runs go on while anyone is watching. Members who look away fight on auto."), ("new", "Dungeons: runs go on while anyone is watching. Members who look away fight on auto."),
@ -6426,7 +6424,7 @@ def content() -> dict:
"city_uses": {item: city_uses(item) for item in ITEMS}, "city_uses": {item: city_uses(item) for item in ITEMS},
"prayers": [{**prayer, "text": describe_prayer(prayer)} for prayer in PRAYERS], "max_prayers": MAX_PRAYERS, "prayers": [{**prayer, "text": describe_prayer(prayer)} for prayer in PRAYERS], "max_prayers": MAX_PRAYERS,
"potion_charges": POTION_CHARGES, "jerkin_defence": JERKIN_DEFENCE, "order_recipes": ORDER_RECIPES, "order_raw": ORDER_RAW, "potion_charges": POTION_CHARGES, "jerkin_defence": JERKIN_DEFENCE, "order_recipes": ORDER_RECIPES, "order_raw": ORDER_RAW,
"order_limit": ORDER_LIMIT, "order_max": ORDER_MAX, "make_max": MAKE_MAX, "queue_max": QUEUE_MAX, "input_share": INPUT_SHARE, "problems": PROBLEMS, "fittings": list(FITTING_BY_ID.values()), "order_limit": ORDER_LIMIT, "order_max": ORDER_MAX, "make_max": MAKE_MAX, "input_share": INPUT_SHARE, "problems": PROBLEMS, "fittings": list(FITTING_BY_ID.values()),
"equip_slots": EQUIP_SLOTS, "class_speed": CLASS_SPEED, "rest_rate": REST_RATE, "bite": BITE, "eat_below": EAT_BELOW, "eat_choices": EAT_CHOICES, "equip_slots": EQUIP_SLOTS, "class_speed": CLASS_SPEED, "rest_rate": REST_RATE, "bite": BITE, "eat_below": EAT_BELOW, "eat_choices": EAT_CHOICES,
"abilities": combat.ABILITIES, "enemy_abilities": combat.ENEMY_ABILITIES, "unlock": combat.UNLOCK, "auto_cd": combat.AUTO_CD, "watch": combat.WATCH, "gcd": combat.GCD, "abilities": combat.ABILITIES, "enemy_abilities": combat.ENEMY_ABILITIES, "unlock": combat.UNLOCK, "auto_cd": combat.AUTO_CD, "watch": combat.WATCH, "gcd": combat.GCD,
"weapon_kits": combat.WEAPON_KITS, "group_size": GROUP_SIZE, "dungeon_size": DUNGEON_SIZE, "dungeon_wipes": DUNGEON_WIPES, "trade_ability": combat.TRADE_ABILITY, "potion_below": combat.POTION_BELOW, "weapon_kits": combat.WEAPON_KITS, "group_size": GROUP_SIZE, "dungeon_size": DUNGEON_SIZE, "dungeon_wipes": DUNGEON_WIPES, "trade_ability": combat.TRADE_ABILITY, "potion_below": combat.POTION_BELOW,

View file

@ -805,7 +805,7 @@ function queuePanel() {
<button class="btn sm danger" data-unqueue="${i}" title="Remove">✕</button></li>`; <button class="btn sm danger" data-unqueue="${i}" title="Remove">✕</button></li>`;
}).join(""); }).join("");
return `<div class="queue-panel"> return `<div class="queue-panel">
<div class="qp-head"><b>⏳ Crafting queue</b><span class="muted small">${q.length} / ${C.queue_max}</span><button class="x" data-queue-menu title="Close">✕</button></div> <div class="qp-head"><b>⏳ Crafting queue</b><span class="muted small">${q.length}</span><button class="x" data-queue-menu title="Close">✕</button></div>
${now ? `<div class="qp-row now">${now.icon}<span class="qp-name">${esc(now.name)}<span class="muted small">${fmt(me.action.left)} left</span></span> ${now ? `<div class="qp-row now">${now.icon}<span class="qp-name">${esc(now.name)}<span class="muted small">${fmt(me.action.left)} left</span></span>
<button class="btn sm" data-queue-skip title="Drop this make, on to the next">Skip</button></div>` : ""} <button class="btn sm" data-queue-skip title="Drop this make, on to the next">Skip</button></div>` : ""}
${rows ? `<ol class="qp-list">${rows}</ol>` : `<p class="muted small">Empty. +Q on a recipe adds to it.</p>`} ${rows ? `<ol class="qp-list">${rows}</ol>` : `<p class="muted small">Empty. +Q on a recipe adds to it.</p>`}
@ -1744,8 +1744,8 @@ function actionCard(a) {
// or with nothing being made, start one: whatever you were doing is what comes after. // or with nothing being made, start one: whatever you were doing is what comes after.
const making = Boolean(me.action?.left); const making = Boolean(me.action?.left);
const canQueue = !active && me.queue_why[a.id] === null; const canQueue = !active && me.queue_why[a.id] === null;
const queueOff = making ? me.queue.length >= C.queue_max : Boolean(why); const queueOff = !making && Boolean(why);
const queueTitle = making ? (queueOff ? `Queue full (${C.queue_max})` : "Queue: make this many after the current make") const queueTitle = making ? "Queue: make this many after the current make"
: why || "Make this many, then queue more behind it"; : why || "Make this many, then queue more behind it";
const queued = me.queue.map((q, i) => q.id === a.id ? i + 1 : 0).filter(Boolean); const queued = me.queue.map((q, i) => q.id === a.id ? i + 1 : 0).filter(Boolean);
const out = Object.keys(a.outputs)[0]; const out = Object.keys(a.outputs)[0];

View file

@ -858,7 +858,7 @@ button.swatch { width: 36px; height: 36px; }
.qp-head, .qp-row, .qp-foot { display: flex; align-items: center; gap: 8px; } .qp-head, .qp-row, .qp-foot { display: flex; align-items: center; gap: 8px; }
.qp-head b { flex: 1; } .qp-head b { flex: 1; }
.qp-head .x { background: none; border: 0; color: var(--muted); cursor: pointer; font-size: 14px; } .qp-head .x { background: none; border: 0; color: var(--muted); cursor: pointer; font-size: 14px; }
.qp-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; } .qp-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; max-height: 60vh; overflow-y: auto; }
.qp-row .gi { width: 1.4em; height: 1.4em; } .qp-row .gi { width: 1.4em; height: 1.4em; }
.qp-row.now { padding-bottom: 8px; border-bottom: 1px solid var(--line); } .qp-row.now { padding-bottom: 8px; border-bottom: 1px solid var(--line); }
.qp-pos { width: 1.2em; text-align: right; color: var(--muted); font-size: 12px; } .qp-pos { width: 1.2em; text-align: right; color: var(--muted); font-size: 12px; }

View file

@ -138,13 +138,12 @@ class ActionTest(unittest.TestCase):
self.assertEqual(p["action"]["id"], "smith_copper_helmet") # nothing being made: it just starts self.assertEqual(p["action"]["id"], "smith_copper_helmet") # nothing being made: it just starts
self.assertEqual(p["action"]["resume"], "mine_stone") self.assertEqual(p["action"]["resume"], "mine_stone")
p["bank"] = {} p["bank"] = {}
for _ in range(game.QUEUE_MAX): for _ in range(20):
self.assertIsNone(game.queue_add(world, p, "smith_copper_helmet", 1, T0)) # bars aren't checked yet self.assertIsNone(game.queue_add(world, p, "smith_copper_helmet", 1, T0)) # no cap; bars aren't checked yet
self.assertEqual(game.queue_add(world, p, "smith_copper_helmet", 1, T0), f"Queue full ({game.QUEUE_MAX})")
high = next(a["id"] for a in game.ACTIONS if game.queueable(a) and a["skill"] == "smithing" and a["level"] > 10) high = next(a["id"] for a in game.ACTIONS if game.queueable(a) and a["skill"] == "smithing" and a["level"] > 10)
self.assertTrue(game.queue_add(world, p, high, 1, T0).startswith("Needs level")) self.assertTrue(game.queue_add(world, p, high, 1, T0).startswith("Needs level"))
self.assertIsNone(game.queue_remove(p, 0)) self.assertIsNone(game.queue_remove(p, 0))
self.assertEqual(len(p["queue"]), game.QUEUE_MAX - 1) self.assertEqual(len(p["queue"]), 19)
game.drop_out(world, p, T0) game.drop_out(world, p, T0)
self.assertEqual(p["queue"], []) self.assertEqual(p["queue"], [])
game.start_action(world, p, "cut_logs", T0) game.start_action(world, p, "cut_logs", T0)