Jump to content

Array Add() function not working


Recommended Posts

Hey guys, any idea why my array length is still 0 after using array Add() function?

Actor Property spawned_actor Auto
Actor[] Property enemy_actor_pool Auto
spawned_actor = spawn_points[random_spawn].PlaceActorAtMe(LvlFeralGhoul,1)
enemy_actor_pool.Add(spawned_actor)
Function ResetActorPool()
    Debug.MessageBox("Array len: " + enemy_actor_pool.length) ;Displays zero
    Int iElement = enemy_actor_pool.Length
    While iElement
	Debug.MessageBox("iElement found") ;Doesn't display. So nothing looping
	iElement -= 1
	enemy_actor_pool[iElement].SetCriticalStage(enemy_actor_pool[iElement].CritStage_DisintegrateEnd)
	enemy_actor_pool.Remove(iElement)
    EndWhile
EndFunction
Link to comment
Share on other sites

Something seemed weird about your loop so I just went about it how I would. I faked the parts of the script I dont have with some guess work.

Scriptname Example extends Quest

Actor[] Pool
int random_spawn = 0 ; whatever random thing

ActorBase Property LvlFeralGhoul Auto Const Mandatory
ObjectReference[] Property spawn_points Auto Const Mandatory

Event OnInit()
	Pool = new Actor[0] ; Array.Add will auto-expand size
EndEvent


Event OnQuestInit()
	SpawnGhoul()
	SpawnGhoul()
	SpawnGhoul()
	SpawnGhoul()
	SpawnGhoul()
EndEvent


Event OnQuestShutdown()
	ResetActors(Pool)
EndEvent


Function SpawnGhoul()
	Actor Spawned = spawn_points[random_spawn].PlaceActorAtMe(LvlFeralGhoul, 1)
	Pool.Add(Spawned)
EndFunction


Function ResetActors(Actor[] actors) Global
	If (actors)
		int size = actors.Length
		int index = 0

		Debug.MessageBox("Size:"+size+"\n\nDo not change the size of your array while perform iterations.")
		While (index < size)
			Actor element = actors[index]
			If (element)
				Debug.MessageBox("Found\n"+element+"\nSetting critical stage to disintegrate end.")
				element.SetCriticalStage(element.CritStage_DisintegrateEnd)
			Else
				Debug.MessageBox("The element at index "+index+" was none, skipping..")
			EndIf
			index += 1 ; move to the next index
		EndWhile

		actors.Clear()
		Debug.MessageBox("Iteration Complete\nClearing the actor pool.\nSize:"+actors.Length)
	Else
		Debug.MessageBox("The actor pool is empty or none, skipping reset.")
	EndIf
EndFunction

Link to comment
Share on other sites

 

Did you ever initialize the array?

Does it not just make an empty array when I declare it?

 

 

When you declare it as you did it's set to a None value. So the entire array = None. You need to initialize it to a zero entity array like Scrivner exampled with

 

Actor[] Pool ; Pool currently = None. You cannot initialize it here. It must be done in a function or event.

Event OnInit()
    Pool = new Actor[0] ; Array.Add will auto-expand size
EndEvent

I suspect if you had papyrus logging turned on and check you'll see some message like, cannot add to a none array, or something like that.

Edited by BigAndFlabby
Link to comment
Share on other sites

Hey guys, thanks for the replies! Unfortunately, i tried initializing the array and it still isn't working.

 

I used the OnInit event to add the following code:

Event OnInit()
	enemy_actor_pool = new Actor[0]
EndEvent

Here is the script in it's full:

Scriptname CMA:CMA_ArenaManagerScript extends ObjectReference
{Main script for controlling the waves of enemy.}

Float Property cool_down_time = 10.0 Auto const
{How long the cool down period is inbetween each round.}
ActorBase Property LvlFeralGhoul Auto Const
{Standard actor used that will be spawned.}
ActorBase Property LvlGlowLegGhoul Auto Const
{Hard actor that will be used in hard rounds.}
Float Property spawn_interval_time = 2.0 Auto const
{Delay between each actual spawn.}
Sound Property snd_new_round Auto Const
{Sound to be played at the start of a new round.}
Sound Property snd_round_end Auto Const
{Sound to be played at the end of a round.}
Sound Property snd_hard_round_wrn Auto Const
{Sound to be played at the start of a hard round.}
Message Property new_round_notification Auto Const
{Message displayed when a new round begins. Shows the actual round number}
Int Property kill_complete_caps Auto Const
{Number of caps to reward the player for killing an enemy.}
Int Property round_complete_caps Auto Const
{Number of caps rewarded to player for completing a round.}
;End of const properties

