Custom spells + monster attacking = Crash!! HELP PLS!!
Posted: Sat Jan 04, 2014 4:02 am
Hello there!!
I have a situation here - if my champ casts a custom projectile spell AND there is a monster in front of the party attacking at the same time - the game crashes!!
I noticed this while play testing Labyrinth of Lies... and have tried to replicate the crash in the editor - which was successful.
However, only some monsters (when attacking) would cause the editor to crash out of the preview...
I tried (using Magic Arrow and Blades) against crabs, spiders, wyverns, ogres, tentacles, scavengers, Leki's Ghoul and crowerns.
Only Tentacles, Spiders and Crowerns would cause the crash... and I may be way off on this, but they are monsters that seem to move themselves into the party's square when melee attacking....???
This is the error message I get...
I am assuming it is talking about the 'node' of the monster that is attacking???
I will post some of the coding that is involved, hopefully someone can see what I can't
The spells... Magic Arrow
and Blades....
In monsters.lua I have an onProjectileHitHook....
that calls a function in the same script as the custom spells....
So that is all pretty simple... what I think is causing the problem is the script that adds the effects to the spells. This script is not my work (it was written by ....... for the spells Wizards Fire and Wizards Life Fire) and admittedly is way beyond me in terms of complexity
This is it....
Unfortunately I do not get any help from the editor when it crashes back to preview.
Any help at all would be appreciated!!
Akroma
I have a situation here - if my champ casts a custom projectile spell AND there is a monster in front of the party attacking at the same time - the game crashes!!
I noticed this while play testing Labyrinth of Lies... and have tried to replicate the crash in the editor - which was successful.
However, only some monsters (when attacking) would cause the editor to crash out of the preview...
I tried (using Magic Arrow and Blades) against crabs, spiders, wyverns, ogres, tentacles, scavengers, Leki's Ghoul and crowerns.
Only Tentacles, Spiders and Crowerns would cause the crash... and I may be way off on this, but they are monsters that seem to move themselves into the party's square when melee attacking....???
This is the error message I get...
SpoilerShow
#fxScripts:86: attempt to index field 'node' (a nil value)
stack traceback:
[C]: in function 'error'
[string "ScriptInterface.lua"]: in function 'setParticleSystem'
#fxScripts:86: in function <#fxScripts:78>
[string "ScriptEntity.lua"]: in function 'onMessageReceived'
[string "MessageSystem.lua"]: in function 'sendMessageToEntity'
[string "MessageSystem.lua"]: in function 'broadcastMessage'
[string "TriggerEvents.lua"]: in function 'fire'
[string "Timer.lua"]: in function 'update'
[string "Map.lua"]: in function 'updateEntities'
[string "Dungeon.lua"]: in function 'updateLevels'
[string "GameMode.lua"]: in function 'update'
[string "Grimrock.lua"]: in function 'display'
[string "Grimrock.lua"]: in main chunk
stack traceback:
[C]: in function 'error'
[string "ScriptInterface.lua"]: in function 'setParticleSystem'
#fxScripts:86: in function <#fxScripts:78>
[string "ScriptEntity.lua"]: in function 'onMessageReceived'
[string "MessageSystem.lua"]: in function 'sendMessageToEntity'
[string "MessageSystem.lua"]: in function 'broadcastMessage'
[string "TriggerEvents.lua"]: in function 'fire'
[string "Timer.lua"]: in function 'update'
[string "Map.lua"]: in function 'updateEntities'
[string "Dungeon.lua"]: in function 'updateLevels'
[string "GameMode.lua"]: in function 'update'
[string "Grimrock.lua"]: in function 'display'
[string "Grimrock.lua"]: in main chunk
I will post some of the coding that is involved, hopefully someone can see what I can't
The spells... Magic Arrow
SpoilerShow
spellCaster = 0
function castMagicArrow(caster, x, y, direction, skill)
local dx,dy = getForward(party.facing)
local e = caster:getStat("energy")
local c = findEntity("learnPrismicMissileCounter")
if skill >= 26 then
shootProjectile("prismic_arrow", party.level, party.x,party.y, direction, 22, 0, 0, 0, 0, 0, 3*skill, party, true, originator)
playSound("magic_arrow")
if c and c:getValue() == 0 then
hudPrint("Magic Arrow has upgraded (skill 26) to a new spell: Prismic Missile!")
playSound("upgrade_spell")
c:destroy()
end
else
if (caster:getItem(7) ~= nil and caster:getItem(7).name == "magic_sphere") or (caster:getItem(8) ~= nil and caster:getItem(8).name == "magic_sphere") then
playSound("magic_arrow")
shootProjectile("prismic_arrow", party.level, party.x,party.y, direction, 22, 0, 0, 0, 0, 0, 3*skill, party, true, originator)
else
playSound("magic_arrow")
shootProjectile("magic_arrow", party.level, party.x,party.y, direction, 16, 0, 0, 0, 0, 0, math.random(20,30), party, true, originator)
end
end
for ent in entitiesAt(party.level, party.x, party.y) do
if ent.name == "magic_arrow" then
fxScripts.addProjectileEffect(ent, "magic_arrow", 20, "magic_arrow_hit")
end
if ent.name == "prismic_arrow" then
fxScripts.addProjectileEffect(ent, "prismic_arrow", 20, "prismic_arrow_hit")
end
end
spellCaster = caster:getOrdinal()
return true
end
function castMagicArrow(caster, x, y, direction, skill)
local dx,dy = getForward(party.facing)
local e = caster:getStat("energy")
local c = findEntity("learnPrismicMissileCounter")
if skill >= 26 then
shootProjectile("prismic_arrow", party.level, party.x,party.y, direction, 22, 0, 0, 0, 0, 0, 3*skill, party, true, originator)
playSound("magic_arrow")
if c and c:getValue() == 0 then
hudPrint("Magic Arrow has upgraded (skill 26) to a new spell: Prismic Missile!")
playSound("upgrade_spell")
c:destroy()
end
else
if (caster:getItem(7) ~= nil and caster:getItem(7).name == "magic_sphere") or (caster:getItem(8) ~= nil and caster:getItem(8).name == "magic_sphere") then
playSound("magic_arrow")
shootProjectile("prismic_arrow", party.level, party.x,party.y, direction, 22, 0, 0, 0, 0, 0, 3*skill, party, true, originator)
else
playSound("magic_arrow")
shootProjectile("magic_arrow", party.level, party.x,party.y, direction, 16, 0, 0, 0, 0, 0, math.random(20,30), party, true, originator)
end
end
for ent in entitiesAt(party.level, party.x, party.y) do
if ent.name == "magic_arrow" then
fxScripts.addProjectileEffect(ent, "magic_arrow", 20, "magic_arrow_hit")
end
if ent.name == "prismic_arrow" then
fxScripts.addProjectileEffect(ent, "prismic_arrow", 20, "prismic_arrow_hit")
end
end
spellCaster = caster:getOrdinal()
return true
end
SpoilerShow
function castBlades(caster,x,y,direction,skill)
local dx,dy = getForward(party.facing)
local x,y = party.x + dx, party.y + dy
local originator = caster:getOrdinal()
local e = caster:getSkillLevel("earth_magic")
local c = findEntity("learnShrapnelBlastCounter")
playSound("blades_gear")
if e >= 40 then
if party.facing == 0 or party.facing == 2 then
for modif = -0.5,0.5,0.1 do
shootProjectile("blade_gear", party.level, x+modif, y, party.facing, 14+(modif*2), 0, 1, 0, 0, 0, 35, party, true, originator)
end
else
for modif = -0.5,0.5,0.1 do
shootProjectile("blade_gear", party.level, x, y+modif, party.facing, 14+(modif*2), 0, 1, 0, 0, 0, 35, party, true, originator)
end
end
for ent in entitiesAt(party.level, party.x, party.y) do
if ent.name == "blade_gear" then
fxScripts.addProjectileEffect(ent, "blades_knife", 9, "hit_flame")
end
end
if c and c:getValue() == 0 then
hudPrint("Blades has upgraded (Earth 40) to a new spell: Shapnel Blast!")
playSound("upgrade_spell")
c:destroy()
end
else
if party.facing == 0 or party.facing == 2 then
for modif = -0.5,0.5,0.1 do
shootProjectile("blade_knife", party.level, x+modif, y, party.facing, 14+(modif*2), 0, 1, 0, 0, 0, 15, party, true, originator)
end
else
for modif = -0.5,0.5,0.1 do
shootProjectile("blade_knife", party.level, x, y+modif, party.facing, 14+(modif*2), 0, 1, 0, 0, 0, 15, party, true, originator)
end
end
for ent in entitiesAt(party.level, party.x, party.y) do
if ent.name == "blade_knife" then
fxScripts.addProjectileEffect(ent, "blades_knife", 9, "hit_flame")
end
end
end
spellCaster = caster:getOrdinal()
return true
end
local dx,dy = getForward(party.facing)
local x,y = party.x + dx, party.y + dy
local originator = caster:getOrdinal()
local e = caster:getSkillLevel("earth_magic")
local c = findEntity("learnShrapnelBlastCounter")
playSound("blades_gear")
if e >= 40 then
if party.facing == 0 or party.facing == 2 then
for modif = -0.5,0.5,0.1 do
shootProjectile("blade_gear", party.level, x+modif, y, party.facing, 14+(modif*2), 0, 1, 0, 0, 0, 35, party, true, originator)
end
else
for modif = -0.5,0.5,0.1 do
shootProjectile("blade_gear", party.level, x, y+modif, party.facing, 14+(modif*2), 0, 1, 0, 0, 0, 35, party, true, originator)
end
end
for ent in entitiesAt(party.level, party.x, party.y) do
if ent.name == "blade_gear" then
fxScripts.addProjectileEffect(ent, "blades_knife", 9, "hit_flame")
end
end
if c and c:getValue() == 0 then
hudPrint("Blades has upgraded (Earth 40) to a new spell: Shapnel Blast!")
playSound("upgrade_spell")
c:destroy()
end
else
if party.facing == 0 or party.facing == 2 then
for modif = -0.5,0.5,0.1 do
shootProjectile("blade_knife", party.level, x+modif, y, party.facing, 14+(modif*2), 0, 1, 0, 0, 0, 15, party, true, originator)
end
else
for modif = -0.5,0.5,0.1 do
shootProjectile("blade_knife", party.level, x, y+modif, party.facing, 14+(modif*2), 0, 1, 0, 0, 0, 15, party, true, originator)
end
end
for ent in entitiesAt(party.level, party.x, party.y) do
if ent.name == "blade_knife" then
fxScripts.addProjectileEffect(ent, "blades_knife", 9, "hit_flame")
end
end
end
spellCaster = caster:getOrdinal()
return true
end
SpoilerShow
for i=1,# allMonstersList do
cloneObject{
name = allMonstersList,
baseObject = allMonstersList,
onProjectileHit = function(monster, projectile, damage, damageType)
return mymod_spells.customSpellOnProjectileHitHook(monster,projectile,damage, damageType)
end,
}
end
cloneObject{
name = allMonstersList,
baseObject = allMonstersList,
onProjectileHit = function(monster, projectile, damage, damageType)
return mymod_spells.customSpellOnProjectileHitHook(monster,projectile,damage, damageType)
end,
}
end
that calls a function in the same script as the custom spells....
SpoilerShow
projectileItems = {'blade_knife' , 'blade_gear' , 'light_missile' , 'arcane_missile' , 'venomstone_exploder' , 'venomstone_shot' ,
'dark_missile' , 'dread_missile' , 'ghost_flame' , 'cleansing_flame' , 'whipping_rock' , 'blazing_rock' ,
'iceflame_bolt' , 'iceflame_torrent' , 'iceflame_torrent_dire' , 'wizards_fire_ball' , 'magic_arrow' ,
'prismic_arrow' ,'boulder_rolling' , 'returning_throwing_axe' , 'recurring_nightmare' , 'crystal_shard' ,
'soul_orb_bomb' , 'cool_stone' , 'pyre_stone' , 'mind_stone' , 'tooth_lizard' , 'boom_rock' , 'death_star'}
function isInTable(table, element)
for _,value in pairs(table) do
if value == element then
return true
end
end
return false
end
function customSpellOnProjectileHitHook(monster,projectile,damage,damageType)
local dx,dy = getForward(monster.facing)
if isInTable(projectileItems, projectile.name) then
if projectile.name == 'magic_arrow' then
local originator = 2 ^ (spellCaster+1) -- calculate the originator of the spell
local damage = math.random(15,30)--
damageTile(monster.level,monster.x,monster.y,(monster.facing + 2)%4,originator+1, 'physical',damage)
playSound("prismic_missile_hit")
return false
elseif projectile.name == 'blade_knife' then
local originator = 2 ^ (spellCaster+1) -- calculate the originator of the spell
local damage = math.random(15,20) --
damageTile(monster.level,monster.x,monster.y,(monster.facing + 2)%4,originator+1, 'physical',damage)
playSoundAt("impact_blade",monster.level,monster.x,monster.y)
return false
end
end
'dark_missile' , 'dread_missile' , 'ghost_flame' , 'cleansing_flame' , 'whipping_rock' , 'blazing_rock' ,
'iceflame_bolt' , 'iceflame_torrent' , 'iceflame_torrent_dire' , 'wizards_fire_ball' , 'magic_arrow' ,
'prismic_arrow' ,'boulder_rolling' , 'returning_throwing_axe' , 'recurring_nightmare' , 'crystal_shard' ,
'soul_orb_bomb' , 'cool_stone' , 'pyre_stone' , 'mind_stone' , 'tooth_lizard' , 'boom_rock' , 'death_star'}
function isInTable(table, element)
for _,value in pairs(table) do
if value == element then
return true
end
end
return false
end
function customSpellOnProjectileHitHook(monster,projectile,damage,damageType)
local dx,dy = getForward(monster.facing)
if isInTable(projectileItems, projectile.name) then
if projectile.name == 'magic_arrow' then
local originator = 2 ^ (spellCaster+1) -- calculate the originator of the spell
local damage = math.random(15,30)--
damageTile(monster.level,monster.x,monster.y,(monster.facing + 2)%4,originator+1, 'physical',damage)
playSound("prismic_missile_hit")
return false
elseif projectile.name == 'blade_knife' then
local originator = 2 ^ (spellCaster+1) -- calculate the originator of the spell
local damage = math.random(15,20) --
damageTile(monster.level,monster.x,monster.y,(monster.facing + 2)%4,originator+1, 'physical',damage)
playSoundAt("impact_blade",monster.level,monster.x,monster.y)
return false
end
end
So that is all pretty simple... what I think is causing the problem is the script that adds the effects to the spells. This script is not my work (it was written by ....... for the spells Wizards Fire and Wizards Life Fire) and admittedly is way beyond me in terms of complexity
SpoilerShow
projectiles = {}
function addProjectileEffect(projectile,effectName,speed,onHitEffectName)
local timer = spawn('timer',projectile.level,projectile.x,projectile.y,projectile.facing)
local effect = spawn('fx',projectile.level,projectile.x,projectile.y,projectile.facing)
projectiles[timer.id] = {}
projectiles[timer.id].projectile_id = projectile.id
projectiles[timer.id].effect_id = effect.id
projectiles[timer.id].level = projectile.level
projectiles[timer.id].x = 0
projectiles[timer.id].y = 0
projectiles[timer.id].facing = projectile.facing
projectiles[timer.id].onHitEffect= onHitEffectName
local dx,dy = getForward(projectile.facing)
dy = -1 * dy
projectiles[timer.id].x = dx * 0.5
projectiles[timer.id].y = dy * 0.5
timer:addConnector('activate','fxScripts','move_effect')
timer:setTimerInterval(0.5/speed)
local light = getLightPreset(effectName)
if light then
effect:setLight(unpack(light))
end
effect:translate(0.5*dx,1,0.5*dy)
effect:setParticleSystem(effectName)
timer:activate()
return effect
end
function addProjectileManualHit(caster, projectile, damageAmount, damageType, radius)
for key,value in pairs(projectiles) do
if value.projectile_id == projectile.id then
if caster then
projectiles[key].caster = caster:getOrdinal()
end
projectiles[key].damage = damageAmount
projectiles[key].damageType = damageType
projectiles[key].radius = radius
end
end
end
function getLightPreset(preset)
--FX:setLight(red, green, blue, brightness, range, time, castShadow)
local s = {}
s['fireball'] = {1, 0.5, 0.25,15,7,200,true}
s['fireball_hit'] = {1, 0.5, 0.25,40,7,1,true}
s['magic_missile'] = {1, 1, 1,15,7,200,true}
s['poison_bolt'] = {0.25, 0.6, 0.2,4,4,200,true}
s['lightning_bolt'] = {0.25, 0.5, 1,30,5,1,true}
s['lightning_bolt_hit'] = {0.25, 0.5, 1,100,5,0.5,true}
s['magic_missile_hit'] = {1, 1, 1,40,10,1,true}
s['wizards_fire'] = {1, 0.9, 0.5,40,10,1,true}
s['wizards_life_fire'] = {1, 1, 1,120,10,1,true}
s['wizards_fire_hit'] = {1, 1, 0.95, 150,10,0.6,true}
local l = s[preset]
if not l then
l = {0, 0, 0, 0, 0, 0, false}
end
return l
end
function move_effect(timer)
local e = projectiles[timer.id]
local p = findEntity(e.projectile_id)
local fx = findEntity(e.effect_id)
if not p then
if e.onHitEffect then
local ohfx = spawn('fx',e.level,e.px,e.py,e.facing)
ohfx:setParticleSystem(e.onHitEffect)
ohfx:translate(0, 1, 0)
local light = getLightPreset(e.onHitEffect)
if light then
ohfx:setLight(unpack(light))
end
end
projectiles[timer.id] = nil
timer:deactivate()
timer:destroy()
fx:destroy()
return
end
e.px = p.x
e.py = p.y
fx:translate(e.x,0,e.y)
end
function addProjectileEffect(projectile,effectName,speed,onHitEffectName)
local timer = spawn('timer',projectile.level,projectile.x,projectile.y,projectile.facing)
local effect = spawn('fx',projectile.level,projectile.x,projectile.y,projectile.facing)
projectiles[timer.id] = {}
projectiles[timer.id].projectile_id = projectile.id
projectiles[timer.id].effect_id = effect.id
projectiles[timer.id].level = projectile.level
projectiles[timer.id].x = 0
projectiles[timer.id].y = 0
projectiles[timer.id].facing = projectile.facing
projectiles[timer.id].onHitEffect= onHitEffectName
local dx,dy = getForward(projectile.facing)
dy = -1 * dy
projectiles[timer.id].x = dx * 0.5
projectiles[timer.id].y = dy * 0.5
timer:addConnector('activate','fxScripts','move_effect')
timer:setTimerInterval(0.5/speed)
local light = getLightPreset(effectName)
if light then
effect:setLight(unpack(light))
end
effect:translate(0.5*dx,1,0.5*dy)
effect:setParticleSystem(effectName)
timer:activate()
return effect
end
function addProjectileManualHit(caster, projectile, damageAmount, damageType, radius)
for key,value in pairs(projectiles) do
if value.projectile_id == projectile.id then
if caster then
projectiles[key].caster = caster:getOrdinal()
end
projectiles[key].damage = damageAmount
projectiles[key].damageType = damageType
projectiles[key].radius = radius
end
end
end
function getLightPreset(preset)
--FX:setLight(red, green, blue, brightness, range, time, castShadow)
local s = {}
s['fireball'] = {1, 0.5, 0.25,15,7,200,true}
s['fireball_hit'] = {1, 0.5, 0.25,40,7,1,true}
s['magic_missile'] = {1, 1, 1,15,7,200,true}
s['poison_bolt'] = {0.25, 0.6, 0.2,4,4,200,true}
s['lightning_bolt'] = {0.25, 0.5, 1,30,5,1,true}
s['lightning_bolt_hit'] = {0.25, 0.5, 1,100,5,0.5,true}
s['magic_missile_hit'] = {1, 1, 1,40,10,1,true}
s['wizards_fire'] = {1, 0.9, 0.5,40,10,1,true}
s['wizards_life_fire'] = {1, 1, 1,120,10,1,true}
s['wizards_fire_hit'] = {1, 1, 0.95, 150,10,0.6,true}
local l = s[preset]
if not l then
l = {0, 0, 0, 0, 0, 0, false}
end
return l
end
function move_effect(timer)
local e = projectiles[timer.id]
local p = findEntity(e.projectile_id)
local fx = findEntity(e.effect_id)
if not p then
if e.onHitEffect then
local ohfx = spawn('fx',e.level,e.px,e.py,e.facing)
ohfx:setParticleSystem(e.onHitEffect)
ohfx:translate(0, 1, 0)
local light = getLightPreset(e.onHitEffect)
if light then
ohfx:setLight(unpack(light))
end
end
projectiles[timer.id] = nil
timer:deactivate()
timer:destroy()
fx:destroy()
return
end
e.px = p.x
e.py = p.y
fx:translate(e.x,0,e.y)
end
Unfortunately I do not get any help from the editor when it crashes back to preview.
Any help at all would be appreciated!!
Akroma