Jump to content

Understanding dynamic array correctly


SMB92

Recommended Posts

Thanks very much for your help so far BnF, would have still been in the stone age without ya. I'm gonna go do some serious play with it now and start getting things polished/set up.

 

@kitcat81 - thanks for all your help so far as well :) For the random spawn markers, I'd prefer they just run the spawn() function themselves, they fire on a chance variable so not all of them will spawn something. But the code you mentioned there is exactly how I want the Ambush type points to work. There will be more functions and values stored in the main quests relative to each type/system so I'm not really wasting them on just storing arrays. Or maybe it is just better to have the function in the quest, I'm not sure if there is any difference or if I'd need to code it differently to make the SpawnEnemyActors() function in the local script work properly

Link to comment
Share on other sites

  • Replies 111
  • Created
  • Last Reply

Top Posters In This Topic

  On 5/28/2017 at 9:02 AM, BigAndFlabby said:

 

  On 5/28/2017 at 8:39 AM, SMB92 said:

Done everything like you mentioned and finally, it compiles (Ship It™)

 

 

  Reveal hidden contents

 

 

EDIT: Confirming that the array is no longer a property on the marker script!

 

Just thought about your mention to move SpawnEnemyActors to the quest script. While you can do that, as it is it doesn't really matter either way. You'd need to make sure to add an argument to the function so you can pass the marker ObjectReference. Then in the SpawnEnemyActors function change the self in the uses of self.PlaceActorAtMe to the argument variable.

 

My problem with that is, I want to store the array of spawned actors on the local script, so I can clean them up or do other things with them later. As mentioned above though, if it is better to have the Spawn() function on the Quest, I could do that, but I'm not sure what changes would have to be made for the SpawnEnemyActors function on the local script so that all the parameters etc would still be passed etc, or maybe I don't have to do anything at all?

 

So visually (because I'm crap at explaining things lol) the script would look like this?

 

  Reveal hidden contents

 

 

And the quest like this

 

  Reveal hidden contents

 

 

If this just works like this than that's great, but the wikis give me the impression I need to do something else for everything to work properly?

Link to comment
Share on other sites

  On 5/28/2017 at 9:07 AM, SMB92 said:

Thanks very much for your help so far BnF, would have still been in the stone age without ya. I'm gonna go do some serious play with it now and start getting things polished/set up.

 

@kitcat81 - thanks for all your help so far as well :smile: For the random spawn markers, I'd prefer they just run the spawn() function themselves, they fire on a chance variable so not all of them will spawn something. But the code you mentioned there is exactly how I want the Ambush type points to work. There will be more functions and values stored in the main quests relative to each type/system so I'm not really wasting them on just storing arrays. Or maybe it is just better to have the function in the quest, I'm not sure if there is any difference or if I'd need to code it differently to make the SpawnEnemyActors() function in the local script work properly

Not at all! ;) You just mentioned that filling properties on every marker and changing them in case of an update can be a problem. In this case you move all the functionality and properties to the quest and the marker only has to detect the right moment and to run the spawn function that is defined in the quest. So you can change any property or function later and this won`t break anything.

Edited by kitcat81
Link to comment
Share on other sites

  Quote

 

Not at all! ;) You just mentioned that filling properties on every marker and changing them in case of an update can be a problem. In this case you move all the functionality and properties to the quest and the marker only has to detect the right moment and to run the spawn function that is defined in the quest. So you can change any property or function later and this won`t break anything.

Cool, I'll have a play with that as well!

Link to comment
Share on other sites

  On 5/28/2017 at 9:45 AM, SMB92 said:

 

 

You're gonna want to remove the line

import ASC_MasterRandomQuestScript

from the ASC_Random script. You're already importing the struct. There's no need to import the quest script. Doing so will give a duplicate array. Won't hurt anything as long as you don't try to use it inadvertently.

Link to comment
Share on other sites

  On 5/28/2017 at 9:49 AM, BigAndFlabby said:

 

  On 5/28/2017 at 9:45 AM, SMB92 said:

Â

Â

You're gonna want to remove the line

import ASC_MasterRandomQuestScript
from the ASC_Random script. You're already importing the struct. There's no need to import the quest script. Doing so will give a duplicate array. Won't hurt anything as long as you don't try to use it inadvertently.

Cheers, I'll do that.

Link to comment
Share on other sites

@BnF - Just wanted to ask one thing before I go to sleep. In the Spawn() function you mentioned that there might have to be something in the else block if both the first blocks returned none/false

