Making a Basic Spell

From Baldur's Gate 3 Modding

This step-by-step guide covers how to make a simple spell. We'll be making a target-based spell that explodes on a target, deals Fire damage to everyone in the area, and heals the caster.

Locating the Spell Data

Open the Stats Editor via the bar chart icon located in the top right of the main toolbar.

Opening the Stats Editor.

In the left column, there will be a list of Projects. Open the one that corresponds to your mod’s name – it should be the same as your project’s name. For the purposes of this guide, our mod is called SimpleNewSpell. Expand the project to see its subfolders.

Expanding the project (mod) in the Stats Browser.

Here, you will see various sections you can open and modify. To create spells, find SpellData and click the + symbol.

The SpellData section.

This will open a dropdown of the various spell types that are available in the game.

The SpellData dropdown.

For the target spell we are making, you’ll need to add both Target and Projectile spell data. You might need to expand the SpellData folder to see your new additions.

The new Target and Projectile files in SpellData.

Making a Target Spell

We will be making a Touch spell (a spell that requires the caster to touch the target) that explodes on a target. The explosion will deal Fire damage to everyone in the area and heal the caster.

Open your newly created Target spell data.

The empty Target spell data table.

For Target spells, there are a few required fields that must be filled in for the spell to execute correctly in the game. We will be going over those required fields, as well as some extras needed for the above example.

Name

You will need to fill in the Name field for the spell. This is the spell’s Technical Name, also referred to as its TechName. This is what the system uses to give a specific spell to the player.

This field:

  • Does not accept spaces
  • Accepts underscores _ (often used in lieu of spaces)
  • Accepts numbers and uppercase and lowercase letters

In our example, we will use the TechName FireTouch.

Level and SpellSchool

If you want your spell to show up as part of a specific level (Cantrip, Level 1, etc.) or spell school (Evocation, Divination, Necromancy, etc.), fill out the Level and SpellSchool fields.

  • The Level field accepts numbers.
    • 0 = Cantrip
    • 1 = Level 1 spell
    • 2 = Level 2 spell, etc.
  • The SpellSchool field is a dropdown of spell schools.

We want to make our spell a Level 3 Evocation spell, similar to Fireball, so we’ll fill in 3 for the Level, and select Evocation from the SpellSchool dropdown.

This information will automatically appear in the in-game tooltip.

Filling in the Level and SpellSchool columns.

TargetRadius

The TargetRadius determines how close the caster has to be to the target in order to cast the spell.

We want to make our spell a Touch spell. This means that the player will need to be in melee range of their target in order to cast it in the first place.

  • This field accepts numbers and decimals.
  • The field’s value is in metres.

For our new spell FireTouch, we will fill in 1.5 for the TargetRadius. This is the value used for melee range in Baldur’s Gate 3.

AreaRadius

The AreaRadius determines the area of effect (AoE) of the spell.

We want our spell to affect those around us, so we will need to fill in the AreaRadius field.

  • This field accepts numbers and decimals.
  • This field's value is in metres.

For our new spell, we will fill in 3. This means that the spell will affect everyone within 3m of the target.

Defining AoE in the AreaRadius column.

SpellRoll

All spells must have either SpellRoll or SpellProperties defined. In our case, we’ll use SpellRoll.

SpellRoll describes what type of spell it is. There are two common options used in BG3: SavingThrow() and Attack().

For our example, we'll make a SavingThrow type spell, which is one that requires the target to make a Saving Throw. To do so, we’ll paste the following into the SpellRoll field:

not SavingThrow(Ability.Dexterity, SourceSpellDC())

You can change the Ability.Dexterity part to be any ability type in the game (e.g. Ability.Charisma, Ability.Strength).

Because we’re making a SavingThrow type of spell, we will need to fill in the SpellSuccess and SpellFail fields. We’ll go into how to fill in both of these in the next sections.

  • SpellSuccess is for what happens when the caster succeeds, meaning the enemy has failed their Saving Throw.
  • SpellFail is for what happens when the caster fails, meaning the enemy has passed their Saving Throw.
    • The SpellFail field is optional and can be left blank.

SpellSuccess

Fill in the SpellSuccess field to define what happens when the caster succeeds. For our new spell, we want two things: we want to heal the caster, and we want to damage the target and any others in the area.

  • Use IF() statements to define what happens to each character.
  • To refer to the caster, use Self().
  • To refer to everyone except the caster, use not Self().

