Jump to content

My script seems to work as intended, checking best practices


Manan6619

Recommended Posts

I got tired of Brahmin from settlements having corpses that do not despawn -- especially when I've been killing them intentionally for their meat(I have a pile of like 20 corpses in Sanctuary). So, I've made a script that deletes them after a certain period, including preexisting corpses. It seems to work as intended, but I wanted to ask on here to be sure I'm not doing anything that might have consequences later I can't see yet, or if I'm doing it in an overly-intensive way, etc. I'm a novice with ObScript from NV and have just barely gotten a foothold with Papyrus. Script source:

 

Scriptname DeadSettlementBrahminDespawn:WorkshopBrahminCleanupScript extends Actor
{Settlement brahmin will be removed a while after death}
 
int DoOnce = 0
 
Event OnLoad()
        if DoOnce == 0 && self.isDead()    ;If the Brahmin is already dead when you load the area, mark it for deletion. Only runs once to clean preexisting corpses, not instantly delete fresh corpses because you left the area for a short period)
                DoOnce = 1
                self.DeleteWhenAble()    ;this seems like the new "MarkForDelete"? Want to ask about this sometime to be sure.
                Debug.Notification("Preexisting dead settlement Brahmin successfully deleted.")    ;Debug message *should* appear when one unloads the settlement with corpses(thereby deleting them), as that's when it sounded like DeleteWhenAble would execute and allow the rest of the Event to run.
        endif
endEvent
 
Event OnDying(Actor AkKiller)
        Debug.Notification("Settlement Brahmin killed. Beginning pre-deletion Wait period.")
        Utility.Wait(12960)    ;12,960 seconds. Should be about 3 in-game days. Need to double-check forums about best practices, apparently Wait is a "latent"(more demanding?) function so maybe something else should be used to keep track of that time.
        self.DeleteWhenAble()
endEvent

To reiterate the concerns I mentioned in my comments, I'm worried about what the right way is to delete things to make sure it actually frees up as many resources as possible, but also doesn't have the potential to cause crashes or other issues later on. This used to be done with disable and MarkForDelete, but MarkForDelete is gone. I'm also concerned about tracking 12,960 seconds in the Wait function. I've heard some info about Latent functions and them being more demanding, but I'm not versed enough to know what a better substitute would be.

Edited by Manan6619
Link to comment
Share on other sites

I don't think deleting Brahmins could cause CTDs but you can add an IsCreated() check if you'd like.

If IsCreated() == 1        ; If Brahmin is created in-game, not editor placed (so its RefID starts with FF)
     Disable()
     Delete()
Else                       ; If editor placed, just disable it
     Disable()
EndIf

As far as I remember, the only editor placed Brahmins that can die in settlements are the pack brahmins of traveling merchants like Trashcan Carla.

Link to comment
Share on other sites

Thank you all for the suggestions.

Instead of using Wait, you may want to consider working with StartTimerGameTime coupled with OnTimerGameTime

 

I do not know what the best method to delete things in FO4 might be.

I like that the unit of measurement for this is in-game hours instead of real-life seconds, it certainly feels cleaner to use over measuring tens of thousands of seconds. Would you happen to know if I can expect making that change to be less resource-intensive?

 

Cleaner would to simply do an OnUnload() test with a const script

 

Event OnUnload()

If((Self as Actor).IsDead() == True)

Self.Disable()

Self.Delete()

EndIf

EndEvent

This looks good, although I'm worried about corpses disappearing because you ran a couple minutes out from your settlement, cleared a dungeon, and returned in less than one in-game day. It's not critical, but I'd like it to feel like other stuff in the game where it might take a day or two for settlement attackers' bodies to despawn.

 

I don't think deleting Brahmins could cause CTDs but you can add an IsCreated() check if you'd like.

If IsCreated() == 1        ; If Brahmin is created in-game, not editor placed (so its RefID starts with FF)
     Disable()
     Delete()
Else                       ; If editor placed, just disable it
     Disable()
EndIf
As far as I remember, the only editor placed Brahmins that can die in settlements are the pack brahmins of traveling merchants like Trashcan Carla.

 

This is the kind of thing I was looking for regarding deleting references. I think you're right about editor-placed Brahmin in the vanilla game, but I think it's good to have a failsafe in case, say, a mod-added/mod-altered settlement starts with a pre-placed Brahmin, then decides to involve that reference in a script later like manipulating it as part of a quest, or whatever. Edited by Manan6619
Link to comment
Share on other sites

Thank you all for the suggestions.

Instead of using Wait, you may want to consider working with StartTimerGameTime coupled with OnTimerGameTime

 

I do not know what the best method to delete things in FO4 might be.

I like that the unit of measurement for this is in-game hours instead of real-life seconds, it certainly feels cleaner to use over measuring tens of thousands of seconds. Would you happen to know if I can expect making that change to be less resource-intensive?

 

Cleaner would to simply do an OnUnload() test with a const script

 

Event OnUnload()

If((Self as Actor).IsDead() == True)

Self.Disable()

Self.Delete()

EndIf

EndEvent

This looks good, although I'm worried about corpses disappearing because you ran a couple minutes out from your settlement, cleared a dungeon, and returned in less than one in-game day. It's not critical, but I'd like it to feel like other stuff in the game where it might take a day or two for settlement attackers' bodies to despawn.

 

I don't think deleting Brahmins could cause CTDs but you can add an IsCreated() check if you'd like.

If IsCreated() == 1        ; If Brahmin is created in-game, not editor placed (so its RefID starts with FF)
     Disable()
     Delete()
Else                       ; If editor placed, just disable it
     Disable()
EndIf
As far as I remember, the only editor placed Brahmins that can die in settlements are the pack brahmins of traveling merchants like Trashcan Carla.

 

