import * as THREE from "three"; // Game settings export const INITIAL_MONEY = 200; export const INITIAL_LIVES = 10; // Audio settings export const AUDIO_CONFIG = { musicVolume: 0.4, // Background music volume (0-1) effectsVolume: 0.3, // Sound effects volume (0-1) musicEnabled: true, // Enable/disable background music effectsEnabled: true, // Enable/disable sound effects }; // Tower settings // Define multiple tower types, keeping the original as "basic" export const TOWER_TYPES = { basic: { key: "basic", name: "Basic Tower", type: "basic", cost: 50, range: 9, fireRate: 1.0, // shots per second damage: 6, }, slow: { key: "slow", name: "Slow Tower", type: "slow", cost: 60, range: 8.5, fireRate: 0.9, damage: 4, // On-hit slow: 40% slow (mult 0.6) for 2.5s, refresh on re-hit projectileEffect: { type: "slow", mult: 0.6, duration: 2.5, color: 0x80d8ff, emissive: 0x104a70, }, }, sniper: { key: "sniper", name: "Sniper Tower", type: "sniper", cost: 130, // 2x the range of basic range: 18, // slow fire rate fireRate: 0.7, // shots per second (reload ≈ 3.33s) damage: 32, // high damage per shot // Sniper specific parameters aimTime: 0.8, // seconds to aim before firing projectileSpeed: 40, // high-speed dart // Targeting priority identifier targetPriority: "closestToExit", // If target moves out of this threshold (>= range) during aiming, cancel cancelThreshold: 18, // Optional chance to pierce; behavior can be extended later pierceChance: 0.0, }, electric: { key: "electric", name: "Electric Tower", type: "electric", cost: 200, // Set to the smallest tower range (slow tower = 8.5) range: 8.5, // world units (scene uses world units; 1 cell = 2 units, so ~4.25 cells) fireRate: 1.0, // shots per second damage: 25, // per target maxTargets: 3, // Persist electric arc visuals for 2 seconds arcDurationMs: 2000, // Visual tuning for arcs (can be read by Tower) arc: { color: 0x9ad6ff, // light electric blue coreColor: 0xe6fbff, thickness: 2, jitter: 0.25, segments: 10, }, // Targeting priority targetPriority: "closestToExit", }, }; // Back-compat alias for existing code that expects TOWER_CONFIG export const TOWER_CONFIG = TOWER_TYPES.basic; // Projectile settings export const PROJECTILE_SPEED = 18; // Upgrade settings export const UPGRADE_MAX_LEVEL = 5; export const UPGRADE_START_COST = 40; export const UPGRADE_COST_SCALE = 1.6; export const UPGRADE_RANGE_SCALE = 1.1; // +10% per level export const UPGRADE_RATE_SCALE = 1.15; // +15% per level export const UPGRADE_DAMAGE_SCALE = 1.12; // +12% per level export const SELL_REFUND_RATE = 0.7; // Infinite wave scaling configuration (replaces static WAVES array) export const WAVE_SCALING = { // base values (wave 1) baseCount: 8, baseHP: 12, baseSpeed: 3.0, baseReward: 5, baseSpawnInterval: 0.8, // per-wave growth (applied from wave 2 onward) countPerWave: 3, // +3 enemies each wave hpMultiplierPerWave: 1.15, // HP *= 1.18 each wave speedIncrementPerWave: 0.025, // +0.05 speed per wave rewardMultiplierPerWave: 1.03, // reward *= 1.03 each wave spawnIntervalDecayPerWave: 0.01, // -0.02s per wave // safeguards/limits minSpawnInterval: 0.3, maxSpeed: 5.5, roundCountToInt: true, }; // Compute wave parameters for a given wave number (1-based) export function getWaveParams(n) { const w = WAVE_SCALING; const waveNum = Math.max(1, Math.floor(n)); const countBase = w.baseCount + (waveNum - 1) * w.countPerWave; const count = w.roundCountToInt ? Math.max(1, Math.round(countBase)) : Math.max(1, countBase); const hp = Math.max( 1, Math.round(w.baseHP * Math.pow(w.hpMultiplierPerWave, waveNum - 1)) ); const speed = Math.min( w.maxSpeed, w.baseSpeed + (waveNum - 1) * w.speedIncrementPerWave ); const reward = Math.max( 1, Math.round(w.baseReward * Math.pow(w.rewardMultiplierPerWave, waveNum - 1)) ); const spawnInterval = Math.max( w.minSpawnInterval, w.baseSpawnInterval - (waveNum - 1) * w.spawnIntervalDecayPerWave ); return { count, hp, speed, reward, spawnInterval }; } // Grid settings export const GROUND_SIZE = 72; // slightly larger to allow wider spacing export const GRID_CELL_SIZE = 2; // Single-path Z-shaped waypoints from top to bottom. // Snakes left↔right across the board with vertical steps. const HALF = GROUND_SIZE / 2; const PATH_MARGIN = 4 * GRID_CELL_SIZE; // 4 squares (8 units) from edges const LEFT_X = -HALF + PATH_MARGIN; const RIGHT_X = HALF - PATH_MARGIN; const MID_Z = 0; // middle of the board // Inset start/end vertical lines a bit further from side edges const EDGE_INSET = 5 * GRID_CELL_SIZE; // 5 cells inward (10 units) const LEFT_X_IN = LEFT_X + EDGE_INSET; const RIGHT_X_IN = RIGHT_X - EDGE_INSET; // Exactly 3 turns: right at top, down at top-right, left at mid, down at mid-left export const PATH_POINTS = [ new THREE.Vector3(RIGHT_X_IN, 0, HALF), // start top-right, straight down (inset) new THREE.Vector3(RIGHT_X_IN, 0, MID_Z), // vertical start segment new THREE.Vector3(LEFT_X_IN, 0, MID_Z), // horizontal across the middle new THREE.Vector3(LEFT_X_IN, 0, -HALF), // vertical to bottom exit (inset) ]; // Disable multi-path branching; keep empty to fallback everywhere to PATH_POINTS export const PATHS = []; // Visual settings export const SCENE_BACKGROUND = 0x202432; // Road settings export const ROAD_HALF_WIDTH = 1.5; export const ROAD_BEVEL_SIZE = 1.2; export const ROAD_ARC_SEGMENTS = 16;