Creating a Spell

Make sure to read Creating an Item first, as this guide will assume you know how to do that.

The Basics


We're going to be creating Heal Prayer. We should get started with the basics:

local spell, super = Class(Spell, "heal_prayer")

function spell:init()
    super.init(self)
end

return spell

Looks simple enough so far!

Now, let's define some variables:

function spell:init()
    super.init(self)

    -- Display name
    self.name = "Heal Prayer"
    -- Name displayed when cast (optional)
    self.cast_name = nil

    -- Battle description
    self.effect = "Heal\nAlly"
    -- Menu description
    self.description = "Heavenly light restores a little HP to\none party member. Depends on Magic."

    -- TP cost
    self.cost = 32

    -- Target mode (ally, party, enemy, enemies, or none)
    self.target = "ally"

    -- Tags that apply to this spell
    self.tags = {"heal"}
end

And now let's make it actually do something:

function spell:onCast(user, target)
    target:heal(user.chara:getStat("magic") * 5)
end

Perfect!


What's a tag?

A tag is a way to categorize spells. For example, Snowgrave has "ice", "fatal" and "damage"!

World Spells


DELTARUNE has this scrapped mechanic which lets you cast spells while in the overworld. To use this, do the following:

function spell:hasWorldUsage(chara)
    return true
end

function spell:onWorldCast(chara)
    Game.world:heal(chara, 100)
end

Note, this requires a few config options to be set, to allow TP in the overworld!!

Advanced


Heal Prayer wasn't good enough? Okay, let's cover Snowgrave.

-- In the init function
    self.cost = 200

-- Outside of the init function
function spell:getTPCost(chara)
    local cost = super.getTPCost(self, chara)
    if chara and chara:checkWeapon("thornring") then
        cost = Utils.round(cost / 2)
    end
    return cost
end

This piece of code dynamically changes the TP cost, depending on if the character has the Thorn Ring equipped.

Now, let's see how the effect actually works:

function spell:onCast(user, target)
    local object = SnowGraveSpell(user)
    object.damage = self:getDamage(user, target)
    object.layer = BATTLE_LAYERS["above_ui"]
    Game.battle:addChild(object)

    return false
end

Wait... that's it? It just spawns another object? Interesting.

Spells don't have physical representations in the stage, so they need to spawn an object to do anything special.