CCG V3-1 Conversion:Part 5 Spells
From NWN1 Custom Content Guide
Contents |
Spells
Let’s see what else we can do with .2da files. Maybe I want to create a new spell effect. I’d like to create the necromantic spell, Chill Touch. I get a huge combination of effects to build my new spell from. I can add new icons similar to what we did for the weapons and other items. The only real tricky part will be coding the effects I need.
To create a new spell, these are four basic steps:
- Create two icons, one for the spell and one for the spell as a scroll.
- Create a spell resource in spells.2da.
- Create a spells item property resource in iprp_spells.2da.
- Create a script that delivers the effect that you want for your spell.
Part 1: The Spell Icons
Create one icon for the spell and another for it as a scroll. You could use the same icon for both but Bioware uses a black, white and purple theme for the spell icon and a brown and white theme for the scroll icon. The image on each is similar. I won’t go into detail on the icons because we have done so many already. They are 24 bit, 32 x 32 pixel Targa bitmaps (.tga files). The naming standard is not critical for spell and scroll icons but if you want to follow the Bioware standard it is:
is_<name>.tga for spell icons
iss_<name>.tga for spell scroll icons
Where <name> is a maximum of 11 characters. You can find these using NWN Explorer in Textures02.bif. Use one as a sample of how to do it. Unlike the weapon icons, there is no alpha mask or other complication on these files.
Here are my two new spell icons. Image:Ccg fig 29.jpeg Image:Ccg fig 30.jpeg I used the Ghoul Touch icons as a template and did some editing to make them more reminiscent of a shivering, cold hand. I actually put the spell name on the spell icon. Why? With the current limitations on changing dialog.tlk, there is really no way to get my new spell name into your spell book. So I want to make it explicit which spell you are dealing with. This is not necessary for the scroll because, as an item, I can put whatever text labels and descriptions I want on it in the Aurora Toolset.
Part 2: The Spell Resource
The spell resource file - spells.2da – defines each of the spells (and spell-like abilities), how it is cast, who can cast it, and a variety of other details. There are eight main parts to a spells.2da record.
|
- General information (spell name, school, range, etc.)
- What classes can use the spell and what level it is
- The Conjuration group which stores the sounds and animations that are played when the spell is being cast. Refer to the spell effects reference near the end of this tutorial for details on effects you can use.
- The Cast group which stores the sounds and animations that are executed when the caster is done chanting and the spell takes effect. This is not the effect on the recipient -- that is handled in the ImpactScript -- but is, for example, the animation for the cone of frost between the caster and target in a cone of cold spell. Cast effects take place after Conjuration effects. Refer to the spell effects reference near the end of this tutorial for details on effects you can use.
- The Projectile group. This one designates any type of model that moves between the caster and the target. An example would be the ball of the fireball spell that travels from the caster’s hand to the target and then explodes.
- A list of immunities.
- Linked spells. This is where you can designate a spell to have more than one type of end effect, similar to a Polymorph spell where you can pick from several options. Linked effects are used for radial menus.
- Miscellaneous information.
The following are the columns from spells.2da:
| Column | Description | Values |
| The ID number | Bioware recommends padding this file out to 1500 so do this and start your new spells at 1501. | |
| Label | The name of the spell | Any spaces should be replaced with underscores '_'. I’m not sure if it will ever be possible to put **** in the Name column for spells – Bioware has indicated that they don’t really consider rules changes (spells, feats, etc.) to be in the field of customizable content. |
| Name | The strref to the name of the spell in dialog.tlk. | The same limitations apply that you should be used to be now. The label will not show up in the game engine. I chose 4692 which points to a string called “Devil Chills”. Close enough to imply Chill Touch for now. I don’t want to use dialog.tlk if I don’t have to. |
| IconResRef | Name of the .tga file that will represent the spell icon. | You can create your own icons and put them in the hakpak. This is the recommended method because people want to be able to tell spells apart visually.
Alternately, you can use generic icons for the different spell school classes: Abjuration = is_abjure Conjuration = is_conjure Divination = is_divine Enchantment = is_enchant Evocation = is_evoke Illusion = is_illusion Necromancy = is_necromancy Transmutation = is_transmut |
| School | School of magic |
A = Abjuration C = Conjuration D = Divination E = Enchantment I = Illusion N = Necromancy T = Transmutation V = Evocation |
| Range | Range of the spell | P = Personal (affects only the caster)
T = Touch (affects the person touched) S = Short (25 ft + 5 ft/2 levels, according to standard 3e rules) M = Medium (100 ft + 10 ft/level) L = Long (400 ft + 40 ft/level) |
| VS | Verbal and somatic components of the spell. | V = Verbal only (cannot cast this spell if silenced)
S = Somatic (Spell suffers arcane spell failure from armor) VS = both - = neither |
| Metamagic | Defines which metamagic feats can be used on the spell. The number is a bit flag setting and must be in hexadecimal format.
The numbers need to be added together to get the final set of flags for the spell. Example: I want a spell that can be Quickened, Silent, Still, and Maximized. I would have 8(Quicken) + 16(Silent) + 32(Still) + 4(Maximize) = 60 total. Once you get the number you need to convert it into hex format. The easiest way if you use Windows is to use the calculator. Open up the Calculator program in Windows and under the View menu switch to scientific mode. Make sure the round radio button is checked for Dec. Enter in your number and then change it from Dec to Hex; this is your hexadecimal number. Enter this number along with a 0x (just programmer’s notation that a number is in hexadecimal format) to the column. That is a 'zero' and not the letter Oh. So our example would be 0x3c. | 0x01 = 1 = Empower
0x02 = 2 = Extend 0x04 = 4 = Maximize 0x08 = 8 = Quicken 0x10 = 16 = Silent 0x20 = 32 = Still |
| TargetType | This is the type of target the spell requires. Like the MetaMagic value, this is actually a binary flag system. You must enter the hex code after adding up the values for all the targets you want to be able to affect. | 0x01 = 1 = Self
0x02 = 2 = Creature 0x04 = 4 = Area/Ground 0x08 = 8 = Items 0x10 = 16 = Doors 0x20 = 32 = Placeables 0x40 = 64 = Trap triggers (only when detected) and area transition triggers (this does not work very well - the cursor is active on the area transition, but when clicking the PC is left hanging before casting the spell and the script doesn't fire). This value is not currently used by Bioware. |
| ImpactScript | The script that runs against the target of the spell | |
| Bard, Cleric, Druid, Paladin, Ranger, Wiz_Sorc, Innate | The level of the spell for each class, if it can't be used by that class then it is commented out with ****
Innate is for creatures that have it as a spell like ability. A lot of creature abilities are implemented as "innate spells". | |
| ConjTime | Conjuration is the process of invoking the spell. The conjuration time in milliseconds.
Note: the Conjuration effects are executed before the Cast effects. | For spells it is 1500 with only 1 exception - Phantasmal Killer - which is at 900 |
| ConjAnim | This is for the character or creature invoking the spell and calls the appropriate animation so that the caster goes through the right motions. | The three possible values are:
hand = Casters hands are in front of him. head = Casters hands reach up to above face level. **** = No hand movement |
| ConjHeadVisual | This is to add a visual effect over the head of the caster when invoking the spell. | Some sample head visuals and the spells they are used on are:
Ice_Storm = vco_mehancold03 Resurrection = vco_mehanelec01 Premonition = vco_mehanelec03 Meteor_Swarm = vco_mehanevil03 There are a lot more. I have included the visual effects reference at the end of this tutorial. |
| ConjHandVisual | This adds an effect to - or between - the caster's hands when invoking the spell. | Refer to the visual effects list. |
| ConjGrndVisual | This adds an effect to the ground around the caster when invoking the spell. | Refer to the visual effects list. |
| ConjSoundVFX | This is the sound effect that plays when invoking the spell. It is not the caster's voice but the energy crackles, moaning, etc. that plays in the background. | Refer to the visual effects list. |
| ConjSoundMale
ConjSoundFemale | These are the sound effects for the chanting that the caster does while invoking the spell. | Refer to the visual effects list. |
| CastAnim | The caster's pose after finishing the spell conjuration.
Note: the Cast animations and effects occur after the Conjuration ones. | Possibilities are:
Area out self touch up **** |
| CastTime | This seems to be how long in milliseconds the caster stays in the CastAnim pose. | There seem to be 2 settings:
1000 = most spells 1700 = spells with ray or cone shaped effects |
| CastHeadVisual | Not currently used for any spells | |
| CastHandVisual | These effects happen to the caster after the conjuration effects take place. An example would be the force rings that radiate from the casters hand after a magic missile spell or the cone of frost from a cone of cold spell | |
| CastGrndVisual | Not currently used for any spells | |
| CastSound | The sound played after the Conjuration | |
| Proj | Is there a projectile model that moves between the caster and the target in the spell |
1 for yes 0 for no |
| ProjModel | The model that moves between the caster and the target. | The currently used ones are:
vpr_aroacid vpr_ectoacid01 vpr_ectocold01 vpr_ectoevil01 vpr_ectofire01 vpr_ectomind01 vpr_ectonatr01 vpr_ectoodd01 vpr_ectosonc01 vpr_fireball vpr_ringsmal vpr_wrait |
| ProjType | The physics of the projectile |
accelerating homing linked |
| ProjSpwnPoint | Where the projectile starts at from the caster |
hand head |
| ProjSound | The sound of the projectile | |
| ProjOrientation | Which direction to orient the projectile in. | Set to path if there is a projectile |
| ImmunityType | Type of immunity needed to ignore the effects of this spell. | Note there are three Mind Affecting immunities and two Positive immunities, I'm not sure if this a typo or not - looks like one
Acid Cold Death Disease Divine Electricity Fear Fire Mind_Affecting Mind_Effecting (Typo?) Mind-Affecting (Typo?) Negative Poison Positive Postive (Typo?) Sonic |
| ItemImmunity | Are items immune to being affected by this spell? |
1 for yes 0 for no |
| SubRadSpell1 - 5 | These are for spells that have multiple ways of casting them. The values in these columns are the index value of "sub" spells that will come up in another radial menu. Spells like Polymorph Self or Shapechange where you can pick a type of creature to turn into or Shadow Conjuration where you can pick the spell to emulate. The maximum number of choices you have for a spell will be 5. The people who are planning on implementing radical new Polymorph spells where you can turn into all sorts of animals may want to look at this. | It has been reported that radials only work if the new spells use ID numbers directly consecutive to those already in use. |
| Category | These are equal to the various TALENT_CATEGORY_* constants in nwscript.nss.
These are used in various AI scripts to select appropriate abilities for creatures or NPCs to use. | The Category is related to the categories.2da file in 2da.bif. Here are the reported values:
1 = Harmful AoE Discriminant (i.e., only affects enemies) 2 = Harmful Ranged 3 = Harmful Touch 4 = Beneficial Healing AoE 5 = Beneficial Healing Touch 6 = Beneficial Conditional AoE (e.g., See Invisible) 7 = Beneficial Conditional Single 8 = Beneficial Enhancement AoE 9 = Beneficial Enhancement Single 10 = Beneficial Enhancement Self 11 = Harmful AoE Indiscriminant (affects all within AoE) 12 = Talent Beneficial Protection Self 13 = Talent Beneficial Protection Single 14 = Talent Beneficial Protection AoE 15 = Talent Beneficial Summon 16 = Auras and Rages 17 = Special Monk Feat 19 = Dragon Attacks |
| Master | Used in conjunction with the SubRadSpell columns. For a sub spell this is the parent spell that called it.
The actual effect of this seems to be that the uses-per-day of the master spell is reduced by one when cast instead of this spell's uses-per-day. Generally all sub-spells will want this and no others will. | |
| UserType | Always 1 for spells |
1 = Spells 2 = Creature Power 3 = Feat 4 = Item Power |
| SpellDesc | The strref for the description of the spell in dialog.tlk | Here we go again. I use 59 which is a blank string. It leaves the description blank. |
| UseConcentration | Determines if a Concentration check is needed to successfully cast the spell if interrupted (e.g., if hit during combat) | 1 for yes
0 for no For spells always 1. The only records which have a 0 are uninterruptible ones like constant creature powers |
| SpontaneouslyCast | This is for the Clerics spontaneously casting. Only Cure/Cause wounds should have this |
1 for yes 0 for no |
| AltMessage | This is the strref for the message in dialog.tlk that is displayed to people other than the caster, for example "SoAndSo smites evil". | |
| HostileSetting | Will a NPC consider this an attack if they are affected by the spell? | 1 for yes
0 for no This actually is used in the SignalEvent call. If it is 1, then it will be a hostile act when the target gets the event signaled to them. |
| FeatID | The ID of the feat. There are a few feats that are activated like spells, and call scripts in a similar manner. These use the FeatID to determine when they show up, and what they do. | 380 Battle_Mastery_Spell (...) 306
381 Divine_Strength (...) 307 382 Divine_Protection (...) 308 383 Negative_Plane_Avatar (...) 310 |
Part 3: The Item Property Spells Resource
Technically, you only need a reference in iprp_spells.2da if you want an item to be able to cast this spell. How does this work? Well, there is a list of item properties in itempropdef.2da and these are the properties you can assign to items in the Aurora Toolset. Within each property is the property sub-type. For spells, this sub-type points you to iprp_spells.2da. By adding a resource in this 2da file, you can then tie your spell to an object like a scroll or another magic item.
| Column | Description | Values |
| The ID number | Bioware recommends padding this file out to 750 so do this and start your new spells at 751. | |
| Label | The name of the spell | Any spaces should be replaced with underscores '_'. Some day it should be possible to put **** in the Name column and the game will use this field to refer to your spell. |
| Name | The strref to the name of the spell in dialog.tlk. | One more instance where I can’t get it to do what I want. Hopefully this will be fixed soon. |
| CasterLvl | The level at which the spell is cast from this item. | 1 to 20 |
| InnateLvl | Not sure. Need to investigate. | 1 to 20 |
| Cost | Appears to be the cost increment added to the minimum level required for the item to be used. If you add too many powers to an item, it becomes unusable because it exceeds the maximum character level of 20. | |
| SpellIndex | Reference back to the spell ID in spells.2da | Use the ID you added for your spell in spells.2da |
| PotionUse | Can this item be used as a potion? |
1 for yes 0 for no |
| Wanduse | Can this item be used as a wand? |
1 for yes 0 for no |
| GeneralUse | Can this item be used for general items? |
1 for yes 0 for no |
| Icon | Icon to be used for this item as a scroll. | It needs to be a typical 32 x 32 pixel tga file. You can select one of the existing icons with the format iss_<name> where <name> is no longer than 8 characters. They are found in textures02.bif. Or you can create your own, use a similar naming standard. |
The other 2da files – iprp_spelllvlimm.2da (spell level limit), iprp_spelllvcost.2da (spell level cost), iprp_spellshl.2da (spell school) – do not need to be adjusted. I am not sure what iprp_spellcost.2da is for.
Part 4: The Spell Script
Let’s take a look at the new script for Chill Touch. This is not a scripting tutorial, but I’ll try to give you a basic flavor of how these work. You can look at existing scripts by opening up scripts.bif using NWN Explorer or from within the Aurora toolset (there is a radio button on the File Open dialog that allows you to open any existing script file). The spells are all named nw_s0_<spellname>.nss. The .ncs files are compiled spell files so you can’t read them directly.
Here is my new Chill Touch script.
//:://///////////////////////////////////////////// //:: [Chill Touch] //:: [ES_S0_ChillTch.nss] //::////////////////////////////////////////////// //:: Causes 1d6 damage on each successful touch //:: attack (1 attack per level). Reduces strength //:: by one if target fails Fortitude save //:: (duration of one minute / level). //:: //:: If the target is undead it is not damaged but //:: must save vs. Will or flee as if panicked for //:: 1d4 rounds + 1 round per level. //:: //:: NOTES: does not properly implement 1 attack //:: per level and does not consider that undead //:: are immune to mind affecting spells //::////////////////////////////////////////////// //:: Created By: Eligio Sacateca //:: Created On: December 21, 2002 //:://////////////////////////////////////////////
#include "NW_I0_SPELLS"
void main()
{
//Declare major variables
//the object you were targetting
object oTarget = GetSpellTargetObject();
//check if you are using any Meta Magic feats
int nMetaMagic = GetMetaMagicFeat();
//check for a successful 'touch attack' on target
int nTouch = TouchAttackMelee(oTarget);
//if successful touch attack on a target that is not friendly
if (nTouch && !GetIsReactionTypeFriendly(oTarget))
{
//if the target is undead, use fear effect
if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
{
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FEAR));
//Make SR Check
if(!MyResistSpell(OBJECT_SELF, oTarget))
{
//calculation duration
int nDuration = GetCasterLevel(OBJECT_SELF) + d4(1);
float fDuration = RoundsToSeconds(nDuration);
//check metamagic
if (nMetaMagic == METAMAGIC_EXTEND)
{
fDuration = fDuration * 2.0; //Duration is +100%
}
//calculate and apply effects
//target is frightened
effect eFear = EffectFrightened();
//use fear visual effect
effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR);
//until impact expires
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
//Link the fear and mind effects
effect eLink = EffectLinkEffects(eFear, eMind);
//Link the fear and mind effects to the duration
eLink = EffectLinkEffects(eLink, eDur);
//Make a will save
if(!MySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FEAR, OBJECT_SELF))
{
//Apply the linked effects
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDuration));
}
}
}
else //target is not undead so apply damage and strength reduction
{
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HARM));
//Make SR Check
if (!MyResistSpell(OBJECT_SELF, oTarget))
{
//Start with the 1d6 damage
//Calculate damage
int nDamage;
//Check Metamagic
if (nMetaMagic == METAMAGIC_MAXIMIZE)
{
nDamage = 6; // damage is maximum
} else
{
nDamage = d6(1);
}
// set the visual effect to show the character taking damage
effect eVis = EffectVisualEffect(VFX_IMP_HARM);
// implement the effect so the character takes damage
effect eDam = EffectDamage(nDamage,DAMAGE_TYPE_NEGATIVE);
//Apply the VFX impact and effects
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
//Now apply the strength reduction
//Make a fortitude save
if(!MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_NEGATIVE))
{
//calculate duration
int nCasterLevel = GetCasterLevel(OBJECT_SELF);
float fDuration = IntToFloat(nCasterLevel) * 60; // 60 seconds per level
//Check for metamagic extend
if (nMetaMagic == METAMAGIC_EXTEND)
{
fDuration = fDuration * 2.0; //Duration is +100%
}
//calculate effects
//target is weakened
effect eFeeb = EffectAbilityDecrease(ABILITY_STRENGTH, 1);
//use ability reduction visual effect
effect eVis = EffectVisualEffect(VFX_IMP_REDUCE_ABILITY_SCORE);
//until impact expires
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
//Set ability damage effect
effect eLink = EffectLinkEffects(eFeeb, eDur);
//Apply the ability effect and VFX impact
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDuration);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget);
}
}
}
}
}
I won’t attempt to explain each line of this script but here is the overall outline:
|
- First, we find out who you were targeting.
- Next, before applying any effects, we check to make sure this is not a friendly target, and that you can make a successful melee attack against the target.
- Assuming that succeeds, we check if the target is undead. If it is, we apply an entirely different effect – frighten – to what we would do if the target were alive – damage and strength reduction.
- Assuming the target is undead, we notify them that they are the target of a fear spell and then do a spell resistance check (they will be notified that they are a target even if they are successful at resisting the spell). The notification will typically make them counterattack if they were not planning on doing that already. The spell resistance check takes into account natural resistance as well as items like cloaks, rings, etc.
- We calculate the duration of the spell (doubling it if the caster was using Metamagic) and then calculate the actual effects. The effects are linked together until the spell expires. This is how NWN maintains integrity between the visual effect (the icon you would get in the top right of your screen plus the 3d effect of the whirling skulls) and the actual effects (fear).
- We give the undead creature one last chance at a Will saving throw. If they fail that, whammo, all those effects are applied.
- Now, what if the target was not undead? We actually go through similar steps. Again, we notify the target they are the target of a spell (this time a harmful spell), and give them a spell resistance check.
- If the target fails that, we calculate the amount of damage they will take (1d6 or a full 6 if the caster had maximized the spell), and apply it. Note we don’t have to link any effects together this time. That is because the duration is instant (you take the damage right away, the visual effect fires and then we can forget about it).
- We also give them a fortitude-save. If they fail that, they suffer a –1 penalty to strength. The spell description in PHB does not specify for how long but I did a quick check and ray of enfeeblement lasts for 1 minute/level so I will assume the same (I have not checked for errata on the subject). The strength penalty is applied in a similar fashion to the fear effect although it differs slightly in that the duration and effects are not linked together? Why not? Beats me. I borrowed the code for the fear effect from nw_s0_fear and the code for the strength effect from nw_s0_rayenfeeb and they were done slightly differently. I think either method does the same thing.
I have seen it recommended that you add an entry in nwscript.nss for the integer CONSTANT of your spell name. I would not recommend this. When you look through the scripts to see where these constants are used, it is generally only in the SignalEvent(EventSpellCastAt()) line. Unless you want to do more coding and code a reaction for your specific spells in those events, it is not necessary to have your own CONSTANT for your new spell.
Part 5: Packaging it all up
Once you have done all of that, tidy it up and put your two spell icons and your two new .2da files into a hakpak. What do you do with the script file? Compile it into your module, of course. If you want to package your spell to send out for others to use, export your scripts as .erf files first.
There are currently some limitations with this approach, most having to do with labels. Let me describe the spell process and I will point them out as I go.
- Fire up the Aurora Toolset. Open your module.
- Add a new item using the Item Wizard. Make a scroll.
- Launch the Item Properties. On the Properties tab, I can add my new spell effect on the scroll. Because of the dialog.tlk limitation, it will use whatever STRREF you put into iprp_spells.2da so look for it there. This is not a huge limitation because you can rename your scroll to be whatever you want. In this case I rename it ‘Chill Touch’ and I add a description to explain what the new spell does.
- Drop a couple of copies of this blueprint into your module somewhere.
- Save your module. Fire up the game.
- As your character, fetch the scrolls you created. Now I can identify each scroll to see what is on them. Works fine.
- Use one of the scrolls to learn this new spell (assuming you are the right class and level, of course). If you go to your spell book you will see the spell there using your new icon. Again, because of the 2da limitation, you will find that the name in your spell book corresponds to the STRREF you chose (in my case, Devil Chills). Click on the description. Again, it will correspond to the STRREF for SpellDesc (in my case, blank).
- Put the spell in one of your spell slots. Rest.
- Now go track down a monster (you did put a monster in your module, didn’t you?).
- Fire the spell off at your new monster. Observe its beauteous effects. Makes you feel good, eh?
- Use the other scroll to fire off at your monster again. This is what it means to customize the game.
Even if you find the naming limitation too annoying in-game, there are still uses for custom spells. Put them on items as special properties (just not in scrolls). That way characters can use them for as item powers but they can’t learn them as spells for their characters. Better yet, give the spells to enemy spell casters. They won’t care that the spell uses funny names and all your players will see is the effect of that nifty new spell which they cannot learn. Is that unfair, or what? Ah, the joy of being a DM.
« Items Without Models | Spells | Custom Armor and Clothing »
