Jump to content

Understanding dynamic array correctly


SMB92

Recommended Posts

Quest alias packages only work while the actor is in the alias. When they are out of the alias, all "stuff" from quest alias is lost.

 

That's why I love quests myself, I can do how many I want, I can turn them on/off when I want, I can have one quest to give actor some keyword/package/faction/etc etc and turn it off whenever I want. Updating is easy just turn off quests and turn them back on and even totally modified scripts are updated. Even uninstalling is easy, just turn off all the quests and disable/delete every alias.

 

It's pretty easy to make good patrol/travel packages just using stuff ingame already, you can have already existing Xmarkers as destinations for example.

 

What you could do with your system: You could have each spawnpoint have their own keyword that they add to the actors that they spawn, then you could start quest after they are spawned, finding matching reference and looking for actors that have your keyword. That way you could have own quest for each "spawn area" and then the quest alias(collection alias?) would have packages. Or, instead of starting/stopping the quest all time to fill aliases, there propably is function to add the actor to RefCollectionAlias in quest that is already running. You could also remove them from the alias in OnDying event in the alias, and mark them for delete etc..

 

But, honestly, I think just using quest for everything is super smooth. I'm not saying there's anything wrong in your system, actually I like it.. it's just a personal preference for quests, lol. I know in the other hand that some people absolutely hate quests and they do have their own problems too, like sometimes for no real reason, alias not filling or quest not starting etc.

 

Just throwing out ideas. Waiting to see your new system in action :smile:

Edited by vkz89q
Link to comment
Share on other sites

  • Replies 111
  • Created
  • Last Reply

Top Posters In This Topic

Another thing that crosses my mind here, seems the OnCellAttach/detach works within the ugrids range, I have not implemented anything in the case that you happen to "pass by" a cell very quickly. I think in WOTC, a lot of CTDs happen when the player moves across a lot of cells and the script isn't keeping up, and by the time it elects a place to MoveTo the spawned actors, they're out of the loaded area (probably why I see up to 5 "could not find navmesh with MoveToNearestNavmeshLocation function before most regular crashes). I think my script is a bit faster though and from what I can see (given I don't intend on having any more than 2 points per cell mostly) it will be finished before that could happen. Just thoughts based on what I have seen anyway

 

 

On an entirely separate note, it's in the back of my head that if I set up a patrol marker network, this will be persistent. I wanted to set it up so that other modders could also use it, a bit of a convenience feature, as well as to address the problem that WOTC sees with it's patrol AI packages and the fact I don't want to modify/have too many custom ActorBases/LvlNPCs (for cross compatibility). But for shiz and giggles I was looking at how it could be possible to dynamically give each NPC a "patrol" package. Apparently the only way to do this is ForceRefTo() a reference alias and assign the package (maybe having to force with EvaluatePackage()). I wonder though, if I had a single Ref Alias on the quest, and I kept forcing NPCs in and out of it and assigning them the package, would that work for the way things are set up (possibly multiple "spawnpoints" sending NPCs to the RefAlias, will they keep package after they are out of it, how to remove the very last NPC fro mthe RefAlias when they've all been through etc etc)

 

Just reading that back to myself, I'll stay with the patrol marker network lol. Just curious how far I can "rev the engine" lol. On that note, I kinda thought of a way to make them non-persistent using an uninstall script. If my whole network is linked from one end of the CW to another, I could do some code that specifically starts at one of them, and keeps getting the next linked ref and setting it to none. Until they are all unlinked in that savegame, so users can have peace of mind. Suppose that would take some very careful placement though, but hey at least I think this way :smile:

 

To give npc a package you can also apply an alias to the npc. It`s not the same as "ForceRefTo". There is a function "ApplyToRef" and "RemoveFromRef". It allows to apply alias data ( keywords, packages, factions) to multiple npc without filling the alias( means you can use 1 Reference Alias for all your npc in the same time). To do this you need to check "can be applied to non aliased refs" in the alias file. The only thing about this is that applying the data does not make the npc persistent and the data can be auto removed on unload sometimes.

Edited by kitcat81
Link to comment
Share on other sites

Another thing that crosses my mind here, seems the OnCellAttach/detach works within the ugrids range, I have not implemented anything in the case that you happen to "pass by" a cell very quickly. I think in WOTC, a lot of CTDs happen when the player moves across a lot of cells and the script isn't keeping up, and by the time it elects a place to MoveTo the spawned actors, they're out of the loaded area (probably why I see up to 5 "could not find navmesh with MoveToNearestNavmeshLocation function before most regular crashes). I think my script is a bit faster though and from what I can see (given I don't intend on having any more than 2 points per cell mostly) it will be finished before that could happen. Just thoughts based on what I have seen anyway

 

 

 

I can think of a mod that might cause that, drive-able motorcycles. Especially if you have the throttle going and you're moving fast. I know I can move faster than the objects can load. For example, I can get to the Diamond City gate for the first time when meeting Piper and the gate and her haven't loaded yet and it takes a couple of seconds for them to appear.

 

So when traveling fast enough via the mod, a player might be able to cross several grids much faster than would otherwise be possible.

 

Just thought I'd mention that as that could cause an issue from what you're saying.

Edited by TheCourier13
Link to comment
Share on other sites

 

Quest alias packages only work while the actor is in the alias. When they are out of the alias, all "stuff" from quest alias is lost.

That's why I love quests myself, I can do how many I want, I can turn them on/off when I want, I can have one quest to give actor some keyword/package/faction/etc etc and turn it off whenever I want. Updating is easy just turn off quests and turn them back on and even totally modified scripts are updated. Even uninstalling is easy, just turn off all the quests and disable/delete every alias.
It's pretty easy to make good patrol/travel packages just using stuff ingame already, you can have already existing Xmarkers as destinations for example.
What you could do with your system: You could have each spawnpoint have their own keyword that they add to the actors that they spawn, then you could start quest after they are spawned, finding matching reference and looking for actors that have your keyword. That way you could have own quest for each "spawn area" and then the quest alias(collection alias?) would have packages. Or, instead of starting/stopping the quest all time to fill aliases, there propably is function to add the actor to RefCollectionAlias in quest that is already running. You could also remove them from the alias in OnDying event in the alias, and mark them for delete etc..
But, honestly, I think just using quest for everything is super smooth. I'm not saying there's anything wrong in your system, actually I like it.. it's just a personal preference for quests, lol. I know in the other hand that some people absolutely hate quests and they do have their own problems too, like sometimes for no real reason, alias not filling or quest not starting etc.
Just throwing out ideas. Waiting to see your new system in action :smile:

Thanks for following the thread :). Personally I quite like it the way it is. But I guess one reason for that is I haven't fully figured out how to run the function from the quest on the marker properly :D. But I still just like it how it is anyway :P. You could say I like a mix of the Quest + script. The quest now contains all the timers and Formlist events, first install stages and uninstall stages as well, and I am thinking to dynamically fill the array of structs now if that's possible (to achieve only having what's allowed to spawn to be present there). I also like being able to copy and replace in the marker script, for variations etc.

 

 

To give npc a package you can also apply an alias to the npc. It`s not the same as "ForceRefTo". There is a function "ApplyToRef" and "RemoveFromRef". It allows to apply alias data ( keywords, packages, factions) to multiple npc without filling the alias( means you can use 1 Reference Alias for all your npc in the same time). To do this you need to check "can be applied to non aliased refs" in the alias file. The only thing about this is that applying the data does not make the npc persistent and the data can be auto removed on unload sometimes.

 

That is perfect. I'll look into it asap. If this works I can just assign them on spawn like the way they get linked to a patrol marker and unlinked on unload.

Link to comment
Share on other sites

 

