mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-28 11:44:16 +00:00
Reused the quick‑info hover logic so territory highlighting now follows boats/ships too.
- Added shared hover helper in HoverInfo.ts (same rules as PlayerInfoOverlay, including nearby ships on water). - PlayerInfoOverlay.ts now uses getHoverInfo(...) instead of its local hover logic. - TerritoryLayer.ts now uses getHoverInfo(...) and highlights the unit owner when hovering ships/boats.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { UnitType } from "../../core/game/Game";
|
||||
import { TileRef } from "../../core/game/GameMap";
|
||||
import { GameView, PlayerView, UnitView } from "../../core/game/GameView";
|
||||
|
||||
export type HoverInfo = {
|
||||
player: PlayerView | null;
|
||||
unit: UnitView | null;
|
||||
isWilderness: boolean;
|
||||
isIrradiatedWilderness: boolean;
|
||||
};
|
||||
|
||||
function euclideanDistWorld(
|
||||
coord: { x: number; y: number },
|
||||
tileRef: TileRef,
|
||||
game: GameView,
|
||||
): number {
|
||||
const x = game.x(tileRef);
|
||||
const y = game.y(tileRef);
|
||||
const dx = coord.x - x;
|
||||
const dy = coord.y - y;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
function distSortUnitWorld(coord: { x: number; y: number }, game: GameView) {
|
||||
return (a: UnitView, b: UnitView) => {
|
||||
const distA = euclideanDistWorld(coord, a.tile(), game);
|
||||
const distB = euclideanDistWorld(coord, b.tile(), game);
|
||||
return distA - distB;
|
||||
};
|
||||
}
|
||||
|
||||
export function getHoverInfo(
|
||||
game: GameView,
|
||||
worldCoord: { x: number; y: number },
|
||||
): HoverInfo {
|
||||
const info: HoverInfo = {
|
||||
player: null,
|
||||
unit: null,
|
||||
isWilderness: false,
|
||||
isIrradiatedWilderness: false,
|
||||
};
|
||||
|
||||
if (!game.isValidCoord(worldCoord.x, worldCoord.y)) {
|
||||
return info;
|
||||
}
|
||||
|
||||
const tile = game.ref(worldCoord.x, worldCoord.y);
|
||||
const owner = game.owner(tile);
|
||||
|
||||
if (owner && owner.isPlayer()) {
|
||||
info.player = owner as PlayerView;
|
||||
return info;
|
||||
}
|
||||
|
||||
if (owner && !owner.isPlayer() && game.isLand(tile)) {
|
||||
info.isIrradiatedWilderness = game.hasFallout(tile);
|
||||
info.isWilderness = !info.isIrradiatedWilderness;
|
||||
return info;
|
||||
}
|
||||
|
||||
if (!game.isLand(tile)) {
|
||||
const units = game
|
||||
.units(UnitType.Warship, UnitType.TradeShip, UnitType.TransportShip)
|
||||
.filter((u) => euclideanDistWorld(worldCoord, u.tile(), game) < 50)
|
||||
.sort(distSortUnitWorld(worldCoord, game));
|
||||
|
||||
if (units.length > 0) {
|
||||
info.unit = units[0];
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
@@ -7,10 +7,8 @@ import {
|
||||
PlayerProfile,
|
||||
PlayerType,
|
||||
Relation,
|
||||
Unit,
|
||||
UnitType,
|
||||
} from "../../../core/game/Game";
|
||||
import { TileRef } from "../../../core/game/GameMap";
|
||||
import { AllianceView } from "../../../core/game/GameUpdates";
|
||||
import { GameView, PlayerView, UnitView } from "../../../core/game/GameView";
|
||||
import { ContextMenuEvent, MouseMoveEvent } from "../../InputHandler";
|
||||
@@ -20,6 +18,7 @@ import {
|
||||
renderTroops,
|
||||
translateText,
|
||||
} from "../../Utils";
|
||||
import { getHoverInfo } from "../HoverInfo";
|
||||
import { getFirstPlacePlayer, getPlayerIcons } from "../PlayerIcons";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
@@ -33,26 +32,6 @@ import missileSiloIcon from "/images/MissileSiloIconWhite.svg?url";
|
||||
import portIcon from "/images/PortIcon.svg?url";
|
||||
import samLauncherIcon from "/images/SamLauncherIconWhite.svg?url";
|
||||
|
||||
function euclideanDistWorld(
|
||||
coord: { x: number; y: number },
|
||||
tileRef: TileRef,
|
||||
game: GameView,
|
||||
): number {
|
||||
const x = game.x(tileRef);
|
||||
const y = game.y(tileRef);
|
||||
const dx = coord.x - x;
|
||||
const dy = coord.y - y;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
function distSortUnitWorld(coord: { x: number; y: number }, game: GameView) {
|
||||
return (a: Unit | UnitView, b: Unit | UnitView) => {
|
||||
const distA = euclideanDistWorld(coord, a.tile(), game);
|
||||
const distB = euclideanDistWorld(coord, b.tile(), game);
|
||||
return distA - distB;
|
||||
};
|
||||
}
|
||||
|
||||
@customElement("player-info-overlay")
|
||||
export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
@property({ type: Object })
|
||||
@@ -119,38 +98,21 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
public maybeShow(x: number, y: number) {
|
||||
this.hide();
|
||||
const worldCoord = this.transform.screenToWorldCoordinates(x, y);
|
||||
if (!this.game.isValidCoord(worldCoord.x, worldCoord.y)) {
|
||||
return;
|
||||
}
|
||||
const info = getHoverInfo(this.game, worldCoord);
|
||||
|
||||
const tile = this.game.ref(worldCoord.x, worldCoord.y);
|
||||
if (!tile) return;
|
||||
|
||||
const owner = this.game.owner(tile);
|
||||
|
||||
if (owner && owner.isPlayer()) {
|
||||
this.player = owner as PlayerView;
|
||||
if (info.player) {
|
||||
this.player = info.player;
|
||||
this.player.profile().then((p) => {
|
||||
this.playerProfile = p;
|
||||
});
|
||||
this.setVisible(true);
|
||||
} else if (owner && !owner.isPlayer() && this.game.isLand(tile)) {
|
||||
if (this.game.hasFallout(tile)) {
|
||||
this.isIrradiatedWilderness = true;
|
||||
} else {
|
||||
this.isWilderness = true;
|
||||
}
|
||||
} else if (info.isWilderness || info.isIrradiatedWilderness) {
|
||||
this.isWilderness = info.isWilderness;
|
||||
this.isIrradiatedWilderness = info.isIrradiatedWilderness;
|
||||
this.setVisible(true);
|
||||
} else if (info.unit) {
|
||||
this.unit = info.unit;
|
||||
this.setVisible(true);
|
||||
} else if (!this.game.isLand(tile)) {
|
||||
const units = this.game
|
||||
.units(UnitType.Warship, UnitType.TradeShip, UnitType.TransportShip)
|
||||
.filter((u) => euclideanDistWorld(worldCoord, u.tile(), this.game) < 50)
|
||||
.sort(distSortUnitWorld(worldCoord, this.game));
|
||||
|
||||
if (units.length > 0) {
|
||||
this.unit = units[0];
|
||||
this.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
MouseOverEvent,
|
||||
} from "../../InputHandler";
|
||||
import { FrameProfiler } from "../FrameProfiler";
|
||||
import { getHoverInfo } from "../HoverInfo";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
import { TerritoryWebGLRenderer } from "./TerritoryWebGLRenderer";
|
||||
@@ -322,12 +323,14 @@ export class TerritoryLayer implements Layer {
|
||||
this.lastMousePosition.x,
|
||||
this.lastMousePosition.y,
|
||||
);
|
||||
if (!this.game.isValidCoord(cell.x, cell.y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const previousTerritory = this.highlightedTerritory;
|
||||
const territory = this.getTerritoryAtCell(cell);
|
||||
const info = getHoverInfo(this.game, cell);
|
||||
let territory: PlayerView | null = null;
|
||||
if (info.player) {
|
||||
territory = info.player;
|
||||
} else if (info.unit) {
|
||||
territory = info.unit.owner();
|
||||
}
|
||||
|
||||
if (territory) {
|
||||
this.highlightedTerritory = territory;
|
||||
@@ -342,18 +345,6 @@ export class TerritoryLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private getTerritoryAtCell(cell: { x: number; y: number }) {
|
||||
const tile = this.game.ref(cell.x, cell.y);
|
||||
if (!tile) {
|
||||
return null;
|
||||
}
|
||||
if (!this.game.hasOwner(tile)) {
|
||||
return null;
|
||||
}
|
||||
const owner = this.game.owner(tile);
|
||||
return owner instanceof PlayerView ? owner : null;
|
||||
}
|
||||
|
||||
redraw() {
|
||||
this.lastMyPlayerSmallId = this.game.myPlayer()?.smallID() ?? null;
|
||||
this.cachedTerritoryPatternsEnabled = this.userSettings.territoryPatterns();
|
||||
|
||||
Reference in New Issue
Block a user