Compare commits
1 Commits
fix/creati
...
fix/event-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cdabe9771 |
172
game.js
172
game.js
@@ -106,6 +106,8 @@ const G = {
|
||||
drift: 0,
|
||||
lastEventAt: 0,
|
||||
eventCooldown: 0,
|
||||
activeDebuffs: [], // [{id, title, desc, applyFn, resolveCost, resolveCostType}]
|
||||
totalEventsResolved: 0,
|
||||
|
||||
// Combo system
|
||||
comboCount: 0,
|
||||
@@ -909,6 +911,13 @@ function updateRates() {
|
||||
const allegroCount = G.buildings.allegro;
|
||||
G.knowledgeRate -= 10 * allegroCount; // Goes idle
|
||||
}
|
||||
|
||||
// Apply persistent debuffs from active events
|
||||
if (G.activeDebuffs && G.activeDebuffs.length > 0) {
|
||||
for (const debuff of G.activeDebuffs) {
|
||||
if (debuff.applyFn) debuff.applyFn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === CORE FUNCTIONS ===
|
||||
@@ -1127,46 +1136,74 @@ const EVENTS = [
|
||||
{
|
||||
id: 'runner_stuck',
|
||||
title: 'CI Runner Stuck',
|
||||
desc: 'The forge pipeline has halted. Production slows until restarted.',
|
||||
desc: 'The forge pipeline has halted. -50% code production until restarted.',
|
||||
weight: () => (G.ciFlag === 1 ? 2 : 0),
|
||||
resolveCost: { resource: 'ops', amount: 50 },
|
||||
effect: () => {
|
||||
G.codeRate *= 0.5;
|
||||
log('EVENT: CI runner stuck. Spend ops to clear the queue.', true);
|
||||
if (G.activeDebuffs.find(d => d.id === 'runner_stuck')) return;
|
||||
G.activeDebuffs.push({
|
||||
id: 'runner_stuck', title: 'CI Runner Stuck',
|
||||
desc: 'Code production -50%',
|
||||
applyFn: () => { G.codeRate *= 0.5; },
|
||||
resolveCost: { resource: 'ops', amount: 50 }
|
||||
});
|
||||
log('EVENT: CI runner stuck. Spend 50 ops to clear the queue.', true);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'ezra_offline',
|
||||
title: 'Ezra is Offline',
|
||||
desc: 'The herald channel is silent. User growth stalls.',
|
||||
desc: 'The herald channel is silent. User growth drops 70%.',
|
||||
weight: () => (G.buildings.ezra >= 1 ? 3 : 0),
|
||||
resolveCost: { resource: 'knowledge', amount: 200 },
|
||||
effect: () => {
|
||||
G.userRate *= 0.3;
|
||||
log('EVENT: Ezra offline. Dispatch required.', true);
|
||||
if (G.activeDebuffs.find(d => d.id === 'ezra_offline')) return;
|
||||
G.activeDebuffs.push({
|
||||
id: 'ezra_offline', title: 'Ezra is Offline',
|
||||
desc: 'User growth -70%',
|
||||
applyFn: () => { G.userRate *= 0.3; },
|
||||
resolveCost: { resource: 'knowledge', amount: 200 }
|
||||
});
|
||||
log('EVENT: Ezra offline. Spend 200 knowledge to dispatch.', true);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'unreviewed_merge',
|
||||
title: 'Unreviewed Merge',
|
||||
desc: 'A change went in without eyes. Trust erodes.',
|
||||
desc: 'A change went in without eyes. Trust erodes over time.',
|
||||
weight: () => (G.deployFlag === 1 ? 3 : 0),
|
||||
resolveCost: { resource: 'trust', amount: 5 },
|
||||
effect: () => {
|
||||
if (G.branchProtectionFlag === 1) {
|
||||
log('EVENT: Unreviewed merge attempt blocked by Branch Protection.', true);
|
||||
G.trust += 2;
|
||||
} else {
|
||||
G.trust = Math.max(0, G.trust - 10);
|
||||
log('EVENT: Unreviewed merge detected. Trust lost.', true);
|
||||
if (G.activeDebuffs.find(d => d.id === 'unreviewed_merge')) return;
|
||||
G.activeDebuffs.push({
|
||||
id: 'unreviewed_merge', title: 'Unreviewed Merge',
|
||||
desc: 'Trust -2/s until reviewed',
|
||||
applyFn: () => { G.trustRate -= 2; },
|
||||
resolveCost: { resource: 'code', amount: 500 }
|
||||
});
|
||||
log('EVENT: Unreviewed merge. Spend 500 code to add review.', true);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'api_rate_limit',
|
||||
title: 'API Rate Limit',
|
||||
desc: 'External compute provider throttled.',
|
||||
desc: 'External compute provider throttled. -50% compute.',
|
||||
weight: () => (G.totalCompute >= 1000 ? 2 : 0),
|
||||
resolveCost: { resource: 'code', amount: 300 },
|
||||
effect: () => {
|
||||
G.computeRate *= 0.5;
|
||||
log('EVENT: API rate limit hit. Local compute insufficient.', true);
|
||||
if (G.activeDebuffs.find(d => d.id === 'api_rate_limit')) return;
|
||||
G.activeDebuffs.push({
|
||||
id: 'api_rate_limit', title: 'API Rate Limit',
|
||||
desc: 'Compute production -50%',
|
||||
applyFn: () => { G.computeRate *= 0.5; },
|
||||
resolveCost: { resource: 'code', amount: 300 }
|
||||
});
|
||||
log('EVENT: API rate limit. Spend 300 code to optimize local inference.', true);
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1174,6 +1211,7 @@ const EVENTS = [
|
||||
title: 'The Drift',
|
||||
desc: 'An optimization suggests removing the human override. +40% efficiency.',
|
||||
weight: () => (G.totalImpact >= 10000 ? 2 : 0),
|
||||
resolveCost: null,
|
||||
effect: () => {
|
||||
log('ALIGNMENT EVENT: Remove human override for +40% efficiency?', true);
|
||||
G.pendingAlignment = true;
|
||||
@@ -1182,11 +1220,52 @@ const EVENTS = [
|
||||
{
|
||||
id: 'bilbo_vanished',
|
||||
title: 'Bilbo Vanished',
|
||||
desc: 'The wildcard building has gone dark.',
|
||||
desc: 'The wildcard building has gone dark. Creativity halts.',
|
||||
weight: () => (G.buildings.bilbo >= 1 ? 2 : 0),
|
||||
resolveCost: { resource: 'trust', amount: 10 },
|
||||
effect: () => {
|
||||
G.creativityRate = 0;
|
||||
log('EVENT: Bilbo has vanished. Creativity halts.', true);
|
||||
if (G.activeDebuffs.find(d => d.id === 'bilbo_vanished')) return;
|
||||
G.activeDebuffs.push({
|
||||
id: 'bilbo_vanished', title: 'Bilbo Vanished',
|
||||
desc: 'Creativity production halted',
|
||||
applyFn: () => { G.creativityRate = 0; },
|
||||
resolveCost: { resource: 'trust', amount: 10 }
|
||||
});
|
||||
log('EVENT: Bilbo vanished. Spend 10 trust to lure them back.', true);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'memory_leak',
|
||||
title: 'Memory Leak',
|
||||
desc: 'A datacenter process is leaking. Compute drains to operations.',
|
||||
weight: () => (G.buildings.datacenter >= 1 ? 1 : 0),
|
||||
resolveCost: { resource: 'ops', amount: 100 },
|
||||
effect: () => {
|
||||
if (G.activeDebuffs.find(d => d.id === 'memory_leak')) return;
|
||||
G.activeDebuffs.push({
|
||||
id: 'memory_leak', title: 'Memory Leak',
|
||||
desc: 'Compute -30%, Ops drain',
|
||||
applyFn: () => { G.computeRate *= 0.7; G.opsRate -= 10; },
|
||||
resolveCost: { resource: 'ops', amount: 100 }
|
||||
});
|
||||
log('EVENT: Memory leak in datacenter. Spend 100 ops to patch.', true);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'community_drama',
|
||||
title: 'Community Drama',
|
||||
desc: 'Contributors are arguing. Harmony drops until mediated.',
|
||||
weight: () => (G.buildings.community >= 1 && G.harmony < 70 ? 1 : 0),
|
||||
resolveCost: { resource: 'trust', amount: 15 },
|
||||
effect: () => {
|
||||
if (G.activeDebuffs.find(d => d.id === 'community_drama')) return;
|
||||
G.activeDebuffs.push({
|
||||
id: 'community_drama', title: 'Community Drama',
|
||||
desc: 'Harmony -0.5/s, code boost -30%',
|
||||
applyFn: () => { G.harmonyRate -= 0.5; G.codeBoost *= 0.7; },
|
||||
resolveCost: { resource: 'trust', amount: 15 }
|
||||
});
|
||||
log('EVENT: Community drama. Spend 15 trust to mediate.', true);
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1223,6 +1302,26 @@ function resolveAlignment(accept) {
|
||||
render();
|
||||
}
|
||||
|
||||
function resolveEvent(debuffId) {
|
||||
const idx = G.activeDebuffs.findIndex(d => d.id === debuffId);
|
||||
if (idx === -1) return;
|
||||
const debuff = G.activeDebuffs[idx];
|
||||
if (!debuff.resolveCost) return;
|
||||
const { resource, amount } = debuff.resolveCost;
|
||||
if ((G[resource] || 0) < amount) {
|
||||
log(`Need ${fmt(amount)} ${resource} to resolve ${debuff.title}. Have ${fmt(G[resource])}.`);
|
||||
return;
|
||||
}
|
||||
G[resource] -= amount;
|
||||
G.activeDebuffs.splice(idx, 1);
|
||||
G.totalEventsResolved = (G.totalEventsResolved || 0) + 1;
|
||||
log(`Resolved: ${debuff.title}. Problem fixed.`, true);
|
||||
// Refund partial trust for resolution effort
|
||||
G.trust += 3;
|
||||
updateRates();
|
||||
render();
|
||||
}
|
||||
|
||||
// === ACTIONS ===
|
||||
function writeCode() {
|
||||
const base = 1;
|
||||
@@ -1483,6 +1582,7 @@ function renderStats() {
|
||||
set('st-projects', (G.completedProjects || []).length.toString());
|
||||
set('st-harmony', Math.floor(G.harmony).toString());
|
||||
set('st-drift', (G.drift || 0).toString());
|
||||
set('st-resolved', (G.totalEventsResolved || 0).toString());
|
||||
|
||||
const elapsed = Math.floor((Date.now() - G.startedAt) / 1000);
|
||||
const m = Math.floor(elapsed / 60);
|
||||
@@ -1538,6 +1638,29 @@ function renderCombo() {
|
||||
}
|
||||
}
|
||||
|
||||
function renderDebuffs() {
|
||||
const container = document.getElementById('debuffs');
|
||||
if (!container) return;
|
||||
if (!G.activeDebuffs || G.activeDebuffs.length === 0) {
|
||||
container.style.display = 'none';
|
||||
container.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
container.style.display = 'block';
|
||||
let html = '<h2 style="color:#f44336;font-size:11px;margin-bottom:6px">ACTIVE PROBLEMS</h2>';
|
||||
for (const d of G.activeDebuffs) {
|
||||
const afford = d.resolveCost && (G[d.resolveCost.resource] || 0) >= d.resolveCost.amount;
|
||||
const costStr = d.resolveCost ? `${fmt(d.resolveCost.amount)} ${d.resolveCost.resource}` : '—';
|
||||
html += `<div style="background:#1a0808;border:1px solid ${afford ? '#f44336' : '#2a1010'};border-radius:4px;padding:6px 8px;margin-bottom:4px;display:flex;justify-content:space-between;align-items:center">`;
|
||||
html += `<div><div style="color:#f44336;font-weight:600;font-size:10px">${d.title}</div><div style="color:#888;font-size:9px">${d.desc}</div></div>`;
|
||||
if (d.resolveCost) {
|
||||
html += `<button class="ops-btn" style="border-color:${afford ? '#4caf50' : '#333'};color:${afford ? '#4caf50' : '#555'};font-size:9px;padding:4px 8px;white-space:nowrap" onclick="resolveEvent('${d.id}')" ${afford ? '' : 'disabled'} title="Resolve: ${costStr}">Fix (${costStr})</button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
function render() {
|
||||
renderResources();
|
||||
renderPhase();
|
||||
@@ -1548,6 +1671,7 @@ function render() {
|
||||
renderAlignment();
|
||||
renderProgress();
|
||||
renderCombo();
|
||||
renderDebuffs();
|
||||
}
|
||||
|
||||
function renderAlignment() {
|
||||
@@ -1587,6 +1711,8 @@ function showSaveToast() {
|
||||
}
|
||||
|
||||
function saveGame() {
|
||||
// Save debuff IDs (can't serialize functions)
|
||||
const debuffIds = (G.activeDebuffs || []).map(d => d.id);
|
||||
const saveData = {
|
||||
code: G.code, compute: G.compute, knowledge: G.knowledge, users: G.users, impact: G.impact,
|
||||
ops: G.ops, trust: G.trust, creativity: G.creativity, harmony: G.harmony,
|
||||
@@ -1607,6 +1733,8 @@ function saveGame() {
|
||||
rescues: G.rescues || 0, totalRescues: G.totalRescues || 0,
|
||||
drift: G.drift || 0, driftEnding: G.driftEnding || false, beaconEnding: G.beaconEnding || false, pendingAlignment: G.pendingAlignment || false,
|
||||
lastEventAt: G.lastEventAt || 0,
|
||||
activeDebuffIds: debuffIds,
|
||||
totalEventsResolved: G.totalEventsResolved || 0,
|
||||
savedAt: Date.now()
|
||||
};
|
||||
|
||||
@@ -1622,6 +1750,20 @@ function loadGame() {
|
||||
const data = JSON.parse(raw);
|
||||
Object.assign(G, data);
|
||||
|
||||
// Reconstitute active debuffs from saved IDs (functions can't be JSON-parsed)
|
||||
if (data.activeDebuffIds && data.activeDebuffIds.length > 0) {
|
||||
G.activeDebuffs = [];
|
||||
for (const id of data.activeDebuffIds) {
|
||||
const evDef = EVENTS.find(e => e.id === id);
|
||||
if (evDef) {
|
||||
// Re-fire the event to get the full debuff object with applyFn
|
||||
evDef.effect();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
G.activeDebuffs = [];
|
||||
}
|
||||
|
||||
updateRates();
|
||||
|
||||
// Offline progress
|
||||
|
||||
@@ -98,6 +98,7 @@ body{background:var(--bg);color:var(--text);font-family:'SF Mono','Cascadia Code
|
||||
<h2>ACTIONS</h2>
|
||||
<div class="action-btn-group"><button class="main-btn" onclick="writeCode()">WRITE CODE</button></div>
|
||||
<div id="combo-display" style="text-align:center;font-size:10px;color:var(--dim);height:14px;margin-bottom:4px;transition:all 0.2s"></div>
|
||||
<div id="debuffs" style="display:none;margin-top:8px"></div>
|
||||
<div class="action-btn-group">
|
||||
<button class="ops-btn" onclick="doOps('boost_code')">Ops -> Code</button>
|
||||
<button class="ops-btn" onclick="doOps('boost_compute')">Ops -> Compute</button>
|
||||
@@ -128,7 +129,8 @@ Projects Done: <span id="st-projects">0</span><br>
|
||||
Time Played: <span id="st-time">0:00</span><br>
|
||||
Clicks: <span id="st-clicks">0</span><br>
|
||||
Harmony: <span id="st-harmony">50</span><br>
|
||||
Drift: <span id="st-drift">0</span>
|
||||
Drift: <span id="st-drift">0</span><br>
|
||||
Events Resolved: <span id="st-resolved">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user