WanderAction
Agent action implementing the NPC wandering behavior loop. The agent moves between random waypoints at varying speeds, periodically visits the store area, and exits when a purchasable item is found — setting sequence variables for downstream trade actions.
Definition
Namespace: Paragon.Townskeep.AgentSystem
Assembly: Townskeep.dll
public class WanderAction : AgentActionInheritance: Action → AgentAction → WanderAction
Remarks
WanderAction is the most complex agent action — it combines exploration, speed management, and shop interaction detection into a single behavior loop. It typically serves as the first action in a trade sequence, responsible for discovering items to buy.
Execution Flow
Waypoint System
The action expects a scene hierarchy:
Wander Waypoints (GameObject)
├── Waypoint1 ← random wander target
├── Waypoint2 ← random wander target
├── ...
├── Connection ← hub waypoint (returned to between wanders)
└── Store ← triggers item search when reachedWander targets — all children except "Connection" and "Store"
Connection target — the hub waypoint; the agent always returns here between random wanders
Store target — when reached, the agent checks display tables for available items
Speed Management
When moving toward the store, speed adjusts based on distance:
< 2 units
Motor.SetWalk(true) — slow approach
< 5 units
Motor.SetWalk(false) — normal speed
≥ 5 units
Motor.SetSprint(true) — sprint
For all non-store waypoints, the agent always sprints.
Variable Outputs
When a purchasable item is found, WanderAction sets two sequence variables that downstream actions consume:
Quick Lookup
Start wandering behavior
Add WanderAction to the beginning of an ActionSequence
Configure waypoints
Create "Wander Waypoints" GameObject with child transforms
Access found item
Read sequence.GetVariable<Item>("Item") in next action
Access found table
Read sequence.GetVariable<Table>("Table") in next action
Fields
targetTable
Table
[Variable] private
The display table with an available item (set on discovery)
currentTarget
Transform
[Variable] private
The current movement target waypoint
wanderTargets
List<Transform>
private
All non-special wander waypoints
connectionTarget
Transform
private
The "Connection" hub waypoint
storeTarget
Transform
private
The "Store" waypoint that triggers item checks
displayTables
List<Table>
private
All tables named "Display Table" in the scene
moveAction
MoveToTargetAction
private
Sub-action for NavMesh-based movement
Methods
OnBegin
Finds all "Display Table" objects, parses the "Wander Waypoints" hierarchy into categories, and creates a MoveToTargetAction.
OnExecute
Runs the wander loop: picks random waypoints, moves to them, checks for items at the store, and returns when an item is found.
MoveToWaypoint (private)
Moves to a waypoint with a random ±3 unit offset. Uses distance-based speed adjustment when targeting the store, or sprints for all other waypoints.
waypoint
Transform
The waypoint to move toward
GetRandomWanderTarget (private)
Returns a random waypoint from wanderTargets.
Common Pitfalls
Scene-dependent object lookup
OnBegin() uses FindObjectsByType<Table> (filtered by name) and GameObject.Find("Wander Waypoints"). If these objects don't exist in the scene, NullReferenceException will be thrown.
Waypoint naming convention is strict
Children named "Connection" and "Store" are filtered by exact string match. Typos or different casing will cause First() to throw InvalidOperationException.
Random offset can go off NavMesh
MoveToWaypoint adds Random.insideUnitCircle * 3f to the target position. If the waypoint is near the NavMesh boundary, the offset position may be unreachable, causing MoveToTargetAction to loop indefinitely.
Store movement uses Execute() not ExecuteAsync()
When targeting the store, the code calls moveAction.Execute() (fire-and-forget) and then manually polls moveAction.IsRunning in a while loop. This is different from the await moveAction.ExecuteAsync() pattern used for non-store waypoints — the manual polling allows speed adjustments each frame.
Item reservation is immediate
shopItem.SetReserve(true) is called as soon as an available item is found, before the agent has navigated to or picked up the item. If the AI sequence fails later, the item may remain reserved.
Sprint mode persists after MoveToWaypoint
Motor.SetSprint(true) is called for non-store waypoints but is never explicitly reset. The speed management in store approach (SetWalk(true/false), SetSprint(true)) handles the transition, but if the action completes or is cancelled mid-sprint, the sprint state may persist.
Infinite wander if no items available
The action loops indefinitely (while (IsRunning)) until it finds a display table with HasAvailableItem == true. If no items are ever stocked, the agent wanders forever.
See Also
AgentAction — abstract base with agent context
MoveToTargetAction — the movement primitive used for waypoint navigation
GoToStoreAction — navigates to display table (used after item found)
GrabItemAction — picks up the discovered item
GoToTradeAction — navigates to trading table
TradeItemAction — places item and initiates trade
Actions Overview — subsystem architecture
Last updated