Jump to content

Understanding dynamic array correctly


SMB92

Recommended Posts

Regarding Q1, what I meant was how does the script fill in all the local variables in the function using the property group and in order?

So like,

Function Spawn (all properties in order here)

All local values filled in order here as per list above?

 

I think I understand what structs do based on your example and explanation, I am a little concerned about fillibg the properties though. This particular script was intended to be attached to a marker, I liked auto-filling as it made the job less tedious since mant many markers will be placed. Its seems like a cleaner system though.

 

Regarding PlaceActorAtMe, I sorta knew it was a bit heavy to use, but it does the job I want it do (I can set the encounter zone and the random difficulty which users can set the values for). PlaceAtMe seems to have CTDs sometimes, I read that actors can spawn under the map with it, but maybe this function is just as heavy anyway.

 

I think I should outline what systems we have planned. There is the random system, which is this script, which is attached to markers. There is then the Ambush system, which will bw similar but have a distance check event and be subject to smaller actor type lists depending on the location of the ambush. We will also have RadRoach infestation points, extra wildlife points that focus only on those types and subject to logical world placement. There is also talk of having a terminator stalk you, which would involve a quest. I'm also considering dividing main facrions from the random script and fiving them their own points and system, but haven't thought much about how that could balance out yet.

 

In the end, all globals I make here can be changed in a menu by the user so they can stuff with as many settings as they like. I wanted that level of customization. You mentioned performance issues with large arrays, the "presets" that i will make will not exceed 20 mist of the time and even then not much more, but users could go and set that to 100, but that is at their own peril.

 

Early talk of some sort of "civil war system" as well, where any faction could vie for control of a region. I am thinking to use a score based system and somehow using the arrays created by each spawn to track who killed who, amongst other relevant variables that could be used to determine "scores". A similar thing has been made in the unreleased beta of War of the Commonwealth which is based on a series of quests and variables for just the main factions alone, but as said its only early thoughts and I haven't studied that too much yet

Link to comment
Share on other sites

  • Replies 111
  • Created
  • Last Reply

Top Posters In This Topic

This is going to be a little out of order. So bear with me. Also, I know I can get pretty technical and into advanced subjects. Don't get discouraged. If you disregard things I say or suggest, but get a working product then great. You can always revisit and modify to improve later. Nobody, myself included, ever writes something that is perfect the first time. I've had scripts that started out as 5 lines, wound up at 5000 lines, and then got stripped down to 200 lines for the end result. All basically doing the same thing. As someone else mentioned there can be multiple ways of achieving the same end result. The ones I describe may not necessarily be the best.

 

It might be worth mentioning now while you're learning the development and how things work. Instead of just removing old code and changing it, comment it out for now and add new code to try. Then if it doesn't work out you can just delete the new stuff, or comment it out, and go back to the old without having to rewrite it. As you get more experienced this may be unnecessary. You could also use some sort of version management. I personally use TortoiseGit and do all my coding outside the CK with Notepad++. This allows me to track the changes and if a huge mistake was made I can just dump it all and go back to a previous point. Kind of like doing periodic backups if you will.

I think I understand what structs do based on your example and explanation, I am a little concerned about fillibg the properties though. This particular script was intended to be attached to a marker, I liked auto-filling as it made the job less tedious since mant many markers will be placed. Its seems like a cleaner system though.


Using autofill is handy but in the way you use it provides complexity to the script. Maybe it's necessary, maybe not. It also makes the script very usage specific. It cannot be re-used without heavy modification. Again, maybe that's how you want it. Not using autofill allows you to make a more generic utility that can be reused just by changing the values you give it. You can still have the flexibility of allowing the user to change settings to the globals. You just use the globals as the properties of the array.

 

Like I mentioned before, if you have many markers which would be identical, or at least very similar. You can make one, set the property array, then duplicate it. If changes need to be made then you can do so. The duplication process copies all the script attached properties intact. If you're placing lots of markers which have drastically different settings then yes, the filling of properties gets extremely tedious. Welcome to game design.

 

The way your original script was written, you'd need a different script for differing markers. Let's say you had 3 markers somewhat close to each other. One of them you want to have only Gunners and Raiders. Another you want Gunners and Triggermen. And the last you want Gunners, Raiders, and Triggermen. Your original script would be unsuable because it expects to have the parameters for every actor type supplied. This means you have 1 global value for spawn chance for a given actor type. So all 3 markers would get the spawn chance for Raiders. But you only want 2 of them to have a chance. You can't without having different scripts then. With the struct and array design you can specify only certain types for that marker, and then using the globals restrict that further. Perhaps I'm misunderstanding how the script works or what the actual design intent is, but that's how I saw it.

Regarding PlaceActorAtMe, I sorta knew it was a bit heavy to use, but it does the job I want it do (I can set the encounter zone and the random difficulty which users can set the values for). PlaceAtMe seems to have CTDs sometimes, I read that actors can spawn under the map with it, but maybe this function is just as heavy anyway.

I think I should outline what systems we have planned. There is the random system, which is this script, which is attached to markers. There is then the Ambush system, which will bw similar but have a distance check event and be subject to smaller actor type lists depending on the location of the ambush. We will also have RadRoach infestation points, extra wildlife points that focus only on those types and subject to logical world placement. There is also talk of having a terminator stalk you, which would involve a quest. I'm also considering dividing main facrions from the random script and fiving them their own points and system, but haven't thought much about how that could balance out yet.

In the end, all globals I make here can be changed in a menu by the user so they can stuff with as many settings as they like. I wanted that level of customization. You mentioned performance issues with large arrays, the "presets" that i will make will not exceed 20 mist of the time and even then not much more, but users could go and set that to 100, but that is at their own peril.

Early talk of some sort of "civil war system" as well, where any faction could vie for control of a region. I am thinking to use a score based system and somehow using the arrays created by each spawn to track who killed who, amongst other relevant variables that could be used to determine "scores". A similar thing has been made in the unreleased beta of War of the Commonwealth which is based on a series of quests and variables for just the main factions alone, but as said its only early thoughts and I haven't studied that too much yet


I like the ambitiousness of the idea. Something a lot of programmers (myself included) do though is write simple specific use code. Then realize they need it to do more, and try to modify that code to suit a multi purpose need. Or they'll write another script to handle the other need while reusing most of the code from the first with small changes. Very similar to what you originally did with the many functions to spawn each actor type. This creates a code nightmare if you need to go make changes that need to effect all of them. What I'm trying to do here is help explain development of a utilitarian code style that is still flexible but also easily modified. For example the way your original code was, let's say you wanted to change the boss spawning logic. You'd have to go edit every function for each actor type and region. IMHO a terrible design flaw. The way I rewrote it, you now have 1 function to modify which handles all of them. By using variables/properties or whatever, you have a method of including flexibility within that one function. There may be use cases where this is not desirable as well though.

I'd like to point out right now that there's a limitation to array sizes with the FO4 engine. They can only be 128 indexes in size. I was unaware of this myself until recently but apparently it's been a limit since Skyrim and FO3. I would imagine earlier as well.

One way people work around the spawning under the map issue is to place the marker in the air. When the actor then spawns, physics drops them to the floor. Obviously you don't need to be really high up, just not on the absolute floor. The spawning and falling through the floor is typically the cause of the CTD that most people encounter when using PlaceAtMe. Though if you wanted it to be assigned to the Encounter Zone then the PlaceActorAtMe is necessary.

Regarding Q1, what I meant was how does the script fill in all the local variables in the function using the property group and in order?
So like,
Function Spawn (all properties in order here)
All local values filled in order here as per list above?


Ok, so now we're gonna need to do some programming 101 here. Passing arguments. Arguments is the programming term used to indicate additional information. Sometimes also referred to as parameters. In this case the way I rewrote your Spawn(...) function was to take arguments, assigning them to local function variables. This means variables only seen to the function. So instead of all the globals being hard coded inside the function, when you call it you give it the variables to use. So a simple example to help wrap your head around it would be like this:

; SomethingToDisplay is a single argument given to this function
Function DisplaySomething(String SomethingToDisplay)
    ; do whatever needs to be done
    DisplayThis(SomethingToDisplay)
