Jump to content

[Papyrus Help] Attempting To use OnInit For Timer To Control Scene


Recommended Posts

Hello everyone,

 

I am more used to Skyrim than Fallout 4 in terms of scripting, and am running into a roadblock anytime I picked up the Fallout 4 Creation Kit for scripting. I am attempting to make a small quest mod where the player runs into Diamond City, and is greeted by a messenger bot with a message to go back to Vault 111.

 

I have a logic cell setup with the required NPCs, and have an object reference in the cell with the following script:

 

 

 

Scriptname AJDBTInitQuestController extends ObjectReference

Quest Property AJDBTQuestForTheVaultTecHomebrew Auto

Event OnInit()
	;Game.GetPlayer().AddItem(AJDBTHolotape, 1)

	StartTimerGameTime(1)

EndEvent

Event OnTimerGameTime(int aiTimerID)
	if (AJDBTQuestForTheVaultTecHomebrew != None)
		;Determine if we need to startup our Dialogue Controller
		if (!AJDBTDialogueController.IsRunning())
			AJDBTDialogueController.Start()

			While (AJDBTDialogueController.IsStarting())
				;Spin
			EndWhile
		EndIf

		;Ensure that the scene has not been done before
		if (AJDBTDialogueController.GetStage() < 1)
			;Verify the distance
			Actor Player = Game.GetPlayer()
			
			If ((AJDBTDiamondCitySceneStartMarker.GetDistance(Game.GetPlayer()) <= 250.0))
				;Force first person
				Game.ForceFirstPerson()
				
				;Disable player controls
				InputEnableLayer myLayer = InputEnableLayer.Create()
				myLayer.DisablePlayerControls(true, true, false, true, true, true, true, true, true, true, true)
				
				;Give a notification that controls have been disabled
				Game.ShakeController(0.75, 0.75, 2)
				
				;Move the eyebot
				AJDBTEyebotMessenger.Enable()
				AJDBTEyebotMessenger.MoveTo(AJDBTDiamondCityEntrance)
				
				;Move everything else to kill each other in Vault 111
				AJDBTVaultTecRoboticOperative.Enable()
				AJDBTVaultTecRoboticOperative.MoveTo(AJDBTVault111Marker)
				AJDBTLvlRaider.Enable()
				
				;Figure out how many raiders to move to Vault | 2 by default
				If (Player.GetLevel() < 10)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 2)
				ElseIf (Player.GetLevel() < 20)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 3)
				ElseIf (Player.GetLevel() < 30)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 4)
				ElseIf (Player.GetLevel() < 40)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 5)
				ElseIf (Player.GetLevel() < 50)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 6)
				ElseIf (Player.GetLevel() < 60)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 7)
				Else
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 9)
				EndIf	
			
				;Start the Scene
				AJDBTDialogueControllerEyebotScene.ForceStart()
			EndIf
		Else
			;Re-register the timer
			StartTimerGameTime(0.033)
		EndIf
	else
		;Cancel our timer for sure
		CancelTimerGameTime()
	EndIf

EndEvent
Actor Property AJDBTVaultTecRoboticOperative Auto

Holotape Property AJDBTHolotape Auto

Actor Property AJDBTEyebotMessenger Auto Const

Quest Property AJDBTDialogueController Auto Const

Actor Property AJDBTLvlRaider Auto Const

Scene Property AJDBTDialogueControllerEyebotScene Auto Const

ObjectReference Property AJDBTDiamondCityEntrance Auto Const

ObjectReference Property AJDBTDiamondCitySceneStartMarker Auto Const

ObjectReference Property AJDBTLogicCellMarker Auto Const

ObjectReference Property AJDBTVault111Marker Auto Const

 

 

 

On my existing save (clean of mods), I go to the Diamond City location which is designed to trigger the quest after fast traveling from Far Harbor, but nothing is happening. Is there something I should be doing something different in the Fallout 4 scripting environment?

Edited by Arron Dominion
Link to comment
Share on other sites

The issue is likely that the player is further away than 250 from that marker and if that's the case your OnTimer exits and never registers itself again. The fix will be adding an else statement after your GetDistance call and calling

StartTimerGameTime(0.033)

in the else statement.

Fixed code:

