Files
OpenFrontIO/src/core/execution/TradeShipExecution.ts
T
2025-05-14 21:19:50 +02:00

201 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { renderNumber } from "../../client/Utils";
import { consolex } from "../Consolex";
import {
Execution,
Game,
MessageType,
Player,
PlayerID,
Unit,
UnitType,
} from "../game/Game";
import { TileRef } from "../game/GameMap";
import { PathFindResultType } from "../pathfinding/AStar";
import { PathFinder } from "../pathfinding/PathFinding";
import { distSortUnit } from "../Util";
export class TradeShipExecution implements Execution {
private active = true;
private mg: Game;
private origOwner: Player;
private tradeShip: Unit;
private index = 0;
private wasCaptured = false;
constructor(
private _owner: PlayerID,
private srcPort: Unit,
private _dstPort: Unit,
private pathFinder: PathFinder,
) {}
init(mg: Game, ticks: number): void {
this.mg = mg;
this.origOwner = mg.player(this._owner);
}
tick(ticks: number): void {
if (this.tradeShip == null) {
const spawn = this.origOwner.canBuild(
UnitType.TradeShip,
this.srcPort.tile(),
);
if (spawn == false) {
consolex.warn(`cannot build trade ship`);
this.active = false;
return;
}
this.tradeShip = this.origOwner.buildUnit(UnitType.TradeShip, spawn, {
dstPort: this._dstPort,
lastSetSafeFromPirates: ticks,
});
}
if (!this.tradeShip.isActive()) {
this.active = false;
return;
}
if (this.origOwner != this.tradeShip.owner()) {
// Store as variable in case ship is recaptured by previous owner
this.wasCaptured = true;
}
// If a player captures another player's port while trading we should delete
// the ship.
if (this._dstPort.owner().id() == this.srcPort.owner().id()) {
this.tradeShip.delete(false);
this.active = false;
return;
}
if (
!this.wasCaptured &&
(!this._dstPort.isActive() ||
!this.tradeShip.owner().canTrade(this._dstPort.owner()))
) {
this.tradeShip.delete(false);
this.active = false;
return;
}
if (this.wasCaptured) {
const ports = this.tradeShip
.owner()
.units(UnitType.Port)
.sort(distSortUnit(this.mg, this.tradeShip));
if (ports.length == 0) {
this.tradeShip.delete(false);
this.active = false;
return;
} else {
this._dstPort = ports[0];
this.tradeShip.setDstPort(this._dstPort);
}
}
const currentTile = this.tradeShip.tile();
const dstPort = this._dstPort;
// Initialize dstPort.data if it doesn't exist
if (!dstPort.data) {
dstPort.data = {};
}
// Check the reverse path cache
if (dstPort.data.pathCache) {
const key = `${this.mg.x(currentTile)},${this.mg.y(currentTile)}`;
const cachedNextTile = dstPort.data.pathCache.get(key);
if (cachedNextTile) {
// Use cached direction, skip pathfinding
if (this.mg.isWater(cachedNextTile) && manages potential map changes
this.mg.isShoreline(cachedNextTile)
) {
this.tradeShip.setSafeFromPirates();
}
this.tradeShip.move(cachedNextTile);
return;
}
}
// Fallback to pathfinder if no cache entry
const result = this.pathFinder.nextTile(currentTile, dstPort.tile());
switch (result.type) {
case PathFindResultType.Completed:
this.complete();
break;
case PathFindResultType.Pending:
// Fire unit event to rerender.
this.tradeShip.move(this.tradeShip.tile());
break;
case PathFindResultType.NextTile:
// Initialize pathCache if it doesnt exist
if (!dstPort.data.pathCache) {
dstPort.data.pathCache = new Map<string, TileRef>();
}
// Update cache with the new direction
const key = `${this.mg.x(currentTile)},${this.mg.y(currentTile)}`;
dstPort.data.pathCache.set(key, result.tile);
// Update safeFromPirates status
if (this.mg.isWater(result.tile) && this.mg.isShoreline(result.tile)) {
this.tradeShip.setSafeFromPirates();
}
this.tradeShip.move(result.tile);
break;
case PathFindResultType.PathNotFound:
consolex.warn("captured trade ship cannot find route");
if (this.tradeShip.isActive()) {
this.tradeShip.delete(false);
}
this.active = false;
break;
}
}
private complete() {
this.active = false;
this.tradeShip.delete(false);
const gold = this.mg
.config()
.tradeShipGold(
this.mg.manhattanDist(this.srcPort.tile(), this._dstPort.tile()),
);
if (this.wasCaptured) {
this.tradeShip.owner().addGold(gold);
this.mg.displayMessage(
`Received ${renderNumber(gold)} gold from ship captured from ${this.origOwner.display Uname()}`,
MessageType.SUCCESS,
this.tradeShip.owner().id(),
);
} else {
this.srcPort.owner().addGold(gold);
this._dstPort.owner().addGold(gold);
this.mg.displayMessage(
`Received ${renderNumber(gold)} gold from trade with ${this.srcPort.owner().displayName()}`,
MessageType.SUCCESS,
this._dstPort.owner().id(),
);
this.mg.displayMessage(
`Received ${renderNumber(gold)} gold from trade with ${this._dstPort.owner().displayName()}`,
MessageType.SUCCESS,
this.srcPort.owner().id(),
);
}
return;
}
isActive(): boolean {
return this.active;
}
activeDuringSpawnPhase(): boolean {
return false;
}
dstPort(): TileRef {
return this._dstPort.tile();
}
}