Spaces:
Running
Running
| 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; | |