Another thing that crosses my mind here, seems the OnCellAttach/detach works within the ugrids range, I have not implemented anything in the case that you happen to "pass by" a cell very quickly. I think in WOTC, a lot of CTDs happen when the player moves across a lot of cells and the script isn't keeping up, and by the time it elects a place to MoveTo the spawned actors, they're out of the loaded area (probably why I see up to 5 "could not find navmesh with MoveToNearestNavmeshLocation function before most regular crashes). I think my script is a bit faster though and from what I can see (given I don't intend on having any more than 2 points per cell mostly) it will be finished before that could happen. Just thoughts based on what I have seen anyway

 

 

 

I can think of a mod that might cause that, drive-able motorcycles. Especially if you have the throttle going and you're moving fast. I know I can move faster than the objects can load. For example, I can get to the Diamond City gate for the first time when meeting Piper and the gate and her haven't loaded yet and it takes a couple of seconds for them to appear.

 

So when traveling fast enough via the mod, a player might be able to cross several grids much faster than would otherwise be possible.

 

Just thought I'd mention that as that could cause an issue from what you're saying.

 

This is a good point in a sense, but I won't be accommodating for this kind of thing :D. I wouldn't use it myself, vanilla would probably crash with it (I have tried the mod though). I will look at failsafes for when players are in Vertibirds however, that is a big one from WOTC people had a problem with (and there are some vanilla random spawns, believe it or not)

 

I'm excited about this ApplyToRef() function kitcat81 mentioned, I'd like to see what I can do that

Link to comment
Share on other sites

So as it would be, the "accumating array" is not working at all. I cannot for the life of me see why though. The Debug Note always returns iPosition as -1 after every spawn, even though actors are spawning just fine. Therefore, cleanup function does nothing either. I've tried both the Add function originally and casting it in but results are identical. I'm not sure what to do right now, this is a fundamental flaw in the mod if these spawned actors cannot be applied to the arrays

 

This would have been the final version of the script:

 

 

Scriptname ASC_SP_Random_R1 extends ObjectReference
{Region 1 Random Type SpawnPoint Marker Script}
import ASC_MainStruct
ASC_MasterRandomQuestScript Property MasterQuest Auto Const
GlobalVariable Property ASC_Main_ModEnabled Auto Const
GlobalVariable Property ASC_Main_Enabled_Random_R1 Auto Const
GlobalVariable Property ASC_Main_Random_Chance_R1 Auto Const
GlobalVariable Property ASC_Main_Random_DisableOnBlock_R1 Auto Const
GlobalVariable Property ASC_Main_Random_EnableOnSpawnBlock_R1 Auto Const
GlobalVariable Property ASC_Main_Difficulty_R1 Auto Const
GlobalVariable Property ASC_Main_Reroll_Limit_R1 Auto Const
FormList Property ASC_ResetList_R1 Auto Const
Actor Property PlayerRef Auto Const
bool bSpawnPointLoaded = false ;bool for cleanup event
bool Group2Loaded = false
bool Group3Loaded = false
int iRerollLimit = 0
int iRerollCount = 0
Actor[] GroupList ; Array to track and cleanup all aspawned actors later, as well as apply new features in future
Actor[] GroupList2 ;if 1st reroll attempt successful, assign spawns here
Actor[] Grouplist3 ;2nd reroll attempt actors here, limit of rerolls is 2, hardcapped.
Event OnCellAttach()
bSpawnPointLoaded = true
if (Self.IsDisabled() == false) && (ASC_Main_ModEnabled.GetValueInt() == 1) && (ASC_Main_Enabled_Random_R1.GetValueInt() == 1)
SPActivate()
Debug.Notification("All Functions Done")
else
Debug.Notification("SpawnPoint Failed")
endif
EndEvent
Event OnCellDetach() ;idea is to stop cleanup from happening while potentially in combat with group while potentially leaving the cell their spawnmarker is in. Cleans up all data generated during spawn.
bSpawnPointLoaded = false
Utility.Wait(10)
while (PlayerRef.IsInCombat()) ; also may not be necessary but reference for sanity check.
; Do nothing until combat is over, then check if we are still in the loaded area
Utility.Wait(0.1)
endwhile
if bSpawnPointLoaded == false ;if we are not in the loaded area, start cleaning up. Event will be called again if we aren't so no worries
int iCounter = 0
while iCounter < GroupList.Length
;GroupList[iCounter].SetLinkedRef(None) ;old, prior to using AI package
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.RemoveFromRef(GroupList[iCounter])
GroupList[iCounter].DeleteWhenAble()
iCounter += 1
endwhile
iCounter = 0
endif
if Group2Loaded == true
int iCounter = 0
while iCounter < GroupList2.Length
;GroupList2[iCounter].SetLinkedRef(None) ;old, prior to using AI package
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.RemoveFromRef(GroupList2[iCounter])
GroupList2[iCounter].DeleteWhenAble()
iCounter += 1
endwhile
iCounter = 0
endif
if Group3Loaded == true
int iCounter = 0
while iCounter < GroupList3.Length
;GroupList3[iCounter].SetLinkedRef(None) ;old, prior to using AI package
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.RemoveFromRef(GroupList3[iCounter])
GroupList3[iCounter].DeleteWhenAble()
iCounter += 1
endwhile
iCounter = 0
endif
Debug.Notification("SpawnPoint cleaned up")
EndEvent
Function SPActivate() ;This may not be necessary but it looks neat. Main roll chance and disabling happens here
iRerollLimit = ASC_Main_Reroll_Limit_R1.GetValueInt()
int iChanceToSpawn = Utility.RandomInt(1,100)
if (iChanceToSpawn <= ASC_Main_Random_Chance_R1.GetValueInt())
Debug.Notification("Spawn Function called on script!")
Self.Disable()
ASC_ResetList_R1.AddForm(Self)
Spawn()
Debug.Notification("Spawn function has completed")
elseif (iChanceToSpawn >= ASC_Main_Random_Chance_R1.GetValueInt()) && (ASC_Main_Random_DisableOnBlock_R1.GetValueInt() == 1)
Self.Disable()
ASC_ResetList_R1.AddForm(Self)
Debug.Notification("SpawnPoint failed and disabled")
else
Debug.Notification("SpawnPoint failed but still armed")
endif
EndFunction
Function Spawn()
iRerollLimit = ASC_Main_Reroll_Limit_R1.GetValueInt()
int iNumSpawnTypes = (MasterQuest as ASC_MasterRandomQuestScript).ActorTypesRandomR1.Length ; how many types of spawning actors can we support
int iWhoToSpawn = Utility.RandomInt(0,iNumSpawnTypes) ; changed to use the size of our array of actor types
ActorTypeStruct spawnDetails = (MasterQuest as ASC_MasterRandomQuestScript).ActorTypesRandomR1[iWhoToSpawn]
bool bAllowedToSpawn = spawnDetails.ASC_Allowed.GetValueInt() as Bool
if bAllowedToSpawn ;Is the elected group allowed to spawn?
SpawnEnemyActors(spawnDetails.ASC_Max_Allowed.GetValueInt(), spawnDetails.ASC_Chance.GetValueInt(), spawnDetails.LvlActorBase, spawnDetails.ASC_Allowed_Boss.GetValue() as Bool, spawnDetails.ASC_Max_Allowed_Boss.GetValueInt(), spawnDetails.ASC_Chance_Boss.GetValueInt(), spawnDetails.LvlActorBossBase, spawnDetails.ASC_EZ_Lvl.GetValueInt(), spawnDetails.ASC_Reroll_Allowed.GetValueInt(), spawnDetails.ASC_Reroll_Chance.GetValueInt())
elseif !bAllowedToSpawn
BlockedOnFirstSpawn() ;For the first election, we allow the player to potentially rearm the spawnpoint if it fails here. But not in rerolls.
spawnDetails = None
endif
EndFunction
Function SpawnEnemyActors(int iMaxSpawnCount, int iChance, ActorBase varBaseActor, bool bBossAllowed, int iMaxBossCount, int iBossChance, ActorBase varBossActor, int iEzLevel, int iRerollAllowed, int iRerollChance)
Debug.Notification("Spawning Enemy Actors")
;Form kMarker = Game.GetFormFromFile(0x00002ce2, "Fallout4.ESM") old system for patroling based on physical marker network
;ObjectReference kPatrolMarker = Game.FindClosestReferenceOfTypeFromRef(kMarker, Self as ObjectReference, 32.0)
Actor Spawned = None
int iDifficulty = ASC_Main_Difficulty_R1.GetValueInt()
int iSpawnCounter = 0
int iPosition = 0
;bool bSpawnSuccess = false ;obsolete, was for checking old reroll system was allowed
GroupList = new Actor[0] ; since we don't have 100% chance of spawning actors, we need this to be an accumulating array
Debug.Notification("Spawning enemies") ; unless we add a function parameter for text this had to be changed to be something generic
while (iSpawnCounter < iMaxSpawnCount)
if (Utility.RandomInt(1,100) <= iChance)
Actor akSpawned = Self.PlaceActorAtMe(varBaseActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]);Other way to do it, left for reference
GroupList[iPosition] = akSpawned
;GroupList.Add(Self.PlaceActorAtMe(varBaseActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
iPosition = GroupList.Length - 1
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList[iPosition]) ;new system for patrols NOTE change to travel aliases
endif
iSpawnCounter += 1
endwhile
Debug.Notification("Array Add Success. Actor count now: " + iPosition)
Debug.Notification("Non Boss Group Spawned")
if bBossAllowed == 1
iSpawnCounter = 0 ; reuse var. memory efficient
while (iSpawnCounter < iMaxBossCount)
if (Utility.RandomInt(1,100) <= iBossChance)
Spawned = Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel])
GroupList[iPosition] = Spawned
;GroupList.Add(Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
iPosition = GroupList.Length - 1
;GroupList[iPosition].SetLinkedRef(kPatrolMarker)
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList[iPosition])
endif
iSpawnCounter += 1
endwhile
endif
Debug.Notification("Array Add Success. Actor count now: " + iPosition)
Debug.Notification("Enemies should be spawned")
if (iRerollAllowed == 1) && (iRerollCount < iRerollLimit) && (Utility.RandomInt(1,100) <= iRerollChance) ;iRerollLimit is a universal value, only 1 global per region, not per type
SpawnAnotherGroup()
iRerollCount += 1
Debug.Notification("Rerolling for another group!")
else
Debug.Notification("Reroll failed")
endif
EndFunction
Function SpawnAnotherGroup() ;this simulates spawning battles between two groups, or possibly a really large group of the same enemy.
int iNumSpawnTypes = (MasterQuest as ASC_MasterRandomQuestScript).ActorTypesRandomR1.Length ; how many types of spawning actors can we support
int iWhoToSpawn = Utility.RandomInt(0,iNumSpawnTypes) ; changed to use the size of our array of actor types
ActorTypeStruct spawnDetails = (MasterQuest as ASC_MasterRandomQuestScript).ActorTypesRandomR1[iWhoToSpawn]
bool bAllowedToSpawn = spawnDetails.ASC_Allowed.GetValueInt() as Bool
if bAllowedToSpawn ;Is the elected group allowed to spawn?
SpawnMoreEnemyActors(spawnDetails.ASC_Max_Allowed.GetValueInt(), spawnDetails.ASC_Chance.GetValueInt(), spawnDetails.LvlActorBase, spawnDetails.ASC_Allowed_Boss.GetValue() as Bool, spawnDetails.ASC_Max_Allowed_Boss.GetValueInt(), spawnDetails.ASC_Chance_Boss.GetValueInt(), spawnDetails.LvlActorBossBase, spawnDetails.ASC_EZ_Lvl.GetValueInt(), spawnDetails.ASC_Reroll_Allowed.GetValueInt(), spawnDetails.ASC_Reroll_Chance.GetValueInt())
else
spawnDetails = none ;just to give the else function something to do
endif
EndFunction
Function SpawnMoreEnemyActors(int iMaxSpawnCount, int iChance, ActorBase varBaseActor, bool bBossAllowed, int iMaxBossCount, int iBossChance, ActorBase varBossActor, int iEzLevel, int iRerollAllowed, int iRerollChance)
;Form kMarker = Game.GetFormFromFile(0x00002ce2, "Fallout4.ESM") old system for patroling based on physical marker network
;ObjectReference kPatrolMarker = Game.FindClosestReferenceOfTypeFromRef(kMarker, Self as ObjectReference, 32.0)
int iDifficulty = ASC_Main_Difficulty_R1.GetValueInt()
int iSpawnCounter = 0
int iPosition = 0
GroupList2 = new Actor[iPosition] ; since we don't have 100% chance of spawning actors, we need this to be an accumulating array
Debug.Notification("Spawning enemies") ; unless we add a function parameter for text this had to be changed to be something generic
while (iSpawnCounter < iMaxSpawnCount)
if (Utility.RandomInt(1,100) <= iChance)
GroupList2.Add(Self.PlaceActorAtMe(varBaseActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
iPosition = GroupList.Length - 1
;GroupList[iPosition].SetLinkedRef(kPatrolMarker) old sytem
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList2[iPosition]) ;new system for patrols
endif
iSpawnCounter += 1
endwhile
Group2Loaded = true
if bBossAllowed == 1
iSpawnCounter = 0 ; reuse var. memory efficient
while (iSpawnCounter < iMaxBossCount)
if (Utility.RandomInt(1,100) <= iBossChance)
GroupList2.Add(Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
iPosition = GroupList.Length - 1
;GroupList2[iPosition].SetLinkedRef(kPatrolMarker)
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList2[iPosition])
endif
iSpawnCounter += 1
endwhile
endif
if (iRerollAllowed == 1) && (iRerollCount < iRerollLimit) && (Utility.RandomInt(1,100) <= iRerollChance)
SpawnYetAnotherGroup()
iRerollCount += 1
else
;Nothing, exit function
endif
EndFunction
Function SpawnYetAnotherGroup() ;this simulates spawning battles between two groups, or possibly a really large group of the same enemy.
int iNumSpawnTypes = (MasterQuest as ASC_MasterRandomQuestScript).ActorTypesRandomR1.Length ; how many types of spawning actors can we support
int iWhoToSpawn = Utility.RandomInt(0,iNumSpawnTypes) ; changed to use the size of our array of actor types
ActorTypeStruct spawnDetails = (MasterQuest as ASC_MasterRandomQuestScript).ActorTypesRandomR1[iWhoToSpawn]
bool bAllowedToSpawn = spawnDetails.ASC_Allowed.GetValueInt() as Bool
if bAllowedToSpawn
SpawnEvenMoreEnemyActors(spawnDetails.ASC_Max_Allowed.GetValueInt(), spawnDetails.ASC_Chance.GetValueInt(), spawnDetails.LvlActorBase, spawnDetails.ASC_Allowed_Boss.GetValue() as Bool, spawnDetails.ASC_Max_Allowed_Boss.GetValueInt(), spawnDetails.ASC_Chance_Boss.GetValueInt(), spawnDetails.LvlActorBossBase, spawnDetails.ASC_EZ_Lvl.GetValueInt(), spawnDetails.ASC_Reroll_Allowed.GetValueInt(), spawnDetails.ASC_Reroll_Chance.GetValueInt())
else
spawnDetails = none ;just to give the else function something to do
endif
EndFunction
Function SpawnEvenMoreEnemyActors(int iMaxSpawnCount, int iChance, ActorBase varBaseActor, bool bBossAllowed, int iMaxBossCount, int iBossChance, ActorBase varBossActor, int iEzLevel, int iRerollAllowed, int iRerollChance)
;Form kMarker = Game.GetFormFromFile(0x00002ce2, "Fallout4.ESM") old system for patroling based on physical marker network
;ObjectReference kPatrolMarker = Game.FindClosestReferenceOfTypeFromRef(kMarker, Self as ObjectReference, 32.0)
int iDifficulty = ASC_Main_Difficulty_R1.GetValueInt()
int iSpawnCounter = 0
int iPosition = 0
GroupList3 = new Actor[iPosition] ; since we don't have 100% chance of spawning actors, we need this to be an accumulating array
Debug.Notification("Spawning enemies") ; unless we add a function parameter for text this had to be changed to be something generic
while (iSpawnCounter < iMaxSpawnCount)
if (Utility.RandomInt(1,100) <= iChance)
GroupList3.Add(Self.PlaceActorAtMe(varBaseActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
iPosition = GroupList.Length - 1
;GroupList3[iPosition].SetLinkedRef(kPatrolMarker) old sytem
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList3[iPosition]) ;new system for patrols
endif
iSpawnCounter += 1
endwhile
Group3Loaded = true
if bBossAllowed == 1
iSpawnCounter = 0 ; reuse var. memory efficient
while (iSpawnCounter < iMaxBossCount)
if (Utility.RandomInt(1,100) <= iBossChance)
GroupList3.Add(Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
iPosition = GroupList.Length - 1
;GroupList[iPosition].SetLinkedRef(kPatrolMarker)
(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList3[iPosition])
endif
iSpawnCounter += 1
endwhile
;Nothing, exit function
endif
EndFunction
Function BlockedOnFirstSpawn() ;reenable the spawnpoint upon not being allowed to spawn 1st elected group, if user settings allow this to happen
if (ASC_Main_Random_EnableOnSpawnBlock_R1.GetValueInt() == 1)
Self.Enable()
else
;Nothing, exit function
endif
EndFunction

 

 

Link to comment
Share on other sites

Okay so thanks to BigandFlabby again, I've moved over to the dynamic struct/array of structs. However the same problem remains as my last post with the SpawnEnemyActors function. It seems to me that if the first actor fails to spawn, they all do, and if the first is a success, it spawns the maximum amount. Sometimes the debug note says that it's size (iPosition) is -1, sometimes 0. When it says -1, there is usually 4 base actors there or 1 boss. Or nothing. So far, there has never been anything when it reports the size as 0. Wtf.

 

Here would be the "dynamic" versions of the scripts (above has the array of structs as a full property)

 

Quest

 

 

Scriptname ASC_MasterRandomQuestScript extends Quest

;Import ASC_MainStruct
;Import ASC_DynMainStruct

Struct ActorTypeStruct
	ActorBase LvlActorBase
	ActorBase LvlActorBossBase
	GlobalVariable ASC_Allowed_Boss
	GlobalVariable ASC_Max_Allowed
	GlobalVariable ASC_Max_Allowed_Boss
	GlobalVariable ASC_Chance
	GlobalVariable ASC_Chance_Boss
	GlobalVariable ASC_Reroll_Allowed
	GlobalVariable ASC_Reroll_Chance
	GlobalVariable ASC_EZ_Lvl
EndStruct

;Quest Property ASC_MasterRandomQuest Auto
;Quest Property Min01 Auto
;Quest Property MinRecruit00 Auto
;Message property ASC_StartUpMenu Auto Const
;Message property ASC_StartConfirmOnDefer Auto Const
GlobalVariable Property ASC_Main_ModEnabled Auto Const
GlobalVariable Property ASC_Timer_Reset_R1 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R2 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R3 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R4 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R5 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R6 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R7 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R8 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R9 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R10 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R11 Auto Const
;GlobalVariable Property ASC_Timer_Reset_R12 Auto Const
FormList Property ASC_ResetList_R1 Auto Const
;FormList Property ASC_ResetList_R2 Auto Const
;FormList Property ASC_ResetList_R3 Auto Const
;FormList Property ASC_ResetList_R4 Auto Const
;FormList Property ASC_ResetList_R5 Auto Const
;FormList Property ASC_ResetList_R6 Auto Const
;FormList Property ASC_ResetList_R7 Auto Const
;FormList Property ASC_ResetList_R8 Auto Const
;FormList Property ASC_ResetList_R9 Auto Const
;FormList Property ASC_ResetList_R10 Auto Const
;FormList Property ASC_ResetList_R11 Auto Const
;FormList Property ASC_ResetList_R12 Auto Const
ReferenceAlias Property ASC_PatrolPackageAlias Auto
ActorBase property LvlRaider Auto Const
ActorBase property LvlRaiderBoss Auto Const
GlobalVariable Property ASC_Allowed_Raider_R1 Auto Const
GlobalVariable Property ASC_Allowed_Boss_Raider_R1 Auto Const
GlobalVariable Property ASC_Max_Allowed_Raider_R1 Auto Const
GlobalVariable Property ASC_Max_Allowed_Boss_Raider_R1 Auto Const
GlobalVariable Property ASC_Chance_Spawn_Raider_R1 Auto Const
GlobalVariable Property ASC_Chance_Spawn_Boss_Raider_R1 Auto Const
GlobalVariable Property ASC_Reroll_Allowed_Raider_R1 Auto Const
GlobalVariable Property ASC_Reroll_Chance_Raider_R1 Auto Const
GlobalVariable Property ASC_EZ_Raider_R1 Auto Const
ActorBase property LvlGunner Auto Const
ActorBase property LvlGunnerBoss Auto Const
GlobalVariable Property ASC_Allowed_Gunner_R1 Auto Const
GlobalVariable Property ASC_Allowed_Boss_Gunner_R1 Auto Const
GlobalVariable Property ASC_Max_Allowed_Gunner_R1 Auto Const
GlobalVariable Property ASC_Max_Allowed_Boss_Gunner_R1 Auto Const
GlobalVariable Property ASC_Chance_Spawn_Gunner_R1 Auto Const
GlobalVariable Property ASC_Chance_Spawn_Boss_Gunner_R1 Auto Const
GlobalVariable Property ASC_Reroll_Allowed_Gunner_R1 Auto Const
GlobalVariable Property ASC_Reroll_Chance_Gunner_R1 Auto Const
GlobalVariable Property ASC_EZ_Gunner_R1 Auto Const
ActorBase property LvlForged Auto Const
ActorBase property LvlForged_Boss Auto Const
GlobalVariable Property ASC_Allowed_Forged_R1 Auto Const
GlobalVariable Property ASC_Allowed_Boss_Forged_R1 Auto Const
GlobalVariable Property ASC_Max_Allowed_Forged_R1 Auto Const
GlobalVariable Property ASC_Max_Allowed_Boss_Forged_R1 Auto Const
GlobalVariable Property ASC_Chance_Spawn_Forged_R1 Auto Const
GlobalVariable Property ASC_Chance_Spawn_Boss_Forged_R1 Auto Const
GlobalVariable Property ASC_Reroll_Allowed_Forged_R1 Auto Const
GlobalVariable Property ASC_Reroll_Chance_Forged_R1 Auto Const
GlobalVariable Property ASC_EZ_Forged_R1 Auto Const
ActorBase property LvlTriggerman Auto Const
GlobalVariable Property ASC_Allowed_Triggerman_R1 Auto Const
GlobalVariable Property ASC_Allowed_Boss_Triggerman_R1 Auto Const
GlobalVariable Property ASC_Max_Allowed_Triggerman_R1 Auto Const
GlobalVariable Property ASC_Max_Allowed_Boss_Triggerman_R1 Auto Const
GlobalVariable Property ASC_Chance_Spawn_Triggerman_R1 Auto Const
GlobalVariable Property ASC_Chance_Spawn_Boss_Triggerman_R1 Auto Const
GlobalVariable Property ASC_Reroll_Allowed_Triggerman_R1 Auto Const
GlobalVariable Property ASC_Reroll_Chance_Triggerman_R1 Auto Const
GlobalVariable Property ASC_EZ_Triggerman_R1 Auto Const

;ActorTypeStruct[] Property ActorTypesRandomR1 Auto Const
;ActorTypeStruct[] Property ActorTypesR2 Auto Const
;ActorTypeStruct[] Property ActorTypesR3 Auto Const
;ActorTypeStruct[] Property ActorTypesR4 Auto Const
;ActorTypeStruct[] Property ActorTypesR5 Auto Const
;ActorTypeStruct[] Property ActorTypesR6 Auto Const
;ActorTypeStruct[] Property ActorTypesR7 Auto Const
;ActorTypeStruct[] Property ActorTypesR8 Auto Const
;ActorTypeStruct[] Property ActorTypesR9 Auto Const
;ActorTypeStruct[] Property ActorTypesR10 Auto Const
;ActorTypeStruct[] Property ActorTypesR11 Auto Const
;ActorTypeStruct[] Property ActorTypesR12 Auto Const
EncounterZone[] Property EzArray Auto Const

ActorTypeStruct[] ActorTypesRandomR1

bool bTimersRunning = false
Int iResetTimerR1 = 1
;Int iResetTimerR2 = 2
;Int iResetTimerR3 = 3
;Int iResetTimerR4 = 4
;Int iResetTimerR5 = 5
;Int iResetTimerR6 = 6
;Int iResetTimerR7 = 7
;Int iResetTimerR8 = 8
;Int iResetTimerR9 = 9
;Int iResetTimerR10 = 10
;Int iResetTimerR11 = 11
;Int iResetTimerR12 = 12

;Event OnInit()
	;StartUpMenu()
;EndEvent

Event OnStageSet(int auiStageID, int auiItemID)
	;if (auiStageID == 5)
	;	Utility.Wait(5.0)
	;	if MinRecruit00.GetStage() < 500
	;		while MinRecruit00.GetStage() < 500
	;			Utility.Wait(30.0)
	;		endwhile
	;	endif
	;	if MinRecruit00.GetStage() == 500
	;		Confirm()
	;	endif
	if (auiStageID == 10) && (bTimersRunning == false)
		StartTimerGameTime(ASC_Timer_Reset_R1.GetValueInt(), iResetTimerR1)
		Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R2.GetValueInt(), iResetTimerR2)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R3.GetValueInt(), iResetTimerR3)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R4.GetValueInt(), iResetTimerR4)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R5.GetValueInt(), iResetTimerR5)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R6.GetValueInt(), iResetTimerR6)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R7.GetValueInt(), iResetTimerR7)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R8.GetValueInt(), iResetTimerR8)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R9.GetValueInt(), iResetTimerR9)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R10.GetValueInt(), iResetTimerR10)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R11.GetValueInt(), iResetTimerR11)
		;Utility.Wait(0.1)
		;StartTimerGameTime(ASC_Timer_Reset_R12.GetValueInt(), iResetTimerR12)
		bTimersRunning = true
		FillArrays()
		ASC_Main_ModEnabled.SetValue(1.0)
		Debug.Notification("Mod is Enabled")
	elseif (auiStageID == 100)
		ASC_Main_ModEnabled.SetValue(0.0)
		CancelTimerGameTime(iResetTimerR1)
		;CancelTimerGameTime(iResetTimerR2)
		;CancelTimerGameTime(iResetTimerR3)
		;CancelTimerGameTime(iResetTimerR4)
		;CancelTimerGameTime(iResetTimerR5)
		;CancelTimerGameTime(iResetTimerR6)
		;CancelTimerGameTime(iResetTimerR7)
		;CancelTimerGameTime(iResetTimerR8)
		;CancelTimerGameTime(iResetTimerR9)
		;CancelTimerGameTime(iResetTimerR10)
		;CancelTimerGameTime(iResetTimerR11)
		;CancelTimerGameTime(iResetTimerR12)
		bTimersRunning = false
		ClearAllArrays()
		Debug.Notification("Mod is uninstalled")
	endif
