Skip to content

Fix/npc ai fixes#380

Merged
BoroBongo merged 8 commits into
mainfrom
fix/npc-ai-fixes
Jun 16, 2026
Merged

Fix/npc ai fixes#380
BoroBongo merged 8 commits into
mainfrom
fix/npc-ai-fixes

Conversation

@BoroBongo

@BoroBongo BoroBongo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix NullReferenceException in ExtNpcGetDistToWp (NpcHelperService) — null check on the NPC GameObject was evaluated after accessing .transform.position; reordered to guard !npcGo first so culled/uninitialized NPCs return int.MaxValue cleanly
  • Fix null dereference in UseMob — the container!.Go null-forgiving operator was wrong; replaced with an explicit container == null guard so a mob action queued before the container is ready finishes gracefully instead of crashing
  • Fix null dereference in ContinueRoutinePrefabProps.AiHandler can be null when the action fires on a freshly respawned NPC; added fallback to GetComponent<AiHandler>(), logs a warning and early-returns if still null
  • Fix stale CurrentWayPoint/CurrentFreePoint after culling in AiHandler.ReEnableNpc — after teleporting an NPC to its routine waypoint on re-enable, the properties were never updated; subsequent ExtNpcGetDistToWp calls were operating on stale (or null) position data
  • Fix ExtAiStartState not immediately clearing the running action when stopCurrentState = true (NpcAiService) — previously the clear was deferred through the queue; now ClearState(false) runs immediately, StateEnd is zeroed, and CurrentWayPoint is nulled so the new state starts next frame rather than after the whole queue drains
  • Fix BodyState not reflecting NPC movement and AI transitions — AbstractWalkAnimationAction2 now sets BsWalk/BsRun on walk start and BsStand on stop; AiHandler.ClearState resets to BsStand; ExtAiStandUp sets BsStand immediately (before enqueuing StandUp) so Daedalus Npc_GetBodyState / C_BodyStateContains checks in the same ZS_*_Loop tick see the correct value

How to test

  1. Load any outdoor world with NPCs on routines (e.g. Old Camp)
  2. Approach an NPC that is walking toward a mob (bench/bed/fire) — verify no crash or freeze when it executes UseMob
  3. Open a dialog with an NPC mid-walk; verify Npc_GetBodyState conditions using BS_WALK evaluate correctly (NPC should not appear to be standing while visually walking)
  4. Trigger a Daedalus state change via AI_StartState with stopCurrentState = 1 — verify the NPC transitions immediately without waiting for the previous action queue to drain. -- Once you finish talking with Diego, let him take a few steps and then talk to him -> He should now stop and engage in conversation instead of ignoring and focusing on getting to his waypoint.

BoroBongo and others added 6 commits June 15, 2026 21:43
Returns int.MaxValue early when the NPC GameObject is not loaded,
preventing a NullReferenceException that blocked Tpl_1430_CALLSLEEPER
condition evaluation during the Chapter 3 ritual.
UseMob: replace container!.Go null-forgiving with explicit null check
so NPCs with no mob within 10m skip gracefully instead of crashing.

ContinueRoutine: fall back to GetComponent<AiHandler>() when the
serialised PrefabProps.AiHandler field is null, and bail out cleanly
if still missing, breaking the infinite crash→restart loop.
…change

After Npc_ExchangeRoutine (e.g. B_Story_PrepareRitual) the NPC's
Props.RoutineCurrent.Waypoint points to the new waypoint, but
Props.CurrentWayPoint still held the old pre-exchange waypoint.

GoToWp.Start() uses Props.CurrentWayPoint as the path start, so it
built a path OLD_WP→NEW_WP with OLD_WP on top of the stack.
The NPC was teleported to NEW_WP by ReEnableNpc, immediately "reached"
the top-of-stack NEW_WP, then walked backward through the path toward
OLD_WP — exactly the regression where Chapter-3 ritual NPCs spawn at
the temple and then walk away to their pre-ritual waypoints.

Fix: update Props.CurrentWayPoint (and CurrentFreePoint) to the new
spawn point inside ReEnableNpc, so GoToWp sees the correct start
position and skips the walk entirely.
BodyState was not updated when NPCs started or stopped walking, causing
Daedalus C_BodyStateContains checks (e.g. in ZS_*_Loop) to see stale values.

- AbstractWalkAnimationAction2: set BsWalk/BsRun on StartWalk, BsStand on StopWalk
- AiHandler.ClearState: reset to BsStand so interrupted NPCs don't keep walk state
- NpcAiService.ExtAiStandUp: reset BsStand immediately (not via queue) so the
  same Daedalus tick sees the correct value
- NpcAiService.ExtAiStartState: when stopCurrentState=true, abandon current state
  immediately via ClearState and clear stale WayPoint so GoToWp picks the nearest one
@BoroBongo BoroBongo marked this pull request as ready for review June 15, 2026 23:00
_mobsiScheme = _mobContainer?.Props.GetVisualScheme();

if (container!.Go == null)
if (container == null || container.Go == null)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same fix in #372, we'll have to solve the conflict regardless of which PR gets merged first

@BoroBongo BoroBongo requested a review from JaXt0r June 16, 2026 09:57
@BoroBongo BoroBongo merged commit cfa0251 into main Jun 16, 2026
@BoroBongo BoroBongo deleted the fix/npc-ai-fixes branch June 16, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants