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,96 @@
|
||||
// ============ economy.js — money, finance cycles, marketing ============
|
||||
import { fmtMoney } from '../core/util.js';
|
||||
|
||||
export function pay(state, amount, category, note) {
|
||||
state.cash -= amount;
|
||||
pushFin(state, category, -amount);
|
||||
return true;
|
||||
}
|
||||
export function earn(state, amount, category, note) {
|
||||
state.cash += amount;
|
||||
pushFin(state, category, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function pushFin(state, category, amount) {
|
||||
const m = state.finance.current;
|
||||
m[category] = (m[category] || 0) + amount;
|
||||
}
|
||||
|
||||
export const FIN_CATEGORIES = [
|
||||
['rideTickets', 'Ride tickets'],
|
||||
['shopSales', 'Shop sales'],
|
||||
['entrance', 'Entrance fees'],
|
||||
['construction', 'Construction'],
|
||||
['wages', 'Staff wages'],
|
||||
['research', 'Research'],
|
||||
['marketing', 'Marketing'],
|
||||
['heroes', 'Heroes & gear'],
|
||||
['loot', 'Monster loot'],
|
||||
['runCosts', 'Ride running costs'],
|
||||
['misc', 'Misc'],
|
||||
['loans', 'Loans'],
|
||||
];
|
||||
|
||||
/** Monthly finance close: wages, interest, archive */
|
||||
export function monthClose(state) {
|
||||
// wages
|
||||
let wages = 0;
|
||||
for (const s of state.staff) wages += s.wage;
|
||||
for (const r of state.rides) wages += Math.round(r.def.runCost);
|
||||
pay(state, wages, 'wages');
|
||||
// loan interest 1%/month
|
||||
if (state.loan > 0) {
|
||||
const interest = Math.ceil(state.loan * 0.01);
|
||||
pay(state, interest, 'loans');
|
||||
}
|
||||
// archive current month
|
||||
const cur = { ...state.finance.current };
|
||||
state.finance.history.push(cur);
|
||||
if (state.finance.history.length > 36) state.finance.history.shift();
|
||||
state.finance.current = {};
|
||||
state.lastMonthProfit = Object.entries(cur).reduce((a, [, v]) => a + v, 0);
|
||||
return wages;
|
||||
}
|
||||
|
||||
// ---------------- Marketing campaigns ----------------
|
||||
export const CAMPAIGNS = [
|
||||
{ id: 'flyers', name: 'Fairy Flyer Drop', cost: 400, weeks: 6, pull: 1.6 },
|
||||
{ id: 'heralds', name: 'Town Crier Heralds', cost: 900, weeks: 8, pull: 2.4 },
|
||||
{ id: 'crystal', name: 'Crystal Ball Vision', cost: 1800, weeks: 10, pull: 3.6 },
|
||||
];
|
||||
|
||||
export function startCampaign(state, id) {
|
||||
const c = CAMPAIGNS.find(c => c.id === id);
|
||||
if (!c || state.cash < c.cost) return false;
|
||||
pay(state, c.cost, 'marketing');
|
||||
state.campaigns.push({ id: c.id, name: c.name, weeksLeft: c.weeks, pull: c.pull });
|
||||
return true;
|
||||
}
|
||||
export function campaignPull(state) {
|
||||
let p = 0;
|
||||
for (const c of state.campaigns) p += c.pull;
|
||||
return p;
|
||||
}
|
||||
export function tickCampaigns(state) {
|
||||
for (let i = state.campaigns.length - 1; i >= 0; i--) {
|
||||
state.campaigns[i].weeksLeft--;
|
||||
if (state.campaigns[i].weeksLeft <= 0) state.campaigns.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- Loan ----------------
|
||||
export function takeLoan(state, amount) {
|
||||
amount = Math.min(amount, state.loanLimit - state.loan);
|
||||
if (amount <= 0) return false;
|
||||
state.loan += amount;
|
||||
earn(state, amount, 'loans');
|
||||
return true;
|
||||
}
|
||||
export function repayLoan(state, amount) {
|
||||
amount = Math.min(amount, state.loan, state.cash);
|
||||
if (amount <= 0) return false;
|
||||
state.loan -= amount;
|
||||
pay(state, amount, 'loans');
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user