Jump to content

[Papyrus Help] Removing Scripts from Dead and Unloaded Actors


lesi123

Recommended Posts

I'm in the process of remaking a mod that applies a debuff to an actor when the player hits them with a certain weapon type. I'm doing this through dynamically attaching scripts to actors near the player and have followed the guide here: https://www.creationkit.com/index.php?title=Dynamically_Attaching_Scripts

 

Everything is working okay except the Death Dispel code. To check who has the script attached, I selected a Hit Shader on the magic effect and ticked FX Persist. When I placed the Death Dispel code on the script, however, it didn't seem like the magic effect got dispelled when they died since the Hit Shader was still active on the corpses. When I unticked the No Death Dispel box on the magic effect, the Hit Shader disappeared on death. However the wiki states unticking this box can cause errors and it's best to remove the magic effect via the script instead.

 

Death Dispel code:

Event OnEffectStart(Actor akTarget, Actor akCaster)
	; Any Initialization/Setup code here
	; Go to our Alive state
	GoToState("alive")
EndEvent
 
State alive
 
	Event OnBeginState()
		RegisterForSingleUpdate(0.25)
	EndEvent
 
	Event OnUpdate()
		; Regular code here
		RegisterForSingleUpdate(0.25)
	EndEvent
 
	Event OnDying(Actor akKiller)
		; Any additional cleanup code here
		UnregisterForUpdate()
		GoToState("dead")
	EndEvent
 
EndState
 
State dead
; Nothing needed here
EndState

When I saw the Hit Shader persist on the actor, I attempted to use the .Dispel() function under the OnDying event but I receive the error "Dispel is not a function or does not exist" even though the script extends ActiveMagicEffect.

 

Another issue I could foresee after long playthroughs with this scripts attaching to any actor around the player is it will continuously be applied to more and more actors unless the actors die (once I can find out how the Death Dispel code is supposed to work). Is there a way to remove a magic effect with an attached script from an actor based on distance from the player? GetDistance seems to only work with objects and not actors.

 

Basically the goal is to get the script removed from actors that die or obtain a certain distance from the player to prevent bloat.

 

Any help would be greatly appreciated!

 

Here's the script:

Scriptname BTDMonitorScript extends activemagiceffect  

;PROPERTIES

Actor Property PlayerRef Auto

Keyword Property WeapTypeBow Auto

Spell Property BTDSpellBleedDmgBOW Auto
Spell Property BTDSpellBleedExtrasBOW Auto

MagicEffect Property BTDMonitorEffect Auto

GlobalVariable Property BTDGlobalBleedDurBOW Auto

Event OnEffectStart(Actor akTarget, Actor akCaster)
	; Any Initialization/Setup code here
	; Go to our Alive state
	GoToState("alive")
EndEvent
 
State alive
 
	Event OnBeginState()
		RegisterForSingleUpdate(0.25)
	EndEvent
 
	Event OnUpdate()
		; Regular code here
		RegisterForSingleUpdate(0.25)
	EndEvent
 
	Event OnDying(Actor akKiller)
		; Any additional cleanup code here
                BTDMonitorEffect.Dispel() ;will not compile with this line
		UnregisterForUpdate()
		GoToState("dead")
	EndEvent
 
EndState
 
State dead
; Nothing needed here
EndState


Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
	if ((akAggressor == PlayerRef) && (akSource as Weapon) && (abHitBlocked != true))
		if ((akSource.HasKeyword(WeapTypeBow)) && BTDGlobalBleedDurBOW.GetValue() != 0))
			if ((Utility.RandomInt() >= 75) && (PlayerRef.GetActorValue("Marksman") < 30))
				if BTDGlobalBleedDurBOW.GetValue() == 1
					BTDSpellBleedDmgBOW.cast(PlayerRef)
					BTDSpellBleedExtrasBOW.cast(PlayerRef)
				endif
			endif
		endif
	endif
EndEvent
Edited by lesi123
Link to comment
Share on other sites

Just a thought, are you sure the effect isn't persisting BECAUSE OF the fx persist flag? as that would be a false positive. I haven't used the fx persist flag much so can't really tell. It could be posible that spells naturally dispel on death without doing anything since there is a "No Death Dispel" flag.

 