EndEvent

Event OnTimerGameTime(int aiTimerID)
	if aiTimerID == iResetTimerR1
		Int iIndex = 0
		While (iIndex < ASC_ResetList_R1.GetSize())
			ObjectReference kMarker = ASC_ResetList_R1.GetAt(iIndex) as ObjectReference
			kMarker.EnableNoWait()
			iIndex += 1
		EndWhile
		ASC_ResetList_R1.Revert()
		Debug.Notification("R1 Spawn Markers Reset")
	;elseif aiTimerID == iResetTimerR2
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R2.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R2.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R2.Revert()
	;elseif aiTimerID == iResetTimerR3
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R3.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R3.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R3.Revert()
	;elseif aiTimerID == iResetTimerR4
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R4.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R4.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R4.Revert()
	;elseif aiTimerID == iResetTimerR5
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R5.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R5.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R5.Revert()
	;elseif aiTimerID == iResetTimerR6
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R6.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R6.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R6.Revert()
	;elseif aiTimerID == iResetTimerR7
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R7.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R7.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R7.Revert()
	;elseif aiTimerID == iResetTimerR8
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R8.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R8.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R8.Revert()
	;elseif aiTimerID == iResetTimerR9
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R9.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R9.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R9.Revert()
	;elseif aiTimerID == iResetTimerR10
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R10.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R10.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R10.Revert()
	;elseif aiTimerID == iResetTimerR11
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R11.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R11.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R11.Revert()
	;elseif aiTimerID == iResetTimerR12
	;	Int iIndex = 0
	;	While (iIndex < ASC_ResetList_R12.GetSize())
	;		ObjectReference kMarker = ASC_ResetList_R12.GetAt(iIndex) as ObjectReference
	;		kMarker.EnableNoWait()
	;		iIndex += 1
	;	EndWhile
	;	ASC_ResetList_R12.Revert()
	endif
