210 lines
7.0 KiB
JavaScript
210 lines
7.0 KiB
JavaScript
/**
|
|
* PvZ Dynamic Game Configuration & Balance System (PvZConfig)
|
|
* Fetches active balance multipliers from /api/config with fallback defaults and offline localStorage cache.
|
|
*/
|
|
|
|
window.PvZConfig = (function () {
|
|
const DEFAULT_CONFIG = {
|
|
preset: 'Classic 2009',
|
|
economy: {
|
|
sunMultiplier: 1.0,
|
|
startingSun: 50,
|
|
coinDropRate: 1.0,
|
|
sunDropRate: 1.0,
|
|
plantCostMultiplier: 1.0,
|
|
upgradeCostMultiplier: 1.0,
|
|
plantPrices: {
|
|
sunflower: 0,
|
|
peashooter: 0,
|
|
wallnut: 0,
|
|
potatomine: 150,
|
|
snowpea: 350,
|
|
repeater: 500,
|
|
chomper: 450,
|
|
cherrybomb: 400,
|
|
jalapeno: 450,
|
|
sunshroom: 250,
|
|
fumeshroom: 300,
|
|
lilypad: 200,
|
|
gravebuster: 250,
|
|
flowerpot: 200,
|
|
cabbagepult: 400,
|
|
melonpult: 750
|
|
},
|
|
plantSunCosts: {
|
|
sunflower: 50,
|
|
peashooter: 100,
|
|
wallnut: 50,
|
|
potatomine: 25,
|
|
snowpea: 175,
|
|
repeater: 200,
|
|
chomper: 150,
|
|
cherrybomb: 150,
|
|
jalapeno: 125,
|
|
sunshroom: 25,
|
|
fumeshroom: 75,
|
|
lilypad: 25,
|
|
gravebuster: 75,
|
|
flowerpot: 25,
|
|
cabbagepult: 100,
|
|
melonpult: 300
|
|
}
|
|
},
|
|
zombies: {
|
|
hpMultiplier: 1.0,
|
|
speedMultiplier: 1.0,
|
|
damageMultiplier: 1.0,
|
|
waveDensityMultiplier: 1.0,
|
|
types: {
|
|
normal: { hp: 200, speed: 22, damage: 30 },
|
|
conehead: { hp: 300, speed: 22, damage: 30 },
|
|
buckethead: { hp: 600, speed: 22, damage: 30 },
|
|
newspaper: { hp: 300, speed: 18, damage: 30 },
|
|
screendoor: { hp: 650, speed: 20, damage: 30 },
|
|
football: { hp: 600, speed: 42, damage: 35 },
|
|
dancing: { hp: 350, speed: 25, damage: 30 },
|
|
gargantuar: { hp: 3000, speed: 14, damage: 300 },
|
|
zomboss: { hp: 10000, speed: 0, damage: 500 },
|
|
polevaulter: { hp: 180, speed: 44, damage: 30 },
|
|
duckytube: { hp: 120, speed: 24, damage: 30 },
|
|
flag: { hp: 200, speed: 28, damage: 30 }
|
|
}
|
|
},
|
|
plants: {
|
|
damageMultiplier: 1.0,
|
|
hpMultiplier: 1.0,
|
|
cooldownMultiplier: 1.0,
|
|
sunProduceIntervalMultiplier: 1.0
|
|
},
|
|
zenGarden: {
|
|
dropRateMultiplier: 1.0,
|
|
growthRateMultiplier: 1.0,
|
|
fertilizerMultiplier: 1.0,
|
|
waterIntervalMinutes: 30
|
|
},
|
|
events: {
|
|
doubleGold: false,
|
|
fastCooldowns: false,
|
|
infiniteSun: false,
|
|
turboZombies: false,
|
|
activeEventName: 'none'
|
|
}
|
|
};
|
|
|
|
let activeConfig = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
|
|
|
|
// Try loading cached config from localStorage
|
|
try {
|
|
const cached = localStorage.getItem('pvz_game_config');
|
|
if (cached) {
|
|
const parsed = JSON.parse(cached);
|
|
if (parsed && typeof parsed === 'object') {
|
|
activeConfig = Object.assign({}, DEFAULT_CONFIG, parsed);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// ignore
|
|
}
|
|
|
|
async function fetchConfig() {
|
|
try {
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), 2500);
|
|
const res = await fetch('/api/config', { signal: controller.signal });
|
|
clearTimeout(timeoutId);
|
|
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
if (data && typeof data === 'object') {
|
|
activeConfig = Object.assign({}, DEFAULT_CONFIG, data);
|
|
try {
|
|
localStorage.setItem('pvz_game_config', JSON.stringify(activeConfig));
|
|
} catch (e) {}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.warn('[PvZConfig] Using cached/default balance config:', err.message);
|
|
}
|
|
return activeConfig;
|
|
}
|
|
|
|
// Auto-fetch on script load
|
|
if (typeof window !== 'undefined') {
|
|
fetchConfig();
|
|
}
|
|
|
|
return {
|
|
fetchConfig,
|
|
getConfig: () => activeConfig,
|
|
getPreset: () => activeConfig.preset || 'Classic 2009',
|
|
|
|
// Economy
|
|
getEconomy: () => activeConfig.economy || DEFAULT_CONFIG.economy,
|
|
getStartingSun: () => {
|
|
const eco = activeConfig.economy || {};
|
|
const base = typeof eco.startingSun === 'number' ? eco.startingSun : 50;
|
|
return activeConfig.events?.infiniteSun ? Math.max(base, 250) : base;
|
|
},
|
|
getSunMultiplier: () => {
|
|
const eco = activeConfig.economy || {};
|
|
const mult = typeof eco.sunMultiplier === 'number' ? eco.sunMultiplier : 1.0;
|
|
return activeConfig.events?.infiniteSun ? mult * 1.5 : mult;
|
|
},
|
|
getCoinDropRate: () => {
|
|
const eco = activeConfig.economy || {};
|
|
const mult = typeof eco.coinDropRate === 'number' ? eco.coinDropRate : 1.0;
|
|
return activeConfig.events?.doubleGold ? mult * 2.0 : mult;
|
|
},
|
|
getSunDropRate: () => activeConfig.economy?.sunDropRate ?? 1.0,
|
|
getPlantShopPrice: (plantId) => {
|
|
const eco = activeConfig.economy || {};
|
|
const prices = eco.plantPrices || {};
|
|
const base = prices[plantId] ?? (plantId === 'sunflower' || plantId === 'peashooter' || plantId === 'wallnut' ? 0 : 250);
|
|
const mult = eco.plantCostMultiplier ?? 1.0;
|
|
return Math.round(base * mult);
|
|
},
|
|
getPlantSunCost: (plantId, defaultCost = 50) => {
|
|
const eco = activeConfig.economy || {};
|
|
const sunCosts = eco.plantSunCosts || {};
|
|
return sunCosts[plantId] !== undefined ? sunCosts[plantId] : defaultCost;
|
|
},
|
|
|
|
// Zombies & Combat
|
|
getZombieGlobal: () => activeConfig.zombies || DEFAULT_CONFIG.zombies,
|
|
getZombieHpMult: () => activeConfig.zombies?.hpMultiplier ?? 1.0,
|
|
getZombieSpeedMult: () => {
|
|
const mult = activeConfig.zombies?.speedMultiplier ?? 1.0;
|
|
return activeConfig.events?.turboZombies ? mult * 1.3 : mult;
|
|
},
|
|
getZombieDamageMult: () => activeConfig.zombies?.damageMultiplier ?? 1.0,
|
|
getWaveDensityMult: () => activeConfig.zombies?.waveDensityMultiplier ?? 1.0,
|
|
getZombieTypeConfig: (type) => {
|
|
const types = activeConfig.zombies?.types || {};
|
|
return types[type] || DEFAULT_CONFIG.zombies.types[type] || { hp: 200, speed: 22, damage: 30 };
|
|
},
|
|
|
|
// Plants
|
|
getPlantGlobal: () => activeConfig.plants || DEFAULT_CONFIG.plants,
|
|
getPlantDamageMult: () => activeConfig.plants?.damageMultiplier ?? 1.0,
|
|
getPlantHpMult: () => activeConfig.plants?.hpMultiplier ?? 1.0,
|
|
getPlantCooldownMult: () => {
|
|
const mult = activeConfig.plants?.cooldownMultiplier ?? 1.0;
|
|
return activeConfig.events?.fastCooldowns ? mult * 0.4 : mult;
|
|
},
|
|
getSunIntervalMult: () => activeConfig.plants?.sunProduceIntervalMultiplier ?? 1.0,
|
|
|
|
// Zen Garden
|
|
getZenGarden: () => activeConfig.zenGarden || DEFAULT_CONFIG.zenGarden,
|
|
getZenDropRateMult: () => {
|
|
const mult = activeConfig.zenGarden?.dropRateMultiplier ?? 1.0;
|
|
return activeConfig.events?.doubleGold ? mult * 2.0 : mult;
|
|
},
|
|
getZenGrowthRateMult: () => activeConfig.zenGarden?.growthRateMultiplier ?? 1.0,
|
|
getZenFertilizerMult: () => activeConfig.zenGarden?.fertilizerMultiplier ?? 1.0,
|
|
getZenWaterIntervalMinutes: () => activeConfig.zenGarden?.waterIntervalMinutes ?? 30,
|
|
|
|
// Events
|
|
getEvents: () => activeConfig.events || DEFAULT_CONFIG.events
|
|
};
|
|
})();
|