mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 07:50:45 +00:00
wire nuke trajectory + blast radius into the build ghost preview
NukeTrajectoryPass and the rangeRadius pipe existed but had no caller — trajectory arc and outer-blast circle never appeared during build mode. BuildPreviewController now picks the closest active player silo as the launch source, collects non-allied SAMs as threats, and pushes a NukeTrajectoryData each preview tick. rangeRadius is set to nukeMagnitudes(type).outer for AtomBomb / HydrogenBomb so the existing RangeCirclePass renders the blast radius at the target.
This commit is contained in:
@@ -22,7 +22,8 @@ import {
|
||||
MouseMoveEvent,
|
||||
MouseUpEvent,
|
||||
} from "../InputHandler";
|
||||
import { GameView as WebGLGameView } from "../render/gl";
|
||||
import { GameView as WebGLGameView, buildNukeTrajectory } from "../render/gl";
|
||||
import type { SAMInfo } from "../render/gl/utils/nuke-trajectory";
|
||||
import type { GhostPreviewData } from "../render/types";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import {
|
||||
@@ -222,9 +223,88 @@ export class BuildPreviewController implements Controller {
|
||||
if (data === null) {
|
||||
this.lastGhostData = null;
|
||||
this.view.updateGhostPreview(null);
|
||||
} else {
|
||||
this.lastGhostData = data;
|
||||
}
|
||||
this.updateNukeTrajectoryPreview(tileRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* For AtomBomb / HydrogenBomb ghosts, push the Bezier trajectory preview
|
||||
* (closest player-owned silo → target, accounting for non-allied SAMs).
|
||||
* Cleared whenever the ghost isn't a nuke, has no target, or the player
|
||||
* has no silos.
|
||||
*/
|
||||
private updateNukeTrajectoryPreview(tileRef: TileRef | undefined): void {
|
||||
if (!this.ghostUnit || tileRef === undefined) {
|
||||
this.view.updateNukeTrajectory(null);
|
||||
return;
|
||||
}
|
||||
this.lastGhostData = data;
|
||||
const type = this.ghostUnit.buildableUnit.type;
|
||||
if (type !== UnitType.AtomBomb && type !== UnitType.HydrogenBomb) {
|
||||
this.view.updateNukeTrajectory(null);
|
||||
return;
|
||||
}
|
||||
const myPlayer = this.game.myPlayer();
|
||||
if (!myPlayer) {
|
||||
this.view.updateNukeTrajectory(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const silos = myPlayer
|
||||
.units(UnitType.MissileSilo)
|
||||
.filter((u) => u.isActive());
|
||||
if (silos.length === 0) {
|
||||
this.view.updateNukeTrajectory(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const dstX = this.game.x(tileRef);
|
||||
const dstY = this.game.y(tileRef);
|
||||
let bestSilo = silos[0];
|
||||
let bestDistSq = Infinity;
|
||||
for (const s of silos) {
|
||||
const sx = this.game.x(s.tile());
|
||||
const sy = this.game.y(s.tile());
|
||||
const dx = sx - dstX;
|
||||
const dy = sy - dstY;
|
||||
const d = dx * dx + dy * dy;
|
||||
if (d < bestDistSq) {
|
||||
bestDistSq = d;
|
||||
bestSilo = s;
|
||||
}
|
||||
}
|
||||
const srcX = this.game.x(bestSilo.tile());
|
||||
const srcY = this.game.y(bestSilo.tile());
|
||||
|
||||
// Non-allied SAMs threaten the trajectory; own + allied SAMs don't.
|
||||
const allyIds = new Set<number>();
|
||||
for (const a of myPlayer.allies()) allyIds.add(a.smallID());
|
||||
const sams: SAMInfo[] = [];
|
||||
for (const s of this.game.units(UnitType.SAMLauncher)) {
|
||||
if (!s.isActive()) continue;
|
||||
const owner = s.owner();
|
||||
if (owner === myPlayer) continue;
|
||||
if (allyIds.has(owner.smallID())) continue;
|
||||
const r = this.game.config().samRange(s.level());
|
||||
sams.push({
|
||||
x: this.game.x(s.tile()),
|
||||
y: this.game.y(s.tile()),
|
||||
rangeSq: r * r,
|
||||
});
|
||||
}
|
||||
|
||||
this.view.updateNukeTrajectory(
|
||||
buildNukeTrajectory(
|
||||
srcX,
|
||||
srcY,
|
||||
dstX,
|
||||
dstY,
|
||||
this.game.height(),
|
||||
this.uiState.rocketDirectionUp,
|
||||
sams,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private buildGhostPreviewData(
|
||||
@@ -243,11 +323,17 @@ export class BuildPreviewController implements Controller {
|
||||
upgradeTargetTile = this.game.unit(u.canUpgrade)?.tile() ?? null;
|
||||
}
|
||||
|
||||
// Range circle: only meaningful for SAM placement preview.
|
||||
// Range circle: SAM placement preview shows targetable radius; nuke
|
||||
// previews show the outer blast radius at the target tile.
|
||||
let rangeRadius = 0;
|
||||
if (u.type === UnitType.SAMLauncher) {
|
||||
const level = this.resolveGhostRangeLevel(u) ?? 1;
|
||||
rangeRadius = this.game.config().samRange(level);
|
||||
} else if (
|
||||
u.type === UnitType.AtomBomb ||
|
||||
u.type === UnitType.HydrogenBomb
|
||||
) {
|
||||
rangeRadius = this.game.config().nukeMagnitudes(u.type).outer;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -345,6 +431,7 @@ export class BuildPreviewController implements Controller {
|
||||
this.uiState.ghostRailPaths = [];
|
||||
this.lastGhostData = null;
|
||||
this.view.updateGhostPreview(null);
|
||||
this.view.updateNukeTrajectory(null);
|
||||
}
|
||||
|
||||
private removeGhostStructure() {
|
||||
|
||||
Reference in New Issue
Block a user