To heal the caster, we will use IF(Self()):RegainHitPoints(3d10)

  • RegainHitPoints() can take dice rolls (e.g. 3d10) or specific numbers (e.g. 9).

To damage the targets, since we want everyone else except for the caster to be damaged, we will use IF(not Self()):DealDamage(3d10,Fire,Magical)

  • DealDamage() can take dice rolls or specific numbers.
  • Fire indicates the damage type.
  • Magical indicates that it deals magical damage, for the sake of Resistance.
    • Because this is a spell, the damage is magical.

Separate each action with a ;. Put together, it looks like this:

The filled-in SpellSuccess field.

SpellFail

Fill in the SpellFail field to define what happens when the caster fails. We will do almost the same thing as we did for SpellSuccess, but for our new spell, we want to deal only half the healing and half the damage on fail. We can take what we wrote for SpellSuccess and modify it slightly by dividing the values by 2 using /2.

  • For healing: IF(Self()):RegainHitPoints(3d10/2) or IF(Self()):RegainHitPoints((3d10)/2)
  • For damage: IF(not Self()):DealDamage(3d10/2,Fire,Magical) or IF(not Self()):DealDamage((3d10)/2,Fire,Magical)

Again, separate each action with a ;. Put together, it looks like this:

The filled-in SpellFail field.

TargetConditions

TargetConditions filter out who the caster can cast the spell on. For example, if we input Self(), the player would would only be able to cast the spell on themselves.

Because we want the player to target any character that is alive, we will use: Character() and not Dead().

AoEConditions

If we want the AoE of this spell to affect a specific type of character, we can define the conditions in the AoEConditions field. For example, if we only want the AoE explosion to affect the enemies of the caster, we can write Enemy() here. Another valid option in this field is Ally().

In our new spell, FireTouch, we want everyone to be damaged, so we’ll use the same as TargetConditions.

The filled-in TargetConditions and AoEConditions fields.

Player-Facing Information

This next section of stats columns is all about filling the player-facing and tooltip information, so players can understand what the spell does.

Icon

In the Icon column, you can define an icon for the spell. For the purposes of this guide, let's reuse an existing spell icon from the Fireball spell: Spell_Evocation_Fireball.

Setting the spell icon in the Icon column.

DisplayName

The DisplayName is the spell name shown on the tooltip. Let’s call our new spell Touch of Fire.

The DisplayName as it appears on the in-game tooltip.

Description

The Description is the description of the spell that appears on the tooltip. Generally, you want to give players an idea of what the spell does.

Don't write any values (damage amounts, etc.) with numerals here. We cover where and how to fill in these values in the following sections.

For our spell, we will write: Touch an enemy with the force of a fireball. Everyone in the area will take [1] and the caster will be [2].

DescriptionParams

As you may have noticed, in the above description, we used [1] and [2]. These are filler spots for the description parameters – DescriptionParams.

In our spell’s tooltip description, we want to indicate that enemies take damage and the player is healed, so we will grab the same DealDamage() and RegainHitPoints() as we added to SpellSuccess.

We will plug them into the DescriptionParams in same order we want the tooltip to display them and separate them with a semicolon (;).

  • [1] should be DealDamage(3d10,Fire)
  • [2] should be RegainHitPoints(3d10)

So, in DescriptionParams, we’ll input DealDamage(3d10,Fire);RegainHitPoints(3d10).

Note that in this version of DealDamage() for the tooltip, Magical is not used.

The filled-in DescriptionParams field.

If done correctly, your tooltip for the spell should now have text that indicates the damage and healing given by the spell:

The spell description with functioning DescriptionParams.

TooltipDamageList and TooltipAttackSave

These are the last bits of the tooltip that we will be modifying for our spell.

TooltipDamageList gives the player a visually concise way to see the damage and healing effects of the spell. This will use the exact same functions as our DescriptionParams: DealDamage(3d10,Fire);RegainHitPoints(3d10).

TooltipAttackSave is used for Saving Throw spells to indicate what type of save it is. Our spell is a Dexterity-based save so we will put Dexterity in this field.

The filled-in TooltipDamageList and TooltipAttackSave fields.

