The Dink Network

Why can't I quit you, DinkC?

October 9th 2013, 04:53 AM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Edit: I decided to change the topic title to reflect the fact that this has become more of a general "scripting problems" thread.

I don't know if anybody else has ever done this, but I got sick of having to use global variables to make sure that one-time events don't happen after the first time you see them, so I came up with a different method.

I have a sprite somewhere on the screen, make it not draw, and give it brain 2 (because that brain is hardly ever used). I use get_sprite_with_this_brain to look for brain 2 sprites before executing the event (use wait(1) first so the sprite in question is sure to do its thing). Then I have whatever event transpires kill this sprite using editor_type!

That sounds like a lot of work, but it really isn't. The "event killer" sprites all have the same script attached. Figuring out that this worked (I've tested it) was a big relief to me, as I wanted many things to happen just once in "Malachi the Jerk," but didn't want a whole mess of variables to keep track of whether they'd happened.

What's weird is that I discovered the engine is picky about get_sprite_with_this_brain, at least as concerns if statements.

if (get_sprite_with_this_brain(2, 0) != 0)
{
//this will never, ever run for some reason.
}

if (get_sprite_with_this_brain(2, 0) > 0)
{
//But this works.
}


Let me know if I overlooked some simpler way of doing the same thing. It's certainly possible.

I wasn't sure whether to put this in its own topic or my DMOD topic. Sorry if I put it in the wrong place.
October 9th 2013, 06:13 AM
slimeg.gif
metatarasal
Bard He/Him Netherlands
I object 
Using a global variable every time is pretty excessive indeed. Having many one-time events can really improve the quality of a DMOD, but having a global for all of them is a bit silly. Personally I use a similar technique to yours, it works a little bit differently:

Place some sprite on the screen (usually I take some very noticable out-of-place sprite so it is easily identified in the editor) and attach a script to it. Do a nodraw inside the script (don't do it in the editor as invisible sprites don't execute scripts) and do whatever you wanted to do inside this script. After the script is finished kill it with the editor_type to make it never come back. You might also want to give your sprite a nohit so a fireball doesn't mysteriously explodes in mid-air.

I personally don't see the advantage of placing a script to the room itself and search for the sprite in question. You can just attach the script to the sprite itself! I use this quite often to make sure that a screenlock only occurs the first time the player gets to the screen, so you don't have to get through screenlocked screens many times. I think redink1 really started this with Initiation. He's even made noticable sprites to place on a screen specifically for this purpose.

If you do want to use brains, you can also use exotic numbers. I can remember one dev-file which used brains 95 and 96 to make sure that they probably wouldn't be around by accident.

Also, a different topic for this is much better than in the preview thread. Better to keep discussions a little bit seperated. Besides, more (meaningful) topics, more joy!
October 9th 2013, 09:00 AM
spike.gif
I use that method too, as described by Meta. I seem to be doing it especially often with one-time comments, like if Dink enters a cave and says "Oooh, this must be where those dinkicious brain-eating boncas are coming from!" It would be silly if he just kept repeating that every time.

A somewhat related thing that you might not be aware of are editor_seq and editor_frame. You can set those to whatever, so you actually get two free sprite-specific variables without wasting a single global. E.g.

int &getnum = sp_editor_num(¤t_sprite)
int &num = editor_seq(&getnum,-1)
if (&num == 0)
{
say("`#Dink, I worship you.",¤t_sprite)
editor_seq(&getnum,1)
}
if (&num == 1)
say("`#Dink, I worshipped you already!!",¤t_sprite)


EDIT: Dinkicious!! I can't believe the swear filter can still one-up me after so many years.
October 9th 2013, 10:53 AM
custom_fish.png
SabreTrout
Noble He/Him United Kingdom
Tigertigertiger. 
Yup, editor_seq & frame are what I always used. An absolute godsend.
October 9th 2013, 01:14 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Wow, it didn't occur to me you could set unused brain numbers. I mean, I could conceivably use brain 2 at some point for some kind of bouncing hazard.

I admit I've been using a global to find the event sprite. I'm still new at this. The reason I was doing it like this was so I could attach the event to another sprite and make THEM say or do something more easily.

You're correct that I wasn't aware of editor_seq and editor_frame. You're blowing my mind right now. So I could use this to determine how many times the player has talked to somebody instead of a global?
October 9th 2013, 02:03 PM
slimeg.gif
metatarasal
Bard He/Him Netherlands
I object 
The editor_seq and editor_frame are set to the sequence and frame number that a sprite should have when it is of a certain editor_type. This is important for, say barrels that should stay down. When you're not messing with the editor_type the editor_seq and editor_frame aren't used by the engine but may still hold information. So essentially you get two variables you can use to store whatever you want. So you could indeed keep track of how many times the player has talked to somebody using this. It is a very very nice trick to save globals.

Keep in mind though that editor_frame only holds numbers up to 255, so to keep track of how many times the player talked to someone you're probably better off using editor_seq. Editor_seq has a maximum of 65535 I believe.
October 9th 2013, 02:31 PM
knights.gif
DinkKiller
Peasant He/Him United States
The world could always use more heroes 
This actually helps me with that new idea I came up with for my D-mod related to the name change. Thanks guys, this helps me a lot. And good luck cocomonkey!
October 9th 2013, 02:46 PM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
Yep! Here's a simple talk counter:

void main( void )
{
  int &ednum = sp_editor_num(&current_sprite);
  int &count;
}

void talk( void )
{
  &count = editor_seq(&ednum, -1);
  &count += 1;
  editor_seq(&ednum,&count);
  say_stop("`5You've talked &count times to me.", &current_sprite);
}


The main difference with globals is that this information is attached to editor sprites. If you've used create_sprite(), this talk counter won't work, as sprites created with create_sprite() don't have an sp_editor_num().

Also, when an NPC moves from the pub to his house (due to storyline, or whatever), it'll be a different editor sprite.
October 9th 2013, 07:57 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Incidentally, I use ducks for all of my events. Beheaded ducks.
October 9th 2013, 08:31 PM
wizardg.gif
leprochaun
Peasant He/Him Japan bloop
Responsible for making things not look like ass 
Incidentally, I use ducks for all of my events. Beheaded ducks.

You even run an sp() loop that changes all sprites into beheaded ducks. You're one crazy guy.
October 9th 2013, 10:41 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Um, well the player never actually sees these beheaded ducks.

But they're there... manipulating events behind the scenes...

...Just like in real life. Wait, what?
October 10th 2013, 04:40 AM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Since I've started using this method, I've had a problem where sometimes an enemy on a screen that uses it whose die procedure sets its editor_type to 6 is back instantly the next time I return. It's never more than one monster per screen.

Anybody know how this could happen/how to fix it? I'm using scripts from/based on thenewguy's Dink Script Improvement Pack, if that helps.

