A Spell System
by Gareth Fouche · 09/02/2005 (5:24 pm) · 35 comments
Download Code File
I created this spell system for my game a little while ago. Basically, my goal was to create something like the item system, whereby you create a new item by filling out details in the datablock and writing a few scripts. The rest should be handled for you behind the scenes (in code).
So here is is. Basically I have created a Spell object in source code. All you do to create a new spell type is fill in a few of the "stub" scripts, such as onBeginCasting and onTick. The spells can do anything you could do with a script, hurl projectiles, heal, teleport, whatever. As long as you have the scripting ability.
To use the spells, add the .cc and .h to your source code and recompile. Then add the spells.cs to your server directory. Make sure you remember to exec it in game.cs. Just after you exec it, put this line :
Add the Spells folder from the zip into the server directory as well. If you write new spells, put them in there. The InitSpells() call will ensure they are loaded up.
Now, to cast a spell, you simply create a new Spell object, just like you would create a projectile. You create it on the server. Note, the spell itself does not get ghosted across to the client. But any effects you create might be. So for example in the fireball spell, I just create a projectile. It handles ghosting itself across. Likewise, the heal spell restores players health. The player object handles transmitting that data across, there is no need to send the spell object itself.
Here is code that creates a spell object, just add it at the end of player.cs :
How you call that function is up to you, you could use a Server Command, personally my player stores a "current spell", and clicking the right mouse button calls this function. Note also the hard coded caster level. The Invisibility spell is an example of how to use caster level as a multiplier of the spells effect, in this case duration.
Spells have a casting time, after that time has finished the spell begins "ticking". It ticks for the duration, then ends. If you want effects (eg. particles) to occur while the player is casting, create them in onBeginCasting and clean them up in onEndCasting. Put the actual spell effects in onEndCasting and onTick. If the spell is instantaneous, like Fireball, just put the code in onEndCasting. onDurationEnd is called when the spell ends.
Note, the duration might not be exactly what you set it to be, as the processing occurs once every 32 ms. If the spell is not a multiple of that, it might get an extra "tick".
I have included some example spells in the .rar, Fireball, Heal and Invisibility. Take a look at those to see how its done.
Have fun!
I created this spell system for my game a little while ago. Basically, my goal was to create something like the item system, whereby you create a new item by filling out details in the datablock and writing a few scripts. The rest should be handled for you behind the scenes (in code).
So here is is. Basically I have created a Spell object in source code. All you do to create a new spell type is fill in a few of the "stub" scripts, such as onBeginCasting and onTick. The spells can do anything you could do with a script, hurl projectiles, heal, teleport, whatever. As long as you have the scripting ability.
To use the spells, add the .cc and .h to your source code and recompile. Then add the spells.cs to your server directory. Make sure you remember to exec it in game.cs. Just after you exec it, put this line :
InitSpells();
Add the Spells folder from the zip into the server directory as well. If you write new spells, put them in there. The InitSpells() call will ensure they are loaded up.
Now, to cast a spell, you simply create a new Spell object, just like you would create a projectile. You create it on the server. Note, the spell itself does not get ghosted across to the client. But any effects you create might be. So for example in the fireball spell, I just create a projectile. It handles ghosting itself across. Likewise, the heal spell restores players health. The player object handles transmitting that data across, there is no need to send the spell object itself.
Here is code that creates a spell object, just add it at the end of player.cs :
function Armor::castSpell(%this, %obj, %spelldata)
{
%energy = %obj.getEnergyLevel();
if(%energy > %spelldata.manaCost)
{
%obj.setEnergyLevel(%energy - %spelldata.manaCost);
%spell = new Spell()
{
datablock = %spelldata;
caster = %obj;
casterLevel = 10;
};
MissionCleanup.add(%spell);
}
}How you call that function is up to you, you could use a Server Command, personally my player stores a "current spell", and clicking the right mouse button calls this function. Note also the hard coded caster level. The Invisibility spell is an example of how to use caster level as a multiplier of the spells effect, in this case duration.
Spells have a casting time, after that time has finished the spell begins "ticking". It ticks for the duration, then ends. If you want effects (eg. particles) to occur while the player is casting, create them in onBeginCasting and clean them up in onEndCasting. Put the actual spell effects in onEndCasting and onTick. If the spell is instantaneous, like Fireball, just put the code in onEndCasting. onDurationEnd is called when the spell ends.
Note, the duration might not be exactly what you set it to be, as the processing occurs once every 32 ms. If the spell is not a multiple of that, it might get an extra "tick".
I have included some example spells in the .rar, Fireball, Heal and Invisibility. Take a look at those to see how its done.
Have fun!
About the author
Recent Blogs
• SoW Weekly Update 10• SoW Weekly Update 9
• SoW Weekly Update 8
• SoW Weekly Update 7
• SoW Weekly Update 6
#22
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11024
08/02/2006 (8:44 pm)
Update. I did manage to get this resource working with the RTS kit. It took modification of several files in both the C++ and script. I had a cvs fiasco so I'm not 100% sure of all the files I changed, and I left the spell hardcoded for now, but click below to try it outhttp://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11024
#23
08/10/2006 (11:45 am)
Got this working great on 1.4
#24
08/10/2006 (2:20 pm)
How do I get it to where the spell effect comes from lets say the player's hand or higher up instead of their feet?
#25
And what do you mean by make a new spell object like a projectile?
Sorry for my bad spelling... If i spelled something wrong, but how would I know!
09/16/2006 (7:15 pm)
I NEED HELP ON WHERE TO PUT THINGS... I didn't get what paragraph 3 said...And what do you mean by make a new spell object like a projectile?
Sorry for my bad spelling... If i spelled something wrong, but how would I know!
#26
09/16/2006 (7:16 pm)
Also is there a way to make it so you can always cast spells?
#27
03/08/2007 (11:10 am)
Just make your energy really high or take out the energy check and drain from the spell
#28
03/08/2007 (4:19 pm)
Great resource, good job.
#29
Anyone know what is causing this?? I'm using TGEA btw.
05/27/2007 (9:16 am)
Hmmm.....i'm getting this error in my console: serverCmdCastSpell: Unknown command. Anyone know what is causing this?? I'm using TGEA btw.
#30
huge thanks to Sabrecyd and Peter Simard for their comments
below are the changes that need to be made to get this resource to work
in Player.cs
function Armor::castSpell(%this, %obj, %spelldata){
to
function Player::castSpell(%this, %obj, %spelldata){
////////////////////////////////////////////////////////////////////////////////
Edit your player.h file and add to the Players public definitions:
bool mCasting;
under
bool canJump(); ///< Can the player jump?
///////////////////////////////////////////////////////////////////////////////
also Peter Simard method for the spell casting works very well
//----------default.bind.cs:
function fireball(%val)
{
if(%val)
{
commandToServer('CastSpell', 'fireball');
}
}
moveMap.bind( keyboard, f, fireball );
//------------server commands.cs
function serverCmdCastSpell(%client, %spellName)
{
%player = %client.player;
if(%player)
{
%player.castSpell(%player, detag(%spellName));
}
}
06/24/2007 (5:48 pm)
Great resource works in 1.5 BUT it really needs to be updated huge thanks to Sabrecyd and Peter Simard for their comments
below are the changes that need to be made to get this resource to work
in Player.cs
function Armor::castSpell(%this, %obj, %spelldata){
to
function Player::castSpell(%this, %obj, %spelldata){
////////////////////////////////////////////////////////////////////////////////
Edit your player.h file and add to the Players public definitions:
bool mCasting;
under
bool canJump(); ///< Can the player jump?
///////////////////////////////////////////////////////////////////////////////
also Peter Simard method for the spell casting works very well
//----------default.bind.cs:
function fireball(%val)
{
if(%val)
{
commandToServer('CastSpell', 'fireball');
}
}
moveMap.bind( keyboard, f, fireball );
//------------server commands.cs
function serverCmdCastSpell(%client, %spellName)
{
%player = %client.player;
if(%player)
{
%player.castSpell(%player, detag(%spellName));
}
}
#31
If you open up spells.cs you can see that it loads up the spell data by checking the ./spell directory. As a quick fix I currently have fireball.cs in both the server/scripts directory as well as server/scripts/spells
Hope this helps someone who is having trouble with this resource.
07/07/2007 (9:54 pm)
I just wanted to comment that if your spells (i.e. fireball.cs) are not also in the server/scripts/spells directory, your spell will not work. I put my fireball.cs in the server/scripts directory only at first, only to receive errors. If you open up spells.cs you can see that it loads up the spell data by checking the ./spell directory. As a quick fix I currently have fireball.cs in both the server/scripts directory as well as server/scripts/spells
Hope this helps someone who is having trouble with this resource.
#32
07/12/2007 (10:48 am)
I have a question. Does anyone know a way to actually stop a spell from within the onTick script? I have made some very nice poison scripts, the only problem is that when you die, the poison keeps damaging you to keep you from respawning. So I added an if dead check to see if this would work, but it appears I can't respawn as long as the spell is still cast on my player. I need a way to force the spell to end manually. I tried to expose the numTicksProcessed to the scripting engine, but as I'm pretty noob to the engine side of things, apparently I failed (an echo showed a current NumTickProcessed of -1039512, but the spells still timed correctly =\ ) . So I was wondering if anyone knows a way to do this, as I'm sure other people could use it as well.
#33
Where do I add them? Any perticular file?
03/14/2009 (8:45 am)
Quote:
To use the spells, add the .cc and .h to your source code and recompile.
Where do I add them? Any perticular file?
#34
This is what I get in the console:
And when I try to use the Fireball spell-example, I get this error:
Anyone got some ideas or can see what I've done wrong?
It compiles without errors on Visual C++ 2005
04/08/2009 (5:48 am)
I'm trying to implement this in TGE 1.5.2 and with GAMEHACK3R's post I made it far but I'm getting errors I can't figure out how to fix..This is what I get in the console:
Loading Spell datablocks from: ./Spells/*.cs Compiling starter.fps/server/scripts/Spells/Invisibility.cs... Loading compiled script starter.fps/server/scripts/Spells/Invisibility.cs. starter.fps/server/scripts/Spells/Invisibility.cs (16): Unable to instantiate non-conobject class SpellData. Compiling starter.fps/server/scripts/Spells/Heal.cs... Loading compiled script starter.fps/server/scripts/Spells/Heal.cs. starter.fps/server/scripts/Spells/Heal.cs (15): Unable to instantiate non-conobject class SpellData. Compiling starter.fps/server/scripts/Spells/fireball.cs... Loading compiled script starter.fps/server/scripts/Spells/fireball.cs. starter.fps/server/scripts/Spells/fireball.cs (14): Unable to instantiate non-conobject class SpellData. Loading complete.
And when I try to use the Fireball spell-example, I get this error:
starter.fps/server/scripts/player.cs (1002): Unable to instantiate non-conobject class Spell. Set::add: Object "0" doesn't exist
Anyone got some ideas or can see what I've done wrong?
It compiles without errors on Visual C++ 2005
#35
Re-did the changes and whatnot, compiled again and now it works.
So, I have to say that it works on TGE 1.5.2
04/09/2009 (10:56 am)
Got it working now, not sure what I did to be honest.. lolRe-did the changes and whatnot, compiled again and now it works.
So, I have to say that it works on TGE 1.5.2
Torque Owner Darin Schneider
Unfortunately, this only open another can of worms. I have now verified that the code runs to completion with echoes, but no projectile is fired. This is due to (I'm guessing) how RTS treats the projectile object compared with standard Torque.
...
After some investigation, it appears that this resource will need a serious overhaul to work with RTS. The RTS kit rewrote the projectile class, and (somebody correct me if I'm wrong) only appears to be a visual. Actual damage caused by projectiles is handled in a completely different manner.
I was able to tweak the resource to get a fireball visual effect to fall flat on the ground of the caster (I assume b/c I can not pass the target location into the RTSProjectile class presently)
I'll give this some more thought and play around to see if I can possibly use this for the visuals, but use the standard (or similar) onAttack/onCast constructs to maim your victim.