## Flee Threshold Changes
- Reduced flee threshold from AttackRadius2+4 to AttackRadius2 (no buffer)
- Modified bots: farmer, gatherer, siege
- Bots now only consider enemies in actual attack range, not preemptively
- Added outnumber logic: only flee when nearbyAllies < nearbyEnemies
## Behavior Vector Changes
- Derive aggression from actual kill rate (not self-reported)
- Formula: behaviorVec[0] = min(killRate, 1.0)
- Preserves existing economy value or defaults to 0.5
- Enhanced logging to show derived aggression value
## Rationale
Aggression must be economically necessary, not just rewarded.
Previous flee logic created a false safe option that discouraged combat.
Now bots only flee when actually outnumbered within combat range.
Related: bf-413 genesis bead tracking mechanics iteration
- Remove omitempty tag from Events field in ReplayTurn
- Create a proper slice copy of gs.Events in RecordTurn
- Prevents null events array in JSON output
- Fixes parsing errors in analysis scripts
Closes: bf-6amz0, bf-3l7tf
Strategy bots (GathererBot, RusherBot, SwarmBot) now move toward zone
center when within 2 tiles of the zone edge, not just when outside.
This anticipates the shrinking zone and prevents bots from moving
away from center due to energy-seeking logic.
Test results: 60% of matches now have combat deaths (3/5), up from 0%.
Zone margin of 2 tiles aligns with engine's built-in bot behavior.
Fixes gap identified in test replay where gatherer bot at distance 5
from center (zone radius 6) moved away from center and died from
zone_death instead of engaging in combat.
Closes: bf-2ham
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add ZoneBounds type to bot state structs (Go, Rust, TypeScript)
- GathererBot now moves toward zone center when outside or near edge
- Bots can see zone bounds in fog-filtered state (per plan §3.7.1)
- Fixes gofmt formatting in types.go and bot_strategies.go
This improves bot survival and combat behavior by making them
zone-aware, preventing unnecessary zone deaths when the safe area
shrinks.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The nearestEnergy variable was referenced inside findNearestEnergy() but
only declared in the caller's scope. Declare it locally and use _ in caller.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>