EndEvent

;Function StartUpMenu()
;	int iMenu = -1
;	While (iMenu != 4)
;		iMenu = -1
;		iMenu = ASC_StartUpMenu.Show()
;		If (iMenu == 0)
;			ASC_MasterRandomQuest.SetStage(10)
;			iMenu = 4
;		elseIf (iMenu == 1)
;			ASC_MasterRandomQuest.SetStage(1)
;			iMenu = 4
;		elseIf (iMenu == 2)
;			ASC_MasterRandomQuest.SetStage(5)
;			iMenu = 4
;		elseif (iMenu == 4)
;		EndIf
;	EndWhile
;EndFunction

;Function Confirm()
;	int iMenu = -1
;	While (iMenu != 2)
;		iMenu = -1
;		iMenu = ASC_StartConfirmOnDefer.Show()
;		If (iMenu == 0)
;			ASC_MasterRandomQuest.SetStage(10)
;			iMenu = 2
;		elseif (iMenu == 1)
;			ASC_MasterRandomQuest.SetStage(1)
;			iMenu = 2
;		endif
;	EndWhile
;EndFunction

Function FillArrays() ;Fills the struct arrays with only the types allowed. Called by update event and initial initialization of the mod. May need to be called every startup.
	Int iPosition = 0
	ActorTypesRandomR1 = new ActorTypeStruct[iPosition]
		if ASC_Allowed_Raider_R1.GetValueInt() == 1
			ActorTypesRandomR1[iPosition].LvlActorBase = LvlRaider
			ActorTypesRandomR1[iPosition].LvlActorBossBase = LvlRaiderBoss
			ActorTypesRandomR1[iPosition].ASC_Allowed_Boss = ASC_Allowed_Boss_Raider_R1
			ActorTypesRandomR1[iPosition].ASC_Max_Allowed = ASC_Max_Allowed_Raider_R1
			ActorTypesRandomR1[iPosition].ASC_Max_Allowed_Boss = ASC_Max_Allowed_Boss_Raider_R1
			ActorTypesRandomR1[iPosition].ASC_Chance = ASC_Chance_Spawn_Raider_R1
			ActorTypesRandomR1[iPosition].ASC_Chance_Boss = ASC_Chance_Spawn_Boss_Raider_R1
			ActorTypesRandomR1[iPosition].ASC_Reroll_Allowed = ASC_Reroll_Allowed_Raider_R1
			ActorTypesRandomR1[iPosition].ASC_Reroll_Chance = ASC_Reroll_Chance_Raider_R1
			ActorTypesRandomR1[iPosition].ASC_EZ_Lvl = ASC_EZ_Raider_R1
			iPosition += 1
		else
			;Nothing, ActorType does not enter the array
		endif
		if ASC_Allowed_Gunner_R1.GetValueInt() == 1
			ActorTypesRandomR1[iPosition].LvlActorBase = LvlGunner
			ActorTypesRandomR1[iPosition].LvlActorBossBase = LvlGunnerBoss
			ActorTypesRandomR1[iPosition].ASC_Allowed_Boss = ASC_Allowed_Boss_Gunner_R1
			ActorTypesRandomR1[iPosition].ASC_Max_Allowed = ASC_Max_Allowed_Gunner_R1
			ActorTypesRandomR1[iPosition].ASC_Max_Allowed_Boss = ASC_Max_Allowed_Boss_Gunner_R1
			ActorTypesRandomR1[iPosition].ASC_Chance = ASC_Chance_Spawn_Gunner_R1
			ActorTypesRandomR1[iPosition].ASC_Chance_Boss = ASC_Chance_Spawn_Boss_Gunner_R1
			ActorTypesRandomR1[iPosition].ASC_Reroll_Allowed = ASC_Reroll_Allowed_Gunner_R1
			ActorTypesRandomR1[iPosition].ASC_Reroll_Chance = ASC_Reroll_Chance_Gunner_R1
			ActorTypesRandomR1[iPosition].ASC_EZ_Lvl = ASC_EZ_Gunner_R1
			iPosition += 1
		else
			;Nothing, ActorType does not enter the array
		endif
		if ASC_Allowed_Forged_R1.GetValueInt() == 1
			ActorTypesRandomR1[iPosition].LvlActorBase = LvlForged
			ActorTypesRandomR1[iPosition].LvlActorBossBase = LvlForged_Boss
			ActorTypesRandomR1[iPosition].ASC_Allowed_Boss = ASC_Allowed_Boss_Forged_R1
			ActorTypesRandomR1[iPosition].ASC_Max_Allowed = ASC_Max_Allowed_Forged_R1
			ActorTypesRandomR1[iPosition].ASC_Max_Allowed_Boss = ASC_Max_Allowed_Boss_Forged_R1
			ActorTypesRandomR1[iPosition].ASC_Chance = ASC_Chance_Spawn_Forged_R1
			ActorTypesRandomR1[iPosition].ASC_Chance_Boss = ASC_Chance_Spawn_Boss_Forged_R1
			ActorTypesRandomR1[iPosition].ASC_Reroll_Allowed = ASC_Reroll_Allowed_Forged_R1
			ActorTypesRandomR1[iPosition].ASC_Reroll_Chance = ASC_Reroll_Chance_Forged_R1
			ActorTypesRandomR1[iPosition].ASC_EZ_Lvl = ASC_EZ_Forged_R1
			iPosition += 1
		else
			;Nothing, ActorType does not enter the array
		endif
		if ASC_Allowed_Triggerman_R1.GetValueInt() == 1
			ActorTypesRandomR1[iPosition].LvlActorBase = LvlTriggerman
			ActorTypesRandomR1[iPosition].LvlActorBossBase = LvlTriggerman
			ActorTypesRandomR1[iPosition].ASC_Allowed_Boss = ASC_Allowed_Boss_Triggerman_R1
			ActorTypesRandomR1[iPosition].ASC_Max_Allowed = ASC_Max_Allowed_Triggerman_R1
			ActorTypesRandomR1[iPosition].ASC_Max_Allowed_Boss = ASC_Max_Allowed_Boss_Triggerman_R1
			ActorTypesRandomR1[iPosition].ASC_Chance = ASC_Chance_Spawn_Triggerman_R1
			ActorTypesRandomR1[iPosition].ASC_Chance_Boss = ASC_Chance_Spawn_Boss_Triggerman_R1
			ActorTypesRandomR1[iPosition].ASC_Reroll_Allowed = ASC_Reroll_Allowed_Triggerman_R1
			ActorTypesRandomR1[iPosition].ASC_Reroll_Chance = ASC_Reroll_Chance_Triggerman_R1
			ActorTypesRandomR1[iPosition].ASC_EZ_Lvl = ASC_EZ_Triggerman_R1
			iPosition += 1
		else
			;Nothing, ActorType does not enter the array
		endif
		Debug.Notification("Array of Structs is filled")