This is the kind of thing I was looking for regarding deleting references. I think you're right about editor-placed Brahmin in the vanilla game, but I think it's good to have a failsafe in case, say, a mod-added/mod-altered settlement starts with a pre-placed Brahmin, then decides to involve that reference in a script later like manipulating it as part of a quest, or whatever.

 

 

You could try something like this:

Scriptname YOURSCRIPTNAME extends Actor Const


Event OnUnload()
	If IsDead() && IsDisabled() == 0 && IsDeleted() == 0    ; for extra safety
		StartTimerGameTime(5, 555)   ; 5 in-game hours
	EndIf
EndEvent

Event OnTimerGameTime(int aiTimerID)
	If Is3DLoaded() == 0		     ; not loaded
                UnregisterForAllEvents()     ; unregister script
		If IsCreated() == 1	     ; created in-game
			Disable()
			Delete()
		Else			     ; editor placed
			Disable()
		EndIf
	Else				     ; if loaded (e.g., Player reentered the location)
		; do nothing, OnUnload() will restart the timer if the conditions are met
	EndIf
EndEvent

Event OnWorkshopObjectDestroyed(ObjectReference akActionRef)		; Brahmin scrapped or stored in the workshbench (can't happen in the vanilla game, only with mods...)
	UnregisterForAllEvents()
	Disable()                                                       ; the game code disables (and in most cases deletes) the object when one scraps/stores it so these are not actually necessary
	Delete()
EndEvent
Edited by LarannKiar
Link to comment
Share on other sites

The reason Wait() is considered expensive is because it remains in occupation of the thread it was occupying at the time of pausing. Whether this is a big deal or never preferable I don't know. I think as a rule of thumb you should try to have as little overhead as possible.

Thank you for the specific insight on that. Part of the idea was to make sure this wouldn't be overly-taxing on the game before potentially sharing it.

 

You could try something like this: <snip>

 

Scriptname YOURSCRIPTNAME extends Actor Const


Event OnUnload()
	If IsDead() && IsDisabled() == 0 && IsDeleted() == 0    ; for extra safety
		StartTimerGameTime(5, 555)   ; 5 in-game hours
	EndIf
EndEvent

Event OnTimerGameTime(int aiTimerID)
	If Is3DLoaded() == 0		     ; not loaded
                UnregisterForAllEvents()     ; unregister script
		If IsCreated() == 1	     ; created in-game
			Disable()
			Delete()
		Else			     ; editor placed
			Disable()
		EndIf
	Else				     ; if loaded (e.g., Player reentered the location)
		; do nothing, OnUnload() will restart the timer if the conditions are met
	EndIf
EndEvent

Event OnWorkshopObjectDestroyed(ObjectReference akActionRef)		; Brahmin scrapped or stored in the workshbench (can't happen in the vanilla game, only with mods...)
	UnregisterForAllEvents()
	Disable()                                                       ; the game code disables (and in most cases deletes) the object when one scraps/stores it so these are not actually necessary
	Delete()
EndEvent

 

Oh, uh, wow. This is above and beyond. The comments are very helpful, and the addition of that third event was good thinking -- I wasn't even thinking about protecting users of mods that allow for the scrapping/storing of actors, they aren't uncommon.

 

Well, I mentioned sharing the completed product, but at this point you've done a great deal of the heavy lifting here. May I use this script for a mod that'll be published here on the Nexus? There's practically nothing with it I'd see the need to change. You'll be credited prominently, and if you allow me to also turn on Donation Points, I'd be glad to grant them mostly(or all!) to you.

Link to comment
Share on other sites

 

The reason Wait() is considered expensive is because it remains in occupation of the thread it was occupying at the time of pausing. Whether this is a big deal or never preferable I don't know. I think as a rule of thumb you should try to have as little overhead as possible.

Thank you for the specific insight on that. Part of the idea was to make sure this wouldn't be overly-taxing on the game before potentially sharing it.

 

You could try something like this: <snip>

 

Scriptname YOURSCRIPTNAME extends Actor Const


Event OnUnload()
	If IsDead() && IsDisabled() == 0 && IsDeleted() == 0    ; for extra safety
		StartTimerGameTime(5, 555)   ; 5 in-game hours
	EndIf
EndEvent

Event OnTimerGameTime(int aiTimerID)
	If Is3DLoaded() == 0		     ; not loaded
                UnregisterForAllEvents()     ; unregister script
		If IsCreated() == 1	     ; created in-game
			Disable()
			Delete()
		Else			     ; editor placed
			Disable()
		EndIf
	Else				     ; if loaded (e.g., Player reentered the location)
		; do nothing, OnUnload() will restart the timer if the conditions are met
	EndIf
EndEvent

Event OnWorkshopObjectDestroyed(ObjectReference akActionRef)		; Brahmin scrapped or stored in the workshbench (can't happen in the vanilla game, only with mods...)
	UnregisterForAllEvents()
	Disable()                                                       ; the game code disables (and in most cases deletes) the object when one scraps/stores it so these are not actually necessary
	Delete()
EndEvent

 

Oh, uh, wow. This is above and beyond. The comments are very helpful, and the addition of that third event was good thinking -- I wasn't even thinking about protecting users of mods that allow for the scrapping/storing of actors, they aren't uncommon.

 

Well, I mentioned sharing the completed product, but at this point you've done a great deal of the heavy lifting here. May I use this script for a mod that'll be published here on the Nexus? There's practically nothing with it I'd see the need to change. You'll be credited prominently, and if you allow me to also turn on Donation Points, I'd be glad to grant them mostly(or all!) to you.

 

 

Sure you can use this script however you like. And no it's not necessary to send DPs to me, it's up to you. :)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...