Scriptname AJDBTInitQuestController extends ObjectReference

Quest Property AJDBTQuestForTheVaultTecHomebrew Auto

Event OnInit()
    ;Game.GetPlayer().AddItem(AJDBTHolotape, 1)

    StartTimerGameTime(1)

EndEvent

Event OnTimerGameTime(int aiTimerID)
    if (AJDBTQuestForTheVaultTecHomebrew != None)
        ;Determine if we need to startup our Dialogue Controller
        if (!AJDBTDialogueController.IsRunning())
            AJDBTDialogueController.Start()

            While (AJDBTDialogueController.IsStarting())
                ;Spin
            EndWhile
        EndIf

        ;Ensure that the scene has not been done before
        if (AJDBTDialogueController.GetStage() < 1)
            ;Verify the distance
            Actor Player = Game.GetPlayer()
            
            If ((AJDBTDiamondCitySceneStartMarker.GetDistance(Game.GetPlayer()) <= 250.0))
                ;Force first person
                Game.ForceFirstPerson()
                
                ;Disable player controls
                InputEnableLayer myLayer = InputEnableLayer.Create()
                myLayer.DisablePlayerControls(true, true, false, true, true, true, true, true, true, true, true)
                
                ;Give a notification that controls have been disabled
                Game.ShakeController(0.75, 0.75, 2)
                
                ;Move the eyebot
                AJDBTEyebotMessenger.Enable()
                AJDBTEyebotMessenger.MoveTo(AJDBTDiamondCityEntrance)
                
                ;Move everything else to kill each other in Vault 111
                AJDBTVaultTecRoboticOperative.Enable()
                AJDBTVaultTecRoboticOperative.MoveTo(AJDBTVault111Marker)
                AJDBTLvlRaider.Enable()
                
                ;Figure out how many raiders to move to Vault | 2 by default
                If (Player.GetLevel() < 10)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 2)
                ElseIf (Player.GetLevel() < 20)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 3)
                ElseIf (Player.GetLevel() < 30)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 4)
                ElseIf (Player.GetLevel() < 40)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 5)
                ElseIf (Player.GetLevel() < 50)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 6)
                ElseIf (Player.GetLevel() < 60)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 7)
                Else
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 9)
                EndIf    
            
                ;Start the Scene
                AJDBTDialogueControllerEyebotScene.ForceStart()
            else
                ;Re-register the timer  
                StartTimerGameTime(0.033)
           endif
        Else
            ;Re-register the timer
            StartTimerGameTime(0.033)
        EndIf
    else
        ;Cancel our timer for sure
        CancelTimerGameTime()
    EndIf

EndEvent
Actor Property AJDBTVaultTecRoboticOperative Auto

Holotape Property AJDBTHolotape Auto

Actor Property AJDBTEyebotMessenger Auto Const

Quest Property AJDBTDialogueController Auto Const

Actor Property AJDBTLvlRaider Auto Const

Scene Property AJDBTDialogueControllerEyebotScene Auto Const

ObjectReference Property AJDBTDiamondCityEntrance Auto Const

ObjectReference Property AJDBTDiamondCitySceneStartMarker Auto Const

ObjectReference Property AJDBTLogicCellMarker Auto Const

ObjectReference Property AJDBTVault111Marker Auto Const
Edited by Reneer
Link to comment
Share on other sites

 

The issue is likely that the player is further away than 250 from that marker and if that's the case your OnTimer exits and never registers itself again. The fix will be adding an else statement after your GetDistance call and calling

StartTimerGameTime(0.033)

in the else statement.

 

Fixed code:

Scriptname AJDBTInitQuestController extends ObjectReference

Quest Property AJDBTQuestForTheVaultTecHomebrew Auto

Event OnInit()
    ;Game.GetPlayer().AddItem(AJDBTHolotape, 1)

    StartTimerGameTime(1)

EndEvent

