Fix/npc ai fixes#380
Merged
Merged
Conversation
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
JucanAndreiDaniel
approved these changes
Jun 16, 2026
| _mobsiScheme = _mobContainer?.Props.GetVisualScheme(); | ||
|
|
||
| if (container!.Go == null) | ||
| if (container == null || container.Go == null) |
Contributor
There was a problem hiding this comment.
same fix in #372, we'll have to solve the conflict regardless of which PR gets merged first
JaXt0r
approved these changes
Jun 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ExtNpcGetDistToWp(NpcHelperService) — null check on the NPC GameObject was evaluated after accessing.transform.position; reordered to guard!npcGofirst so culled/uninitialized NPCs returnint.MaxValuecleanlyUseMob— thecontainer!.Gonull-forgiving operator was wrong; replaced with an explicitcontainer == nullguard so a mob action queued before the container is ready finishes gracefully instead of crashingContinueRoutine—PrefabProps.AiHandlercan be null when the action fires on a freshly respawned NPC; added fallback toGetComponent<AiHandler>(), logs a warning and early-returns if still nullCurrentWayPoint/CurrentFreePointafter culling inAiHandler.ReEnableNpc— after teleporting an NPC to its routine waypoint on re-enable, the properties were never updated; subsequentExtNpcGetDistToWpcalls were operating on stale (or null) position dataExtAiStartStatenot immediately clearing the running action whenstopCurrentState = true(NpcAiService) — previously the clear was deferred through the queue; nowClearState(false)runs immediately,StateEndis zeroed, andCurrentWayPointis nulled so the new state starts next frame rather than after the whole queue drainsBodyStatenot reflecting NPC movement and AI transitions —AbstractWalkAnimationAction2now setsBsWalk/BsRunon walk start andBsStandon stop;AiHandler.ClearStateresets toBsStand;ExtAiStandUpsetsBsStandimmediately (before enqueuingStandUp) so DaedalusNpc_GetBodyState/C_BodyStateContainschecks in the sameZS_*_Looptick see the correct valueHow to test
UseMobNpc_GetBodyStateconditions usingBS_WALKevaluate correctly (NPC should not appear to be standing while visually walking)AI_StartStatewithstopCurrentState = 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.