EndFunction

; We now call that function with code like this
DisplaySomething("The display text")
; Or using a property or a local variable
DisplaySomething(sSomeStringProperty)
; For papyrus we can also call giving it no arguments. Though when the function runs and tries to use the argument it will receive a None value.
DisplaySomething()

So here we have a function DisplaySomething() that needs some data given to it SomethingToDisplay which is a string type. Inside the function we do whatever we want, and when we need to reference the data relevant we use the local variable SomethingToDisplay. This gives us the contents that was passed in the argument.

; iMaxSpawnCount = how many spawned actors you want
; iChance = chance for a spawn to happen
; varBaseActor = any value that PlaceActorAtMe will accept. ActorBase, LvlList, etc.
; bBossAllowed = whether to allow boss
; iMaxBossCount = max number of bosses to roll spawns for
; iBossChance = chance per roll for a boss
; varBossActor = any value that PlaceActorAtMe will accept. ActorBase, LvlList, etc.
Function SpawnEnemyActors(int iMaxSpawnCount, int iChance, ActorBase varBaseActor, bool bBossAllowed, int iMaxBossCount, int iBossChance, ActorBase varBossActor)
    ; stuff
EndFunction

So here we've defined a function SpawnEnemyActors(...) which accepts 7 arguments. In the comment above the definition I briefly explained what each argument is for, simply as a reference. It's a good habit to get into documenting things like that. Not only for others who may read your code, but yourself as well. I've gone back to code months/years later and forgotten what some of it does. Reading the little comments I put in as reminders has helped immensely. As for the order, the definition specifies the order that is expected from the caller. So when calling they would need to be in the same order. Papyrus has a facility to allow calling without needing to fill every argument in order, but that gets a bit complex so we'll just stick to filling out every argument. Since the design of this function actually requires all of them. When you prepare for production use, error checking should be put in place to make sure everything is supplied before starting the all the looping code to prevent a bunch of potential errors. For example if you were to call this function and give it only a max spawn count, and chance but failed to fill the rest of the parameters with appropriate values, things would fail miserably. It would roll for a chance, if valid it would then try to place an actor of None. This would immediately fail and halt execution of the script. If papyrus logging is turned on you'll get a stack dump with the error in the log file. Nothing more would happen until something triggers another event to cause it to re-run. Such as the OnCellDetach.

I hope that explained what you are confused about. Some other reading I'd recommend, though you may not understand it yet:

https://www.creationkit.com/fallout4/index.php?title=Function_Reference
https://www.creationkit.com/fallout4/index.php?title=Flag_Reference

Edited by BigAndFlabby
Link to comment
Share on other sites

 

This is going to be a little out of order. So bear with me. Also, I know I can get pretty technical and into advanced subjects. Don't get discouraged.

I'm not daunted at all mate, best I study into the advanced subjects now so the full potential can be realised and the direction of the mod decided sooner. My original code has advanced as I have realised more and more optimisations and/or bugs (sometimes false positives lol) and I've pretty much gotten to the stage now, where I feel (keyword there FEEL) I need to explore all the unknowns (which was at the point of studying into arrays and their potential)

 

 

Using autofill is handy but in the way you use it provides complexity to the script. Maybe it's necessary, maybe not. It also makes the script very usage specific. It cannot be re-used without heavy modification. Again, maybe that's how you want it. Not using autofill allows you to make a more generic utility that can be reused just by changing the values you give it. You can still have the flexibility of allowing the user to change settings to the globals. You just use the globals as the properties of the array.

