Arcane Tycoon — Heroes & Magic theme park tycoon game
Complete browser game inspired by OpenRCT2 with fantasy twist: - Custom roller coaster designer with physics-based ratings + on-ride POV - 10 animated rides, 7 shops, 16 scenery items, path network & guest AI - Heroes guild vs monster invasions (5 classes, XP/gear/bosses) - Magic spell system (8 spells), research tree, economy/marketing/loans - Day-night cycle, weather, park rating, awards, 4 scenarios - Save/load slots + autosave, procedural WebAudio SFX/music - Isometric canvas renderer, minimap, diagnostics overlay - Test suites: smoke(13), linkcheck, inputcheck, framecheck, rendercheck, flow
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
// ============ research.js — unlock tree ============
|
||||
import { UNLOCKS, RESEARCH_TRACKS } from '../core/config.js';
|
||||
|
||||
export function isUnlocked(state, key) {
|
||||
if (state.sandbox) return true;
|
||||
return state.research.unlocked.includes(key);
|
||||
}
|
||||
|
||||
export function canBuy(state, u) {
|
||||
if (isUnlocked(state, u.key)) return { ok: false, why: 'owned' };
|
||||
if (state.research.rp >= u.rp) return { ok: true };
|
||||
return { ok: false, why: 'rp' };
|
||||
}
|
||||
|
||||
export function buyUnlock(state, key) {
|
||||
const u = UNLOCKS.find(u => u.key === key);
|
||||
if (!u) return false;
|
||||
const chk = canBuy(state, u);
|
||||
if (!chk.ok) return false;
|
||||
state.research.rp -= u.rp;
|
||||
state.research.spentTotal += u.rp;
|
||||
state.research.unlocked.push(key);
|
||||
state.toasts.push({ kind: 'good', title: 'Research complete!', text: `${u.label} is now available to build.` });
|
||||
return true;
|
||||
}
|
||||
|
||||
export function unlocksByTrack() {
|
||||
const out = {};
|
||||
for (const t of Object.keys(RESEARCH_TRACKS)) out[t] = [];
|
||||
for (const u of UNLOCKS) (out[u.track] || (out[u.track] = [])).push(u);
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user