> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lootroute.volvox.bot/llms.txt
> Use this file to discover all available pages before exploring further.

# State machine

> The Status and State globals that drive the Gatherer bot, and the Routine() dispatcher.

Two globals drive the bot:

* **`Status`** — high-level: `PAUSE`, `IDLE`, or `RUN`.
* **`State`** — fine-grained activity. `Routine()` in `Gatherer/Routine.lua` is the central dispatcher branching on `State`.

## GathererState constants

`Gatherer/Module.lua` publishes `GathererState`, a shared table of the exact state/status string constants. Use it for new or touched cross-file state writes and high-value status checks instead of raw string literals.

Most values equal their key name; three differ:

| Constant                          | Value                 |
| --------------------------------- | --------------------- |
| `GathererState.GO_TO_MAIL`        | `"GOtoMAIL"`          |
| `GathererState.REPAIR_SELL`       | `"REPAIR/SELL"`       |
| `GathererState.METAMORPH_EZ_MINE` | `"METAMORPH/EZ-MINE"` |

## State values

| Group                | States                                                                      |
| -------------------- | --------------------------------------------------------------------------- |
| Lifecycle            | `PAUSE`, `IDLE`, `RUN`                                                      |
| Movement             | `MOVE`, `MOVETO`, `CUSTOM_MOVE`, `JUMP`, `SKY`                              |
| Gathering            | `SCAN`, `CAN_GATHER_START`, `GATHER_START`, `SPORE`, `SEEDPLANT`, `ITEMUSE` |
| Overload / skyriding | `OVERLOAD`, `OVERLOAD_ORB`, `CHARGEVIGOR`, `METAMORPH/EZ-MINE`              |
| Fishing              | `FISHING`, `SPOTFISHING`                                                    |
| Combat               | `FIGHT`, `FLEE`, `LOOTMOB`, `AVOID`                                         |
| Death recovery       | `DEAD`, `RESCUE`, `RES_SICKNESS`                                            |
| Errands              | `SENDMAIL`, `GOtoMAIL`, `GUILDBANK`, `REPAIR/SELL`, `INN`, `HEARTSTONE`     |

<Tip>
  Before changing any transition, survey all read/write sites first:

  ```sh theme={null}
  rg 'State\s*(=|==|~=)\s*"' Gatherer/*.lua
  ```
</Tip>

## How the loop runs

The bot core is driven by self-rescheduling `C_Timer` loops started at file scope during load — `Fishi()`, `nodecheck()`, `fight()`, and `Routine()` among them. `Routine()` inspects `Status` and `State` each cycle and hands control to the matching handler: scanning, moving to a node, gathering, fighting, fleeing, recovering from death, or running an errand such as mailing or repairing.

`volvox:IsGathererEnabled()` (defined in `Main.lua`) reports whether the Gatherer module is enabled **and** the global `State` is not `PAUSE` or `DEAD` — useful for other modules that want to defer to the bot.

`ITEMUSE` owns ground consumable use. `Flask()` returns without landing, dismounting, or cancelling form when the player is in combat, and it drops back to `IDLE` without using a consumable when an enemy is already nearby.

`LOOTMOB` runs after combat ends when `gatherer.loot_killed_mobs` is enabled. It interacts with regular `IsObjectLootable` corpses and dead wild-node guardians (`Rumbling Oreling` / `Vengeful Lasher`) that were confirmed by combat-log `UNIT_DIED`, even when they are not flagged as normal loot. Harvest-style guardian corpses stay eligible while `LOOTMOB` is active, so delayed casts or a failed first interaction can retry until the 10-second stall timeout.

`FIGHT` chases live attackable combat targets even when threat APIs do not clearly mark the unit as targeting the player, which keeps melee characters moving into range of ranged attackers. Chase distance is measured from the target's current coordinates before movement is stopped.

`DEAD` releases the spirit, scans for the nearest Spirit Healer, and ghost-walks toward that healer. Nav movement is considered active only when `WGG.MoveAlongPath()` reports success. If nav cannot start—or if the ghost run stops making distance progress—the move falls back to WGG's documented left-click terrain movement (`WGG.MouseClick(..., 4)`). Once the ghost reaches interaction range, the existing Spirit Healer interaction and resurrection-confirmation flow runs.

`RES_SICKNESS` parks the bot after a revive while the Resurrection Sickness debuff (spell 15007) is active. Every revive path (`DeadManCheck`, the `PLAYER_ALIVE` event, and the spirit-healer interaction callback) funnels through `ResumeAfterRevive()` in `Gatherer/FlightTasks.lua`. In addition, the self-rescheduling `ResSicknessCheck()` loop polls every 0.25 seconds in every active bot state, so it still detects the debuff if Blizzard applies the aura after the initial `PLAYER_ALIVE` transition. Detection checks `C_UnitAuras.GetPlayerAuraBySpellID`, scans harmful aura data by spell ID, and falls back to `UnitAura(..., "HARMFUL")`.

On detection, `EnterResSicknessState()` enters `RES_SICKNESS`, clears the active gather target and `MOVETO` tracking, cancels the current path, and stops auto-run plus every directional/vertical movement input. `MoveTo()`, `GhostMoveTo()`, and `GathererCombatMoveTo()` also reject new movement requests while the state is active. While parked, the `Routine()` dispatcher, node scanning (`ShouldScanNodes()`), `scan()`/`nodecheck()`, flight checks, hearthstone-after-idle, and the freeze/stuck checker are all gated off, while anti-AFK and combat self-defense (`fight()` / `AgroCheck()`) stay active. Once the debuff expires, the watcher logs a success message, begins the 20-second post-revive grace, and returns to `IDLE`. Enabling the bot while the debuff is active also parks in `RES_SICKNESS` instead of `IDLE`.

## Runtime mirrors

`volvox.Gatherer` (the module object) mirrors part of the runtime state for the UI:

* `GathererModule.Status`, `.Route`, `.Points`, `.CurrentIndex` — runtime mirrors of the bot-core globals.
* `GathererModule:OnSettingChanged(key, value)` — mirrors UI/config changes into bot-core globals with side effects.
* `GathererModule:EnsureStatusFrame()` / `:UpdateStatusFrame()` — the draggable one-line status frame, refreshed at 4 Hz, gated by the `gatherer.show_status` setting.
