mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-26 12:34:36 +00:00
ee4b91a422
## Description: Adds back the nuke overlay for teammates ## 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: Mr. Box
188 lines
5.1 KiB
TypeScript
188 lines
5.1 KiB
TypeScript
import { renderNumber } from "src/client/Utils";
|
|
import { EventBus } from "src/core/EventBus";
|
|
import { UnitType } from "src/core/game/Game";
|
|
import {
|
|
BonusEventUpdate,
|
|
ConquestUpdate,
|
|
GameUpdateType,
|
|
} from "src/core/game/GameUpdates";
|
|
import type { GameView, UnitView } from "../../../core/game/GameView";
|
|
import { MoveWarshipIntentEvent } from "../../Transport";
|
|
import { TransformHandler } from "../TransformHandler";
|
|
import { MoveIndicatorUI } from "../ui/MoveIndicatorUI";
|
|
import { NavalTarget } from "../ui/NavalTarget";
|
|
import { NukeTelegraph } from "../ui/NukeTelegraph";
|
|
import { TextIndicator } from "../ui/TextIndicator";
|
|
import { UIElement } from "../ui/UIElement";
|
|
import { Layer } from "./Layer";
|
|
|
|
const TEXT_OFFSET_Y = -5;
|
|
const TEXT_STACK_SPACING = 8;
|
|
const TEXT_DURATION = 2500;
|
|
|
|
export class DynamicUILayer implements Layer {
|
|
private readonly uiElements: Array<UIElement> = [];
|
|
private lastRefresh = Date.now();
|
|
|
|
constructor(
|
|
private readonly game: GameView,
|
|
private transformHandler: TransformHandler,
|
|
private eventBus: EventBus,
|
|
) {}
|
|
|
|
init() {
|
|
// Listen for warship move clicks for MoveIndicatorUI
|
|
this.eventBus.on(MoveWarshipIntentEvent, (e) => {
|
|
const x = this.game.x(e.tile);
|
|
const y = this.game.y(e.tile);
|
|
this.uiElements.push(new MoveIndicatorUI(this.transformHandler, x, y));
|
|
});
|
|
}
|
|
|
|
shouldTransform(): boolean {
|
|
return false;
|
|
}
|
|
|
|
tick() {
|
|
if (!this.game.config().userSettings()?.fxLayer()) {
|
|
return;
|
|
}
|
|
|
|
const updates = this.game.updatesSinceLastTick();
|
|
if (!updates) return;
|
|
|
|
updates[GameUpdateType.Unit]?.forEach((unit) => {
|
|
const unitView = this.game.unit(unit.id);
|
|
if (!unitView) return;
|
|
this.onUnitEvent(unitView);
|
|
});
|
|
|
|
updates[GameUpdateType.BonusEvent]?.forEach((bonusEvent) => {
|
|
if (bonusEvent === undefined) return;
|
|
this.onBonusEvent(bonusEvent);
|
|
});
|
|
|
|
updates[GameUpdateType.ConquestEvent]?.forEach((update) => {
|
|
if (update === undefined) return;
|
|
this.onConquestEvent(update);
|
|
});
|
|
}
|
|
|
|
onBonusEvent(bonus: BonusEventUpdate) {
|
|
// Only display text fx for the current player
|
|
if (this.game.player(bonus.player) !== this.game.myPlayer()) {
|
|
return;
|
|
}
|
|
const tile = bonus.tile;
|
|
const x = this.game.x(tile);
|
|
let y = this.game.y(tile) + TEXT_OFFSET_Y;
|
|
const gold = bonus.gold;
|
|
const troops = bonus.troops;
|
|
|
|
if (gold !== 0) {
|
|
this.addNumber(gold, x, y, 1000, 10);
|
|
y += TEXT_STACK_SPACING; // increase y so the next popup starts below
|
|
}
|
|
|
|
if (troops !== 0) {
|
|
this.addNumber(troops, x, y, 1000, 10);
|
|
}
|
|
}
|
|
|
|
onConquestEvent(conquest: ConquestUpdate) {
|
|
// Only display text for the current player
|
|
const conqueror = this.game.player(conquest.conquerorId);
|
|
if (conqueror !== this.game.myPlayer()) {
|
|
return;
|
|
}
|
|
const nameLocation = this.game.player(conquest.conqueredId).nameLocation();
|
|
const x = nameLocation.x;
|
|
const y = nameLocation.y;
|
|
this.addNumber(conquest.gold, x, y + 8, TEXT_DURATION, 0);
|
|
}
|
|
|
|
onUnitEvent(unit: UnitView) {
|
|
switch (unit.type()) {
|
|
case UnitType.HydrogenBomb:
|
|
case UnitType.AtomBomb: {
|
|
this.onBombEvent(unit);
|
|
break;
|
|
}
|
|
case UnitType.TransportShip: {
|
|
this.onTransportShipEvent(unit);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
onBombEvent(unit: UnitView) {
|
|
const myPlayer = this.game.myPlayer();
|
|
if (!myPlayer) {
|
|
return;
|
|
}
|
|
if (
|
|
this.createdThisTick(unit) &&
|
|
(unit.owner() === myPlayer || unit.owner().isOnSameTeam(myPlayer))
|
|
) {
|
|
const target = new NukeTelegraph(this.transformHandler, this.game, unit);
|
|
this.uiElements.push(target);
|
|
}
|
|
}
|
|
|
|
onTransportShipEvent(unit: UnitView) {
|
|
const myPlayer = this.game.myPlayer();
|
|
if (!myPlayer) {
|
|
return;
|
|
}
|
|
if (this.createdThisTick(unit) && unit.owner() === myPlayer) {
|
|
const target = new NavalTarget(this.transformHandler, this.game, unit);
|
|
this.uiElements.push(target);
|
|
}
|
|
}
|
|
|
|
renderLayer(context: CanvasRenderingContext2D) {
|
|
const now = Date.now();
|
|
const dt = now - this.lastRefresh;
|
|
this.lastRefresh = now;
|
|
if (this.game.config().userSettings()?.fxLayer()) {
|
|
this.renderUIElements(context, dt);
|
|
}
|
|
}
|
|
|
|
renderUIElements(context: CanvasRenderingContext2D, delta: number) {
|
|
for (let i = this.uiElements.length - 1; i >= 0; i--) {
|
|
if (!this.uiElements[i].render(context, delta)) {
|
|
this.uiElements.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
private createdThisTick(unit: UnitView): boolean {
|
|
return unit.createdAt() === this.game.ticks();
|
|
}
|
|
|
|
private addNumber(
|
|
num: bigint | number,
|
|
x: number,
|
|
y: number,
|
|
duration: number,
|
|
riseDistance: number,
|
|
) {
|
|
if (BigInt(num) === 0n) return; // Don't show anything for 0
|
|
const absNum =
|
|
typeof num === "bigint" ? (num < 0n ? -num : num) : Math.abs(num);
|
|
const shortened = renderNumber(absNum, 0);
|
|
const sign = num >= 0 ? "+" : "-";
|
|
this.uiElements.push(
|
|
new TextIndicator(
|
|
this.transformHandler,
|
|
`${sign} ${shortened}`,
|
|
x,
|
|
y,
|
|
duration,
|
|
riseDistance,
|
|
),
|
|
);
|
|
}
|
|
}
|