9 new spells (+2 rituals required for choosing magic paths).
Planned spells: At least 2 more in these schools, plus eventually 1 each for the existing schools, and a new school with 4 spells.
Planned schools of magic: Shaman spell tree (based on staves) for a Minotaur mage, which uses HP to cast spells rather than mana, and gives combat bonuses only.
School types, all requirements should be somewhat higher than the elemental spell trees since these are more powerful:
Light Magic=Blessings, cost all available mana, gives bigger benefits the more mana spent. Part of the Staves skills.
Dark Magic=Curses, cost party HP, increasing with skill and effect. Part of the Staves skills.
I am aware that the spells might be unbalanced right now. Some thought has gone into balancing them, but I need your help to test and give input. I plan to expand this as a complete magic expansion, feel free to add suggestions. Many scripts can be streamlined, new icons/textures included. All this will be added in the next release. Bugs might still be in there. Feel free to use the code as you like, give credit if you're nice
Put this in spells.lua (inludes needed non-spell entities such as two wands and light-entities):
Code: Select all
cloneObject{
name = "wand_of_darkness",
baseObject = "whitewood_wand",
uiName = "Wand of Darkness",
description = "A wand that channels the forces of death and darkness necessary for Dark Magic.",
}
cloneObject{
name = "wand_of_light",
baseObject = "whitewood_wand",
uiName = "Wand of Light",
description = "A wand that channels the forces of life and light necessary for Light Magic.",
}
defineSpell{
name = "curse",
uiName = "Caliginous Curse",
skill = "staves",
level = 16,
runes = "DEH",
manaCost = 10,
onCast = function(champ, x, y, direction, skill)
if champ:getItem(7) ~= nil and champ:getItem(7).name == "wand_of_darkness" or champ:getItem(8) ~= nil and champ:getItem(8).name == "wand_of_darkness" then
hudPrint(champ:getName().." pulls life force to strengthen the spell")
damageTile(party.level, party.x, party.y, party.facing, 1, "physical", (5+(skill/2)))
spawn("curseburst", party.level, party.x, party.y-1, party.facing)
spawn("curseburst", party.level, party.x+1, party.y, party.facing)
spawn("curseburst", party.level, party.x, party.y+1, party.facing)
spawn("curseburst", party.level, party.x-1, party.y, party.facing)
damageTile(party.level, party.x, party.y-1, party.facing, 188, "physical", math.random(1,10)*(skill*2))
damageTile(party.level, party.x-1, party.y, party.facing, 188, "physical", math.random(1,10)*(skill*2))
damageTile(party.level, party.x, party.y+1, party.facing, 188, "physical", math.random(1,10)*(skill*2))
damageTile(party.level, party.x+1, party.y, party.facing, 188, "physical", math.random(1,10)*(skill*2))
party:playScreenEffect("party_crush")
else
hudPrint("You are not schooled in the Dark Arts")
return false
end
end,
}
----SUMMON DARKNESS
defineSpell{
name = "cursedark",
uiName = "Summon Darkness",
skill = "staves",
level = 20,
runes = "CDEH",
manaCost = 10,
onCast = function(champ, x, y, direction, skill)
if champ:getItem(7) ~= nil and champ:getItem(7).name == "wand_of_darkness" or champ:getItem(8) ~= nil and champ:getItem(8).name == "wand_of_darkness" then
spawn("darkburst", party.level, party.x, party.y, party.facing)
damageTile(party.level, party.x, party.y, party.facing, 1, "physical", (5+(skill/2)))
for slot=1,4 do
if party:getChampion(slot) ~= nil then
party:getChampion(slot):setCondition("invisibility", skill);
end
end
else
hudPrint("You are not schooled in the Dark Arts")
return false
end
end
}
---RITUAL OF LIGHT
defineSpell{
name = "lritual",
uiName = "Ritual of Light",
skill = "spellcraft",
level = 1,
runes = "ABCEGI",
manaCost = 5,
onCast = function(casty)
if casty:getItem(8) ~= nil then
if casty:getItem(8).name == "whitewood_wand" then
casty:removeItem(8)
casty:insertItem(8,spawn("wand_of_light"))
playSound("generic_spell")
hudPrint("You have chosen Light as your guide")
end
elseif casty:getItem(7) ~= nil then
if casty:getItem(7).name == "whitewood_wand" then
casty:removeItem(7)
casty:insertItem(7,spawn("wand_of_light"))
playSound("generic_spell")
hudPrint("You have chosen Light as your guide")
else hudPrint("You have to cast Ritual of Light while holding a whitewood wand")
end
else
hudPrint("You have to cast Ritual of Light while holding a whitewood wand")
return false
end
end,
}
----RITUAL OF DARKNESS
defineSpell{
name = "Dritual",
uiName = "Ritual of Darkness",
skill = "spellcraft",
level = 1,
runes = "ACEGHI",
manaCost = 5,
onCast = function(casty)
if casty:getItem(8) ~= nil then
if casty:getItem(8).name == "whitewood_wand" then
casty:removeItem(8)
casty:insertItem(8,spawn("wand_of_darkness"))
playSound("generic_spell")
hudPrint("You have chosen the Dark Arts as your path")
end
elseif casty:getItem(7) ~= nil then
if casty:getItem(7).name == "whitewood_wand" then
casty:removeItem(7)
casty:insertItem(7,spawn("wand_of_darkness"))
playSound("generic_spell")
hudPrint("You have chosen the Dark Arts as your path")
else hudPrint("You have to cast Ritual of Darkness while holding a whitewood wand")
end
else
hudPrint("You have to cast Ritual of Darkness while holding a whitewood wand")
return false
end
end,
}
----VENGEFUL CURSE
defineSpell{
name = "curserage",
uiName = "Vengeful Curse",
skill = "staves",
level = 8,
runes = "AEH",
manaCost = 10,
onCast = function(champ, x, y, direction, skill)
if champ:getItem(7) ~= nil and champ:getItem(7).name == "wand_of_darkness" or champ:getItem(8) ~= nil and champ:getItem(8).name == "wand_of_darkness" then
damageTile(party.level, party.x, party.y, party.facing, 1, "physical", (5+(skill/2)))
for slot=1,4 do
if party:getChampion(slot) ~= nil then
party:getChampion(slot):setCondition("rage", skill);
end
end
else
hudPrint("You are not schooled in the Dark Arts")
return false
end
end
}
----HOLY VIGOR
defineSpell{
name = "holyvigor",
uiName = "Holy Vigor",
skill = "staves",
level = 12,
runes = "BCE",
manaCost = 10,
onCast = function(champ, x, y, direction, skill)
if champ:getItem(7) ~= nil and champ:getItem(7).name == "wand_of_light" or champ:getItem(8) ~= nil and champ:getItem(8).name == "wand_of_light" then
local cenergy = champ:getStat("energy")
champ:modifyStat("energy", -200)
for slot=1,4 do
if party:getChampion(slot) ~= nil then
party:getChampion(slot):setCondition("haste", cenergy);
end
end
else hudPrint("You are not a true follower of the Light")
return false
end
end
}
-----CALM MONSTER
defineSpell{
name = "Calm",
uiName = "Calm",
skill = "staves",
level = 16,
runes = "BEF",
manaCost = 25,
onCast = function(champ)
if champ:getItem(7) ~= nil and champ:getItem(7).name == "wand_of_light" or champ:getItem(8) ~= nil and champ:getItem(8).name == "wand_of_light" then
return flatlines_script.calmmonster(champ)
else hudPrint("You are not a true follower of the Light")
return false
end
end,
}
--- ARROWSHIELD v2
cloneObject{
name = "party",
baseObject = "party",
onProjectileHit = function()
return flatlines_script.arrowshieldcheck()
end
}
defineSpell{
name = "RROWTest",
uiName = "Arrow Shield",
skill = "staves",
level = 22,
runes = "ABGH",
manaCost = 1,
onCast = function(champ, skill)
if champ:getItem(7) ~= nil and champ:getItem(7).name == "wand_of_light" or champ:getItem(8) ~= nil and champ:getItem(8).name == "wand_of_light" then
if findEntity("arrowshieldobj") ~= nil then
findEntity("arrowshieldobj"):destroy()
end
currenergy = champ:getStat("energy")
champ:modifyStat("energy", -200)
playSound("generic_spell")
spawn("timer", party.level, party.x, party.y, party.facing, "arrowshieldobj")
:addConnector("activate", "flatlines_script", "resetarrowshield")
:setTimerInterval(currenergy*2)
:activate()
else hudPrint("You are not a true follower of the Light")
return false
end
end,
}
defineParticleSystem{
name = "arrowshielded",
emitters = {
-- fog
{
spawnBurst=true,
emissionRate = 1,
emissionTime = 0,
maxParticles = 1,
boxMin = {0, 0,0},
boxMax = { 0, 0, 0},
sprayAngle = {0,360},
velocity = {10,10},
objectSpace = true,
texture = "assets/textures/particles/glow.tga",
lifetime = {0.3,0.3},
colorAnimation = true,
color0 = {10, 10, 10},
color1 = {2, 0.352941, 0.803922},
opacity = 0.02,
fadeIn = 0,
fadeOut = 0.05,
size = {22, 22},
gravity = {0,0,0},
airResistance = 0.1,
rotationSpeed = 0,
blendMode = "Additive",
},
}
}
---- MANASHIELD
defineSpell{
name = "ManaShield",
uiName = "Mana Shield",
skill = "spellcraft",
level = 18,
runes = "BDEF",
manaCost = 1,
onCast = function(champ)
return flatlines_script.manashield(champ)
end,
}
defineParticleSystem{
name = "manashielded",
emitters = {
-- fog
{
emissionRate = 10,
emissionTime = 40,
maxParticles = 1000,
boxMin = {-0.5, 0.0,-0.5},
boxMax = { 0.5, 2.5, 0.5},
sprayAngle = {0,360},
velocity = {0.1,0.2},
objectSpace = true,
texture = "assets/textures/particles/fog.tga",
lifetime = {3,3},
color0 = {0.152941, 0.352941, 0.803922},
opacity = 0.5,
fadeIn = 2.2,
fadeOut = 2.2,
size = {1.5, 1.5},
gravity = {0,0,0},
airResistance = 0.1,
rotationSpeed = 0.3,
blendMode = "Additive",
},
-- stars
{
emissionRate = 200,
emissionTime = 40,
maxParticles = 1000,
boxMin = {-0.6, 0.3,-0.6},
boxMax = { 0.6, 2.5, 0.6},
sprayAngle = {0,360},
velocity = {0.2,0.2},
objectSpace = true,
texture = "assets/textures/particles/teleporter.tga",
lifetime = {3,3},
color0 = {3.0,3.0,3.0},
opacity = 1,
fadeIn = 0.1,
fadeOut = 0.1,
size = {0.05, 0.13},
gravity = {0,0,0},
airResistance = 0.1,
rotationSpeed = 2,
blendMode = "Additive",
}
}
}
----TELEPORT
defineSpell{
name = "portal",
uiName = "Portal",
skill = "spellcraft",
level = 40,
runes = "BDFH",
manaCost = 70,
onCast = function()
return flatlines_script.telly()
end
}
---DETECT MONSTER
defineSpell{
name = "DetectMonster",
uiName = "Detect Monster",
skill = "spellcraft",
level = 8,
runes = "BFG",
manaCost = 13,
onCast = function(champ)
return flatlines_script.detectmonster(champ)
end,
}
defineParticleSystem{
name = "DetectMonster",
emitters = {
-- glow
{
emissionRate = 1,
emissionTime = 0,
spawnBurst = true,
maxParticles = 1,
boxMin = {0,0,0},
boxMax = {0,0,0},
sprayAngle = {0,0},
velocity = {0,0},
texture = "assets/textures/particles/glitter_silver.tga",
lifetime = {10, 10},
colorAnimation = false,
color0 = {1, 0.1, 0.1},
-- color1 = {0.1, 1, 0.1},
-- color2 = {0.1, 0.1, 1},
opacity = 1,
fadeIn = 1,
fadeOut = 1,
size = {3, 3},
gravity = {0,0,0},
airResistance = 1,
rotationSpeed = 1,
blendMode = "Additive",
depthBias = -10,
}
}
}
---NEEDED FOR CALIGINOUS CURSE
defineObject{
name = "curseburst",
class = "ProjectileSpell",
lightColor = vec(0.5, 0.5, 0.5),
particleSystem = "curse_fireP",
hitParticleEffect = "curse_fireP",
lightPosition = vec(0, 0, 0),
lightBrightness = 1000,
lightRange = 3,
castShadow = true,
hitSound = "poison_cloud",
launchSound = "poison_cloud",
lightHitBrightness = -1000,
lightHitRange = 5,
projectileSound = "poison_cloud",
attackPower = 0,
damageType = "physical",
projectileSpeed = 100000,
--cameraShake = true,
tags = { "spell" },
}
defineObject{
name = "darkburst",
class = "ProjectileSpell",
lightColor = vec(0, 0, 0),
particleSystem = "dark_fireP",
hitParticleEffect = "dark_fireP",
lightPosition = vec(0, 0, 0),
lightBrightness = -1000,
lightRange = 30,
castShadow = true,
hitSound = "poison_cloud",
launchSound = "poison_cloud",
lightHitBrightness = -1000,
lightHitRange = 30,
projectileSound = "poison_cloud",
attackPower = 0,
damageType = "physical",
projectileSpeed = 0,
--cameraShake = true,
tags = { "spell" },
}
defineParticleSystem{
name = "curse_fireP",
emitters = {
-- glow}
{
spawnBurst = false,
emissionRate = 0,
emissionTime = 0,
maxParticles = 0,
boxMin = {0,0,-0.1},
boxMax = {0,0,-0.1},
sprayAngle = {30,45},
velocity = {3,3},
texture = "assets/textures/particles/glow.tga",
lifetime = {5, 5},
colorAnimation = false,
color0 = {0.5, 0.5, 0.5},
opacity = 0.1,
fadeIn = 0,
fadeOut = 2,
size = {0, 0},
gravity = {0,-4,0},
airResistance = 0,
rotationSpeed = 2,
blendMode = "Translucent",
depthBias = -0.002,
}
}
}
defineParticleSystem{
name = "dark_fireP",
emitters = {
-- glow}
{
spawnBurst = false,
emissionRate = 40,
emissionTime = 0,
maxParticles = 100,
boxMin = {-20,0,-20},
boxMax = {20,0,20},
sprayAngle = {0,360},
velocity = {1,1},
texture = "assets/textures/particles/glow.tga",
lifetime = {25, 35},
colorAnimation = false,
color0 = {0, 0, 0},
opacity = 1,
fadeIn = 5,
fadeOut = 5,
size = {100, 100},
gravity = {0,0,0},
airResistance = 2,
rotationSpeed = 1,
blendMode = "Translucent",
depthBias = -0.002,
}
}
}
flatlines_script (name a in-game Lua script flatlines_script and paste this)
Code: Select all
--arrowshield
function arrowshieldcheck(Champ)
if findEntity("arrowshieldobj") == nil then
return true
else
for p = 1,4 do
if party:getChampion(p):getSkillLevel("spellcraft") ~=nil then
if math.random(1, 50) <= party:getChampion(p):getSkillLevel("spellcraft") then
party:playScreenEffect("arrowshielded")
playSound("swipe_bow")
return false
end
else
return true
end
end
end
end
function resetarrowshield()
if findEntity("arrowshieldobj") ~= nil then
findEntity("arrowshieldobj"):destroy()
playSound("generic_spell")
end
end
--teleport
function telly()
if findEntity("Telly1") ~=nil then
spawn("teleporter", party.level, party.x, party.y, party.facing, "Telly2")
:setTeleportTarget(Telly1.x, Telly1.y, party.facing)
:setTriggeredByParty(true)
:setTriggeredByMonster(false)
:setTriggeredByItem(false)
:setChangeFacing(false)
:setInvisible(false)
:setSilent(true)
:setHideLight(true)
:setScreenFlash(false)
:activate()
spawn("timer", party.level, party.x, party.y, party.facing, "Telly1_timer")
:setTimerInterval(0.1)
:addConnector("activate", "flatlines_script", "Telly1Destroy")
:activate()
hudPrint("Marked A")
elseif findEntity("Telly2") ~=nil then
spawn("teleporter", party.level, party.x, party.y, party.facing, "Telly1")
:setTeleportTarget(Telly2.x, Telly2.y, party.facing)
:setTriggeredByParty(true)
:setTriggeredByMonster(false)
:setTriggeredByItem(false)
:setChangeFacing(false)
:setInvisible(false)
:setSilent(true)
:setHideLight(true)
:setScreenFlash(false)
:activate()
spawn("timer", party.level, party.x, party.y, party.facing, "Telly2_timer")
:setTimerInterval(0.1)
:addConnector("activate", "flatlines_script", "Telly2Destroy")
:activate()
hudPrint("Marked B")
else
spawn("teleporter", party.level, party.x, party.y, party.facing, "Telly1")
:setTeleportTarget(party.x, party.y, party.facing)
:setTriggeredByParty(false)
:setTriggeredByMonster(false)
:setTriggeredByItem(false)
:setChangeFacing(false)
:setInvisible(false)
:setSilent(true)
:setHideLight(true)
:setScreenFlash(false)
hudPrint("Marked A 1")
end
return true
end
function Telly1Destroy()
Telly1:destroy()
Telly1_timer:destroy()
end
function Telly2Destroy()
Telly2:destroy()
Telly2_timer:destroy()
end
--Manashield
-- set initial base_energy value (this variable used for 'resetting' the protection)
base_energy = 0
-- modify protection value
function modifyProtection(modifier)
for slot=1,4 do
if party:getChampion(slot) ~= nil then
party:getChampion(slot):modifyStatCapacity("protection", modifier)
party:getChampion(slot):modifyStat("protection", modifier)
-- hudPrint("max protection " .. tostring(party:getChampion(slot):getStatMax("protection")))
end
end
end
-- check for and destroy mana timer
function checkManaTimer()
local mana_timer_entity = findEntity("manaShieldTimer")
if mana_timer_entity ~= nil then
mana_timer_entity:destroy()
end
end
-- cast mana shield code
function manashield(Champ)
checkManaTimer()
base_energy = Champ:getStat("energy")
hudPrint("The mana shield strengthens armor by " .. base_energy)
-- hudPrint("base energy = " .. tostring(base_energy))
spawn("timer",party.level,0,0,0,"manaShieldTimer")
:addConnector("activate", "flatlines_script", "resetProtection")
:setTimerInterval(40)
:activate()
Champ:setStat("energy", 0)
party:playScreenEffect("manashielded")
modifyProtection(base_energy)
end
function resetProtection()
modifyProtection(-base_energy)
checkManaTimer()
end
--Calm monster
function calmmonster()
local monsters = findAllCalm(party.level, party.x, party.y, {":setAIState"}, "all", false, false, false)
for _, monster in ipairs(monsters) do
monster:setAIState("guard")
end
end
function findAllCalm(level, x, y, keys, all, surrounding, facing, facingUs)
local answers, r, dx, dy, entity, match, _ = {}, 0
all = all == "all"
local any = not all
if surrounding then r = 1 end
if facing then
dx, dy = getForward(self.facing)
x, y = x + dx, y + dy
end
if keys == nil then keys = {"*"} end
for entity in allEntities(party.level) do
match = true
for _, value in ipairs(keys) do
if value == "*" then pass = true
elseif string.sub(value, 1, 1) == ":" then pass = entity[(string.sub(value, 2))] ~= nil
else pass = string.find(entity.name, value) ~= nil end
if all then match = pass and match
else match = pass end
if (match and any) or ((not match) and all) then break end
end
if match then
dx, dy = getForward(entity.facing)
if (not facingUs) or (facingUs and entity.x + dx == self.x and entity.y + dy == self.y) or (self.x == entity.x and self.y == entity.y) then
answers[# answers + 1] = entity
end
end
end
return answers
end
--Detect Monster
function detectmonster()
local monsters = findAllDetect(party.level, party.x, party.y, {":setAIState"}, "all", false, false, false)
for _, monster in ipairs(monsters) do
spawn("fx", monster.level, monster.x, monster.y, monster.facing)
:setParticleSystem("DetectMonster")
:translate(0, 2, 0)
end
playSound("generic_spell")
end
function findAllDetect(level, x, y, keys, all, surrounding, facing, facingUs)
local answers, r, dx, dy, entity, match, _ = {}, 0
all = all == "all"
local any = not all
if surrounding then r = 1 end
if facing then
dx, dy = getForward(self.facing)
x, y = x + dx, y + dy
end
if keys == nil then keys = {"*"} end
for entity in allEntities(party.level) do
match = true
for _, value in ipairs(keys) do
if value == "*" then pass = true
elseif string.sub(value, 1, 1) == ":" then pass = entity[(string.sub(value, 2))] ~= nil
else pass = string.find(entity.name, value) ~= nil end
if all then match = pass and match
else match = pass end
if (match and any) or ((not match) and all) then break end
end
if match then
dx, dy = getForward(entity.facing)
if (not facingUs) or (facingUs and entity.x + dx == self.x and entity.y + dy == self.y) or (self.x == entity.x and self.y == entity.y) then
answers[# answers + 1] = entity
end
end
end
return answers
end