Jump to content

defaultSetStageOnEnter running with no actors


Recommended Posts

I'm documenting a design flaw that I've been unable to fix thus far.

Some time ago, I'd posted a bug report about:

There are 2 instances in Dawnstar. In both cases, the scenes run before the player arrives. If you run there fast enough, you can hear them in the distance talking as they walk toward their markers.

I'd instrumented them, and discovered that they were running with no actors. This should be impossible.

I'd thought that the problem was the changes US*P made long ago to one of them, setting enable parent. The log does spam out that error:

[04/21/2021 - 02:34:20PM] Error:  (00087792): cannot disable an object with an enable state parent.
stack:
	[ (00087792)].DefaultSetStageOnEnter.Disable() - "<native>" Line ?
	[ (00087792)].defaultOnEnter.TriggerMe() - "defaultOnEnter.psc" Line 145
	[ (00087792)].DefaultSetStageOnEnter.TriggerMe() - "defaultSetStageOnEnter.psc" Line 21
	[ (00087792)].DefaultSetStageOnEnter.OnTriggerEnter() - "defaultOnEnter.psc" Line 67
[04/21/2021 - 02:34:20PM] Error:  (00087792): cannot disable an object with an enable state parent.
stack:
	[ (00087792)].DefaultSetStageOnEnter.Disable() - "<native>" Line ?
	[ (00087792)].defaultOnEnter.TriggerMe() - "defaultOnEnter.psc" Line 145
	[ (00087792)].DefaultSetStageOnEnter.TriggerMe() - "defaultSetStageOnEnter.psc" Line 21
	[ (00087792)].DefaultSetStageOnEnter.OnTriggerEnter() - "defaultOnEnter.psc" Line 67
[04/21/2021 - 02:34:20PM] InitWidgetLoader()
[04/21/2021 - 02:34:20PM] Error:  (00087792): cannot disable an object with an enable state parent.
stack:
	[ (00087792)].DefaultSetStageOnEnter.Disable() - "<native>" Line ?
	[ (00087792)].defaultOnEnter.TriggerMe() - "defaultOnEnter.psc" Line 145
	[ (00087792)].DefaultSetStageOnEnter.TriggerMe() - "defaultSetStageOnEnter.psc" Line 21
	[ (00087792)].DefaultSetStageOnEnter.OnTriggerEnter() - "defaultOnEnter.psc" Line 67

The US*P added parenting of trigger 00087792 is incorrect. Instead, it should be disabled by script where CWGarrisonEnableMarkerSonsDawnstar [REFR:0002C77C] is disabled.

But why 3 times? It should only TriggerMe() once. That's a clue!

After examining these and 3 others that I've rarely or never heard, I've found that the trigger properties have set bAllTargetsInTrigger to true (default is false).

Apparently, when a property is set, code in the parent script (in this case, defaultOnEnter) cannot modify it. The defaultOnEnter function modTargetCount() is busily checking and updating bAllTargetsInTrigger, but it always remains true. So TriggerMe() runs with no actors present.

Why would Bethesda have set bAllTargetsInTrigger?

I'm guessing that otherwise it didn't ever run. A note from 2016 is currently on https://www.creationkit.com/index.php?title=OnTriggerEnter_-_ObjectReference: "If you set a trigger around a teleport door marker this event will fire for the player but not for NPCs."

These all have NPCs arriving via teleport door.

The easiest bugfix approach would be modifying the triggers to avoid the teleport doors. It looks possible. A better approach would be redesign using Story Manager along the lines of the Whiterun scene for Fralia.

There are only a few other uses of this script.

Link to comment
Share on other sites

5 hours ago, DayDreamer said:

Why would Bethesda have set bAllTargetsInTrigger

This specific trigger is configured to start a dialogue scene (via quest DialogueDawnstarIntroBrinaHorikSkaldScene; the only purpose of this quest is to start a specific scene), that involves four actors: three to take part in the dialogue (Brina, Horik and Skald) and the player to witness this. It thus makes little sense for the script to proceed before all of them are within a sufficiently short distance to each other.

DefaultOnEnter reacts to trigger enter and leave events, and will process them if any of the specified actors interacts with the trigger. Since the player is one of the specified actors, there is no NPC required..

Edited by Sclerocephalus
typos
Link to comment
Share on other sites

5 minutes ago, Sclerocephalus said:

Since the player is one of the specified actors, there is no NPC required..

Incorrect. The targetCountCurrent includes all 3 NPCs plus the player. See onTriggerEnter() and modTargetCount().

The script is running before the player arrives. The log shows that it runs for 2 NPCs, then later for the player. Presumably the NPC that isn't triggering it arrives via loading door (Skald).

However, the setstage 10 running the scene only happens at the first NPC. That's when they start talking, even though nobody else is yet present.

Link to comment
Share on other sites

Well, you're right.

On the other hand, if you believe in your own theory, it shouldn't matter what modTargetCount().is doing and TriggerMe() would run if any of the specified actors enters the trigger.

But only once because TriggerMe() changes states. Thinking of it, that actually leads to another problem: it's near to impossible that the three instances were triggered by the same actor. There should have been some delay if it was the same actor leaving and re-entering, so the state change after the first call of TriggerMe() would have left the script unable to react to the following events - unless they were delayed and fired at the same time as trigger events may do (not impossuble, but too much of a coincidence).

