166 lines
5.3 KiB
JavaScript
166 lines
5.3 KiB
JavaScript
// Production - The Idle Game: State Container & Persistence
|
|
|
|
import { PRODUCTS } from '../data/products.js';
|
|
import { BOARDROOM_PERKS, calculateSharesEarned } from '../data/boardroom.js';
|
|
import { CONTRACT_TEMPLATES } from '../data/contracts.js';
|
|
import { ACHIEVEMENTS } from '../data/achievements.js';
|
|
|
|
const STORAGE_KEY = 'production_the_idle_game_save_v1';
|
|
|
|
export function getInitialState() {
|
|
const state = {
|
|
version: 1,
|
|
companyName: 'Apex Production Industries',
|
|
cash: 30.0,
|
|
lifetimeRevenue: 0.0,
|
|
valuation: 30.0,
|
|
ventureShares: 0,
|
|
totalVentureShares: 0,
|
|
ipoCount: 0,
|
|
reputation: 0,
|
|
buyMode: '1',
|
|
activeTab: 'production',
|
|
selectedSector: 'all',
|
|
selectedProductId: 'wheat',
|
|
stats: {
|
|
totalProduced: 0,
|
|
contractsCompleted: 0,
|
|
managersHired: 0
|
|
},
|
|
products: {},
|
|
boardroomPerks: {},
|
|
achievements: {},
|
|
activeContracts: [],
|
|
lastTick: Date.now()
|
|
};
|
|
|
|
// Initialize all products
|
|
PRODUCTS.forEach(p => {
|
|
state.products[p.id] = {
|
|
unlocked: p.unlockedDefault,
|
|
stock: 0.0,
|
|
lines: p.unlockedDefault ? 1 : 0,
|
|
manager: false,
|
|
logistics: p.unlockedDefault ? 1 : 0,
|
|
logisticsEnabled: true,
|
|
supplyDownstreamEnabled: true,
|
|
productionTarget: 1.0,
|
|
cycleProgress: 0.0,
|
|
isBottlenecked: false,
|
|
totalProduced: 0.0
|
|
};
|
|
});
|
|
|
|
|
|
// Initialize boardroom perks
|
|
BOARDROOM_PERKS.forEach(perk => {
|
|
state.boardroomPerks[perk.id] = 0;
|
|
});
|
|
|
|
// Initialize achievements
|
|
ACHIEVEMENTS.forEach(ach => {
|
|
state.achievements[ach.id] = 0;
|
|
});
|
|
|
|
// Generate initial starting contracts
|
|
state.activeContracts = [
|
|
{
|
|
uid: 'c_start_1',
|
|
templateId: CONTRACT_TEMPLATES[0].id,
|
|
productId: CONTRACT_TEMPLATES[0].productId,
|
|
title: CONTRACT_TEMPLATES[0].title,
|
|
clientId: CONTRACT_TEMPLATES[0].clientId,
|
|
targetAmount: CONTRACT_TEMPLATES[0].requiredAmount,
|
|
remainingSeconds: CONTRACT_TEMPLATES[0].timeLimit,
|
|
rewardCash: CONTRACT_TEMPLATES[0].rewardCash,
|
|
rewardRep: CONTRACT_TEMPLATES[0].rewardRep
|
|
}
|
|
];
|
|
|
|
return state;
|
|
}
|
|
|
|
export class StateManager {
|
|
constructor() {
|
|
this.state = this.load();
|
|
this.listeners = new Set();
|
|
}
|
|
|
|
subscribe(fn) {
|
|
this.listeners.add(fn);
|
|
return () => this.listeners.delete(fn);
|
|
}
|
|
|
|
notify(changedKeys = []) {
|
|
for (const fn of this.listeners) {
|
|
fn(this.state, changedKeys);
|
|
}
|
|
}
|
|
|
|
load() {
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
if (!raw) return getInitialState();
|
|
const parsed = JSON.parse(raw);
|
|
const fresh = getInitialState();
|
|
|
|
// Merge safely to preserve schema additions
|
|
const merged = { ...fresh, ...parsed };
|
|
merged.products = { ...fresh.products, ...(parsed.products || {}) };
|
|
merged.boardroomPerks = { ...fresh.boardroomPerks, ...(parsed.boardroomPerks || {}) };
|
|
merged.achievements = { ...fresh.achievements, ...(parsed.achievements || {}) };
|
|
merged.stats = { ...fresh.stats, ...(parsed.stats || {}) };
|
|
if (!Array.isArray(merged.activeContracts) || merged.activeContracts.length === 0) {
|
|
merged.activeContracts = fresh.activeContracts;
|
|
}
|
|
return merged;
|
|
} catch (err) {
|
|
console.error('Failed to load local state, fallback to fresh:', err);
|
|
return getInitialState();
|
|
}
|
|
}
|
|
|
|
save() {
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state));
|
|
} catch (err) {
|
|
console.error('Failed to save state to localStorage:', err);
|
|
}
|
|
}
|
|
|
|
reset() {
|
|
this.state = getInitialState();
|
|
this.save();
|
|
this.notify();
|
|
}
|
|
|
|
performIPO() {
|
|
const earned = calculateSharesEarned(this.state.lifetimeRevenue);
|
|
if (earned <= 0) return false;
|
|
|
|
const startingBonusPerk = this.state.boardroomPerks['angel_syndicate'] || 0;
|
|
const startingCashBonuses = [30.0, 500.0, 5000.0, 50000.0, 500000.0, 5000000.0];
|
|
const newStartingCash = startingCashBonuses[Math.min(startingBonusPerk, startingCashBonuses.length - 1)];
|
|
|
|
const preservedShares = this.state.ventureShares + earned;
|
|
const preservedTotalShares = this.state.totalVentureShares + earned;
|
|
const preservedPerks = { ...this.state.boardroomPerks };
|
|
const preservedIpoCount = this.state.ipoCount + 1;
|
|
const preservedAchievements = { ...this.state.achievements };
|
|
|
|
// Fresh state
|
|
this.state = getInitialState();
|
|
this.state.cash = newStartingCash;
|
|
this.state.ventureShares = preservedShares;
|
|
this.state.totalVentureShares = preservedTotalShares;
|
|
this.state.ipoCount = preservedIpoCount;
|
|
this.state.boardroomPerks = preservedPerks;
|
|
this.state.achievements = preservedAchievements;
|
|
|
|
this.save();
|
|
this.notify();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export const GState = new StateManager();
|