This document describe all things spell and spell related that developers need to know. This document outlines the new spell objects and how this all works.
In the old model, each spell had a specific number associated with it. Monster spell abilities, while objects, just said to use spell number X. Given that everything else in the game is object, this hardcoding of spells was less than ideal.
In the new system, spells are objects. The spell object the player knows has the characteristics of the spell. As a first pass, the existing spells are just converted to object form. As time passes, new spells can be easily added in this system. It also simplifies the code - the spells a player knows are now objects in his inventory. The spell a wand casts is the spell in its inventory. The spell a scroll casts is the spell in its inventory, and the spell you learn by reading a spellbook is the spell in its inventory.
This model makes it very easy to make variations of some spells. Want to make an extra large fireball? All this is needed is to take the large fireball arch, increase a few parameters, and you're all set.
The following is the fields in the object structure, and how they correspond to a spell. Fields that are not mentioned are not used.
char *name | Name of the spell (large fireball, icestorm, etc) |
char *lore | Description of the spell to be put in books, or perhaps even to just let the player see. In a sense, this puts documentation of the spells within the object, instead of having to maintain seperate files. |
sint16 casting_time | How long it takes to cast the spell (was time). This is the number of ticks it takes for the player to cast the spell, and is thus not a fixed time. |
face/anim | If the spells is a generic spell that doesn't have an other_arch pointer, this is the face (or animation to use when the spell is cast. |
uint8 type | set to SPELL (101) (to denote this is spell object) |
sint16 resist_* | For protection spells, resistance they provide. |
uint32 attacktype | Attacktype of the spell. |
uint32 path_* | spell path information. Note as of this writing, only path_attuned is expected to mean anything. However, I can envision the user of path_repelled/denied to denote that if the caster is attuned to some path, they have penalties in casting this spell. |
sint32 value | Base value of this spell for scroll, spellbooks, wands, rods. |
sint16 level | Level of the spell |
other_arch | archetype this spell uses. In the case of bolts, this is the bolt that is fired. |
char *skill | Skill needed to cast this spell. |
sint32 subtype | Sub classification for this spell. It sort of relates to the existing spell number, but in a more general form. At first pass, subtypes would fall into protection spells, bolt spells, ball spells, cone spells, stat increase spells. There are a number of spells which can not be abstracted and are unique in their own right (dimension door, word of recall, polymorph, etc). In these cases, there will be one value for that spell type. |
invisible | Always set to 1, so that the player can't directly see it in their inventory. |
no_drop | Always 1, so when a spell object is destroyed, the spell it contains is dropped and not freed. |
Suggested casting time values:
These are only suggestions - they more or less match when the spell will be used and usefulness. An attack spell that takes forever to cast isn't very useful. There are really two things to keep in mind - when the spell is cast, and how long the spell itself last. A long lasting spell can have a longer casting time, simply because it isn't cast that often and will last for a while (thus, smart players won't cast it in combat).
From living/stats substructure:
Str, Dex, etc | If spell changes and ability, this is the ability it changes. |
sint16 dam | Base damage the spell does |
sint16 sp | how many spellpoints the spell costs |
sint16 grace | how much grace the spell costs |
sint16 maxsp/maxgrace | Every 'maxsp/maxgrace' levels beyond its base level, the spell cost doubles (this is pro rated like the old code). For example, if a first level spell costs 5 sp, and maxsp is 5, then at level 6 it would cost 10 sp. However, at level 2, it is 6 sp, level 3 is 7 sp, etc. |
uint8 dam_modifier | for every maxdam levels above what is needed to cast the spell, it does an extra point of damage. Note if you want a spell to double its damage every X levels, the maxdam may have to be quite low (1) if the spell does high damage. For example, suppose you have a 10'th level spell that does 50 damage. If dam_modifier is 5, then every 5 levels it does one extra point, so at level 25, it would do 53. If dam_modifier is 1, then at level 25 it would do 65. |
sint16 duration | Base duration of the spell (was bdur) |
uint8 duration_modifier | Modifies duration of spell, acts the same way as dam_modifier. |
uint8 range | Range of the spell - this could be how far a lightning bolt goes, how big that fireball is, etc. Spells with range 0 are personal only spells. Spells with range 1 can touch a person on a neighboring space. Range will not change based on level of the caster - if higher range is desired, different spell should be made. |
uint8 range_modifier | Modifies range of spell, acts ame way as dam_modifier |
TBD: There are also many fields in the spell structure which are not copied - charges, scrolls, scroll_chance, books, defensive, cleric, onself.
The defensive, and onself can largely be derived from the subtype above. if subtype is protection or healing, it'd be self.
cleric is basically redundant now - the skill says what skill to use for this spell. Note that a spell could in theory cost both mana and grace - what it costs is not necessarily tied to a skill. However, it would be bad practice to make a wizardry spell use mana. However, I could potentially see hybrid skills that have some variosu benefits, or if we have say a 'magic' god, perhaps some special spells it provides a use mana.
So lets next touch on the idea of treasurelist for spell objects.
As mentioned above, spell objects, like wands, spellbooks, scrolls, etc, contain the spell they cast. The way spells end up in those objects is via a mechanism there is already code for - treasurelists.
Currently, the treasure generation code notices if a wand, rod, spellbook, or scroll is generated. If so, it calls special code that looks at the field of the spell structure and randomly chooses a spell.
Instead, this is just replaced with treasurelists. The scroll object would have a 'randomitems scroll', wands a 'randomitems wand',etc. These may be big treasure lists, but that shouldn't post any problem. More likely, these lists would be broken up into smaller pieces (eg, scroll_low_level, scroll_medium_level, scroll_high_level).
This provides finer resolution than is currently allowed in the spell structure - you could make some spell available only in rods, but not wands. you can better adjust things to better spells show up in tougher dungeons, etc,
When a spell is cast, often it copies over certain values into the SPELL_EFFECT (102). The subtype of the SPELL_EFFECT, which should generally match that of SPELL itself, determines what the spell does.
Long ago a number of archmages discovered patterns in the web that spells weave in the aether. They found that some spells had structural similarities to others and some of the mages took to studying particular groups of spells. These mages found that by molding their thought patterns to match the patterns of the spells they could better utilise all the spells of the group. Because of their disciplined approach, the mages were described as following spell Paths. As they attuned themselves to particular spell Paths they found that they would become repelled from others, and in some cases found they were denied any access to some paths. The legacy of these mages remains in some of the magical items to be found around the world.
In the same way that players and objects can be protected, immune, and vulnerable to the different types of attacks, they can now be attuned, repelled, or denied access to the different spell Paths. An object that is attuned to a Path cast spells from that Path at 80% of the spell point cost and receives duration/damage bonuses as if the caster were five levels higher. An object that is repelled from a Path casts spells from that Path at 125% of the spell point cost and receives duration/damage bonuses as if the caster were five levels lower (minimum of first level). An object that is denied access to a Path cannot cast any spells from it. The casting time is also modified by 80% and 125% respectively. These values are defined in PATH_SP_MULT (from spells.h), PATH_TIME_MULT (from spells.h), and path_level_mod (from spells.c)
The Paths themselves are the following:
0 "Nothing" 1 "Protection" 2 "Fire", 4 "Frost", 8 "Electricity", 16 "Missiles", 32 "Self", 64 "Summoning", 128 "Abjuration", 256 "Restoration", 512 "Detonation", 1024 "Mind", 2048 "Creation", 4096 "Teleportation", 8192 "Information", 16384 "Transmutation", 32768 "Transferrence", 65536 "Turning", 131072 "Wounding", 262144 "Death", 524288 "Light".
The Crossfire Bit Decoder is a useful tool to extract these types of values.
See define.h for the number values corresponding to the Path.
Some more will be added in the near future. Some spells do not currently belong to a Path, this is probably appropriate for some spells. Paths are inherited just like protection/immunity/vulnerability, ie if a ring contains “path_attuned 1”, the wearer becomes attuned to the Path of Protection.
Paths are quite powerful and shouldn't be given away cheaply. Ideally, most objects with path_attuned attributes should have path_repelled and path_denied attributes as well, to balance out (eg attuned to Fire, repelled from Protection, and denied from Restoration)
check above information :)
This section lists specific spell subtypes and what they really do. The idea is to try and generalize the object types (cones, bolts, balls, etc). However, some number of spells, most notably detection spells, must have their own entries because the code that is actually executed needs to re-act accordingly.
These spells bring back dead players. These spells are only useful on servers that use PERMADEATH.
Runes are objects that embed another spell in them, and are activated when someone walks on top of the rune. Runes can be disarmed.
* other_arch: This can be set to one of 3 values: 1) name of rune (type = rune). If this is the case, rune is put on the map with few changes. 2) name of spell. In this case, the spell is embedded into the the rune. generic_rune object will be used, with the face updated. 3) NULL. In this case, the player specifies the rune to embed. * face: Face that the rune object will use.
If other_arch is set in the spell object, then it is assumed that the sp (or grace) cost in the spell object is the total that should be used. If it is an embedded spell, then the cost will be in addition to that to cast the spell.
Special rules for runes where player can choose what spell to embed: skill for the embedded spell must match the rune. Player must have enough mana/grace to embed the spell as well as cast the actual rune.
Note that runes created by players/monsters will have the spell put into the rune's inventory. However, archetype runes will still use the other arch, as inventory in archetypes isn't really supported.
This really works fine - This allows custom spells to be embedded into runes. For archetypes, using the default spell archetypes work fine.
This makes a 'mark' that contains a message. In the old system, this used to be part of the rune code, but it really doesn't have anything in common with runes (except in name).
This fires a bolt (other_arch) of the spell object. All of the following values are copied from the spell object and into the bolt object (other_arch in the spell object).
Note if duration is less than range, which it should typically be, then a bolt will only be in a subsection of the entire range.
A bolt object can have the generator flag set, in which case as the bolt moves along, it will create an other_arch object. The steambolt is an example of this. This can not be set in the spell object, and is instead set in the other_arch field that the spell refers to.
Bullets are single objects that go in a direction and hit something. The simplest case here is magic bullet, that hits something and does damage.
Exploding ball type spells are a more complicated variation. These object start out as a bullet, but when they hit something, they explode, into fire or poison or the like. The other_arch field determines what they explode into.
Values for spell object:
See notes about explosion below.
Objects of subtype explosion are really only useful when attached to a bullet - you don't really want to explode something on yourself.
Note that the set up of the below values is also the same for SP_CONE types if a cone is attached to a bullet.
Given two objects are created from one spell, tuning this/creating new spells of this type is tricky. We can only use the range for the bullet or explosion. Likewise, adjusting damage is difficult. Ideally, perhaps, some additional fields in the spell object itself are used to fully implement this, eg, these two fields determine the range/damage of the bullet, and these 3 determine range/blast/damage of the ball itself. That is the only real way to make a ball spell fully adjustable.
Note that SP_CONE can be the other_arch of a SP_BULLET. In this case, the set up of the cone values is as described in SP_EXPLOSION setting.
Note 2: The other_arch that is in the cone can really be any object. As such, the code does not modify this object, other than to set proper ownership. As such, you can't set what values will be set in the arch thus vitriol is the best example of both of these notes - it starts out as a bullet, which then turns into a cone, which then drops acid pools.
Bombs are as they are described - objects that sit around for a little while before exploding.
The bomb itself is harmless - its not until it explodes do bad things happen.
In the bomb object, the following attributes are set up:
bombs tick at a constant rate, as defined by there speed. They explode when the finish their last animation. There is no way to adjust this rate of ticking in the spell object, other than to point other_arch at a customized bomb.
A bomb then explodes. It explodes into 'splints' (this is unfortunately hardcoded), which are of type specified by the other_arch pointer of the bomb, which default to SP_EXPLOSION.
Wonder is a spell that will cast another spell. It will also sometimes cast a cone of flowers (other_arch).
Note old wonder code would only cast spell that would be found in books. This new code can be used to cast most any spell, as defined as in the treasurelist.
Note 2: Ideally, the flower effect should also be in this treasure list, so the occurence could be accurately controlled.
Smite spells are target spells - the spell looks for an appropriate enemy in the direction pointed, and if one is found, hits them with whatever is in the other_arch. It is generally assumed that other_arch will point to another spell.
Special notes if attacktype includes a death attacktype (finger of death):
Magic missiles are really just a bullet type object that have some more intelligence in their guiding (but not much). Basically, a magic missile will more or less go in the direction it is fired, but will adjust course to hit a monster. Thus, if something isn't perfectly lined up, magic missile will still hit it. range, attacktype, etc, all have normal meanings.
This spell summons a friendly creature/object that helps out the player.
Golems lose 1 hp each time they do something. This effectively limits their duration, but does mean it can be extended by healing the golem. Not sure if this is the way to go, or if duration should really just be used.
Note: the old code had ldam and ldur have multiple meanings, and the code multipled them by 10 internally. This is no longer done - instead, the archetype itself should have the real value (10 times the old compiled in values)
Dimension door lets the player move some large number of spaces. One still can not teleport through no magic areas.
This draws an overview of the map around the player. There are currently no parameters the spell takes - the results are always the same. One could forsee parameters to change how far one sees, what one sees, etc.
This spell creates a magic wall. Walls can have a wide set of properties. Many are determined by the other_arch or race (the wall the spell creates).
Exactly how the a attacktype, duration, and damage values play out depend on what is being created and the spell.
Created object is of type SPELL_EFFECT: attacktype, dam, and duration are copied into fields of same name.
Created object is alive: duration becomes the objects hit points.
The level of the created object is always set to half that of the caster level.
Destruction hits all the spaces within some distance of the player with damage.
Note: As converted to a spell object, this is now usuable by monsters.
The rule for what is damaged is basically this:
This is really just a hook to know to call the right routine - at current time, none of the dam/range/duration fields of the spell have any meaning - only think that is used is the grace and skill pointers.
Perceive self basically presents information to the player about themselves, eg, race, any depletions, etc. Generally, isn't that useful since most all the same information is available with built in commands.
Word of recall teleports the player back 'home' after some amount of time. Parameters:
Makes the character invisible to monsters.
This spell looks in some direction (as specified by the player) and returns information about a monster.
This spell heals a character/monster. Creature must be where the player is.
Note that any number of these fields can be combined.
This creats food for the player. The food is not worth any money, but otherwise normal food.
The formula for how much food value is created is:
food_value=spell_ob->stats.food + 50 * SP_level_duration_adjust(caster,spell_ob);
This destroys earthwalls near the player.
This adjusts some ability the player has (str, dex, attacktypes, etc). This is only for beneficial effects - this is mostly because of the targetting logic (negative effect would still target friendly creature).
By default, only one benefit spell of each time can be active at a time (eg, you could have a strength and a dex, but not two strength spells). This is noormally tracked by changing the force name to be the same name as the spell, but see the race attribute below.
If a spell is already in effect, the duration of the existing spell will be increased, but otherwise none of the spell effects will be changed.
This blesses the character - the character gets various benefits based on the god he worships. Note that BLESS spells use the same type of force object as ability change above, include the race to prevent multiple castings. Note that most of all of the values are copied _from the god_. The value in the spell_object is only really used to know if the value from the god should be copied.
This is a lot like BLESS. Notable difference is that this is a bad effect for the recipient.
This covers a large subtype of monster/object summoning. At its very basic, this spell will create an object that is unchanged from the archetype, and thus can be used to basically create any object.
The reason not all summoned monsters are friendly is because there are some spells that create monsters specifically meant to be agressive to the player. If flag_monster is set, the monster/created object is not changed. Only if it is not set, do we set a value (flag_friendly).
This spell is used to recharge a wand.
This spell by default is disabled because of various abuses within the spell.
The spell normally turns one object into another similar type of object (eg, orc to goblin, sword to dagger, etc).
This turns nearby objects into gold nuggets.
This removes the cursed/damned status of objects. It only effects objects equipped by the player.
This identifies objects in the players inventory and on the ground.
This detects nearby objects (including ones in the players inventory). Detection in this context typically means revealing properties about the objects.
This following attributes determine what objects to show. Note that more than one of these can be set (for a 'detect all spell' for example).
This changes the 'mood' of a monster. See below for how moods are changed.
Note that a spell could set multiple of these fields, but it wouldn't really do much - a monster can really only have one mood.
This is really only used as a spell effect. Values of note:
Swarms are spells that fire other spells. It fires the same spell, but multiple times (eg, 5 lightning bolts).
Set during casting:
This gives/takes spellpoints to the target of the spell. If this spell gives sp, then the cost should be more than the sp it gives. target must be in the same or adjacent space.
This subtypes corresponds to the old transferrence and drain magic spells.
This removes runes from the ground. There are currently no option for this spell.
Creates bolts or arrows.
Note that making good (highly magical) arrows reduces number of arrows to be made.
This converts an altar to that of players god. There are currently no option to this spell.
This spell is similar to the GOLEM spells - it basically creates a golem, but uses a donor weapon for the face, basic attributes, etc. To implement this, it puts the donor weapon in the inventory of the golem, so when the golem dies, the weapon is returned to the ground. Note that in the conversion, I modified this spell to use the weapon 'marked' by the player, instead of the equipped weapon.
Arguably, such a basic spell wouldn't seem to need its own subtype. However, looking at the other spells, it really didn't fit in very well elsewhere - the magic_wall code passes most of its parameters to the object it creates. Something like summon_monster doesn't work, because it wants a free space to put the object.
And while it would be nice to somehow merge create food, create missile, and this, they are sufficiently different that they don't work very well. So instead, I try to abstract this as much as I can.
This changes the light level on the map. There is only one option:
Faery fire makes creatures within the area of effect glow. This code uses the cast_destruction routine, but just handles what happens when it finds a valid target.
Note: As converted to a spell object, this is now usuable by monsters. The rule for what is damaged is basically this:
Disease spells infect players with a harmful disease. See also Diseases.
The disease code treats these modified values in its own way.
Auras create fields around the players that effect anyone that steps into them.
This creates two linked portals which the player can use to get back and forth quickly.
Note the spell otherwise doesn't have any tunables.
It should be noted that if different archetypes were made it, it should be possible to have multiple town portal type spells that lead to different destinations.
document, or clean totally broken spell :)
This will curse or bless player's marked item. Curse will not change weight, just set the cursed flag. Bless will make the item god-given.
Note that if both cursed and blessed are set, cursed only applies. Also, no check is made to not have an item both cursed and blessed.
As described in section 2 above, objects that cast spells (wands, rods, scrolls, etc) contain the spell they cast in their inventory. When the player uses the object, the code looks for an object in the inventory, and uses as the type of spell to cast.
Treasure lists are used to determine what spell goes in the object. Thus, what spells show up in the objects is determined purely by the treasure lists, and unique lists can be made for potions, scrolls, wands, horns, and even different lists for heavy and light rods.
The value of the finished object is the value field in the spell object multiplied by the value object in the original object (rod, wand, scroll).
For items that come in different levels, the value is also adjusted based on the level of the object based on the difference of level. The code for this is in common/treasure.c
The nrof field for the treasurelists for these objects have special meanings - since the spell objects are invisible objects within the spell casting object, the nrof field has no actual meaning. However, we borrow that meaning for use in the parent object.
For wands, nrof is used for the number of charges the item has. For scrolls, nrof is the number of scrolls to make. This overrides the nrof value for the scroll itself - this allows for fine tuning number of scrolls that show up for different spells.
hp is the amount of 'energy' the rod currently has. when a spell is cast, hp is reduced by the amount of sp/grace the spell takes up.
speed is how often the rod recharges. There used to be a much more complicated way of of regenerating charges. Instead, each time a rod activates, it regenerates 10% of its total power. Thus, a rod of speed 1.0 would fully recharge in 10 ticks, a rod with speed 0.1 would fully recharge in 100 ticks.
This change in the way rods recharge now mean the speed of a rod can be set in a map (or elsewhere), and that change would stick.
Within the archetype itself, the maxhp value determines the number of spells the rod can hold before it needs to recharge again.
Potions and dusts (which were really just potions with a is_dust flag set) have been redone in several ways.
First, potions had varying meanings for the same archetype. You could have potions that improve stats permanently, ones that cast spells, and dust.
There is now a SPELL_POTION (116) type. This is used for potions that cast spells. These type of potions really never should have been the same type in the first place - other than name, they really had none of the same code.
These objects are very basic - they cast a spell whenever they activate.
If they have a spell object in their inventory (must be first item), that is the spell that is cast. Otherwise, they cast what other_arch points to.
Firewalls can be activated by buttons, and can also cast spells in specific directions. The direction the firewalls fire in is stored in the 'sp' field of the firewall.
Note that FIRECHEST (61) got folded into FIREWALLS, because functionally, they were identical - just set 'sp 0' in the firechest, and it fires in a random direction.
This section describes the basic layout of the archetypes in the arch directory. This explanation is here to try and prevent confusion (where should this arch go), where would I find an arch, etc.
I thought about this a bit - would it be better to organize spells by attacktype (eg, all fire spells together, all cold spells, etc), or by type of spell (bolt spells, bullet spells, cone spells, etc).
I think both methods have valid reasons for and against them. I decided to do it by spell type because I think it will make it easier to compare spells.
For example, if one bolt spell does 20 damage, and another does 30 damage, even if by another attacktype, pretty easy to see that the later is more potent.
This also organizes the spells more by their subtype, which is the more standard way the arch's have been done in the past. It makes for designing new spells much easier (you'd just copy a starter arch from the same directory, and not need to hunt for another one - imagine something like acid bolt).
That said, the organization (all relative to the arch top level directory)
There are almost certainly sub types I'm missing that I'll have to fill in. The idea here is to try to sketch something out that gives me a working layout to fill things in.
Within each of the spell subtype directories, the entries for the spell information would be needed. And example below:
In the case of subtype directories with lots of entries, it is likely that the directories may then get broken up by things like attacktype of the spells.
The number of top level object types is reduced - instead, many are now SPELL_EFFECT, with the subtype being the same as the spell that created them.
The server/time.c still has a dispatch for the SPELL_EFFECT, but it is in server/spell_util.c which determines how each subtype should be handled.
I try to keep all the same spell related code together, eg, put the code that casts the cone as well as moves the cone in the same file next to each other. This should reduce bugs - if someone changes one piece, they are more likely to notice the other piece and also update that. This is better than having the function in a completely different file.
spell_util.c really only contains very general code - dispatch routines, funcitons to adjust spells, etc. The actual work is done in either spell_attack.c, spell_effect.c, rune.c, or pets.c.
basically all the defines are in include/spells.h. This is a much simpler file than once was here. Remember, all the data now comes from the archetypes.
In the old code, abilities had some special meaning in terms of what spells the monster would cast.
In the new system, abilities are no different than spells, and use the same type/subtype.
Abilities may still be seperate for a few reasons:
It should be noted that many creatures just use the spell, and not the ability. Only some spells have ability counterparts.
Note: Before giving spell abilities to monsters, be sure that the monster will actually use them - the code in monster.c results in monsters only casting spells of certain subtypes.
is information below still right?