Event OnTimerGameTime(int aiTimerID)
    if (AJDBTQuestForTheVaultTecHomebrew != None)
        ;Determine if we need to startup our Dialogue Controller
        if (!AJDBTDialogueController.IsRunning())
            AJDBTDialogueController.Start()

            While (AJDBTDialogueController.IsStarting())
                ;Spin
            EndWhile
        EndIf

        ;Ensure that the scene has not been done before
        if (AJDBTDialogueController.GetStage() < 1)
            ;Verify the distance
            Actor Player = Game.GetPlayer()
            
            If ((AJDBTDiamondCitySceneStartMarker.GetDistance(Game.GetPlayer()) <= 250.0))
                ;Force first person
                Game.ForceFirstPerson()
                
                ;Disable player controls
                InputEnableLayer myLayer = InputEnableLayer.Create()
                myLayer.DisablePlayerControls(true, true, false, true, true, true, true, true, true, true, true)
                
                ;Give a notification that controls have been disabled
                Game.ShakeController(0.75, 0.75, 2)
                
                ;Move the eyebot
                AJDBTEyebotMessenger.Enable()
                AJDBTEyebotMessenger.MoveTo(AJDBTDiamondCityEntrance)
                
                ;Move everything else to kill each other in Vault 111
                AJDBTVaultTecRoboticOperative.Enable()
                AJDBTVaultTecRoboticOperative.MoveTo(AJDBTVault111Marker)
                AJDBTLvlRaider.Enable()
                
                ;Figure out how many raiders to move to Vault | 2 by default
                If (Player.GetLevel() < 10)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 2)
                ElseIf (Player.GetLevel() < 20)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 3)
                ElseIf (Player.GetLevel() < 30)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 4)
                ElseIf (Player.GetLevel() < 40)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 5)
                ElseIf (Player.GetLevel() < 50)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 6)
                ElseIf (Player.GetLevel() < 60)
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 7)
                Else
                    AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 9)
                EndIf    
            
                ;Start the Scene
                AJDBTDialogueControllerEyebotScene.ForceStart()
            else
                ;Re-register the timer  
                StartTimerGameTime(0.033)
           endif
        Else
            ;Re-register the timer
            StartTimerGameTime(0.033)
        EndIf
    else
        ;Cancel our timer for sure
        CancelTimerGameTime()
    EndIf

EndEvent
Actor Property AJDBTVaultTecRoboticOperative Auto

Holotape Property AJDBTHolotape Auto

Actor Property AJDBTEyebotMessenger Auto Const

Quest Property AJDBTDialogueController Auto Const

Actor Property AJDBTLvlRaider Auto Const

Scene Property AJDBTDialogueControllerEyebotScene Auto Const

ObjectReference Property AJDBTDiamondCityEntrance Auto Const

ObjectReference Property AJDBTDiamondCitySceneStartMarker Auto Const

ObjectReference Property AJDBTLogicCellMarker Auto Const

ObjectReference Property AJDBTVault111Marker Auto Const

 

Doh! I missed that when I was going over the script. I have added the missing Else for the re-register of the timer and decided for testing's sake to increase the distance from 250 to 1000. The results are not any different.

 

I decided to go a step further and add a Debug message in the OnInit with the message not firing. I have this script attached to a random static inside of a cell that the player will never reach. Are scripts not fired in this scenario for Fallout 4?

Edited by Arron Dominion
Link to comment
Share on other sites

Doh! I missed that when I was going over the script. I have added the missing Else for the re-register of the timer and decided for testing's sake to increase the distance from 250 to 1000. The results are not any different.

 

I decided to go a step further and add a Debug message in the OnInit with the message not firing. I have this script attached to a random static inside of a cell that the player will never reach. Are scripts not fired in this scenario for Fallout 4?

If the player is never within the cell that the static is also in, no, the script / the OnInit will never fire because the object it is attached to is never loaded (unless the reference is marked as persistent). What you seem to be looking for is using this in a Quest script instead of an ObjectReference.

Edited by Reneer
Link to comment
Share on other sites

I changed the quest containing the scene to a Start Game Enabled Quest, and it has the flags Run Once and Warn On Alias failure enabled. The quest has a single alias for the AJDBTEyebotMessenger NPC, and it is set to UniqueActor | Not Optional | Allow Reuse in Quest

 

In stage 0 of the quest, I have the Run on start? checked, and in the Papyrus Fragment section I have the following call:

(AJDBTDialogueController as AJDBTDialogueControllerQuestScript).RegisterGameTime()

Here is the quest script that I am using:

 

 

