Programmable Spell Effects

NoteEdit

Most, if not all, of this is easier to do with OBSE's Active Effect functions



PROGRAMMABLE SPELL EFFECTS


Er? Can't I program my own spells using script effects already?

Well of course you can but there are several limitations. For example, what if you wished to do some combination of the following:


1) 'Silently' damage an NPC, i.e. without seeing any magic effects.

2) To turn the player invisible without raising his/her arm to cast.

3) XXX spell to be considered hostile only when a guard sees me cast it.

4) Cast a Morrowind-like spell that may fail and/or do a random amount of weapon damage.

5) Cast a spell that does fire damage to frost atronarchs but frost damage to flame atronarchs.

6) Know who cast that spell at me or some other actor.


Well now you can! The following procedures are built on the fact that Ability spell effects are cast on the target the moment they are added and do not cause any visible effects on the target nor caster. Of course you can add whatever effects you do want to see with PlayMagicShaderEffects or PlayMagicVisualEffects, etc.


Here is a BASIC example of how to create a 'silent' spell effect that does an instant 10 damage to the target:


Step 1: create an Ability spell, lets say 'SilentDm10' with:

Std Effect: Health Damage 10

Script Effect: StopSilentDm10


Step 2: create and attach the following magic effect script 'StopSilentDm10':

scn StopSilectDm10

Begin ScriptEffectStart
RemoveSpell SilentDm10
End

Step 3: actually use the spell in some other script:

; target here is a reference to some actor (or player)
target.AddSpell SilentDm10

Notice that using this spell is actually a neater syntax than that for Cast.


NOTE: Adding an ability to the player will produce message spam and so in this case this effect is not so silent. I would recommend changing the actual name of the spell to be something appropriate, e.g. "Poison damage". You wont see more than one "Posion damage added" message so long as all of your equivalent ability-cast effects have the same name.


True programmable spells are more useful. They are in effect (in-game) function wrappers for several silent and standard (area-effect targetting) spells.


Here is one example to show the BASIC principle. This one allows you to do X-fixed plus Y-random damage to a target:

scn WildDamageSpell

; this is an in-game function attached to object 'FIGWildDamageSpell'
;  - refer to the 2nd post and other posts of this thread

ref target
short baseDamage
short wildDamage
short isPlayerHostile
short dam

Begin Activate

; get/check the target
set target to GetActionRef
if target.IsActor == 0 || target.GetDead == 1
  Return
endif

; calculate damage apply to target
set dam to baseDamage+wildDamage*0.01*GetRandomPercent

; activate hostile - very primative version to give an idea
;  - does not check in town, guard vacinity/sight, current bounty, etc.
if dam > 0 && isPlayerHostile > 0   
 if target.IsGuard == 0   
  target.Startcombat player   
 endif   
 SendTrespassAlarm player   
 player.ModCrimeGold 35   
endif   

; add some (un-typical) spell graphic(s) (optional!)   
if dam > 0 
 target.PME DTCT 1   
endif   
    
; apply damage - here it is limited to 0-31 points per cast   
; - dam <= 0 does nothing, dam > 31 does 31   
if dam >= 16   
 target.AddSpell SilentDm16; same as SilentDm10 in last example but does 16 damage   
 set dam to (dam)-16   
endif   
if dam >= 8   
 target.AddSpell SilentDm08; ditto for 8 damage, and so on...   
 set dam to (dam)-8   
endif   
if dam >= 4   
 target.AddSpell SilentDm04   
 set dam to (dam)-4   
endif   
if dam >= 2   
 target.AddSpell SilentDm02   
 set dam to (dam)-2   
endif   
if dam >= 1   
 target.AddSpell SilentDm01   
endif   
    
End


To cast this spell, since it is an in-game function:

; target here is a reference to some actor - player is assumed to be the caster   
set FIGWildDamageSpell.baseDamage to 10   
set FIGWildDamageSpell.wildDamage to 20   
set FIGWildDamageSpell.isPlayerHostile to 1   
FIGWildDamageSpell.Activate target 1   
   

Advanced programable spell effects


Basically the sky's-the-limit here, or rather a matter of your imagination and scripting experience. Here are just a few things to expand the range of programmable spell functions:


1) Timed spells: Since in-game functions have the ability to trigger their own GameMode, a small modification of your spell function can be made to trigger every second (or every frame) for any variable time.

2) Touch/Target/Area effects: Since in-game functions can be called from anywhere, create a standard spell with the scope effect you want and add a script ability that just calls the function on the target(s).

3) Player-area/fast-target spells: Area effect spells cast from an activator/marker on to the player (caster) have been used by several people and are discussed on the CS Wiki and various threads. However, now you can wrap these effects nicely in your programmable spell function and have full control.

4) Caster tracking: Just add a reference variable to your function script called 'caster' and set before calling the function. (It may be appropriate to do this for the target ref(s) too.)

5) Simulating resistance, casting cost, etc.: These can all be done as checks, etc., in your spell function before the silent spell effect(s) are added. It's all up to you!

6) NPC cast spells: To force actor X to immediately cast on target Y is simple. Having it cast as it would be by RAI may take a bit of work. You could add a (hostile) spell to the actor directly that then adds your effect the target (as in 2 above). However, this will add to the base actor object. You can also simulate the AI yourself (AAI) with a permanent spell effect. This has a similar issue and solution, as described below.


Permanent Spell Effects


Ironically enough, the thing that Ability spells are not a good idea for is adding permanent effects to targets - including the player! The problem is that abilities get cancelled/re-cast when the target enters or leaves the player cell, and any scripted variables are reset. This also applies to abilities on the player when he/she changes cell, although here it is not so bad if you employ all global variable in the ScriptEffectUpdate block. An even less desirable issue is that the ability is added to the base actor object so any spawned generic characters will inherit the same ability. (This is partly why the recipe for silent spells always removes the ability after 1 frame.)

This is not an issue if you want your script to affect all base models and may actually be appropriate since the ability will only be in effect when the affected actor(s) are in the same cell as the player.

However, for true permanent (spell) effects on targets or invisible abilities on the player you really need to use Token Effects.