Bomb target location (same logic as naval invasions) (#2309)

## Description:

Added logic to hydro/atom bombs - using same FX as the boat invasion
(keeping PR smaller, can add more UX for hydro/atoms later)

Only you & teammates can see the target.

<img width="747" height="356" alt="image"
src="https://github.com/user-attachments/assets/bc1aaec0-8b41-4def-92ee-9f076a8cd550"
/>


Viewpoint from two players:
<img width="1667" height="680" alt="image"
src="https://github.com/user-attachments/assets/76e96ad1-af09-4584-a71a-823c85b6e26b"
/>



## 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:

w.o.n
This commit is contained in:
Ryan Barlow
2025-10-28 09:03:33 +00:00
committed by GitHub
parent cb744b49fc
commit 7dd45e8dd4
+36 -2
View File
@@ -30,6 +30,7 @@ export class FxLayer implements Layer {
private allFx: Fx[] = [];
private boatTargetFxByUnitId: Map<number, TargetFx> = new Map();
private nukeTargetFxByUnitId: Map<number, TargetFx> = new Map();
constructor(private game: GameView) {
this.theme = this.game.config().theme();
@@ -87,6 +88,28 @@ export class FxLayer implements Layer {
}
}
// Register a persistent nuke target marker for the current player or teammates
private createNukeTargetFxIfOwned(unit: UnitView) {
const my = this.game.myPlayer();
if (!my) return;
// Show nuke marker owned by the player or by players on the same team
if (
(unit.owner() === my || my.isOnSameTeam(unit.owner())) &&
unit.isActive()
) {
if (!this.nukeTargetFxByUnitId.has(unit.id())) {
const t = unit.targetTile();
if (t !== undefined) {
const x = this.game.x(t);
const y = this.game.y(t);
const fx = new TargetFx(x, y, 0, true);
this.allFx.push(fx);
this.nukeTargetFxByUnitId.set(unit.id(), fx);
}
}
}
}
onBonusEvent(bonus: BonusEventUpdate) {
if (this.game.player(bonus.player) !== this.game.myPlayer()) {
// Only display text fx for the current player
@@ -135,13 +158,19 @@ export class FxLayer implements Layer {
}
break;
}
case UnitType.AtomBomb:
case UnitType.AtomBomb: {
this.createNukeTargetFxIfOwned(unit);
this.onNukeEvent(unit, 160);
break;
}
case UnitType.MIRVWarhead:
this.onNukeEvent(unit, 70);
break;
case UnitType.HydrogenBomb:
case UnitType.HydrogenBomb: {
this.createNukeTargetFxIfOwned(unit);
this.onNukeEvent(unit, 160);
break;
}
case UnitType.Warship:
this.onWarshipEvent(unit);
break;
@@ -270,6 +299,11 @@ export class FxLayer implements Layer {
onNukeEvent(unit: UnitView, radius: number) {
if (!unit.isActive()) {
const fx = this.nukeTargetFxByUnitId.get(unit.id());
if (fx) {
fx.end();
this.nukeTargetFxByUnitId.delete(unit.id());
}
if (!unit.reachedTarget()) {
this.handleSAMInterception(unit);
} else {