How to get an ActiveMagicEffect instance?

Post » Sun Nov 09, 2014 9:20 pm

Yeah, this is quite painful...previously, I was getting my ActiveMagicEffect script to report itself via "Self" in OnEffectStart, but Self started suddenly always returning None when it never has done in the past.

Here are my two tracker scripts:

Spoiler
ScriptName ACGMagicCasterActorScript extends ActiveMagicEffectActor Property RefSelfActor Auto ; Reference to the Actor this script is attached to.ACGQuestMagicSystemScript Property RefMagicSystemQuest Auto ; Reference to the magic system quest script.Int Property SelfQuestIndex Auto ; Tracks this script's location in the quest.String[] Property EffectNameArray Auto ; Array to cache effect names.Int[] Property RefTargetScriptIndexCache Auto ; Array to cache target scripts that have been affect by this caster.Int CacheLength ; Keep track of length, for easy looping.Float[] Property TargetDistanceArray Auto ; Keeps track of target distances (in feet).Float[] Property MEffectBaseTimeCostArray Auto ; Keeps track of magic costs time-wise (per second).Float[] Property MEffectBaseDistanceCostArray Auto ; Keeps track of magic costs distance-wise (per foot).Float[] Property MEffectBaseTimeCostStackArray Auto ; MEffectBaseTimeCost stack tracking array.Float[] Property MEffectBaseDistanceCostStackArray Auto ; MEffectBaseDistanceCost stack tracking array.Float TotalCost ; Total calculated Energy cost.Float HealthPercentOld ; Keeps track of this caster's health percentage.Float HealthPercentCur ; This is the current percentage.Float HealthPercentDiff ; Track this caster's health percentage difference.Float Property UpdateInterval = 0.1 AutoEvent OnEffectStart(Actor akTarget, Actor akCaster)	RefMagicSystemQuest.RegisterCasterScript(Self)	RefSelfActor = akTarget	HealthPercentOld = RefSelfActor.GetActorValuePercentage("Health")	HealthPercentDiff = 0.0	Debug.Notification("Caster script added.")EndEventFunction RegisterEffect(Int EffectScriptIndex, String ALName, Float BaseTimeCost, Float BaseDistanceCost)	RefTargetScriptIndexCache[CacheLength] = EffectScriptIndex	EffectNameArray[CacheLength] = ALName	MEffectBaseTimeCostArray[CacheLength] = BaseTimeCost	MEffectBaseDistanceCostArray[CacheLength] = BaseDistanceCost	; Update CacheLength with the new length.	CacheLength = RefTargetScriptIndexCache.LengthEndFunctionEvent OnUpdate()	Int n = 0	While n < CacheLength		TargetDistanceArray[n] = RefMagicSystemQuest.GetTargetDistance(n, RefSelfActor) / (64 / 3) ; Evaluates to 21.33333333333333333333.		TotalCost += (MEffectBaseDistanceCostStackArray[n] * TargetDistanceArray[n]) * (MEffectBaseTimeCostStackArray[n] * UpdateInterval)		n += 1	EndWhile	RefSelfActor.DamageActorValue("Magicka", TotalCost)	If RefSelfActor.GetActorValue("Magicka") <= 0		Self.Dispel()	EndIf	RegisterForSingleUpdate(UpdateInterval)EndEventEvent OnControlDown(String Control)	If Control == "Shout"		; This will remove either all magic from targets the player has cast spells on, or		; selected targets.	EndIfEndEventEvent OnKeyDown(Int KeyCode)	; TODO - this function will track the Minus and Equals keys, and modify the damage of spell	; effects of the player's choosing.	; Depending on the key the player presses, damage is stacked positively or negatively for	; the spells the player has selected.	;If KeyCode == 12 ; Minus key.	;	MEffectBaseTimeCostStack -= MEffectBaseTimeCost	;	MEffectBaseDistanceCostStack -= MEffectBaseDistanceCost	;ElseIf KeyCode == 13 ; Equals key.	;	MEffectBaseTimeCostStack += MEffectBaseTimeCost	;	MEffectBaseDistanceCostStack += MEffectBaseDistanceCost	;EndIfEndEvent; TODO - When this event is triggered, we want some event to happen to the caster or the caster's tracked targets.Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)	If abPowerAttack && !RefSelfActor.HasLOS(akAggressor)		;	ElseIf abPowerAttack && abSneakAttack		;	ElseIf abPowerAttack && abHitBlocked		;	ElseIf abBashAttack && abSneakAttack		;	EndIf	; Check if the caster has recieved enough damage to affect this effect.	HealthPercentCur = RefSelfActor.GetActorValuePercentage("Health")	; If this is a negative value	If HealthPercentCur != HealthPercentOld		HealthPercentDiff = HealthPercentOld - HealthPercentCur		HealthPercentOld = HealthPercentCur		Debug.Notification("HealthPercentDiff: " + HealthPercentDiff as String)	EndIf	; NOTE - this looks very inefficient. It might cause script engine lag over a long period.	; Only tracks damage for now and doesn't restore base damage yet.	If HealthPercentDiff < 0.0 && HealthPercentDiff > -0.6		Debug.Notification("Magnitude weakened.")		;Int n = 0		;Int ArrayLength = QuestRegistryArray.Length		;While n != ArrayLength		;	Float TValue = http://forums.bethsoft.com/topic/1510136-how-to-get-an-activemagiceffect-instance/RefMagicSystemQuest.GetTargetHealthDamageBaseStack(QuestRegistryArray[ArrayLength]) * (1.0 + HealthPercentDiff)		;	RefMagicSystemQuest.SetTargetHealthDamageMod(QuestRegistryArray[ArrayLength], TValue)		;	ArrayLength += 1		;	Utility.Wait(0.05)		;EndWhile	ElseIf HealthPercentDiff <= -0.6		Debug.Notification("Effect dispelled.")		;Int n = 0		;Int ArrayLength = QuestRegistryArray.Length		;While ArrayLength		;	RefMagicSystemQuest.DispelTargetEffect(QuestRegistryArray[ArrayLength])		;	ArrayLength += 1		;	Utility.Wait(0.05)		;EndWhile		;Self.Dispel()	EndIfEndEvent; Thread-safe function for getting the Actor this script is attached to.Actor Function GetActor()	Return Self.RefSelfActorEndFunction
Spoiler
ScriptName ACGMagicTargetActorScript extends ActiveMagicEffectActor Property RefSelfActor Auto ; Reference to the Actor this script is attached to.MagicEffect Property RefEffectParent Auto ; Reference to the Magic Effect this script is attached to.ACGQuestMagicSystemScript Property RefMagicSystemQuest Auto ; Reference to the magic system quest script.Int Property SelfQuestIndex Auto ; Tracks this script's location in the quest.String[] Property EffectNameArray Auto ; Array to cache effect names.Int[] Property RefCasterScriptIndexCache Auto ; Array to cache caster scripts for casters who have affected this Actor.Int CacheLength ; Tracks the length of RefCasterScriptIndexCache. Useful for easily adding new effect entries to the array.Float[] Property HealthDamageBaseArray Auto ; Base damage per second.Float[] Property HealthDamageModArray Auto ; Helps track changes to HealthDamageBase.Float[] Property HealthDamageBaseStackArray Auto ; HealthDamageBase stacking.Float[] Property HealthDamageModStackArray Auto ; HealthDamageMod stacking.Float TotalDamage ; Total calculated damage to apply.Bool DamageModified = False ; Check for modified damage stack.Bool[] Property DeathDispelArray Auto ; For non-Essential Actors.Bool[] Property BleedoutDispelArray Auto ; For Essential Actors.Float UpdateInterval = 0.1 ; Update interval for RegisterForUpdateSingle()Event OnEffectStart(Actor akTarget, Actor akCaster)	RefSelfActor = akTarget	; Register with the control Quest.	RefMagicSystemQuest.RegisterTargetScript(Self)	; Only for player use.	RegisterForControl("Shout") ; Is this the best key to use? Can it be tapped quickly in the middle of combat?	RegisterForKey(12) ; Minus key.	RegisterForKey(13) ; Equals key.	Debug.Notification("Target script added.")EndEventFunction RegisterEffect(Int EffectScriptIndex, String ALName, Float HealthDamage, Bool DispelOnDeath, Bool DispelOnBleedout)	RefCasterScriptIndexCache[CacheLength] = EffectScriptIndex	EffectNameArray[CacheLength] = ALName	HealthDamageBaseArray[CacheLength] = HealthDamage	DeathDispelArray[CacheLength] = DispelOnDeath	BleedoutDispelArray[CacheLength] = DispelOnBleedout	; Update CacheLength with the new length.	CacheLength = RefCasterScriptIndexCache.LengthEndFunctionEvent OnUpdate()	; TODO - DamageModified is False for now. This will be updated soon.	If DamageModified		; TODO - update HealthDamage variables as appropriate.		Int n = 0		While n < CacheLength			TotalDamage += HealthDamageModStackArray[n]		EndWhile	EndIf	; Deal a relative amount of damage in relation to the UpdateInterval period.	RefSelfActor.DamageActorValue("Health", TotalDamage)	RegisterForSingleUpdate(UpdateInterval)EndEventEvent OnKeyDown(Int KeyCode)	; TODO - this function will track the Minus and Equals keys, and modify the damage of spell	; effects of the player's choosing.	; Depending on the key the Player presses, we either stack damage positively or negatively,	; according to the base damage and Caster-health-influenced damage. Time cost and distance	; cost are also stacked. This affects this target only if they on the player's selected target list.	;If ??? ; How will this work?	;	If KeyCode == 12 ; Minus key.	;		HealthDamageBaseStack -= HealthDamageBase	;		HealthDamageModStack -= HealthDamageMod	;		If HealthDamageBase <= 0.0	;			Self.Dispel()	;		EndIf	;	ElseIf KeyCode == 13 ; Equals key.	;		HealthDamageBaseStack += HealthDamageBase	;		HealthDamageModStack += HealthDamageMod	;	EndIf	;EndIfEndEvent; For Essential Actors. Non-Essential Actors enter bleedout too, but we want it to keep; affecting them until the OnDying() event.Event OnEnterBleedout()	If RefSelfActor.IsEssential()		Int n = 0		While n < BleedoutDispelArray.Length			If BleedoutDispelArray[n] == True				; Do something			EndIf		EndWhile	EndIfEndEvent; For non-Essential Actors, as only they can die.; OnDying() used because OnDeath() is buggy, according to various gamesas Forum posters.Event OnDying(Actor akKiller)	Int n = 0	While n < DeathDispelArray.Length		If DeathDispelArray[n] == True			; Do something		EndIf	EndWhileEndEvent; This function will, in future, remove effect entries and modify spell damage appropriately.Function SelfDispel()	;EndFunction; Thread-safe function for getting the Actor this script is attached to.Actor Function GetActor()	Return Self.RefSelfActorEndFunction

