Boost bars for the informant and drill sergeant too
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
76778a660a
commit
35491c6f4d
2 changed files with 21 additions and 17 deletions
|
|
@ -617,18 +617,19 @@ function actionCard(a) {
|
|||
if (a.special === "drill") {
|
||||
const s = S.favours.sergeant, boost = s.boost;
|
||||
extra = !s.needed ? `<div class="small muted">Only while a raid is coming.</div>`
|
||||
: `<div class="small makes">${skillOf("combat").icon} +${+me.drill_per_action.toFixed(2)} drill · ${fmt(s.points)} / ${fmt(s.needed)} points, worth ${fmt(s.defence)} of ${fmt(s.cap)} defence${boost ? ` <b class="boosted">×2 drill and XP for the next ${fmt(boost)}</b>` : ""}</div>`;
|
||||
: `<div class="small makes">${skillOf("combat").icon} +${+me.drill_per_action.toFixed(2)} drill · ${fmt(s.points)} / ${fmt(s.needed)} points, worth ${fmt(s.defence)} of ${fmt(s.cap)} defence</div>
|
||||
${boostBar(s.points, s.needed, boost, "Drill sergeant: this stretch drills twice as fast")}`;
|
||||
}
|
||||
if (a.special === "recon") {
|
||||
const boost = S.favours.informant.boost;
|
||||
const ev = S.upcoming, full = ev && ev.recon >= ev.recon_full;
|
||||
extra = full ? `<div class="small muted">Fully scouted: XP only.</div>`
|
||||
: `<div class="small makes">${skillOf("reconnaissance").icon} +${+me.recon_gain[a.id].toFixed(2)} recon${boost ? ` <b class="boosted">×2 recon and XP for the next ${fmt(boost)}</b>` : ""}</div>`;
|
||||
: `<div class="small makes">${skillOf("reconnaissance").icon} +${+me.recon_gain[a.id].toFixed(2)} recon</div>
|
||||
${ev?.recon_full ? boostBar(ev.recon, ev.recon_full, boost, "Informant: this stretch scouts twice as fast") : ""}`;
|
||||
}
|
||||
const temple = S.city.buildings.temple?.level || 0;
|
||||
if (a.special === "labour") {
|
||||
const boost = S.favours.builders.boost;
|
||||
extra = `<div class="small makes">${skillOf("construction").icon} +${me.labour_per_action} labour per action${boost ? ` <b class="boosted">×2 labour and XP for the next ${fmt(boost)}</b>` : ""}</div>`;
|
||||
extra = `<div class="small makes">${skillOf("construction").icon} +${me.labour_per_action} labour per action</div>`;
|
||||
}
|
||||
if (a.special === "bury") extra = `<div class="small makes">${skillOf("prayer").icon} +${a.pp + temple} prayer points</div>`;
|
||||
if (a.special === "offer") extra = `<div class="small makes">${C.buildings.temple.icon} +${+(a.devotion * (1 + 0.25 * temple)).toFixed(1)} devotion</div>`;
|
||||
|
|
@ -782,6 +783,14 @@ function town() {
|
|||
return html;
|
||||
}
|
||||
|
||||
// Progress towards a goal favour can boost. Favour doubles the next `boost` points players put
|
||||
// in, so the striped stretch behind the bar (twice the boost) is where work counts double.
|
||||
function boostBar(done, total, boost, tip) {
|
||||
const pct = (x) => Math.min(100, x / total * 100);
|
||||
return `<div class="bar gold thick boost-bar"${boost ? ` title="${esc(tip)}"` : ""}>${boost
|
||||
? `<span class="boost" style="width:${pct(done + 2 * boost)}%"></span>` : ""}<span style="width:${pct(done)}%"></span></div>`;
|
||||
}
|
||||
|
||||
// The building site: labour so far, who is helping, and ways to speed it up.
|
||||
function siteBanner() {
|
||||
const city = S.city, work = city.construction, me = S.me;
|
||||
|
|
@ -790,9 +799,6 @@ function siteBanner() {
|
|||
const hire = S.favours.builders;
|
||||
const working = me.action?.id === "labour";
|
||||
const builders = S.players.filter((p) => p.skill === "construction" && p.doing === "Work on the building site").map((p) => esc(p.name));
|
||||
// A master builder doubles the next `boost` labour players put in: that stretch of the bar fills twice as fast.
|
||||
const done = Math.min(100, work.labour / work.needed * 100);
|
||||
const boosted = Math.min(100, (work.labour + 2 * hire.boost) / work.needed * 100);
|
||||
return `<div class="banner"><span class="banner-ico">${skillOf("construction").icon}</span><div class="grow">
|
||||
<div class="site-head"><b>${work.repair ? "Repairing" : "Building"} ${esc(spec.name)}</b>
|
||||
<span class="muted small">${fmt(work.labour)} / ${fmt(work.needed)} labour</span>
|
||||
|
|
@ -800,8 +806,7 @@ function siteBanner() {
|
|||
${working ? `<span class="btn sm working">Working</span>` : `<button class="btn sm primary" data-start="labour">Work on it</button>`}
|
||||
${hire.why ? "" : `<button class="btn sm gold" data-favour="builders" ${me.favour < hire.cost ? "disabled" : ""} title="×2 labour and XP for the next ${hire.labour}">Master builder ${FAVOUR} ${fmt(hire.cost)}</button>`}
|
||||
</span></div>
|
||||
<div class="bar gold thick site-bar" style="margin-top:6px"${hire.boost ? ` title="Master builder: this stretch builds twice as fast"` : ""}>
|
||||
${hire.boost ? `<span class="boost" style="width:${boosted}%"></span>` : ""}<span style="width:${done}%"></span></div>
|
||||
${boostBar(work.labour, work.needed, hire.boost, "Master builder: this stretch builds twice as fast")}
|
||||
<div class="small muted" style="margin-top:6px">${builders.length ? `On site: ${builders.join(", ")}. ` : ""}Townsfolk +${fmt(city.townsfolk_labour)}/h.${queued ? ` Next: ${queued}.` : ""}</div>
|
||||
</div></div>`;
|
||||
}
|
||||
|
|
@ -929,9 +934,8 @@ function pips(level) {
|
|||
function reconText(ev) {
|
||||
const points = `${fmt(ev.recon)} / ${fmt(ev.recon_full)} points`;
|
||||
if (ev.intel >= 3) return `${points} · complete`;
|
||||
const boost = S.favours.informant.boost ? ` · <b class="boosted">informant: ×2 for the next ${fmt(S.favours.informant.boost)}</b>` : "";
|
||||
if (ev.recon_next <= 0) return `${points} · next level opens closer to the threat${boost}`;
|
||||
return `${points} · ${fmt(ev.recon_next)} to the next level${boost}`;
|
||||
if (ev.recon_next <= 0) return `${points} · next level opens closer to the threat`;
|
||||
return `${points} · ${fmt(ev.recon_next)} to the next level`;
|
||||
}
|
||||
|
||||
function council() {
|
||||
|
|
@ -950,7 +954,8 @@ function council() {
|
|||
${ev.trait ? `<span class="k">Scouts say</span><span>${esc(ev.trait)}</span>` : ""}
|
||||
${ev.camp ? `<span class="k">Their camp</span><span>Found · sabotage it in Combat${ev.sabotage ? ` (-${ev.sabotage}% so far)` : ""}</span>` : ""}
|
||||
<span class="k">Reconnaissance</span><span>${reconText(ev)}</span>
|
||||
</div>`;
|
||||
</div>
|
||||
${ev.recon_full && ev.intel < 3 ? boostBar(ev.recon, ev.recon_full, S.favours.informant.boost, "Informant: this stretch scouts twice as fast") : ""}`;
|
||||
if (threat) {
|
||||
const strength = ev.strength ?? (ev.range ? `${ev.range[0]}–${ev.range[1]}` : "?");
|
||||
html += `<div class="vs"><div class="side"><span class="muted small">Our defence</span><b>${fmt(city.defence.total)}</b></div><span class="muted">vs</span><div class="side"><span class="muted small">Raiders</span><b>${strength}</b></div></div>`;
|
||||
|
|
|
|||
|
|
@ -142,9 +142,9 @@ main { padding: 24px; max-width: 1200px; width: 100%; }
|
|||
.bar.xp > span { background: var(--xp); }
|
||||
.bar.gold > span { background: var(--gold); }
|
||||
.bar.thick { height: 12px; }
|
||||
.site-bar { position: relative; }
|
||||
.site-bar > span { position: relative; z-index: 1; }
|
||||
.site-bar > span.boost { position: absolute; left: 0; top: 0; z-index: 0;
|
||||
.boost-bar { position: relative; margin-top: 8px; }
|
||||
.boost-bar > span { position: relative; z-index: 1; }
|
||||
.boost-bar > span.boost { position: absolute; left: 0; top: 0; z-index: 0;
|
||||
background: repeating-linear-gradient(-45deg, color-mix(in srgb, var(--gold) 45%, transparent) 0 6px, color-mix(in srgb, var(--gold) 20%, transparent) 6px 12px); }
|
||||
|
||||
.btn {
|
||||
|
|
@ -432,4 +432,3 @@ button.sheet-skill:hover { background: var(--panel-2); }
|
|||
.credit a { color: var(--muted); }
|
||||
.btn.working { color: var(--good); border-color: rgba(92, 191, 106, .5); background: rgba(92, 191, 106, .1); cursor: default; }
|
||||
.banner-ico { font-size: 22px; display: flex; }
|
||||
.boosted { color: var(--gold); font-weight: 600; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue