This commit is contained in:
Evan
2025-01-08 20:58:08 -08:00
parent 162b6dc349
commit 459fc50dae
12 changed files with 176 additions and 168 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ import { and, bfs, dist, generateID, manhattanDist } from "../core/Util";
import { SendAttackIntentEvent, SendSpawnIntentEvent, Transport } from "./Transport";
import { createCanvas } from "./Utils";
import { MessageType } from '../core/game/Game';
import { DisplayMessageEvent } from '../core/game/Game';
import { DisplayMessageUpdate } from '../core/game/Game';
import { WorkerClient } from "../core/worker/WorkerClient";
import { consolex, initRemoteSender } from "../core/Consolex";
import { getConfig, getServerConfig } from "../core/configuration/Config";
+5 -3
View File
@@ -30,7 +30,9 @@ export class SendBreakAllianceIntentEvent implements GameEvent {
export class SendAllianceReplyIntentEvent implements GameEvent {
constructor(
public readonly allianceRequest: AllianceRequest,
// The original alliance requestor
public readonly requestor: Player,
public readonly recipient: Player,
public readonly accepted: boolean
) { }
}
@@ -262,8 +264,8 @@ export class Transport {
this.sendIntent({
type: "allianceRequestReply",
clientID: this.lobbyConfig.clientID,
requestor: event.allianceRequest.requestor().id(),
recipient: event.allianceRequest.recipient().id(),
requestor: event.requestor.id(),
recipient: event.recipient.id(),
accept: event.accepted,
})
}
+103 -90
View File
@@ -2,8 +2,13 @@ import { LitElement, html, css } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { EventBus } from "../../../core/EventBus";
import {
AllianceRequestReplyUpdate,
AllianceRequestUpdate,
AllPlayers,
DisplayMessageUpdate,
EmojiUpdate,
MessageType,
TargetPlayerUpdate,
} from "../../../core/game/Game";
import { ClientID } from "../../../core/Schemas";
import { Layer } from "./Layer";
@@ -140,13 +145,6 @@ export class EventsDisplay extends LitElement implements Layer {
}
init() {
this.eventBus.on(AllianceRequestEvent, a => this.onAllianceRequestEvent(a));
this.eventBus.on(AllianceRequestReplyEvent, a => this.onAllianceRequestReplyEvent(a));
this.eventBus.on(DisplayMessageEvent, e => this.onDisplayMessageEvent(e));
this.eventBus.on(BrokeAllianceEvent, e => this.onBrokeAllianceEvent(e));
this.eventBus.on(AllianceExpiredEvent, e => this.onAllianceExpiredEvent(e));
this.eventBus.on(TargetPlayerEvent, e => this.onTargetPlayerEvent(e));
this.eventBus.on(EmojiMessageEvent, e => this.onEmojiMessageEvent(e));
}
tick() {
@@ -186,9 +184,9 @@ export class EventsDisplay extends LitElement implements Layer {
renderLayer(): void { }
onDisplayMessageEvent(event: DisplayMessageEvent) {
onDisplayMessageEvent(event: DisplayMessageUpdate) {
const myPlayer = this.game.playerByClientID(this.clientID);
if (event.playerID != null && (!myPlayer || myPlayer.id() !== event.playerID)) {
if (event.playerID != null && (!myPlayer || myPlayer.smallID() !== event.playerID)) {
return;
}
@@ -196,122 +194,137 @@ export class EventsDisplay extends LitElement implements Layer {
description: event.message,
createdAt: this.game.ticks(),
highlight: true,
type: event.type,
type: event.messageType,
unsafeDescription: true,
});
}
onAllianceRequestEvent(event: AllianceRequestEvent) {
onAllianceRequestEvent(update: AllianceRequestUpdate) {
const myPlayer = this.game.playerByClientID(this.clientID);
if (!myPlayer || event.allianceRequest.recipient() !== myPlayer) {
if (!myPlayer || update.recipientID !== myPlayer.smallID()) {
return;
}
const requestor = this.game.playerBySmallID(update.requestorID)
const recipient = this.game.playerBySmallID(update.recipientID)
this.addEvent({
description: `${event.allianceRequest.requestor().name()} requests an alliance!`,
description: `${requestor.name()} requests an alliance!`,
buttons: [
{
text: "Accept",
className: "btn",
action: () => this.eventBus.emit(new SendAllianceReplyIntentEvent(event.allianceRequest, true)),
action: () => this.eventBus.emit(
new SendAllianceReplyIntentEvent(requestor, recipient, true)
),
},
{
text: "Reject",
className: "btn btn-info",
action: () => this.eventBus.emit(new SendAllianceReplyIntentEvent(event.allianceRequest, false)),
action: () => this.eventBus.emit(
new SendAllianceReplyIntentEvent(requestor, recipient, false)
),
}
],
highlight: true,
type: MessageType.INFO,
createdAt: this.game.ticks(),
onDelete: () => this.eventBus.emit(new SendAllianceReplyIntentEvent(event.allianceRequest, false))
onDelete: () => this.eventBus.emit(
new SendAllianceReplyIntentEvent(requestor, recipient, false)
)
});
}
onAllianceRequestReplyEvent(event: AllianceRequestReplyEvent) {
const myPlayer = this.game.playerByClientID(this.clientID);
if (!myPlayer || event.allianceRequest.requestor() !== myPlayer) {
return;
}
// onAllianceRequestReplyEvent(event: AllianceRequestReplyUpdate) {
// const myPlayer = this.game.playerByClientID(this.clientID);
// if (!myPlayer || event.allianceRequest.requestor() !== myPlayer) {
// return;
// }
this.addEvent({
description: `${event.allianceRequest.recipient().name()} ${event.accepted ? "accepted" : "rejected"} your alliance request`,
type: event.accepted ? MessageType.SUCCESS : MessageType.ERROR,
highlight: true,
createdAt: this.game.ticks(),
});
}
// this.addEvent({
// description: `${event.allianceRequest.recipient().name()} ${event.accepted ? "accepted" : "rejected"} your alliance request`,
// type: event.accepted ? MessageType.SUCCESS : MessageType.ERROR,
// highlight: true,
// createdAt: this.game.ticks(),
// });
// }
onBrokeAllianceEvent(event: BrokeAllianceEvent) {
const myPlayer = this.game.playerByClientID(this.clientID);
if (!myPlayer) return;
// onBrokeAllianceEvent(event: BrokeAllianceEvent) {
// const myPlayer = this.game.playerByClientID(this.clientID);
// if (!myPlayer) return;
if (!event.betrayed.isTraitor() && event.traitor === myPlayer) {
this.addEvent({
description: `You broke your alliance with ${event.betrayed.name()}, making you a TRAITOR`,
type: MessageType.ERROR,
highlight: true,
createdAt: this.game.ticks(),
});
} else if (event.betrayed === myPlayer) {
this.addEvent({
description: `${event.traitor.name()}, broke their alliance with you`,
type: MessageType.ERROR,
highlight: true,
createdAt: this.game.ticks(),
});
}
}
// if (!event.betrayed.isTraitor() && event.traitor === myPlayer) {
// this.addEvent({
// description: `You broke your alliance with ${event.betrayed.name()}, making you a TRAITOR`,
// type: MessageType.ERROR,
// highlight: true,
// createdAt: this.game.ticks(),
// });
// } else if (event.betrayed === myPlayer) {
// this.addEvent({
// description: `${event.traitor.name()}, broke their alliance with you`,
// type: MessageType.ERROR,
// highlight: true,
// createdAt: this.game.ticks(),
// });
// }
// }
onAllianceExpiredEvent(event: AllianceExpiredEvent) {
const myPlayer = this.game.playerByClientID(this.clientID);
if (!myPlayer) return;
// onAllianceExpiredEvent(event: AllianceExpiredEvent) {
// const myPlayer = this.game.playerByClientID(this.clientID);
// if (!myPlayer) return;
const other = event.player1 === myPlayer ? event.player2 : event.player2 === myPlayer ? event.player1 : null;
if (!other || !myPlayer.isAlive() || !other.isAlive()) return;
// const other = event.player1 === myPlayer ? event.player2 : event.player2 === myPlayer ? event.player1 : null;
// if (!other || !myPlayer.isAlive() || !other.isAlive()) return;
this.addEvent({
description: `Your alliance with ${other.name()} expired`,
type: MessageType.WARN,
highlight: true,
createdAt: this.game.ticks(),
});
}
// this.addEvent({
// description: `Your alliance with ${other.name()} expired`,
// type: MessageType.WARN,
// highlight: true,
// createdAt: this.game.ticks(),
// });
// }
onTargetPlayerEvent(event: TargetPlayerEvent) {
const myPlayer = this.game.playerByClientID(this.clientID);
if (!myPlayer || !myPlayer.isAlliedWith(event.player)) return;
// onTargetPlayerEvent(event: TargetPlayerUpdate) {
// const other = this.game.playerBySmallID(event.playerID)
// const myPlayer = this.game.playerByClientID(this.clientID);
// if (!myPlayer || !myPlayer.isAlliedWith(other)) return;
this.addEvent({
description: `${event.player.name()} requests you attack ${event.target.name()}`,
type: MessageType.INFO,
highlight: true,
createdAt: this.game.ticks(),
});
}
// const target = this.game.playerBySmallID(event.targetID)
onEmojiMessageEvent(event: EmojiMessageEvent) {
const myPlayer = this.game.playerByClientID(this.clientID);
if (!myPlayer) return;
// this.addEvent({
// description: `${other.name()} requests you attack ${target.name()}`,
// type: MessageType.INFO,
// highlight: true,
// createdAt: this.game.ticks(),
// });
// }
if (event.message.recipient === myPlayer) {
this.addEvent({
description: `${event.message.sender.displayName()}:${event.message.emoji}`,
unsafeDescription: true,
type: MessageType.INFO,
highlight: true,
createdAt: this.game.ticks(),
});
} else if (event.message.sender === myPlayer && event.message.recipient !== AllPlayers) {
this.addEvent({
description: `Sent ${event.message.recipient.displayName()}: ${event.message.emoji}`,
unsafeDescription: true,
type: MessageType.INFO,
highlight: true,
createdAt: this.game.ticks(),
});
}
}
// onEmojiMessageEvent(update: EmojiUpdate) {
// const myPlayer = this.game.playerByClientID(this.clientID);
// if (!myPlayer) return;
// const recipient = update.recipientID == AllPlayers ? AllPlayers : this.game.playerBySmallID(update.recipientID)
// const sender = this.game.playerBySmallID(update.senderID)
// if (recipient == myPlayer) {
// this.addEvent({
// description: `${sender.displayName()}:${update.message}`,
// unsafeDescription: true,
// type: MessageType.INFO,
// highlight: true,
// createdAt: this.game.ticks(),
// });
// } else if (sender === myPlayer && recipient !== AllPlayers) {
// this.addEvent({
// description: `Sent ${recipient.displayName()}: ${update.message}`,
// unsafeDescription: true,
// type: MessageType.INFO,
// highlight: true,
// createdAt: this.game.ticks(),
// });
// }
// }
render() {
if (this.events.length === 0) {
+17 -17
View File
@@ -1,6 +1,6 @@
import { colord, Colord } from "colord";
import { Theme } from "../../../core/configuration/Config";
import { Unit, UnitEvent, Cell, Game, Tile, UnitType } from "../../../core/game/Game";
import { Unit, Cell, Game, Tile, UnitType } from "../../../core/game/Game";
import { bfs, dist, euclDist } from "../../../core/Util";
import { Layer } from "./Layer";
import { EventBus } from "../../../core/EventBus";
@@ -70,7 +70,7 @@ export class StructureLayer implements Layer {
}
tick() {
this.game.units().forEach(u => this.handleUnitRendering(new UnitEvent(u, u.tile())))
this.game.units().forEach(u => this.handleUnitRendering(u))
}
init() {
@@ -83,7 +83,7 @@ export class StructureLayer implements Layer {
this.context = this.canvas.getContext("2d", { alpha: true });
this.canvas.width = this.game.width();
this.canvas.height = this.game.height();
this.game.units().forEach(u => this.handleUnitRendering(new UnitEvent(u, u.tile())))
this.game.units().forEach(u => this.handleUnitRendering(u))
}
renderLayer(context: CanvasRenderingContext2D) {
@@ -100,15 +100,15 @@ export class StructureLayer implements Layer {
return unitType in this.unitConfigs;
}
private handleUnitRendering(event: UnitEvent) {
const unitType = event.unit.type();
private handleUnitRendering(unit: Unit) {
const unitType = unit.type();
if (!this.isUnitTypeSupported(unitType)) return;
if (event.unit.isActive() && this.seenUnits.has(event.unit)) {
if (unit.isActive() && this.seenUnits.has(unit)) {
// Already rendered, so don't do anything.
return
}
if (!event.unit.isActive() && !this.seenUnits.has(event.unit)) {
if (!unit.isActive() && !this.seenUnits.has(unit)) {
// Has been deleted and render is cleared so don't do anything.
return
}
@@ -119,14 +119,14 @@ export class StructureLayer implements Layer {
if (!config || !unitImage) return;
// Clear previous rendering
bfs(event.unit.tile(), euclDist(event.unit.tile(), config.borderRadius))
bfs(unit.tile(), euclDist(unit.tile(), config.borderRadius))
.forEach(t => this.clearCell(t.cell()));
if (!event.unit.isActive()) {
this.seenUnits.delete(event.unit)
if (!unit.isActive()) {
this.seenUnits.delete(unit)
return;
}
this.seenUnits.add(event.unit)
this.seenUnits.add(unit)
// Create temporary canvas for icon processing
const tempCanvas = document.createElement('canvas');
@@ -138,19 +138,19 @@ export class StructureLayer implements Layer {
tempContext.drawImage(unitImage, 0, 0);
const iconData = tempContext.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
const cell = event.unit.tile().cell();
const cell = unit.tile().cell();
const startX = cell.x - Math.floor(tempCanvas.width / 2);
const startY = cell.y - Math.floor(tempCanvas.height / 2);
// Draw border and territory
bfs(event.unit.tile(), euclDist(event.unit.tile(), config.borderRadius))
.forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.unit.owner().info()), 255));
bfs(unit.tile(), euclDist(unit.tile(), config.borderRadius))
.forEach(t => this.paintCell(t.cell(), this.theme.borderColor(unit.owner().info()), 255));
bfs(event.unit.tile(), euclDist(event.unit.tile(), config.territoryRadius))
.forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.unit.owner().info()), 130));
bfs(unit.tile(), euclDist(unit.tile(), config.territoryRadius))
.forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(unit.owner().info()), 130));
// Draw the icon
this.renderIcon(iconData, startX, startY, tempCanvas.width, tempCanvas.height, event.unit);
this.renderIcon(iconData, startX, startY, tempCanvas.width, tempCanvas.height, unit);
}
private renderIcon(
+1 -14
View File
@@ -1,5 +1,5 @@
import { PriorityQueue } from "@datastructures-js/priority-queue";
import { Cell, Game, Player, PlayerType, Tile, TileEvent, UnitEvent, UnitType } from "../../../core/game/Game";
import { Cell, Game, Player, PlayerType, Tile, Unit, UnitType, UnitUpdate } from "../../../core/game/Game";
import { PseudoRandom } from "../../../core/PseudoRandom";
import { colord, Colord } from "colord";
import { bfs, dist, euclDist, euclideanDist } from "../../../core/Util";
@@ -197,19 +197,6 @@ export class TerritoryLayer implements Layer {
this.imageData.data[offset + 3] = 0; // Set alpha to 0 (fully transparent)
}
unitEvent(event: UnitEvent) {
if (event.unit.type() == UnitType.DefensePost) {
bfs(
event.unit.tile(),
dist(event.unit.tile(), this.game.config().defensePostRange())
).forEach(t => {
if (t.isBorder()) {
this.enqueueTile(t)
}
})
}
}
enqueueTile(tile: Tile) {
this.tileToRenderQueue.push({ tile: tile, lastUpdate: this.game.ticks() + this.random.nextFloat(0, .5) })
}
+14 -10
View File
@@ -14,6 +14,10 @@ enum Relationship {
Enemy
}
class UnitEvent {
constructor(public unit: Unit, public oldTile: Tile) { }
}
export class UnitLayer implements Layer {
private canvas: HTMLCanvasElement;
private context: CanvasRenderingContext2D;
@@ -176,22 +180,22 @@ export class UnitLayer implements Layer {
}
private handleTradeShipEvent(unit: Unit) {
const rel = this.relationship(unit)
bfs(unit.oldTile, euclDist(unit.oldTile, 3)).forEach(t => {
private handleTradeShipEvent(event: UnitEvent) {
const rel = this.relationship(event.unit)
bfs(event.oldTile, euclDist(event.oldTile, 3)).forEach(t => {
this.clearCell(t.cell());
});
if (unit.isActive()) {
bfs(unit.tile(), dist(unit.tile(), 2))
.forEach(t => this.paintCell(t.cell(), rel, this.theme.territoryColor(unit.owner().info()), 255));
if (event.unit.isActive()) {
bfs(event.unit.tile(), dist(event.unit.tile(), 2))
.forEach(t => this.paintCell(t.cell(), rel, this.theme.territoryColor(event.unit.owner().info()), 255));
}
if (unit.isActive()) {
bfs(unit.tile(), dist(unit.tile(), 1))
.forEach(t => this.paintCell(t.cell(), rel, this.theme.borderColor(unit.owner().info()), 255));
if (event.unit.isActive()) {
bfs(event.unit.tile(), dist(event.unit.tile(), 1))
.forEach(t => this.paintCell(t.cell(), rel, this.theme.borderColor(event.unit.owner().info()), 255));
}
}
private handleBoatEvent(event: Unit) {
private handleBoatEvent(event: UnitEvent) {
const rel = this.relationship(event.unit)
if (!this.boatToTrail.has(event.unit)) {
this.boatToTrail.set(event.unit, new Set<Tile>());
+4 -5
View File
@@ -1,9 +1,10 @@
import { utcDay } from "d3";
import { placeName } from "../client/graphics/NameBoxCalculator";
import { getConfig } from "./configuration/Config";
import { EventBus } from "./EventBus";
import { Executor } from "./execution/ExecutionManager";
import { WinCheckExecution } from "./execution/WinCheckExecution";
import { Cell, DisplayMessageEvent, Game, MessageType, MutableGame, MutableTile, Player, PlayerID, Tile, UnitType } from "./game/Game";
import { Cell, DisplayMessageUpdate, Game, GameUpdateType, MessageType, MutableGame, MutableTile, Player, PlayerID, Tile, UnitType } from "./game/Game";
import { createGame } from "./game/GameImpl";
import { loadTerrainMap } from "./game/TerrainMapLoader";
import { GameUpdateViewData, NameViewData, packTileData, PlayerActions, PlayerViewData } from "./GameView";
@@ -20,7 +21,6 @@ export async function createGameRunner(gameID: string, gameConfig: GameConfig, c
}
export class GameRunner {
private updatedTiles: Set<MutableTile> = new Set()
private tickInterval = null
private turns: Turn[] = []
private currTurn = 0
@@ -56,12 +56,11 @@ export class GameRunner {
return
}
this.isExecuting = true
this.updatedTiles.clear()
this.game.addExecution(...this.execManager.createExecs(this.turns[this.currTurn]))
this.currTurn++
this.game.executeNextTick()
const updates = this.game.executeNextTick()
if (this.game.inSpawnPhase() || this.game.ticks() % 10 == 0) {
this.game.players()
@@ -78,7 +77,7 @@ export class GameRunner {
this.callBack({
tick: this.game.ticks(),
units: this.game.units().map(u => u.toViewData()),
packedTileUpdates: Array.from(this.updatedTiles).map(t => packTileData(t.toViewData())),
packedTileUpdates: updates.filter(u => u.type == GameUpdateType.Tile).map(u => packTileData(u)),
players: playerViewData
})
this.isExecuting = false
+18 -15
View File
@@ -1,4 +1,4 @@
import { MessageType, Player, Tile, Unit } from './game/Game';
import { GameUpdateType, MessageType, Player, Tile, TileUpdate, Unit } from './game/Game';
import { Config } from "./configuration/Config";
import { Alliance, AllianceRequest, AllPlayers, Cell, DefenseBonus, EmojiMessage, Execution, ExecutionView, Game, Gold, MutableTile, Nation, PlayerID, PlayerInfo, PlayerType, Relation, TerrainMap, TerrainTile, TerrainType, TerraNullius, Tick, UnitInfo, UnitType } from "./game/Game";
import { ClientID } from "./Schemas";
@@ -24,7 +24,7 @@ export interface TileViewData extends ViewData<TileViewData> {
export class TileView {
constructor(private game: GameView, public data: TileViewData, private _terrain: TerrainTile) { }
constructor(private game: GameView, public data: TileUpdate, private _terrain: TerrainTile) { }
type(): TerrainType {
return this._terrain.type()
@@ -33,10 +33,10 @@ export class TileView {
if (!this.hasOwner()) {
return new TerraNulliusImpl()
}
return this.game.playerBySmallID(this.data?.smallID)
return this.game.playerBySmallID(this.data?.ownerID)
}
hasOwner(): boolean {
return this.data?.smallID !== undefined && this.data.smallID !== 0;
return this.data?.ownerID !== undefined && this.data.ownerID !== 0;
}
isBorder(): boolean {
return this.data?.isBorder
@@ -276,7 +276,7 @@ export interface GameUpdateViewData extends ViewData<GameUpdateViewData> {
tick: number
units: UnitViewData[]
players: Record<PlayerID, PlayerViewData>
tileUpdates?: TileViewData[]
tileUpdates?: TileUpdate[]
packedTileUpdates: Uint16Array[]
}
@@ -310,7 +310,7 @@ export class GameView {
this.lastUpdate = gu
this.lastUpdate.tileUpdates = this.lastUpdate.packedTileUpdates.map(tu => unpackTileData(tu))
this.lastUpdate.tileUpdates.forEach(tu => {
this.tiles[tu.x][tu.y].data = tu
this.tiles[tu.pos.x][tu.pos.y].data = tu
})
Object.entries(gu.players).forEach(([key, value]) => {
this.smallIDToID.set(value.smallID, key);
@@ -330,7 +330,7 @@ export class GameView {
}
recentlyUpdatedTiles(): TileView[] {
return this.lastUpdate.tileUpdates.filter(d => true).map(tu => new TileView(this, tu, this._terrainMap.terrain(new Cell(tu.x, tu.y))))
return this.lastUpdate.tileUpdates.map(tu => new TileView(this, tu, this._terrainMap.terrain(new Cell(tu.pos.x, tu.pos.y))))
}
player(id: PlayerID): PlayerView {
@@ -404,11 +404,11 @@ export class GameView {
}
}
export function packTileData(tile: TileViewData): Uint16Array {
export function packTileData(tile: TileUpdate): Uint16Array {
const packed = new Uint16Array(4);
packed[0] = tile.x;
packed[1] = tile.y;
packed[2] = tile.smallID;
packed[0] = tile.pos.x;
packed[1] = tile.pos.y;
packed[2] = tile.ownerID;
// Pack booleans into bits
packed[3] = (tile.hasFallout ? 1 : 0) |
@@ -418,11 +418,14 @@ export function packTileData(tile: TileViewData): Uint16Array {
return packed;
}
export function unpackTileData(packed: Uint16Array): TileViewData {
export function unpackTileData(packed: Uint16Array): TileUpdate {
return {
x: packed[0],
y: packed[1],
smallID: packed[2],
type: GameUpdateType.Tile,
pos: {
x: packed[0],
y: packed[1],
},
ownerID: packed[2],
hasFallout: !!(packed[3] & 1),
hasDefenseBonus: !!(packed[3] & 2),
isBorder: !!(packed[3] & 4),
+2 -2
View File
@@ -1,8 +1,8 @@
import { Unit, Cell, Execution, MutableUnit, MutableGame, MutablePlayer, Player, PlayerID, TerraNullius, Tile, UnitType, TerrainType } from "../game/Game";
import { Unit, Cell, Execution, MutableUnit, MutableGame, MutablePlayer, Player, PlayerID, TerraNullius, Tile, UnitType, TerrainType } from "../game/Game";
import { and, bfs, manhattanDistWrapped, sourceDstOceanShore, targetTransportTile } from "../Util";
import { AttackExecution } from "./AttackExecution";
import { MessageType } from '../game/Game';
import { DisplayMessageEvent } from '../game/Game';
import { DisplayMessageUpdate } from '../game/Game';
import { PathFinder } from "../pathfinding/PathFinding";
import { PathFindResultType } from "../pathfinding/AStar";
import { SerialAStar } from "../pathfinding/SerialAStar";
+4 -5
View File
@@ -344,7 +344,7 @@ export interface Game {
forEachTile(fn: (tile: Tile) => void): void
executions(): ExecutionView[]
terraNullius(): TerraNullius
executeNextTick(): void
executeNextTick(): GameUpdate[]
ticks(): Tick
inSpawnPhase(): boolean
addExecution(...exec: Execution[]): void
@@ -391,17 +391,16 @@ export type GameUpdate = TileUpdate
| AllianceRequestReplyUpdate
| BrokeAllianceUpdate
| AllianceExpiredUpdate
| DisplayMessageEvent
| DisplayMessageUpdate
| TargetPlayerUpdate
| EmojiUpdate
| WinUpdate
export interface TileUpdate {
type: GameUpdateType.Tile
owner: number
ownerID: number
pos: MapPos
isBorder: boolean
borderOnlyChange: boolean
hasFallout: boolean
hasDefenseBonus: boolean
}
@@ -457,7 +456,7 @@ export interface EmojiUpdate {
createdAt: Tick
}
export interface DisplayMessageEvent {
export interface DisplayMessageUpdate {
type: GameUpdateType.DisplayEvent
message: string
messageType: MessageType
+5 -3
View File
@@ -79,7 +79,7 @@ export class GameImpl implements MutableGame {
throw Error(`cannot set fallout, tile ${tile} has owner`)
}
ti._hasFallout = true
this.updates.push(ti.toUpdate(false))
this.updates.push(ti.toUpdate())
}
addTileDefenseBonus(tile: Tile, unit: Unit, amount: number): DefenseBonus {
@@ -164,7 +164,8 @@ export class GameImpl implements MutableGame {
return this._ticks
}
executeNextTick() {
executeNextTick(): GameUpdate[] {
this.updates = []
this.execs.forEach(e => {
if (e.isActive() && (!this.inSpawnPhase() || e.activeDuringSpawnPhase())) {
e.tick(this._ticks)
@@ -193,6 +194,7 @@ export class GameImpl implements MutableGame {
})
consolex.log(`tick ${this._ticks}: hash ${hash}`)
}
return this.updates
}
terraNullius(): TerraNullius {
@@ -386,7 +388,6 @@ export class GameImpl implements MutableGame {
tile.neighbors().forEach(t => tiles.push(t as TileImpl))
for (const t of tiles) {
this.updates.push(t.toUpdate(true))
if (!t.hasOwner()) {
t._isBorder = false
continue
@@ -398,6 +399,7 @@ export class GameImpl implements MutableGame {
(t.owner() as PlayerImpl)._borderTiles.delete(t);
t._isBorder = false
}
this.updates.push(t.toUpdate())
}
}
+2 -3
View File
@@ -27,18 +27,17 @@ export class TileImpl implements MutableTile {
throw new Error("Method not implemented.");
}
toUpdate(borderOnlyChange: boolean = false): TileUpdate {
toUpdate(): TileUpdate {
return {
type: GameUpdateType.Tile,
pos: {
x: this._cell.x,
y: this._cell.y
},
owner: this._owner.isPlayer() ? this._owner.smallID() : 0,
ownerID: this._owner.isPlayer() ? this._owner.smallID() : 0,
hasFallout: this._hasFallout,
hasDefenseBonus: this.hasDefenseBonus(),
isBorder: this.isBorder(),
borderOnlyChange: borderOnlyChange
}
}