EndFunction

Function ClearAllArrays()
	ActorTypesRandomR1.Clear()
EndFunction

Function SpawnR1(ASC_SP_Random_R1 akCallingObject)
    int iNumSpawnTypes = ActorTypesRandomR1.Length ; how many types of spawning actors can we support
    int iWhoToSpawn = Utility.RandomInt(1,iNumSpawnTypes) ; changed to use the size of our array of actor types
    ActorTypeStruct spawnDetails = ActorTypesRandomR1[iWhoToSpawn]
    akCallingObject.SpawnEnemyActors(spawnDetails.ASC_Max_Allowed.GetValueInt(), spawnDetails.ASC_Chance.GetValueInt(), spawnDetails.LvlActorBase, spawnDetails.ASC_Allowed_Boss.GetValue() as Bool, spawnDetails.ASC_Max_Allowed_Boss.GetValueInt(), spawnDetails.ASC_Chance_Boss.GetValueInt(), spawnDetails.LvlActorBossBase, spawnDetails.ASC_EZ_Lvl.GetValueInt(), spawnDetails.ASC_Reroll_Allowed.GetValueInt(), spawnDetails.ASC_Reroll_Chance.GetValueInt())
EndFunction

Function SpawnAnotherGroupR1(ASC_SP_Random_R1 akCallingObject) ;this simulates spawning battles between two groups, or possibly a really large group of the same enemy. 
	int iNumSpawnTypes = ActorTypesRandomR1.Length ; how many types of spawning actors can we support
    int iWhoToSpawn = Utility.RandomInt(1,iNumSpawnTypes) ; changed to use the size of our array of actor types
    ActorTypeStruct spawnDetails = ActorTypesRandomR1[iWhoToSpawn]
    akCallingObject.SpawnMoreEnemyActors(spawnDetails.ASC_Max_Allowed.GetValueInt(), spawnDetails.ASC_Chance.GetValueInt(), spawnDetails.LvlActorBase, spawnDetails.ASC_Allowed_Boss.GetValue() as Bool, spawnDetails.ASC_Max_Allowed_Boss.GetValueInt(), spawnDetails.ASC_Chance_Boss.GetValueInt(), spawnDetails.LvlActorBossBase, spawnDetails.ASC_EZ_Lvl.GetValueInt(), spawnDetails.ASC_Reroll_Allowed.GetValueInt(), spawnDetails.ASC_Reroll_Chance.GetValueInt())
