ab473c6b68
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
28 lines
1.2 KiB
Nim
28 lines
1.2 KiB
Nim
## Gun selector — picks best gun×power, computes aim angle, gates firing.
|
||
## Fires highest power with acceptable hit rate when gun is aimed within
|
||
## threshold and gunHeat == 0.
|
||
|
||
import std/math
|
||
import gun_interface
|
||
import virtual_bullets
|
||
|
||
const AimThresholdDeg* = 2.0 ## max angle error to fire; ponytail: tune per bot
|
||
|
||
proc aimAngle*(selfX, selfY, targetX, targetY: float): float =
|
||
## Absolute bearing in degrees (0=East, CCW+) toward (targetX, targetY).
|
||
result = radToDeg(arctan2(targetY - selfY, targetX - selfX))
|
||
|
||
proc shouldFire*(currentGunDir, targetAngle, gunHeat: float): bool =
|
||
## Returns true when gun is close enough and cool enough to fire.
|
||
var delta = (targetAngle - currentGunDir) mod 360.0
|
||
if delta > 180.0: delta -= 360.0
|
||
elif delta < -180.0: delta += 360.0
|
||
abs(delta) <= AimThresholdDeg and gunHeat <= 0.0
|
||
|
||
proc selectShot*(t: VirtualTracker, targetId: int = -1): (GunId, int, float) =
|
||
## Returns (gunId, powerBinIdx, power) — the shot to take this tick.
|
||
## Pass targetId to pick the best gun for that specific enemy.
|
||
let gunId = t.bestGun(targetId)
|
||
let (binIdx, power) = t.bestPower(gunId, targetId)
|
||
result = (gunId, binIdx, power)
|