ID:161312
 
I am getting a runtime error from a fight proc where the error has no apparent effect on the fight or the end. Everything is running smoothly except for the fact that the error is posted in the output screen.

I have tried to find where exactly the error is occurring in the proc but I can find nothing wrong, like I said the proc runs perfectly (I think).

Error:
runtime error: Cannot read null.agility
proc name: battlesorter (/mob/proc/battlesorter)
usr: the gh (/mob/player/soldier/male)
src: the gh (/mob/player/soldier/male)
call stack:
the gh (/mob/player/soldier/male): battlesorter()
the gh (/mob/player/soldier/male): Move(the grass (70,18,2) (/turf/grass), 8)


I am posting the relevant proc code for the outputted error:

mob/proc/battlesorter()
if(src.battle)
if(fightlist.len == 2)
var/mob/monster/M1 = fightlist[1]
var/mob/monster/M2 = fightlist[2]
if(src.agility < M1.agility && src.agility < M2.agility && M1.agility >= M2.agility)// <-- This is where the error is apparently occurring
src.first = M1
src.second = M2
src.third = src
src << "M1, M2, You"
battle2()
if(fightlist.len == 1)
var/mob/monster/M1 = fightlist[1]
if(src.agility < M1.agility)
src << "M1, You"
src.first = M1
src.second = src
battle1()


The spawn code:
mob
Move()
if(src.lock) return
if(..())
if(src.fight)
if(!src.battle)
var/monsterspawn/S = new src.fight
if(S)
if(prob(S.spawnchance))
var/battlefield/a
for(var/battlefield/b in world)
if(!b.inuse)
a = b
break
if(a)
var/amount = rand(2,2)
if(amount == 2)
var/list/monsterlist = S.monsterspawnlist
var/monster = pick(monsterlist)
var/monster2 = pick(monsterlist)
var/mob/monster/M1 = new monster
var/mob/monster/M2 = new monster2
src.lastx = src.x
src.lasty = src.y
src.lastz = src.z
src.lock = 1
src.loc = a.loc
src.monster1 = M1
src.monster2 = M2
src.battle = 1
sleep(15)
fightlist = list(M1,M2)
src.battlesorter()


The rest of the code:
mob/proc/battle1()
var/mob/monster/M1 = fightlist[1]
var/mob/a = src.first
var/mob/b = src.second
src.target = null
M1.target = null
if(a)
if(b)
var/list/fight = list("Attack","Run")
var/cfight = input(src,"What will you do?") in fight
switch(cfight)
if("Attack") src.fightchoice = 1
if("Run") src.fightchoice = 0

if(src.fightchoice == 1)
var/list/target = list(M1)
var/ctarget = input(src,"Who will you attack?") as null|mob in target
if(ctarget == M1)
src.target = M1
M1.target = src
a.attack1()
if(b)
if(!b.dead)
b.attack1()
battlesorter()


mob/proc/battle2()
var/mob/monster/M1 = fightlist[1]
var/mob/monster/M2 = fightlist[2]
var/mob/a = src.first
var/mob/b = src.second
var/mob/c = src.third
if(a)
if(b)
if(c)
var/list/fight = list("Attack","Run")
var/cfight = input(src,"What will you do?") in fight
switch(cfight)
if("Attack") src.fightchoice = 1
if("Run") src.fightchoice = 0

if(src.fightchoice == 1)
var/list/target = list(M1,M2)
var/ctarget = input(src,"Who will you attack?") as null|mob in target
if(ctarget == M1)
src.target = M1
a.attack2()
if(b)
if(!b.dead)
b.attack2()
if(c)
if(!c.dead)
c.attack2()
else if(c)
if(!c.dead)
c.attack2()
battlesorter()


mob/proc/attack1()
var/mob/m = src.target
var/damage = (src.strength || src.attack) - round(m.agility / 2)
if(damage <= 0)
damage = 0
m.hitpoints -= damage
if(m.deathcheck())
if(src.client)
m.dead = 1
fightlist -= m
src.victory()
del(m)


mob/proc/attack2()
var/mob/m = src.target
var/damage = (src.strength || src.attack) - round(m.agility / 2)
if(damage <= 0)
damage = 0
m.hitpoints -= damage
if(m.deathcheck())
if(src.client)
m.dead = 1
fightlist -= m
del(m)


mob/proc/victory()
src.loc = locate(src.lastx, src.lasty, src.lastz)
src.battle = 0


I hope I have posted enough information without posting too much.

As always any help would be appreciated.

CyanHB
The problem is that because you delete a monster when it dies, its entry in the fightlist becomes null. One way to fix this is to call while(fightlist.Remove(null)); at the beginning of battlesorter(). Make sure to include the semicolon--it's there to remind you not to indent anything under it.

I'd recommend you rewrite this fight code a little differently to save yourself some trouble and make it more adaptable. Include any PCs and fighting NPCs in the list. Then in battlesorter, sort the list by decreasing agility, which you can do regardless of length. This allows you to get rid of the vars first, second, and third, and just keep a simple index in the list of whose turn it is. Each time a turn is about to begin, make sure any nulls are removed. If the index has gone past the length of the list, reset to 1.

Lummox JR
In response to Lummox JR
I've added what you suggested, played with it, moved it around all to no avail.

I forgot to mention that the error code is being outputted after the enemies are dead but before the victory proc is called. Although I don't think it makes any difference.
In response to Lummox JR
While you're rewriting it, remember to remove any recursive calls. battlesorter() calls battle1() calls battlesorter() calls battle2() calls battlesorter(), and they're all waiting for the next one to end, which they shouldn't be.