Scriptname AJDBTDialogueControllerQuestScript extends Quest
{This script controls when to start the required scene.}

Actor Property AJDBTEyebotMessenger Auto Const

Actor Property AJDBTVaultTecOperative Auto Const

ObjectReference Property AJDBTVault111Marker Auto Const

Actor[] Property AJDBTRaiders Auto

Actor Property AJDBTLvlRaider Auto Const

ObjectReference Property AJDBTDiamondCityEntrance Auto Const

ObjectReference Property AJDBTDiamondCitySceneStartMarker Auto Const

Quest Property AJDBTDialogueController Auto Const

Quest Property AJDBTQuestForTheVaultTecHomebrew Auto Const

Scene Property AJDBTDialogueControllerEyebotScene Auto Const

Event OnTimerGameTime(int aiTimerID)
		;Ensure that the scene has not been done before
		if (AJDBTDialogueController.GetStage() < 1)
			;Verify the distance
			Actor Player = Game.GetPlayer()
			
			If ((AJDBTDiamondCitySceneStartMarker.GetDistance(Game.GetPlayer()) <= 1000.0))
				;Force first person
				Game.ForceFirstPerson()
				
				;Disable player controls
				InputEnableLayer myLayer = InputEnableLayer.Create()
				myLayer.DisablePlayerControls(true, true, false, true, true, true, true, true, true, true, true)
				
				;Give a notification that controls have been disabled
				Game.ShakeController(0.75, 0.75, 2)
				
				;Move the eyebot
				AJDBTEyebotMessenger.Enable()
				AJDBTEyebotMessenger.MoveTo(AJDBTDiamondCityEntrance)
				
				;Move everything else to kill each other in Vault 111
				AJDBTVaultTecOperative.Enable()
				AJDBTVaultTecOperative.MoveTo(AJDBTVault111Marker)
				AJDBTLvlRaider.Enable()
				
				;Figure out how many raiders to move to Vault | 2 by default
				If (Player.GetLevel() < 10)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 2)
				ElseIf (Player.GetLevel() < 20)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 3)
				ElseIf (Player.GetLevel() < 30)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 4)
				ElseIf (Player.GetLevel() < 40)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 5)
				ElseIf (Player.GetLevel() < 50)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 6)
				ElseIf (Player.GetLevel() < 60)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 7)
				Else
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 9)
				EndIf	
			
				;Start the Scene
				AJDBTDialogueControllerEyebotScene.ForceStart()
			Else
				;Re-register the timer
				StartTimerGameTime(0.033)
			EndIf
		Else
			
		EndIf
EndEvent

Function RegisterGameTime()
	StartTimerGameTime(0.033)
EndFunction

Function HandleSceneEnd()
	;Re-enable player controls
	InputEnableLayer myLayer = InputEnableLayer.Create()
	myLayer.EnablePlayerControls()
	
	;Remove the Eyebot...goodbye dear F.H.A.M.M.
	AJDBTEyebotMessenger.MoveTo(AJDBTLogicCellMarker)
	AJDBTEyebotMessenger.Disable()

	;Start the quest
	AJDBTQuestForTheVaultTecHomebrew.Start()
	
	AJDBTQuestForTheVaultTecHomebrew.SetStage(10)
	AJDBTQuestForTheVaultTecHomebrew.SetObjectiveDisplayed(10)
EndFunction



ObjectReference Property AJDBTLogicCellMarker Auto Const

 

 

 

None of the actions contained within the distance segment of the IF...ELSE are firing. Am I screwing something up in setting up the quest, or is there an accepted practice I should be trying instead for setting up a quest with dialogue?

Link to comment
Share on other sites

I changed the quest containing the scene to a Start Game Enabled Quest, and it has the flags Run Once and Warn On Alias failure enabled. The quest has a single alias for the AJDBTEyebotMessenger NPC, and it is set to UniqueActor | Not Optional | Allow Reuse in Quest

 

In stage 0 of the quest, I have the Run on start? checked, and in the Papyrus Fragment section I have the following call:

(AJDBTDialogueController as AJDBTDialogueControllerQuestScript).RegisterGameTime()

Here is the quest script that I am using:

 

 

Scriptname AJDBTDialogueControllerQuestScript extends Quest
{This script controls when to start the required scene.}

