Skip to content

spell

The spells of Magery: what a spell is, the spellbook, and casting.

Source: src/Moongate.Server.Ultima/Modules/SpellModule.cs

spell.add(book, spell_ref) -> boolean

Writes the spell, by number or key, in the spellbook, as a scroll dropped on it does, and shows the book again. False, with nothing changed, for an item that is no spellbook, an unknown spell or one the book holds already.

Writes a spell in a book, as a scroll dropped on it does; false when the book holds it already:

spell.add(book, "recall")
spell.add(book, 32)
ParameterTypeDefault
bookinteger
spell_refany

Returns boolean.

spell.can_cast_at(caster, spell_ref) -> boolean

Whether a cast of the spell, by number or key, would begin for the NPC now: the spell is known, enabled and has its script, and the NPC is alive, not casting, not frozen and has the mana of the spell. Nothing is said, spent or started, so a script may ask for each spell it can choose from. False for a player. The circle an NPC may use is the script's rule (npc.spell_circles), not asked here.

Whether spell.cast_at would begin now, with nothing said or spent; a script asks for each spell it may choose from and takes the first that answers true:

for _, key in ipairs({ "flame_strike", "fireball", "magic_arrow" }) do
if spell.can_cast_at(serial, key) then
spell.cast_at(serial, key, target)
break
end
end
ParameterTypeDefault
casterinteger
spell_refany

Returns boolean.

spell.can_use_from_afar(player, item) -> boolean

Whether the player could use the item from afar, as the Telekinesis spell does: it has an on_use in its script, or is a container the player carries or that lies on the ground, and a double click would not be refused (a bank that is not open, an inventory kept shut). False for a player or an item that is none, an NPC, or an item another mobile carries.

Whether Telekinesis may use an item, before anything is spent:

function telekinesis.check(caster, target, info)
if not spell.can_use_from_afar(caster, target.serial) then
return 501857 -- This spell won't work on that!
end
end
ParameterTypeDefault
playerinteger
iteminteger

Returns boolean.

spell.cancel(caster) -> boolean

Ends the cast of the mobile, if it has one, with no message, and takes its target cursor away. The recovery that the end of the delay already set stays, so a cancel at the cursor still leaves the short wait before the next cast.

Ends the cast with no message, such as when a player is teleported away. The short wait that the end of the delay set stays, so a cancel at the target cursor still leaves it:

spell.cancel(user)
ParameterTypeDefault
casterinteger

Returns boolean.

spell.cast(caster, spell_ref) -> boolean

Begins the cast of a spell, by number or key, as the player's own request does: it must have the spell in a spellbook it wears or carries in its backpack, and the usual checks tell it why not (dead, casting, frozen, not recovered, no mana). True when the cast began; then the words, the delay, the target cursor, the reagents, the mana and the skill check follow.

Begins the cast of a spell the mobile has in a book it carries, by key or by number; the usual checks tell it why not:

if spell.cast(user, "magic_arrow") then
-- the words, the delay and the target cursor follow
end
ParameterTypeDefault
casterinteger
spell_refany

Returns boolean.

spell.cast_at(caster, spell_ref, target?) -> boolean

Begins the cast of a spell, by number or key, for an NPC at the mobile with the serial target, as a creature of the classic game casts: no book, no scroll, no reagents and no words, the mana of the spell paid when it takes effect, a fizzle by its Magery, the delay of the circle with its gestures during which the NPC does not move, and no disturbance by damage. At the end of the delay the target is looked up again: out of the world, dead, hidden from a harmful spell, farther than 12 tiles or out of sight, the cast ends and spends nothing. target is left out for a spell that needs none. False for a player, a spell that is unknown, disabled or has no script, one that asks for an item, a target that is none, and any refusal of the cast (casting already, frozen, not enough mana).

What a creature’s script does to cast at who it fights: no book, no reagents and no words, the mana and the delay of the circle as for a player. The target is looked up again when the delay ends, so one that left, died, hid or got out of range or sight costs nothing:

if spell.can_cast_at(serial, "energy_bolt") then
spell.cast_at(serial, "energy_bolt", target)
end

A spell that needs no target leaves it out: spell.cast_at(serial, "create_food").

ParameterTypeDefault
casterinteger
spell_refany
target (optional)integer0

