The Dink Network

Local variable problem

August 6th 2009, 03:59 PM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
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?
August 6th 2009, 04:32 PM
slimeg.gif
metatarasal
Bard He/Him Netherlands
I object 
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?
August 6th 2009, 06:03 PM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
Sure, here's the full script.

void main (void)
{
int &stun = 0;
int &stunduration = 0;

checkstatus:

if (&stun == 1)
{

	if (&stunduration > 0)
	{
		freeze(&current_sprite);
		&stunduration -= 1;
	}
	else
	{
		&stun = 0;
		unfreeze(&current_sprite);
	}
}
wait(100);
goto checkstatus;

}

void hit (void)
{

	&stun = 1;
        &stunduration = 20;
	
}


It never even gets into the if (&stun == 1) part.
August 6th 2009, 07:28 PM
custom_robj.png
Robj
Jester He/Him Australia
You feed the madness, and it feeds on you. 
"It never even gets into the if (&stun == 1) part."

You need to add goto checkstatus; after &stunduration = 20; in the hit procedure.
August 7th 2009, 05:05 AM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
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
August 7th 2009, 06:57 AM
spike.gif
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.
August 7th 2009, 06:59 AM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
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
August 7th 2009, 07:05 AM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
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:

// 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?
August 7th 2009, 08:05 AM
slimeg.gif
metatarasal
Bard He/Him Netherlands
I object 
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?

void main (void)
{
int &stun = 0;
int &stunduration = 0;

checkstatus:
 
if (&stun == 1)
{
wait(100);
if (&stunduration > 0)
{
freeze(&current_sprite);
&stunduration -= 1;
}
else
{
&stun = 0;
unfreeze(&current_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).
August 7th 2009, 10:02 AM
slayer.gif
rabidwolf9
Peasant He/Him United States
twitch.tv/rabidwolf9 
Why not just have the loop in a spawned script so it won't get interrupted no matter what?
August 7th 2009, 11:55 AM
spike.gif
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.
August 7th 2009, 03:23 PM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
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
August 8th 2009, 08:31 AM
slayer.gif
rabidwolf9
Peasant He/Him United States
twitch.tv/rabidwolf9 
If you were to use a spawned script, you could always do something like this to record the sprite.

//code from enemy
&save_x = &current_sprite;
spawn("script");


//code from script
int &enemy = &save_x;
August 8th 2009, 09:25 AM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
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 :/
August 8th 2009, 09:57 AM
slayer.gif
rabidwolf9
Peasant He/Him United States
twitch.tv/rabidwolf9 
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.
August 8th 2009, 10:45 AM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
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
August 8th 2009, 06:17 PM
dinkdead.gif
If in the spawned script all you need to pass is which sprite summoned it, using external() might be easier because you can use &current_sprite in that directly, without needing Rabid's way of recording the sprite.