The Dink Network

Scripting problem

October 3rd 2010, 09:30 AM
custom_iplaydink.gif
iplaydink
Peasant He/Him Sweden
Hmm.. 
Why can't I get Dink to say the value of the variable in the below script?
when say("&x"); is called he says "x" with a line under the x instead of the value... and I'm 100 percent sure &x has a value!

I need to know the value of &x and &y to figure out another problem with the script, why the object nebver returns that it's inside the coordinates in check_p.
The pushing works fine.

Script:

void main (void)
{
	int &x;
	int &y;
	&x = 100;
	&y = 100;
	int &junk;
	int &dir1;
	sp_speed(&current_sprite, 5);
	sp_brain(&current_sprite, 0);
	sp_x(&current_sprite, &x);
	sp_y(&current_sprite, &y);
	sp_hard(&current_sprite, 0);
	draw_hard_map();
}
void push(void)
{
	freeze(1);	
	sp_hard(&current_sprite, 1);
	draw_hard_map();
	
	&dir1 = sp_dir(1, -1);
	
	if(&dir1 == 6)
	{
		&x = sp_x(&current_sprite, -1);
		&x += 20;
		move_stop(&current_sprite, 6, &x, 1);
	}
	if(&dir1 == 2)
	{
		&y = sp_y(&current_sprite, -1);
		&y += 20;
		move_stop(&current_sprite, 2, &y, 1);
		
	}
	if(&dir1 == 8)
	{
		&y = sp_y(&current_sprite, -1);
		&y -= 20;
		move_stop(&current_sprite, 8, &y, 1);
		
	}
	if(&dir1 == 4)
	{
		&x = sp_x(&current_sprite, -1);
		&x -= 20;
		move_stop(&current_sprite, 4, &x, 1);
	}
	say("&dir", 1);
	sp_hard(&current_sprite, 0);
	unfreeze(1);
	check_p();
}
void talk(void)
{
	say("It's a stone", 1);
}
void check_p(void)
{
	&x = sp_x(&current_sprite, -1);
	&y = sp_y(&current_sprite, -1);
	
	if (&x >= 221)
	{
		if (&x <= 272)
		{
			if (&y <= 304)
			{
				if (&y >= 268)
				{
                                        //I need to print the x and y
                                        //to figure out why the script never gets here
					say("It's inside!", 1);
					goto skip;
				}
			}
			
		}
		
	}
	say("&x", 1);
        //Why doesn't that work?!
skip:
	draw_hard_map();
}
October 3rd 2010, 09:56 AM
slimeg.gif
metatarasal
Bard He/Him Netherlands
I object 
The problem is that variables declared in the void main() procedure of a script do not exist in custom procedures. According to the custom procedure you are running &x doesn't exist, that's why you are getting the x with a line under it. You can use this to make it work:

void main (void)
{
	int &x;
	int &y;
	&x = 100;
	&y = 100;
	int &junk;
	int &dir1;
	sp_speed(&current_sprite, 5);
	sp_brain(&current_sprite, 0);
	sp_x(&current_sprite, &x);
	sp_y(&current_sprite, &y);
	sp_hard(&current_sprite, 0);
	draw_hard_map();
}
void push(void)
{
	freeze(1);	
	sp_hard(&current_sprite, 1);
	draw_hard_map();
	
	&dir1 = sp_dir(1, -1);
	
	if(&dir1 == 6)
	{
		&x = sp_x(&current_sprite, -1);
		&x += 20;
		move_stop(&current_sprite, 6, &x, 1);
	}
	if(&dir1 == 2)
	{
		&y = sp_y(&current_sprite, -1);
		&y += 20;
		move_stop(&current_sprite, 2, &y, 1);
		
	}
	if(&dir1 == 8)
	{
		&y = sp_y(&current_sprite, -1);
		&y -= 20;
		move_stop(&current_sprite, 8, &y, 1);
		
	}
	if(&dir1 == 4)
	{
		&x = sp_x(&current_sprite, -1);
		&x -= 20;
		move_stop(&current_sprite, 4, &x, 1);
	}
	say("&dir", 1);
	sp_hard(&current_sprite, 0);
	unfreeze(1);
	check_p();
}
void talk(void)
{
	say("It's a stone", 1);
}
void check_p(void)
{
	int &x = sp_x(&current_sprite, -1);
	int &y = sp_y(&current_sprite, -1);
	
	if (&x >= 221)
	{
		if (&x <= 272)
		{
			if (&y <= 304)
			{
				if (&y >= 268)
				{
                                        //I need to print the x and y
                                        //to figure out why the script never gets here
					say("It's inside!", 1);
					goto skip;
				}
			}
			
		}
		
	}
	say("&x", 1);
        //Now it does work! Yay!
skip:
	draw_hard_map();
}


