Jump to content

Help requested looking over and error proofing a script


Recommended Posts

I'm working on a version of my Wave Spawner that sends increasingly harder enemies at you, and I just wondered if anyone would look over my script and maybe find any flaws, recursions, things the compiler may have missed. It works most of the time (sometimes it delays spawning the enemies, but I think that has to do with script priority).

Scriptname _gkx_battlespawnerscript extends ObjectReference

Group SpawnLists
	LeveledActor[] Property VeryEasyArray Auto
	LeveledActor[] Property EasyArray Auto
	LeveledActor[] Property NormalArray Auto
	LeveledActor[] Property HardArray Auto
	LeveledActor[] Property VeryHardArray Auto
	LeveledActor[] Property BossArray Auto
EndGroup

Group Messages
	Message Property StartMenu Auto
	Message Property WavesStarting Auto
EndGroup

Function SpawnVeryEasy(Int NumToSpawn, Int DelayTimer)
	Int Rand = Utility.RandomInt(1, VeryEasyArray.Length)
	LeveledActor Spawn = VeryEasyArray[Rand]
	PlaceAtMe(Spawn, NumToSpawn)
	Int Delay = DelayTimer * 10
	If Delay > 180
		Delay = 180
	EndIf
	Debug.Notification("Next wave in " + Delay + " seconds.")
	Utility.Wait(Delay)
EndFunction

Function SpawnEasy(Int NumToSpawn, Int DelayTimer)
	Int Rand = Utility.RandomInt(1, EasyArray.Length)
	LeveledActor Spawn = EasyArray[Rand]
	PlaceAtMe(Spawn, NumToSpawn)
	Int Delay = DelayTimer * 15
	If Delay > 180
		Delay = 180
	EndIf
	Debug.Notification("Next wave in " + Delay + " seconds.")
	Utility.Wait(Delay)
EndFunction

Function SpawnNormal(Int NumToSpawn, Int DelayTimer)
	Int Rand = Utility.RandomInt(1, NormalArray.Length)
	LeveledActor Spawn = NormalArray[Rand]
	PlaceAtMe(Spawn, NumToSpawn)
	Int Delay = DelayTimer * 20
	If Delay > 180
		Delay = 180
	EndIf
	Debug.Notification("Next wave in " + Delay + " seconds.")
	Utility.Wait(Delay)
EndFunction

Function SpawnHard(Int NumToSpawn, Int DelayTimer)
	Int Rand = Utility.RandomInt(1, HardArray.Length)
	LeveledActor Spawn = HardArray[Rand]
	PlaceAtMe(Spawn, NumToSpawn)
	Int Delay = DelayTimer * 30
	If Delay > 180
		Delay = 180
	EndIf
	Debug.Notification("Next wave in " + Delay + " seconds.")
	Utility.Wait(Delay)
EndFunction

Function SpawnVeryHard(Int NumToSpawn, Int DelayTimer)
	Int Rand = Utility.RandomInt(1, VeryHardArray.Length)
	LeveledActor Spawn = VeryHardArray[Rand]
	PlaceAtMe(Spawn, NumToSpawn)
	Int Delay = DelayTimer * 40
	If Delay > 240
		Delay = 240
	EndIf
	Debug.Notification("Next wave in " + Delay + " seconds.")
	Utility.Wait(Delay)
EndFunction

Function SpawnBoss(Int NumToSpawn, Int DelayTimer)
	Int Rand = Utility.RandomInt(1, BossArray.Length)
	LeveledActor Spawn = BossArray[Rand]
	PlaceAtMe(Spawn, NumToSpawn)
	Int Delay = DelayTimer * 60
	If Delay > 300
		Delay = 300
	EndIf
	Debug.Notification("Next wave in " + Delay + " seconds.")
	Utility.Wait(Delay)
EndFunction

Int WaveNumber
Int WaveGroupNum