With these fields filled in, your spell’s tooltip should now show the spell damage, including the dice visual, as well as the DEX Save at the bottom.

The TooltipDamageList and TooltipAttackSave elements functioning correctly in the tooltip.

CastTextEvent

Spells all need their CastTextEvent filled out. This is related to the animation that the caster is using – animations look for this cast event to in order to execute parts of the spell.

For our spell, we only want to execute one cast event, so we will just write Cast in this column.

If you forget to fill this out, your animation may have a delay instead of casting smoothly.

The filled-in CastTextEvent field.

UseCosts

The UseCosts field is used to determine the resources needed to cast the spell. Right now, there are no use costs associated with our spell.

Let’s say that we want FireTouch to cost one Action Point and one Level 3 Spell Slot.

  • ActionPoint:1
    • This means it will cost one Action Point.
  • SpellSlotsGroup:1:1:3
    • This means it will take one Level 3 Spell Slot to cast the spell.

Separate these with a semicolon (;).

If you have done this correctly, your tooltip will now show the cost of the spell as below:

The use costs of the spell functioning correctly.

Spell Animation

All spells need a Spell Animation in order to be used. Without a spell animation, the spell cannot be cast.

Let’s grab an existing animation and use it. In the Stats Editor, expand the Shared section on the left, then expand SpellData inside it.

Open the Target file inside SpellData by double-clicking on it.

Finding an existing spell animation in the Shared project.

We are looking for a Touch animation spell, so press Ctrl+F to open the search bar at the bottom and type in Touch. Press Enter to search.

Using the search function to find Touch spells.

You should see the area below the search bar update with the results, showing you all the spells in the Shared Target file that have the word "Touch" in them.

Let’s use the Vampiric Touch animations.

The search results for spells with "Touch" in them.

If you double-click on Vampiric Touch (any of the VampiricTouch results will do), it will take you to that row in the Target file. It should be row 179.

VampiricTouch located in the Target file.

Scroll over until you find the Spell Animation column (Column BL).

Click on the cell containing VampiricTouch’s Spell Animation data, and Ctrl+C to copy all the spell animation information.

Return to your mod's Target file and Ctrl+V to paste the copied spell animation information into FireTouch’s Spell Animation column. Your Spell Animation column should now look like this:

The filled-in Spell Animation column in your mod's Target file.

PrepareEffect, CastEffect, and HitEffect (VFX)

PrepareEffect, CastEffect, and HitEffect are how we apply visuals to our spells. All of these columns contain dropdowns that show the existing effects available in the game.

If you’d like to make your own effects, please refer to VFX – Part 1: Making Effects. For now, we’ll use some existing visuals.

PrepareEffect is the pre-casting effect of the spell, while you're "preparing" it. In the game, this is the period after you have selected a spell, but you haven't yet selected the target. For FireTouch, we want something fire-based, so let’s type fire into the dropdown to filter the results.

The PrepareEffect requires an effect that has the _PrepareEffect suffix, so let’s use Fireball_PrepareEffect.

The filled-in PrepareEffect field.

CastEffect is the visual on the caster while the spell is being executed. You might have noticed earlier that Fireball also has a cast effect, so let’s use that one here. Like with PrepareEffect, the CastEffect should have the _CastEffect suffix.

Fireball's CastEffect, HitEffect, and PrepareEffect showing up in the dropdown menu.

Finally, HitEffect is for the visual that plays on the target of the spell when it connects with them. Here, too, the effect should end in _HitEffect, and once again we’ll reuse the one for Fireball: Fireball_HitEffect.

The filled-in PrepareEffect, CastEffect, and HitEffect fields.

Now our spell should have visuals!

PrepareSound, PrepareLoopSound, and CastSound (SFX)

PrepareSound, PrepareLoopSound, and CastSound are how we apply sounds to our spells. Creating new sounds is not supported at this time, and therefore the best method is to look for a similar spell and copy its values to your new spell, much like we did for the VFX. For our FireTouch spell, we’ll copy the Firebolt sounds from Shared > Projectile:

Copying appropriate SFX values from the existing FireBolt spell.

Now our spell should have sound!

ⓘ If you want to hear sounds in the Editor without having to enter Game Mode, navigate to Options > Preferences > Global Settings > Mute Sound in Editor.

SpellFlag