EndFunction

Function SpawnYetAnotherGroupR1(ASC_SP_Random_R1 akCallingObject) ;this simulates spawning battles between two groups, or possibly a really large group of the same enemy. 
	int iNumSpawnTypes = ActorTypesRandomR1.Length ; how many types of spawning actors can we support
    int iWhoToSpawn = Utility.RandomInt(1,iNumSpawnTypes) ; changed to use the size of our array of actor types
    ActorTypeStruct spawnDetails = ActorTypesRandomR1[iWhoToSpawn]
    akCallingObject.SpawnEvenMoreEnemyActors(spawnDetails.ASC_Max_Allowed.GetValueInt(), spawnDetails.ASC_Chance.GetValueInt(), spawnDetails.LvlActorBase, spawnDetails.ASC_Allowed_Boss.GetValue() as Bool, spawnDetails.ASC_Max_Allowed_Boss.GetValueInt(), spawnDetails.ASC_Chance_Boss.GetValueInt(), spawnDetails.LvlActorBossBase, spawnDetails.ASC_EZ_Lvl.GetValueInt(), spawnDetails.ASC_Reroll_Allowed.GetValueInt(), spawnDetails.ASC_Reroll_Chance.GetValueInt())
EndFunction
 

 

 

Spawnpoint object:

 

 

