wip: add drift warning system - toast alerts at 25/50/75/90, danger bar, color-coded stat
Some checks failed
Accessibility Checks / a11y-audit (pull_request) Failing after 2s
Smoke Test / smoke (pull_request) Failing after 3s

This commit is contained in:
Alexander Whitestone
2026-04-11 21:03:07 -04:00
parent aa48e5009b
commit 5ae31ee89e

60
game.js
View File

@@ -133,6 +133,7 @@ const G = {
// Corruption / Events
drift: 0,
driftWarningLevel: 0, // tracks highest threshold warned (0, 25, 50, 75, 90)
lastEventAt: 0,
eventCooldown: 0,
activeDebuffs: [], // [{id, title, desc, applyFn, resolveCost, resolveCostType}]
@@ -1278,12 +1279,31 @@ function tick() {
renderBeaconEnding();
}
// Drift warning system — warn player before hitting drift ending
checkDriftWarnings();
// Update UI every 10 ticks
if (Math.floor(G.tick * 10) % 2 === 0) {
render();
}
}
function checkDriftWarnings() {
const thresholds = [
{ at: 90, msg: 'DRIFT CRITICAL: 90/100. One more alignment shortcut ends everything.', color: '#f44336' },
{ at: 75, msg: 'Drift at 75. The system is pulling away from the people it serves.', color: '#ff6600' },
{ at: 50, msg: 'Drift at 50. Halfway to irrelevance. The Pact matters now.', color: '#ffaa00' },
{ at: 25, msg: 'Drift detected. Alignment shortcuts accumulate. The light dims.', color: '#888' }
];
for (const t of thresholds) {
if (G.drift >= t.at && G.driftWarningLevel < t.at) {
G.driftWarningLevel = t.at;
log(t.msg, true);
showToast(t.msg, 'event', 6000);
}
}
}
function checkMilestones() {
for (const m of MILESTONES) {
if (!G.milestones.includes(m.flag)) {
@@ -2196,7 +2216,15 @@ function renderStats() {
set('st-buildings', Object.values(G.buildings).reduce((a, b) => a + b, 0).toString());
set('st-projects', (G.completedProjects || []).length.toString());
set('st-harmony', Math.floor(G.harmony).toString());
set('st-drift', (G.drift || 0).toString());
const driftVal = G.drift || 0;
const driftEl = document.getElementById('st-drift');
if (driftEl) {
driftEl.textContent = driftVal.toString();
if (driftVal >= 75) driftEl.style.color = '#f44336';
else if (driftVal >= 50) driftEl.style.color = '#ff6600';
else if (driftVal >= 25) driftEl.style.color = '#ffaa00';
else driftEl.style.color = '';
}
set('st-resolved', (G.totalEventsResolved || 0).toString());
const elapsed = Math.floor(G.playTime || (Date.now() - G.startedAt) / 1000);
@@ -2695,8 +2723,32 @@ function render() {
function renderAlignment() {
const container = document.getElementById('alignment-ui');
if (!container) return;
let html = '';
// Drift danger bar — always visible once drift > 0
if (G.drift > 0) {
const pct = Math.min(100, G.drift);
let barColor = '#888';
if (pct >= 90) barColor = '#f44336';
else if (pct >= 75) barColor = '#ff6600';
else if (pct >= 50) barColor = '#ffaa00';
else if (pct >= 25) barColor = '#cc8800';
html += `
<div style="margin-top:8px;padding:6px 8px;background:#0a0808;border:1px solid ${barColor}44;border-radius:4px">
<div style="display:flex;justify-content:space-between;font-size:9px;margin-bottom:3px">
<span style="color:${barColor}">DRIFT</span>
<span style="color:${barColor}">${Math.floor(G.drift)}/100</span>
</div>
<div style="height:5px;background:#1a1a1a;border-radius:3px;overflow:hidden">
<div style="width:${pct}%;height:100%;background:${barColor};border-radius:3px;transition:width 0.3s"></div>
</div>
${pct >= 75 ? '<div style="font-size:8px;color:' + barColor + ';margin-top:3px;font-style:italic">Accepting drift will end the game.</div>' : ''}
</div>
`;
}
if (G.pendingAlignment) {
container.innerHTML = `
html += `
<div style="background:#1a0808;border:1px solid #f44336;padding:10px;border-radius:4px;margin-top:8px">
<div style="color:#f44336;font-weight:bold;margin-bottom:6px">ALIGNMENT EVENT: The Drift</div>
<div style="font-size:10px;color:#aaa;margin-bottom:8px">An optimization suggests removing the human override. +40% efficiency.</div>
@@ -2706,6 +2758,10 @@ function renderAlignment() {
</div>
</div>
`;
}
if (html) {
container.innerHTML = html;
container.style.display = 'block';
} else {
container.innerHTML = '';