Like I mentioned before, if you have many markers which would be identical, or at least very similar. You can make one, set the property array, then duplicate it. If changes need to be made then you can do so. The duplication process copies all the script attached properties intact. If you're placing lots of markers which have drastically different settings then yes, the filling of properties gets extremely tedious. Welcome to game design.
The way your original script was written, you'd need a different script for differing markers. Let's say you had 3 markers somewhat close to each other. One of them you want to have only Gunners and Raiders. Another you want Gunners and Triggermen. And the last you want Gunners, Raiders, and Triggermen. Your original script would be unsuable because it expects to have the parameters for every actor type supplied. This means you have 1 global value for spawn chance for a given actor type. So all 3 markers would get the spawn chance for Raiders. But you only want 2 of them to have a chance. You can't without having different scripts then. With the struct and array design you can specify only certain types for that marker, and then using the globals restrict that further. Perhaps I'm misunderstanding how the script works or what the actual design intent is, but that's how I saw it.
I like the ambitiousness of the idea. Something a lot of programmers (myself included) do though is write simple specific use code. Then realize they need it to do more, and try to modify that code to suit a multi purpose need. Or they'll write another script to handle the other need while reusing most of the code from the first with small changes. Very similar to what you originally did with the many functions to spawn each actor type. This creates a code nightmare if you need to go make changes that need to effect all of them. What I'm trying to do here is help explain development of a utilitarian code style that is still flexible but also easily modified. For example the way your original code was, let's say you wanted to change the boss spawning logic. You'd have to go edit every function for each actor type and region. IMHO a terrible design flaw. The way I rewrote it, you now have 1 function to modify which handles all of them. By using variables/properties or whatever, you have a method of including flexibility within that one function. There may be use cases where this is not desirable as well though.

WOTC uses arrays for pretty much everything, I guess I can understand why now. I had wondered this quite a bit.

 

To clarify the random code itself was meant to hold a lot of different Actor Types/Races, I wasn't intending on removing any for specific locations as this marker is for "generic" locations, where anything on that list could spawn. I wasn't quite happy with how I was cycling through said list, or the whole reroll system (which is currently limited to happening just once, I sorta wanted users to be able to set a limit on that themselves as well, at their own peril lol). However, there a few things that bring that undone already (not even considering "civil war" implementation). The first thing being DLC implementation. I will have to refill all the markers properties anyway when adding the DLC Actor types to the list, which happens that not all markers I want to have DLC spawns at (I had no intention of having Fog Crawlers walking around town, limit them to the coast etc etc). Then as you mentioned, there are points I want to have without certain actor types, and I had planned to attach a customised version of the script. If we start talking about a civil war type system, if I wanted to remove a group from an area, in effect I am also lowering the chances of spawns in an area at all with my current script (but I was kinda letting that happen anyway letting users turn off various actor types, again coming back to me not being 100% happy with the reroll system etc).

 

So with that alone, I realise the coding nightmare you speak of, I stand to lose track of everything very quickly. It's also still in the back of my head, am I better off having this script tied to a quest and run dynamically, which picks out a marker to use as a spawn point as you go (which I spoke about on the other thread), thus making the whole thing dynamic? I'm also sorta wondering if I could use that to have all the other "systems" integrated to the one script (but probably I can't because the script would never be able to know the different types of base markers I'm placing and what I want to spawn there)

 

 

I'm having a look at those links you posted, I'll do some more reading on some of the other things as well.

Link to comment
Share on other sites

Just reading the Flags page there on Const properties, I need users Globals to be read at runtime from the save game, otherwise they'd always have the defaults from CK.

 

I think I'll go along the lines of what you mentioned and have an update script, something that looks at version change, and in the mod menu, have a second global that remembers the user settings as well as an extra value that I can return as a bool that says if the user has set custom values outside the presets.

Link to comment
Share on other sites

Let's see if I'm getting an understanding of things so far. Looking at what you've shown me, I wonder if I can do something like this: (Sorry, haven't time to write it in code right now)

 

Lets say I have a master script that contains a struct for each Actor type. Lets say that this script updates when users update their settings. In this script, all the structs for each Actor Type are defined in an array. So when we do the roll "iWhoToSpawn, we pick out a struct currently present in said array. So in effect, instead of having a check to see if a Actor type is allowed at all, it won't even be present if it's not, then I can purely have the reroll function for what I originally intended for, to emulate a battle (instead of setting up a scene and placing at a point if you get what I mean). I brought in he "reroll on block" as a workaround for the shortcoming in the code that I mentioned earlier.

 