October 10th 2013, 08:16 PM
goblins.gif
Hmm, I've always just set the sp_active(&current_sprite, 0) or kill_this_task() when done with an event and after setting the editor_type if I don't want to see the script again. If I still need the script to exist to do something later I can just use a global like &story.

if (&story == 1)
{
    //event happens
    //event is done, now kill this script
    &story = 2;
    kill_this_task();
}

//run alternate event
//event is done, now kill this script
kill_this_task();


This method hasn't failed me yet.

Anybody know how this could happen/how to fix it? I'm using scripts from/based on thenewguy's Dink Script Improvement Pack, if that helps.

If it's any reassurance I don't believe I did anything with the editor number or sequence on any of the DSIP scripts. That doesn't mean there couldn't be some kind of incompatibility, though. Let me know if a solution is found.
October 10th 2013, 08:52 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Well, I thought I was just doing too much with those &jug globals, but I tried switching the enemy scripts in question back to the local variable method and it didn't fix it.
October 10th 2013, 09:45 PM
goblins.gif
&jug, &jugb, and &jugc should be able to be used to your discretion however you want without any glitches, so long as you don't have a wait() statement or equivalent (like move_stop or say_stop) anywhere and use them within the same script. Even if you do use wait() the only real issue should be the variable has a chance to have changed in the meantime, which would only cause errors in the script with the wait() statements or equivalents. So I'm not sure if your problem is related to the modified scripts or not, but it probably has nothing to do with the juggle variables if so.

Good luck. You can always try using the method in my previous post if it's sufficient for your purposes, though that may require some rewriting of your scripts to do so...I don't know why your editor variables would be changing.

Maybe, post the script of one your problem enemies whose editor variables are giving you problems?
October 10th 2013, 11:22 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
It can't be the enemies. I haven't changed your enemy scripts except to mess with speed, hitpoints, exp, etc.

Maybe it's the event script. The brain 20 sprite checked for here exists to see if you've ever done this before. It's placed in the editor, but given a brain in a script (that and nodraw are all the script does).

//script to make stairs appear when you beat enemies and stay there later
void main
{
wait(1)

	if (get_sprite_with_this_brain(20, 0) == 0)
	{
	goto stairs
	}
	
loop:
wait(250)

if (get_sprite_with_this_brain(9, 0) == 0)
{
int &junk = get_sprite_with_this_brain(20, 0)
int &crap = sp_editor_num(&junk)
editor_type(&crap, 1)
playsound(43, 22050,0,0,0);
stairs:
	if (&player_map == 644)
	{
	&jugb = create_sprite(90, 47, 0, 428, 1)
	}

	if (&player_map == 675)
	{
	&jugb = create_sprite(56, 261, 0, 428, 1)
	}
	
	if (&player_map == 737)
	{
	&jugb = create_sprite(52, 264, 0, 428, 1)
	}
	
	if (&player_map == 739)
	{
	&jugb = create_sprite(112, 190, 0, 428, 4)
	}

sp_script(&jugb, "warper")
return
//for some danged reason if I used kill_this_task here it worked on some screens but not others
//I spent hours trying to figure this out
//DINKC, WHY CAN'T I QUIT YOU
}
goto loop
}


All "warper" does is move Dink around; it's what you'd expect. I don't bother with fading down and up because they are just stairs.

Just in case it's somehow responsible, here's part of it. It looks like that script up there in that I have it do different things depending on &player_map.

if (&player_map == 739)
	{
	playsound(39, 22050, 0, 0, 0)
	&player_map = 675
	sp_x(1, 184)
	sp_y(1, 136)
	goto draw
	}

draw:
load_screen()
draw_screen()


I'm at a loss. Why would monsters reappear? It doesn't make any sense. The monsters' die procedure looks like it did in DSIP.

That is to say, like this:

void die( void )
{
  &jug = sp_editor_num(&current_sprite);
  if (&jug != 0)
  editor_type(&jug, 6); 
	
	&save_x = sp_x(&current_sprite, -1);
	&save_y = sp_y(&current_sprite, -1);
	external("emake","small");
}
October 10th 2013, 11:32 PM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
if (get_sprite_with_this_brain(2, 0) != 0)

DinkC is weird. It is unclear whether things like this work. In my preprocessor, I never generate any expressions more complex than a simple compare in an if for that reason; instead, I create a variable before it, and use that in the if:

int &tmp = get_sprite_with_this_brain(2,0);
if (&tmp != 0)
...


It's probably not needed most of the time, but it is needed sometimes, and I have no motivation at all to find out the details of what does and what doesn't work. I know it always works if you put the function call on a line of its own.

For finding other sprites, I have seen DMODs that give those sprites a script which sets a global in their main function (to &current_sprite), and the other script can use this global.

