From 400d8a2657de31e004f7422eddeef0c3b04e8d4c Mon Sep 17 00:00:00 2001 From: rope Date: Mon, 19 Oct 2026 11:23:26 +0100 Subject: [PATCH] Tooltips pass: weather, purse, badges, chips, sheet Co-Authored-By: Claude Opus 5.5 --- game.py | 6 +++--- static/app.js | 36 +++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/game.py b/game.py index 41ec031..6f6e6ce 100644 --- a/game.py +++ b/game.py @@ -1883,10 +1883,10 @@ SEASON_DAYS = 7 # `speed` multiplies action time (below 1 is faster), `yield` multiplies output, # `food` multiplies what the townsfolk eat, `firewood` is logs per person per hour. WEATHER = { - "clear": {"name": "Clear skies", "icon": "๐ŸŒค๏ธ", "text": "Nothing out of the ordinary"}, + "clear": {"name": "Clear skies", "icon": "๐ŸŒค๏ธ", "text": "No effect on work or the city"}, "rain": {"name": "Rain", "icon": "๐ŸŒง๏ธ", "speed": {"farming": 0.9}, "text": "Farming 10% faster"}, "heat": {"name": "Heat wave", "icon": "๐Ÿฅต", "speed": {"farming": 0.85}, "food": 1.15, - "text": "Farming 15% faster, but food spoils faster"}, + "text": "Farming 15% faster, but food spoils: the city eats 15% more"}, "storm": {"name": "Storm", "icon": "โ›ˆ๏ธ", "speed": {"fishing": 1.25}, "text": "Fishing 25% slower"}, "fog": {"name": "Fog", "icon": "๐ŸŒซ๏ธ", "speed": {"reconnaissance": 1.3, "hunting": 1.1}, "text": "Scouting 30% and hunting 10% slower"}, @@ -2609,5 +2609,5 @@ def content() -> dict: "city_uses": {item: city_uses(item) for item in ITEMS}, "prayers": [{**prayer, "text": describe_prayer(prayer)} for prayer in PRAYERS], "max_prayers": MAX_PRAYERS, "potion_charges": POTION_CHARGES, "problems": PROBLEMS, "fittings": list(FITTING_BY_ID.values()), - "equip_slots": EQUIP_SLOTS, "eat_below": EAT_BELOW, "regen_per_hour": REGEN_PER_HOUR, + "equip_slots": EQUIP_SLOTS, "eat_below": EAT_BELOW, "class_speed": CLASS_SPEED, "regen_per_hour": REGEN_PER_HOUR, } diff --git a/static/app.js b/static/app.js index 8774762..59ee241 100644 --- a/static/app.js +++ b/static/app.js @@ -217,8 +217,8 @@ function setMenu(open) { document.documentElement.classList.toggle("menu-open", open); } -function nav(id, icon, label, meta = "", extra = "") { - return ``; +function nav(id, icon, label, meta = "", extra = "", tip = "") { + return ``; } function sidebar() { @@ -230,16 +230,16 @@ function sidebar() {
${esc(me.name)}
${cls.icon} ${cls.name} ยท ${HEART} ${fmt(me.hp)}/${me.max_hp}
-
${COIN} ${fmt(me.gold)}${FAVOUR} ${fmt(me.favour)}
+
${COIN} ${fmt(me.gold)}${FAVOUR} ${fmt(me.favour)}
- ${nav("town", "๐Ÿ˜๏ธ", "Town square", `${S.city.population}`)} - ${nav("council", "๐Ÿ“œ", "Council & threats", "", raid ? `` : "")} + ${nav("town", "๐Ÿ˜๏ธ", "Town square", `${S.city.population}`, "", `Population ${S.city.population}`)} + ${nav("council", "๐Ÿ“œ", "Council & threats", "", raid ? `` : "", raid ? "A threat is coming" : "")} ${nav("board", "๐Ÿ’ฌ", "Town board")} - ${nav("roster", "๐Ÿ‘ฅ", "Guild roster", `${S.players.length}`)} + ${nav("roster", "๐Ÿ‘ฅ", "Guild roster", `${S.players.length}`, "", `${S.players.length} ${S.players.length === 1 ? "adventurer" : "adventurers"}`)} - ${nav("character", cls.icon, "Character", `${skillOf("combat").icon} ${me.levels.combat}`)} - ${nav("bank", "๐Ÿฆ", "Bank", `${me.slots_used}/${me.slots}`)}`; + ${nav("character", cls.icon, "Character", `${skillOf("combat").icon} ${me.levels.combat}`, "", `Combat level ${me.levels.combat}`)} + ${nav("bank", "๐Ÿฆ", "Bank", `${me.slots_used}/${me.slots}`, "", `${me.slots_used} of ${me.slots} bank slots used`)}`; let group = null; for (const skill of C.skills) { if (skill.class && skill.class !== me.cls) continue; @@ -283,7 +283,7 @@ function topbar() { chips += `Idle${S.me.stopped ? ` ยท ${esc(S.me.stopped)}` : ""}`; } const w = S.happenings?.weather; - if (w) chips += ``; + if (w) chips += ``; if (S.upcoming) chips += ``; return `

${esc(title)}

${chips}`; } @@ -317,7 +317,7 @@ function itemChip(id, qty, have) { // Progress towards a building cost: "have / need". function costChip(icon, name, need, have) { - return `${icon} ${fmt(have)} / ${fmt(need)}`; + return `${icon} ${fmt(have)} / ${fmt(need)}`; } // --- skill pages ---------------------------------------------------------- @@ -532,7 +532,7 @@ function bank() { return parts; }); let slots = stacks.map(([id, q]) => ` - `).join(""); for (let i = stacks.length; i < me.slots; i++) slots += `
`; @@ -665,9 +665,15 @@ function siteBanner() { `; } +// "Rain: farming 10% faster. Clear skies in 3h 20m." +function weatherTip(w) { + const next = w.next === w.kind ? `Staying ${w.name.toLowerCase()}` : w.next_name; + return `${w.name}: ${w.text.charAt(0).toLowerCase()}${w.text.slice(1)}. ${next} in ${dur(w.until - serverNow())}.`; +} + function weatherCard() { const h = S.happenings, w = h.weather; - return `
${h.season.icon} ${h.season.name}, day ${h.season.day}
+ return `
${h.season.icon} ${h.season.name}, day ${h.season.day}
${w.icon} ${esc(w.name)}
${w.next === w.kind ? `Staying ${esc(w.name.toLowerCase())}` : `${w.next_icon} ${esc(w.next_name)}`} in ${countdown(w.until)}
`; } @@ -883,7 +889,7 @@ function board() { function roster() { return `
${S.players.map((p) => { const cls = C.classes[p.cls]; - const levels = C.skills.filter((s) => !s.class || s.class === p.cls).map((s) => `
${s.icon}${s.name}${p.levels[s.id]}
`).join(""); + const levels = C.skills.filter((s) => !s.class || s.class === p.cls).map((s) => `
${s.icon}${s.name}${p.levels[s.id]}
`).join(""); return `
${cls.icon}
${esc(p.name)} ${cls.name} ยท total level ${p.total}
${p.doing ? `${skillOf(p.skill).icon} ${esc(p.doing)}` : `Idle`}${p.garrison ? ` ยท On guard` : ""}
@@ -925,8 +931,8 @@ function characterSheet(uid) { const floor = C.xp_table[level], ceil = C.xp_table[level + 1]; const pct = ceil ? (xp - floor) / (ceil - floor) * 100 : 100; const tool = p.equip[`tool_${s.id}`]; - const marks = (cls.fast.includes(s.id) ? `${cls.icon}` : "") - + (tool ? `${item(tool).icon}` : ""); + const marks = (cls.fast.includes(s.id) ? `${cls.icon}` : "") + + (tool ? `${item(tool).icon}` : ""); return `<${mine ? `button data-nav="skill:${s.id}"` : "div"} class="sheet-skill"> ${s.icon} ${s.name}${marks}${level}