Would it also be possible (I think I might be dreaming a bit here) to get the parameters for each actor type (like you did in your revision of my script) out of the struct which is defined inside the array? I'm a bit cloudy on that one but I'm seeing "something in the distance" so to speak.

 

EDIT: this could potentially make use of "defining parameters out of order" as you mentioned, if I also understand that correctly. Maybe, maybe not necessary.

 

Basically the picture I have in my head is avoiding the 128 (512 bit) limit on these arrays whilst still retaining all my variables. The other thing being, having a single master code for each system would make the whole filling properties easier, only a small script would need be placed on each marker with only that script as a property.

 

Forgive me if I'm going off the beaten track here :wink:

 

Going off of this:

Struct ActorTypeStruct
    ActorBase LvlActorBase
    ActorBase LvlActorBossBase
    GlobalVariable ASC_Allowed
    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
EndStruct

ActorTypeStruct[] Property ActorTypes Auto Const ; this is const so that any additional entries we put in the array are passed to the script whenever it checks the contents of the array. the only time this will be inaccrurate is if a save was created in the middle of the spawn function running and then the mod updated to have changes to the array.

Function Spawn()
    int iNumSpawnTypes = ActorTypes.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 = ActorTypes[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)
        RerollCheck(spawnDetails.ASC_Reroll_Chance.GetValueInt())
    ;else
        ; should there be something to handle a case where we're not allowed and have no reroll allowance? the way this is right now, if both were 0 then nothing would get spawned and the script stalls until the cell unloads and the spawn is called again on the new cell load.
    endif
EndFunction
Link to comment
Share on other sites

Just reading the Flags page there on Const properties, I need users Globals to be read at runtime from the save game, otherwise they'd always have the defaults from CK.

 

I think I'll go along the lines of what you mentioned and have an update script, something that looks at version change, and in the mod menu, have a second global that remembers the user settings as well as an extra value that I can return as a bool that says if the user has set custom values outside the presets.

 

That's slightly misleading in regards to GlobalVariables. You can look at it a little differently. You're always reading whatever the CK is pointing to. The difference is that you're passing a pointer reference not actual data. So it's not really an exception to the rule. You're really always passing references unless it's a primitive like int, bool, or the exception a string. Anytime the property is a quest, or some sort of form, it's always a reference pointer to an object. The key is that if you don't use const in the script definition of the property, the pointer is stored in the save. If you modify the desired content in CK the pointer in the running script isn't changed because that's in the save. With globals the global value is in the save but not the pointer. The pointer is pulled from the value specified in the CK. You get it?

 

This is going to basically reiterate what I said a little differently. Try to look at it like this:

 

In the script you have a property

 

GlobalVariable Property SomeProperty Auto Const

 

Basically the same thing you'd be using in your script code. Now in CK you assign that property to use the GlobalVariable MyCustomGlobalVar. You've now told the game to give the script a pointer to the global MyCustomGlobalVar. You can still change the value of the global from script code using SetValue() and get the value with GetValue()/GetValueInt(). That change is stored in the save as long as the GlobalValue as defined in CK isn't a const. You can have a holo tape or another script, quest, whatever to change the GlobalVariable value. The value every time you use GetValue()/GetValueInt() is checked against whatever object the property is pointing to. The reason it needs to be const is to get the real global pointer from the ck data. Let's say some time later there's a reason you need to have SomeProperty use the global MyOtherGlobalVar instead of MyCustomGlobalVar. If you change it in CK without the script using it as const, the script never knows. It still uses the reference to MyCustomGlobalVar instead because the non-const properties are saved in the save file. If it's const, then the next time the script executes it looks at MyOtherGlobalVar instead because the pointer is always whatever CK points to. I'm over simplifying how it really works behind the scenes but I think this is the best way to grasp logically how it will respond.

 

Let's see if I'm getting an understanding of things so far. Looking at what you've shown me, I wonder if I can do something like this: (Sorry, haven't time to write it in code right now)

 

