/** * LevelData.js * Predefined level map configurations. * Each level is a 13×21 grid (rows × cols). Values correspond to TERRAIN enum: * 0=EMPTY, 1=BRICK, 2=STEEL, 3=RIVER, 4=FOREST, 5=BASE, 6=BASE_WALL * * In landscape mode the map is 13 rows × 21 cols. * The original 13×13 design sits in the center (cols 4–16), * with additional terrain on the flanks (cols 0–3 and cols 17–20). * * Player spawns at bottom area, enemies spawn from top row. * Base (5) is at bottom-center, surrounded by BASE_WALL (6). */ const LEVELS = [ // ============================================================ // Level 1 - Tutorial: open terrain, few bricks // ============================================================ { id: 1, name: 'Tutorial I', grid: [ //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,0], [0,0,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0,0], [0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0], [0,0,0,0,0,0,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0], [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0], [0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0], [0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0], [0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0], [0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0], [0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,5,6,6,0,0,0,0,0,0,0,0], ], enemies: { total: 20, composition: { normal: 18, fast: 2, armor: 0, boss: 0 }, }, speedMultiplier: 0.6, spawnPoints: [ { col: 0, row: 0 }, { col: 10, row: 0 }, { col: 20, row: 0 }, ], playerSpawn: { col: 8, row: 10 }, }, // ============================================================ // Level 2 - Tutorial II: more bricks, simple layout // ============================================================ { id: 2, name: 'Tutorial II', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,0,0,0,1,1,0,1,1,0,1,1,0,1,1,0,0,0,1,0], [0,0,0,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,0,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0], [0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0], [0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0], [0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0], [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,5,6,6,0,0,0,0,0,0,0,0], ], enemies: { total: 20, composition: { normal: 16, fast: 4, armor: 0, boss: 0 }, }, spawnPoints: [ { col: 0, row: 0 }, { col: 10, row: 0 }, { col: 20, row: 0 }, ], playerSpawn: { col: 8, row: 10 }, }, // ============================================================ // Level 3 - Tutorial III: denser bricks, introduce forest // ============================================================ { id: 3, name: 'Tutorial III', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,4,0,0,0,1,0,4,0,1,0,1,0,4,0,1,0,0,0,4,0], [0,4,0,1,0,1,0,4,0,1,0,1,0,4,0,1,0,1,0,4,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,0,0,1,1,0,1,0,4,0,1,0,1,1,0,0,1,0,0], [0,0,0,0,0,0,0,0,1,0,4,0,1,0,0,0,0,0,0,0,0], [0,1,0,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,0,1,0], [0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0], [0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0], [0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0], [0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,5,6,6,0,0,0,0,0,0,0,0], ], enemies: { total: 20, composition: { normal: 14, fast: 6, armor: 0, boss: 0 }, }, spawnPoints: [ { col: 0, row: 0 }, { col: 10, row: 0 }, { col: 20, row: 0 }, ], playerSpawn: { col: 8, row: 10 }, }, // ============================================================ // Level 4 - Steel Fortress: steel walls appear // ============================================================ { id: 4, name: 'Steel Fortress', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,2,0,0,1,2,0,1,1,0,1,1,0,2,1,0,0,2,0,0], [0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0], [0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0], [0,0,0,0,2,0,0,1,0,2,0,2,0,1,0,0,2,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,2,0,0,0,1,1,0,2,1,0,1,2,0,1,1,0,0,0,2,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0], [0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0], [0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0], [0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,5,6,6,0,0,0,0,0,0,0,0], ], enemies: { total: 20, composition: { normal: 12, fast: 5, armor: 3, boss: 0 }, }, spawnPoints: [ { col: 0, row: 0 }, { col: 10, row: 0 }, { col: 20, row: 0 }, ], playerSpawn: { col: 8, row: 10 }, }, // ============================================================ // Level 5 - River Crossing: introduces water terrain // ============================================================ { id: 5, name: 'River Crossing', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0], [0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0], [0,1,0,0,0,0,0,3,3,0,1,0,3,3,0,0,0,0,0,1,0], [0,0,0,1,0,1,0,3,3,0,0,0,3,3,0,1,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,0,0,1,0,1,0,3,1,0,1,3,0,1,0,1,0,0,1,0], [0,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0], [0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0], [0,1,0,0,0,1,0,1,0,1,1,1,0,1,0,1,0,0,0,1,0], [0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,5,6,6,0,0,0,0,0,0,0,0], ], enemies: { total: 20, composition: { normal: 10, fast: 6, armor: 4, boss: 0 }, }, spawnPoints: [ { col: 0, row: 0 }, { col: 10, row: 0 }, { col: 20, row: 0 }, ], playerSpawn: { col: 8, row: 10 }, }, // ============================================================ // Level 10 - Iron Wall: lots of armored enemies // ============================================================ { id: 10, name: 'Iron Wall', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,2,0,0,0,2,1,0,2,1,0,1,2,0,1,2,0,0,0,2,0], [0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,0,0,1,2,0,1,3,3,0,3,3,1,0,2,1,0,0,1,0], [0,0,0,0,0,0,0,1,3,3,0,3,3,1,0,0,0,0,0,0,0], [0,0,2,0,0,1,0,0,0,2,0,2,0,0,0,1,0,0,2,0,0], [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], [0,1,0,1,0,0,0,2,0,1,4,1,0,2,0,0,0,1,0,1,0], [0,0,0,0,0,1,0,0,0,1,4,1,0,0,0,1,0,0,0,0,0], [0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0], [0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,5,6,6,0,0,0,0,0,0,0,0], ], enemies: { total: 20, composition: { normal: 6, fast: 4, armor: 10, boss: 0 }, }, spawnPoints: [ { col: 0, row: 0 }, { col: 10, row: 0 }, { col: 20, row: 0 }, ], playerSpawn: { col: 8, row: 10 }, }, // ============================================================ // Level 20 - Boss Battle: giant tank encounter // ============================================================ { id: 20, name: 'Boss Battle', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,0,0,1,2,0,1,2,0,2,1,0,2,1,0,0,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,2,0,0,2,0,0,2,3,0,0,0,3,2,0,0,2,0,0,2,0], [0,0,0,0,0,0,0,0,3,0,4,0,3,0,0,0,0,0,0,0,0], [0,0,1,0,0,1,2,0,0,0,4,0,0,0,2,1,0,0,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,0,0,0,2,0,1,0,2,0,2,0,1,0,2,0,0,0,1,0], [0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,6,6,5,6,6,0,0,0,0,0,0,0,0], ], enemies: { total: 20, composition: { normal: 8, fast: 4, armor: 6, boss: 2 }, }, spawnPoints: [ { col: 0, row: 0 }, { col: 10, row: 0 }, { col: 20, row: 0 }, ], playerSpawn: { col: 8, row: 10 }, }, ]; /** * Get level data by level number. * If the level doesn't exist, generate one based on the closest template * with increased difficulty. * @param {number} levelNum * @returns {object} Level data */ function getLevelData(levelNum) { // Direct match const exact = LEVELS.find((l) => l.id === levelNum); if (exact) return JSON.parse(JSON.stringify(exact)); // Find the closest template (highest id <= levelNum) let template = LEVELS[0]; for (const l of LEVELS) { if (l.id <= levelNum && l.id > template.id) { template = l; } } // Clone and adjust difficulty const data = JSON.parse(JSON.stringify(template)); data.id = levelNum; data.name = `Level ${levelNum}`; // Scale enemy composition based on level const cycle = Math.floor((levelNum - 1) / 20); // difficulty cycle const extra = cycle * 2; data.enemies.composition.armor = Math.min( data.enemies.total, data.enemies.composition.armor + extra ); data.enemies.composition.fast = Math.min( data.enemies.total - data.enemies.composition.armor, data.enemies.composition.fast + cycle ); data.enemies.composition.normal = Math.max( 0, data.enemies.total - data.enemies.composition.armor - data.enemies.composition.fast - data.enemies.composition.boss ); return data; } // ============================================================ // PVP Maps - Symmetric layouts with bases for 1v1 base-destruction mode // Each player has a base (TERRAIN.BASE=5) surrounded by BASE_WALL (6) // Player 1 base on left, Player 2 base on right // ============================================================ const PVP_MAPS = [ { id: 1, name: 'Arena I', grid: [ //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0], [0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0], [0,6,5,6,1,0,1,0,2,0,0,0,2,0,1,0,1,6,5,6,0], [0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0], [0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], ], teamABase: [{ col: 2, row: 6 }], teamBBase: [{ col: 18, row: 6 }], teamASpawns: [{ col: 1, row: 5 }], teamBSpawns: [{ col: 19, row: 7 }], }, { id: 2, name: 'Arena II', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,2,1,0,0,0,1,2,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,4,0,0,1,0,0,0,0,0,0,0], [0,6,6,0,0,1,0,0,0,1,4,1,0,0,0,1,0,0,6,6,0], [0,6,5,6,0,0,0,0,4,4,0,4,4,0,0,0,0,6,5,6,0], [0,6,6,0,0,1,0,0,0,1,4,1,0,0,0,1,0,0,6,6,0], [0,0,0,0,0,0,0,1,0,0,4,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,2,1,0,0,0,1,2,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], ], teamABase: [{ col: 2, row: 6 }], teamBBase: [{ col: 18, row: 6 }], teamASpawns: [{ col: 0, row: 6 }], teamBSpawns: [{ col: 20, row: 6 }], }, { id: 3, name: 'Arena III', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,0,0,2,0,0,0,0,0,2,0,0,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,3,0,0,0,3,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,0], [0,6,6,1,0,2,0,0,0,0,0,0,0,0,0,2,0,1,6,6,0], [0,6,5,6,0,0,0,1,0,4,4,4,0,1,0,0,0,6,5,6,0], [0,6,6,1,0,2,0,0,0,0,0,0,0,0,0,2,0,1,6,6,0], [0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,3,0,0,0,3,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,0,0,2,0,0,0,0,0,2,0,0,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], ], teamABase: [{ col: 2, row: 6 }], teamBBase: [{ col: 18, row: 6 }], teamASpawns: [{ col: 1, row: 5 }], teamBSpawns: [{ col: 19, row: 7 }], }, ]; /** * Get a PVP map by id, or deterministically by roomId seed. * When no mapId is given, uses roomId to pick the same map on both clients. * Falls back to random only when neither mapId nor roomId is provided. * @param {number} [mapId] - Explicit map id * @param {string} [roomId] - Room id used as seed for deterministic selection * @returns {object} PVP map data (deep clone). */ function getPvpMap(mapId, roomId) { let map; if (mapId) { map = PVP_MAPS.find((m) => m.id === mapId); } if (!map && roomId) { // Deterministic selection based on roomId so both clients pick the same map let hash = 0; for (let i = 0; i < roomId.length; i++) { hash = ((hash << 5) - hash + roomId.charCodeAt(i)) | 0; } const index = Math.abs(hash) % PVP_MAPS.length; map = PVP_MAPS[index]; } if (!map) { map = PVP_MAPS[Math.floor(Math.random() * PVP_MAPS.length)]; } return JSON.parse(JSON.stringify(map)); } // ============================================================ // 3v3 Team Maps - Symmetric layouts with bases on both ends // Each team has a base (TERRAIN.BASE=5) surrounded by BASE_WALL (6) // Left team base at left end, right team base at right end // Center area is the contested zone // ============================================================ const TEAM_MAPS = [ { id: 1, name: 'Battlefield I', grid: [ //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0], [0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,1,0,0,1,0,2,0,2,0,1,0,0,1,0,0,0,0], [0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0], [0,6,5,6,0,2,0,0,3,3,0,3,3,0,0,2,0,6,5,6,0], [0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0], [0,0,0,0,1,0,0,1,0,2,0,2,0,1,0,0,1,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], ], // Each team has exactly 1 base, centered vertically on their side teamABase: [{ col: 2, row: 6 }], teamBBase: [{ col: 18, row: 6 }], // Spawn points for Team A (left side, near base) teamASpawns: [ { col: 1, row: 5 }, { col: 0, row: 6 }, { col: 1, row: 7 }, ], // Spawn points for Team B (right side, near base) teamBSpawns: [ { col: 19, row: 5 }, { col: 20, row: 6 }, { col: 19, row: 7 }, ], }, { id: 2, name: 'Battlefield II', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,0,4,0,4,0,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,4,0,4,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,2,0,1,0,1,0,2,0,0,0,0,0,0,0], [0,6,6,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,6,6,0], [0,6,5,6,1,0,2,0,0,0,3,0,0,0,2,0,1,6,5,6,0], [0,6,6,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,6,6,0], [0,0,0,0,0,0,0,2,0,1,0,1,0,2,0,0,0,0,0,0,0], [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,4,0,4,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,0,4,0,4,0,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], ], teamABase: [{ col: 2, row: 6 }], teamBBase: [{ col: 18, row: 6 }], teamASpawns: [ { col: 1, row: 5 }, { col: 0, row: 6 }, { col: 1, row: 7 }, ], teamBSpawns: [ { col: 19, row: 5 }, { col: 20, row: 6 }, { col: 19, row: 7 }, ], }, { id: 3, name: 'Battlefield III', grid: [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,0,0,2,0,0,0,0,0,2,0,0,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,3,0,0,0,3,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,0], [0,6,6,1,0,2,0,0,0,0,0,0,0,0,0,2,0,1,6,6,0], [0,6,5,6,0,0,0,1,0,4,4,4,0,1,0,0,0,6,5,6,0], [0,6,6,1,0,2,0,0,0,0,0,0,0,0,0,2,0,1,6,6,0], [0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,0,3,0,0,0,3,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,0,0,2,0,0,0,0,0,2,0,0,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], ], teamABase: [{ col: 2, row: 6 }], teamBBase: [{ col: 18, row: 6 }], teamASpawns: [ { col: 1, row: 5 }, { col: 0, row: 6 }, { col: 1, row: 7 }, ], teamBSpawns: [ { col: 19, row: 5 }, { col: 20, row: 6 }, { col: 19, row: 7 }, ], }, ]; /** * Get a 3v3 team map by id or random. * @param {number} [mapId] - Optional map id * @returns {object} Team map data (deep clone). */ function getTeamMap(mapId) { let map; if (mapId) { map = TEAM_MAPS.find((m) => m.id === mapId); } if (!map) { map = TEAM_MAPS[Math.floor(Math.random() * TEAM_MAPS.length)]; } return JSON.parse(JSON.stringify(map)); } module.exports = { LEVELS, getLevelData, PVP_MAPS, getPvpMap, TEAM_MAPS, getTeamMap };