And here's the quest script they report to:

Spoiler
ScriptName ACGQuestMagicSystemScript extends QuestSpell Property RefTargetActorSpell AutoSpell Property RefCasterActorSpell AutoActor[] Property MagicTargetActorRegistry AutoActor[] Property MagicCasterActorRegistry AutoACGMagicTargetActorScript[] Property MagicTargetScriptRegistry AutoACGMagicCasterActorScript[] Property MagicCasterScriptRegistry AutoInt TargetIndex = 0Int CasterIndex = 0; Int[] Property RefPlayerCasterActorArray AutoFunction RegisterTargetScript(ACGMagicTargetActorScript TargetScript)    MagicTargetScriptRegistry[TargetIndex] = TargetScript    MagicTargetActorRegistry[TargetIndex] = MagicTargetScriptRegistry[TargetIndex].GetActor()    TargetIndex += 1EndFunctionFunction RegisterCasterScript(ACGMagicCasterActorScript CasterScript)    MagicCasterScriptRegistry[CasterIndex] = CasterScript    MagicCasterActorRegistry[CasterIndex] = MagicCasterScriptRegistry[CasterIndex].GetActor()    CasterIndex += 1EndFunction; See whether the tracker scripts already exist on the target and caster Actors, and if not, add them. Then, add the effects to; the scripts' effect caches.Function RegisterEffect(Actor TargetActor, Actor CasterActor, String EffectNameAL, Float MEffectBaseDistanceCost , Float MEffectBaseTimeCost, Float HealthDamageBase, Bool DeathDispel, Bool BleedoutDispel)    Bool FoundTargetActor = False    Bool FoundCasterActor = False    Bool loop = True    Int ArrayLength = MagicTargetActorRegistry.Length    Int n = 0    Int WantedTargetIndex    Int WantedCasterIndex    While loop && n < ArrayLength        If MagicTargetActorRegistry[n] == TargetActor && MagicCasterActorRegistry[n] == CasterActor            ; If the target and caster Actor pair are found, let's register straight away.            MagicTargetScriptRegistry[n].RegisterEffect(n, EffectNameAL, HealthDamageBase, DeathDispel, BleedoutDispel)            MagicCasterScriptRegistry[n].RegisterEffect(n, EffectNameAL, MEffectBaseTimeCost, MEffectBaseDistanceCost)            Return        EndIf        If MagicTargetActorRegistry[n] == TargetActor && FoundTargetActor == False            WantedTargetIndex = n            FoundTargetActor = True            If FoundCasterActor                loop = False            EndIf        EndIf        If MagicCasterActorRegistry[n] == CasterActor && FoundCasterActor == False            WantedCasterIndex = n            FoundCasterActor = True            If FoundTargetActor                loop = False            EndIf        EndIf        n += 1    EndWhile    If FoundTargetActor        MagicTargetScriptRegistry[ArrayLength] = MagicTargetScriptRegistry[WantedTargetIndex]    Else        TargetActor.AddSpell(RefTargetActorSpell)    EndIf    If FoundCasterActor        MagicCasterScriptRegistry[ArrayLength] = MagicCasterScriptRegistry[WantedCasterIndex]    Else        CasterActor.AddSpell(RefCasterActorSpell)    EndIf    MagicTargetScriptRegistry[ArrayLength].RegisterEffect(ArrayLength, EffectNameAL, HealthDamageBase, DeathDispel, BleedoutDispel)    MagicCasterScriptRegistry[ArrayLength].RegisterEffect(ArrayLength, EffectNameAL, MEffectBaseTimeCost, MEffectBaseDistanceCost)EndFunctionFloat Function GetTargetDistance(Int n, Actor CasterActor)    Return MagicTargetScriptRegistry[n].GetActor().GetDistance(CasterActor)EndFunction

If someone could help me find an alternative way of getting a handle for the ActiveMagicEffect scripts I need to access, that would be very much appreciated. :smile:

User avatar
Miragel Ginza
 
Posts: 3502
Joined: Thu Dec 21, 2006 6:19 am

Return to V - Skyrim