Actor Property AJDBTEyebotMessenger Auto Const

Actor Property AJDBTVaultTecOperative Auto Const

ObjectReference Property AJDBTVault111Marker Auto Const

Actor[] Property AJDBTRaiders Auto

Actor Property AJDBTLvlRaider Auto Const

ObjectReference Property AJDBTDiamondCityEntrance Auto Const

ObjectReference Property AJDBTDiamondCitySceneStartMarker Auto Const

Quest Property AJDBTDialogueController Auto Const

Quest Property AJDBTQuestForTheVaultTecHomebrew Auto Const

Scene Property AJDBTDialogueControllerEyebotScene Auto Const

Event OnTimerGameTime(int aiTimerID)
		;Ensure that the scene has not been done before
		if (AJDBTDialogueController.GetStage() < 1)
			;Verify the distance
			Actor Player = Game.GetPlayer()
			
			If ((AJDBTDiamondCitySceneStartMarker.GetDistance(Game.GetPlayer()) <= 1000.0))
				;Force first person
				Game.ForceFirstPerson()
				
				;Disable player controls
				InputEnableLayer myLayer = InputEnableLayer.Create()
				myLayer.DisablePlayerControls(true, true, false, true, true, true, true, true, true, true, true)
				
				;Give a notification that controls have been disabled
				Game.ShakeController(0.75, 0.75, 2)
				
				;Move the eyebot
				AJDBTEyebotMessenger.Enable()
				AJDBTEyebotMessenger.MoveTo(AJDBTDiamondCityEntrance)
				
				;Move everything else to kill each other in Vault 111
				AJDBTVaultTecOperative.Enable()
				AJDBTVaultTecOperative.MoveTo(AJDBTVault111Marker)
				AJDBTLvlRaider.Enable()
				
				;Figure out how many raiders to move to Vault | 2 by default
				If (Player.GetLevel() < 10)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 2)
				ElseIf (Player.GetLevel() < 20)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 3)
				ElseIf (Player.GetLevel() < 30)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 4)
				ElseIf (Player.GetLevel() < 40)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 5)
				ElseIf (Player.GetLevel() < 50)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 6)
				ElseIf (Player.GetLevel() < 60)
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 7)
				Else
					AJDBTVault111Marker.PlaceAtMe(AJDBTLvlRaider, 9)
				EndIf	
			
				;Start the Scene
				AJDBTDialogueControllerEyebotScene.ForceStart()
			Else
				;Re-register the timer
				StartTimerGameTime(0.033)
			EndIf
		Else
			
		EndIf
EndEvent

Function RegisterGameTime()
	StartTimerGameTime(0.033)
EndFunction

Function HandleSceneEnd()
	;Re-enable player controls
	InputEnableLayer myLayer = InputEnableLayer.Create()
	myLayer.EnablePlayerControls()
	
	;Remove the Eyebot...goodbye dear F.H.A.M.M.
	AJDBTEyebotMessenger.MoveTo(AJDBTLogicCellMarker)
	AJDBTEyebotMessenger.Disable()

	;Start the quest
	AJDBTQuestForTheVaultTecHomebrew.Start()
	
	AJDBTQuestForTheVaultTecHomebrew.SetStage(10)
	AJDBTQuestForTheVaultTecHomebrew.SetObjectiveDisplayed(10)
EndFunction



ObjectReference Property AJDBTLogicCellMarker Auto Const

 

 

 

None of the actions contained within the distance segment of the IF...ELSE are firing. Am I screwing something up in setting up the quest, or is there an accepted practice I should be trying instead for setting up a quest with dialogue?

 

Well, I'd say that the next logical step is to see if anything prior to that GetDistance IF call is happening. You basically have three possibilities (other than the script just not running at all):

 

1. The game timer isn't registering or firing properly.

 

2. The AJDBTDialogueController quest stage is never 0.

 

3. Something's up with your marker. Try swapping the values in that IF condition, so that you're comparing "Player.GetDistance(AJDBTDiamondCitySceneStartMarker)" rather than running the GetDistance on the marker.

 

Throw a few debug.notification lines in there and find out exactly which one's the problem. When the messages stop displaying, you know which one it is.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...