|
|
|
|
@@ -111,6 +111,15 @@ function updateRates() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// === CORE FUNCTIONS ===
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if player has reached the ReCKoning endgame.
|
|
|
|
|
* Conditions: totalRescues >= 100000, pactFlag === 1, harmony > 50
|
|
|
|
|
*/
|
|
|
|
|
function isEndgame() {
|
|
|
|
|
return G.totalRescues >= 100000 && G.pactFlag === 1 && G.harmony > 50;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Main game loop tick, called every 100ms.
|
|
|
|
|
*/
|
|
|
|
|
@@ -337,6 +346,11 @@ function checkMilestones() {
|
|
|
|
|
function checkProjects() {
|
|
|
|
|
// Check for new project triggers
|
|
|
|
|
for (const pDef of PDEFS) {
|
|
|
|
|
// Skip non-ReCKoning projects during endgame
|
|
|
|
|
if (isEndgame() && !pDef.id.startsWith('p_reckoning_')) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const alreadyPurchased = G.completedProjects && G.completedProjects.includes(pDef.id);
|
|
|
|
|
if (!alreadyPurchased && !G.activeProjects) G.activeProjects = [];
|
|
|
|
|
|
|
|
|
|
@@ -1096,7 +1110,7 @@ function renderBuildings() {
|
|
|
|
|
|
|
|
|
|
// Locked preview: show dimmed with unlock hint
|
|
|
|
|
if (!isUnlocked) {
|
|
|
|
|
html += `<div class="build-btn" style="opacity:0.25;cursor:default" data-edu="${def.edu || ''}" data-tooltip-label="${def.name} (Locked)">`;
|
|
|
|
|
html += `<div class="build-btn" style="opacity:0.25;cursor:default" data-edu="${def.edu || ''}" data-tooltip-label="${def.name} (Locked)" data-tooltip-desc="${def.desc || ''}">`;
|
|
|
|
|
html += `<span class="b-name" style="color:#555">${def.name}</span>`;
|
|
|
|
|
html += `<span class="b-count" style="color:#444">\u{1F512}</span>`;
|
|
|
|
|
html += `<span class="b-cost" style="color:#444">Phase ${def.phase}: ${PHASES[def.phase]?.name || '?'}</span>`;
|
|
|
|
|
@@ -1137,7 +1151,7 @@ function renderBuildings() {
|
|
|
|
|
return boost !== 1 ? `+${fmt(boosted)}/${r}/s` : `+${v}/${r}/s`;
|
|
|
|
|
}).join(', ') : '';
|
|
|
|
|
|
|
|
|
|
html += `<button class="build-btn ${afford ? 'can-buy' : ''}" onclick="buyBuilding('${def.id}')" data-edu="${def.edu || ''}" data-tooltip-label="${def.name}" aria-label="Buy ${def.name}, cost ${costStr}">`;
|
|
|
|
|
html += `<button class="build-btn ${afford ? 'can-buy' : ''}" onclick="buyBuilding('${def.id}')" data-edu="${def.edu || ''}" data-tooltip-label="${def.name}" data-tooltip-desc="${def.desc || ''}" aria-label="Buy ${def.name}, cost ${costStr}">`;
|
|
|
|
|
html += `<span class="b-name">${def.name}</span>`;
|
|
|
|
|
if (count > 0) html += `<span class="b-count">x${count}</span>`;
|
|
|
|
|
html += `<span class="b-cost">Cost: ${costStr}</span>`;
|
|
|
|
|
@@ -1173,14 +1187,19 @@ function renderProjects() {
|
|
|
|
|
|
|
|
|
|
// Show available projects
|
|
|
|
|
if (G.activeProjects) {
|
|
|
|
|
for (const id of G.activeProjects) {
|
|
|
|
|
// Filter out non-ReCKoning projects during endgame
|
|
|
|
|
const projectsToShow = isEndgame()
|
|
|
|
|
? G.activeProjects.filter(id => id.startsWith('p_reckoning_'))
|
|
|
|
|
: G.activeProjects;
|
|
|
|
|
|
|
|
|
|
for (const id of projectsToShow) {
|
|
|
|
|
const pDef = PDEFS.find(p => p.id === id);
|
|
|
|
|
if (!pDef) continue;
|
|
|
|
|
|
|
|
|
|
const afford = canAffordProject(pDef);
|
|
|
|
|
const costStr = Object.entries(pDef.cost).map(([r, a]) => `${fmt(a)} ${r}`).join(', ');
|
|
|
|
|
|
|
|
|
|
html += `<button class="project-btn ${afford ? 'can-buy' : ''}" onclick="buyProject('${pDef.id}')" data-edu="${pDef.edu || ''}" data-tooltip-label="${pDef.name}" aria-label="Research ${pDef.name}, cost ${costStr}">`;
|
|
|
|
|
html += `<button class="project-btn ${afford ? 'can-buy' : ''}" onclick="buyProject('${pDef.id}')" data-edu="${pDef.edu || ''}" data-tooltip-label="${pDef.name}" data-tooltip-desc="${pDef.desc || ''}" aria-label="Research ${pDef.name}, cost ${costStr}">`;
|
|
|
|
|
html += `<span class="p-name">* ${pDef.name}</span>`;
|
|
|
|
|
html += `<span class="p-cost">Cost: ${costStr}</span>`;
|
|
|
|
|
html += `<span class="p-desc">${pDef.desc}</span></button>`;
|
|
|
|
|
|