mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-23 10:42:36 +00:00
Feat : focus attack average position and some movement camera fixes (#740)
## Description: Makes so that when clicking on the attack warning message in chat, the camera focuses on the "average position" of the attack, instead of just the player. The average position is calculated by taking the average position of all attacking border cells. It makes the calculation for every AttackUpdate, which adds some calculations every tick, but it shouldn't affect performance that much, as it's just a sum of coordinates. If you have a better way of getting the averagePosition information (calculating it only when necessary instead of every tick), it would be great. closes #703 ## 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: leo21_ --------- Co-authored-by: Scott Anderson <scottanderson@users.noreply.github.com> Co-authored-by: evanpelle <evanpelle@gmail.com>
This commit is contained in:
@@ -2,12 +2,21 @@ import { EventBus } from "../../core/EventBus";
|
||||
import { Cell } from "../../core/game/Game";
|
||||
import { GameView } from "../../core/game/GameView";
|
||||
import { CenterCameraEvent, DragEvent, ZoomEvent } from "../InputHandler";
|
||||
import { GoToPlayerEvent, GoToUnitEvent } from "./layers/Leaderboard";
|
||||
import {
|
||||
GoToPlayerEvent,
|
||||
GoToPositionEvent,
|
||||
GoToUnitEvent,
|
||||
} from "./layers/Leaderboard";
|
||||
|
||||
export const GOTO_INTERVAL_MS = 16;
|
||||
export const CAMERA_MAX_SPEED = 15;
|
||||
export const CAMERA_SMOOTHING = 0.03;
|
||||
|
||||
export class TransformHandler {
|
||||
public scale: number = 1.8;
|
||||
private offsetX: number = -350;
|
||||
private offsetY: number = -200;
|
||||
private lastGoToCallTime: number | null = null;
|
||||
|
||||
private target: Cell | null;
|
||||
private intervalID: NodeJS.Timeout | null = null;
|
||||
@@ -21,6 +30,7 @@ export class TransformHandler {
|
||||
this.eventBus.on(ZoomEvent, (e) => this.onZoom(e));
|
||||
this.eventBus.on(DragEvent, (e) => this.onMove(e));
|
||||
this.eventBus.on(GoToPlayerEvent, (e) => this.onGoToPlayer(e));
|
||||
this.eventBus.on(GoToPositionEvent, (e) => this.onGoToPosition(e));
|
||||
this.eventBus.on(GoToUnitEvent, (e) => this.onGoToUnit(e));
|
||||
this.eventBus.on(CenterCameraEvent, () => this.centerCamera());
|
||||
}
|
||||
@@ -146,7 +156,13 @@ export class TransformHandler {
|
||||
event.player.nameLocation().x,
|
||||
event.player.nameLocation().y,
|
||||
);
|
||||
this.intervalID = setInterval(() => this.goTo(), 1);
|
||||
this.intervalID = setInterval(() => this.goTo(), GOTO_INTERVAL_MS);
|
||||
}
|
||||
|
||||
onGoToPosition(event: GoToPositionEvent) {
|
||||
this.clearTarget();
|
||||
this.target = new Cell(event.x, event.y);
|
||||
this.intervalID = setInterval(() => this.goTo(), GOTO_INTERVAL_MS);
|
||||
}
|
||||
|
||||
onGoToUnit(event: GoToUnitEvent) {
|
||||
@@ -155,7 +171,7 @@ export class TransformHandler {
|
||||
this.game.x(event.unit.lastTile()),
|
||||
this.game.y(event.unit.lastTile()),
|
||||
);
|
||||
this.intervalID = setInterval(() => this.goTo(), 1);
|
||||
this.intervalID = setInterval(() => this.goTo(), GOTO_INTERVAL_MS);
|
||||
}
|
||||
|
||||
centerCamera() {
|
||||
@@ -163,43 +179,42 @@ export class TransformHandler {
|
||||
const player = this.game.myPlayer();
|
||||
if (!player || !player.nameLocation()) return;
|
||||
this.target = new Cell(player.nameLocation().x, player.nameLocation().y);
|
||||
this.intervalID = setInterval(() => this.goTo(), 1);
|
||||
this.intervalID = setInterval(() => this.goTo(), GOTO_INTERVAL_MS);
|
||||
}
|
||||
|
||||
private goTo() {
|
||||
const { screenX, screenY } = this.screenCenter();
|
||||
const screenMapCenter = new Cell(screenX, screenY);
|
||||
|
||||
if (this.target === null) throw new Error("null target");
|
||||
|
||||
if (
|
||||
this.game.manhattanDist(
|
||||
this.game.ref(screenX, screenY),
|
||||
this.game.ref(this.target.x, this.target.y),
|
||||
) < 2
|
||||
Math.abs(this.target.x - screenX) + Math.abs(this.target.y - screenY) <
|
||||
2
|
||||
) {
|
||||
this.clearTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const dX = Math.abs(screenMapCenter.x - this.target.x);
|
||||
if (dX > 2) {
|
||||
const offsetDx = Math.max(1, Math.floor(dX / 25));
|
||||
if (screenMapCenter.x > this.target.x) {
|
||||
this.offsetX -= offsetDx;
|
||||
} else {
|
||||
this.offsetX += offsetDx;
|
||||
}
|
||||
}
|
||||
const dY = Math.abs(screenMapCenter.y - this.target.y);
|
||||
if (dY > 2) {
|
||||
const offsetDy = Math.max(1, Math.floor(dY / 25));
|
||||
if (screenMapCenter.y > this.target.y) {
|
||||
this.offsetY -= offsetDy;
|
||||
} else {
|
||||
this.offsetY += offsetDy;
|
||||
}
|
||||
let dt: number;
|
||||
const now = window.performance.now();
|
||||
if (this.lastGoToCallTime === null) {
|
||||
dt = GOTO_INTERVAL_MS;
|
||||
} else {
|
||||
dt = now - this.lastGoToCallTime;
|
||||
}
|
||||
this.lastGoToCallTime = now;
|
||||
|
||||
const r = 1 - Math.pow(CAMERA_SMOOTHING, dt / 1000);
|
||||
|
||||
this.offsetX += Math.max(
|
||||
Math.min((this.target.x - screenX) * r, CAMERA_MAX_SPEED),
|
||||
-CAMERA_MAX_SPEED,
|
||||
);
|
||||
this.offsetY += Math.max(
|
||||
Math.min((this.target.y - screenY) * r, CAMERA_MAX_SPEED),
|
||||
-CAMERA_MAX_SPEED,
|
||||
);
|
||||
|
||||
this.changed = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,11 @@ import { Layer } from "./Layer";
|
||||
import { GameView, PlayerView, UnitView } from "../../../core/game/GameView";
|
||||
import { onlyImages } from "../../../core/Util";
|
||||
import { renderTroops } from "../../Utils";
|
||||
import { GoToPlayerEvent, GoToUnitEvent } from "./Leaderboard";
|
||||
import {
|
||||
GoToPlayerEvent,
|
||||
GoToPositionEvent,
|
||||
GoToUnitEvent,
|
||||
} from "./Leaderboard";
|
||||
|
||||
import { translateText } from "../../Utils";
|
||||
|
||||
@@ -393,6 +397,10 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
this.eventBus.emit(new GoToPlayerEvent(attacker));
|
||||
}
|
||||
|
||||
emitGoToPositionEvent(x: number, y: number) {
|
||||
this.eventBus.emit(new GoToPositionEvent(x, y));
|
||||
}
|
||||
|
||||
emitGoToUnitEvent(unit: UnitView) {
|
||||
this.eventBus.emit(new GoToUnitEvent(unit));
|
||||
}
|
||||
@@ -476,6 +484,26 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
: event.description;
|
||||
}
|
||||
|
||||
private async attackWarningOnClick(attack: AttackUpdate) {
|
||||
const playerView = this.game.playerBySmallID(attack.attackerID);
|
||||
if (playerView !== undefined) {
|
||||
if (playerView instanceof PlayerView) {
|
||||
const averagePosition = await playerView.attackAveragePosition(
|
||||
attack.attackerID,
|
||||
attack.id,
|
||||
);
|
||||
|
||||
if (averagePosition === null) {
|
||||
this.emitGoToPlayerEvent(attack.attackerID);
|
||||
} else {
|
||||
this.emitGoToPositionEvent(averagePosition.x, averagePosition.y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.emitGoToPlayerEvent(attack.attackerID);
|
||||
}
|
||||
}
|
||||
|
||||
private renderIncomingAttacks() {
|
||||
return html`
|
||||
${this.incomingAttacks.length > 0
|
||||
@@ -487,10 +515,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
<button
|
||||
translate="no"
|
||||
class="ml-2"
|
||||
@click=${() => {
|
||||
attack.attackerID &&
|
||||
this.emitGoToPlayerEvent(attack.attackerID);
|
||||
}}
|
||||
@click=${() => this.attackWarningOnClick(attack)}
|
||||
>
|
||||
${renderTroops(attack.troops)}
|
||||
${(
|
||||
@@ -520,7 +545,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
<button
|
||||
translate="no"
|
||||
class="ml-2"
|
||||
@click=${() => this.emitGoToPlayerEvent(attack.targetID)}
|
||||
@click=${async () => this.attackWarningOnClick(attack)}
|
||||
>
|
||||
${renderTroops(attack.troops)}
|
||||
${(
|
||||
|
||||
@@ -22,6 +22,13 @@ export class GoToPlayerEvent implements GameEvent {
|
||||
constructor(public player: PlayerView) {}
|
||||
}
|
||||
|
||||
export class GoToPositionEvent implements GameEvent {
|
||||
constructor(
|
||||
public x: number,
|
||||
public y: number,
|
||||
) {}
|
||||
}
|
||||
|
||||
export class GoToUnitEvent implements GameEvent {
|
||||
constructor(public unit: UnitView) {}
|
||||
}
|
||||
|
||||
@@ -225,6 +225,27 @@ export class GameRunner {
|
||||
borderTiles: player.borderTiles(),
|
||||
} as PlayerBorderTiles;
|
||||
}
|
||||
|
||||
public attackAveragePosition(
|
||||
playerID: number,
|
||||
attackID: string,
|
||||
): Cell | null {
|
||||
const player = this.game.playerBySmallID(playerID);
|
||||
if (!player.isPlayer()) {
|
||||
throw new Error(`player with id ${playerID} not found`);
|
||||
}
|
||||
|
||||
const condition = (a) => a.id() === attackID;
|
||||
const attack =
|
||||
player.outgoingAttacks().find(condition) ??
|
||||
player.incomingAttacks().find(condition);
|
||||
if (attack === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return attack.averagePosition();
|
||||
}
|
||||
|
||||
public bestTransportShipSpawn(
|
||||
playerID: PlayerID,
|
||||
targetTile: TileRef,
|
||||
|
||||
@@ -27,8 +27,6 @@ export class AttackExecution implements Execution {
|
||||
|
||||
private mg: Game;
|
||||
|
||||
private border = new Set<TileRef>();
|
||||
|
||||
private attack: Attack | null = null;
|
||||
|
||||
constructor(
|
||||
@@ -119,8 +117,15 @@ export class AttackExecution implements Execution {
|
||||
this.target,
|
||||
this.startTroops,
|
||||
this.sourceTile,
|
||||
new Set<TileRef>(),
|
||||
);
|
||||
|
||||
if (this.sourceTile !== null) {
|
||||
this.addNeighbors(this.sourceTile);
|
||||
} else {
|
||||
this.refreshToConquer();
|
||||
}
|
||||
|
||||
// Record stats
|
||||
this.mg.stats().attack(this._owner, this.target, this.startTroops);
|
||||
|
||||
@@ -152,12 +157,6 @@ export class AttackExecution implements Execution {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.sourceTile !== null) {
|
||||
this.addNeighbors(this.sourceTile);
|
||||
} else {
|
||||
this.refreshToConquer();
|
||||
}
|
||||
|
||||
if (this.target.isPlayer()) {
|
||||
if (this._owner.isAlliedWith(this.target)) {
|
||||
// No updates should happen in init.
|
||||
@@ -168,8 +167,12 @@ export class AttackExecution implements Execution {
|
||||
}
|
||||
|
||||
private refreshToConquer() {
|
||||
if (this.attack === null) {
|
||||
throw new Error("Attack not initialized");
|
||||
}
|
||||
|
||||
this.toConquer.clear();
|
||||
this.border.clear();
|
||||
this.attack.clearBorder();
|
||||
for (const tile of this._owner.borderTiles()) {
|
||||
this.addNeighbors(tile);
|
||||
}
|
||||
@@ -243,7 +246,7 @@ export class AttackExecution implements Execution {
|
||||
troopCount,
|
||||
this._owner,
|
||||
this.target,
|
||||
this.border.size + this.random.nextInt(0, 5),
|
||||
this.attack.borderSize() + this.random.nextInt(0, 5),
|
||||
);
|
||||
|
||||
while (numTilesPerTick > 0) {
|
||||
@@ -260,7 +263,7 @@ export class AttackExecution implements Execution {
|
||||
}
|
||||
|
||||
const [tileToConquer] = this.toConquer.dequeue();
|
||||
this.border.delete(tileToConquer);
|
||||
this.attack.removeBorderTile(tileToConquer);
|
||||
|
||||
let onBorder = false;
|
||||
for (const n of this.mg.neighbors(tileToConquer)) {
|
||||
@@ -294,6 +297,10 @@ export class AttackExecution implements Execution {
|
||||
}
|
||||
|
||||
private addNeighbors(tile: TileRef) {
|
||||
if (this.attack === null) {
|
||||
throw new Error("Attack not initialized");
|
||||
}
|
||||
|
||||
const tickNow = this.mg.ticks(); // cache tick
|
||||
|
||||
for (const neighbor of this.mg.neighbors(tile)) {
|
||||
@@ -303,7 +310,7 @@ export class AttackExecution implements Execution {
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
this.border.add(neighbor);
|
||||
this.attack.addBorderTile(neighbor);
|
||||
let numOwnedByMe = 0;
|
||||
for (const n of this.mg.neighbors(neighbor)) {
|
||||
if (this.mg.owner(n) === this._owner) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Attack, Player, TerraNullius } from "./Game";
|
||||
import { Attack, Cell, Player, TerraNullius } from "./Game";
|
||||
import { GameImpl } from "./GameImpl";
|
||||
import { TileRef } from "./GameMap";
|
||||
import { PlayerImpl } from "./PlayerImpl";
|
||||
|
||||
export class AttackImpl implements Attack {
|
||||
private _isActive = true;
|
||||
private _borderSize = 0;
|
||||
public _retreating = false;
|
||||
public _retreated = false;
|
||||
|
||||
@@ -13,6 +15,8 @@ export class AttackImpl implements Attack {
|
||||
private _attacker: Player,
|
||||
private _troops: number,
|
||||
private _sourceTile: TileRef | null,
|
||||
private _border: Set<number>,
|
||||
private _mg: GameImpl,
|
||||
) {}
|
||||
|
||||
sourceTile(): TileRef | null {
|
||||
@@ -69,4 +73,50 @@ export class AttackImpl implements Attack {
|
||||
retreated(): boolean {
|
||||
return this._retreated;
|
||||
}
|
||||
|
||||
borderSize(): number {
|
||||
return this._borderSize;
|
||||
}
|
||||
|
||||
clearBorder(): void {
|
||||
this._borderSize = 0;
|
||||
this._border.clear();
|
||||
}
|
||||
|
||||
addBorderTile(tile: TileRef): void {
|
||||
this._borderSize += 1;
|
||||
this._border.add(tile);
|
||||
}
|
||||
|
||||
removeBorderTile(tile: TileRef): void {
|
||||
if (this._border.has(tile)) {
|
||||
this._borderSize -= 1;
|
||||
this._border.delete(tile);
|
||||
}
|
||||
}
|
||||
|
||||
averagePosition(): Cell | null {
|
||||
if (this._borderSize === 0) {
|
||||
if (this.sourceTile() === null) {
|
||||
// No border tiles and no source tile—return a default position or throw an error
|
||||
return null;
|
||||
}
|
||||
// No border tiles yet—use the source tile's location
|
||||
const tile: number = this.sourceTile()!;
|
||||
return new Cell(this._mg.map().x(tile), this._mg.map().y(tile));
|
||||
}
|
||||
|
||||
let averageX = 0;
|
||||
let averageY = 0;
|
||||
|
||||
for (const t of this._border) {
|
||||
averageX += this._mg.map().x(t);
|
||||
averageY += this._mg.map().y(t);
|
||||
}
|
||||
|
||||
averageX = averageX / this._borderSize;
|
||||
averageY = averageY / this._borderSize;
|
||||
|
||||
return new Cell(averageX, averageY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,6 +282,11 @@ export interface Attack {
|
||||
delete(): void;
|
||||
// The tile the attack originated from, mostly used for boat attacks.
|
||||
sourceTile(): TileRef | null;
|
||||
addBorderTile(tile: TileRef): void;
|
||||
removeBorderTile(tile: TileRef): void;
|
||||
clearBorder(): void;
|
||||
borderSize(): number;
|
||||
averagePosition(): Cell | null;
|
||||
}
|
||||
|
||||
export interface AllianceRequest {
|
||||
@@ -505,10 +510,12 @@ export interface Player {
|
||||
|
||||
// Attacking.
|
||||
canAttack(tile: TileRef): boolean;
|
||||
|
||||
createAttack(
|
||||
target: Player | TerraNullius,
|
||||
troops: number,
|
||||
sourceTile: TileRef | null,
|
||||
border: Set<number>,
|
||||
): Attack;
|
||||
outgoingAttacks(): Attack[];
|
||||
incomingAttacks(): Attack[];
|
||||
|
||||
@@ -158,6 +158,13 @@ export class PlayerView {
|
||||
return this.data.incomingAttacks;
|
||||
}
|
||||
|
||||
async attackAveragePosition(
|
||||
playerID: number,
|
||||
attackID: string,
|
||||
): Promise<Cell | null> {
|
||||
return this.game.worker.attackAveragePosition(playerID, attackID);
|
||||
}
|
||||
|
||||
units(...types: UnitType[]): UnitView[] {
|
||||
return this.game
|
||||
.units(...types)
|
||||
|
||||
+21
-20
@@ -148,26 +148,24 @@ export class PlayerImpl implements Player {
|
||||
isTraitor: this.isTraitor(),
|
||||
targets: this.targets().map((p) => p.smallID()),
|
||||
outgoingEmojis: this.outgoingEmojis(),
|
||||
outgoingAttacks: this._outgoingAttacks.map(
|
||||
(a) =>
|
||||
({
|
||||
attackerID: a.attacker().smallID(),
|
||||
targetID: a.target().smallID(),
|
||||
troops: a.troops(),
|
||||
id: a.id(),
|
||||
retreating: a.retreating(),
|
||||
}) as AttackUpdate,
|
||||
),
|
||||
incomingAttacks: this._incomingAttacks.map(
|
||||
(a) =>
|
||||
({
|
||||
attackerID: a.attacker().smallID(),
|
||||
targetID: a.target().smallID(),
|
||||
troops: a.troops(),
|
||||
id: a.id(),
|
||||
retreating: a.retreating(),
|
||||
}) as AttackUpdate,
|
||||
),
|
||||
outgoingAttacks: this._outgoingAttacks.map((a) => {
|
||||
return {
|
||||
attackerID: a.attacker().smallID(),
|
||||
targetID: a.target().smallID(),
|
||||
troops: a.troops(),
|
||||
id: a.id(),
|
||||
retreating: a.retreating(),
|
||||
} as AttackUpdate;
|
||||
}),
|
||||
incomingAttacks: this._incomingAttacks.map((a) => {
|
||||
return {
|
||||
attackerID: a.attacker().smallID(),
|
||||
targetID: a.target().smallID(),
|
||||
troops: a.troops(),
|
||||
id: a.id(),
|
||||
retreating: a.retreating(),
|
||||
} as AttackUpdate;
|
||||
}),
|
||||
outgoingAllianceRequests: outgoingAllianceRequests,
|
||||
hasSpawned: this.hasSpawned(),
|
||||
betrayals: stats?.betrayals,
|
||||
@@ -958,6 +956,7 @@ export class PlayerImpl implements Player {
|
||||
target: Player | TerraNullius,
|
||||
troops: number,
|
||||
sourceTile: TileRef | null,
|
||||
border: Set<number>,
|
||||
): Attack {
|
||||
const attack = new AttackImpl(
|
||||
this._pseudo_random.nextID(),
|
||||
@@ -965,6 +964,8 @@ export class PlayerImpl implements Player {
|
||||
this,
|
||||
troops,
|
||||
sourceTile,
|
||||
border,
|
||||
this.mg,
|
||||
);
|
||||
this._outgoingAttacks.push(attack);
|
||||
if (target.isPlayer()) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createGameRunner, GameRunner } from "../GameRunner";
|
||||
import { GameUpdateViewData } from "../game/GameUpdates";
|
||||
import {
|
||||
AttackAveragePositionResultMessage,
|
||||
InitializedMessage,
|
||||
MainThreadMessage,
|
||||
PlayerActionsResultMessage,
|
||||
@@ -121,6 +122,27 @@ ctx.addEventListener("message", async (e: MessageEvent<MainThreadMessage>) => {
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
case "attack_average_position":
|
||||
if (!gameRunner) {
|
||||
throw new Error("Game runner not initialized");
|
||||
}
|
||||
|
||||
try {
|
||||
const averagePosition = (await gameRunner).attackAveragePosition(
|
||||
message.playerID,
|
||||
message.attackID,
|
||||
);
|
||||
sendMessage({
|
||||
type: "attack_average_position_result",
|
||||
id: message.id,
|
||||
x: averagePosition ? averagePosition.x : null,
|
||||
y: averagePosition ? averagePosition.y : null,
|
||||
} as AttackAveragePositionResultMessage);
|
||||
} catch (error) {
|
||||
console.error("Failed to get attack average position:", error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
case "transport_ship_spawn":
|
||||
if (!gameRunner) {
|
||||
throw new Error("Game runner not initialized");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
Cell,
|
||||
PlayerActions,
|
||||
PlayerBorderTiles,
|
||||
PlayerID,
|
||||
@@ -189,6 +190,41 @@ export class WorkerClient {
|
||||
});
|
||||
}
|
||||
|
||||
attackAveragePosition(
|
||||
playerID: number,
|
||||
attackID: string,
|
||||
): Promise<Cell | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isInitialized) {
|
||||
reject(new Error("Worker not initialized"));
|
||||
return;
|
||||
}
|
||||
|
||||
const messageId = generateID();
|
||||
|
||||
this.messageHandlers.set(messageId, (message) => {
|
||||
if (
|
||||
message.type === "attack_average_position_result" &&
|
||||
message.x !== undefined &&
|
||||
message.y !== undefined
|
||||
) {
|
||||
if (message.x === null || message.y === null) {
|
||||
resolve(null);
|
||||
} else {
|
||||
resolve(new Cell(message.x, message.y));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.worker.postMessage({
|
||||
type: "attack_average_position",
|
||||
id: messageId,
|
||||
playerID: playerID,
|
||||
attackID: attackID,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
transportShipSpawn(
|
||||
playerID: PlayerID,
|
||||
targetTile: TileRef,
|
||||
|
||||
@@ -20,6 +20,8 @@ export type WorkerMessageType =
|
||||
| "player_profile_result"
|
||||
| "player_border_tiles"
|
||||
| "player_border_tiles_result"
|
||||
| "attack_average_position"
|
||||
| "attack_average_position_result"
|
||||
| "transport_ship_spawn"
|
||||
| "transport_ship_spawn_result";
|
||||
|
||||
@@ -87,6 +89,18 @@ export interface PlayerBorderTilesResultMessage extends BaseWorkerMessage {
|
||||
result: PlayerBorderTiles;
|
||||
}
|
||||
|
||||
export interface AttackAveragePositionMessage extends BaseWorkerMessage {
|
||||
type: "attack_average_position";
|
||||
playerID: number;
|
||||
attackID: string;
|
||||
}
|
||||
|
||||
export interface AttackAveragePositionResultMessage extends BaseWorkerMessage {
|
||||
type: "attack_average_position_result";
|
||||
x: number | null;
|
||||
y: number | null;
|
||||
}
|
||||
|
||||
export interface TransportShipSpawnMessage extends BaseWorkerMessage {
|
||||
type: "transport_ship_spawn";
|
||||
playerID: PlayerID;
|
||||
@@ -106,6 +120,7 @@ export type MainThreadMessage =
|
||||
| PlayerActionsMessage
|
||||
| PlayerProfileMessage
|
||||
| PlayerBorderTilesMessage
|
||||
| AttackAveragePositionMessage
|
||||
| TransportShipSpawnMessage;
|
||||
|
||||
// Message send from worker
|
||||
@@ -115,4 +130,5 @@ export type WorkerMessage =
|
||||
| PlayerActionsResultMessage
|
||||
| PlayerProfileResultMessage
|
||||
| PlayerBorderTilesResultMessage
|
||||
| AttackAveragePositionResultMessage
|
||||
| TransportShipSpawnResultMessage;
|
||||
|
||||
Reference in New Issue
Block a user