ID:144404
 
Problem description:

I have a problem with a particular proc that I made. It used to be fine then all of a sudden it stopped working correctly. I've run several profile's and byond claims it's calling the proc but it's not doing anything. I've run several checks on it and made sure there were no other procs in BYOND or my code. I can't seem to figure out anything. If anyone can help me understand why a proc is being called but not executed please explain how I can fix it...
If you need help with a particular proc, you'll need to show your code.
In response to Prodigal Squirrel
proc
Dispel(mob/M)
if(!M) return
if(M.Float) M.Float = null
if(M.Image) M.Image = null
if(M.Regen) M.Regen = null
if(M.Haste) M.Haste = null
if(M.Quick) M.Quick = null
if(M.Shell) M.Shell = null
if(M.Armor) M.Armor = null
if(M.Countdown) M.Countdown = null
if(M.HP_Leak) M.HP_Leak = null
if(M.Wall) M.Wall = null
if(M.Berserk)M.Berserk = null


This is the proc suppossedly being called. However it does nothing. The profile claims it to being called several times yet there is nothing happening.
In response to Cecil81067
Are you calling it with the correct argument? Does the mob exist? What do all these variables have for a value? Why can't you just run through like this:

m.Float=null
m.Image=null
m.Regen=null
//Etc.
In response to Jp
I've put in several debugging messages sent out to the world.

world << "Check 1"
if(!M) world << "No Mob"


Like this. However Check 1 isn't even occuring, even though Byond Claims the proc is being called. Oh, and the variables are either 1 or null. Activating it or de-activating it. The reason I didn't just use your example was mainly because I'm told it's good "code practice" to do checks.
In response to Cecil81067
Then the proc isn't being called. Nuff said. If you don't see the debug output, it's NOT HAPPENING.

It's good practice to do sanity checks. But going

if(something is true) it is now false

is silly. It's got EXACTLY THE SAME EFFECT as just setting it to false.
In response to Jp
Then why is the profile counting the Dispel proc? I think i'm reading this correctly. Plus I did checks just before the proc is called to make sure arguments were fine. They checked out fine but Dispel still won't get called. And that's fine about your opinion concerning those checks. But to my knowledge it doesn't change much either way.
In response to Jp
Jp wrote:
Then the proc isn't being called. Nuff said. If you don't see the debug output, it's NOT HAPPENING.

So not true.
Here are 4 examples off the top of my head, where your sentence isn't correct.
--The output may be directed at somethings that are NOT you or NOT including you (nullified by using 'world').
--You may be "not-available"/unable to receive output at that time. Only reason I can think of, is somewhat common; if you send output at world/New() (unless you use spawn() or sleep()), you won't receive it, because at the time that proc is called, you aren't logged in YET (even if hosting it from Dream Seeker, yes. However, in that case you should normally be logged in shortly afterwards).
Also, if you send output at client/New(), when client/New() is called for YOUR client, I don't think you will receive that output, because again - you aren't logged in it.
--Well, somewhat redundant since it should be easy to spot&fix, but - the proc may be indeed running but not reaching the debug output OR the proc may be attempting to run, but isn't doing so because of a runtime error occuring somewhere early (possibly even at the arguments-specifying).
--If the above is not true, then it's likely you're experiencing a BYOND bug.

Regardless - how could you of said your sentence despite he said he looked at the World Profile and it said the proc WAS, indeed, running? (unless THAT is some BYOND bug ;)).

It's good practice to do sanity checks. But going
if(something is true) it is now false

is silly. It's got EXACTLY THE SAME EFFECT as just setting it to false.

True. It's better to just directly set it to null.

Cecil, check if the above specified reasons apply to you. Also, re-post the whole proc including the debug messages, and also post the proc where you're calling Despell() from.
In response to Cecil81067
It'll be slightly faster.

Why is profile counting the Dispel() proc? It's not being run, I believe you'll find. It appears in the table but has a runtime of 0, I'm willing to bet.
In response to Kaioken
Hey, guess what, he's using world in his debug output! And it's happening after a battle, according to his first post! The debug output is the first line in the proc! It's somewhat unlikely that he's run into a BYOND bug!

Given all that, the procedure is NOT BEING CALLED.
In response to Kaioken
For starters I thought i'd show the profile information on Dispel.


/proc/Dispel
self-cpu time is 0.000
total-cpu time is 0.010
real-time is 0.010
call is 1

I'm not sure exactly what this means. As for the procedure that calls Dispel...

if("Dispel")
if(MagicalHitSuccess(M,Hit)) //A procedure I use concerning accuracy...
world << "Dispel Check 1" //Debugging information to be sure previous proc is working
Dispel(M) //The problem in question
return 1
else return 0


Now "dispel check 1" checked out fine however Dispel doesn't run, so it's not the previous procs fault. However Dispel() is just refusing to cooperate with me. Oh, and also there are no runtime errors recorded during the entire procedure (which is what I thought it was initially).
In response to Cecil81067
That means it's being called once.

Hmmm...

You definitely have a check in the Dispel() proc right at the start? As in:

proc/Dispel(mob/m)
world << "Testing"
if(!m) return //etc.


