Files
SirRoboGarage/common_libs/targeting/enemy_tracker.nim
T
SirStone 2cc2a3bd87 fix(ModularBot): ram loop prevention, dead-target guards, cleaner logging
- 30-tick cooldown after ghost-stuck/timeout ram exit prevents re-entry loop
- enemy_tracker.update() skips dead bots to prevent same-tick scan resurrection
- TFIL graphics cleared when ramming is active movement
- [config] logs: white base with green-highlighted changes only
- [ram:enter] logs trigger reason and key values on false→true transition
- [death] and [target-invalid] logs retained for diagnostics
2026-09-20 20:44:45 +02:00

57 lines
1.5 KiB
Nim

## Per-enemy state table. Keyed by bot ID.
## Tank Royale: 0° = East.
import std/tables
import std/math
type
EnemyState* = object
id*: int
x*, y*: float
heading*: float ## degrees
speed*: float
energy*: float
lastSeenTick*: int
alive*: bool
EnemyTracker* = object
enemies*: Table[int, EnemyState]
proc update*(et: var EnemyTracker, botId: int, x, y, heading, speed, energy: float, tick: int) =
if botId in et.enemies and not et.enemies[botId].alive:
return # don't resurrect dead bots
et.enemies[botId] = EnemyState(id: botId, x: x, y: y, heading: heading,
speed: speed, energy: energy,
lastSeenTick: tick, alive: true)
proc markDead*(et: var EnemyTracker, botId: int) =
if botId in et.enemies:
et.enemies[botId].alive = false
proc resetRound*(et: var EnemyTracker) =
et.enemies.clear()
proc getEnemy*(et: EnemyTracker, botId: int): EnemyState =
et.enemies[botId]
proc allAlive*(et: EnemyTracker): seq[EnemyState] =
for s in et.enemies.values:
if s.alive: result.add(s)
proc closestTo*(et: EnemyTracker, x, y: float): EnemyState =
var bestDist = Inf
for s in et.enemies.values:
if not s.alive: continue
let d = hypot(s.x - x, s.y - y)
if d < bestDist:
bestDist = d
result = s
proc weakest*(et: EnemyTracker): EnemyState =
var bestEnergy = Inf
for s in et.enemies.values:
if not s.alive: continue
if s.energy < bestEnergy:
bestEnergy = s.energy
result = s