Spell flags are used to give additional information on how the spell is expected to behave. These can vary from case to case. The dropdown in this field allows multiple options to be selected. For FireTouch, let’s select the following:

  • HasVerbalComponent: Spells with this flag will become unusable if the caster is Silenced.
  • HasSomaticComponent: Used for spells that require somatics in order to cast.
  • IsMelee: Used for attacks and/or spells that are within melee range.
  • IsSpell: Recommended for any spell that is meant to be considered a spell in D&D. Using this flag makes the spell work with other systems like Silencing, Counterspelling and Armor Proficiency requirements. Without this flag, your spell will show up as a "Class Action" on the tooltip if its spell level is 0.
  • IsHarmful: Lets the AI know whether or not to bring NPCs into combat. If the spell does damage, this should naturally happen, but if there’s a chance that the target could save and negate the damage, we want this flag there as well.
Setting basic spell flags.

A few other common flags that are not used in this example, but might be interesting:

  • IsConcentration: Used to make a spell into a Concentration spell.
  • IsAttack: Used for attacks that are not meant to be magical.
  • Temporary: Used to open the temporary section of the hotbar for spells that the player only has for a short time.

Testing Your Spell

Now, with all of these fields filled out, we can test the spell. To test the spell, we need to add it to one of the class spell lists so we can pick it during Character Creation or Level Up.

Open the UUID Object Editor and create a new SpellLists table in the Lists section of your mod:

Creating a new SpellLists table in the UUID Object Editor.

Also in the UUID Object Editor, go to Shared > Lists > SpellLists. Look through this existing SpellList for one that you’d like to modify. Remember that we made FireTouch a Level 3 spell, so you should choose a Level 3 spell list. For testing in this guide, we’ll use the Level 3 SpellList for Clerics:

The Level 3 spell list for clerics in the Shared project.

Copy the UUID field from the Shared SpellLists table and paste it into your mod’s SpellLists table:

The UUID from the Shared SpellLists table pasted into the SimpleNewSpell SpellLists table.

Repeat this copy-and-paste process for the Spells field. This is so we keep the original Cleric list intact. Add the tech name of your new spell at the end, separated by ;.

ⓘ The “tech name” we refer to here is SpellType_SpellName. In this case, the type is Target, and the spell name is FireTouch, so together it becomes Target_FireTouch.

You can leave the Comment field empty. This field is not used by the game in any way, and only serves as a note for developers.

Save all of your changes thus far.

To test, you’ll need to load a level, if you haven’t already. Basic_Level_A is sufficient. Once a level is loaded, enter Game Mode.

The console icon to enter Game Mode in the Editor.

With your cursor over the character portrait, press Ctrl+Shift+L to level them up. Click the Level Up button to enter the Level Up screen.

If your test character isn’t already a Cleric, add the Cleric class using the Multiclassing menu.

Adding a class on the Level Up screen.

Keep levelling up until you’re a Level 5 Cleric to get your Level 3 spell list. Once you've done this, go to the Spells tab. In the list of available spells, you should see the newly added spell: Touch of Fire. Once you pick it, you can use it in-game and check that all parts work as intended.

The new Touch of Fire spell appearing correctly in-game.

TargetRadius and HitRadius

Press Ctrl+Shift+3 to spawn in a wolf.

When casting the spell, there are two circles present on the ground. The smaller circle (highlighted green in screenshot below) is our TargetRadius of 1.5, and the larger circle (highlighted magenta) is our AreaRadius.

The TargetRadius and HitRadius working as intended.

PrepareEffect, CastEffect, HitEffect, and Spell Animation

When going to cast our spell, we should see a fire-based visual around our character. This is the PrepareEffect and the Spell Animation.

The PrepareEffect and Spell Animation working as intended.

When the character goes to cast the spell, we should see them step forward with a glow on their hand. This is the CastEffect and Spell Animation.

The CastEffect and Spell Animation working as intended.

When the spell is used on the wolf, we should see a fire effect. This is the HitEffect.

The HitEffect working as intended.

Combat Log

In this example, Shadowheart was the caster of the spell against a wolf. In the Combat Log, you can double-check the values of the spell: Our wolf enemy was dealt 7 Fire damage (3d10/2) and Shadowheart was healed 8 HP (3d10/2) because they both succeeded their saves.

The spell working as expected in the Combat Log.

Congratulations! You've made a basic spell.