Delete your own board messages; drop chips name their item
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
70246f78ea
commit
2eed9b7ec4
4 changed files with 28 additions and 4 deletions
11
app.py
11
app.py
|
|
@ -330,6 +330,14 @@ class Handler(BaseHTTPRequestHandler):
|
|||
return "There's no raid to stand guard for"
|
||||
player["garrison"] = bool(body.get("join"))
|
||||
return None
|
||||
if path == "/api/board/delete":
|
||||
message = next((m for m in world["board"] if m.get("id") == body.get("id")), None)
|
||||
if not message:
|
||||
return "That message is gone"
|
||||
if message["who"] != player["id"]:
|
||||
return "You can only delete your own messages"
|
||||
world["board"].remove(message)
|
||||
return None
|
||||
if path == "/api/aid":
|
||||
return game.aid_problem(world, player, str(body.get("kind")), str(body.get("item")), str(body.get("source")), now)
|
||||
if path == "/api/hire":
|
||||
|
|
@ -358,7 +366,8 @@ class Handler(BaseHTTPRequestHandler):
|
|||
text = str(body.get("text", "")).strip()[:500]
|
||||
if not text:
|
||||
return "Say something"
|
||||
world["board"].append({"at": now, "who": player["id"], "text": text})
|
||||
world["next_message_id"] = world.get("next_message_id", 1) + 1
|
||||
world["board"].append({"id": world["next_message_id"] - 1, "at": now, "who": player["id"], "text": text})
|
||||
del world["board"][:-game.MAX_LOG]
|
||||
return None
|
||||
return "Not found"
|
||||
|
|
|
|||
9
game.py
9
game.py
|
|
@ -496,7 +496,7 @@ RAID_TRAITS = ["lightly armoured, heavy on archers", "mounted and fast, few bows
|
|||
|
||||
# --- world ---------------------------------------------------------------
|
||||
|
||||
WORLD_VERSION = 8
|
||||
WORLD_VERSION = 9
|
||||
|
||||
|
||||
def new_world(now: float, speed: float = 1.0) -> dict:
|
||||
|
|
@ -528,6 +528,7 @@ def new_world(now: float, speed: float = 1.0) -> dict:
|
|||
"next_event_id": 1,
|
||||
"ledger": [],
|
||||
"board": [],
|
||||
"next_message_id": 1,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -592,6 +593,12 @@ def migrate(world: dict, now: float | None = None) -> dict:
|
|||
world.setdefault("next_hardship_at", now + 24 * HOUR / speed(world))
|
||||
world.setdefault("next_fortune_at", now + 8 * HOUR / speed(world))
|
||||
world["version"] = 8
|
||||
if world["version"] < 9:
|
||||
# Board messages get ids so their authors can delete them.
|
||||
for number, message in enumerate(world["board"], 1):
|
||||
message["id"] = number
|
||||
world["next_message_id"] = len(world["board"]) + 1
|
||||
world["version"] = 9
|
||||
return world
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ function actionCard(a) {
|
|||
if (a.skill === "combat") {
|
||||
const chance = Math.min(0.97, Math.max(0.15, 0.5 + (me.power - a.difficulty) * 0.04));
|
||||
extra = `<div class="small">Win chance <b>${Math.round(chance * 100)}%</b> · about <b>${me.fight_damage[a.id]}</b> damage a fight${a.gold ? ` · ${a.gold} gold` : ""}</div>`;
|
||||
if (a.drops) io += a.drops.map(([id, q, odds]) => `<span class="item-chip" title="${Math.round(odds * 100)}% chance">${item(id).icon} ${q} <span class="have">${Math.round(odds * 100)}%</span></span>`).join("");
|
||||
if (a.drops) io += a.drops.map(([id, q, odds]) => `<span class="item-chip" title="${esc(item(id).name)}: ${Math.round(odds * 100)}% chance">${item(id).icon} ${q} <span class="have">${Math.round(odds * 100)}%</span></span>`).join("");
|
||||
if (a.special === "sabotage") extra += `<div class="small muted">Each win weakens the coming raid by 3%, up to 30%.</div>`;
|
||||
}
|
||||
if (a.special === "recon") extra = `<div class="small muted">+${a.recon} recon on the next event</div>`;
|
||||
|
|
@ -818,7 +818,9 @@ function raidPrep(ev) {
|
|||
// --- board & roster -------------------------------------------------------
|
||||
|
||||
function board() {
|
||||
const msgs = S.board.map((m) => `<div class="msg"><span class="who">${esc(playerName(m.who))}</span><span class="when">${ago(m.at)}</span><div class="text">${esc(m.text)}</div></div>`).join("");
|
||||
const msgs = S.board.map((m) => `<div class="msg"><span class="who">${esc(playerName(m.who))}</span><span class="when">${ago(m.at)}</span>
|
||||
${m.who === S.uid && m.id ? `<button class="msg-delete" data-unpost="${m.id}" title="Delete this message">✕</button>` : ""}
|
||||
<div class="text">${esc(m.text)}</div></div>`).join("");
|
||||
const ledger = [...S.ledger].reverse().map((l) => `<li>${esc(l.text)}<span class="when">${ago(l.at)}</span></li>`).join("");
|
||||
return `<div class="cols">
|
||||
<div class="panel"><h2>Town board</h2>
|
||||
|
|
@ -1000,6 +1002,10 @@ document.addEventListener("click", (e) => {
|
|||
if (d.favour) return act("/api/favour", { kind: d.favour });
|
||||
if (d.food) return act("/api/food", { item: d.food });
|
||||
if (d.potion) return act("/api/potion", { item: d.potion });
|
||||
if (d.unpost) {
|
||||
if (!confirm("Delete this message?")) return;
|
||||
return act("/api/board/delete", { id: Number(d.unpost) });
|
||||
}
|
||||
if (d.aid) return act("/api/aid", { kind: d.aid, item: d.item, source: d.source });
|
||||
if ("hire" in d) return act("/api/hire", {});
|
||||
if (d.devHappen) return act("/api/dev/happen", { track: d.devHappen });
|
||||
|
|
|
|||
|
|
@ -395,3 +395,5 @@ button.sheet-skill:hover { background: var(--panel-2); }
|
|||
.happening .grow { display: flex; flex-direction: column; gap: 4px; }
|
||||
.happening > .btn, .happening > .small { align-self: center; }
|
||||
.skill-happenings { flex-direction: column; align-items: flex-start; gap: 4px; }
|
||||
.msg-delete { background: none; border: 0; color: var(--muted); padding: 0 4px; margin-left: 4px; font-size: 12px; }
|
||||
.msg-delete:hover { color: var(--bad); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue