Jump to content

Code to get an object based on distance


SMB92

Recommended Posts

You can try OnCellAttach. It will ensure that nothing spawns for as long as the player isn't in the cell. OnLoad can fire before you enter.

 

Markers are statics, and the find functions may not pick up your markers for this reason, especially if they are not in an ObjectReference property. As you are concerned about persistence, it means they aren't in properties. So you can try this instead:

 

Form kMarker = Game.GetFormFromFile(0x00000034, "Fallout4.ESM") ; XmarkerHeadings, or use the formID 0x0000003B for xmarkers if using those)
ObjectReference kRandMarker = .Game.FindRandomReferenceOfTypeFromRef(kMarker, Game.GetPlayer(), 4096.0) ; radius is length of a cell.

This will ensure that it ONLY searches for XmarkerHeadings and not pick up other markers, and beth uses ton of markers have you've seen. Do not make arCenter the marker though, in case you want to do that. The find functions will always return arCenter if its the same type as arBaseObject.

 

I know that doesn't help much with the initial problem. I like to use dummy markers specifically for this and then do things to the real object I want to use through a script on the dummy marker.

Thx for the reply.

 

Say I made a property out of the base marker, which is a duplicated XmarkerHeading that I've named ASC_SPP. So the base form will be persistent, but perhaps the actual instances of it I place won't be. If you get what I mean. I'm not sure what that would translate to in terms of persistence for the actual placed markers of the same base object, but I am kinda assuming this would be the way around it (as I won't be able to reference the formID directly from my ESM?). Also If I go and get the regular xmarkerheading around the map, I might cause problems with other things, as well as god knows where spawns are actually ending up :D

 

For my tests of the spawn code, I have markers placed with OnCellAttach events already, basically I want to avoid any placed objects with any code on them at all, seems they will end up in the savegame and effectively blow it up on uninstall.

 

There doesn't seem to be any reliable or straight up code to find an object > or in between "N" units away from centre of search, so far all I can think to do is spawn a marker at the player and move it "N" units in front of the player and do the search around it, which I don't like the idea of for some obvious reasons including latency. If I get a marker too close to the player we'll have groups popping in out of nowhere which would be super immersive :sad:

 

Idk atm, so much codes in my head lol. Just for fun here is a brief of what the code should look like ideally:

 

State Find

Find me a marker

SP = marker

GoToState Spawn

EmdState

 

State Spawn

if SP = none

gotostate wait

else run spawncode on marker

EndState

 

State Wait

StartTimer (definedtimer)

timerrunning = true (this is security feature for other code)

 

Event OnTimer

timerrunning = false

GoToState Find

EndState

 

Simple in theory :D

Link to comment
Share on other sites

  • Replies 40
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Yay 3000th post :)

 

Had a bit of a revelation over a cigarette.

 

Maybe what I can do is run the code as normal to get a marker and then go to an additional "check distance" state where I check if the marker is over and under the specified amount of units away and if not send it back to the find state and keep looping that until I get one. I sorta need to run a check at some stage anyway, because what I am doing is checking if the marker is disabled, as I have my own respawn timer etc independent of the games, so maybe I can move that check out of the spawn code as well.

 

I think I mentioned this earlier but I wasn't seeing it as clearly as I am now.

Link to comment
Share on other sites

I can either use a quest or an object in a persistent cell that loads at game start to receive the event, however I am preferring a quest so I can set stages to run other codes depending on the status of the mod (think uninstall stage etc). I believe the quest is also preferable for reliability in saving the state of the code, rather than forcing an OnLoad event everytime.

 

Problem with adding scripts to markers is, 1. They are persistent in the save game and 2. Multiple instances of scripts firing close by modify each others values. Example for the latter, if I have a timer in the "generic" script each time one fires it resets the timer on all of them. I'm not sure this is suppose to happen but thats what I saw with that. It would be a tremendous amount of work to make individual points, which could amount to the thousands.

 

Regarding the marker being invisible and load events, they seem to present even when not persistent, which would be required they not be persistent, or we could end up with spawns outside of loaded areas occasionally.

 

The code you posted above is really good for "ambush" type spawns, because their markers are few and far between. So you've have indeed answered a question I haven't even asked myself yet :D

I mostly created craftable settlement objects, I have not tried to add objects to cells :smile:. Maybe it works in another way. On my experince each objects has it`s own copy of the script and it runs indephendantly. But maybe you are right and it`s not the best option in this case. Not sure that I understood about persistance. Did you mean that all markers in the game are persistent? And how many markers do you have in one cell? You can try to go with a quest that is registered for some events (location change, cell change, might be other events for the player)...When the event fires the quest start itself and applies alises to markers in loaded area. Aliases can have a script that registers them for "distancelessthanevent". Function "find" seems to work for any type of object (static , activator etc). But it wants a radius. I doubt it can work with <>. But not sure about that.

You can check the distance this way:

Event ;for example,  location change

ObjectReference MyCurrentMarker

ObjectReference[] MyMarkers = Game.GetPlayer().FindAllReferencesWithKeyword(YourKeyword, 4000.0)  ;can use FindAllReferencesOfType instead, it can  accept a formlist
If MyMarkers.Length > 0
        int i = 0
        While i < MyMarkers.Length 
          Float MyDistance =  Game.GetPlayer().GetDistance(MyMarkers[i]) 
               If  MyDistance > 2000  
                     MyCurrentMarker = MyMarkers[i]
                     MyCurrentMarker.PlaceAtMe(something to spawn, number)
                     i = MyMarkers.Length
               EndIf
            i += 1
        EndWhile
  EndIf

Edited by kitcat81
Link to comment
Share on other sites

Placed objects(CK or through PlaceAtMe) are temporarily persistent. Objects become permanently persistent when they are assigned to properties. Objects will remain temporarily persistent if held in variables for whatever reason.

This is why it's best to assign objects to local variables in a function. When the function ends, the variable is cleared.

I was also going to suggest the above. Markers don't have keywords, but you can use activators and give them keywords.

I feel as though you are limiting yourself greatly due to an understandable fear of baking them into saves. There are a few best scripting practices to avoid that.

On save baking:
http://www.creationkit.com/fallout4/index.php?title=Save_File_Notes_(Papyrus)

On persistence:

http://www.creationkit.com/fallout4/index.php?title=Persistence_(Papyrus)

Also performance is important too:

http://www.creationkit.com/fallout4/index.php?title=Performance_(Papyrus)

Keep in mind, some baking unfortunately can't be avoided, and wont always be due to ones doing.

Good luck. :smile:

Edited by TheDungeonDweller
Link to comment
Share on other sites

Thanks for the reply again. I'll explain the problems with persistence/multiple instance a bit better:

 

If I place a marker and have my script on it, that marker becomes persistent. If I remove the mod the save game still has this script and marker. This can lead to CTDs when unloading that area from my experience (not so much loading it). SO for example I place a marker with my script in Concord. I test my script and then remove the mod from load order. I come back to Concord and as I am walking away from Concord (unloading the area) I could get a crash. I find in Papyrus log complaints of a missing object and my script still trying to run on it, even after I remove the files. This is the behaviour I have observed with that.

 

So regarding that, I can't have markers with scripts on them unless the user never uninstalls the mod :/ But wait there's more:

 

Regarding multiple instances of the same script, lets say I have 2 cells next to each other with one marker in each cell. As I walk into the area and those 2 cells start load at the same time, both receive the OnCellAttach. Despite each object being separate and having a different base marker property, the code interferes with itself. So if marker 1's script gets me a random number and then marker 2's script is running ever so slightly behind the first script, the second overrides the values the first collected, which is no good. I am able to observe this behaviour every time.

 

Just to mention for relevance sake, I am going to assume that if I have a predefined formlist with every marker listed, and then having that formlist as a property, all of the markers in game will become persistent. Perhaps it doesn't matter/not as bad if the object itself becomes persistent, as long as a script is not attached to it directly.

 

 

I'm not planning on having a great deal of markers per cell, just enough to cover most areas a spawn would be feasible. But they will be all over the Commonwealth. I haven't really looked at using an array to store said markers like in the example you give above however, I haven't really seen the need to study into making arrays or how they could work for me. I get the impression that in that code, a spawn would be placed at every marker in the array :O I am looking at that FindAllReferencesWithKeyword, that looks more reliable. I only want one marker at a time though, not all the markers at once. On a separate note though I kinda need to study arrays more, as I have thought about storing the actual NPCs spawned to run some extra code on them/monitor them for some future features that users have suggested.

Link to comment
Share on other sites

Placed objects(CK or through PlaceAtMe) are temporarily persistent. Objects become permanently persistent when they are assigned to properties. Objects will remain temporarily persistent if held in variables for whatever reason.

 

This is why it's best to assign objects to local variables in a function. When the function ends, the variable is cleared.

 

I was also going to suggest the above. Markers don't have keywords, but you can use activators and give them keywords.

 

I feel as though you are limiting yourself greatly due to an understandable fear of baking them into saves. There are a few best scripting practices to avoid that.

 

On save baking:

