first commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
// BattlePassData - DEPRECATED (removed in monetization-lite)
|
||||
module.exports = {};
|
||||
@@ -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 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 };
|
||||
@@ -0,0 +1,2 @@
|
||||
// SkinData - DEPRECATED (removed in monetization-lite)
|
||||
module.exports = {};
|
||||
Reference in New Issue
Block a user