Lets say I have a master script that contains a struct for each Actor type. Lets say that this script updates when users update their settings. In this script, all the structs for each Actor Type are defined in an array. So when we do the roll "iWhoToSpawn, we pick out a struct currently present in said array. So in effect, instead of having a check to see if a Actor type is allowed at all, it won't even be present if it's not, then I can purely have the reroll function for what I originally intended for, to emulate a battle (instead of setting up a scene and placing at a point if you get what I mean). I brought in he "reroll on block" as a workaround for the shortcoming in the code that I mentioned earlier.

 

Would it also be possible (I think I might be dreaming a bit here) to get the parameters for each actor type (like you did in your revision of my script) out of the struct which is defined inside the array? I'm a bit cloudy on that one but I'm seeing "something in the distance" so to speak.

 

EDIT: this could potentially make use of "defining parameters out of order" as you mentioned, if I also understand that correctly. Maybe, maybe not necessary.

 

Basically the picture I have in my head is avoiding the 128 (512 bit) limit on these arrays whilst still retaining all my variables. The other thing being, having a single master code for each system would make the whole filling properties easier, only a small script would need be placed on each marker with only that script as a property.

Ok, I think I understand what you're trying to do. I'm not sure I understand what you mean by create multiple structs though. You would only define one struct type. That would have all the variables related to all the types of actors you'd use.

 

I'm thinking maybe you're misunderstanding how they're used so I'll oversimply that here. Think of it like this. A struct is a house. Inside the house is the people that live there, the variables.

 

Struct ActorTypeStruct
    ActorBase LvlActorBase
    ActorBase LvlActorBossBase
    GlobalVariable ASC_Allowed
    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
EndStruct
 
ActorTypeStruct[] Property ActorTypes Auto Const ; this is const so that any additional entries we put in the array are passed to the script whenever it checks the contents of the array. the only time this will be inaccrurate is if a save was created in the middle of the spawn function running and then the mod updated to have changes to the array.
 
ActorTypeStruct SingleActorVal = new ActorTypeStruct ; this is not actually a valid definition unless inside a function. only for demonstrative purposes.

SingleActorVal was added for demonstrative purposes only. The array of ActorTypes is a street block full of houses. You can reference each occupant of the house like such SingleActorVal.LvlActorBase or SingleActorVal.ASC_Chance. If you needed to refence the first house on the block, and the ASC_Allowed_Boss occupant you'd go ActorTypes[0].ASC_Allowed_Boss. I hope that helps.

Edited by BigAndFlabby
Link to comment
Share on other sites

 

 

 

Just reading the Flags page there on Const properties, I need users Globals to be read at runtime from the save game, otherwise they'd always have the defaults from CK.

I think I'll go along the lines of what you mentioned and have an update script, something that looks at version change, and in the mod menu, have a second global that remembers the user settings as well as an extra value that I can return as a bool that says if the user has set custom values outside the presets.


That's slightly misleading in regards to GlobalVariables. You can look at it a little differently. You're always reading whatever the CK is pointing to. The difference is that you're passing a pointer reference not actual data. So it's not really an exception to the rule. You're really always passing references unless it's a primitive like int, bool, or the exception a string. Anytime the property is a quest, or some sort of form, it's always a reference pointer to an object. The key is that if you don't use const in the script definition of the property, the pointer is stored in the save. If you modify the desired content in CK the pointer in the running script isn't changed because that's in the save. With globals the global value is in the save but not the pointer. The pointer is pulled from the value specified in the CK. You get it?

This is going to basically reiterate what I said a little differently. Try to look at it like this:

In the script you have a property

GlobalVariable Property SomeProperty Auto Const


Basically the same thing you'd be using in your script code. Now in CK you assign that property to use the GlobalVariable MyCustomGlobalVar. You've now told the game to give the script a pointer to the global MyCustomGlobalVar. You can still change the value of the global from script code using SetValue() and get the value with GetValue()/GetValueInt(). That change is stored in the save as long as the GlobalValue as defined in CK isn't a const. You can have a holo tape or another script, quest, whatever to change the GlobalVariable value. The value every time you use GetValue()/GetValueInt() is checked against whatever object the property is pointing to. The reason it needs to be const is to get the real global pointer from the ck data. Let's say some time later there's a reason you need to have SomeProperty use the global MyOtherGlobalVar instead of MyCustomGlobalVar. If you change it in CK without the script using it as const, the script never knows. It still uses the reference to MyCustomGlobalVar instead because the non-const properties are saved in the save file. If it's const, then the next time the script executes it looks at MyOtherGlobalVar instead because the pointer is always whatever CK points to. I'm over simplifying how it really works behind the scenes but I think this is the best way to grasp logically how it will respond.