I agree that this is a really strange bug, I've had to make scripts 3 times as long in the past because of this. Variables do retain their value from void main() to other standard procedures, but apparently custom procedures work differently. Highly annoying.

Also I'm not exactly sure if a variable used in a custom procedure is cleaned up after running the procedure, I sure hope so as this is wasting variables...
October 3rd 2010, 10:44 AM
custom_iplaydink.gif
iplaydink
Peasant He/Him Sweden
Hmm.. 
It works! Love you meta! :3

I agree that it's a strange bug. It's defiantly something Seth should fix for 1.09!
October 3rd 2010, 11:36 PM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
This... is complicated hairy internal stuff. What I'm going to say now probably only applies to 1.08. No clue about earlier versions (some of the comments suggest it used to be different), nor about freedink.

Anyway, procedure calls, external(), spawn()... they all actually create a new script. It uses up a script slot, and they have a different value of &current_script.
Using run_script_by_number doesn't create a new script. Think of it as a goto-by-proxy. script_attach also doesn't create a new script.

Those freshly spawned scripts (at least those created by external() and procedure calls) will be killed off as expected. Unlike what the previous version of this post said, you don't need to kill_this_task() them. You still need to do that for spawn(), though!

Here's the catch: local variables are stored by script-number. Anything that creates a new script (with a new number) won't be able to read local variables. Globals work, of course. Pseudoglobals (&current_sprite, &arg1 to &arg9, etc.) are probably different in every case.

So... how do you know if a different script number is used? Use &current_script. To see if it survives, periodically check scripts_used():

// test.c
void main( void )
{
  int &x = 1234;
  sp_custom("myscript",&current_sprite,&current_script);
}

void talk( void )
{
  custom();
  // Didn't know about &x, but at least we got back.
  external("test","custom");
  // Also didn't know about &x, but we're still here.
  goto label;
  // Yay, it knows about &x. Sadly, we're stuck there.
  say_stop("You'll never see this. Muhahaha!");
}

void custom( void )
{
label:
  int &scripts = scripts_used();
  say_stop("Now using: &scripts scripts",1);
  int &oldme = sp_custom("myscript",&current_sprite,-1);
  if (&oldme == &current_script)
  {
    say_stop("I know about &x and I am happy about that!",1);
  }
  else
  {
    say_stop("I don't know what &x is",1);
  }
}
October 4th 2010, 03:23 AM
slimeg.gif
metatarasal
Bard He/Him Netherlands
I object 
I knew that external() procedures would not be able to use the local variables from the script that created them. That's why the original game uses the globals &save_x and &save_y for saving x and y positions when using external() to place goodies when monsters die. But that intuitively makes sense as you use a physically different script to write it in. Custom procedures are written in the same script, so it sounds like a strange and unnecessary step to create a new script, especially as other procedures such as hit() and main() all use the same script.

I am kind of worried about this actually as I use quite a few custom procedures in my latest DMOD(s). I just hope that using a return(); kills of the newly created "script" when you use a custom procedure. Otherwise using custom procedures becomes almost totally useless as you can't return variables without keeping an extra local script alive...

It does sound nice that at least theoretically newly created variables in custom procedures only take up variable space as long as the procedure is active, that offers perspective... I'll try and see what I can find this week...
October 4th 2010, 04:36 AM
spike.gif
It might make sense, but &save_x and &save_y are actually pretty unnecessary for the purpose they're used in Original Dink.

int &crapx = sp_x(&current_sprite,-1);
int &crapy = sp_y(&current_sprite,-1);

from the external script works perfectly well to put the goodie in the right place... A lot of other stuff like say("`%I'm the spirit of the old sprite and I'm here to haunt you!",&current_sprite); doesn't, though.
October 4th 2010, 08:46 AM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
Actually, that last example should work just fine. An external()'d script uses the same &current_sprite as the script you called it in.
Stuff goes wrong if a sprite is dead, and you use one of those few special "pausing" commands of which I wrote a rant earlier here (what? Last December already? Feels like something I did just before summer...). Calling external() does not pause, nor does say() (say_stop() does pause, though). I'm not sure if returning from an external() pauses, though, so that may screw up things as well.
October 4th 2010, 08:51 AM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
I lied. Unintentionally, though. I'll edit my previous post.

You're right. Using "return" in any way will kill the script-instance if it has a "parent". So if it's inside a procedure call, or an external, or such, then the script won't take up a script slot after it's done.
Reaching the end of the procedure works that way, too. Huzzah!

(oops, double post, but to two different people, so it should be okay. Yes?)