# Nexus.Engine & Nexus.Systems — Bot Brain ## BotEngine (Orchestrator) The main loop. Owns systems, navigation, profiles, and action execution. ### Logic Loop (25Hz, background thread) ``` 1. Wait for MemoryPoller to provide latest GameState 2. CheckCharacterProfile() → auto-load profile if character changed 3. GameStateEnricher.Enrich() → compute NearestEnemies, ThreatMap, DangerLevel 4. Clear ActionQueue 5. NavigationController.Update(state) → compute path, set DesiredDirection 6. Run all ISystem implementations in priority order 7. NavigationSystem submits MoveAction if DesiredDirection is set 8. ActionQueue.Resolve() → merge conflicts 9. ExecuteActions() → emit key/mouse/click commands via IInputController ``` ### Action Execution | Action | Execution | |--------|-----------| | MoveAction | Direction → MovementKeyTracker → WASD key state changes (delta-based) | | CastAction | SmoothMoveTo target + key press. Re-projects moving entities. Adds ±30-50px jitter. | | FlaskAction | Direct key press | | KeyAction | Press/Down/Up operations | | ClickAction | Left/Right/Middle click at screen position | ### MovementKeyTracker Converts world-space direction vectors to WASD keys for isometric camera: ``` 1. Rotate direction 45° to align with isometric axes 2. sx = dir.X * cos(45°) - dir.Y * sin(45°) 3. sy = dir.X * sin(45°) + dir.Y * cos(45°) 4. W if sy > 0.3, S if sy < -0.3, D if sx > 0.3, A if sx < -0.3 5. Only emit key changes (delta-based — no redundant KeyDown/KeyUp) ``` ### Mouse Drift (Navigation) During navigation, lazily repositions the mouse toward enemy clusters: - Projects enemy centroid ahead of player movement - Applies ±25° angular offset for organic appearance - Fires every 800-1500ms (randomized) ### Safety - Releases all held keys when loading screen or escape menu detected - CombatSystem's `ReleaseAllHeld()` called on state transitions --- ## Systems ### ThreatSystem (Priority 50) Emergency threat response. Runs first, only acts on elevated danger. | Danger | Response | |--------|----------| | Safe / Low | No action | | Medium | No action (MovementSystem handles soft avoidance) | | High | Flee toward safety (priority 50, allows casting) | | Critical or point-blank (<150 units) | **Urgent flee (priority 5) — blocks all casting** | **Flee direction**: `Player.Position - ThreatCentroid`, validated against terrain via `FindWalkableDirection()`. ### MovementSystem (Priority 100) Continuous soft avoidance via **inverse-square repulsion field**. For each hostile monster within SafeDistance (400 units): ``` force += (playerPos - enemyPos) / distanceSquared * RepulsionWeight ``` Normalizes sum, validates against terrain, submits as lower-priority MoveAction. Effect: Player gently drifts away from enemies without hard fleeing. ### AreaProgressionSystem (Priority 199) High-level area traversal. Runs before NavigationSystem to take precedence. **State machine (7 phases):** ``` Exploring → Looting → NavigatingToChest → InteractingChest → NavigatingToTransition → Interacting → TalkingToNpc ``` **Exploration strategy:** 1. Check for elite enemies (Rare/Unique within 800u) → yield to combat 2. Check for quest chests → navigate and interact 3. Check for loot (if danger ≤ Low) → pick up within 600u 4. Once fully explored → find area transition matching quest target 5. In towns with active quest → talk to NPC **Quest integration**: Queries active quests for target areas. Prioritizes tracked quests, then lowest act, then shortest path. Blacklists failed transitions after 5s timeout. **Navigation delegation**: Uses `NavigationController.NavigateToEntity()` and `.Explore()`. Sets targets and yields until reached. ### NavigationSystem (Priority 200) Ultra-thin passthrough. If `NavigationController.DesiredDirection` is set, submits a MoveAction. All actual pathfinding logic lives in NavigationController (see [pathfinding.md](pathfinding.md)). ### CombatSystem (Priority 300) Skill rotation and target selection. Hot-swappable via CharacterProfile. **Rotation loop:** ``` 1. Check global cooldown (skip if recently cast) 2. For each skill in priority order: a. Check per-skill cooldown b. Match skill to memory via slot index (fallback to name) c. If aura: cast once per zone d. If damage: find target → submit CastAction 3. Release held keys for skills without valid targets ``` **Target selection pipeline:** ``` 1. Filter by TargetSelection (Nearest, Rarest, MagicPlus, RarePlus, UniqueOnly) 2. Filter by range (SkillProfile.RangeMin/RangeMax) 3. Filter by line-of-sight (terrain query) 4. Check MinMonstersInRange (AOE threshold) 5. Pick best: Rarest mode → prefer higher rarity then nearer; others → nearest 6. Project to screen coordinates ``` **Skill input types:** - LeftClick/RightClick/MiddleClick: Direct click at target position - KeyPress with MaintainPressed: Hold key continuously - KeyPress normal: Single tap **Kiting/orbit (during global cooldown):** - Computes enemy centroid - Moves perpendicular to centroid (orbital movement) - Applies radial bias to maintain ideal distance - Flips orbit direction if terrain blocks path - Persists orbit sign across ticks for smooth motion **Cooldown management:** - Per-skill: `max(skill.CooldownMs, globalCd + 50)` for rotation - MaintainPressed skills: use skill.CooldownMs directly - Area reset: clears aura tracking, resets orbit ### ResourceSystem (Priority 400) Flask automation based on life/mana thresholds. ``` if LifePercent < LifeFlaskThreshold (50%) && cooldown expired → FlaskAction if ManaPercent < ManaFlaskThreshold (50%) && cooldown expired → FlaskAction ``` Flask cooldown: 4000ms default. Hot-swappable on character profile change. ### LootSystem (Priority 500) Stub — disabled by default. Item pickup logic handled by AreaProgressionSystem's looting phase. --- ## System Interaction Diagram ``` GameState (read-only, shared) │ ├─→ ThreatSystem ──→ MoveAction (priority 5 or 50) │ [blocks casting if priority ≤ 10] │ ├─→ MovementSystem ──→ MoveAction (priority 100) │ [soft repulsion, overridable] │ ├─→ AreaProgressionSystem ──→ NavigateTo/Explore commands │ [drives NavigationController] │ ├─→ NavigationSystem ──→ MoveAction (priority 200) │ [passthrough from NavigationController] │ ├─→ CombatSystem ──→ CastAction (priority 300) │ [skill rotation + target selection] │ ├─→ ResourceSystem ──→ FlaskAction (priority 400) │ [always passes through] │ └─→ ActionQueue.Resolve() │ ├── Highest MoveAction wins ├── CastAction passes unless blocked by urgent flee ├── FlaskAction always passes └──→ ExecuteActions() → IInputController ```