first commit

This commit is contained in:
jakciehan
2026-04-10 22:59:39 +08:00
commit cc2e7b9bb0
89 changed files with 23631 additions and 0 deletions
+525
View File
@@ -0,0 +1,525 @@
/**
* 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 416),
* with additional terrain on the flanks (cols 03 and cols 1720).
*
* 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 };