[Tutorial] How to cast spells at Non-Actors

Post » Mon Nov 19, 2012 3:54 am

This is a very easy trick to cast spells at non-actors. It might not do everything you need, but there is usually a workaround. For example, I recently released a Gravity Gun spell here:
http://skyrim.nexusmods.com/mods/23135
that works pretty well.

The trick is this: Make first a custom MiscItem (I use the soul gem fragment mesh as it is small). Apply the NullTextureSet shader to it to make it invisible. Now, put a script on this object that OnLoad() it does whatever you want. Probably you'll want to have the first line be something like this:
TargetObject = Game.FindClosestReferenceOfAnyTypeInListFromRef(DamnNearEverything, self, 45.0)

The list you will have to make yourself, and should consist of every object you would ever want to be able to cast your spell at. My list for the gravity gun spell includes every single object in the game that isn't an activator, actor, or static.
Don't worry about the size of the list much. Mine is about 7000 entries long, and it doesn't slow down the spell's performance one bit. I think FindClosestReferenceOfAnyTypeInList has a built in non-iterative search function based upon FormID, but this is pure conjecture.

Another thing you will want to do in all likelihood is put this objectreference in an alias, so make yourself an alias placeholder quest, and do that.

Also, make sure to disable/delete the MiscItem once it has accomplished its function, or you'll have a lot of invisible tiny objects around.

Now, make an explosion. It needn't have any special things about it, and should probably have a force of 0 unless you want to piss off everyone around you. The explosion should however place the MiscItem you made.

Now, make a custom projectile for your spell that includes this explosion. I've found this to be more consistent than using a vanilla projectile with your explosion declared in the Magic Effect for whatever reason.

Now make your spell's effect with the projectile you made.

Done.

In the spoiler below I will give a thorough examination of my gravgunspell as an example.

Spoiler


The first event that occurs is that my projectile's explosion's miscitem is spawned. It has this script.
Scriptname Portal_OnLoadFillAlias extends ObjectReference FormList Property DamnNearEverything autoReferenceAlias Property Thrown autoGlobalVariable Property ShouldThrow autoObjectReference Pulledevent OnLoad()if !Thrown.GetReference()  Pulled = Game.FindClosestReferenceOfAnyTypeInListFromRef(DamnNearEverything, self, 45.0)   if (Pulled)   Pulled.SetMotionType(Pulled.Motion_Keyframed)	    ShouldThrow.SetValue(1)     Thrown.ForceRefIfEmpty(Pulled)   Thrown.GetReference().SplineTranslateTo(Thrown.GetReference().GetPositionX(), Thrown.GetReference().GetPositionY(), (Thrown.GetReference().GetPOsitionZ() + 48.0), 0.0, 0.0, 0.0, 1.0, 300.0, 0.0)    endIFendIfdisable()delete()endEvent

As you can see, all this does is find the nearest object, put it in an alias, set it's motion type to KeyFramed (meaning I can manipulate it with translation functions (Thanks Verteiron!)) translate it once, and then disable deletes the miscitem itself.

Now, in the alias for the item I have this script.

Scriptname PCKP_Script_GravThrownAlias extends ReferenceAlias GlobalVariable Property ShouldThrow autoReferenceAlias Property HitActor autoActor Property PlayerREF autoint DealDamage=0bool transfailed=falseevent OnTranslationComplete()if ShouldThrow.GetValue() as int==1       GetReference().TranslateTo(PlayerRef.GetPositionX() + (50*Math.sin(PlayerREF.GetAngleZ())), PlayerRef.GetPositionY() + (50*(Math.cos(PlayerREF.GetAngleZ()))), PlayerRef.GetPositionZ() +90, 0, 0, 0, 256, 1)   elseIf HitActor.GetReference() && DealDamage==0   GetReference().SplineTranslateToRefNode(HitActor.GetReference(), "NPC Head [Head]", 1, 5000)    DealDamage=1 elseIf  DealDamage==1  GetReference().SetMotionType(GetReference().Motion_Dynamic)  float DamageDealt = (GetReference().GetMass() * 5.0)  if (GetReference().GetBaseObject() as Weapon) || (GetReference().GetBaseObject() as Ammo)   DamageDealt = DamageDealt * 2.0  endIf  if DamageDealt >=10.0   (HitActor.GetReference() as Actor).SendAssaultAlarm()  endIf  Debug.Notification(DamageDealt)  (HitActor.GetReference() as Actor).DamageActorValue("Health", DamageDealt)  HitActor.Clear()  dealdamage=0  Clear()else  GetReference().SetMotionType(GetReference().Motion_Dynamic)  HitActor.Clear()  Clear()endIfendEvent

Now, once the translation from my MiscItem's script is accomplished, it will trigger the first OnTranslationComplete event. Now, since the globalvariable shouldthrow==1 (meaning that it shoudln't be thrown) it will translate to a spot in front of the player. Once this is done, the event will be thrown again, and if shouldthrow still ==1, it will track to the spot in front of the player again. Now, this is where the script on the MagicEffect comes in. It is as follows:

Scriptname Portal_MEffScript_FillHitActorAlias extends activemagiceffect ReferenceAlias Property HitActor autoGlobalVariable Property ShouldThrow autoevent OnEffectSTart(Actor T, Actor C)if !HitActor.Getreference()HitActor.ForceRefTo(T)endIfendEventevent OnEffectFinish(Actor T, Actor C)if (HitActor.GetReference())  ShouldThrow.SetValue(0)endIFendEvent



So, whenever my projectile hits an actor (this is a concentration spell btw) it will register that actor as the target, filling an alias with him. Whenever I let go of the spell, ShouldThrow is set to 0. Now we revisit the alias script on Thrown.

Now I get to the second if statement of Thrown, where it has not yet translated to the hitactor, but there is a hitactor to go to. It translates to him and sets a boolean to true. Now, when the OntranslationComplete event is thrown again, as this boolean is true, it will deal him damage according to the mass of the object being thrown, and then sets its motion back to simulated.

That's about it, thanks for reading!

User avatar
lolli
 
Posts: 3485
Joined: Mon Jan 01, 2007 10:42 am

Post » Mon Nov 19, 2012 1:30 am

Hey Ducie,

NullTextureSet

I've read you listing this as a good thing to do, elsewhere: http://www.gamesas.com/topic/1398525-helemt-visiblity/page__view__findpost__p__21273221

Do you have an example script of doing that? And would it work for an Actor?

Cheers if you can help me out



Nice tutorial as well ... I can make use of this casting-trick as well :)
User avatar
Juliet
 
Posts: 3440
Joined: Fri Jun 23, 2006 12:49 pm

Post » Sun Nov 18, 2012 8:16 pm

You can just set the textureset when you create the object on the mesh directly, no scripting required.
User avatar
OJY
 
Posts: 3462
Joined: Wed May 30, 2007 3:11 pm

Post » Sun Nov 18, 2012 10:45 pm

Ah, I see. I was hoping you'd found a way to switch it via scripts.

I can do what I want with race changes, it's just that's a little bit cludgy because of the extended hops for SetRace with modded races.

Cheers. :)
User avatar
Ann Church
 
Posts: 3450
Joined: Sat Jul 29, 2006 7:41 pm


Return to V - Skyrim