2cc2a3bd87
- 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
39 lines
1.3 KiB
Nim
39 lines
1.3 KiB
Nim
## Averaged-lead gun: mean prediction from linear, circular, and wall-bounce guns.
|
|
## Smooths noise when enemy movement is between analytical models.
|
|
|
|
import gun_harness/gun_interface
|
|
import guns/linear
|
|
import guns/circular
|
|
import guns/wall_bounce
|
|
|
|
type AveragedLeadGun* = object
|
|
linear: LinearGun
|
|
circular: CircularGun
|
|
wallBounce: WallBounceGun
|
|
cachedTick: int
|
|
cachedPred: GunPrediction # per-tick cache; ponytail: single cache, extend if multi-power needed
|
|
debugGraphics*: bool
|
|
|
|
proc initAveragedLeadGun*(): AveragedLeadGun =
|
|
AveragedLeadGun(wallBounce: initWallBounceGun(), debugGraphics: false)
|
|
|
|
proc predict*(g: var AveragedLeadGun, state: WorldState, bulletSpeed: float): GunPrediction =
|
|
if state.tick == g.cachedTick:
|
|
return g.cachedPred
|
|
|
|
let lp = g.linear.predict(state, bulletSpeed)
|
|
let cp = g.circular.predict(state, bulletSpeed)
|
|
let wp = g.wallBounce.predict(state, bulletSpeed)
|
|
|
|
var px = (lp.x + cp.x + wp.x) / 3.0
|
|
var py = (lp.y + cp.y + wp.y) / 3.0
|
|
px = clamp(px, BotRadius, state.arenaWidth - BotRadius)
|
|
py = clamp(py, BotRadius, state.arenaHeight - BotRadius)
|
|
|
|
g.cachedTick = state.tick
|
|
g.cachedPred = GunPrediction(x: px, y: py)
|
|
g.cachedPred
|
|
|
|
proc onResult*(g: var AveragedLeadGun, e: FeedbackEvent) =
|
|
discard # analytical average — no learning
|