Int Property round_counter = 1 Auto
{Counter to keep track of what round it is.}

Int Property hard_round_counter = 0 Auto
{Counter to see when the next hard round will be.}

Int Property hard_rounds_completed = 1 Auto
{Used to multiply the number of hard enemies for every hard round}

Int Property enemies_remaining = 0 Auto
{Keeps track of how many enemies remain to be killed.}

Bool Property game_started Auto
{Used to check if the game has already been setup and started.}

ObjectReference[] Property spawn_points Auto
{Where the enemies will spawn}

Bool Property finished_spawning Auto
{Used to check if there are still enemies spawning. Used to stop premature end of round}

Bool Property in_cool_down = true Auto
{Used to check if the game is currently in it's cool down state}

Actor Property spawned_actor Auto
Actor[] Property enemy_actor_pool Auto
{Used to keep track of enemies spawned in the last round so they can be deleted at the end of cool down.}

Event OnInit()
	enemy_actor_pool = new Actor[0]
EndEvent

Event OnLoad()
	Self.Reset()
	GetParentCell().Reset()
	Reset()

	ResetGame()
EndEvent

Event OnActivate(ObjectReference akActionRef)
	StartGame()
EndEvent

Event Actor.OnDeath(Actor akSender, Actor akKiller)
	if(akSender != Game.GetPlayer())
		enemies_remaining -= 1
		Game.GivePlayerCaps(kill_complete_caps)

		if(CheckEndOfRound())
			int instanceID = snd_round_end.play(Game.GetPlayer())
			Sound.SetInstanceVolume(instanceID,1.0)
			StartCoolDown()
		endIf

		UnregisterForRemoteEvent(akSender, "OnDeath")
	endif
EndEvent

Function StartGame()
	if(!game_started)
		Debug.MessageBox("Game starting. Get ready!")
		RegisterForRemoteEvent(Game.GetPlayer(), "OnDeath")
		StartRound(1)
		 in_cool_down = false
		game_started = true
	else
		Debug.MessageBox("Game has already started!")
	endIf
EndFunction

Function StartRound(Int num_round)

	new_round_notification.Show(round_counter)

	int instanceID =  snd_new_round.play(Game.GetPlayer())
	Sound.SetInstanceVolume(instanceID,1.0)

	finished_spawning = false
	Int counter = 0
	Int random_spawn

	Int num_enemies_to_spawn = num_round + 5

	while(counter < num_enemies_to_spawn)
		random_spawn = Utility.RandomInt(0, spawn_points.Length - 1)

		spawned_actor = spawn_points[random_spawn].PlaceActorAtMe(LvlFeralGhoul,1)
		enemy_actor_pool.Add(spawned_actor)
		RegisterForRemoteEvent(spawned_actor, "OnDeath")
		enemies_remaining += 1		
		counter += 1

		Utility.Wait(spawn_interval_time)
	endWhile

	hard_round_counter += 1

	if(hard_round_counter == 5)
		int snd_inst = snd_hard_round_wrn.play(Game.GetPlayer())
		Sound.SetInstanceVolume(snd_inst, 4.0)

		Int hard_counter = 0
		while(hard_counter < hard_rounds_completed)

			random_spawn = Utility.RandomInt(0, spawn_points.Length - 1)
			spawned_actor = spawn_points[random_spawn].PlaceActorAtMe(LvlGlowLegGhoul, 1)
			enemy_actor_pool.Add(spawned_actor)
			RegisterForRemoteEvent(spawned_actor, "OnDeath")
			enemies_remaining += 1	
			hard_counter += 1	
		endWhile

		hard_round_counter = 0
		hard_rounds_completed += 1
	endif

	finished_spawning = true
EndFunction

Function StartCoolDown()
	 in_cool_down = true
	StartTimer(cool_down_time, 10)
EndFunction

Function EndOfCooldown()
 	in_cool_down = false 
	ResetActorPool()
	round_counter += 1
	StartRound(round_counter)
EndFunction

Event OnTimer(int iTimerID)
	if( iTimerID == 10)
		EndOfCooldown()
	endIf
EndEvent

Bool Function CheckEndOfRound()
	if(enemies_remaining <= 0 && finished_spawning)
		Game.GivePlayerCaps(round_complete_caps)
		return true
	else
		return false	
	endIf
EndFunction

Function ResetGame()
	CancelTimer(10)
	round_counter = 1
	hard_round_counter = 0
	hard_rounds_completed = 1
	enemies_remaining = 0
	game_started = false
	finished_spawning = true
	in_cool_down = true
EndFunction

Function ResetActorPool()
	Debug.MessageBox("Array len: " + enemy_actor_pool.Length)
	Int iElement = enemy_actor_pool.Length
	While iElement
		Debug.MessageBox("iElement found")
		iElement -= 1
		enemy_actor_pool[iElement].SetCriticalStage(enemy_actor_pool[iElement].CritStage_DisintegrateEnd)
		enemy_actor_pool.Remove(iElement)
	EndWhile
EndFunction
Link to comment
Share on other sites

Hey guys, thanks for the replies! Unfortunately, i tried initializing the array and it still isn't working.ÃÂ

ÃÂ

I used the OnInit event to add the following code:

 

Event OnInit()
	enemy_actor_pool = new Actor[0]
EndEvent
Here is the script in it's full:ÃÂ

ÃÂ

Scriptname CMA:CMA_ArenaManagerScript extends ObjectReference
{Main script for controlling the waves of enemy.}

Float Property cool_down_time = 10.0 Auto const
{How long the cool down period is inbetween each round.}
ActorBase Property LvlFeralGhoul Auto Const
{Standard actor used that will be spawned.}
ActorBase Property LvlGlowLegGhoul Auto Const
{Hard actor that will be used in hard rounds.}
Float Property spawn_interval_time = 2.0 Auto const
{Delay between each actual spawn.}
Sound Property snd_new_round Auto Const
{Sound to be played at the start of a new round.}
Sound Property snd_round_end Auto Const
{Sound to be played at the end of a round.}
Sound Property snd_hard_round_wrn Auto Const
{Sound to be played at the start of a hard round.}
Message Property new_round_notification Auto Const
{Message displayed when a new round begins. Shows the actual round number}
Int Property kill_complete_caps Auto Const
{Number of caps to reward the player for killing an enemy.}
Int Property round_complete_caps Auto Const
{Number of caps rewarded to player for completing a round.}
;End of const properties

Int Property round_counter = 1 Auto
{Counter to keep track of what round it is.}

Int Property hard_round_counter = 0 Auto
{Counter to see when the next hard round will be.}

Int Property hard_rounds_completed = 1 Auto
{Used to multiply the number of hard enemies for every hard round}

Int Property enemies_remaining = 0 Auto
{Keeps track of how many enemies remain to be killed.}

Bool Property game_started Auto
{Used to check if the game has already been setup and started.}

ObjectReference[] Property spawn_points Auto
{Where the enemies will spawn}

Bool Property finished_spawning Auto
{Used to check if there are still enemies spawning. Used to stop premature end of round}

Bool Property in_cool_down = true Auto
{Used to check if the game is currently in it's cool down state}

Actor Property spawned_actor Auto
Actor[] Property enemy_actor_pool Auto
{Used to keep track of enemies spawned in the last round so they can be deleted at the end of cool down.}

Event OnInit()
	enemy_actor_pool = new Actor[0]
EndEvent

Event OnLoad()
	Self.Reset()
	GetParentCell().Reset()
	Reset()

	ResetGame()
EndEvent

Event OnActivate(ObjectReference akActionRef)
	StartGame()
EndEvent

Event Actor.OnDeath(Actor akSender, Actor akKiller)
	if(akSender != Game.GetPlayer())
		enemies_remaining -= 1
		Game.GivePlayerCaps(kill_complete_caps)

		if(CheckEndOfRound())
			int instanceID = snd_round_end.play(Game.GetPlayer())
			Sound.SetInstanceVolume(instanceID,1.0)
			StartCoolDown()
		endIf

		UnregisterForRemoteEvent(akSender, "OnDeath")
	endif
EndEvent

Function StartGame()
	if(!game_started)
		Debug.MessageBox("Game starting. Get ready!")
		RegisterForRemoteEvent(Game.GetPlayer(), "OnDeath")
		StartRound(1)
		 in_cool_down = false
		game_started = true
	else
		Debug.MessageBox("Game has already started!")
	endIf
EndFunction

Function StartRound(Int num_round)

	new_round_notification.Show(round_counter)

	int instanceID =  snd_new_round.play(Game.GetPlayer())
	Sound.SetInstanceVolume(instanceID,1.0)

	finished_spawning = false
	Int counter = 0
	Int random_spawn

	Int num_enemies_to_spawn = num_round + 5

	while(counter < num_enemies_to_spawn)
		random_spawn = Utility.RandomInt(0, spawn_points.Length - 1)

		spawned_actor = spawn_points[random_spawn].PlaceActorAtMe(LvlFeralGhoul,1)
		enemy_actor_pool.Add(spawned_actor)
		RegisterForRemoteEvent(spawned_actor, "OnDeath")
		enemies_remaining += 1		
		counter += 1

		Utility.Wait(spawn_interval_time)
	endWhile

	hard_round_counter += 1

	if(hard_round_counter == 5)
		int snd_inst = snd_hard_round_wrn.play(Game.GetPlayer())
		Sound.SetInstanceVolume(snd_inst, 4.0)

		Int hard_counter = 0
		while(hard_counter < hard_rounds_completed)

			random_spawn = Utility.RandomInt(0, spawn_points.Length - 1)
			spawned_actor = spawn_points[random_spawn].PlaceActorAtMe(LvlGlowLegGhoul, 1)
			enemy_actor_pool.Add(spawned_actor)
			RegisterForRemoteEvent(spawned_actor, "OnDeath")
			enemies_remaining += 1	
			hard_counter += 1	
		endWhile

		hard_round_counter = 0
		hard_rounds_completed += 1
	endif

	finished_spawning = true
EndFunction

Function StartCoolDown()
	 in_cool_down = true
	StartTimer(cool_down_time, 10)
EndFunction

Function EndOfCooldown()
 	in_cool_down = false 
	ResetActorPool()
	round_counter += 1
	StartRound(round_counter)
EndFunction

Event OnTimer(int iTimerID)
	if( iTimerID == 10)
		EndOfCooldown()
	endIf
EndEvent

Bool Function CheckEndOfRound()
	if(enemies_remaining <= 0 && finished_spawning)
		Game.GivePlayerCaps(round_complete_caps)
		return true
	else
		return false	
	endIf
EndFunction

Function ResetGame()
	CancelTimer(10)
	round_counter = 1
	hard_round_counter = 0
	hard_rounds_completed = 1
	enemies_remaining = 0
	game_started = false
	finished_spawning = true
	in_cool_down = true
EndFunction

Function ResetActorPool()
	Debug.MessageBox("Array len: " + enemy_actor_pool.Length)
	Int iElement = enemy_actor_pool.Length
	While iElement
		Debug.MessageBox("iElement found")
		iElement -= 1
		enemy_actor_pool[iElement].SetCriticalStage(enemy_actor_pool[iElement].CritStage_DisintegrateEnd)
		enemy_actor_pool.Remove(iElement)
	EndWhile
EndFunction

 

That should work unless the object was already created. I would move the initializer to the start game function personally if it would be applicable there. It would mean you start with a fresh array each time your object is activated. I'm not sure if you want that behavior or not. You could try that and see how it goes.

Edited by BigAndFlabby
Link to comment
Share on other sites

Glad to hear it's working. Now that I'm home it's easier to type.

 

The issue you probably were running in to is that the OnInit wasn't firing because you were loading a save that already had a spawned object containing the script. It would be worth reading the wiki page for OnInit https://www.creationkit.com/fallout4/index.php?title=OnInit_-_ScriptObject specifically the circumstances of when it is called. I just realized I have a few scripts on a mod to go update now.

 

Something else to be aware of. If the player was to leave the cell which causes the 3D to unload for the actors, your resetactors function may fail. Also the OnLoad having the 3 resets is redundant. The cell reset alone should do it. Unless the cell is in an encounter zone that is marked as no reset. Then the script will fail and halt. Calling self.Reset() and just Reset() is the same thing. Not including Self makes it implied vs explicit.

 

Another thing that's more of a nit picky thing. There's really no point in registering for Player OnDeath and then checking for != Player in the event. If the player triggers it, the game will force a reload before anything else would fire up anyway and the whole crap resets to the save. So it's pretty pointless.

Edited by BigAndFlabby
Link to comment
Share on other sites

  • Recently Browsing   0 members

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