Scriptname ASC_SP_Random_R1 extends ObjectReference
{Region 1 Random Type SpawnPoint Marker Script}

import ASC_MainStruct

ASC_MasterRandomQuestScript Property MasterQuest Auto Const
GlobalVariable Property ASC_Main_ModEnabled Auto Const
GlobalVariable Property ASC_Main_Enabled_Random_R1 Auto Const
GlobalVariable Property ASC_Main_Random_Chance_R1 Auto Const
GlobalVariable Property ASC_Main_Random_DisableOnBlock_R1 Auto Const
GlobalVariable Property ASC_Main_Difficulty_R1 Auto Const
GlobalVariable Property ASC_Main_Reroll_Limit_R1 Auto Const
FormList Property ASC_ResetList_R1 Auto Const
Actor Property PlayerRef Auto Const


bool bSpawnPointLoaded = false ;bool for cleanup event
bool Group2Loaded = false
bool Group3Loaded = false
int iRerollLimit = 0
int iRerollCount = 0
Actor[] GroupList  ; Array to track and cleanup all aspawned actors later, as well as apply new features in future
Actor[] GroupList2 ;if 1st reroll attempt successful, assign spawns here
Actor[] Grouplist3 ;2nd reroll attempt actors here, limit of rerolls is 2, hardcapped. 

Event OnCellAttach()
	bSpawnPointLoaded = true
	if (Self.IsDisabled() == false) && (ASC_Main_ModEnabled.GetValueInt() == 1) && (ASC_Main_Enabled_Random_R1.GetValueInt() == 1)
		SPActivate()
		Debug.Notification("All Functions Done")
	else
		Debug.Notification("SpawnPoint Failed")
	endif
EndEvent

Event OnCellDetach() ;idea is to stop cleanup from happening while potentially in combat with group while potentially leaving the cell their spawnmarker is in. Cleans up all data generated during spawn. 
    bSpawnPointLoaded = false
    Utility.Wait(10)
		while (PlayerRef.IsInCombat()) ; also may not be necessary but reference for sanity check.
			; Do nothing until combat is over, then check if we are still in the loaded area
			Utility.Wait(0.1)
		endwhile
		if bSpawnPointLoaded == false ;if we are not in the loaded area, start cleaning up. Event will be called again if we aren't so no worries
			int iCounter = 0
			while iCounter < GroupList.Length
				;GroupList[iCounter].SetLinkedRef(None) ;old, prior to using AI package
				(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.RemoveFromRef(GroupList[iCounter])
				GroupList[iCounter].DeleteWhenAble()
				iCounter += 1
			endwhile
			iCounter = 0
		endif
		if Group2Loaded == true
			int iCounter = 0
			while iCounter < GroupList2.Length
				;GroupList2[iCounter].SetLinkedRef(None) ;old, prior to using AI package
				(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.RemoveFromRef(GroupList2[iCounter])
				GroupList2[iCounter].DeleteWhenAble()
				iCounter += 1
			endwhile
			iCounter = 0
		endif
		if Group3Loaded == true
			int iCounter = 0
			while iCounter < GroupList3.Length
				;GroupList3[iCounter].SetLinkedRef(None) ;old, prior to using AI package
				(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.RemoveFromRef(GroupList3[iCounter])
				GroupList3[iCounter].DeleteWhenAble()
				iCounter += 1
			endwhile
			iCounter = 0
		endif
		Debug.Notification("SpawnPoint cleaned up")
EndEvent

Function SPActivate()  ;This may not be necessary but it looks neat. Main roll chance and disabling happens here
	iRerollLimit = ASC_Main_Reroll_Limit_R1.GetValueInt()
	int iChanceToSpawn = Utility.RandomInt(1,100)
    if (iChanceToSpawn <= ASC_Main_Random_Chance_R1.GetValueInt())
		Debug.Notification("Spawn Function called on script!")
        Self.Disable()
        ASC_ResetList_R1.AddForm(Self)
		(MasterQuest as ASC_MasterRandomQuestScript).SpawnR1(Self)
		Debug.Notification("Spawn function has completed")
    elseif (iChanceToSpawn >= ASC_Main_Random_Chance_R1.GetValueInt()) && (ASC_Main_Random_DisableOnBlock_R1.GetValueInt() == 1)
        Self.Disable()
        ASC_ResetList_R1.AddForm(Self)
		Debug.Notification("SpawnPoint failed and disabled")
    else
        Debug.Notification("SpawnPoint failed but still armed")
    endif
EndFunction

Function SpawnEnemyActors(int iMaxSpawnCount, int iChance, ActorBase varBaseActor, bool bBossAllowed, int iMaxBossCount, int iBossChance, ActorBase varBossActor, int iEzLevel, int iRerollAllowed, int iRerollChance)
	Debug.Notification("Spawning Enemy Actors")
    ;Form kMarker = Game.GetFormFromFile(0x00002ce2, "Fallout4.ESM")  old system for patroling based on physical marker network
	;ObjectReference kPatrolMarker = Game.FindClosestReferenceOfTypeFromRef(kMarker, Self as ObjectReference, 32.0)
	Actor Spawned = None
	int iDifficulty = ASC_Main_Difficulty_R1.GetValueInt()
    int iSpawnCounter = 0
	int iPosition = 0
    ;bool bSpawnSuccess = false ;obsolete, was for checking old reroll system was allowed
    GroupList = new Actor[0] ; since we don't have 100% chance of spawning actors, we need this to be an accumulating array
    Debug.Notification("Spawning enemies") ; unless we add a function parameter for text this had to be changed to be something generic
        while (iSpawnCounter < iMaxSpawnCount)
            if (Utility.RandomInt(1,100) <= iChance)
				Actor akSpawned = Self.PlaceActorAtMe(varBaseActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]);Other way to do it, left for reference
				GroupList[iPosition] = akSpawned
                ;GroupList.Add(Self.PlaceActorAtMe(varBaseActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
                iPosition = GroupList.Length - 1
				(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList[iPosition])  ;new system for patrols NOTE change to travel aliases
            endif
            iSpawnCounter += 1
        endwhile
		Debug.Notification("Array Add Success. Actor count now: " + iPosition)
		Debug.Notification("Non Boss Group Spawned")
        if bBossAllowed == 1
            iSpawnCounter = 0 ; reuse var. memory efficient
            while (iSpawnCounter < iMaxBossCount)
                if (Utility.RandomInt(1,100) <= iBossChance)
                    Spawned = Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel])
					GroupList[iPosition] = Spawned
					;GroupList.Add(Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
                    iPosition = GroupList.Length - 1
                    ;GroupList[iPosition].SetLinkedRef(kPatrolMarker)
					(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList[iPosition])
                endif
                iSpawnCounter += 1
            endwhile
        endif
		Debug.Notification("Array Add Success. Actor count now: " + iPosition)
		Debug.Notification("Enemies should be spawned")
		if (iRerollAllowed == 1) && (iRerollCount < iRerollLimit) && (Utility.RandomInt(1,100) <= iRerollChance)  ;iRerollLimit is a universal value, only 1 global per region, not per type
			(MasterQuest as ASC_MasterRandomQuestScript).SpawnAnotherGroupR1(Self)
			iRerollCount += 1
			Debug.Notification("Rerolling for another group!")
		else
			Debug.Notification("Reroll 1 failed")
		endif
EndFunction

Function SpawnMoreEnemyActors(int iMaxSpawnCount, int iChance, ActorBase varBaseActor, bool bBossAllowed, int iMaxBossCount, int iBossChance, ActorBase varBossActor, int iEzLevel, int iRerollAllowed, int iRerollChance)
    ;Form kMarker = Game.GetFormFromFile(0x00002ce2, "Fallout4.ESM")  old system for patroling based on physical marker network
	;ObjectReference kPatrolMarker = Game.FindClosestReferenceOfTypeFromRef(kMarker, Self as ObjectReference, 32.0)
	Actor Spawned = None
	int iDifficulty = ASC_Main_Difficulty_R1.GetValueInt()
    int iSpawnCounter = 0
	int iPosition = 0
    GroupList2 = new Actor[iPosition] ; since we don't have 100% chance of spawning actors, we need this to be an accumulating array
    Debug.Notification("Spawning enemies") ; unless we add a function parameter for text this had to be changed to be something generic
        while (iSpawnCounter < iMaxSpawnCount)
            if (Utility.RandomInt(1,100) <= iChance)
                Spawned = Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel])
				GroupList2[iPosition] = Spawned
				;GroupList2.Add(Self.PlaceActorAtMe(varBaseActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
                iPosition = GroupList.Length - 1
                ;GroupList[iPosition].SetLinkedRef(kPatrolMarker) old sytem
				(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList2[iPosition])  ;new system for patrols
            endif
            iSpawnCounter += 1
        endwhile
		Group2Loaded = true
        if bBossAllowed == 1
            iSpawnCounter = 0 ; reuse var. memory efficient
            while (iSpawnCounter < iMaxBossCount)
                if (Utility.RandomInt(1,100) <= iBossChance)
					Spawned = Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel])
					GroupList2[iPosition] = Spawned
                    ;GroupList2.Add(Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
                    iPosition = GroupList.Length - 1
                    ;GroupList2[iPosition].SetLinkedRef(kPatrolMarker)
					(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList2[iPosition])
                endif
                iSpawnCounter += 1
            endwhile
        endif
		if (iRerollCount < iRerollLimit) && (Utility.RandomInt(1,100) <= iRerollChance)
			(MasterQuest as ASC_MasterRandomQuestScript).SpawnYetAnotherGroupR1(Self)
			iRerollCount += 1
			Debug.Notification("Rerolling for yet another group!")
		else
			Debug.Notification("Reroll 2 failed")
		endif
EndFunction

Function SpawnEvenMoreEnemyActors(int iMaxSpawnCount, int iChance, ActorBase varBaseActor, bool bBossAllowed, int iMaxBossCount, int iBossChance, ActorBase varBossActor, int iEzLevel, int iRerollAllowed, int iRerollChance)
    ;Form kMarker = Game.GetFormFromFile(0x00002ce2, "Fallout4.ESM")  old system for patroling based on physical marker network
	;ObjectReference kPatrolMarker = Game.FindClosestReferenceOfTypeFromRef(kMarker, Self as ObjectReference, 32.0)
	Actor Spawned = None
	int iDifficulty = ASC_Main_Difficulty_R1.GetValueInt()
    int iSpawnCounter = 0
	int iPosition = 0
    GroupList3 = new Actor[iPosition] ; since we don't have 100% chance of spawning actors, we need this to be an accumulating array
    Debug.Notification("Spawning enemies") ; unless we add a function parameter for text this had to be changed to be something generic
        while (iSpawnCounter < iMaxSpawnCount)
            if (Utility.RandomInt(1,100) <= iChance)
                Spawned = Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel])
				GroupList3[iPosition] = Spawned
				;GroupList3.Add(Self.PlaceActorAtMe(varBaseActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
                iPosition = GroupList.Length - 1
                ;GroupList3[iPosition].SetLinkedRef(kPatrolMarker) old sytem
				(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList3[iPosition])  ;new system for patrols
            endif
            iSpawnCounter += 1
        endwhile
		Group3Loaded = true
        if bBossAllowed == 1
            iSpawnCounter = 0 ; reuse var. memory efficient
            while (iSpawnCounter < iMaxBossCount)
                if (Utility.RandomInt(1,100) <= iBossChance)
                    Spawned = Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel])
					GroupList3[iPosition] = Spawned
					;GroupList3.Add(Self.PlaceActorAtMe(varBossActor, Utility.RandomInt(1,iDifficulty), (MasterQuest as ASC_MasterRandomQuestScript).EzArray[iEzLevel]))
                    iPosition = GroupList.Length - 1
                    ;GroupList[iPosition].SetLinkedRef(kPatrolMarker)
					(MasterQuest as ASC_MasterRandomQuestScript).ASC_PatrolPackageAlias.ApplyToRef(GroupList3[iPosition])
                endif
                iSpawnCounter += 1
            endwhile
        endif
