ID:139278
 
Code:
        Attack(mob/M as mob in view(1))
if(M.life >= 1 && usr.delayed == 0 && M.attackable == 1 && usr.canattack == 1)
M.Damage(((usr.strength*0.8)+rand(usr.strength/5,usr.strength/3))/(M.resilience/3))
var/ow = M
ow = M.Damage()
view() << "[usr] hit [M] for [ow] !"
usr.delayed = 1
usr.await = 30 - (usr.speed/4)
sleep(usr.await)
usr.await = 0
usr.delayed = 0
if(M.Damage() >= M.life)
M.KO()
if(usr.delayed == 1||usr.canattack == 0)
M.life += 0


if(M.ko == 1)
view() << "[usr] is about to kill [M]"
switch(alert("Do you want to kill them?",,"Yes","No"))
if("Yes")
if(M.NPC == 1)
view() << "<font color = maroon> [usr] kills [M]!"
del M
if(!NPC)
view() << "<font color = maroon> [usr] kills [M]!"
M.contents = locate(M.loc)
M.loc = locate(/turf/dead)

if("No")
view() << "[usr] gave mercy on [M]."
M.loc=M.loc



//------------------------------//
mob
proc
Damage(D)
life = life - D


KO()
src.ko = 1
canattack = 0
view() << "<font color=yellow>[src] is unable to stand by themselves!"
sleep(120)
view() << "<font color=yellow>[src] wobbled back to their feet!"
src.ko = 0
src.canattack = 1


Problem description:

Hello Forum people. Above is the Attack verb, KO proc and Damage proc. It basically allows the attacking of a mob in view range 1, with a delay to allow manipulation of attack speed. I have several issues. The first issue I have is, how do I make it so that it attacks what is in the direction the usr is faceing, rather than anything in a radius around the usr? Also, when the player "kills" an npc this pops up in Dream Seeker :

runtime error: Cannot read null.loc
proc name: Attack (/mob/verb/Attack)
usr: Jin150 (/mob)
src: Jin150 (/mob)
call stack:
Jin150 (/mob): Attack(null)
runtime error: Cannot read null.ko
proc name: Attack (/mob/verb/Attack)
usr: Jin150 (/mob)
src: Jin150 (/mob)
call stack:
Jin150 (/mob): Attack(null)

However, when a normal player is killed, everything runs as planned (I.E teleporting the player to the specified turf).

My final problem, is the message that displays attack damage looks like this in game: Jin150 hit Jin150 for !

I can't for the life of me, get the Damage() number to show xD.

Well thank you for reading this if you did, and any responses will be greatly appreciated :) (I should probably point out now that I am learning to use DM properlly as I make this game XP )
Instead of
Code:
>       Attack(mob/M as mob in view(1))
>


Try that one

Attack(mob/M in get_step(usr,usr.dir))
In response to Paffci0
Thanks so much, I have been trying for two days to figure this out by scouring the DM reference and guide XD Much appreciated.
You get the "cannot read null.loc" error is because you are deleting M and then attempting to read M.loc. However, because you've deleted M, M is null, and so you get the null.loc error

It's rather self-explanatory.

It is occuring right here:

                        if(M.NPC == 1)
view() << "<font color = maroon> [usr] kills [M]!"
del M
if(!NPC)
view() << "<font color = maroon> [usr] kills [M]!"
M.contents = locate(M.loc)
M.loc = locate(/turf/dead)


Presumably, that second if() statement should just be "else".

Also: the line M.contents = locate(M.loc) is... wrong. If you want to actually move everything in M.contents to M.loc, you would need to use a for() loop to iterate through M.contents and move them to M.loc.
In response to Jin150
Heh no problem :) Good luck with your project :)
In response to Garthor
Thanks for the response Garthor. The contents.loc = locate(M.loc) worked, but I read an article about "Just because it works doesn't mean its right" lol. So I'll change that to a for() loop.

As for the null error message, I made it look like this, so as to erase all nulls (to my knowledge) once the NPC is deleted.



        Attack(mob/M as mob in view(1))
if(M.life >= 1 && usr.delayed == 0 && M.attackable == 1 && usr.canattack == 1)
M.Damage(((usr.strength*0.8)+rand(usr.strength/5,usr.strength/3))/(M.resilience/3))
view() << "[usr] hit [M] with a [usr.wpn]"
usr.delayed = 1
usr.await = 30 - (usr.speed/4)
sleep(usr.await)
usr.await = 0
usr.delayed = 0



if(M.Damage() >= M.life)
M.KO()



if(M.ko == null)
return ..()
if(M.ko == 1||M.ko == null)
view() << "[usr] is about to kill [M]"
switch(alert("Do you want to kill them?",,"No","Yes"))
if("Yes")
if(M.NPC)
view() << "<font color = maroon> [usr] kills [M]!"
del M
return ..()
else
view() << "<font color = maroon> [usr] kills [M]!"
M.contents = locate(M.loc)
M.loc = locate(/turf/dead)
return ..()

if("No")
view() << "[usr] gave mercy on [M]."
M.loc=M.loc
return

else
M.life += 0
return


And here are the damage and KO procs the code calls on, just for reference:

mob
proc
Damage(D)
life = life - D


KO()
src.ko = 1
canattack = 0
view() << "<font color=yellow>[src] is unable to stand by themselves!"
sleep(120)
view() << "<font color=yellow>[src] wobbled back to their feet!"
src.ko = 0
src.canattack = 1
src.life += (src.truelife/10)

now, I get this error message:

runtime error: Cannot read null.ko
proc name: Attack (/mob/verb/Attack)
usr: Jin150 (/mob/admin)
src: Jin150 (/mob/admin)
call stack:
Jin150 (/mob/admin): Attack(null)

From what I can gather, its trying to read the ko var but I thought that what I did code wise stopped it trying to continue doing calculations and whatnot once it was determined to be null. But even with my tinkering about, I couldn't fix it -facepalm- Any ideas?
In response to Jin150
Any time a procedure sleeps, anything can happen. This includes deleting one of the objects involved in it. In this case, you call M.KO(), it sleeps for 12 seconds, during which the mob is getting deleted. After KO() finishes sleeping, it returns to Attack(), which attempts to read M.ko, which results in an error.

Most likely the simplest fix would be to change your sleep() statements into spawn() blocks. For example, you would change:

sleep(usr.await)
usr.await = 0
usr.delayed = 0


to:

spawn(usr.await)
usr.await = 0
usr.delayed = 0


this would cause the block to be executed later without causing the rest of the procedure to wait for it.

Additionally, your if() statement, if(M.Damage() >= M.life) is useless. Aside from not passing an argument to Damage() which it requires, Damage() doesn't return any value, so that will ALWAYS be if(null >= M.life).

Also, "return ..()" is improper here. ..() calls the parent procedure, the one which has been overridden. So, if you override Move(), you need to call ..() to make the mob actually move. In this case, you are defining a new procedure, and so there will be no parent, so just "return" is all you need. It doesn't actually make a difference here, but it shows you have a misunderstanding of ..()
In response to Garthor
Thanks alot for your help Garthor. I think I should probably learn more about DM then redo the attack system from scratch, as it seems I have much to understand before I can tinker about with the code.

Your advice helped me understand certain aspects that I was struggling with so thanks a bunch :)