Function Spawn()
    int iNumSpawnTypes = (ASC_MasterRandomQuest as ASC_MasterRandomQuestScript).ActorTypesR1.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 = (ASC_MasterRandomQuest as ASC_MasterRandomQuestScript).ActorTypesR1[iWhoToSpawn]
    if (spawnDetails.ASC_Allowed.GetValueInt() == 1)
        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)
    elseif (spawnDetails.ASC_Allowed.GetValueInt() == 0) && (spawnDetails.ASC_Reroll_Allowed.GetValueInt() == 1)   ;Reroll for another spawn once, if elected group is not allowed as per user settings
        RerollCheck(spawnDetails.ASC_Reroll_Chance.GetValueInt())
    else     
		;Not sure what to do here to stop script from stalling
    endif
EndFunction

Would you just link that to another bogus function that just does something for the sake of it (or nothing) just to complete the code? Or something specific?

 

BTW here is a more polished up version now:

 

  Reveal hidden contents

 

Link to comment
Share on other sites

  On 5/28/2017 at 2:16 PM, SMB92 said:

@BnF - Just wanted to ask one thing before I go to sleep. In the Spawn() function you mentioned that there might have to be something in the else block if both the first blocks returned none/false

Function Spawn()
    int iNumSpawnTypes = (ASC_MasterRandomQuest as ASC_MasterRandomQuestScript).ActorTypesR1.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 = (ASC_MasterRandomQuest as ASC_MasterRandomQuestScript).ActorTypesR1[iWhoToSpawn]
    if (spawnDetails.ASC_Allowed.GetValueInt() == 1)
        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)
    elseif (spawnDetails.ASC_Allowed.GetValueInt() == 0) && (spawnDetails.ASC_Reroll_Allowed.GetValueInt() == 1)   ;Reroll for another spawn once, if elected group is not allowed as per user settings
        RerollCheck(spawnDetails.ASC_Reroll_Chance.GetValueInt())
    else     
        ;Not sure what to do here to stop script from stalling
    endif
EndFunction
Would you just link that to another bogus function that just does something for the sake of it (or nothing) just to complete the code? Or something specific?

 

BTW here is a more polished up version now:

 

  Reveal hidden contents

 

I had originally commented out the else on the Spawn function because it was empty. Leaving it there empty doesn't hurt either. I just wasn't sure if there was something you wanted to do if the first 2 checks failed.

 

The changes you made to OnCellDetach are a good try. The while loop for checking if player is in combat shoud have a wait so it doesn't eat a ton of cycles and freeze up the machine.

 

        while (PlayerRef.IsInCombat() == true)
            ; Do nothing until combat is over, then check if we are still in the loaded area
            Utility.Wait(0.1)
        endwhile

You could also refactor that to put the loop in the first check and drop the check on the initial if statement. Though on a side note. Checking if they're in combat doesn't really work well here because we could have left the area and are in combat somewhere else and the script will halt. It probably won't hurt anything but just something to take note of. I should point out that the cell doesn't get unloaded until you're pretty far away. Like Sanctuary to Starlight drive in far. So the initial 10s wait probably isn't necessary. Nor the wait on combat. Unless a mod is involved the enemies won't follow that far. I think this would do what you want.

 

Event OnCellDetach()
    bSpawnPointLoaded = false
    ;Utility.Wait(10) ; Not really necessary but left for reference
    while (PlayerRef.IsInCombat()) ; also may not be necessary but reference for sanity check. never do a while loop without something to do inside. if you don't have anything to do then do a little pause before looping.
        ; Do nothing until combat is over, then check if we are still in the loaded area
        Utility.Wait(0.1)
    endwhile
    if (bSpawnPointLoaded == false) ; make sure we are still out of loaded area
        int iCounter = 0
        while iCounter < GroupList.Length
            GroupList[iCounter].SetLinkedRef(None)
            GroupList[iCounter].DeleteWhenAble()
            iCounter += 1
        endwhile
        GroupList.Clear()
        Debug.Notification("All members cleared from array")
    endif
EndEvent
Link to comment
Share on other sites

Thanks for the optimization.

 

From my testing, the cells detach fairly close (inline with ugrids settings), I could see this with the debug note when testing that before. I couldn't use OnUnload I think due to some parts of it still being persistent and never getting the event. Unless I never walked far away enough for it to get the event :P

 

I guess the idea behind the IsInCombat check and the initial 10 second timer, I have seen in WOTC some enemies being "cleaned up" when I've only been out of the cell for a few seconds. And it could be possible for the player to engage combat with another group while backing away from one group etc, and end up crossing 10 cells or so. So in my mind it was the lesser evil to have the check. The 10 seconds timer, I was thinking to make a Global for it as well, so users can decide said timer. That was the intentions anyway.

 

I added a new item to the struct as well, ASC_Ez_Lvl, and an array on the quest of all the EZ's I have made. Also because I wasn't sure about the "script stalling" a made a new function that could rearm the point if nothing actually happened

 

  Reveal hidden contents

 

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

 

 

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 :)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...