diff --git a/src/client/BuildSettingsModal.ts b/src/client/BuildSettingsModal.ts index f01cf67d2..ef7ad6ac6 100644 --- a/src/client/BuildSettingsModal.ts +++ b/src/client/BuildSettingsModal.ts @@ -38,7 +38,7 @@ export class BuildSettingsModal extends LitElement { return { id, name: id, - icon: unitIconMap[id] || "", + icon: unitIconMap[id] ?? "", }; }); const persisted = this._loadPersisted(); diff --git a/src/client/Transport.ts b/src/client/Transport.ts index 9b80c1093..8cb9b3800 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -423,6 +423,12 @@ export class Transport { console.error("socket is null"); return; } + // Notify the client code that we are connected (mirrors local behavior) + try { + this.onconnect?.(); + } catch (err) { + console.error("Error in onconnect handler:", err); + } while (this.buffer.length > 0) { console.log("sending dropped message"); const msg = this.buffer.pop(); diff --git a/src/client/Utils.ts b/src/client/Utils.ts index c99f80939..14697d7e2 100644 --- a/src/client/Utils.ts +++ b/src/client/Utils.ts @@ -165,6 +165,7 @@ export function getMessageTypeClasses(type: MessageType): string { switch (type) { case MessageType.SAM_HIT: case MessageType.CAPTURED_ENEMY_UNIT: + case MessageType.TRADE_SHIP_CAPTURED_ENEMY: case MessageType.RECEIVED_GOLD_FROM_TRADE: case MessageType.CONQUERED_PLAYER: case MessageType.INSURANCE_REFUND: @@ -174,6 +175,8 @@ export function getMessageTypeClasses(type: MessageType): string { case MessageType.ALLIANCE_BROKEN: case MessageType.UNIT_CAPTURED_BY_ENEMY: case MessageType.UNIT_DESTROYED: + case MessageType.TRADE_SHIP_CAPTURED: + case MessageType.TRADE_SHIP_SUNK: return severityColors["fail"]; case MessageType.ATTACK_CANCELLED: case MessageType.ATTACK_REQUEST: @@ -192,6 +195,7 @@ export function getMessageTypeClasses(type: MessageType): string { case MessageType.PARATROOPER_INBOUND: case MessageType.WARN: case MessageType.PEACE_TIMER_BLOCKED: + case MessageType.TRADE_SHIP_TURNED_AROUND: return severityColors["warn"]; case MessageType.WAR_DECLARED: return severityColors["warn"]; // war start: highlight prominently diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 0fe4b3ec3..a21e89695 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -22,6 +22,7 @@ import { NameLayer } from "./layers/NameLayer"; import { OptionsMenu } from "./layers/OptionsMenu"; import { PlayerInfoOverlay } from "./layers/PlayerInfoOverlay"; import { PlayerPanel } from "./layers/PlayerPanel"; +import { PointerCoordsLayer } from "./layers/PointerCoordsLayer"; import { RadialMenu } from "./layers/RadialMenu"; import { RangeOverlayLayer } from "./layers/RangeOverlayLayer"; import { ReplayPanel } from "./layers/ReplayPanel"; @@ -38,6 +39,9 @@ import { UILayer } from "./layers/UILayer"; import { UnitLayer } from "./layers/UnitLayer"; import { WinModal } from "./layers/WinModal"; +// Debug flags (keep off for normal gameplay) +const DEBUG_SHOW_POINTER_COORDS = false; + export function createRenderer( canvas: HTMLCanvasElement, game: GameView, @@ -246,6 +250,10 @@ export function createRenderer( new NameLayer(game, transformHandler, eventBus), // UI layer comes after world-space drawing to minimize save/restore new UILayer(game, eventBus, transformHandler), + // Pointer coordinates (screen-space, debug only) + ...(DEBUG_SHOW_POINTER_COORDS + ? [new PointerCoordsLayer(game, eventBus, transformHandler)] + : []), eventsDisplay, chatDisplay, new RadialMenu( diff --git a/src/client/graphics/layers/ControlPanel2.ts b/src/client/graphics/layers/ControlPanel2.ts index 774bb2e42..4e06e6937 100644 --- a/src/client/graphics/layers/ControlPanel2.ts +++ b/src/client/graphics/layers/ControlPanel2.ts @@ -10,7 +10,7 @@ import { UnitType, UpgradeType, } from "../../../core/game/Game"; -import { GameView, PlayerView } from "../../../core/game/GameView"; +import { GameView, PlayerView, UnitView } from "../../../core/game/GameView"; import { getTechMeta, RESEARCH_TECH_IDS } from "../../../core/tech/TechEffects"; // Ensure modal custom elements register at runtime import "../../BuildSettingsModal"; @@ -87,7 +87,8 @@ export class ControlPanel2 extends LitElement implements Layer { private init_: boolean = false; @state() - private activeTab: "Build" | "Attack" | "Economy" | "Bombers" = "Build"; + private activeTab: "Build" | "Attack" | "Economy" | "Bombers" | "Trade" = + "Build"; @state() private _lastAirfieldCount: number = 0; @@ -237,6 +238,11 @@ export class ControlPanel2 extends LitElement implements Layer { super.disconnectedCallback(); } + // Restore disabled shadow DOM so legacy global CSS and querySelector usage continue working + protected createRenderRoot(): HTMLElement | DocumentFragment { + return this; // Render into light DOM + } + init() { this.attackRatio = Number( localStorage.getItem("settings.attackRatio") ?? "0.3", @@ -883,7 +889,7 @@ export class ControlPanel2 extends LitElement implements Layer { private _openBuildSettings() { const modal = - (document.querySelector("build-settings-modal") as any) || + (document.querySelector("build-settings-modal") as any) ?? this._ensureBuildSettingsModal(); if (!modal) { console.warn("BuildSettingsModal element not found or failed to create"); @@ -950,7 +956,9 @@ export class ControlPanel2 extends LitElement implements Layer { return el; } - private _changeTab(tab: "Build" | "Attack" | "Economy" | "Bombers") { + private _changeTab( + tab: "Build" | "Attack" | "Economy" | "Bombers" | "Trade", + ) { this.activeTab = tab; if (this.uiState.pendingBuildUnitType) { this.uiState.pendingBuildUnitType = null; @@ -1170,6 +1178,15 @@ export class ControlPanel2 extends LitElement implements Layer { > Economy + ${this._hasAirfields ? html`