Let's see if I'm getting an understanding of things so far. Looking at what you've shown me, I wonder if I can do something like this: (Sorry, haven't time to write it in code right now)

Lets say I have a master script that contains a struct for each Actor type. Lets say that this script updates when users update their settings. In this script, all the structs for each Actor Type are defined in an array. So when we do the roll "iWhoToSpawn, we pick out a struct currently present in said array. So in effect, instead of having a check to see if a Actor type is allowed at all, it won't even be present if it's not, then I can purely have the reroll function for what I originally intended for, to emulate a battle (instead of setting up a scene and placing at a point if you get what I mean). I brought in he "reroll on block" as a workaround for the shortcoming in the code that I mentioned earlier.

Would it also be possible (I think I might be dreaming a bit here) to get the parameters for each actor type (like you did in your revision of my script) out of the struct which is defined inside the array? I'm a bit cloudy on that one but I'm seeing "something in the distance" so to speak.

EDIT: this could potentially make use of "defining parameters out of order" as you mentioned, if I also understand that correctly. Maybe, maybe not necessary.

Basically the picture I have in my head is avoiding the 128 (512 bit) limit on these arrays whilst still retaining all my variables. The other thing being, having a single master code for each system would make the whole filling properties easier, only a small script would need be placed on each marker with only that script as a property.


Ok, I think I understand what you're trying to do. I'm not sure I understand what you mean by create multiple structs though. You would only define one struct type. That would have all the variables related to all the types of actors you'd use.

 

I'm thinking maybe you're misunderstanding how they're used so I'll oversimply that here. Think of it like this. A struct is a house. Inside the house is the people that live there, the variables.

Struct ActorTypeStruct
    ActorBase LvlActorBase
    ActorBase LvlActorBossBase
    GlobalVariable ASC_Allowed
    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
EndStruct
 
ActorTypeStruct[] Property ActorTypes Auto Const ; this is const so that any additional entries we put in the array are passed to the script whenever it checks the contents of the array. the only time this will be inaccrurate is if a save was created in the middle of the spawn function running and then the mod updated to have changes to the array.
 
ActorTypeStruct SingleActorVal = new ActorTypeStruct ; this is not actually a valid definition unless inside a function. only for demonstrative purposes.

 

 

 

Okay I get it now, that little wiki entry threw me off a bit. After posting that I kinda realised that lol.

 

Regarding my other post above with structs etc, I think I realise now this is exactly what you done in that snippet lol. I just sat down (just got my youngest to sleep lol) and looked at writing said code while looking at yours.

Link to comment
Share on other sites

So you wouldn't have this for example:

 

 

 

Struct RaiderTypeStruct
    ActorBase LvlActorBase
    ActorBase LvlActorBossBase
    GlobalVariable ASC_Allowed
    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
EndStruct

Struct GunnerTypeStruct
    ActorBase LvlActorBase
    ActorBase LvlActorBossBase
    GlobalVariable ASC_Allowed
    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
EndStruct

 

 

 

But you'd have this for example:

 

 

Struct ActorTypeStruct
    ActorBase LvlRaider
    ActorBase LvlRaiderBoss
	ActorBase LvlGunner
    ActorBase LvlGunnerBoss
	ETC ETC ETC
    GlobalVariable ASC_Allowed
    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
EndStruct

 

 

 

And each Array contains the relevant reference to the global for that type?

 

 

iMaxSpawnCount = iMaxSpawnCountArray[iWhoToSpawn].GetValueInt()
iChance = ETC ETC ETC
varBaseActor = 
bBossAllowed = 
iMaxBossCount = 
iBossChance = 
varBossActor = 

 

 

 

For that last one, suppose you could pass them as parameters as well, I'm just being lazy here.

 

