The Dink Network

Bad potion script? --RESOLVED--

December 30th 2009, 04:58 PM
pq_knight.gif
ExDeathEvn
Peasant Male New Zealand xbox steam
Don't look at me, I'm a ghost 
I'm having trouble with a potion that you can't pick up until after defeating a boss on the screen. I'm not sure if the problem is with the boss's script or the potions script, though, but for some reason it won't do anything when I talk to pick up the potion from a shelf.

Boss script
void main(void)
{
screenlock(1);
say("That made no sense, AND just sounds WRONG!!", 1);
//Said because the boss's script doesnt activate until after a dialogue script
sp_brain(&current_sprite, 9);
sp_speed(&current_sprite, 2);
sp_exp(&current_sprite, 500);
sp_timing(&current_sprite, 20);
sp_hitpoints(&current_sprite, 120);
sp_touch_damage(&current_sprite, 6);
sp_defense(&current_sprite, 1);
preload_seq(651);
preload_seq(653);
preload_seq(661);
preload_seq(663);
sp_base_attack(&current_sprite, -1);
sp_base_walk(&current_sprite,690);
sp_base_death(&current_sprite, 700);
                              
if (random(2,1) == 1)
 {
 sp_target(&current_sprite, 1);
 }
}

void touch(void)
{
//slurp noise

 playsound(38, 18050, 6000, 0, 0);

}

void hit(void)
{
sp_target(&current_sprite, &enemy_sprite);
//lock on to the guy who just hit us
//playsound (scream)
 playsound(53, 22050, 0, 0, 0);

}
void die(void)
{
 if (get_sprite_with_this_brain(9, &current_sprite) == 0)
 {
  screenlock(0);
 playsound(53, 22050, 0, 0, 0);
	playmidi("3.mid");
 }

 //TALK LINE, LETS GRAB THE POTION
&story = 2;
say_stop("THAT was a pain... Let's get that potion.", 1);
&sign = 2;

  int &hold = sp_editor_num(&current_sprite);
  if (&hold != 0)
  editor_type(&hold, 1);
  &save_x = sp_x(&current_sprite, -1);
  &save_y = sp_y(&current_sprite, -1);
  external("emake","small");

}


Potion script:
void talk(void)
{
 sp_seq(&current_sprite, 55);
 sp_brain(&current_sprite, 6);

 if (&sign == 1)  
  {
  say_stop("I'm a little too busy to grab this now!", 1);
  }

 if (&sign == 2)
 { 
  freeze(1);
  say_stop("Now I've got the potion, I can...", 1);
  wait(200);
  say_stop("Hey, there's some kind of flame spell back there!", 1);
  &magic += 3;
  //Give the player a modified Rabidwolf9's firespin magic
  add_magic("item-fspn",437, 6);
  Playsound(10,22050,0,0,0);
  &sign = 3;
  &story = 3;
  sp_brain_parm(&current_sprite, 3);
  sp_brain(&current_sprite, 12);
  sp_touch_damage(&current_sprite, 0);
  sp_timing(&current_sprite, 0);
  int &hold = sp_editor_num(&current_sprite);
  if (&hold != 0)
  editor_type(&hold, 1);
  sp_notouch(&current_sprite, 1);
  sp_nohit(&current_sprite, 1);
  sp_hard(&current_sprite, 1);
  draw_hard_sprite(&current_sprite);
  sp_active(&current_sprite, 0); 
  unfreeze(1);
  say_stop("Sweet! Now, to get this potion back.", 1):
 }
}
December 30th 2009, 05:18 PM
custom_iplaydink.gif
iPLAYdink
Peasant Male Sweden steam
Hmm.. 
You've double-checked that &sign is a global, right?
try commenting out the &sign = 2; in the void die and set &sign to 2 in another script, like when you hit something, if it works to pick up the potion then, the problem should be in the boss script. If you are sure that the problem is in the boss script try to spawn another script in the void die and change the value of &sign in that script.
December 30th 2009, 05:30 PM
spike.gif
scratcher
Bard Male Finland bloop
cigarette bonca 
Try using say() in the boss script, instead of say_stop(). The commands past that probably don't run, since the script stops working soon after the monster is killed.
December 30th 2009, 05:31 PM
slimeg.gif
metatarasal
Bard Male Netherlands
I object 
Solution: Never place a say_stop() command in a void die() procedure, it kills the procedure. So everything after the say_stop() command is not executed, including setting the variable &sign to 2.

