ID:145766
 
Code:
        attack(mob/M as mob in oview(1))     //attack a mob within 1 tile of you
oview() << "[usr] attacks [M]!" //send this message to everybody else
var/damage = rand(1, 10) * (usr.atk - M.def)
if(damage <= 0)
usr << "[M] easily dodges your attack!"
M << "You easily dodge [usr]'s attack."
else
M.HP -= damage
usr << "You attack [M] for [damage] HP!"
M << "[usr] attacks you for [damage] HP!"
M:DeathCheck()

if (M.HP >> 0)
oview() << "[M] counterattacks [usr]!" //send this message to everybody else
var/cdamage = rand(1, 10) * (M.atk - usr.def)
if(cdamage <= 0)
usr << "You easily dodge [M]'d attack!"
M << "[usr] easily dodge your attack."
else
usr.HP -= cdamage
usr << "[M] attacks you for [cdamage] HP!"
M << "You attack [usr] for [cdamage] HP!"


Problem description:
I can't figure out what's wrong with this code... it works fine without the second bit (If M.HP >> 0 and afterwards), but when I put it back in I get a runtime error that displays right before the enemy dies.


(
eg. bug with 15 HP

You attack the bug for 9 HP!
The bug attacks you for 8 HP!

runtime error: Cannot read null.HP
proc name: attack (/mob/verb/attack)
You attack the bug for 9 HP!
The bug was killed by Cinnamonspider
)

Sorry, I realize there are already threads on null runtime errors, I just can't seem to make much sense of any of them. :P

Few hints;

-Use
Attack(mob/M in get_step(usr, usr.dir)

instead of oview(1). This will attack only the monster that the player is facing.

-In this case it's better to use M.deathcheck(usr). Use a '.' instead of ':', and pass (usr) as an argument to the deathcheck, thus;

M.deathcheck(usr)
mob/proc/Deathcheck(mob/M)//usr gets passed to mob/M
if(src.hp>=0) //if the dying mob's (M in attack verb) HP is less or the same as 0
del(src) // Delete it


-Also do you seem to use
if(M.hp>>0)

The '>>' does nothing good. One '>' is enough. Thus;
if(M.hp>0)//If M's HP is bigger than 0

In response to Mysame
Ok, so I did all that, and now it looks like this:

mob
proc
DeathCheck(mob/M)
if (src.HP <= 0)
world << "[src] was killed by [usr]"
del(src)
usr.exp += 1

verb
attack(mob/M in get_step(usr, usr.dir)) //attack a mob within 1 tile of you
oview() << "[usr] attacks [M]!" //send this message to everybody else
var/damage = rand(1, 10) * (usr.atk - M.def)
if(damage <= 0)
usr << "[M] easily dodges your attack!"
M << "You easily dodge [usr]'s attack."
else
M.HP -= damage
usr << "You attack [M] for [damage] HP!"
M << "[usr] attacks you for [damage] HP!"
M.DeathCheck(usr)

if (M.HP > 0)
oview() << "[M] counterattacks [usr]!" //send this message to everybody else
var/cdamage = rand(1, 10) * (M.atk - usr.def)
if(cdamage <= 0)
usr << "You easily dodge [M]'d attack!"
M << "[usr] easily dodge your attack."
else
usr.HP -= cdamage
usr << "[M] attacks you for [cdamage] HP!"
M << "You attack [usr] for [cdamage] HP!"


Unfortunately the error message got longer, and I still don't understand it. :(

runtime error: Cannot read null.HP
proc name: attack (/mob/verb/attack)
usr: Greytabby (/mob)
src: Greytabby (/mob)
call stack:
Greytabby (/mob): attack(null)

The 'attack only when facing' thing worked nice, though. :) Thanks. Maybe I'll understand all of this better when I've had more sleep...
In response to Cinnamonspider
I know what's happening here.

After the DeathCheck proc is called and the enemy removed from the map, your Attack proc is still trying to call the counterattack section, therefore generating the error.

Here's the new piece of code:

mob
var
killer = ""
proc
DeathCheck()
if (HP <= 0)
world << "[src] was killed by [src.killer]" // better method of showing who killed what
if(usr<>src)
del(src)
usr.exp += 1
else
src.Move(locate(2,2,1)) // insert respawn loaction here

verb
attack(mob/M in get_step(usr, usr.dir))
oview() << "[usr] attacks [M]!"
var/damage = rand(1, 10) * (usr.atk - M.def)
if(damage <= 0)
usr << "[M] easily dodges your attack!"
M << "You easily dodge [usr]'s attack."
else
M.HP -= damage
usr << "You attack [M] for [damage] HP!"
M << "[usr] attacks you for [damage] HP!"
if(M.HP <= 0) // Only tries to run the DeathCheck if M's HP are 0 or less
M.killer = usr.name
M.DeathCheck()
else
oview() << "[M] counterattacks [usr]!"
var/cdamage = rand(1, 10) * (M.atk - usr.def)
if(cdamage <= 0)
usr << "You easily dodge [M]'d attack!"
M << "[usr] easily dodge your attack."
else
usr.HP -= cdamage
usr << "[M] attacks you for [cdamage] HP!"
M << "You attack [usr] for [cdamage] HP!"
if(usr.HP <= 0) // added player DeathCheck() call
usr.killer = M.name
usr.DeathCheck()


Hope that helps ya
In response to Magus_Christel
Magus, don't use usr in procs..

At the topic starter, you're still using 'usr' in your proc, too.I said pass usr as an argument in the M.deathcheck(usr). The (usr) in there being an argument, wich gets continued in deathcheck(mob/M). So usr becomes mob/M.
In response to Mysame
I am not a fool, Mysame. I've used 'usr' in my DeathCheck procs all the time, and not a single bug has resulted from it.

Plus, if I hadn't used 'usr' in that proc, then how would the player get EXP from a monster he had slain? Moreover, how could we avoid the user being kicked when he was killed?

Now tell me again not to use 'usr' in a proc.
In response to Magus_Christel
Simple enough, you know nothing about coding. Go read the DM guide.

Say it again? Sure. Don't use usr in procs. I've already said 2 times that usr gets passed as mob/M in the deathcheck proc. If you would READ what I'm saying, and if you read the guide, you will know what I mean.

src has been proven better many times. What if the usr didn't attack by itself? What if it didn't move by itself? Boof, runtime, bboof, crash. You don't have to have something coded in that moves a person, BYOND strangely does this by itself.

So please, read the guide and be rude when you know what you're talking about.

Here I am, trying to help, and all you do is saying how stupid I am. Well cough cough.
In response to Magus_Christel
Magus_Christel wrote:
I've used 'usr' in my DeathCheck procs all the time, and not a single bug has resulted from it.

When you start to expand your battle system, usr will be wrong. It is better to have correct information than wrong information.

Plus, if I hadn't used 'usr' in that proc, then how would the player get EXP from a monster he had slain? Moreover, how could we avoid the user being kicked when he was killed?

You simply send the information you need through the argument. And the way that you are doing your DeathCheck, the killer will never gain experience, since the mob is being deleted before so, resulting in the proc being stopped.

For your original problem, that runtime error states as it says. M is null, and you need to fix that. You cannot use "get_step()" like that inside a verb argument, because it isn't supported. You either need to check it in the verb yourself, or do your attacking differently. It'd be more helpful if you turn on DEBUG mode (#define DEBUG) and used the verb again, then tell us what line it was at. That way, it would be easier to tell where exactly the error is occuring.

~~> Unknown Person