migrate from perforce
This commit is contained in:
262
dist/Simulation/Models/SimLevel.js
vendored
Normal file
262
dist/Simulation/Models/SimLevel.js
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
import { Hex, PathFinding } from "../../Util/index.js";
|
||||
import { ECellType, SimCell } from "../index.js";
|
||||
export class SimLevel {
|
||||
static version = 2;
|
||||
_paused = true;
|
||||
_currentStep = -1;
|
||||
_gdLevel;
|
||||
_highlightedIndex = -1;
|
||||
_currency = -1;
|
||||
_stride = -1;
|
||||
_simCells;
|
||||
_simEnemies;
|
||||
_simProjectiles;
|
||||
_nextWaveStep = -1;
|
||||
_lastEnemySpawnStep = 0;
|
||||
_currentWave;
|
||||
_enemiesLeftToSpawn;
|
||||
_levelIdx;
|
||||
_gdRoot;
|
||||
constructor(gdRoot, levelIdx) {
|
||||
this._levelIdx = levelIdx;
|
||||
this._gdRoot = gdRoot;
|
||||
this._gdLevel = gdRoot.levels[levelIdx];
|
||||
this._simCells = [];
|
||||
this._simEnemies = [];
|
||||
this._simProjectiles = [];
|
||||
this._currentStep = 0;
|
||||
this._currency = this._gdLevel.currency;
|
||||
this._currentWave = 0;
|
||||
this._enemiesLeftToSpawn = this._gdLevel.waves[0].amount;
|
||||
const radius = this._gdLevel.radius;
|
||||
this._stride = 2 * radius + 1;
|
||||
const h0 = new Hex(0, 0);
|
||||
for (let y = -radius; y <= radius; ++y) {
|
||||
for (let x = -radius; x <= radius; ++x) {
|
||||
const hex = new Hex(x, y);
|
||||
const distance = Hex.distance(hex, h0);
|
||||
const type = distance >= radius ? ECellType.Blocked : ECellType.Free;
|
||||
const cellIndex = this.getCellIndex(hex);
|
||||
this._simCells[cellIndex] = new SimCell(hex, distance, type, cellIndex);
|
||||
}
|
||||
}
|
||||
this._gdLevel.walls.forEach((wall) => {
|
||||
const cellIndex = this.getCellIndex(wall);
|
||||
this._simCells[cellIndex].type = ECellType.Blocked;
|
||||
});
|
||||
this._gdLevel.enemySpawns.forEach((hex) => {
|
||||
const cellIndex = this.getCellIndex(hex);
|
||||
this._simCells[cellIndex].type = ECellType.Entry;
|
||||
});
|
||||
this._gdLevel.enemyTargets.forEach((hex) => {
|
||||
const cellIndex = this.getCellIndex(hex);
|
||||
this._simCells[cellIndex].type = ECellType.Entry;
|
||||
});
|
||||
this._simCells.forEach((cell) => {
|
||||
this.updateBlockedType(cell);
|
||||
});
|
||||
this.updatePaths();
|
||||
}
|
||||
;
|
||||
get gdLevel() {
|
||||
return this._gdLevel;
|
||||
}
|
||||
get simCells() {
|
||||
return this._simCells;
|
||||
}
|
||||
get simEnemies() {
|
||||
return this._simEnemies;
|
||||
}
|
||||
get simProjectiles() {
|
||||
return this._simProjectiles;
|
||||
}
|
||||
get currentStep() {
|
||||
return this._currentStep;
|
||||
}
|
||||
set currentStep(value) {
|
||||
this._currentStep = value;
|
||||
}
|
||||
get currency() {
|
||||
return this._currency;
|
||||
}
|
||||
set currency(value) {
|
||||
this._currency = value;
|
||||
}
|
||||
get highlightedIndex() {
|
||||
return this._highlightedIndex;
|
||||
}
|
||||
set highlightedIndex(value) {
|
||||
this._highlightedIndex = value;
|
||||
}
|
||||
get paused() {
|
||||
return this._paused;
|
||||
}
|
||||
set paused(value) {
|
||||
this._paused = value;
|
||||
}
|
||||
get currentWave() {
|
||||
return this._currentWave;
|
||||
}
|
||||
set currentWave(value) {
|
||||
this._currentWave = value;
|
||||
}
|
||||
get nextWaveStep() {
|
||||
return this._nextWaveStep;
|
||||
}
|
||||
set nextWaveStep(value) {
|
||||
this._nextWaveStep = value;
|
||||
}
|
||||
get lastEnemySpawnStep() {
|
||||
return this._lastEnemySpawnStep;
|
||||
}
|
||||
set lastEnemySpawnStep(value) {
|
||||
this._lastEnemySpawnStep = value;
|
||||
}
|
||||
get enemiesLeftToSpawn() {
|
||||
return this._enemiesLeftToSpawn;
|
||||
}
|
||||
set enemiesLeftToSpawn(value) {
|
||||
this._enemiesLeftToSpawn = value;
|
||||
}
|
||||
serialize() {
|
||||
const data = {
|
||||
version: SimLevel.version,
|
||||
levelIdx: this._levelIdx,
|
||||
paused: this._paused,
|
||||
gdLevel: this._gdLevel,
|
||||
currentStep: this._currentStep,
|
||||
highlightedIndex: this._highlightedIndex,
|
||||
currency: this._currency,
|
||||
stride: this._stride,
|
||||
cells: this._simCells,
|
||||
enemies: this._simEnemies,
|
||||
projectiles: this._simProjectiles,
|
||||
nextWaveStep: this._nextWaveStep,
|
||||
lastEnemySpawnStep: this._lastEnemySpawnStep,
|
||||
currentWave: this._currentWave,
|
||||
enemiesLeftToSpawn: this._enemiesLeftToSpawn
|
||||
};
|
||||
return btoa(JSON.stringify(data));
|
||||
}
|
||||
static deserialize(gdRoot, data) {
|
||||
const parsedData = JSON.parse(atob(data));
|
||||
if (parsedData.version != SimLevel.version) {
|
||||
console.warn('Unsupported version:', parsedData.version);
|
||||
return null;
|
||||
}
|
||||
let level = new SimLevel(gdRoot, parsedData.levelIdx);
|
||||
level._paused = parsedData.paused;
|
||||
level._gdLevel = parsedData.gdLevel;
|
||||
level._currentStep = parsedData.currentStep;
|
||||
level._highlightedIndex = parsedData.highlightedIndex;
|
||||
level._currency = parsedData.currency;
|
||||
level._stride = parsedData.stride;
|
||||
level._simCells = parsedData.cells;
|
||||
level._simEnemies = parsedData.enemies;
|
||||
level._simProjectiles = parsedData.projectiles;
|
||||
level._nextWaveStep = parsedData.nextWaveStep;
|
||||
level._lastEnemySpawnStep = parsedData.lastEnemySpawnStep;
|
||||
level._currentWave = parsedData.currentWave;
|
||||
level._enemiesLeftToSpawn = parsedData.enemiesLeftToSpawn;
|
||||
return level;
|
||||
}
|
||||
getCellIndex(hex) {
|
||||
const x = hex.col + this._gdLevel.radius;
|
||||
const y = hex.row + this._gdLevel.radius;
|
||||
if (x < 0 || x >= this._stride || y < 0 || y >= this._stride) {
|
||||
return -1;
|
||||
}
|
||||
return y * this._stride + x;
|
||||
}
|
||||
getNeighbourCell(cell, direction) {
|
||||
const hex = cell.hex;
|
||||
const neighbourHex = Hex.neighbour(hex, direction);
|
||||
const neighbourIndex = this.getCellIndex(neighbourHex);
|
||||
return this._simCells[neighbourIndex];
|
||||
}
|
||||
updateBlockedType(cell) {
|
||||
if (cell.type == ECellType.Free) {
|
||||
cell.blockedType = -1;
|
||||
return;
|
||||
}
|
||||
if (cell.type == ECellType.Entry && cell.blockedType != -1) {
|
||||
return;
|
||||
}
|
||||
let blockedType = 0;
|
||||
for (let direction = 0; direction < 6; ++direction) {
|
||||
const neighbourCell = this.getNeighbourCell(cell, direction);
|
||||
if (!!neighbourCell && neighbourCell.type == ECellType.Free) {
|
||||
blockedType |= 1 << direction;
|
||||
}
|
||||
}
|
||||
cell.blockedType = blockedType;
|
||||
}
|
||||
reservePaths(hexToBlock) {
|
||||
try {
|
||||
if (!!hexToBlock) {
|
||||
const reservedCell = this._simCells[this.getCellIndex(hexToBlock)];
|
||||
if (reservedCell.type != ECellType.Free || !!reservedCell.simTower)
|
||||
return false;
|
||||
reservedCell.type = ECellType.Reserved;
|
||||
}
|
||||
return this.updatePaths();
|
||||
}
|
||||
finally {
|
||||
if (!!hexToBlock) {
|
||||
const reservedCell = this._simCells[this.getCellIndex(hexToBlock)];
|
||||
if (reservedCell.type == ECellType.Reserved)
|
||||
reservedCell.type = ECellType.Free;
|
||||
}
|
||||
}
|
||||
}
|
||||
updatePaths() {
|
||||
const level = this._gdLevel;
|
||||
const newRoutePaths = [];
|
||||
const newEnemyPaths = [];
|
||||
let invalid = false;
|
||||
for (const routeIdx in level.enemyRoutes) {
|
||||
const route = level.enemyRoutes[routeIdx];
|
||||
const enemySpawnHex = level.enemySpawns[route[0]];
|
||||
const enemySpawnCell = this._simCells[this.getCellIndex(enemySpawnHex)];
|
||||
const enemyTargetHex = level.enemyTargets[route[1]];
|
||||
const enemyTargetCell = this._simCells[this.getCellIndex(enemyTargetHex)];
|
||||
const path = PathFinding.bfs(this, enemySpawnCell.index, enemyTargetCell.index);
|
||||
if (path == null) {
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
newRoutePaths[routeIdx] = path;
|
||||
}
|
||||
if (invalid) {
|
||||
return false;
|
||||
}
|
||||
for (let idx in this._simEnemies) {
|
||||
const simEnemy = this._simEnemies[idx];
|
||||
const hex = Hex.fromWorld(simEnemy.position);
|
||||
const startIndex = this.getCellIndex(hex);
|
||||
const endIndex = this.getCellIndex(simEnemy.endHex);
|
||||
const path = PathFinding.bfs(this, startIndex, endIndex);
|
||||
if (path == null) {
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
newEnemyPaths[idx] = path;
|
||||
}
|
||||
if (invalid) {
|
||||
return false;
|
||||
}
|
||||
for (const routeIdx in level.enemyRoutes) {
|
||||
const route = level.enemyRoutes[routeIdx];
|
||||
const enemySpawnHex = level.enemySpawns[route[0]];
|
||||
const enemySpawnCell = this._simCells[this.getCellIndex(enemySpawnHex)];
|
||||
enemySpawnCell.pathsToTarget[routeIdx] = newRoutePaths[routeIdx];
|
||||
}
|
||||
this._simEnemies.forEach((simEnemy, idx) => {
|
||||
simEnemy.path = newEnemyPaths[idx];
|
||||
simEnemy.currentPathIndex = 0;
|
||||
simEnemy.onPathUpdated();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=SimLevel.js.map
|
||||
Reference in New Issue
Block a user