That works; my editor does it better (it doesn't waste a global on it): it allows you to use sp("name"), where name is the name of the sprite; it will be replaced by its editor_num, and sp(num) will return its sprite number on the screen (which is not predictable for the editor). However, that method requires you to know the editor_num; my editor gives you tools to know it, but if you try this with any other editor, I think you are waiting for bugs to pop up; it's just too easy to change the editor_num of a sprite (changing the name doesn't happen by accident, but the other editors don't have sprite names).
October 10th 2013, 11:34 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
My brain check works as far as the fact that the next time you enter that screen, it makes the stairs right away like it's supposed to.
October 10th 2013, 11:42 PM
spike.gif
All "warper" does is move Dink around; it's what you'd expect. I don't bother with fading down and up because they are just stairs.

I believe this is the problem - your warps. The method by which you change the screen is not "natural" (that is, you use load_screen and draw_screen), so the 6 minute delay doesn't work for some reason. I'm actually surprised if any of the sprites on the screen are gone, if you kill them all at once without changing screens in a normal way in the meantime...

Since my memory seems to be swiss cheese recently, I went and tested this with pillbugs; if you kill all pillbugs on screen 2, then console yourself to screen 1 with load_screen and draw_screen, the pillbugs will be back. However, if you walk to the next screen and back, they will be gone like they're supposed to.
October 10th 2013, 11:51 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Actually, I just tested this again and in eight tries I didn't have a single enemy reappear this time. I dunno.
October 11th 2013, 01:10 AM
goblins.gif
Oh...that's highly likely. For instance, if you go into secret stairs after burning trees, it likes to bring the enemies immediately back to life when you resurface. Kind of annoying.

If you are concerned enough with the problem, you might have to do a check for the monster brains and the editor types and manually delete monsters with editor type 6 when doing those kinds of warps. I haven't tested this method myself, but I think it could work.
October 11th 2013, 01:15 AM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Thanks to leprochaun and others' help on IRC, I have fixed this bug by using editor-placed warps that are first set to not draw or be hard and then re-activated instead of using scripted warps. hoorah.
October 11th 2013, 01:27 AM
goblins.gif
Can you go into more detail, or post the script? I'd love to fix this problem in my DMOD as well.
October 11th 2013, 01:28 AM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Sure, I'll do that once I have a final version of the script. The one I've got right now is a real mess I whipped up just to prove I can get it working.
October 11th 2013, 01:45 AM
goblins.gif
Thanks, and no problem.
October 11th 2013, 03:18 AM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Okay. Here is a script you can attach to an ordinary warp that will (if there's a sprite on screen with brain 20) cause it not to appear until you've killed all enemies. It kills the brain 20 sprite so that it will always appear after that. I've tested it and it works.

If you don't like the method of looking for a brain, use a global instead.

void main
{
wait(1)
int &kill = get_sprite_with_this_brain(20, 0)
if (&kill == 0)
{
kill_this_task()
}

sp_nodraw(¤t_sprite, 1)
sp_hard(¤t_sprite, 1)
draw_hard_sprite(&current_sprite)

loop:
wait(250)
if (get_sprite_with_this_brain(9, 0) == 0)
{
playsound(43, 22050,0,0,0)
int &eddy = sp_editor_num(&kill)
editor_type(&eddy, 1)
sp_nodraw(&current_sprite, 0)
sp_hard(&current_sprite, 0)
draw_hard_sprite(&current_sprite)
kill_this_task()
}
goto loop
}


Edit: I have got no idea what caused all my "&current_sprite" to be replaced by a weird character. Fixed.
October 22nd 2013, 04:10 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Hey, you can use semicolons inside a dialogue string. I didn't think that would work.
October 30th 2013, 01:58 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Arrrgh. Okay, can anybody tell me why my script that checks to see what you hit something with doesn't work?

It's called from other scripts like this...

void hit
{
external("hitcheck", "main")
if (&hitcheck == 1)
{
//hit text for fists
}

if (&hitcheck == 2)
{
//hit text for weapon 2
}

if (&hitcheck == 10)
{
//hit text for fireball
}


&hitcheck is a global I declared explicitly for this. I was using &jugb, but when it didn't work I tried giving it its own var to see if that fixed it. It didn't.

Here's the hitchecker script itself:

//hitcheck.c
void main
if (&missle_source == 1)
{
weapon()
}
else
{
//Okay, you threw SOMETHING at it
magic()
}
}

void weapon
{
&jugc = compare_weapon("item-fst")
if (&jugc == 1)
{
&hitcheck = 1
//1 then we know it's fist
return
}

&jugc = compare_weapon("item-swl")
//yes, this IS what I named my sword script
if (&jugc == 1)
{
&hitcheck = 2
//2 = sword 1
return
}

//more weapons to add here later
}

void magic
{
&jugc = compare_magic("item-fb")
if (&jugc == 1)
{
&hitcheck = 10
//10 is fireball
return
}
//more magic to add here later, I'll also check for the throwing axe
}


Sometimes it'll work, usually it won't. It'll read the sword as the fists for some absolutely unfathomable reason. I am banging my face into the keyboard over this.

Oh, and if you're wondering why I used compare_magic to see if you have the fireball equipped rather than looking for dam_fire, I tried that and it absolutely never worked, whereas I've had this method work for the fireball sometimes, despite it never once working for the sword. I have NO IDEA. I had a script's hit procedure just have Dink say "&hitcheck", and the fists and the fireball produce the expected values, but the sword gives whatever the value already was. Help?

Edit: Hell, I just noticed a missing equals sign in the sword check. How did I miss that the last five times I went over this? Ugh.

With that and a couple of changes to the calling scripts, I seem to have gotten this working properly. Sorry for bringing it up.
October 30th 2013, 02:50 PM
wizardg.gif
leprochaun
Peasant He/Him Japan bloop
Responsible for making things not look like ass 
external() runs after the current script finishes. So it goes through all those if(&hitcheck == #) before hitcheck.c runs.
October 30th 2013, 03:15 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Really? It seems to work now. I thought the script paused to run the external script. The DinkC reference says, "The script using external will wait until procedure has finished before it resumes operation."
October 30th 2013, 03:21 PM
wizardg.gif
leprochaun
Peasant He/Him Japan bloop
Responsible for making things not look like ass 
I'm pretty sure it runs after the current script finishes. That's why it causes problems when you use an external in a script with a loop.
October 30th 2013, 04:14 PM
spike.gif
Nuh-uh, it runs right away. If the externalled script used a loop, that could potentially be a problem, because then operation would never return to the procedure that called the external.
November 3rd 2013, 01:28 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
So... enemy brains.

Do they really HAVE to be 9 or 10? Can you make them something else and still have Dink fight something? I am trying to have an enemy move along a set path (move_stop) while repeating a sequence (brain 6), but whenever Dink hits it, the sprite freezes and stops executing its move_stop commands (the sprite can still damage Dink at this point, if he walks into it).

Actually, that's what happened when I had the enemy be a normal brain 9 enemy at first and change when it had a certain amount of hitpoints left. I tried replacing it with a new sprite instead, and that fared better, going through its movement path no matter what, but it still won't take damage when hit. Is this impossible? I hope not, because the boss fight I've made here would be really cool if it actually worked.
November 3rd 2013, 07:32 AM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
I'm pretty sure it's possible, but let me first explain what the problem is you're seeing.

DinkC has a pretty weird way of multi-threading. There are several threads ("scripts") that can run concurrently, but not in the way they do in other systems.

Firstly, there is no preemption (they don't interrupt each other). This means a running script will not be interrupted by another script; events are not handled except when no script is running. This is ok, because the script stops running when it does wait (or *_stop), so at that point another script can run. This means it feels like all scripts run at the same time.

However, here's the tricky thing: while every other program I know would start a new script for a new event, DinkC DOES NOT. When you hit an enemy, it checks if there is already a script attached to that enemy and if so, it will tell this script to continue running from the event function. This is fine if it's doing nothing (the last event was handled and has returned), but it is very bad if the last event was still running, for example doing a move_stop. Because in that case the old event function will be aborted and execution will instead go to the hit function. When that returns, it will not go back to the original event (which would have made sense), but it will just stop and wait for a new event.

You can imagine that a sprite which has an endless loop of move_stop commands does not like this at all. When you hit it, the loop is interrupted and it is not resumed.

As a solution, I'd say you should keep a counter of which part of the move is currently being done in a variable (it doesn't have to be global; non-global variables are per-script, and all this is within one script, that's the whole reason this problem exists in the first place), and at the end of the hit function (and any other function that you want to work) explicitly restart the loop. The loop must then check this variable to know which part of the move it needs to continue with.

Does that make any sense?
November 3rd 2013, 09:10 AM
wizardg.gif
leprochaun
Peasant He/Him Japan bloop
Responsible for making things not look like ass 
Is the script that moves the sprite attached to that sprite, or something else entirely?

If it is attached to that sprite, does the script have a hit() or touch() proc? Because what you described really makes it seem like the sprite stops as soon as it's hit- which implies there's something in a hit() proc.

Do brain 6 sprites even understand hitpoints? When you replaced the sprite did you make sure to declare its hitpoints?
November 3rd 2013, 12:21 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
The script that moves the sprite is attached to the new "phase two" sprite using the sp_script command.

Yes, I tried declaring the hitpoints before and after changing the brain to 6.

If brain 6 sprites can't have hit points, I wish this sort of thing was in the DinkC reference... I wish there were something to get a sprite to continuously loop a sequence without changing its brain.

Sure, it would be easy enough to count which of the 28 move commands in my loop is executing... maybe I could have it change the brain back to 9 when you hit it, then change back to 6 and redo the move command it was just doing... If brain 6 really doesn't understand hit points, I don't know that this would fix anything
November 3rd 2013, 01:57 PM
spike.gif
I can't recall if brain 6 can be damaged, but the damage does register as long as the sprite has hitpoints, so changing the brain to 9 when the sprite is punched should work. (If you hit a brain 0 sprite 10 times, once you change the brain to 9, the sprite will receive 10x damage. It's really cool, actually!)

Regarding script interruption, one way to avoid that is to external() whatever you want to loop. Either that, or gotos in every procedure that can interrupt the movement.
November 3rd 2013, 04:36 PM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
... why the heck does that even work XD

Oh, DinkC, you've done it again. I need to play around with this, now
November 3rd 2013, 06:43 PM
goblins.gif
I use a technique where I use a "head" of a complex enemy and a "body" which are two separate sprites. The head does the hard work, loops, and whatnot to get the effects and attacks done, while the body is invisible and follows the position of the head, and takes the damage from Dink. The head has 0 hp while the body holds the true hp of the enemy.
November 3rd 2013, 11:33 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Having anything at all in the hit procedure seems to make the sprite freeze in the middle of its movement. I can think of a way around that, but it's complicated. Having an invisible sprite on top of it that takes the actual damage sounds more appealing to me.

Um... how would you make that sprite follow the brain 6 sprite? I've never done anything like that.
November 4th 2013, 12:35 AM
goblins.gif
Note that this specific code only works if the enemy is the only object with it's brain during the setup. It also requires &jug to be initialized or to be replaced with a local variable. It is probably possible to improve the code to make it less dependent on specific brains and to allow multiple enemies but I haven't gotten it to work that way yet.

The "head" (boss1a.c):

void main( void )
{
    int &body;
    //now set brain, touch damage, speed, timing, etc.
    sp_brain(&current_sprite, [brain]);
    sp_speed(&current_sprite, [speed]);
    sp_timing(&current_sprite, [timing]);
    sp_touch_damage(&current_sprite, [touch damage]);
    sp_base_walk(&current_sprite, [base_walk]);
    sp_target(&current_sprite, 1);
    //nohit so that arrows/fireballs and stuff don't hit him instead of the body.
    sp_nohit(&current_sprite, 1);
    
    //replace coordinates and sprite with the correct values
    //even though the body is invisible it still must use the same graphic so that
    //collisions can happen properly (unless you want to use a different collision sprite)
    &body = create_sprite([100],[100],[16],[100],[0]);
    sp_script(&body, "boss1b");
    //if you need to do anything with the body from here on out, you have the &body variable
}


The "body" (boss1b.c):

void main( void )
{
    int &head;
    //first set the stats
    //sp_hitpoints and such goes here
    //be careful to set the brain to a different brain than the "head"
    sp_brain(&current_sprite, [9 or 10]);
    sp_hitpoints(&current_sprite, [hp]);
    sp_defense(&current_sprite, [defense]);
    sp_base_walk(&current_sprite, [same as head]);
    //set nodraw so that the body can't be seen
    sp_nodraw(&current_sprite, 1);

    //then we must find the head and put it in a variable
    &head = get_sprite_with_this_brain([brainofhead], &current_sprite);

mainloop:
    //get same x as head
    &jug = sp_x(&head, -1);
    sp_x(&current_sprite, &jug);
	
    //get same y as head
    &jug = sp_y(&head, -1);
    sp_y(&current_sprite, &jug);

    //get same facing as head (for collisions sake)
    &jug = sp_dir(&head, -1);
    sp_dir(&current_sprite, &jug);

    //wait(0) will wait the minimum amount of time and update the position precisely
    wait(0);
	
    goto mainloop;
}

void hit( void )
{
    //then if you need a hit procedure (more than likely you do)
    //do whatever hit procedure should do, then at the end, return to mainloop like so
    goto mainloop;
}


Hopefully I got that all down right, let me know if you have any issues or need help trying to do something specific with it.
November 4th 2013, 01:00 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Thank you. My sprite will have no base walk because it's just repeating an animation, but I think this should still work, since I've experimented and the brain of 6 seemed to be the only thing that was keeping the sprite from taking damage.
November 4th 2013, 01:44 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Hey, what do you know, it works!

Thanks so much, I would have beat my head against that particular wall for ages!
November 4th 2013, 01:47 AM
goblins.gif
Awesome!

Glad to be of help.
November 5th 2013, 12:14 PM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
... why the heck does that even work

Using external to avoid killing the script? I would think that makes sense: the original script spawns a new one and enters the "waiting for reply" state. Then the sprite is hit, which will abort whatever the sprite was doing (waiting) and instead start hit(). The spawned script is not involved, and does not notice a thing.

The question is, what happens when the spawned script returns? Will it force the original script to resume from where it was called, aborting whatever it was doing by now? Or will it be ignored? Only one way to find out.
November 5th 2013, 06:52 PM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
For a while I have been wanting to write up a good essay about the different ways to jump in code, to run code in other scripts, and stuff like that. I'll probably make a different post about it.

The answer to that question is: "It will be ignored". Perhaps a weirder observation is this:

void talk( void )
{
  say_stop("Talk!",1);
  stuff();
  say_stop("No talk!",1);
}

void hit( void )
{
  say_stop("Hit!",1);
  // A.k.a. A long time.
  wait(100000);
  say_stop("No hit!",1);
}

void stuff( void )
{
  say_stop("Stuff!",1);
  // A.k.a. Not quite a long time.
  wait(10000);
  say_stop("No stuff!",1);
}


I talk to the sprite, and see "Talk!", followed by "Stuff!". When "Stuff!" disappears, I punch the sprite, and "Hit!" appears. Not quite a long time later (say, 10 seconds, give or take ), "No stuff!" appears. This is immediately followed by "No hit!". "No talk!" never appears, which is consistent with the way scripts are spawned. I'm rather surprised at not having to wait over a minute for "No hit!" to appear.

Something related that actually managed to make a game crash for me comes down to the following. This script won't crash, but try to figure out what'll happen before reading on:

void talk( void )
{
  int &scripts = scripts_used();
  say_stop("Talk 1: &scripts",1);
  stuff();
  &scripts = scripts_used();
  say_stop("Talk 2: &scripts",1);
  &scripts = scripts_used();
  say_stop("Talk 3: &scripts",1);
}

void stuff( void )
{
  int &scripts = scripts_used();
  say_stop("Stuff: &scripts",1);
}


Got all that? Got an idea as to what will happen? Excellent.

I talk to the sprite. The following happens:
"Talk 1: 3" (As it happens: screen base script, the sprite's script, fist script)
"Stuff: 4" (screen base script, the sprite's script, the script that's just been spawned for stuff(), fist script)
"Talk 2: 4" (screen base script, the sprite's script, fist script, ... the script that's just been spawned for stuff()?)
"Talk 3: 3" (the original 3 again)

Conclusion: Until a script yields control, any scripts spawned by proc()s or external()s won't get garbage collected.

The more complicated version I had running, managed to crash the game by running into the script limit of all things.
November 5th 2013, 06:58 PM
wizardg.gif
leprochaun
Peasant He/Him Japan bloop
Responsible for making things not look like ass 
YAY! Magicman's scripts are environmentally friendly!
November 5th 2013, 07:07 PM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
The answer to that question is: "It will be ignored".

Your tests contradict that. Instead, it will resume doing whatever it was waiting for, without finishing the wait. Since the script is not running itself, it must be waiting for something. Whether it is the next event, a wait or *_stop command, or the function returning.

This could have been useful, I suppose, if scripts weren't so extremely fragile. Any event and your carefully crafted setup is destroyed.
November 5th 2013, 07:19 PM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
Perhaps I understood you incorrectly? I meant that the point from where the spawned script was called will be ignored. When the spawned script returns, nothing happens. Well... probably the value of &return will be set, haven't played with that yet (and I think this'll be very tricky to check, seeing how all built-in functions *also* set &return, any suggestions?), but from the things I've tried, the control flow does not change once hitting it has stopped the "let's wait for the spawned script"-thing.

void talk( void )
{
  say("Hello",1);
  stuff();
  say("Bye",1);
}

void hit( void )
{
  say("Boo",1);
}

void stuff( void )
{
  wait(10000);
  say_stop("Mneh",1);
}


When just talking, I see "Hello", "Mneh", "Bye". When talking and then hitting, I see "Hello", "Boo", "Mneh", but never "Bye".

EDIT: Oh, hey, I guess you mean that, when not interrupted by a hit, the point from where the script was spawned is not ignored. Yeah, that's true. I was mostly still thinking in terms of interrupted scripts.
November 5th 2013, 07:52 PM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
I ran into very odd problems when calling custom procedures like that when working on "Malachi the Jerk." These problems were sometimes fixed by putting things in another script instead.
November 5th 2013, 08:06 PM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
Perhaps I understood you incorrectly?

It seems so.

I meant that the point from where the spawned script was called will be ignored.

I meant the fact that the spawned script returned would be ignored.

When the spawned script returns, nothing happens.

That's what I meant. But it's not true, according to your test: the calling script will stop waiting, which is quite different from "nothing". Even if it is by now waiting for something completely different, it still stops waiting.

Most of the time, the event that interrupted the call will have completed, and it is waiting for the next event. In that case, it can't really continue, so it will immediately start waiting again. But if it was waiting for a wait() (and I'm guessing also a say_stop or move_stop), the waiting is aborted and the script immediately continues. If the returning of the spawned script would be ignored, it would have no influence on this waiting (or on anything else, of course). So I conclude that it is not ignored.
November 5th 2013, 08:16 PM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
I'd like to see that code, actually (or a minimal example that also exhibits the same behaviour). I find stuff like this immensely interesting.

An important thing to know about calling other procedures is that this won't share any local variables (¤t_sprite works just fine, though. ¤t_script will actually have a different value inside the called procedure, due to having spawned a new script instance).

void main( void )
{
  int &crap = 3;
}

void talk( void )
{
  say_stop("&crap",1);
  stuff();
  &crap += 1;
  say_stop("&crap",1);
}

void stuff( void )
{
  &crap += 1;
  say_stop("&crap",1);
}


When talking to this, Dink first says "3", then "crap" (with the c underlined), then "4". Subsequently talking to it, we'll see "4", "crap" (with c underlined), "5".

The following:

void main( void )
{
  int &crap = 300;
}

void talk( void )
{
  say("Now I'm here!",¤t_sprite);
  stuff();
  say("Now I'm here!",¤t_sprite);
}

void stuff( void )
{
  sp_x(¤t_sprite, &crap);
}


Will cause the sprite to have an x-coordinate of 0. Essentially, this means that uninitialized variables will be a partially underlined variable name when displayed through say and friends, and will be 0 when used as a number.
November 5th 2013, 10:21 PM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
I'd like to see that code, actually

I was talking about your example, so I think you have the code.

Anyway, I just checked, and it is correct that returning from a function will make the script resume, no matter what it was waiting for (I tested wait, move_stop and say_stop; are there any others?) Here's the script:

void main ()
{
        wait (1); // This is required.
        run ();
        // This is not reached if you talk to the sprite in time.
        freeze (1);
        say_stop ("Too late!", &current_sprite);
        unfreeze (1);
}

void run ()
{
        wait (5000); // 5 seconds after the script starts, resume something.
}

void talk ()
{
        freeze (1);
        move_stop (&current_sprite, 6, 600, 1);
        // Execution can resumed from here before  the move is completed.
        say_stop ("Somebody stop me!", &current_sprite);
        unfreeze (1);
}


If you talk to the sprite within 5 seconds of entering the screen (or in my case, with a single-screen test dmod, starting the dmod), it will talk when those 5 seconds are up, and then dink unfreezes. Effectively, this turns the move_stop into a move (the move does continue, and it does stop when it reaches 600).

In Freedink it doesn't underline, it just prints the & sign. The underlining sounds like a failed attempt to provide this as a "color". After all, underlining was treated as a color code on ancient (text only) video cards. You can check if it also underlines if you put the & in a different position than the first character. Another option is that the text renderer that Dink uses (directX, I think?) supports this as a way to mark hotkeys. Freedink uses a different renderer (SDL), so that would explain the difference.
November 23rd 2013, 07:12 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Has anybody ever made brain 9 enemies that cast harm like the brain 10 enemies? Has anyone ever made enemies that both attack AND cast?
November 23rd 2013, 07:48 PM
spike.gif
Sure.

...not the most substantial reply, I know. But I didn't have any problems, so I'm not sure where you're going with the question.
November 23rd 2013, 07:55 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Oh, I haven't tried yet and I was just wondering if there were any problems doing that. Thanks.
November 24th 2013, 12:45 AM
wizardg.gif
leprochaun
Peasant He/Him Japan bloop
Responsible for making things not look like ass 
It's my understanding that brain 10 was meant for enemies that move in non-diagonal directions. Dragons have brain 10 because their seqs are 2, 4, 6, and 8 rather than all the other enemies' 1, 3, 7, and 9 seqs.
November 24th 2013, 01:00 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
It's also different in that brain 10 enemies don't pursue their target.
November 24th 2013, 04:09 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Aw, hell. In my hitcheck script above, I commented that I'd check for the throwing axe in the magic procedure because missle_source isn't 1, but that doesn't work. It thinks you threw a fireball if fireball is equipped and so on because I'm checking what's equipped instead of what hits.

On the other hand, back when I tried checking for dam-fire, it didn't ever register at all. I'm confused again.
November 24th 2013, 09:54 AM
custom_skull.gif
Skull
Peasant He/Him Finland bloop
A Disembodied Sod 
It's also different in that brain 10 enemies don't pursue their target.

And also don't effect screenlocks.
November 24th 2013, 11:03 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
That depends on what mechanism you have unlocking the screen. It's easy to make it check for brain 10 enemies, like this code from the DinkC Reference:

loop:
wait(250);
if (get_sprite_with_this_brain(9, 0) == 0)
{
if (get_sprite_with_this_brain(10, 0) == 0)
{
// Remove the screenlock
screenlock(0);
}
}


It's true that in the original game, the screen would unlock as long as there were no brain 9 enemies, but this checks for both 9 and 10.
November 24th 2013, 11:25 AM
custom_skull.gif
Skull
Peasant He/Him Finland bloop
A Disembodied Sod 
Yeah, that's true. I was referring to the original game, and that you can't just use your normal screenlocking mechanism for brain 10 enemies.
December 14th 2013, 11:44 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
I ran into the bug from Hell.

I put a new title screen into my DMOD. It was a 32-bit color image. When I tried running the mod without true color mode on, my computer crashed. When I started it up again, all my maps and hardness had been ruined. I was able to copy over backup map.dat and hard.dat files, and I soon caught up to where I'd been. I thought I was fine.

Several hours later, I discovered that a certain crucial screen had developed a problem that was impossible to fix. I don't know how this happened, but the screen rejected scripts. The screen script wouldn't run, and any sprite with a script attached to it would simply not exist. Deleting the screen and making a new one didn't help. I realized that not only could I not fix this, but I couldn't be sure how many screens might have this or other inscrutable problems. I had no choice but to revert to a backup from a couple of days ago (a couple of days I've spent nonstop working on this).



Incidentally, I've made the title screen a 16-bit image and it no longer causes crashes.

EDIT: Whup, It turns out that my save files were corrupted, and that was somehow causing the problem. Not as bad as I thought.
December 16th 2013, 01:03 AM
goblins.gif
Yikes, I'm glad you got it handled, I've never heard anything like that! I do know that Dink crashes when you use 32 bit images (they must be 24 bit or lower) but I've never had a problem where it screws everything up like that or literally crashes the entire computer.
December 16th 2013, 04:07 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
I'm testing now to get ready for beta, and I've run into a big problem.

It's that boss with the invisible brain 9 "body" that takes damage for the visible brain 6 "head". If you throw fireballs at it, they hit it just fine and it takes damage as expected, but swiping your sword at it is no good. Since it's not quite 100% guaranteed that the player will even HAVE fireball at this point, this is a big problem. I can't figure out what's going on here at all.

The "body" is created with these lines in the script of the "head," which bounces around the room and has nohit set to 1:

&body = create_sprite(359, 224, 9, 780, 1)
sp_script(&body, "topbody")


And here's the main procedure for the "body" (it has no hit procedure):

void main
{
int &head
sp_brain(&current_sprite, 9)
sp_hitpoints(&current_sprite, 50)
sp_defense(&current_sprite, 4)
sp_nodraw(&current_sprite, 1)
//get sprite # of the "head"
&head = get_sprite_with_this_brain(6, 0)

mainloop:
//thenewguy came up with this sensible method of making sure this stays on top of the "head" sprite
&jug = sp_x(&head, -1)
sp_x(&current_sprite, &jug)

&jug = sp_y(&head, -1)
sp_y(&current_sprite, &jug)

//he had sp_dir here but it isn't necessary since it's just a looping animation really

wait(0)
goto mainloop
}


I'm certain it worked correctly when I tested it during development... what on Earth could be wrong here?

Oh... while I've been tinkering around trying to fix it, it stopped getting hurt by fireballs too. That's great.
December 16th 2013, 04:19 PM
dinkdead.gif
If it had a hit procedure then hitting it would cause the main loop to stop running, perhaps it also stops looping even though there is no hit procedure and so the body and head get separated? Perhaps it's not getting hit because it's the other side of the room...

It's the only thing I can think of right now. Easy to check by making the body visible while testing.

Edit: though that wouldn't explain the difference between fireballs and swords...
December 16th 2013, 04:30 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
I figured it out: The body wasn't moving at all. My fireballs hit it because they hit where it actually was. It wasn't getting the number of the "head." I switched to just declaring a global for the "head" and it works now.

There's a big heart on the screen, and get_sprite_with_this_brain was getting it (it's brain 6, after all). Once again, I'm a moron.

Honestly, this topic should be called "cocomonkey's a moron: Here is some proof."
December 17th 2013, 04:34 AM
knights.gif
DinkKiller
Peasant He/Him United States
The world could always use more heroes 
You seem to be doing much more epic and difficult things with DinkC than I would ever attempt. I doubt I'd ever get most of what you're doing to ever work even half-way correctly.
December 17th 2013, 04:47 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
I have a Bonca that regenerates 10 HP every 2 seconds (if it's at least 10 under its max) and announces this to you. Sometimes it works and sometimes it doesn't. On a screen with 3 of them, it works on 2 but not the third, and it never works on a screen with just 1. I'm kind of tempted to just shrug my shoulders at this one, since it's just a regular enemy and not a boss, but here's another puzzle for everybody.

Code:

void main( void )
{
	sp_brain(&current_sprite, 9);
	sp_speed(&current_sprite, 3);
	sp_distance(&current_sprite, 50);
	sp_range(&current_sprite, 30);
	sp_exp(&current_sprite, 400);
	sp_base_walk(&current_sprite, 600);
	sp_base_death(&current_sprite, 550);
	sp_base_attack(&current_sprite, 590);
	sp_defense(&current_sprite, 5);
	sp_strength(&current_sprite, 28);
	sp_touch_damage(&current_sprite, 15);
	sp_hitpoints(&current_sprite, 175);
	//preload_seqs are here in the real script, blah
	
	regen()
}

void regen
{
int &heal
//recover 10 health every 2 seconds
heal:
wait(2000)
&heal = sp_hitpoints(&current_sprite, -1)
if (&heal <= 165)
{
&heal += 10
sp_hitpoints(&current_sprite, &heal)
say("`0+10 HP! HP: &heal", &current_sprite)
}
goto heal
}

//rest of script is ordinary bonca stuff
December 17th 2013, 05:10 AM
slimeg.gif
metatarasal
Bard He/Him Netherlands
I object 
When you hit (or talk to, when the bonca's script allows this) the script will move to the appropriate procedure, and break the healing loop you set up.

You can fix this in multiple ways, one of them is by simply adding "goto heal;" at the end of the hit procedure. Unfortunately that still means that the loop gets restarted every time the monster is hit, so the player can prevent the bonca from healing by hitting it at least ever two seconds. You can (somewhat) get around that by splitting up the wait into multiple wait() commands so the loop continues where it was (approximately) after being hit. Remember that each wait must be at least 50 or so milliseconds long for it to be somewhat reliable in its duration.

The other possibility is to do the healing loop in another script, but you must be careful to track whether or not the bonca is still alive.
December 17th 2013, 12:06 PM
wizardg.gif
leprochaun
Peasant He/Him Japan bloop
Responsible for making things not look like ass 
In the dmod I'm currently working on- in which enemies all have their own special ability, I run everything through their hit() proc. Which made me change from running things via wait() commands. They're still there at the end of the proc in case it doesn't get hit for a while. But most enemies tend to activate abilities based on number of hits taken or percentage of health lost. Others cast spells through the attack() proc, or just activate by chance.

You might be able to use a set_callback_random(); to cast the healing every 2 seconds. I'm not sure if that breaks upon another proc being called or not.
December 17th 2013, 01:03 PM
spike.gif
I think the method coco's using for the loop (calling a custom procedure) should subvert the script interruption problem, actually. I can't see anything obviously wrong with the script... Maybe some kind of weird conflict between using heal both as a variable name and a name for the loop? Or maybe the very fact it's using a custom procedure (which creates a new instance of the script, IIRC) somehow breaks up checking up for &current_sprite...? Or something somehow sometimes? I'm sure I've had weird problems with checking for the host sprite's stuff from an externalled script myself, but I can't really remember anything useful.
December 17th 2013, 01:47 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
In the cases where it works, it works perfectly - you can hit the bonca as much or as little as you please and it'll still regenerate 10 health every 2 seconds. What I can't figure out is why it doesn't work part of the time. To be more specific, it never works unless there's more than one on screen, and then only on all but one of them.

Hell, I guess I could work around this by putting an extra one offscreen somewhere?
December 18th 2013, 10:49 AM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
My guess would be it has something to do with &current_sprite having the wrong value. To debug, I'd start freedink from a commandline window with debugging enabled (or press alt-D until it is). It outputs lots of info to the commandline then, including which scripts are started at which position (counted in bytes, I think, which is hard to read, but better than nothing).

You may also print variable values (using debug() to the console, or say() to the game window (and the console)) to see which parts of the code are being executed, and what the values of the variables are at those times. IME this is the fastest way to find out why code isn't doing what you expect; once you know on which line its values start to deviate from your expectations, it's usually easy to understand why.
December 18th 2013, 05:10 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
From debug, it seems that it calls this script constantly for some reason? It loads it into every slot and soon, "[ERROR] Couldn't add callback, all out of space"

Not sure what this means.

Oh, I also got this: "[ERROR] [DinkC] Procedure void regen( void ); not found in script . (word 2 was )"

I'm not sure what this is about, since the regen procedure is right there. I even tried adding the ( void ) to the end, even though I thought it didn't matter, and it still gives the same message.

On the screen with more than one, it seems to load the first two correctly and run their regen procedure as expected, but then get stuck trying to load the last one into every callback slot.

It also produces the line "[ERROR] Tried to run a script that doesn't exist in memory. Nice work." which doesn't happen on the screen with just one bonca.

I've... still got no idea how to fix this. This is pretty over my head.
December 18th 2013, 06:43 PM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
That sounds strange indeed. Perhaps you need a semicolon after the call to regen() to avoid it ignoring the closing }? I don't really know how it handles such things, I thought it didn't care.

You can ignore the not found error; that is after it fails to load the file because it's out of space, then it can't find it because it didn't load. Same thing for running the nonexistent script.

I'll try reproducing the problem. I'll let you know how it goes.
December 18th 2013, 07:44 PM
peasantm.gif
shevek
Peasant They/Them Netherlands
Never be afraid to ask, but don't demand an answer 
I'll try reproducing the problem. I'll let you know how it goes.

Very weird indeed. I have found the solution, and I have no idea why it helps. Put a wait(1); statement before the function call. If you don't do that, the file's main function will be called before the function itself, resulting in infinite recursion. Another solution which works (I tried that first, but it's uglier) is to put the regen function in a separate file, which doesn't have a main function.

To make a guess at what's happening: during draw_screen, any script that is called is assumed to need its main function called first. With the wait, draw_screen will first exit before the rest of the script is executed.

And as to why it would work this way: ehm, well, let's just say that this is DinkC, and we've seen worse. But I sure wouldn't mind if someone would make freedink work with a real language like lua.
December 18th 2013, 07:47 PM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
This explains so much. calling regen() spawns a new script, and since the engine's still in the draw_screen-loop, this script gets its main() forcibly run as well.

Holy hell.
December 18th 2013, 08:46 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Oh wow. DinkC, you cray.

Thanks a lot, shevek. It works now.
December 18th 2013, 08:48 PM
dinkdead.gif
"This explains so much. calling regen() spawns a new script, and since the engine's still in the draw_screen-loop, this script gets its main() forcibly run as well."

Wait... I always assumed that calling another function meant that that function would run as if it was a separate script. Never realised that the entire script (ie, .c file) would be duplicated.

The mind boggles.
December 19th 2013, 06:28 AM
custom_coco.gif
cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
I enjoy how many posts there are on this forum of people in awe - genuine awe! - of how little sense DinkC makes.

Speaking of things that make no sense, I typed this on a Wii.
January 6th 2014, 03:01 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
While having a friend playtest my mod, I learned that if you use Hellfire on a certain NPC, triggering a procedure that contains a freeze, the fireball passes through him and hits something else, triggering a different hit procedure. Dink never unfreezes at this point. I fear there are probably a lot of cases like this in the mod. Does anybody know how I can fix this problem?
January 6th 2014, 03:50 AM
goblins.gif
I don't remember the exact method of how to do it (if someone could post it that would help greatly) but couldn't making sure Dink hit's it with a non-projectile fix it? I'd never heard of this problem... I'd better make sure that isn't the case in my own DMOD as well!
January 6th 2014, 04:03 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
I found a fix. It's kinda kludgy, but it works - add "unfreeze(1)" to the end of the hit procedure of anything you could hit in this way after hitting the object with the freeze in its hit procedure. You'll still abort the first hit and trigger the second, but Dink won't be frozen.
January 7th 2014, 03:36 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
I have a credits sequence where the text just displays still on the screen for a while. Like this (Dink is frozen and not drawn):

&credit = say_xy("Dink Smallwood by RTSoft", 0, 100)
&acredit = say_xy("Additional Graphics by", 0, 200)
&bcredit = say_xy("`0Binirit, Castman, ExDeathEvn, iplaydink, Simon Klaebe, MsDink", 0, 220)
&ccredit = say_xy("`0James Perley, Rabidwolf9, Striker, SuperWolfman, Undink1 and VonZepplin", 0, 260)
&dcredit = say_xy("Includes Scripts by", 0, 300)
&ecredit = say_xy("`6Thenewguy and Paul Pliska", 0, 320)
sp_kill(&credit, 10000)
sp_kill(&acredit, 10000)
sp_kill(&bcredit, 10000)
sp_kill(&ccredit, 10000)
sp_kill(&dcredit, 10000)
sp_kill(&ecredit, 10000)
wait(11000)


The problem is that the last line of each "page" of credits can be skipped by pressing the talk/examine button. I was careful to arrange the timing of the credits sequence, and somebody making lines disappear really ruins it. Is there any way to make skipping the text impossible here? unfreezing Dink is no good because pressing the talk button will then make his dnotalk lines come up. I could make dnotalk.c display nothing on the credits screen, but I've found in testing that if you press talk enough times on one screen, the dnotalk.c script stops working and is replaced by the default set of "I'm not interacting with anything" text, so even that isn't ideal.
January 7th 2014, 03:44 PM
wizardg.gif
leprochaun
Peasant He/Him Japan bloop
Responsible for making things not look like ass 
say_stop_npc("") is non-skippable text.
January 7th 2014, 03:54 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Yes, but there's no such command as say_stop_npc_xy().

Hm, and it actually makes the whole "page" disappear, testing it myself right now.
January 7th 2014, 06:37 PM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
How do you feel about ugly hacks? (Which are untested, this post is just hypothesis)

// credits.c
void main( void )
{
  int &lock = spawn("lock");
  say_xy("Credits here!",200,500);
  wait(10000);
  stop_wait_for_button();
  run_script_by_number(&lock,"close");
}


// lock.c
void main( void )
{
creditloop:
  wait_for_button();
  goto creditloop;
}

void close( void )
{
  kill_this_task();
}


Ideally, you'd put the stop_wait_for_button() inside the close() proc of lock.c as well, but dinkc.chm says that it'll behave as if the script that originally caled wait_for_button() will react as if it just encountered a return. This may mean that the kill_this_task() is not run. Not that that matters much, you'd just end up with a ghost script in memory, taking up a script slot. It should be gone as soon as you load a game.
January 7th 2014, 07:52 PM
dinkdead.gif
Got curious and did some testing, I seem to have found the (weird) solution.

Firstly though, why so many variables? Unless you need them elsewhere, it seems a bit unnecessary.

You could call them all &credit and just put
sp_kill(&credit, 10000)
after each say_xy line.
Or not use any new variables at all and put
sp_kill(&return, 10000)
after each line.

Anyway:

When I made a test script with some text on the screen using say_xy, it was not skippable whether frozen or not. If a say_stop was in the script previously then the following say's were then skippable. Strange but true. Perhaps other things cause this to happen other than say_stop, I didn't test that far.
If you need say_stop somewhere you can get around it by putting the text that should not be skippable in a separate script (or function... some say it's the same thing. dang DinkC).

//test 1 - text cannot be skipped
void main (void)
{
	freeze(1)
	say_xy("1", 0, 150)
	sp_kill(&return, 5000)
	say_xy("2", 0, 175)
	sp_kill(&return, 5000)
	say_xy("3", 0, 200)
	sp_kill(&return, 5000)
	
	wait(6000)
	unfreeze(1)
}
//test 2 - text CAN be skipped
void main (void)
{
	freeze(1)
	say_stop("blah blah", 1)
	say_xy("1", 0, 150)
	sp_kill(&return, 5000)
	say_xy("2", 0, 175)
	sp_kill(&return, 5000)
	say_xy("3", 0, 200)
	sp_kill(&return, 5000)
	
	wait(6000)
	unfreeze(1)
}
//test 3 - text cannot be skipped
void main (void)
{
	freeze(1)
	say_stop("blah blah", 1)
	talk()
	unfreeze(1)
}

void talk (void)
{
	say_xy("1", 0, 150)
	sp_kill(&return, 5000)
	say_xy("2", 0, 175)
	sp_kill(&return, 5000)
	say_xy("3", 0, 200)
	sp_kill(&return, 5000)
	
	wait(6000)
}

(Note say_stop can always be skipped)
January 7th 2014, 11:07 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
You're right, that fixes it. I don't understand it at all, like so much of DinkC.

You'll be happy to know that you also shamed me into cleaning up my variables.
January 8th 2014, 03:51 AM
custom_magicman.gif
magicman
Peasant They/Them Netherlands duck
Mmmm, pizza. 
... waaaaaaat.

DinkC, you never cease to amaze me.
January 29th 2014, 09:38 PM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Here's another oddity I found with the help of shevek.

If you give a sprite a fake brain number (say, 80), make it hard, and then throw hellfire against it, the fireball will explode against it constantly forever. See here.

As usual, I'm not sure why this happens.
January 30th 2014, 04:17 AM
custom_coco.gif
Cocomonkey
Bard He/Him United States
Please Cindy, say the whole name each time. 
Okay, there is stuff happening to me at this point that just makes no sense.

NO sense.

//make pillars
int &bhold = create_sprite(170, 108, 0, 82, 1)
int &chold = create_sprite(484, 108, 0, 82, 1)
int &dhold = create_sprite(170, 299, 0, 82, 1)
int &ehold = create_sprite(484, 299, 0, 82, 1)
sp_hard(&bhold, 0)
sp_hard(&chold, 0)
sp_hard(&dhold, 0)
sp_hard(&ehold, 0)
draw_hard_map()


This makes pillars with big weird hardboxes. They don't have the big weird hardboxes when I put them on the map with the map editor. I tried using a different sprite sequence and frame - same problem. I went so far as to put this script into a completely new screen in a completely different and unrelated DMOD just to make sure that it couldn't be anything but the script - same problem. I even tried using a version of the script that was pared down ENTIRELY to the lines you see above. No difference!

I... I just... what?

Oh, and the reason they each have their own variable is that the script removes them later, like so:

//remove pillars
sp_active(&bhold, 0)
sp_active(&chold, 0)
sp_active(&dhold, 0)
sp_active(&ehold, 0)
draw_hard_map()


I have given up and worked around this by adding yet more pointless globals. I just wanted to let everybody know how weird it's gotten.
January 30th 2014, 05:33 AM
spike.gif
This makes pillars with big weird hardboxes.

Pretty neat. I'd guess it's some kind of loading problem - if you run the script twice, or add preload_seq(82) at the beginning, the problem disappears. If I weren't lazy, I'd check whether all graphics that are load_sequenced (as opposed to load_sequence_now'd) behave the same way...

If you give a sprite a fake brain number (say, 80), make it hard, and then throw hellfire against it, the fireball will explode against it constantly forever.

This is more sensible; the dam-sfb.c script just doesn't account for fake brains, since the original game didn't use those.