GetDistance should work with actors too, they are object references in the end, and the wiki example uses the player.

 

EDIT: the wiki says this:

 

FX Persist: If checked, the visual effect on the target persists for the entire duration of the Effect. Otherwise, it only plays once.

No Death Dispel: If checked, the effect persists even if the target dies.

Link to comment
Share on other sites

It could be posible that spells naturally dispel on death without doing anything since there is a "No Death Dispel" flag.

 

 

You're correct, if I untick the No Death Dispel flag, then the FX stops playing when the actor dies and I assume it's because the magic effect (and it's attached script) has been dispelled. However, the wiki says it's best to dispel the effect from within the script itself since unticking the No Death Dispel can cause this error:

 

"Unable to call X - no native object bound to the script object, or object is of incorrect type"

This error appears when native function X, which is non-global, is called on an object variable which does not point at an actual object in game. This usually happens in ActiveMagicEffect scripts which can have their effect deleted out from under them, or when calling certain functions on objects in containers.

 

I just have no idea how to make the magic effect dispel itself on the dead actor since .Dispel() won't work.

 

As for the distance thing, I may have been looking for a problem that's not really there since it wouldn't make sense for a script to run on something that's not even loaded for the player.

Link to comment
Share on other sites

The tutorial you linked to appears to have been edited by some true luminaries of Papyrus scripting. Nevertheless, I feel remiss if I don't mention that it contradicts my own direct experiences, which makes me skeptical of some of its suggestions.

 

In the case of death dispel, I have actually found it to be best to UNcheck "No death dispel," and then put any necessary cleanup functions in the OnEffectFinish block, which fires when the actor dies and the effect is dispelled.

 

Another point of difference is that I find it preferable to put the script effect in the actual effect applied by the cloak, rather than having the cloak effect apply an ability. that way the script effect is removed automatically when the player leaves the vicinity, eliminating some risk of bloat. In cases where it is better to have the cloak effect apply a secondary tracking effect, I would use the cast() function to apply timered effect that lasts 5 minutes or so rather than use a constant effect. That way, worst case scenario, the effect is removed after 5 minutes, which again helps minimize bloat (at the cost of some negligible amount of extra script processing).

Edited by lofgren
Link to comment
Share on other sites

It seems the wiki is also saying that using the OnEffectFinish event has the same issue as unchecking the No Death Dispel box on a magic effect carrying a script (http://www.creationkit.com/fallout4/index.php?title=OnEffectFinish_-_ActiveMagicEffect). There's even various reports of OnDeath events being inconsistent and the general consensus is to use OnDying instead; I can only assume to give the game and papyrus that tiny extra bit of time to actually execute whatever is in the OnDying event block.

 

However, I did find that a simple self.dispel() in the OnDying event block removes the effect and the attached script from any NPCs affected with it.

 

I did toy around with attaching the script to the Cloak Effect or the Applying Effect but I kept running into issues with Casting Type and Delivery not matching up with the spells. Making them match up then caused the magic effect to not apply and thus no script got added to the NPCs. It's been rough relearning this stuff.

 

Thank you guys for your all your help. I'm sure I'll have more questions down the road as I continue to improve on this damn thing.

 

EDIT: Well, I'm dumb. I forgot to adjust the Applying Spell duration from 0.

 

I removed the Applying Script from the Applying Effect and just placed my Monitor Script on it instead, then changed the Applying Spell duration to 5 minutes. Now it truly acts like a bubble! I also made sure to have the target conditions on the Applying Effect to not apply it to already dead actors or actors that already have the Applying Effect on them.

Edited by lesi123
Link to comment
Share on other sites

You probably figured it out already but just in case, the exact reason why the original dispel line did not compile is because you run it on a magic effect when its an activemagiceffect function, that is, the specific instance not the form, similar to an object reference. Self is an activemagiceffect so it works.
Link to comment
Share on other sites

The errors reported on the OnEffectFinish page aren't really relevant to your script, since the only thing you are doing in the clean up function is unregistering for an update, which is done automatically by the game when it dispels the effect anyway.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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