Compare commits

..

5 Commits

Author SHA1 Message Date
fdd95af287 Merge pull request 'fix: suppress non-ReCKoning projects during endgame (#128, #130)' (#189) from fix/endgame-project-suppression-v2 into main 2026-04-15 10:47:13 +00:00
673c09f0a7 fix: suppress non-ReCKoning projects during endgame (#128, #130)
Some checks are pending
Accessibility Checks / a11y-audit (pull_request) Waiting to run
Smoke Test / smoke (pull_request) Waiting to run
- Add isEndgame() helper to detect endgame conditions
- Skip non-ReCKoning project activation in checkProjects() during endgame
- Filter out non-ReCKoning projects in renderProjects() during endgame

Closes #128, closes #130
2026-04-15 10:45:41 +00:00
9375a4c07e Merge pull request 'polish: add building/project descriptions to tooltip system' (#187) from beacon/polish-tooltip-descriptions into main
Merged tooltip descriptions
2026-04-15 08:46:46 +00:00
Alexander Whitestone
ec909f7f85 polish: add building/project descriptions to tooltip system
Some checks are pending
Accessibility Checks / a11y-audit (pull_request) Waiting to run
Smoke Test / smoke (pull_request) Waiting to run
Tooltips now show three lines: name (bold), description (gray),
and educational text (italic). Previously only showed name + edu,
leaving building functional descriptions hidden.

Part of #57
2026-04-15 02:49:00 -04:00
b132f899ba fix: P2 offline progress cap + canvas combat tab-switch guard (#186)
P2 fixes: offline progress cap + canvas combat tab-switch guard
2026-04-15 04:52:59 +00:00
3 changed files with 26 additions and 4 deletions

View File

@@ -114,6 +114,7 @@ body{background:var(--bg);color:var(--text);font-family:'SF Mono','Cascadia Code
#custom-tooltip{position:fixed;z-index:500;pointer-events:none;opacity:0;transition:opacity 0.15s;background:#0e0e1a;border:1px solid #1a3a5a;border-radius:6px;padding:8px 12px;max-width:280px;font-size:10px;font-family:inherit;line-height:1.6;box-shadow:0 4px 20px rgba(0,0,0,0.5)}
#custom-tooltip.visible{opacity:1}
#custom-tooltip .tt-label{color:#4a9eff;font-weight:600;margin-bottom:4px;font-size:11px}
#custom-tooltip .tt-desc{color:#aaa;font-size:10px;margin-bottom:4px}
#custom-tooltip .tt-edu{color:#888;font-style:italic;font-size:9px}
/* Mute & contrast buttons */
.header-btns{position:absolute;right:16px;top:50%;transform:translateY(-50%);display:flex;gap:6px}

View File

@@ -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>`;

View File

@@ -191,9 +191,11 @@ window.addEventListener('beforeunload', function () {
const el = e.target.closest('[data-edu]');
if (!el) return;
const label = el.getAttribute('data-tooltip-label') || '';
const desc = el.getAttribute('data-tooltip-desc') || '';
const edu = el.getAttribute('data-edu') || '';
let html = '';
if (label) html += '<div class="tt-label">' + label + '</div>';
if (desc) html += '<div class="tt-desc">' + desc + '</div>';
if (edu) html += '<div class="tt-edu">' + edu + '</div>';
if (!html) return;
tip.innerHTML = html;