import { html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { assetUrl } from "../../../core/AssetUrls";
import { EventBus } from "../../../core/EventBus";
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,
TouchEvent,
} from "../../InputHandler";
import {
getTranslatedPlayerTeamLabel,
renderDuration,
renderNumber,
renderTroops,
translateText,
} from "../../Utils";
import {
EMOJI_ICON_KIND,
getFirstPlacePlayer,
getPlayerIcons,
IMAGE_ICON_KIND,
} from "../PlayerIcons";
import { TransformHandler } from "../TransformHandler";
import { ImmunityBarVisibleEvent } from "./ImmunityTimer";
import { Layer } from "./Layer";
import { CloseRadialMenuEvent } from "./RadialMenu";
import "./RelationSmiley";
import { SpawnBarVisibleEvent } from "./SpawnTimer";
const soldierIconAquarius = assetUrl("images/SoldierIconAquarius.svg");
const allianceIcon = assetUrl("images/AllianceIcon.svg");
const warshipIcon = assetUrl("images/BattleshipIconWhite.svg");
const cityIcon = assetUrl("images/CityIconWhite.svg");
const factoryIcon = assetUrl("images/FactoryIconWhite.svg");
const goldCoinIcon = assetUrl("images/GoldCoinIcon.svg");
const missileSiloIcon = assetUrl("images/MissileSiloIconWhite.svg");
const portIcon = assetUrl("images/PortIcon.svg");
const samLauncherIcon = assetUrl("images/SamLauncherIconWhite.svg");
const soldierIcon = assetUrl("images/SoldierIcon.svg");
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 })
public game!: GameView;
@property({ type: Object })
public eventBus!: EventBus;
@property({ type: Object })
public transform!: TransformHandler;
@state()
private player: PlayerView | null = null;
@state()
private playerProfile: PlayerProfile | null = null;
@state()
private unit: UnitView | null = null;
@state()
private _isInfoVisible: boolean = false;
@state()
private spawnBarVisible = false;
@state()
private immunityBarVisible = false;
private _isActive = false;
private get barOffset(): number {
return (this.spawnBarVisible ? 7 : 0) + (this.immunityBarVisible ? 7 : 0);
}
private lastMouseUpdate = 0;
init() {
this.eventBus.on(MouseMoveEvent, (e: MouseMoveEvent) =>
this.onMouseEvent(e),
);
this.eventBus.on(ContextMenuEvent, (e: ContextMenuEvent) =>
this.maybeShow(e.x, e.y),
);
this.eventBus.on(TouchEvent, (e: TouchEvent) => this.maybeShow(e.x, e.y));
this.eventBus.on(CloseRadialMenuEvent, () => this.hide());
this.eventBus.on(SpawnBarVisibleEvent, (e) => {
this.spawnBarVisible = e.visible;
});
this.eventBus.on(ImmunityBarVisibleEvent, (e) => {
this.immunityBarVisible = e.visible;
});
this._isActive = true;
}
private onMouseEvent(event: MouseMoveEvent) {
const now = Date.now();
if (now - this.lastMouseUpdate < 100) {
return;
}
this.lastMouseUpdate = now;
this.maybeShow(event.x, event.y);
}
public hide() {
this.setVisible(false);
this.unit = null;
this.player = null;
}
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 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;
this.player.profile().then((p) => {
this.playerProfile = p;
});
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);
}
}
}
tick() {
this.requestUpdate();
}
renderLayer(context: CanvasRenderingContext2D) {
// Implementation for Layer interface
}
shouldTransform(): boolean {
return false;
}
setVisible(visible: boolean) {
this._isInfoVisible = visible;
this.requestUpdate();
}
private getPlayerNameColor(isFriendly: boolean): string {
if (isFriendly) return "text-green-500";
return "text-white";
}
private getRelationSmiley(
player: PlayerView,
myPlayer: PlayerView | null | undefined,
): TemplateResult | string {
if (!myPlayer || myPlayer === player || player.type() !== PlayerType.Nation)
return "";
const relation =
this.playerProfile?.relations[myPlayer.smallID()] ?? Relation.Neutral;
if (relation === Relation.Neutral) return "";
return html`