Refactor territory defense management in GameImpl and CanvasTerritoryRenderer

- Consolidated defended state logic for tiles into dedicated methods in GameImpl to improve clarity and maintainability.
- Updated CanvasTerritoryRenderer to utilize the new isDefended method for determining tile defense status.
- Removed redundant checks and streamlined the painting logic for territory tiles.
This commit is contained in:
scamiv
2025-12-11 18:01:16 +01:00
parent 9ed794264d
commit 3f4d629ffb
2 changed files with 75 additions and 34 deletions
+73
View File
@@ -532,6 +532,10 @@ export class GameImpl implements Game {
owner._lastTileChange = this._ticks;
this.updateBorders(tile);
this._map.setFallout(tile, false);
// Update defended state for the conquered tile and nearby border tiles
this.updateDefendedStateForTileChange(tile, owner);
this.addUpdate({
type: GameUpdateType.Tile,
update: this.toTileUpdate(tile),
@@ -553,6 +557,9 @@ export class GameImpl implements Game {
this._map.setOwnerID(tile, 0);
this.updateBorders(tile);
if (this._map.isDefended(tile)) {
this._map.setDefended(tile, false);
}
this.addUpdate({
type: GameUpdateType.Tile,
update: this.toTileUpdate(tile),
@@ -752,14 +759,23 @@ export class GameImpl implements Game {
addUnit(u: Unit) {
this.unitGrid.addUnit(u);
if (u.type() === UnitType.DefensePost) {
this.updateDefendedStateForDefensePost(u.tile(), u.owner() as PlayerImpl);
}
}
removeUnit(u: Unit) {
if (u.type() === UnitType.DefensePost) {
this.updateDefendedStateForDefensePost(u.tile(), u.owner() as PlayerImpl);
}
this.unitGrid.removeUnit(u);
if (u.hasTrainStation()) {
this._railNetwork.removeStation(u);
}
}
updateUnitTile(u: Unit) {
if (u.type() === UnitType.DefensePost) {
this.updateDefendedStateForDefensePost(u.tile(), u.owner() as PlayerImpl);
}
this.unitGrid.updateUnitCell(u);
}
@@ -955,6 +971,63 @@ export class GameImpl implements Game {
// Record stats
this.stats().goldWar(conqueror, conquered, gold);
}
/**
* Update defended state for border tiles within range of a defense post.
*/
private updateDefendedStateForDefensePost(
center: TileRef,
owner: PlayerImpl,
) {
const range = this.config().defensePostRange();
const rangeSq = range * range;
for (const tile of owner._borderTiles) {
if (this._map.euclideanDistSquared(center, tile) <= rangeSq) {
const wasDefended = this._map.isDefended(tile);
const isDefended = this.unitGrid.hasUnitNearby(
tile,
range,
UnitType.DefensePost,
owner.id(),
);
if (wasDefended !== isDefended) {
this._map.setDefended(tile, isDefended);
this.addUpdate({
type: GameUpdateType.Tile,
update: this.toTileUpdate(tile),
});
}
}
}
}
/**
* Update defended state when a tile changes ownership.
*/
private updateDefendedStateForTileChange(tile: TileRef, owner: PlayerImpl) {
const wasDefended = this._map.isDefended(tile);
const isDefended = this.unitGrid.hasUnitNearby(
tile,
this.config().defensePostRange(),
UnitType.DefensePost,
owner.id(),
);
if (wasDefended !== isDefended) {
this._map.setDefended(tile, isDefended);
this.addUpdate({
type: GameUpdateType.Tile,
update: this.toTileUpdate(tile),
});
}
// If the conquered tile has a defense post, update nearby border tiles
if (
this.unitGrid.hasUnitNearby(tile, 0, UnitType.DefensePost, owner.id())
) {
this.updateDefendedStateForDefensePost(tile, owner);
}
}
}
// Or a more dynamic approach that will catch new enum values: