senterpat Posted November 13, 2018 Share Posted November 13, 2018 Hello, I'm hoping someone can help with this, as the only way I can figure to do it is a ton of FO4edit edits. I need to find and replace potion objects as cells are loaded that are placed in the game world. I used GetNextRef in FNV to accomplish this, but cannot find any documentation on a similar command for FO4. The only other way I can think to accomplish this is to replace all the references with a dummy object and then set its Leveled List in FO4edit. There are thousands of references, so would prefer to find a scripted way. Also this method won't support mod added locations, so I would have to make more patches. Link to comment Share on other sites More sharing options...
SKKmods Posted November 13, 2018 Share Posted November 13, 2018 What your asking is fairly complex, so I trust your OK with the fundamental quest and script structures: Create an Xmarker at the player either quest alias or PlaceAtMe() Area Scan FindAllReferencesOfType() max radius 10K units loaded area Do stuff with the results Xmarker MoveTo() Player RegisterForDistanceGreaterThanEvent() from the Xmarker, typically half the scan radius for overlap OnDistanceGreaterThan() event trigger Area Scan Link to comment Share on other sites More sharing options...
pra Posted November 13, 2018 Share Posted November 13, 2018 So you are suggesting using RegisterForDistanceGreaterThanEvent on the player, process everything it gives you, drop an xMarker at the position, and then redo the whole thing as soon as the player leaves a certain area around the xmarker? Yes, that sounds like it should work. However, what happens if the player enters an interior or changes worldspaces? Will the event fire, too? If not, you'd need something to catch that, too. Maybe onCellDetach on the marker could work? If you want to do it in xEdit instead, you can look at my search&replace script in here: https://www.nexusmods.com/fallout4/mods/28898The way I made it you need to make a replacement map file, where you write which editor IDs should be replaced by which other editor IDs. Link to comment Share on other sites More sharing options...
SKKmods Posted November 13, 2018 Share Posted November 13, 2018 Its the well proven basis for all SKK dynamic detection systems used by tens of thousands of satisfied customers in stuff like AutoUnlock, Combat Settlers, Dogmeat Sniffs Glue, Combat Stalkers, 4-76 NPC replacement, 4-76 Item replacement ... The trick is to ensure variation in the distance events so they don't all trigger at the same time, tripping the SKK Script Lag detector Previously used OnLocationChange, but the named boundaries are rather random from 1K to 20K units apart, and there are over 30 50 base game registrations for that event already all triggering at the same time. /research Link to comment Share on other sites More sharing options...
Reneer Posted November 13, 2018 Share Posted November 13, 2018 SKK50 has a great system set up, though I might recommend a small addition of storing all the found potions into a Formlist in case someone wants to revert the changes. Link to comment Share on other sites More sharing options...
senterpat Posted November 13, 2018 Author Share Posted November 13, 2018 Awesome, thanks for the point in the right direction, I'll be back when I can't figure it out lol ;) Link to comment Share on other sites More sharing options...
senterpat Posted November 22, 2018 Author Share Posted November 22, 2018 So I've managed to get this working to some extent, but now I've hit another road block, the item that is replacing the found potion is a leveled list, and you can't add a Leveled Item directly to the world, in FNV I used a container reference to work out the leveled item, then used GetInventoryObject to get the new item and place it in the world. I can't find a function to do this in FO4 tho. Any ideas? Link to comment Share on other sites More sharing options...
SKKmods Posted November 22, 2018 Share Posted November 22, 2018 PlaceAtMe can be used with level lists no problem: ObjectReference ThisItem = pPlayerREF.PlaceAtMe(pLL_Deliverer, aiCount = 1, abForcePersist = true, abInitiallyDisabled = false, abDeleteWhenAble = false) ObjectReference ThisItem = ObjectToSpawnAt.PlaceAtMe(pLGND_PossibleLegendaryItemBaseLists, aiCount = 1, abForcePersist = true, abInitiallyDisabled = false, abDeleteWhenAble = false) You may need to avoid bounding collisions either: (a) spawn at the replaced item abInitiallyDisabled = true, then .Disable() the replaced item and .Enable() the replacement item (b) .Disable() the replaced item before spawning the replacement. Link to comment Share on other sites More sharing options...
senterpat Posted November 23, 2018 Author Share Posted November 23, 2018 Awesome thanks for all the help SKK, this sort of script is a bit more complex then any I've attempted, and I just want to make sure I didn't miss anything, I used your script as a reference (hope you don't mind) and was wondering if you could look it over and make sure it's not wasteful or anything. Either way, thanks for all the help! Function FindStuff Self.UnregisterForDistanceEvents(pPlayerREF as ScriptObject, Alias_LocationChangeMarker.GetReference() as ScriptObject) Self.UnRegisterForPlayerTeleport() ObjectReference[] FoundStuff = pPlayerREF.FindAllReferencesOfType(CigaretteCarton, fDetectionDistance) int currentElement = 0 while (currentElement < FoundStuff.Length) FoundStuff[currentElement].Disable() ObjectReference NewObject = FoundStuff[currentElement].Placeatme(CigaretteCartonReplacer, 1, True, false, false) FoundStuff[currentElement].Delete() currentElement += 1 endWhile ObjectReference[] FoundStuff = pPlayerREF.FindAllReferencesOfType(CigarettePack, fDetectionDistance) int currentElement = 0 while (currentElement < FoundStuff.Length) FoundStuff[currentElement].Disable() ObjectReference NewObject = FoundStuff[currentElement].Placeatme(CigarettePackReplacer, 1, True, false, false) FoundStuff[currentElement].Delete() currentElement += 1 endWhile Self.SwitchEnabled() EndFunction Function SwitchEnabled() Self.RegisterForPlayerTeleport() Alias_LocationChangeMarker.GetReference().MoveTo(pPlayerREF, 0, 0, 0, True) Self.RegisterForDistanceGreaterThanEvent(pPlayerREF as ScriptObject, Alias_LocationChangeMarker.GetReference() as ScriptObject, fMovementDistance) EndFunction Event Actor.OnLocationChange(Actor akSender, Location akOldLoc, Location akNewLoc) Self.UnregisterForAllEvents() Self.RegisterForRemoteEvent((pPlayerREF as Actor) as ScriptObject, "OnPlayerLoadGame") Self.SwitchEnabled() EndEvent Event Actor.OnLocationChange(Actor akSender, Location akOldLoc, Location akNewLoc) Self.UnregisterForAllEvents() Self.RegisterForRemoteEvent((pPlayerREF as Actor) as ScriptObject, "OnPlayerLoadGame") Self.SwitchEnabled() EndEvent Event OnQuestInit() Self.RegisterForRemoteEvent((pPlayerREF as Actor) as ScriptObject, "OnPlayerLoadGame") Self.RegisterForCustomEvent((pFollowers as followersscript) as ScriptObject, "followersscript_CompanionChange") Self.SwitchEnabled() EndEvent Event OnDistanceGreaterThan(ObjectReference akObj1, ObjectReference akObj2, float afDistance) If ((pPlayerREF as Actor).IsOnMount() == True) Alias_LocationChangeMarker.GetReference().MoveTo(pPlayerREF, 0, 0, 0, True) Self.RegisterForDistanceGreaterThanEvent(pPlayerREF as ScriptObject, Alias_LocationChangeMarker.GetReference() as ScriptObject, fMovementDistance) Else Self.FindStuff() EndIf EndEvent Event Actor.OnPlayerLoadGame(Actor akSender) Self.RegisterForRemoteEvent((pPlayerREF as Actor) as ScriptObject, "OnPlayerLoadGame") Self.SwitchEnabled() EndIf EndEvent Link to comment Share on other sites More sharing options...
SKKmods Posted November 23, 2018 Share Posted November 23, 2018 Hey that script looks familiar ! Don't have a stack of time, but a quick scan looks lovely. Except tiny detail you cant declare int currentElement twice in the same scope. Second one will compile error. + Don't forget to create a LocationChangeMarker quest reference alias that creates a persistent xmarker at the player. ++ fMovementDistance is best at around 50% fDetectionDistance for good overlap and minimum overhead. Challenge is the default uGridsToLoad max active radius is 10,240 so *everyone* uses that to detect and 5,120 to move. Try and jitter those numbers. Link to comment Share on other sites More sharing options...
Recommended Posts