What I was thinking is, if I had multiple structs in an array, I could remove a whole Actor Type from the array so it would never even be looked at if it were disabled, instead of having say ASC_Allowed_Raider_R1 etc etc etc. So using your analogy, I'll only have the houses I (the user) want present on the street, if that makes sense. That's just the first thing that came to mind when I really looked at it.

Link to comment
Share on other sites

So you wouldn't have this for example:

 

 

 

Struct RaiderTypeStruct
    ActorBase LvlActorBase
    ActorBase LvlActorBossBase
    GlobalVariable ASC_Allowed
    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
EndStruct

Struct GunnerTypeStruct
    ActorBase LvlActorBase
    ActorBase LvlActorBossBase
    GlobalVariable ASC_Allowed
    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
EndStruct

 

 

But you'd have this for example:

 

 

Struct ActorTypeStruct
    ActorBase LvlRaider
    ActorBase LvlRaiderBoss
	ActorBase LvlGunner
    ActorBase LvlGunnerBoss
	ETC ETC ETC
    GlobalVariable ASC_Allowed
    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
EndStruct

 

 

And each Array contains the relevant reference to the global for that type?

 

 

iMaxSpawnCount = iMaxSpawnCountArray[iWhoToSpawn].GetValueInt()
iChance = ETC ETC ETC
varBaseActor = 
bBossAllowed = 
iMaxBossCount = 
iBossChance = 
varBossActor = 

 

 

For that last one, suppose you could pass them as parameters as well, I'm just being lazy here.

 

What I was thinking is, if I had multiple structs in an array, I could remove a whole Actor Type from the array so it would never even be looked at if it were disabled, instead of having say ASC_Allowed_Raider_R1 etc etc etc. So using your analogy, I'll only have the houses I (the user) want present on the street, if that makes sense. That's just the first thing that came to mind when I really looked at it.

 

 

Eh no. The struct, as I posted it, would be used. The array created in CK and attached to the object and configured. I could give a visual example if I knew what you were going to attach the script to. An XMarker is a static so you can't put a script on it. Anything else you plan to use?

 

*Edit: Here's a sample of how you'd create the array. Then when the script fires it checks length and rolls to get a random within the array limits.

 

This is the top of the script I used for the example. I didn't create all the globals just the ones I was going to use in the array. After I do the first entry I show how to use the filter better to get a smaller list to make the filling faster. Still kinda tedious.

 

 

GlobalVariable Property ASC_Main_ModEnabled Auto Const
GlobalVariable Property ASC_Main_RandomEnabled_R1 Auto Const
GlobalVariable Property ASC_Main_Random_Chance_R1 Auto Const
GlobalVariable Property ASC_Main_Random_DisableOnBlock_R1 Auto Const
FormList Property ASC_ResetList_R1 Auto Const
Actor Property PlayerRef Auto Const
ObjectReference Property PatrolMarker Auto Const
GlobalVariable Property ASC_Main_Difficulty_R1 Auto Const
GlobalVariable Property ASC_Reroll_Main_Chance_R1 Auto Const
GlobalVariable Property ASC_Reroll_Main_R1 Auto Const
GlobalVariable Property ASC_DeleteTimer_R1 Auto Const
 
Struct ActorTypeStruct
    ActorBase LvlActorBase
    ActorBase LvlActorBossBase
    GlobalVariable ASC_Allowed
    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
EndStruct
 
ActorTypeStruct[] Property ActorTypes Auto Const ; this is const so that any additional entries we put in the array are passed to the script whenever it checks the contents of the array. the only time this will be inaccrurate is if a save was created in the middle of the spawn function running and then the mod updated to have changes to the array.

https://www.youtube.com/watch?v=DpmIvovS9jc

Edited by BigAndFlabby
Link to comment
Share on other sites

I guess I was seeing things with the structs. Ah well nvm.

 

 

I was attaching the script to an XmarkerHeading that i duplicated and renamed, although I recently heard placing a script on a static is a bad idea.

 

What I'm thinking now is to just have a master script (probably attached to a quest), with child scripts attached to patrol marker or something getting the already defined info from the master and having the spawn function on the child.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...