Local variable problem
So I was messing around trying to fix one of the incompatible dmods a friend of mine released a long time ago which doesn't work for 1.08 anymore. I found a strange thing while scripting, but my memory of 7-8 years ago isn't too great so it might always have been like this I guess.
I'm declaring a variable in an enemy's main procedure called &stun. However, I can't seem to access this variable in its hit procedure anymore. I could honestly swear it used to allow that. So, excluding the possibility I might be doing something horribly wrong and this was a (unintended?) change in 1.08, how can I pass multiple variables from my hit procedure to main and back again?
I'm declaring a variable in an enemy's main procedure called &stun. However, I can't seem to access this variable in its hit procedure anymore. I could honestly swear it used to allow that. So, excluding the possibility I might be doing something horribly wrong and this was a (unintended?) change in 1.08, how can I pass multiple variables from my hit procedure to main and back again?
If my memory serves me right you can only use a local variable in the procedure it's declared with the exception of the main procedure. I usually declare my variables in the main procedure and then use them wherever I want. It shouldn't give any trouble.
There have been changes in 1.08 concerning 'sharing' of variables between procedures, but declaring in the main procedure and then using it in the hit procedure should work perfectly well. Do you have the script so we can take a look at it?
There have been changes in 1.08 concerning 'sharing' of variables between procedures, but declaring in the main procedure and then using it in the hit procedure should work perfectly well. Do you have the script so we can take a look at it?
Sure, here's the full script.
It never even gets into the if (&stun == 1) part.
void main (void)
{
int &stun = 0;
int &stunduration = 0;
checkstatus:
if (&stun == 1)
{
if (&stunduration > 0)
{
freeze(¤t_sprite);
&stunduration -= 1;
}
else
{
&stun = 0;
unfreeze(¤t_sprite);
}
}
wait(100);
goto checkstatus;
}
void hit (void)
{
&stun = 1;
&stunduration = 20;
}
It never even gets into the if (&stun == 1) part.
"It never even gets into the if (&stun == 1) part."
You need to add goto checkstatus; after &stunduration = 20; in the hit procedure.
You need to add goto checkstatus; after &stunduration = 20; in the hit procedure.
So I can't reliably run a loop in the main procedure? (does it get interrupted when it's hit?)
I added the &stunduration = 20 in the hit procedure to test it. In reality it's going to be a global variable that acts like a constant throughout the game. So, if I don't add it in the hit procedure and I use the goto command in the hit procedure, hitting it 20 times in a row will actually subtract one from the duration each time, overwriting the timer mechanic of the main procedure. I hope that makes sense :/ I think I'll try it with the sp_custom key feature which seems to be new (??).
EDIT: I tested it and hitting an enemy indeed ends the main procedure. Something to keep in mind if you want to do anything in that procedure I guess. Still leaves me with the problem that I can not use variables in the hit procedure that I declared in the main procedure. Weird stuff. Guess I'll follow Rob's suggestion and just live with the potential exploits
I added the &stunduration = 20 in the hit procedure to test it. In reality it's going to be a global variable that acts like a constant throughout the game. So, if I don't add it in the hit procedure and I use the goto command in the hit procedure, hitting it 20 times in a row will actually subtract one from the duration each time, overwriting the timer mechanic of the main procedure. I hope that makes sense :/ I think I'll try it with the sp_custom key feature which seems to be new (??).
EDIT: I tested it and hitting an enemy indeed ends the main procedure. Something to keep in mind if you want to do anything in that procedure I guess. Still leaves me with the problem that I can not use variables in the hit procedure that I declared in the main procedure. Weird stuff. Guess I'll follow Rob's suggestion and just live with the potential exploits
So I can't reliably run a loop in the main procedure? (does it get interrupted when it's hit?)
Yep. Using set_callback_random("checkstatus",100,0); should get the job done. Is it completely reliable, though? Hmmm.
Yep. Using set_callback_random("checkstatus",100,0); should get the job done. Is it completely reliable, though? Hmmm.
Hmm, good idea
I forgot about that functionality, used in the dragon scripts right? I'll see if I can make that work.
Thanks for all the help so far guys
Thanks for all the help so far guys
Nope, unfortunately even the callback stops when I hit the enemy, even if I delete all the code in the hit procedure.
Let's illustrate what I tested:
When I hit it the life stops being added. Now, I checked the dragon scripts, and they seem to work the same way, yet don't have the problem (I assume?).
EDIT: Okay it's far worse than I thought. The original game's dragon script is also broken by this. I assume a lot of original Dink scripts might be affected by it as well. Is Redink still around to fix stuff like this or has he bailed?
Let's illustrate what I tested:
// Basic pillbug
void main (void)
{
set_callback_random("checkstatus", 100, 0);
}
void hit (void)
{
}
void checkstatus (void)
{
&life += 1;
}
When I hit it the life stops being added. Now, I checked the dragon scripts, and they seem to work the same way, yet don't have the problem (I assume?).
EDIT: Okay it's far worse than I thought. The original game's dragon script is also broken by this. I assume a lot of original Dink scripts might be affected by it as well. Is Redink still around to fix stuff like this or has he bailed?
Was the original dragon also broken in 1.07? In that case we'd need to look into it again.
Can't you use something like this?
Obviously this won't work if you hit very fast in a row either, but maybe you could change the wait(100); value into something lower (Under 30 or so should definitely work).
Can't you use something like this?
void main (void)
{
int &stun = 0;
int &stunduration = 0;
checkstatus:
if (&stun == 1)
{
wait(100);
if (&stunduration > 0)
{
freeze(¤t_sprite);
&stunduration -= 1;
}
else
{
&stun = 0;
unfreeze(¤t_sprite);
}
}
goto checkstatus;
}
void hit (void)
{
&stun = 1;
&stunduration = 20;
goto checkstatus;
}Obviously this won't work if you hit very fast in a row either, but maybe you could change the wait(100); value into something lower (Under 30 or so should definitely work).
Why not just have the loop in a spawned script so it won't get interrupted no matter what?
Huh, I had the memory there were some issues with that command, but it seems to be utterly broken for the purpose it's used in original Dink's monster scripts.
If you completely remove void hit(), hitting it shouldn't interrupt the callback. I haven't tested that with set_callback_random(), but it works with other stuff, so it should be true here as well.
Not an option if you need that procedure, though.
If you completely remove void hit(), hitting it shouldn't interrupt the callback. I haven't tested that with set_callback_random(), but it works with other stuff, so it should be true here as well.
Not an option if you need that procedure, though.
Yes, that would probably work, I'll test it. But, getting hit by a hellfire will trigger the hit procedure rapidly in a row, possibly interrupting the effects being handled in the main procedure. I'll let you know if it turns out alright. And a spawned script is not an option, since I can't give it any parameters to work with (so it won't know which sprite summoned it).
EDIT: It seems to work this way, hope it won't shut down after a while or when too many monsters like it are on screen. On another note, I found out the details about the variable bug. Variables declared in the main procedure appear to only be accessible within default Dink procedures such as hit and die, but never custom ones. That's a pity, because I won't be able to split the big hit procedure in multiple easy to read procedures
EDIT: It seems to work this way, hope it won't shut down after a while or when too many monsters like it are on screen. On another note, I found out the details about the variable bug. Variables declared in the main procedure appear to only be accessible within default Dink procedures such as hit and die, but never custom ones. That's a pity, because I won't be able to split the big hit procedure in multiple easy to read procedures
If you were to use a spawned script, you could always do something like this to record the sprite.
//code from enemy
&save_x = ¤t_sprite;
spawn("script");
//code from script int &enemy = &save_x;
Yeah, I was wondering about doing it like that, but I'm not sure how the Dink engine runs its scripts. If it runs them internally in different threads it can execute that script 5 times simultaneously for 5 different enemies, which would mean the global &save_x (or for procedures, the &arg arguments) get overwritten constantly between scripts :/
It should be fine as long as there's no wait in between setting the save_x variable and storing the value into a local variable.
You should check into someone's FIFO & Variables in DinkC tutorial if you haven't already. This was explained in the scripts: order of execution section. It helped me a great deal.
You should check into someone's FIFO & Variables in DinkC tutorial if you haven't already. This was explained in the scripts: order of execution section. It helped me a great deal.
Oh, thanks! That's exactly the kind of material I needed to read
EDIT: This was it, now I understand it all. This is gonna make it sooo much easier
EDIT: This was it, now I understand it all. This is gonna make it sooo much easier
If in the spawned script all you need to pass is which sprite summoned it, using external() might be easier because you can use ¤t_sprite in that directly, without needing Rabid's way of recording the sprite.














