Files
OpenFrontIO/src/core/execution/ConstructionExecution.ts
T
evanpelle d35d0f38cb refactor & update warships (#796)
## Description:
1. Refactor WarshipExecution so that it takes either attrs or a warship
unit. This makes testing much simpler as the unit test can construct a
warship and then pass it into a warship execution
2. Have MoveWarshipExecution set the patrol tile, not the move tile so
warships stay in new location instead of moving back to original
location.
3. Warships no longer target trade ships outside of its patrol range.
this prevents warships from wandering
4. Refactored & simplified WarshipExecution
5. Added more tests for warships
6. Move health modification from PlayerExecution to WarshipExecution
since Warships are the only unit that have health
7. Move fields from WarshipExecution to the Warship unit itself, this
allows other executions & components to see more data about the warship.



## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

## Please put your Discord username so you can be contacted if a bug or
regression is found:

<DISCORD USERNAME>
2025-05-24 13:42:56 -07:00

139 lines
4.0 KiB
TypeScript

import { consolex } from "../Consolex";
import {
Execution,
Game,
Player,
PlayerID,
Tick,
Unit,
UnitType,
} from "../game/Game";
import { TileRef } from "../game/GameMap";
import { CityExecution } from "./CityExecution";
import { DefensePostExecution } from "./DefensePostExecution";
import { MirvExecution } from "./MIRVExecution";
import { MissileSiloExecution } from "./MissileSiloExecution";
import { NukeExecution } from "./NukeExecution";
import { PortExecution } from "./PortExecution";
import { SAMLauncherExecution } from "./SAMLauncherExecution";
import { WarshipExecution } from "./WarshipExecution";
export class ConstructionExecution implements Execution {
private player: Player;
private construction: Unit | null = null;
private active: boolean = true;
private mg: Game;
private ticksUntilComplete: Tick;
private cost: number;
constructor(
private ownerId: PlayerID,
private tile: TileRef,
private constructionType: UnitType,
) {}
init(mg: Game, ticks: number): void {
this.mg = mg;
if (!mg.hasPlayer(this.ownerId)) {
console.warn(`ConstructionExecution: owner ${this.ownerId} not found`);
this.active = false;
return;
}
this.player = mg.player(this.ownerId);
}
tick(ticks: number): void {
if (this.construction === null) {
const info = this.mg.unitInfo(this.constructionType);
if (info.constructionDuration === undefined) {
this.completeConstruction();
this.active = false;
return;
}
const spawnTile = this.player.canBuild(this.constructionType, this.tile);
if (spawnTile === false) {
consolex.warn(`cannot build ${this.constructionType}`);
this.active = false;
return;
}
this.construction = this.player.buildUnit(
UnitType.Construction,
spawnTile,
{},
);
this.cost = this.mg.unitInfo(this.constructionType).cost(this.player);
this.player.removeGold(this.cost);
this.construction.setConstructionType(this.constructionType);
this.ticksUntilComplete = info.constructionDuration;
return;
}
if (!this.construction.isActive()) {
this.active = false;
return;
}
if (this.player !== this.construction.owner()) {
this.player = this.construction.owner();
}
if (this.ticksUntilComplete === 0) {
this.player = this.construction.owner();
this.construction.delete(false);
// refund the cost so player has the gold to build the unit
this.player.addGold(this.cost);
this.completeConstruction();
this.active = false;
return;
}
this.ticksUntilComplete--;
}
private completeConstruction() {
const player = this.player;
switch (this.constructionType) {
case UnitType.AtomBomb:
case UnitType.HydrogenBomb:
this.mg.addExecution(
new NukeExecution(this.constructionType, player.id(), this.tile),
);
break;
case UnitType.MIRV:
this.mg.addExecution(new MirvExecution(player.id(), this.tile));
break;
case UnitType.Warship:
this.mg.addExecution(
new WarshipExecution({ owner: player, patrolTile: this.tile }),
);
break;
case UnitType.Port:
this.mg.addExecution(new PortExecution(player.id(), this.tile));
break;
case UnitType.MissileSilo:
this.mg.addExecution(new MissileSiloExecution(player.id(), this.tile));
break;
case UnitType.DefensePost:
this.mg.addExecution(new DefensePostExecution(player.id(), this.tile));
break;
case UnitType.SAMLauncher:
this.mg.addExecution(new SAMLauncherExecution(player.id(), this.tile));
break;
case UnitType.City:
this.mg.addExecution(new CityExecution(player.id(), this.tile));
break;
default:
throw Error(`unit type ${this.constructionType} not supported`);
}
}
isActive(): boolean {
return this.active;
}
activeDuringSpawnPhase(): boolean {
return false;
}
}