Jump to content

Recommended Posts

Posted

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
Posted

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..

Posted

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.

Posted

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

Posted
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.

Posted

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.

 

 

Stack_321731 log opened (PC-64)
86869555^START^321731
86869695^POP^321731^1^None^debug..StartStackProfiling
86869801^QUEUE_PUSH^321731^1^ (2F001741)^message.??.Show
86902717^PUSH^321731^1^ (2F001741)^message..Show
89213625^POP^321731^1^ (2F001741)^message..Show
89214296^QUEUE_PUSH^321731^1^ (2F001742)^message.??.Show
89249862^PUSH^321731^1^ (2F001742)^message..Show
90820612^POP^321731^1^ (2F001742)^message..Show
90821249^PUSH^321731^1^ (FF0134C1)^_gkx_battlespawnerscript..StartSpawning
90821264^QUEUE_PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript.??.IsPowered
90856755^PUSH^321731^2^ (FF0134C1)^ObjectReference..IsPowered
90856782^POP^321731^2^ (FF0134C1)^ObjectReference..IsPowered
90859080^QUEUE_PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript.??.Is3DLoaded
90891646^PUSH^321731^2^ (FF0134C1)^ObjectReference..Is3DLoaded
90891667^POP^321731^2^ (FF0134C1)^ObjectReference..Is3DLoaded
90893880^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnVeryEasy
90893903^QUEUE_PUSH^321731^3^None^utility.??.RandomInt
90924601^PUSH^321731^3^None^utility..RandomInt
90924611^POP^321731^3^None^utility..RandomInt
90926863^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe
90958256^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
90959456^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
90960517^QUEUE_PUSH^321731^3^None^debug.??.Notification
90992446^PUSH^321731^3^None^debug..Notification
90992463^POP^321731^3^None^debug..Notification
90994683^QUEUE_PUSH^321731^3^None^utility.??.Wait
91026932^PUSH^321731^3^None^utility..Wait
101033147^POP^321731^3^None^utility..Wait
101035703^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnVeryEasy
101035760^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnEasy
101035789^QUEUE_PUSH^321731^3^None^utility.??.RandomInt
101068837^PUSH^321731^3^None^utility..RandomInt
101068852^POP^321731^3^None^utility..RandomInt
101071873^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe
101100838^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
101103794^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
101105249^QUEUE_PUSH^321731^3^None^debug.??.Notification
101136223^PUSH^321731^3^None^debug..Notification
101136251^POP^321731^3^None^debug..Notification
101138146^QUEUE_PUSH^321731^3^None^utility.??.Wait
101170870^PUSH^321731^3^None^utility..Wait
116182558^POP^321731^3^None^utility..Wait
116186500^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnEasy
116186600^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnNormal
116186646^QUEUE_PUSH^321731^3^None^utility.??.RandomInt
116218894^PUSH^321731^3^None^utility..RandomInt
116218917^POP^321731^3^None^utility..RandomInt
116221920^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe
116254940^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
116258565^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
116260715^QUEUE_PUSH^321731^3^None^debug.??.Notification
116289030^PUSH^321731^3^None^debug..Notification
116289047^POP^321731^3^None^debug..Notification
116290893^QUEUE_PUSH^321731^3^None^utility.??.Wait
116323119^PUSH^321731^3^None^utility..Wait
136337123^POP^321731^3^None^utility..Wait
136340114^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnNormal
136340159^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnHard
136340178^QUEUE_PUSH^321731^3^None^utility.??.RandomInt
136368083^PUSH^321731^3^None^utility..RandomInt
136368093^POP^321731^3^None^utility..RandomInt
136372008^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe
136405319^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
136407134^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
136410158^QUEUE_PUSH^321731^3^None^debug.??.Notification
136442999^PUSH^321731^3^None^debug..Notification
136443029^POP^321731^3^None^debug..Notification
136446937^QUEUE_PUSH^321731^3^None^utility.??.Wait
136479026^PUSH^321731^3^None^utility..Wait
166503701^POP^321731^3^None^utility..Wait
166506433^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnHard
166506493^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnVeryHard
166506556^QUEUE_PUSH^321731^3^None^utility.??.RandomInt
166536879^PUSH^321731^3^None^utility..RandomInt
166536894^POP^321731^3^None^utility..RandomInt
166540088^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe
166572206^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
166575729^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
166577387^QUEUE_PUSH^321731^3^None^debug.??.Notification
166604971^PUSH^321731^3^None^debug..Notification
166604992^POP^321731^3^None^debug..Notification
166607774^QUEUE_PUSH^321731^3^None^utility.??.Wait
166640696^PUSH^321731^3^None^utility..Wait
402405048^POP^321731^3^None^utility..Wait
402407990^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnVeryHard
402408054^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnBoss
402408083^QUEUE_PUSH^321731^3^None^utility.??.RandomInt
402440006^PUSH^321731^3^None^utility..RandomInt
402440026^POP^321731^3^None^utility..RandomInt
402442677^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe
402471728^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
402477524^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe
402479431^QUEUE_PUSH^321731^3^None^debug.??.Notification
402502795^PUSH^321731^3^None^debug..Notification
402502811^POP^321731^3^None^debug..Notification
402505037^QUEUE_PUSH^321731^3^None^utility.??.Wait
402537053^PUSH^321731^3^None^utility..Wait

 

Posted

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.

Posted (edited)

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
  • Recently Browsing   0 members

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