Page 1 of 1

[Tutorial] Make a magic missile (or other projectile) spell

Posted: Fri Oct 26, 2012 11:08 pm
by JKos
Due to limitations of current custom spell support I had to invent a workaround for making projectile spells.
See this thread: viewtopic.php?f=14&t=3846

So I made a small tutorial about it as I promised :)
I will post this to grimwiki too.

how to make a properly working magic missile (or other projectile spell)

First we have to make a spell projectile model, for that a blue gem retextured with white_light material works nicely, this tutorial will not cover retexturing process, but you can download already retextured spell_projectile.model from here:
https://docs.google.com/open?id=0B7cR7s ... ENwRG5zamM

Save the spell_projectile.model file to your mods mod_assest/models/ directory

Next phase is to define an object which uses that model
mod_assets/scripts/objects.lua

Code: Select all

--general spell projectile object
defineObject{
	name = "spell_projectile",
	class = "Item",
	uiName = "Spell projectile",
	model = "mod_assets/models/spell_projectile.fbx",
	gfxIndex = 109,
	attackPower = 1,
	impactSound = "fireball_hit",
	stackable = false,
	sharpProjectile = false,
	projectileRotationY = 0,
	weight = 0,	
}
Now lets clone it as a magic missile

Code: Select all

cloneObject{
		name = "magic_missile",
		baseObject = "spell_projectile",
		uiName = "Magic missile",
		particleEffect = "magic_missile",
}
Define white glowing particle effect for magic missile

Code: Select all

defineParticleSystem{
	name = "magic_missile",
	emitters = {
		-- glow
		{
			spawnBurst = true,
			emissionRate = 1,
			emissionTime = 0,
			maxParticles = 1,
			boxMin = {-0.0, -0.0, 0.0},
			boxMax = { 0.0, 0.0,  -0.0},
			sprayAngle = {0,30},
			velocity = {0,0},
			texture = "assets/textures/particles/glow.tga",
			lifetime = {1000000, 1000000},
			colorAnimation = false,
			color0 = {1, 1, 1},
			opacity = 1,
			fadeIn = 0.1,
			fadeOut = 0.1,
			size = {0.8, 0.8},
			gravity = {0,0,0},
			airResistance = 1,
			rotationSpeed = 2,
			blendMode = "Additive",
			objectSpace = true,
		}
	}
}	
Ok, now we have an item that can be used as a projectile and looks like a white glowing ball of light.
But now it's time to do the real magic, so lets do some scripting.

Define the magic_missle spell

Code: Select all

defineSpell{
		name = "magic_missile",
		uiName = "Magic missile",
		skill = "fire_magic",
		level = 1,
		runes = "A",
		manaCost = 15,
		description = "The mage creates a bolt of magic force that unerringly strikes one target.",
		onCast = function(caster,x,y,direction,skill)
			mymod_spells.castMagicMissile(caster,x,y,direction,skill)
		end
	}
onCast-hook calls a function castMagicMissile from script entity named as mymod_spells(you can change that).
Of course the mymod_spells script entity does not exist yet so we have to create it in editor.

mymod_spells script entity

Code: Select all

function castMagicMissile(caster,x,y,direction,skill)
	shootProjectile('magic_missile', party.level, x, y, direction, 14, 0, 0, 0, 0, 0,10, party, true)
end
Now we can cast the magic missile (rune A). That was pretty easy right? BUT the caster or party will never get XP for kills made by magic missile spell.
So if we wan't to implement that, things do get bit trickier. For that we have to setup a onParticleHit hook for EVERY monster, but on this tutorial I will set it up for snail only.
mod_assets/scripts/monsters.lua

Code: Select all

cloneObject{
		name = "snail",
		baseObject = "snail",
		onProjectileHit = function(monster,projectile)
			return mymod_spells.magicMissileOnProjectileHitHook(monster,projectile)
		end
}
You can use a for loop to define that hook to all monsters. You just need a list of monsters.

Now we have to extend the mymod_spells script entity and add that function called from onProjectileHit-hook.

Code: Select all

-- we have to store the caster ordinal here 
-- so that we can calculate the right originator for damageTile on magicMissileOnProjectileHitHook
spellCasters = 0

function castMagicMissile(caster,x,y,direction,skill)
	shootProjectile('magic_missile', party.level, x, y, direction, 14, 0, 0, 0, 0, 0,100, party, true)
	spellCaster = caster:getOrdinal()
end
-- we have to use damageTile to deal the spell damage to monsters because that is the only way to give xp for the spell caster for kills 
function magicMissileOnProjectileHitHook(monster,projectile)
	if projectile.name == 'magic_missile' then
		local originator = 2 ^ (spellCaster+1) -- calculate the originator of the spell
		local damage = math.random(2,10) --
		damageTile(monster.level,monster.x,monster.y,(monster.facing + 2)%4,originator+1, 'physical',damage)
		playSoundAt("fireball_hit",monster.level,monster.x,monster.y)
		return false
	end
end
See this post about the damageTile flags argument: viewtopic.php?f=14&t=3861#p40130

Re: [Tutorial] Make a magic missile (or other projectile) sp

Posted: Sat Oct 27, 2012 12:45 am
by Grimwold
Great tutorial, thanks!

Re: [Tutorial] Make a magic missile (or other projectile) sp

Posted: Sat Oct 27, 2012 1:17 am
by JohnWordsworth
Awesome tutorial - let me know if you would like any help putting it on the Wiki (I noticed in your other thread that you said you might!).

It's a shame that projectiles don't have an 'onHit' hook instead of having to use the monster's hook.

Re: [Tutorial] Make a magic missile (or other projectile) sp

Posted: Sat Oct 27, 2012 12:13 pm
by JKos
Added to Grimwiki http://grimwiki.net/wiki/Make_a_magic_missile_spell

projectile:onHit() - hook would be great. I think I can implement it in LoG Framework, thanks for the idea.

Re: [Tutorial] Make a magic missile (or other projectile) sp

Posted: Mon Nov 12, 2012 2:43 pm
by akroma222
Very useful indeed! Thanks :D

Re: [Tutorial] Make a magic missile (or other projectile) sp

Posted: Tue Nov 13, 2012 3:48 pm
by cromcrom
I love it, thanks a lot, Adding this to TLC, crediting you of course.