EndFunction
 

 

 

 

Edit: I am also looking at another angle here, I'm thinking of ditching the arrays on the object altogether and the cleanup OnCellDetach event, in favor of applying a script to each actor via a referencealias that may be able to clean them up and track them better. One upside to that I'm considering is tracking their killers, so I can make a score system.

 

So in theory

 

-Marker script spawns the actor and we give it the refalias data via ApplyToRef() on it (scripts and AI)

-Scripts in the refalias include events for OnCellDetach or similar that will clean up the actor etc + OnCellAttach event to keep him loaded

-Script has OnKill or OnDeath event that each kill they get in a region up their "regional score"

-(Potentially if user enables this system), different actor types chances to spawn goes up or down depending on the score and maybe we could have an event happen where when the score gets high a special boss = group spawns that you battle it out with, and whoever wins claims the area (so all scores are reset)

 

Something along those lines anyway :wink:

Link to comment
Share on other sites

"ApplyToRef" won`t work for a script. It will add the script, but the script won`t work properly. The only way to add a working alias script is to make aliases filled on quest start. It won`t properly work with "ForceRefTo" either.

 

Maybe you can highlight that part of the script that does not work. It takes to long to find the part :wink: I think you would get more help.

 

You have so many different values there that it`s hard to find out where is the error. What the papyrus log says ?

I`ll just give you a simple example of an array that stores object references (it`s just simplified functions from the vanilla workshopobjectscript ):

 

Function CreateFurnitureMarkers() ; Function runs when we assign a new actor to the object
If myFurnitureBase ; if we have filled MyFurnitureBase property in the CK
ObjectReference newMarker = PlaceAtMe(myFurnitureBase)
myFurnitureMarkerRefs.Add(newMarker) ; an array defined outside of any function or event (ObjectReference[] myFurnitureMarkerRefs)
newMarker.MoveToNearestNavmeshLocation()
endFunction

 

Function DeleteFurnitureMarkers()

If myFurnitureMarkerRefs.Length > 0 ; if we do have any markers
int i = 0
While i < myFurnitureMarkerRefs.Length
myFurnitureMarkerRefs.SetActorRefOwner(none)
myFurnitureMarkerRefs.Delete()
i += 1
EndWhile
myFurnitureMarkerRefs.Clear()
EndIf
endFunction

 

Function HideMarkers()
int i = 0
int size = myFurnitureMarkerRefs.Length
While i < size
myFurnitureMarkerRefs.Disable()
i += 1
EndWhile
endFunction

Edited by kitcat81
Link to comment
Share on other sites

Ah i kinda suspected that might be the case with the refsliases, what a shame.

 

Its the SpawnEnemyActors function on the Object script. Its not filling the array at all.

 

Log is empty, nothing about anything in the mod at all. Seems very strange to me.

Link to comment
Share on other sites

The only way to add a working alias script is to make aliases filled on quest start. It won`t properly work with "ForceRefTo" either.

 

 

What makes you think that? I use forcerefto a lot and never had any problems. I use it on actors, doors, terminals, weapons, etc etc and not even once they failed to fill or had any problems with scripts. When I need to store variables I store them in properties so no problem there either.

 

Only issue I know with ForceRefTo is if you use it on actor on a scene that is running package, if you too it several times a row (more than once per second), it can mess up actors scene package.

Edited by vkz89q
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...