http://www.creationkit.com/fallout4/index.php?title=Save_File_Notes_(Papyrus)

 

On persistence:

 

http://www.creationkit.com/fallout4/index.php?title=Persistence_(Papyrus)

 

Also performance is important too:

 

http://www.creationkit.com/fallout4/index.php?title=Performance_(Papyrus)

 

Keep in mind, some baking unfortunately can't be avoided, and wont always be due to ones doing.

 

Good luck. :smile:

Everything I am endeavouring to do is because of these things ;) I realise there is a degree of marring the save game, it's the extent I'm trying to limit.

Link to comment
Share on other sites

Thanks for the reply again. I'll explain the problems with persistence/multiple instance a bit better:

 

If I place a marker and have my script on it, that marker becomes persistent. If I remove the mod the save game still has this script and marker. This can lead to CTDs when unloading that area from my experience (not so much loading it). SO for example I place a marker with my script in Concord. I test my script and then remove the mod from load order. I come back to Concord and as I am walking away from Concord (unloading the area) I could get a crash. I find in Papyrus log complaints of a missing object and my script still trying to run on it, even after I remove the files. This is the behaviour I have observed with that.

 

So regarding that, I can't have markers with scripts on them unless the user never uninstalls the mod :/ But wait there's more:

 

Regarding multiple instances of the same script, lets say I have 2 cells next to each other with one marker in each cell. As I walk into the area and those 2 cells start load at the same time, both receive the OnCellAttach. Despite each object being separate and having a different base marker property, the code interferes with itself. So if marker 1's script gets me a random number and then marker 2's script is running ever so slightly behind the first script, the second overrides the values the first collected, which is no good. I am able to observe this behaviour every time.

 

Just to mention for relevance sake, I am going to assume that if I have a predefined formlist with every marker listed, and then having that formlist as a property, all of the markers in game will become persistent. Perhaps it doesn't matter/not as bad if the object itself becomes persistent, as long as a script is not attached to it directly.

 

 

I'm not planning on having a great deal of markers per cell, just enough to cover most areas a spawn would be feasible. But they will be all over the Commonwealth. I haven't really looked at using an array to store said markers like in the example you give above however, I haven't really seen the need to study into making arrays or how they could work for me. I get the impression that in that code, a spawn would be placed at every marker in the array :O I am looking at that FindAllReferencesWithKeyword, that looks more reliable. I only want one marker at a time though, not all the markers at once. On a separate note though I kinda need to study arrays more, as I have thought about storing the actual NPCs spawned to run some extra code on them/monitor them for some future features that users have suggested.

 

The object should not become persistent because of the script properties..though if you keep some ref as a property then this ref will be persistent. But there is no need to use a reference in properties when it`s possible to use a game id. You know you can use dppi command that dumps persistent info to the log so you can find out what keeps the object persistent and you can clear all variables in the script so it only keeps them when they are needed. There is also a condition If IsBoundGameObjectAvailable() that checks if the script is attached to something.

Link to comment
Share on other sites

I'm not sure why the object my script was on became persistent when it wasn't ever referenced as a property, I know its not meant to happen, but I seen it in the papyrus log still being looked for by the savegame.

 

I didn't think you could use a formid unless it was from Fallout.esm cos they change. Correct me if I'm wrong. Would be nice.

 

I'm gonna have a look at how these "find" functions are drawn up in the main scripts and see if i can invent a FindRandomRefWithKeyword type of function for my script.

Link to comment
Share on other sites

I'm not sure why the object my script was on became persistent when it wasn't ever referenced as a property, I know its not meant to happen, but I seen it in the papyrus log still being looked for by the savegame.

 

I didn't think you could use a formid unless it was from Fallout.esm cos they change. Correct me if I'm wrong. Would be nice.

 

I'm gonna have a look at how these "find" functions are drawn up in the main scripts and see if i can invent a FindRandomRefWithKeyword type of function for my script.

You can use form ID from fallout esm and your own esp. Can`t be sure about DLC, but I think you can do it in a way as theDungeoDweller wrote (GetFormFrom, and you can use IfPluginInstalled ). But you also can just copy a marker to your mod so it becomes a part from your mod and you can use it`s id. Good luck with it!

Link to comment
Share on other sites

Thx. I figured what was going on with the persistence on that object. I continued from a save where the object was still loaded so the game was seemingly looking for it. Should have thought about that. Issue still remains on multi-instance script though.

 

I'll look into whats been said about getting the forms from file. I just thought it couldn't be done on any file thats not guaranteed to be in the same load order like Fallout.esm, therefore I binned that idea.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...