Skip to main content
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:
ConstantValue
GathererState.GO_TO_MAIL"GOtoMAIL"
GathererState.REPAIR_SELL"REPAIR/SELL"
GathererState.METAMORPH_EZ_MINE"METAMORPH/EZ-MINE"

State values

GroupStates
LifecyclePAUSE, IDLE, RUN
MovementMOVE, MOVETO, CUSTOM_MOVE, JUMP, SKY
GatheringSCAN, CAN_GATHER_START, GATHER_START, SPORE, SEEDPLANT, ITEMUSE
Overload / skyridingOVERLOAD, OVERLOAD_ORB, CHARGEVIGOR, METAMORPH/EZ-MINE
FishingFISHING, SPOTFISHING
CombatFIGHT, FLEE, LOOTMOB, AVOID
Death recoveryDEAD, RESCUE, RES_SICKNESS
ErrandsSENDMAIL, GOtoMAIL, GUILDBANK, REPAIR/SELL, INN, HEARTSTONE
Before changing any transition, survey all read/write sites first:
rg 'State\s*(=|==|~=)\s*"' Gatherer/*.lua

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.