Function StartSpawning()

	While IsPowered()
		While WaveGroupNum <= 6
			If WaveGroupNum == 1
				SpawnVeryEasy(WaveNumber, WaveNumber)
			ElseIf WaveGroupNum == 2
				SpawnEasy(WaveNumber, WaveNumber)
			ElseIf WaveGroupNum == 3
				SpawnNormal(WaveNumber, WaveNumber)
			ElseIf WaveGroupNum == 4
				SpawnHard(WaveNumber, WaveNumber)
			ElseIf WaveGroupNum == 5
				SpawnVeryHard(WaveNumber, WaveNumber)
			ElseIf WaveGroupNum == 6
				SpawnBoss(WaveNumber, WaveNumber)
			EndIf
			WaveGroupNum += 1
		EndWhile
		WaveNumber += 1
		WaveGroupNum = 1
	EndWhile
		
EndFunction

Event OnPowerOn(ObjectReference akGenerator)
	Int StartChoice = StartMenu.Show()
	If StartChoice == 1
		WaveGroupNum = 1
		WaveNumber = 1
	EndIf
	WavesStarting.Show()
	StartSpawning()
EndEvent
Link to comment
Share on other sites

1 thing, champolions decompiler changes Events to Functions, so make sure anything you've cannibilzed using that is an event not a function if it begins with On. Also, you can download notepad++ and a format set for it for papyrus, to help you identify mistakes. An output log would also help you narrow down what function and what line is throwing the error. (actually that should do that when you try to compile in the CK).

 

Other than that, what is your probelm? Does it just not work sometimes? does it slow to a crawl? does it CTD? whats going on that it is not working correctly..

Link to comment
Share on other sites

The script compiles fine, no errors. Just that in-game, I sometimes get the notification that another wave will spawn in x seconds, and nothing spawns. Then when it is time for the next wave to spawn, it spawns both. So, I have no error logs, just a disobedient activator.

Link to comment
Share on other sites

There's a lot going on that is slowing your script down. Optimization is needed but you need to know first what papyrus is doing with your script in order to know what to optimize.

 

For Event OnPower() - add these two functions

Debug.StartStackProfiling() ; before the actual code

 

Debug.StopStackProfiling() ; after the actual code

 

You'll get a new folder called Profiling,

 

Here's what the folder address should look like: Documents\My Games\Fallout 4\Logs\Script\Profiling

 

the "bEnableProfiling" flag in the "[Papyrus]" section of the ini file to be set to 1

 

PUSH = Function is called

POP = Function has finished

QUEUE_PUSH = Function is waiting its turn

QUEUE_POP = Function is waiting to finish

Link to comment
Share on other sites

Utility.Wait(Delay)

Disclaimer: I don't have a clue about the inner workings and performance mechanisms of Papyrus.

 

However, somewhere on the wiki I remember reading that using Utility.Wait is bad practice and should be replaced with custom timers and OnTimer events.

Link to comment
Share on other sites

Ok, I did the stack profiling for a one-wave (six spawns) run through and got the following result. I have no idea how to interpret it, however. To my untrained eye, it looks like everything is working normally (queue_push, push, pop, etc)

 

I opted for using Utility.Wait because the delays are so variable, writing all those timer scripts would be a pain in the ass.

 

 

  Reveal hidden contents

 

Link to comment
Share on other sites

  On 6/3/2018 at 12:18 PM, GenghisKhanX said:

I opted for using Utility.Wait because the delays are so variable, writing all those timer scripts would be a pain in the ass.

 

Again, I'm not a professional but from my limited knowledge using that function should actually block the VM or at least its thread, consuming CPU time while the timer is handled by engine-internal logic and probably *way* faster than a Papyrus function call.

Link to comment
Share on other sites

Utility.Wait doesn't seem to consume any resources I can measure, it just puts a flag on the event queue to trigger at a future time, same a Timer.

 

If you have a simple single path script that isn't referenced or state changed by any external event driven stuff they are fine for a short term break in a function. Infact for short durations I have found timer return times to be less reliable (+10% variance) than wait return times (+2% variance) running parallel scripts.

 

EDIT: @GenghisKhanX Get those Utility.Wait(Delay) out of the subsidiary spawn functions and have one in the StartSpawning() While loop. In this case StartSpawning() starting as a timer may be better as it deoends on an external factor (power) and can be cancelled directly on power off rather than waiting for the wait to return IUSWIM.

Edited by SKK50
Link to comment
Share on other sites

  • Recently Browsing   0 members

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