Because if that's not happening, that's serious weirdness.
In response to Jp
Yeah... this is all becoming quite strange. I feel like shooting myself. I did a ton of different stuff for checks and they are coming back negative during the proc... I even removed the series of checks and still got nothing.
In response to Cecil81067
I reviewed a lot of stuff and found out that it didn't have anything to do with the proc but the mob itself. Apparantly the mob switched somewhere between targetting. The reason I was unable to locate the direct checks is because they were sent to monster's that are controlled by the world.... I feel really dumb right now. Thanks for helping me out though. Heh.
In response to Cecil81067
proc
Dispel(mob/M)
ASSERT(M)
for(var/X in list("Float","Image","Regen","Haste","Quick","Shell","Armor","Countdown","HP_Leak","Wall","Berserk"))
if(X in M.verbs) M.verbs[X]=null


if(X in M.vars) checks if the variable exists, while M.vars[X]=null. This shows how you can easily shrink your code down!
In response to Android Data
((note to Cencil: it's not even the best design BTW to have tons of vars like that; use a list or bit flag var instead))

Um...I also thought of that after reading his initial post, but it isn't the smartest thing to do. Albeit amount-of-code-wise shorter it's needlessly less efficient than just doing
M.Float=null
M.Image=null
M.Regen=null
M.Haste=null
//etc


If already, and you want to shorten it, do something simple but equally efficient like this:
#define n/*ullify*/(A) A=null
n(M.Image)
n(M.Regen)
n(M.Haste)
n(M.Float)

(shorter version, only applicable specifically for this (and similar) proc:)
#define n/*ullify*/(x) M.x=null
n(Image)
n(Regen)
n(Haste)
n(Float)
#undef n

You could even go as far as this, though if you add more vars later you will need to update the macro as well, since the #define macros aren't currently advanced enough:
#define n/*ullify*/(A,B,C,D) {M.A=null;M.B=null;M.C=null;M.D=null}
n(Image,Regen,Haste,Float)
#undef n


Much shorter, as well as still efficient. These things are one of the reasons we got #define macros when we already got procs.
That said, not much reasons to get lazy around on copy&pastin' some 5 lines and devise a shortcut that at all, thoug especially not one that will hamper performance.

Jp: Too lazy to comment on your posts, but, good job dude, good job.

Cencil: Glad you got if fixed; I'm a bit curious, care to provide a more detailed explanation of how you did it and what was the problem? I didn't exactly gather a lot from that post where you said you fixed it.
In response to Kaioken
Kaioken wrote:
Much shorter, as well as still efficient.

Did you read my post? I gave a better method of doing this. If you really want a proc:

datum/proc/nullify(list/vars)
if(istext(vars)) vars=list(vars)
if(!istype(vars,/list)) return
for(var/X in vars) if(X in src.vars) src.vars[X]=null


Then just call it like so:
nullify(list("Image","Regen","Haste","Float"))
In response to Android Data
Android Data wrote:
Kaioken wrote:
Much shorter, as well as still efficient.

Did you read my post? I gave a better method of doing this. If you really want a proc:
xD
Did YOU read MY post? Which happened to be in reply to yours. Your way of just shortening that copy&pasting some 5 lines has an efficiency penalty, which makes it pretty worthless. Same for your nullify proc, which wasn't much different, of course.
Those #defines I posted still retain efficiency, and don't need to pointlessly create list objects and loops.
Have a good day...
In response to Kaioken
Not sure if you know what I work on, but I work on a game called Final Fantasy 5: Another World (Not an FFL Rip or clone). Basically it had problems with "Reflection" and somehow a variable got mixed up and switched the mob on me earlier. I feel kinda stupid for not thinking about it before I bothered you all lol. As for the examples they are great. (I'm not that advanced a coder yet so I have never worked with #define type code)
In response to Cecil81067
I see. Oh well, glad to try to help. >.>
#define isn't really advanced. Look it up in the reference. All it does, that it replaces define names with the define value when compiling.
So if your code looks like this:
#define HEAL_HP 50
mob/verb/heal()
set desc="Heal [HEAL_HP] points of damage"
src.HP = max(src.HP+HEAL_HP,src.maxHP)
src << "You heal yourself."

It actually gets compiled as if you typed:
mob/verb/heal()
set desc="Heal [50] points of damage"
src.HP = max(src.HP+50,src.maxHP)
src << "You heal yourself."

#defines with arguments are a bit procedure-like, but theyre still just like a bit more advanced find & replaces. Take this for an example of an islist() proc (well, actually its a #define macro)
#define islist(X) istype(X,/list)

By that, each time you type islist(some_var), it will get compiled as istype(some_var,/list).

#defines have their uses, to make changing things easy (including in libraries), like the HEAL_HP macro above - just change it and it will change all of the number in the verb. They can also make using numeric values and bit flags easier, by giving them names (better than using strings, since bitflags are faster and also text strings take more memory).
#define ACTION_ATTACK 1
#define ACTION_DEFEND 2
#define ACTION_ESCAPE 3

#define ESCAPE_DISTANCE 20

mob/proc/AI()
for() //infinite loop
switch(rand(1,3)) //choose random number from 1 to 3. we could also use rand(ACTION_ATTACK,ACTION_ESCAPE) but it doesn't make things easier specifically here
if(ACTION_ATTACK) //gets compiled as 'if(1)', but this is obviously way more readable
var/mob/M = locate(/mob) in oview()
if(M) src.Attack(M)
if(ACTION_DEFEND)
//src.Defend()
src.icon_state = "defend"
if(ACTION_ESCAPE)
var/turf/escapeloc = src.loc //store the current loc
while(get_dist(escapeloc,src.loc) < ESCAPE_DISTANCE)
step_away(src,escapeloc,ESCAPE_DISTANCE) //step away from it until far enough
sleep(src.delay) //delay movement. smaller it is, faster steps


If you use bit flags, they make using them much easier, via custom names, as well.
Page: 1 2