11import { EventBus } from "../../../core/EventBus" ;
22import { UnitType } from "../../../core/game/Game" ;
33import { TileRef } from "../../../core/game/GameMap" ;
4- import { GameUpdateType } from "../../../core/game/GameUpdates" ;
5- import { GameView , PlayerView , UnitView } from "../../../core/game/GameView" ;
4+ import { GameView } from "../../../core/game/GameView" ;
65import { ParabolaPathFinder } from "../../../core/pathfinding/PathFinding" ;
76import { GhostStructureChangedEvent , MouseMoveEvent } from "../../InputHandler" ;
87import { TransformHandler } from "../TransformHandler" ;
@@ -23,8 +22,6 @@ export class NukeTrajectoryPreviewLayer implements Layer {
2322 private currentGhostStructure : UnitType | null = null ;
2423 // Cache spawn tile to avoid expensive player.actions() calls
2524 private cachedSpawnTile : TileRef | null = null ;
26- // Track SAM launcher IDs -> SAM launcher unit
27- private readonly enemySAMLaunchers : Map < number , UnitView > = new Map ( ) ;
2825
2926 constructor (
3027 private game : GameView ,
@@ -56,7 +53,6 @@ export class NukeTrajectoryPreviewLayer implements Layer {
5653 }
5754
5855 tick ( ) {
59- this . updateSAMs ( ) ;
6056 this . updateTrajectoryPreview ( ) ;
6157 }
6258
@@ -66,72 +62,6 @@ export class NukeTrajectoryPreviewLayer implements Layer {
6662 this . drawTrajectoryPreview ( context ) ;
6763 }
6864
69- /**
70- * Check for updates to the list of SAMS for intercept prediction
71- */
72- private updateSAMs ( ) {
73- // Check for updates to SAM launchers
74- const updates = this . game . updatesSinceLastTick ( ) ;
75- const unitUpdates = updates ?. [ GameUpdateType . Unit ] ;
76- const allianceResponse = updates ?. [ GameUpdateType . AllianceRequestReply ] ;
77- const allianceBroke = updates ?. [ GameUpdateType . BrokeAlliance ] ;
78- const allianceExpired = updates ?. [ GameUpdateType . AllianceExpired ] ;
79-
80- if ( unitUpdates ) {
81- for ( const update of unitUpdates ) {
82- const unit = this . game . unit ( update . id ) ;
83- if ( ! unit || unit . type ( ) !== UnitType . SAMLauncher ) continue ;
84- if ( this . enemySAMLaunchers . has ( update . id ) && ! unit . isActive ( ) ) {
85- // SAM was destroyed
86- this . enemySAMLaunchers . delete ( update . id ) ;
87- } else if ( unit . isActive ( ) ) {
88- // New SAM was built or owner swap, check if friendly.
89- if (
90- ! unit . owner ( ) . isMe ( ) &&
91- ! this . game . myPlayer ( ) ?. isFriendly ( unit . owner ( ) )
92- ) {
93- this . enemySAMLaunchers . set ( update . id , unit ) ;
94- } else if ( this . enemySAMLaunchers . has ( update . id ) ) {
95- this . enemySAMLaunchers . delete ( update . id ) ;
96- }
97- }
98- }
99- }
100- for ( const update of allianceResponse ?? [ ] ) {
101- if ( update . accepted ) {
102- // check for good SAMs
103- this . enemySAMLaunchers . forEach ( ( sam , sam_id ) => {
104- if ( this . game . myPlayer ( ) ?. isFriendly ( sam . owner ( ) ) ) {
105- this . enemySAMLaunchers . delete ( sam_id ) ;
106- }
107- } ) ;
108- break ;
109- }
110- }
111- const checkPlayers : number [ ] = [ ] ;
112- for ( const update of allianceBroke ?? [ ] ) {
113- if ( this . game . myPlayer ( ) ?. smallID ( ) === update . traitorID ) {
114- checkPlayers . push ( update . betrayedID ) ;
115- } else if ( this . game . myPlayer ( ) ?. smallID ( ) === update . betrayedID ) {
116- checkPlayers . push ( update . traitorID ) ;
117- }
118- }
119- for ( const update of allianceExpired ?? [ ] ) {
120- if ( this . game . myPlayer ( ) ?. smallID ( ) === update . player1ID ) {
121- checkPlayers . push ( update . player2ID ) ;
122- } else if ( this . game . myPlayer ( ) ?. smallID ( ) === update . player2ID ) {
123- checkPlayers . push ( update . player1ID ) ;
124- }
125- }
126- for ( const playerID of checkPlayers ) {
127- const player = this . game . playerBySmallID ( playerID ) as PlayerView ;
128- if ( ! player ) continue ;
129- for ( const sam of player . units ( UnitType . SAMLauncher ) ) {
130- this . enemySAMLaunchers . set ( sam . id ( ) , sam ) ;
131- }
132- }
133- }
134-
13565 /**
13666 * Update trajectory preview - called from tick() to cache spawn tile via expensive player.actions() call
13767 * This only runs when target tile changes, minimizing worker thread communication
@@ -325,10 +255,21 @@ export class NukeTrajectoryPreviewLayer implements Layer {
325255 // Check trajectory
326256 for ( let i = 0 ; i < this . trajectoryPoints . length ; i ++ ) {
327257 const tile = this . trajectoryPoints [ i ] ;
328- for ( const [ , sam ] of this . enemySAMLaunchers . entries ( ) ) {
329- const samTile = sam . tile ( ) ;
330- const r = this . game . config ( ) . samRange ( sam . level ( ) ) ;
331- if ( this . game . euclideanDistSquared ( tile , samTile ) <= r ** 2 ) {
258+ for ( const sam of this . game . nearbyUnits (
259+ tile ,
260+ this . game . config ( ) . maxSamRange ( ) ,
261+ UnitType . SAMLauncher ,
262+ ) ) {
263+ if (
264+ sam . unit . owner ( ) . isMe ( ) ||
265+ this . game . myPlayer ( ) ?. isFriendly ( sam . unit . owner ( ) )
266+ ) {
267+ continue ;
268+ }
269+ if (
270+ sam . distSquared <=
271+ this . game . config ( ) . samRange ( sam . unit . level ( ) ) ** 2
272+ ) {
332273 this . targetedIndex = i ;
333274 break ;
334275 }
0 commit comments