remove unit menu (#1338)

## Description:

This PR reverts 0b79d0be16

The unit menu adds additionally complexity, and can be unintentionally
opened on mobile when trying to build a unit.

Unit upgrades will be handled automatically:
https://github.com/openfrontio/OpenFrontIO/commit/513fcb094418f0e9405e878396bd5b3db8b34e5a

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [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:

evan
This commit is contained in:
evanpelle
2025-07-03 19:16:01 -07:00
committed by GitHub
parent 513fcb0944
commit 18889db3f0
4 changed files with 1 additions and 388 deletions
+1 -17
View File
@@ -35,7 +35,6 @@ import { TeamStats } from "./layers/TeamStats";
import { TerrainLayer } from "./layers/TerrainLayer";
import { TerritoryLayer } from "./layers/TerritoryLayer";
import { UILayer } from "./layers/UILayer";
import { UnitInfoModal } from "./layers/UnitInfoModal";
import { UnitLayer } from "./layers/UnitLayer";
import { WinModal } from "./layers/WinModal";
@@ -191,21 +190,7 @@ export function createRenderer(
}
headsUpMessage.game = game;
const unitInfoModal = document.querySelector(
"unit-info-modal",
) as UnitInfoModal;
if (!(unitInfoModal instanceof UnitInfoModal)) {
console.error("unit info modal not found");
}
unitInfoModal.game = game;
const structureLayer = new StructureLayer(
game,
eventBus,
transformHandler,
unitInfoModal,
);
unitInfoModal.structureLayer = structureLayer;
// unitInfoModal.eventBus = eventBus;
const structureLayer = new StructureLayer(game, eventBus, transformHandler);
const spawnAd = document.querySelector("spawn-ad") as SpawnAd;
if (!(spawnAd instanceof SpawnAd)) {
@@ -261,7 +246,6 @@ export function createRenderer(
teamStats,
playerPanel,
headsUpMessage,
unitInfoModal,
multiTabModal,
spawnAd,
gutterAdModal,
@@ -1,10 +1,8 @@
import { colord, Colord } from "colord";
import { Theme } from "../../../core/configuration/Config";
import { EventBus } from "../../../core/EventBus";
import { MouseUpEvent } from "../../InputHandler";
import { TransformHandler } from "../TransformHandler";
import { Layer } from "./Layer";
import { UnitInfoModal } from "./UnitInfoModal";
import cityIcon from "../../../../resources/non-commercial/images/buildings/cityAlt1.png";
import factoryIcon from "../../../../resources/non-commercial/images/buildings/factoryAlt1.png";
@@ -18,7 +16,6 @@ import { GameUpdateType } from "../../../core/game/GameUpdates";
import { GameView, UnitView } from "../../../core/game/GameView";
const underConstructionColor = colord({ r: 150, g: 150, b: 150 });
const selectedUnitColor = colord({ r: 0, g: 255, b: 255 });
// Base radius values and scaling factor for unit borders and territories
const BASE_BORDER_RADIUS = 16.5;
@@ -37,8 +34,6 @@ export class StructureLayer implements Layer {
private context: CanvasRenderingContext2D;
private unitIcons: Map<string, HTMLImageElement> = new Map();
private theme: Theme;
private selectedStructureUnit: UnitView | null = null;
private previouslySelected: UnitView | null = null;
private tempCanvas: HTMLCanvasElement;
private tempContext: CanvasRenderingContext2D;
@@ -80,14 +75,7 @@ export class StructureLayer implements Layer {
private game: GameView,
private eventBus: EventBus,
private transformHandler: TransformHandler,
private unitInfoModal: UnitInfoModal | null,
) {
if (!unitInfoModal) {
throw new Error(
"UnitInfoModal instance must be provided to StructureLayer.",
);
}
this.unitInfoModal = unitInfoModal;
this.theme = game.config().theme();
this.tempCanvas = document.createElement("canvas");
const tempContext = this.tempCanvas.getContext("2d");
@@ -132,7 +120,6 @@ export class StructureLayer implements Layer {
init() {
this.redraw();
this.eventBus.on(MouseUpEvent, (e) => this.onMouseUp(e));
}
redraw() {
@@ -228,9 +215,6 @@ export class StructureLayer implements Layer {
if (!unit.isActive()) return;
if (this.selectedStructureUnit === unit) {
borderColor = selectedUnitColor;
}
this.drawBorder(unit, borderColor, config);
// Render icon at 1/2 scale for better quality
@@ -283,84 +267,4 @@ export class StructureLayer implements Layer {
clearCell(cell: Cell) {
this.context.clearRect(cell.x * 2, cell.y * 2, 2, 2);
}
private findStructureUnitAtCell(
cell: { x: number; y: number },
maxDistance: number = 10,
): UnitView | null {
const targetRef = this.game.ref(cell.x, cell.y);
const allUnitTypes = Object.values(UnitType);
const nearby = this.game.nearbyUnits(targetRef, maxDistance, allUnitTypes);
for (const { unit } of nearby) {
if (unit.isActive() && this.isUnitTypeSupported(unit.type())) {
return unit;
}
}
return null;
}
private onMouseUp(event: MouseUpEvent) {
const cell = this.transformHandler.screenToWorldCoordinates(
event.x,
event.y,
);
if (!this.game.isValidCoord(cell.x, cell.y)) {
return;
}
const clickedUnit = this.findStructureUnitAtCell(cell);
this.previouslySelected = this.selectedStructureUnit;
if (clickedUnit) {
if (clickedUnit.owner() !== this.game.myPlayer()) {
return;
}
const wasSelected = this.previouslySelected === clickedUnit;
if (wasSelected) {
this.selectedStructureUnit = null;
if (this.previouslySelected) {
this.handleUnitRendering(this.previouslySelected);
}
this.unitInfoModal?.onCloseStructureModal();
} else {
this.selectedStructureUnit = clickedUnit;
if (
this.previouslySelected &&
this.previouslySelected !== clickedUnit
) {
this.handleUnitRendering(this.previouslySelected);
}
this.handleUnitRendering(clickedUnit);
const screenPos = this.transformHandler.worldToScreenCoordinates(cell);
const unitTile = clickedUnit.tile();
this.unitInfoModal?.onOpenStructureModal({
eventBus: this.eventBus,
unit: clickedUnit,
x: screenPos.x,
y: screenPos.y,
tileX: this.game.x(unitTile),
tileY: this.game.y(unitTile),
});
}
} else {
this.selectedStructureUnit = null;
if (this.previouslySelected) {
this.handleUnitRendering(this.previouslySelected);
}
this.unitInfoModal?.onCloseStructureModal();
}
}
public unSelectStructureUnit() {
if (this.selectedStructureUnit) {
this.previouslySelected = this.selectedStructureUnit;
this.selectedStructureUnit = null;
this.handleUnitRendering(this.previouslySelected);
}
}
}
-274
View File
@@ -1,274 +0,0 @@
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { translateText } from "../../../client/Utils";
import { EventBus } from "../../../core/EventBus";
import { UnitType } from "../../../core/game/Game";
import { GameView, UnitView } from "../../../core/game/GameView";
import {
SendCreateTrainStationIntentEvent,
SendUpgradeStructureIntentEvent,
} from "../../Transport";
import { Layer } from "./Layer";
import { StructureLayer } from "./StructureLayer";
@customElement("unit-info-modal")
export class UnitInfoModal extends LitElement implements Layer {
@property({ type: Boolean }) open = false;
@property({ type: Number }) x = 0;
@property({ type: Number }) y = 0;
@property({ type: Object }) unit: UnitView | null = null;
public game: GameView;
public structureLayer: StructureLayer | null = null;
private eventBus: EventBus;
constructor() {
super();
}
init() {}
tick() {
if (this.unit) {
this.requestUpdate();
}
}
public onOpenStructureModal = ({
eventBus,
unit,
x,
y,
tileX,
tileY,
}: {
eventBus: EventBus;
unit: UnitView;
x: number;
y: number;
tileX: number;
tileY: number;
}) => {
if (!this.game) return;
this.x = x;
this.y = y;
this.eventBus = eventBus;
const targetRef = this.game.ref(tileX, tileY);
const allUnitTypes = Object.values(UnitType);
const matchingUnits = this.game.nearbyUnits(
targetRef,
10,
allUnitTypes,
({ unit }) => unit.isActive(),
);
if (matchingUnits.length > 0) {
matchingUnits.sort((a, b) => a.distSquared - b.distSquared);
this.unit = matchingUnits[0].unit;
} else {
this.unit = null;
}
this.open = this.unit !== null;
};
public onCloseStructureModal = () => {
this.open = false;
this.unit = null;
};
connectedCallback() {
super.connectedCallback();
}
disconnectedCallback() {
super.disconnectedCallback();
}
private buildUnitTypeTranslationString(): string {
if (!this.unit) return "unit_type.unknown"; // fallback stays the same
const unitType = this.unit.type().toLowerCase().replace(/\s+/g, "_");
return `unit_type.${unitType}`;
}
static styles = css`
:host {
position: fixed;
pointer-events: none;
z-index: 1000;
}
.modal {
pointer-events: auto;
background: rgba(30, 30, 30, 0.95);
color: #f8f8f8;
border: 1px solid #555;
padding: 12px 18px;
border-radius: 8px;
min-width: 220px;
max-width: 300px;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.5);
font-family: "Segoe UI", sans-serif;
font-size: 15px;
line-height: 1.6;
backdrop-filter: blur(6px);
position: relative;
}
.modal strong {
color: #e0e0e0;
}
.close-button {
background: #d00;
color: #fff;
border: none;
border-radius: 4px;
font-size: 14px;
font-weight: bold;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
padding: 6px 12px;
}
.close-button:hover {
background: #a00;
}
.upgrade-button {
background: #3a0;
color: #fff;
border: none;
border-radius: 4px;
font-size: 14px;
font-weight: bold;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
padding: 6px 12px;
}
.upgrade-button:hover {
background: #0a0;
}
`;
render() {
if (!this.unit) return null;
const ticksLeftInCooldown = this.unit.ticksLeftInCooldown();
let configTimer;
switch (this.unit.type()) {
case UnitType.MissileSilo:
configTimer = this.game.config().SiloCooldown();
break;
case UnitType.SAMLauncher:
configTimer = this.game.config().SAMCooldown();
break;
}
let cooldown = 0;
if (ticksLeftInCooldown !== undefined && configTimer !== undefined) {
cooldown = configTimer - (this.game.ticks() - ticksLeftInCooldown);
}
const secondsLeft = Math.ceil(cooldown / 10);
return html`
<div
class="modal"
style="display: ${this.open ? "block" : "none"}; left: ${this
.x}px; top: ${this.y}px; position: absolute;"
>
<div style="margin-bottom: 8px; font-size: 16px; font-weight: bold;">
${translateText("unit_info_modal.structure_info")}
</div>
<div style="margin-bottom: 4px;">
<strong>${translateText("unit_info_modal.type")}:</strong>
${translateText(this.buildUnitTypeTranslationString()) ??
translateText("unit_info_modal.unit_type_unknown")}
<strong
style="display: ${this.game.unitInfo(this.unit.type()).upgradable
? "inline"
: "none"};"
>${translateText("unit_info_modal.level")}:</strong
>
${this.game.unitInfo(this.unit.type()).upgradable &&
this.unit.level?.()
? this.unit.level?.()
: ""}
</div>
${secondsLeft > 0
? html`<div style="margin-bottom: 4px;">
<strong>${translateText("unit_info_modal.cooldown")}</strong>
${secondsLeft}s
</div>`
: ""}
<div
style="margin-top: 14px; display: flex; justify-content: space-between;"
>
<button
@click=${() => {
if (this.unit) {
this.eventBus.emit(
new SendUpgradeStructureIntentEvent(
this.unit.id(),
this.unit.type(),
),
);
}
}}
class="upgrade-button"
title="${translateText("unit_info_modal.upgrade")}"
style="width: 100px; height: 32px; display: ${this.game.unitInfo(
this.unit.type(),
).upgradable
? "block"
: "none"};"
>
${translateText("unit_info_modal.upgrade")}
</button>
<button
@click=${() => {
if (this.unit) {
this.eventBus.emit(
new SendCreateTrainStationIntentEvent(this.unit.id()),
);
this.onCloseStructureModal();
if (this.structureLayer) {
this.structureLayer.unSelectStructureUnit();
}
}
}}
class="upgrade-button"
title="${translateText("unit_info_modal.create_station")}"
style="width: 100px; height: 32px;
display: ${this.game.config().isUnitDisabled(UnitType.Train) ||
this.unit.hasTrainStation() ||
!this.game.unitInfo(this.unit.type()).canBuildTrainStation
? "none"
: "block"};"
>
${translateText("unit_info_modal.create_station")}
</button>
<button
@click=${() => {
this.onCloseStructureModal();
if (this.structureLayer) {
this.structureLayer.unSelectStructureUnit();
}
}}
class="close-button"
title="${translateText("unit_info_modal.close")}"
style="width: 100px; height: 32px;"
>
${translateText("unit_info_modal.close")}
</button>
</div>
</div>
`;
}
}
-1
View File
@@ -369,7 +369,6 @@
<chat-modal></chat-modal>
<user-setting></user-setting>
<multi-tab-modal></multi-tab-modal>
<unit-info-modal></unit-info-modal>
<news-modal></news-modal>
<game-left-sidebar></game-left-sidebar>
<spawn-ad></spawn-ad>