Papyrus - Advanced Spell Creation

The first part begins with the set up. Here's what we need to do:

  1. Modify a spell that has an explosion (Fireball for example) to create a custom spell
  2. Modify the MagicEffect it references, making it your own MagicEffect, with Detrimental flag unchecked and everything else the same

Now for the second part, we need to add a Quest that will act as the controller / receiver for spell hit events. After this we merely need to customize the properties we scripted, as demonstrated in the video. Note that the spell as it is here was designed for demonstration purposes, and I leave it up to the reader to extend it any further. There are a few things that can be done with that in mind, such as maintaining proximity to every NPC that the orb attacks, using TranslateTo and averaging the NPC locations to generate a centroid. You can also improve the robustness of the event handling and so forth.

Here is the script for the Quest


Scriptname AAASpellControlScript extends Quest  
;by EB / Xoleras xoleras.com - leave this here please! :)

float Property maxDist = 768.0 Auto
Activator Property AAASphere Auto

ObjectReference[] spheres = None
Actor[] extraActors

bool lock = false

Event OnUpdate()
	int i = 0
	while (i < extraActors.Length)
		if (extraActors[i] && !extraActors[i].IsDead())

		int j = 0
		while (j < spheres.Length)
			if (spheres[j] && spheres[j].GetDistance(extraActors[i]) < maxDist)
				(spheres[j] As AAASphereScript).AddActor(extraActors[i])
			endIf
			j += 1
		endWhile

		endIf

		i += 1
	endWhile
endEvent

function HitEvent(Actor A)

if (!lock)
	lock = true

	if (spheres)
		int i = 0
		while (i < spheres.Length)
			if (spheres[i] && spheres[i].GetDistance(A) < maxDist)
				(spheres[i] As AAASphereScript).AddActor(A)
			endIf
			i += 1
		endWhile

		if (i == spheres.Length)
			int index = GenerateSphere(A)
			(spheres[index] As AAASphereScript).AddActor(A)
		endIf
	else
		;create new sphere
		spheres = new ObjectReference[16]
		int index = GenerateSphere(A)
		(spheres[index] As AAASphereScript).AddActor(A)
	endIf	

	lock = false
else
	if (!extraActors)
		extraActors = new Actor[16]
	endIf

	int i = 0

	while (i < extraActors.Length)
		if (!extraActors[i] || extraActors[i].IsDead())
			extraActors[i] = A
			i = extraActors.Length
		endIf

		i += 1
	endWhile

	RegisterForSingleUpdate(0.2)
endIf
endFunction

int  function GenerateSphere(ObjectReference spawnPoint)
	int i = 0
	while (i < spheres.Length)
		if (!spheres[i])
			spheres[i] = spawnPoint.PlaceAtMe(AAASphere)
			spheres[i].SetPosition(spheres[i].X, spheres[i].Y, spheres[i].Z + 384.0)
			return i
		endIf
		i += 1
	endWhile
endFunction

And here is the code for the Activator


Scriptname AAASphereScript extends ObjectReference  
;by EB / Xoleras xoleras.com - leave this here please! :)

Spell Property streamSpell Auto

int maxHits = 10
float timeDelta = 0.1
float timeDelay=  0.4

Actor[] targetList
int count = 0

Event OnUpdate()
	maxHits -= 1

	if (targetList)
		LaunchStream()
	endIf

	if (maxHits > 0)
		RegisterForSingleUpdate(timeDelta)
	else
		Disable(true)
		utility.wait(2)
		Delete()
	endIf
endEvent

Event OnLoad()
RegisterForSingleUpdate(timeDelta)
endEvent

function AddActor(Actor A)
	if (!targetList)
		targetList = new Actor[16]
	endIf

	if (count < 16)
		targetList[count] = A
		count += 1
	endIf
endFunction

function LaunchStream()
int i = 0

	while (i < count)
		if (targetList[i] && !targetList[i].IsDead())
			streamSpell.Cast(self, targetList[i])
			utility.wait(timeDelay)
			InterruptCast()
		endIf
		i += 1
	endWhile
endFunction

Finally, add the script to the MagicEffect. We need to add a Quest property and we need to add the OnEffectStart event that fires when the spell hits a target. Before you compile the ActiveMagicEffect script, you must first compile the Activator script then the Quest script.

Quest Property ControlQuest Auto

Event OnEffectStart(Actor victim, Actor caster)
if (victim)
(ControlQuest As AAASpellControlScript).HitEvent(victim)
endIf
endEvent

Make sure that the scripts are actually added to the objects that we intended to add them to, otherwise errors will be given and the spell will not function.