EDIT: Dang, scratcher beat me to it...
December 30th 2009, 07:57 PM
bonca.gif
Christiaan
Bard Netherlands xbox
Lazy bum 
I have found this out the hard way as well. Is there any kind of logical explanation to this or is it one of the many glitches in the engine?
December 30th 2009, 10:05 PM
custom_magicman.gif
magicman
Peasant Netherlands steam duck
Mmmm, pizza. 
My attempt at an explanation (it also explains some other possible game freezes):

When a script runs, it runs until it is done. If so, it's the *only* thing that happens. Just the script, nothing else. Not even, say, the Dink engine doing some of its magic like player input. Just the one script.

Butbutbut, you ask, I can walk around while all kinds of scripts are running. What about that?

Simply put, most scripts are over before you know it. For anything else there are the following pausing commands, which give the engine the possibility of dealing with other stuff.

These are a few DinkC commands that tell the Dink engine something like "You can do something else now, if you want". These are say_stop(), say_stop_xy(), wait(), wait_for_button(), move_stop(), and perhaps some others (choice menus, probably? Maybe show_bmp() and activate_bow() as well...). These commands stop running the script until it's ready to continue (text has been said, a certain amount of time has expired, etc). This is where the Dink engine can choose to continue running another script, do some of its own magic, or whatever else it is that it does.

The thing with suddenly stopping die() procedures in enemies is caused by the following two things:
- Actually killing the sprite is one of those other things that the engine can choose to do.
- Killing the sprite kills the script.

So what happens:
- Dink kills monster
- Engine runs die() procedure, and makes sure that the sprite is killed whenever the engine has the chance to do something.
- die() procedure has one of the previously mentioned pausing commands.
- Engine pauses the script, and does something else.
- Engine chooses to kill the sprite.
- Engine kills sprite, and thus the script.
- Engine can no longer continue running the die() procedure.

Commonly-used workaround:
Use script_attach(1000) or script_attach(0). This causes the script to not be on the sprite anymore, so it won't be killed when the engine kills the sprite. Alternatively, put it in its own file, and use spawn(). script_attach() will remove the script from the sprite, and spawn() will run it as an independent script, so it won't be killed when the engine kills off the sprite. Note that in this case &current_sprite can't be used either, because a script needs to be on a sprite to use that.

Another note: once the sprite gets killed, its sprite number has no meaning anymore. This means that you can't just use another variable (say, &crap), and give it the value of &current_sprite, and then use &crap. When I need some post-death animation, I create a clone of the recently deceased sprite, make the deceased sprite invisible, and play around with the clone.

Something similar happens with the touch() procedure:
- Dink touches sprite
- Engine detects Dink touching the sprite
- Engine runs touch() procedure (if touch_damage is -1, of course)
- touch() procedure has one of the previously mentioned pausing commands.
- Engine pauses the script, and does something else.
- Engine detects Dink touching the sprite
- goto 3.

