ID:900733
 
Keywords: call
Code:
This is part of my NPC code:
mob/proc
Wander()
while(src)
for(var/mob/M in oview(6))
if(!M.client) continue
if(M in oview(1))
call(/mob/Attack/proc/Attack)(M)

and this is the attack code been call
mob/Attack/proc//Attacks.dm,1
Attack(mob/M in oview(1))//2
src.hit += src.Atk(M,src)//3
return//4

Problem description: I'm getting:
runtime error: Cannot execute null.Atk().
proc
name: Attack (/mob/Attack/proc/Attack)
source file: Attacks.dm,3
usr: Fire (/mob/Boss)
src: null
call stack:
Attack(Prf X (/mob/Player))

how do I get call() to send the src to the proc?

Have you thought to use usr?
Why don't you make Attack() just a mob proc:
mob/proc
Attack()

Then you don't have to use call() to use it for this purpose. Also why not use:
for(mob/M in get_step(src, src.dir))

for the Attack proc, oview() is kind of out-dated for attacking.
You're using the wrong form of call(). You want call(Object,ProcName)(Arguments) to call it with an src.

However, as GreatFisher noted, there's no reason to be using call() here at all.
@Albro1
Dream Maker's Help wrote:
A good rule of thumb is to never put usr in a proc.

@GF & DC
It's only one part of my NPC code
the full code is:
    Wander(T AT,O AT)
while(src)
if(T == "") T = pick("Atk","Magic","Weapon")
if("Atk")
for(var/mob/M in oview(6))
if(!M.client) continue
if(M in oview(1))
call(/mob/Attack/proc/Attack)(M,src)
sleep(5)
Wander("","")
else
step_towards(src,M)
sleep(2)
Wander("Atk","")
if("Magic")
var/obj/Magic/mag
if(O == "")mag = pick(src.Magic)
else mag = text2path("/obj/Magic/[O]")
if(FT(mag.name,"Def"))
call(text2path("/mob/Magic/proc/[mag.name]"))(src,src)
if(FT(mag.name,"Heal")&&src.HP < src.MHP)
call(text2path("/mob/Magic/proc/[mag.name]"))(src,src)
for(var/mob/M in oview(mag.Range+6))
if(!M.client) continue
if(M in oview(mag.Range))
call(text2path("/mob/Magic/proc/[mag.name]"))()
sleep(5)
Wander("","")
else
step_towards(src,M)
sleep(2)
Wander("Magic",mag.name)
if("Weapon")
for(var/mob/M in oview(tcn(src.weaponequip.Lv)))
if(!M.client) continue
if(M in oview(1))
call(text2path("/mob/Attack/proc/[src.weaponequip.atk]"))()
sleep(5)
Wander("","")
else
step_towards(src,M)
sleep(2)
Wander("Weapon","")
if(src.Wander)
step_rand(src)
sleep(5)
spawn(5)
Wander("","")

& each attack is attach to an /obj (see Puting /obj/Attacks onto interface buttons
Oh my!

First and foremost, you do not need to recall Wander() as it loops continues to loop while src is in existence. What's worse is you are not spawning off separate instances of the procedure when you recall it, meaning you are at risk for a stack overflow. Instead, you can use a variable to store the next action for the next repetition of the loop and clear it when you decide what action to take.

Secondly, if("Atk"), if("Weapon"), if("Magic") are always true and those portions of code will always run regardless of what T is. Essentially, you are checking to see if static strings (which always exist in the scope they are defined in) exist with those conditionals. What you want is to check for equality, which you can do with the == operator or a switch(T) statement.

The way you handle attacking is kind of silly. I won't get into what happens in your Attack() procedure, but to loop through all mobs in oview(6) and either attack or walk to each of them would be idiotic. You don't see this behavior, however--you are bypassing the rest of the procedure when you open a new instance of Wander(). You may consider having the Wander() procedure pick a target. This will also help for the magic and weapon portions of the code.

Finally, you are calling the attack incorrectly. call(Object,ProcName)(Arguments) is the form you are looking for, and it should look something like call(src,/mob/proc/Attack)(M). Of course, I think it would be better to just be handling verbs directly instead of storing them in some dummy objects. Datums would also be a better alternative, using less useless memory than objects.
In response to Dipstyx
Dipstyx wrote:
Secondly, if("Atk"), if("Weapon"), if("Magic") are always true and those portions of code will always run regardless of what T is. Essentially, you are checking to see if static strings (which always exist in the scope they are defined in) exist with those conditionals. What you want is to check for equality, which you can do with the == operator or a switch(T) statement.
Thank you for see that

Finally, you are calling the attack incorrectly. call(Object,ProcName)(Arguments) is the form you are looking for, and it should look something like call(src,/mob/proc/Attack)(M).

runtime error: undefined proc or verb /mob/Bosses/Water/Attack().

proc name: Wander (/mob/proc/Wander)
source file: Procs.dm,156
usr: Water (/mob/Bosses/Water)
src: Water (/mob/Bosses/Water)
call stack:
In response to Prf X
Prf X wrote:
runtime error: undefined proc or verb /mob/Bosses/Water/Attack().

You don't have verb or proc in that type path.
If you want to use the src in the process, the process actually has to be defined under that type. Also, I think ProcName is intended to be a text string of just the name, not the path.

That said, I agree with Dipstyx: you should be using datums for this.
@DC no ProcName needs to be the path
In response to Prf X
Prf X wrote:
@DC no ProcName needs to be the path

Reference:
ProcRef: path of proc (/proc/MyProc)
ProcName: name of proc or verb ("MyProc")

I guess it might also accept a path, but requiring a name would make more sense (in terms of ensuring the process is actually defined under the src provided)
I fix it by changing mob/Attack/proc/ to mob/proc/
but now it can't read /obj/Magic/EarthHeal (/obj/Magic/EarthHeal).name {all of the magics in his list is output that}
You aren't actually creating the "Magic" object, you just have a type path. You need to create it before you can access any of its variables.
How?
In response to Prf X
Prf X wrote:
How?

Assuming that src.Magic also contains type paths and not objects:
            var/magType
if(O == "") magType = pick(src.Magic)
else magType = text2path("/obj/Magic/[O]")
var/obj/Magic/mag = new magType()
I'm not sure about this, but perhaps the colon operator could be of use here:

var/magic = /obj/Magic/mag
world << magic:name


If you're looking for the default name, that is. I know this technique works for static variables. Regarding the efficiency in terms of time or memory, I have no idea which is better. I'd assume not creating an object at all would be, but who knows!