Returns boolean.

spell.cast_scroll(caster, scroll) -> boolean

Begins the cast of the spell of a scroll the mobile carries in its backpack, as a double click does: no reagents, a skill window two circles easier, and one scroll used up when it succeeds. True when the cast began; false for a mobile or an item that is none, or a scroll that is no spell.

What a double click on a scroll does, from the script of the scroll:

function spell_scroll.on_use(serial, user)
spell.cast_scroll(user, serial)
return true
end
ParameterTypeDefault
casterinteger
scrollinteger

Returns boolean.

spell.disturb(caster) -> boolean

Disturbs the cast of the mobile as damage does: a player's spell above the first circle, while its delay runs, is ruined (the player is told so and waits to cast again); nothing for a first circle spell, an NPC, a cast waiting for its target or a mobile that is not casting. A curse uses it on its target.

A curse may ruin the spell its target is casting, as damage does:

spell.disturb(target)
ParameterTypeDefault
casterinteger

Returns boolean.

spell.find_book(mobile, spell_ref) -> integer?

The serial of a spellbook the mobile wears or carries in its backpack (not in a bag inside it) that holds the spell, by number or key, the one a cast would use; nil when it has none, for an unknown spell or a mobile that is not in the world.

The spellbook a mobile wears or carries that holds a spell, as a cast would find it; nil when it has none:

local book = spell.find_book(user, "recall")
if not book then
mobile.message_cliloc(user, 1042404) -- You don't have that spell!
end
ParameterTypeDefault
mobileinteger
spell_refany

Returns integer?.

spell.has(book, spell_ref) -> boolean

Whether the spellbook holds the spell, by number or key. False for an item that is no spellbook.

if not spell.has(book, "heal") then
mobile.message(user, "Your book does not hold Heal.")
end
ParameterTypeDefault
bookinteger
spell_refany

Returns boolean.

spell.info(spell_ref) -> table?

What data/spells.toml says of a spell, by number or key, as a table: id, key, name, circle, mantra, mana, target ('none', 'mobile', 'item' or 'location'), harmful, resistable, reflectable, scroll (the template), enabled. Nil for an unknown spell.

What the data says of a spell:

local arrow = spell.info("magic_arrow")
mobile.message(user, arrow.name .. " costs " .. arrow.mana .. " mana")
ParameterTypeDefault
spell_refany

Returns table?.

spell.is_casting(caster) -> boolean

Whether the mobile is casting a spell, its delay running or its target cursor waiting.

if spell.is_casting(user) then
return false
end
ParameterTypeDefault
casterinteger

Returns boolean.

spell.of_scroll(scroll) -> integer?

The number of the spell a scroll item holds; nil for an item that is no scroll of a spell.

local id = spell.of_scroll(serial)
if id then
mobile.message(user, "A scroll of " .. spell.info(id).name)
end
ParameterTypeDefault
scrollinteger

Returns integer?.

spell.open_book(player, book) -> boolean

Opens a spellbook for a player, showing the spells it holds, as a double click does. The player must wear it or carry it in its backpack (and not in a bag inside it): else it is told so. False for a player, an item or a spellbook that is none, or a book not carried.

What a double click on a spellbook does:

function spellbook.on_use(serial, user)
spell.open_book(user, serial)
return true
end
ParameterTypeDefault
playerinteger
bookinteger

Returns boolean.

spell.spells(book) -> table?

The numbers of the spells the spellbook holds, in order, as a list; nil for an item that is no spellbook.

The numbers of the spells a book holds:

for _, id in ipairs(spell.spells(book)) do
log.info(spell.info(id).name)
end
ParameterTypeDefault
bookinteger

Returns table?.

spell.use_from_afar(player, item) -> boolean

Uses the item for the player as a double click would, but from any distance and with no reach check: the on_use of its script runs, or a container is shown open. True when something was done; false for a player or an item that is none, an NPC (it has no client to show a container to), or an item that cannot be used from afar.

Uses an item as a double click would, from any distance: its script’s on_use runs, or a container is shown open:

spell.use_from_afar(caster, target.serial)
ParameterTypeDefault
playerinteger
iteminteger

Returns boolean.

Made with ❤️ by Tom

Buy me a coffee