Link to comment
Share on other sites

Posted (edited)
On 4/22/2021 at 1:02 PM, Sclerocephalus said:

if you believe in your own theory

As I'd mentioned, my conclusion is based upon instrumentation. There are several vanilla debug lines that can be activated, and I'd added others. But nothing readily showed that bAllTargetsInTrigger stayed forever true. That's some kind of game engine bug. I'm fairly sure we've seen that in the past, but so many bugs over so many years....

Thus, all of these problems are because of a pair of game engine bugs as mentioned above: a property staying forever true, and the 2016 discovery that NPCs entering a trigger via teleport won't run the event.

I've begun a survey of all the other places using this trigger. There are 13.

Only a few set bAllTargetsInTrigger to true:

  • DawnstarExterior01
  • DawnstarExterior04 DA07IntroTrigger
  • HelgenKeep01 MQ101SetStage500
  • LeftHandMineExterior02 LeftHandMineSceneTriggerREF (DialogueLeftHandMineIntroScene)
  • MarkarthMines (DialogueMarkarthIntroBlacksmithSceneView)
  • MarkarthArnleifandSonsTradingCompany ArnleifandSonsIntroTrigger (DialogueMarkarthIntroArnleifandSonsScene)

In two cases, Bethesda (in Skyrim.esm) long ago deleted the script and replaced it.

  • MQ104TowerGrabTrigger
  • MQ105GreybeardOutroTrigger

I've also begun a survey of other triggered scenes (at least the common ones) to determine best practices. AFAICT, there are two best practices:

  1. (mostly entering cities) Start Enabled quest. Some use a trigger to start scene, others have Phase 1 GetDistance to player < 1000.
  2. Story Manager starts quest, quest fragment_0 moves the NPCs to the scene markers. Trigger, or Phase 1 has GetDistance to player < 1000.

In most cases, NPC stay at marker packages are in the scene itself. Also, US*P has modified the underlying defaultSetStageTrigSCRIPT to prevent scenes from running more than once.

The Dawnstar scenes have the NPC marker packages in the NPCs. In Skald's case, the marker package is in both the NPC and the quest alias. This duplication is definitely not best practice. US*P has modified these NPC packages to check CWGarrisonEnableMarkerSonsDawnstar. That wouldn't have been needed with the packages being in the scene, as the scene itself could be prevented from running with a single check in Story Manager.

Edited by DayDreamer
defaultSetStageTrigSCRIPT
Link to comment
Share on other sites

Posted (edited)
5 hours ago, DayDreamer said:

DawnstarExterior04 DA07IntroTrigger

 

5 hours ago, DayDreamer said:

Story Manager starts quest, quest fragment_0 moves the NPCs to the scene markers.

Turns out, that's how this one is already setup. It simply has the wrong trigger box. Control-F changed to defaultSetStageTRIGPlayerOnly using defaultSetStageTrigSCRIPT, copy over the script fields, works perfectly.

Edited by DayDreamer
defaultSetStageTrigSCRIPT
Link to comment
Share on other sites

6 hours ago, DayDreamer said:

DawnstarExterior01 (DialogueDawnstarIntroBrinaHorikSkaldScene)

Converted it to Story Manager, with condition CWGarrisonEnableMarkerSonsDawnstar [REFR:0002C77C] is enabled, to match what US*P had already done.

Control-F changed to defaultSetStageTRIGPlayerOnly using defaultSetStageTrigSCRIPT, copy over the script fields, initially disabled.

Works perfectly the next time you enter Dawnstar exterior.

(Didn't bother to move the NPC packages to the scene, although it would make the game slightly more efficient.)

 

Link to comment
Share on other sites

  • 2 weeks later...
On 4/23/2021 at 2:31 PM, DayDreamer said:

HelgenKeep01 MQ101SetStage500

I've tested a new game with the bAllTargetsInTrigger unchecked. The result is subtle. Instead of it happening as soon as the player enters, it happens after both the player and Hadvar (in my case) enter. That is, ever so slightly later.

However, carefully leave the disable flag unchecked. The disable is done by a parent. That seems to be an exclusive parent for this box. Maybe a naive design mistake. Or they added the disable after enter to the script sometime after designing Helgen.

Looking around Helgen, they've used this same box+script with only the player in multiple places. Elsewhere, most places use the defaultSetStageTRIGPlayerOnly box and script instead.

https://afktrack.afkmods.com/index.php?a=issues&i=31300

Link to comment
Share on other sites

On 4/23/2021 at 2:31 PM, DayDreamer said:

MarkarthArnleifandSonsTradingCompany ArnleifandSonsIntroTrigger (DialogueMarkarthIntroArnleifandSonsScene)

I've tested with the bAllTargetsInTrigger unchecked and the disable after enter checked. Because it's in an interior, there's no significant difference, other than now cleaning up the trigger itself afterward.

The package order and trigger box seem to be organized so that this wouldn't trigger with the occupants sleeping. But they don't lock the door. That's a bug. All that seems to happen is they are standing in different places, yet still allow you to buy/sell immediately anyway. You can enter in the middle of the night and be invited to step up to the counter. That's another bug.

The problem turns out to be their aliases in DialogueMarkarth. The packages are duplicated there. By adding a 8x16 schedule to the packages, they can fall through to their sleeping and eating packages.

https://afktrack.afkmods.com/index.php?a=issues&i=31301

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...