(there's a neat trick that the buttonon() procedure will just trigger once, and also works for Dink-brain, not just mouse-brain).

And also why the game freezes if you don't have a wait() in a loop. This can actually be relaxed to guarantee having one of the pausing commands executed in the loop. If there's no pausing command between the label and the goto, the engine will be given no chance to do anything except running the code. The player experiences this as a gamefreeze.

Hope that clears things up. There's actually more logic to how the engine decides what to do, but I can't be bothered going into that now. Check out the FIFO part of FIFO and variables in DinkC.

EDIT: Whooooaaa, dude. That was quite the post >_>

EDIT2: Right, I feel like I haven't quite said everything I wanted to say. Sorry, dear readers.

About wait(): What it does is tell the Dink engine to "stop running this for at least this amount of milliseconds". If the engine encounters a wait(100), and then does non-pausing things for more than a tenth-second, the wait(100) will take more than a tenth-second. If the engine does non-pausing things for 75 milliseconds, it won't switch back. If it then does more non-pausing things for 75 milliseconds, it can continue. This is after 150 milliseconds, not 100.

Just to make a point that wait(&crap) can't be guaranteed to take &crap milliseconds, though it's quite hard to have it do non-pausing things for 75 milliseconds.
December 31st 2009, 04:33 AM
slimeg.gif
metatarasal
Bard Male Netherlands
I object 
Aye, I noticed that wait() commands are very inaccurate. I did a test how many wait(1)'s are equal to a wait(1000). I got values ranging from 26 to 31. This means that a wait(1) waits for about 30 to 40 ms on my machine on a relatively empty screen (3 sprites including one bonca). This will likely be better on a faster computer though.
December 31st 2009, 05:52 AM
burntree.gif
Fireball5
Peasant Male Australia
Let me heat that up for you... 
I'm sure it is more accurate with higher wait(); vallues, I'm sure it is impossible for the Dink engine to do all its "magic" in one millisecond... of course it's going to take longer. If it was more like wait(50); it would be much more accurate.
December 31st 2009, 10:14 AM
custom_magicman.gif
magicman
Peasant Netherlands steam duck
Mmmm, pizza. 
This indeed. I wonder if metatarasal gets the same results for wait() values up to 30.

If so, it'd mean what Fireball said: The Dink engine needs about 30ms (on meta's machine) to do its magic.
December 31st 2009, 01:02 PM
slimeg.gif
metatarasal
Bard Male Netherlands
I object 
Strangely I don't. I just tested it, and when I use wait(1) I got values around 32, with wait(25) I got values of around 22. This means in practice that a wait(1) command would take about 32 ms to execute and a wait(25) takes 49 ms. Also I found that a wait(50) takes about 71 ms, for values higher than that I'd have to revise my method of measuring to have a sufficient resolution. But this does seem to suggest that even higher values for wait() have quite a bit of room for error.

All of this is, of course, assuming that a wait(1000) takes 1000 ms.

Also, this measurement might be distorted by the fact that the script is initiated on entering the screen, when the engine is a little bit busy. I might set up a more detailed measuring later. (I've gotten a little curious.)
December 31st 2009, 06:42 PM
burntree.gif
Fireball5
Peasant Male Australia
Let me heat that up for you... 
I would imagine that the longer the wait, the less (relative) error. 30 milisecinds out is a big deal for wait(1); but not so much for wait(1000); The former would be thirty times as long whereas the latter would have only been 1.3 times as long.

I'm not sure if this is what happens in the Dink engine, but I doubt any engine can accurately measure exact milliseconds.
December 31st 2009, 07:16 PM
slimeg.gif
metatarasal
Bard Male Netherlands
I object 
1.03 not 1.3
December 31st 2009, 10:47 PM
knightg.gif
PaladinEmet
Peasant Male United States
The Truth is out there 
@magicman:
mo, because the script is in void talk(void), and runs whenever dink talks to the attached sprite

@exdeath:
what do you mean by 'it won't do anything when I talk to pick up the potion from a shelf.'? do you mean it won't say anything (in which case it looks like your global variable's off) or it just won't say what you want it to?
December 31st 2009, 10:55 PM
pq_knight.gif
ExDeathEvn
Peasant Male New Zealand xbox steam
Don't look at me, I'm a ghost 
It wasn't reading at one point. If I froze Dink while speaking after killing the boss it would stay frozen, for example.

The problem's been sorted, at any rate. it was the say"_stop" line, replaced it with say and I can continue now.
Trying to fix it originally occasionalyl presented odd results though.
January 1st 2010, 09:03 PM
custom_magicman.gif
magicman
Peasant Netherlands steam duck
Mmmm, pizza. 
PaladinEmet: No, what? I wasn't talking about Ex-D's script at all, as I was replying to Christiaan's question about why certain stuff happens.