95 lines
3.0 KiB
JavaScript
95 lines
3.0 KiB
JavaScript
// Fog of war and the grid walkers. Explored cells stay known; visible cells
|
|
// are the ones currently watched by territory and units.
|
|
|
|
import { key } from "../hex.js";
|
|
import { UNIT_VISION, TERRITORY_VISION } from "./constants.js";
|
|
import { serializeSet } from "./helpers.js";
|
|
|
|
export const visibilityMethods = {
|
|
isExplored(civ, coords) {
|
|
const set = this.explored.get(civ);
|
|
return set ? set.has(key(coords.x, coords.y)) : false;
|
|
},
|
|
|
|
isVisible(civ, coords) {
|
|
const set = this.visible.get(civ);
|
|
return set ? set.has(key(coords.x, coords.y)) : false;
|
|
},
|
|
|
|
canEnter(civ, proto, coords) {
|
|
if (!proto || !this.isExplored(civ, coords)) return false;
|
|
const tile = this.tiles[key(coords.x, coords.y)];
|
|
if (!tile) return false;
|
|
return proto.traversableTerrains.includes(tile.terrainClass);
|
|
},
|
|
|
|
_refreshVisibility() {
|
|
this.visible = new Map();
|
|
for (let i = 0; i < this.civilisations.length; i++) this.visible.set(i, new Set());
|
|
for (const [civ, cells] of this._territoryByCiv) {
|
|
for (const coords of cells) this._reveal(civ, coords, TERRITORY_VISION);
|
|
}
|
|
for (const unit of this.units) {
|
|
this._reveal(unit.civ, unit.coords, UNIT_VISION);
|
|
}
|
|
},
|
|
|
|
_revealAll() {
|
|
for (let i = 0; i < this.civilisations.length; i++) {
|
|
this.explored.set(i, new Set(Object.keys(this.tiles)));
|
|
}
|
|
},
|
|
|
|
_reveal(civ, center, radius) {
|
|
if (!this.explored.has(civ)) this.explored.set(civ, new Set());
|
|
if (!this.visible.has(civ)) this.visible.set(civ, new Set());
|
|
const exploredCells = this.explored.get(civ);
|
|
const visibleCells = this.visible.get(civ);
|
|
let discovered = false;
|
|
for (const coords of this._cellsInRadius(center, radius)) {
|
|
const k = key(coords.x, coords.y);
|
|
if (!exploredCells.has(k)) {
|
|
exploredCells.add(k);
|
|
discovered = true;
|
|
}
|
|
visibleCells.add(k);
|
|
}
|
|
if (discovered) this._serializedExplored.delete(civ);
|
|
},
|
|
|
|
_cachedExplored(civ) {
|
|
if (!this._serializedExplored.has(civ)) {
|
|
this._serializedExplored.set(civ, serializeSet(this.explored.get(civ) || new Set()));
|
|
}
|
|
return this._serializedExplored.get(civ);
|
|
},
|
|
|
|
_cellsInRadius(center, radius) {
|
|
const result = [center];
|
|
const visited = new Set([key(center.x, center.y)]);
|
|
let frontier = [center];
|
|
for (let step = 0; step < radius; step++) {
|
|
const next = [];
|
|
for (const coords of frontier) {
|
|
for (const neighbour of this._neighbours(coords)) {
|
|
const k = key(neighbour.x, neighbour.y);
|
|
if (visited.has(k)) continue;
|
|
visited.add(k);
|
|
next.push(neighbour);
|
|
result.push(neighbour);
|
|
}
|
|
}
|
|
frontier = next;
|
|
}
|
|
return result;
|
|
},
|
|
|
|
_neighbours(coords) {
|
|
const k = key(coords.x, coords.y);
|
|
if (this._neighbourCache.has(k)) return this._neighbourCache.get(k);
|
|
const result = this.topology.neighbours(coords.x, coords.y);
|
|
this._neighbourCache.set(k, result);
|
|
return result;
|
|
},
|
|
};
|