1 /**
2  * Link game engine and DinkC script engine
3 
4  * Copyright (C) 1997, 1998, 1999, 2002, 2003  Seth A. Robinson
5  * Copyright (C) 2005, 2006  Dan Walma
6  * Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011, 2012  Sylvain Beucler
7 
8  * This file is part of GNU FreeDink
9 
10  * GNU FreeDink is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 3 of the
13  * License, or (at your option) any later version.
14 
15  * GNU FreeDink is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19 
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see
22  * <http://www.gnu.org/licenses/>.
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include "dinkc_bindings.h"
30 
31 #include <stdio.h>
32 #include <stdlib.h> /* atol */
33 #include <time.h>
34 #include <math.h>
35 #include <alloca.h>
36 #include <string.h>
37 #include <ctype.h> /* tolower */
38 #include <xalloc.h>
39 
40 /* Gnulib */
41 #include "hash.h"
42 
43 #include "game_engine.h"
44 #include "screen.h"
45 #include "dinkvar.h"
46 #include "dinkc.h"
47 #include "freedink.h"
48 #include "gfx.h"
49 #include "gfx_fonts.h"
50 #include "gfx_palette.h"
51 #include "gfx_sprites.h"
52 #include "gfx_tiles.h"
53 #include "bgm.h"
54 #include "sfx.h"
55 #include "input.h"
56 #include "str_util.h"
57 #include "paths.h"
58 #include "log.h"
59 #include "dinkc_console.h"
60 #include "i18n.h"
61 
62 /* store current procedure arguments expanded values of type 'int' (see get_parms) */
63 static long nlist[10];
64 /* store current procedure arguments of type 'string' (idem) */
65 static char* slist[10];
66 static char* cur_funcname;
67 
68 
69 /***************/
70 /*  DinkC API  */
71 /*             */
72 /***************/
73 
74 /**
75  * Short-hand to check for invalid sprites and avoid segfaults.
76  * Also warn the D-Mod author about it.
77  */
78 #define STOP_IF_BAD_SPRITE(sprite)                                             \
79   if (sprite <= 0 || sprite >= MAX_SPRITES_AT_ONCE)                            \
80     {                                                                          \
81       log_error("[DinkC] %s:%d:%s: invalid sprite %d (offset %d)",             \
82                 rinfo[script]->name, rinfo[script]->debug_line,                \
83                 cur_funcname, sprite, rinfo[script]->current);                 \
84       return;                                                                  \
85     }
86 
87 /**
88  * sp_* functions used to call 'change_sprite' on spr[sprite] without
89  * checking if 'sprite' was in [1; MAX_SPRITES_AT_ONCE-1]. Since
90  * 'change_sprite' returns -1 when 'sprite' is inactive, that's also
91  * what we return when the sprite is out of range.
92  */
93 #define RETURN_NEG_IF_BAD_SPRITE(sprite)                                       \
94   if (sprite <= 0 || sprite >= MAX_SPRITES_AT_ONCE)                            \
95     {                                                                          \
96       log_error("[DinkC] %s:%d:%s: invalid sprite %d (offset %d)",             \
97                 rinfo[script]->name, rinfo[script]->debug_line,                \
98                 cur_funcname, sprite, rinfo[script]->current);                 \
99       *preturnint = -1;                                                        \
100       return;                                                                  \
101     }
102 
103 
dc_sp_active(int script,int * yield,int * preturnint,int sprite,int sparg)104 void dc_sp_active(int script, int* yield, int* preturnint, int sprite, int sparg)
105 {
106   RETURN_NEG_IF_BAD_SPRITE(sprite);
107   *preturnint = change_sprite(sprite, sparg, &spr[sprite].active);
108 }
109 
dc_sp_attack_hit_sound(int script,int * yield,int * preturnint,int sprite,int sparg)110 void dc_sp_attack_hit_sound(int script, int* yield, int* preturnint, int sprite, int sparg)
111 {
112   RETURN_NEG_IF_BAD_SPRITE(sprite);
113   *preturnint = change_sprite(sprite, sparg, &spr[sprite].attack_hit_sound);
114 }
115 
dc_sp_attack_hit_sound_speed(int script,int * yield,int * preturnint,int sprite,int sparg)116 void dc_sp_attack_hit_sound_speed(int script, int* yield, int* preturnint, int sprite, int sparg)
117 {
118   RETURN_NEG_IF_BAD_SPRITE(sprite);
119   *preturnint = change_sprite(sprite, sparg, &spr[sprite].attack_hit_sound_speed);
120 }
121 
dc_sp_attack_wait(int script,int * yield,int * preturnint,int sprite,int sparg)122 void dc_sp_attack_wait(int script, int* yield, int* preturnint, int sprite, int sparg)
123 {
124   RETURN_NEG_IF_BAD_SPRITE(sprite);
125   *preturnint = change_sprite(sprite, sparg+thisTickCount, &spr[sprite].attack_wait);
126 }
127 
dc_sp_base_attack(int script,int * yield,int * preturnint,int sprite,int sparg)128 void dc_sp_base_attack(int script, int* yield, int* preturnint, int sprite, int sparg)
129 {
130   RETURN_NEG_IF_BAD_SPRITE(sprite);
131   *preturnint = change_sprite_noreturn(sprite, sparg, &spr[sprite].base_attack);
132 }
133 
dc_sp_base_die(int script,int * yield,int * preturnint,int sprite,int base_sequence)134 void dc_sp_base_die(int script, int* yield, int* preturnint, int sprite, int base_sequence)
135 {
136   RETURN_NEG_IF_BAD_SPRITE(sprite);
137   *preturnint = change_sprite_noreturn(sprite, base_sequence, &spr[sprite].base_die);
138 }
139 
dc_sp_base_hit(int script,int * yield,int * preturnint,int sprite,int sparg)140 void dc_sp_base_hit(int script, int* yield, int* preturnint, int sprite, int sparg)
141 {
142   RETURN_NEG_IF_BAD_SPRITE(sprite);
143   *preturnint = change_sprite_noreturn(sprite, sparg, &spr[sprite].base_hit);
144 }
145 
dc_sp_base_idle(int script,int * yield,int * preturnint,int sprite,int sparg)146 void dc_sp_base_idle(int script, int* yield, int* preturnint, int sprite, int sparg)
147 {
148   RETURN_NEG_IF_BAD_SPRITE(sprite);
149   *preturnint = change_sprite_noreturn(sprite, sparg, &spr[sprite].base_idle);
150 }
151 
dc_sp_base_walk(int script,int * yield,int * preturnint,int sprite,int sparg)152 void dc_sp_base_walk(int script, int* yield, int* preturnint, int sprite, int sparg)
153 {
154   RETURN_NEG_IF_BAD_SPRITE(sprite);
155   *preturnint = change_sprite_noreturn(sprite, sparg, &spr[sprite].base_walk);
156 }
157 
dc_sp_brain(int script,int * yield,int * preturnint,int sprite,int sparg)158 void dc_sp_brain(int script, int* yield, int* preturnint, int sprite, int sparg)
159 {
160   RETURN_NEG_IF_BAD_SPRITE(sprite);
161   *preturnint = change_sprite(sprite, sparg, &spr[sprite].brain);
162 }
163 
dc_sp_brain_parm(int script,int * yield,int * preturnint,int sprite,int sparg)164 void dc_sp_brain_parm(int script, int* yield, int* preturnint, int sprite, int sparg)
165 {
166   RETURN_NEG_IF_BAD_SPRITE(sprite);
167   *preturnint = change_sprite(sprite, sparg, &spr[sprite].brain_parm);
168 }
169 
dc_sp_brain_parm2(int script,int * yield,int * preturnint,int sprite,int sparg)170 void dc_sp_brain_parm2(int script, int* yield, int* preturnint, int sprite, int sparg)
171 {
172   RETURN_NEG_IF_BAD_SPRITE(sprite);
173   *preturnint = change_sprite(sprite, sparg, &spr[sprite].brain_parm2);
174 }
175 
dc_sp_defense(int script,int * yield,int * preturnint,int sprite,int sparg)176 void dc_sp_defense(int script, int* yield, int* preturnint, int sprite, int sparg)
177 {
178   RETURN_NEG_IF_BAD_SPRITE(sprite);
179   *preturnint = change_sprite(sprite, sparg, &spr[sprite].defense);
180 }
181 
dc_sp_dir(int script,int * yield,int * preturnint,int sprite,int sparg)182 void dc_sp_dir(int script, int* yield, int* preturnint, int sprite, int sparg)
183 {
184   RETURN_NEG_IF_BAD_SPRITE(sprite);
185   *preturnint = change_sprite(sprite, sparg, &spr[sprite].dir);
186   if (sparg != -1)
187     changedir(spr[sprite].dir, sprite, spr[sprite].base_walk);
188 }
189 
dc_sp_disabled(int script,int * yield,int * preturnint,int sprite,int sparg)190 void dc_sp_disabled(int script, int* yield, int* preturnint, int sprite, int sparg)
191 {
192   RETURN_NEG_IF_BAD_SPRITE(sprite);
193   *preturnint = change_sprite(sprite, sparg, &spr[sprite].disabled);
194 }
195 
dc_sp_distance(int script,int * yield,int * preturnint,int sprite,int sparg)196 void dc_sp_distance(int script, int* yield, int* preturnint, int sprite, int sparg)
197 {
198   RETURN_NEG_IF_BAD_SPRITE(sprite);
199   *preturnint = change_sprite(sprite, sparg, &spr[sprite].distance);
200 }
201 
dc_sp_exp(int script,int * yield,int * preturnint,int sprite,int sparg)202 void dc_sp_exp(int script, int* yield, int* preturnint, int sprite, int sparg)
203 {
204   RETURN_NEG_IF_BAD_SPRITE(sprite);
205   *preturnint = change_sprite(sprite, sparg, &spr[sprite].exp);
206 }
207 
dc_sp_flying(int script,int * yield,int * preturnint,int sprite,int sparg)208 void dc_sp_flying(int script, int* yield, int* preturnint, int sprite, int sparg)
209 {
210   RETURN_NEG_IF_BAD_SPRITE(sprite);
211   *preturnint = change_sprite(sprite, sparg, &spr[sprite].flying);
212 }
213 
dc_sp_follow(int script,int * yield,int * preturnint,int sprite,int sparg)214 void dc_sp_follow(int script, int* yield, int* preturnint, int sprite, int sparg)
215 {
216   RETURN_NEG_IF_BAD_SPRITE(sprite);
217   *preturnint = change_sprite(sprite, sparg, &spr[sprite].follow);
218 }
219 
dc_sp_frame(int script,int * yield,int * preturnint,int sprite,int sparg)220 void dc_sp_frame(int script, int* yield, int* preturnint, int sprite, int sparg)
221 {
222   RETURN_NEG_IF_BAD_SPRITE(sprite);
223   *preturnint = change_sprite(sprite, sparg, &spr[sprite].frame);
224 }
225 
dc_sp_frame_delay(int script,int * yield,int * preturnint,int sprite,int sparg)226 void dc_sp_frame_delay(int script, int* yield, int* preturnint, int sprite, int sparg)
227 {
228   RETURN_NEG_IF_BAD_SPRITE(sprite);
229   *preturnint = change_sprite(sprite, sparg, &spr[sprite].frame_delay);
230 }
231 
dc_sp_gold(int script,int * yield,int * preturnint,int sprite,int sparg)232 void dc_sp_gold(int script, int* yield, int* preturnint, int sprite, int sparg)
233 {
234   RETURN_NEG_IF_BAD_SPRITE(sprite);
235   *preturnint = change_sprite(sprite, sparg, &spr[sprite].gold);
236 }
237 
dc_sp_hard(int script,int * yield,int * preturnint,int sprite,int sparg)238 void dc_sp_hard(int script, int* yield, int* preturnint, int sprite, int sparg)
239 {
240   RETURN_NEG_IF_BAD_SPRITE(sprite);
241   *preturnint = change_sprite(sprite, sparg, &spr[sprite].hard);
242   if (spr[sprite].sp_index != 0 && sparg != -1)
243     pam.sprite[spr[sprite].sp_index].hard = *preturnint;
244 }
245 
dc_sp_hitpoints(int script,int * yield,int * preturnint,int sprite,int sparg)246 void dc_sp_hitpoints(int script, int* yield, int* preturnint, int sprite, int sparg)
247 {
248   RETURN_NEG_IF_BAD_SPRITE(sprite);
249   *preturnint = change_sprite(sprite, sparg, &spr[sprite].hitpoints);
250 }
251 
dc_sp_move_nohard(int script,int * yield,int * preturnint,int sprite,int sparg)252 void dc_sp_move_nohard(int script, int* yield, int* preturnint, int sprite, int sparg)
253 {
254   RETURN_NEG_IF_BAD_SPRITE(sprite);
255   *preturnint = change_sprite(sprite, sparg, &spr[sprite].move_nohard);
256 }
257 
dc_sp_mx(int script,int * yield,int * preturnint,int sprite,int sparg)258 void dc_sp_mx(int script, int* yield, int* preturnint, int sprite, int sparg)
259 {
260   RETURN_NEG_IF_BAD_SPRITE(sprite);
261   *preturnint = change_sprite(sprite, sparg, &spr[sprite].mx);
262 }
263 
dc_sp_my(int script,int * yield,int * preturnint,int sprite,int sparg)264 void dc_sp_my(int script, int* yield, int* preturnint, int sprite, int sparg)
265 {
266   RETURN_NEG_IF_BAD_SPRITE(sprite);
267   *preturnint = change_sprite(sprite, sparg, &spr[sprite].my);
268 }
269 
dc_sp_noclip(int script,int * yield,int * preturnint,int sprite,int sparg)270 void dc_sp_noclip(int script, int* yield, int* preturnint, int sprite, int sparg)
271 {
272   RETURN_NEG_IF_BAD_SPRITE(sprite);
273   *preturnint = change_sprite(sprite, sparg, &spr[sprite].noclip);
274 }
275 
dc_sp_nocontrol(int script,int * yield,int * preturnint,int sprite,int sparg)276 void dc_sp_nocontrol(int script, int* yield, int* preturnint, int sprite, int sparg)
277 {
278   RETURN_NEG_IF_BAD_SPRITE(sprite);
279   *preturnint = change_sprite(sprite, sparg, &spr[sprite].nocontrol);
280 }
281 
dc_sp_nodraw(int script,int * yield,int * preturnint,int sprite,int sparg)282 void dc_sp_nodraw(int script, int* yield, int* preturnint, int sprite, int sparg)
283 {
284   RETURN_NEG_IF_BAD_SPRITE(sprite);
285   *preturnint = change_sprite(sprite, sparg, &spr[sprite].nodraw);
286 }
287 
dc_sp_nohit(int script,int * yield,int * preturnint,int sprite,int sparg)288 void dc_sp_nohit(int script, int* yield, int* preturnint, int sprite, int sparg)
289 {
290   RETURN_NEG_IF_BAD_SPRITE(sprite);
291   *preturnint = change_sprite(sprite, sparg, &spr[sprite].nohit);
292 }
293 
dc_sp_notouch(int script,int * yield,int * preturnint,int sprite,int sparg)294 void dc_sp_notouch(int script, int* yield, int* preturnint, int sprite, int sparg)
295 {
296   RETURN_NEG_IF_BAD_SPRITE(sprite);
297   *preturnint = change_sprite(sprite, sparg, &spr[sprite].notouch);
298 }
299 
dc_sp_pframe(int script,int * yield,int * preturnint,int sprite,int sparg)300 void dc_sp_pframe(int script, int* yield, int* preturnint, int sprite, int sparg)
301 {
302   RETURN_NEG_IF_BAD_SPRITE(sprite);
303   *preturnint = change_sprite(sprite, sparg, &spr[sprite].pframe);
304 }
305 
dc_sp_picfreeze(int script,int * yield,int * preturnint,int sprite,int sparg)306 void dc_sp_picfreeze(int script, int* yield, int* preturnint, int sprite, int sparg)
307 {
308   RETURN_NEG_IF_BAD_SPRITE(sprite);
309   *preturnint = change_sprite(sprite, sparg, &spr[sprite].picfreeze);
310 }
311 
dc_sp_pseq(int script,int * yield,int * preturnint,int sprite,int sparg)312 void dc_sp_pseq(int script, int* yield, int* preturnint, int sprite, int sparg)
313 {
314   RETURN_NEG_IF_BAD_SPRITE(sprite);
315   *preturnint = change_sprite(sprite, sparg, &spr[sprite].pseq);
316 }
317 
dc_sp_que(int script,int * yield,int * preturnint,int sprite,int sparg)318 void dc_sp_que(int script, int* yield, int* preturnint, int sprite, int sparg)
319 {
320   RETURN_NEG_IF_BAD_SPRITE(sprite);
321   *preturnint = change_sprite(sprite, sparg, &spr[sprite].que);
322 }
323 
dc_sp_range(int script,int * yield,int * preturnint,int sprite,int sparg)324 void dc_sp_range(int script, int* yield, int* preturnint, int sprite, int sparg)
325 {
326   RETURN_NEG_IF_BAD_SPRITE(sprite);
327   *preturnint = change_sprite(sprite, sparg, &spr[sprite].range);
328 }
329 
dc_sp_reverse(int script,int * yield,int * preturnint,int sprite,int sparg)330 void dc_sp_reverse(int script, int* yield, int* preturnint, int sprite, int sparg)
331 {
332   RETURN_NEG_IF_BAD_SPRITE(sprite);
333   *preturnint = change_sprite(sprite, sparg, &spr[sprite].reverse);
334 }
335 
dc_sp_seq(int script,int * yield,int * preturnint,int sprite,int sparg)336 void dc_sp_seq(int script, int* yield, int* preturnint, int sprite, int sparg)
337 {
338   RETURN_NEG_IF_BAD_SPRITE(sprite);
339   if ((sparg < 0 || sparg >= MAX_SEQUENCES) && sparg != -1)
340     {
341       log_error("[DinkC] %s:%d:%s: invalid sequence %d, ignoring (offset %d)",
342                 rinfo[script]->name, rinfo[script]->debug_line,
343                 cur_funcname, sparg, rinfo[script]->current);
344       *preturnint = -1;
345       return;
346     }
347   *preturnint = change_sprite(sprite, sparg, &spr[sprite].seq);
348 }
349 
dc_sp_size(int script,int * yield,int * preturnint,int sprite,int sparg)350 void dc_sp_size(int script, int* yield, int* preturnint, int sprite, int sparg)
351 {
352   RETURN_NEG_IF_BAD_SPRITE(sprite);
353   *preturnint = change_sprite(sprite, sparg, &spr[sprite].size);
354 }
355 
dc_sp_sound(int script,int * yield,int * preturnint,int sprite,int sparg)356 void dc_sp_sound(int script, int* yield, int* preturnint, int sprite, int sparg)
357 {
358   RETURN_NEG_IF_BAD_SPRITE(sprite);
359   *preturnint = change_sprite(sprite, sparg, &spr[sprite].sound);
360   if (sparg > 0)
361     SoundPlayEffect(spr[sprite].sound,22050, 0, sprite, 1);
362 }
363 
dc_sp_speed(int script,int * yield,int * preturnint,int sprite,int sparg)364 void dc_sp_speed(int script, int* yield, int* preturnint, int sprite, int sparg)
365 {
366   RETURN_NEG_IF_BAD_SPRITE(sprite);
367   *preturnint = change_sprite(sprite, sparg, &spr[sprite].speed);
368   if (sparg != -1)
369     changedir(spr[sprite].dir, sprite, spr[sprite].base_walk);
370 }
371 
dc_sp_strength(int script,int * yield,int * preturnint,int sprite,int sparg)372 void dc_sp_strength(int script, int* yield, int* preturnint, int sprite, int sparg)
373 {
374   RETURN_NEG_IF_BAD_SPRITE(sprite);
375   *preturnint = change_sprite(sprite, sparg, &spr[sprite].strength);
376 }
377 
dc_sp_target(int script,int * yield,int * preturnint,int sprite,int sparg)378 void dc_sp_target(int script, int* yield, int* preturnint, int sprite, int sparg)
379 {
380   RETURN_NEG_IF_BAD_SPRITE(sprite);
381   *preturnint = change_sprite(sprite, sparg, &spr[sprite].target);
382 }
383 
dc_sp_timing(int script,int * yield,int * preturnint,int sprite,int sparg)384 void dc_sp_timing(int script, int* yield, int* preturnint, int sprite, int sparg)
385 {
386   RETURN_NEG_IF_BAD_SPRITE(sprite);
387   *preturnint = change_sprite(sprite, sparg, &spr[sprite].timer);
388 }
389 
dc_sp_touch_damage(int script,int * yield,int * preturnint,int sprite,int sparg)390 void dc_sp_touch_damage(int script, int* yield, int* preturnint, int sprite, int sparg)
391 {
392   RETURN_NEG_IF_BAD_SPRITE(sprite);
393   *preturnint = change_sprite_noreturn(sprite, sparg, &spr[sprite].touch_damage);
394 }
395 
dc_sp_x(int script,int * yield,int * preturnint,int sprite,int sparg)396 void dc_sp_x(int script, int* yield, int* preturnint, int sprite, int sparg)
397 {
398   RETURN_NEG_IF_BAD_SPRITE(sprite);
399   *preturnint = change_sprite(sprite, sparg, &spr[sprite].x);
400 }
401 
dc_sp_y(int script,int * yield,int * preturnint,int sprite,int sparg)402 void dc_sp_y(int script, int* yield, int* preturnint, int sprite, int sparg)
403 {
404   RETURN_NEG_IF_BAD_SPRITE(sprite);
405   *preturnint = change_sprite(sprite, sparg, &spr[sprite].y);
406 }
407 
408 
409 
dc_sp_kill(int script,int * yield,int * preturnint,int sprite,int sparg)410 void dc_sp_kill(int script, int* yield, int* preturnint, int sprite, int sparg)
411 {
412   STOP_IF_BAD_SPRITE(sprite);
413   spr[sprite].kill = sparg;
414 }
415 
dc_sp_editor_num(int script,int * yield,int * preturnint,int sprite)416 void dc_sp_editor_num(int script, int* yield, int* preturnint, int sprite)
417 {
418   *preturnint = 0;
419   if (sprite > 0 && sprite < MAX_SPRITES_AT_ONCE)
420     *preturnint = spr[sprite].sp_index;
421   else
422     log_error("[DinkC] sp_editor_num: invalid sprite %d", sprite);
423 }
424 
425 
dc_sp_kill_wait(int script,int * yield,int * preturnint,int sprite)426 void dc_sp_kill_wait(int script, int* yield, int* preturnint, int sprite)
427 {
428   if (sprite > 0 && sprite < MAX_SPRITES_AT_ONCE)
429     spr[sprite].wait = 0;
430   else
431     log_error("[DinkC] sp_kill_wait: invalid sprite %d", sprite);
432 }
433 
dc_sp_script(int script,int * yield,int * preturnint,int sprite,char * dcscript)434 void dc_sp_script(int script, int* yield, int* preturnint, int sprite, char* dcscript)
435 {
436   // (sprite, direction, until, nohard);
437   if (sprite <= 0 || (sprite >= MAX_SPRITES_AT_ONCE && sprite != 1000))
438     {
439       log_error("[DinkC] %s:%d:%s: cannot process sprite %d??",
440                 rinfo[script]->name, rinfo[script]->debug_line, cur_funcname,
441 		sprite);
442       return;
443     }
444   kill_scripts_owned_by(sprite);
445   if (load_script(dcscript, sprite, /*true*/1) == 0)
446     {
447       *preturnint = 0;
448       return;
449     }
450 
451   int tempreturn = 0;
452   if (sprite != 1000)
453     {
454       if (no_running_main == /*true*/1)
455 	log_info("Not running %s until later..", rinfo[spr[sprite].script]->name);
456       if (no_running_main == /*false*/0 && sprite != 1000)
457 	locate(spr[sprite].script, "MAIN");
458 
459       tempreturn = spr[sprite].script;
460 
461       if (no_running_main == /*false*/0)
462 	run_script(spr[sprite].script);
463     }
464 
465   *preturnint = tempreturn;
466 }
467 
468 
dc_unfreeze(int script,int * yield,int * preturnint,int sprite)469 void dc_unfreeze(int script, int* yield, int* preturnint, int sprite)
470 {
471   STOP_IF_BAD_SPRITE(sprite);
472 
473   if (spr[sprite].active)
474     spr[sprite].freeze = 0;
475   else
476     log_error("[DinkC] Couldn't unfreeze sprite %d in script %d, it doesn't exist.", sprite, script);
477 }
478 
dc_freeze(int script,int * yield,int * preturnint,int sprite)479 void dc_freeze(int script, int* yield, int* preturnint, int sprite)
480 {
481   STOP_IF_BAD_SPRITE(sprite);
482 
483   if (spr[sprite].active)
484     spr[sprite].freeze = script;
485   else
486     log_error("[DinkC] Couldn't freeze sprite %d in script %d, it doesn't exist.", sprite, script);
487 }
488 
dc_set_callback_random(int script,int * yield,int * preturnint,char * procedure,int base,int range)489 void dc_set_callback_random(int script, int* yield, int* preturnint, char* procedure, int base, int range)
490 {
491   int retval = add_callback(procedure, base, range, script);
492   if (dversion >= 108)
493     *preturnint = retval;
494 }
495 
dc_set_dink_speed(int script,int * yield,int * preturnint,int speed)496 void dc_set_dink_speed(int script, int* yield, int* preturnint, int speed)
497 {
498   if (dversion >= 108 && speed == 0)
499     ; // do nothing
500   else
501     dinkspeed = speed;
502 }
503 
dc_reset_timer(int script,int * yield,int * preturnint)504 void dc_reset_timer(int script, int* yield, int* preturnint)
505 {
506   time(&time_start);
507   play.minutes = 0;
508 }
509 
dc_set_keep_mouse(int script,int * yield,int * preturnint,int keep_mouse_p)510 void dc_set_keep_mouse(int script, int* yield, int* preturnint, int keep_mouse_p)
511 {
512   keep_mouse = keep_mouse_p;
513 }
514 
dc_add_item(int script,int * yield,int * preturnint,char * dcscript,int sequence,int frame)515 void dc_add_item(int script, int* yield, int* preturnint, char* dcscript, int sequence, int frame)
516 {
517   add_item(dcscript, sequence, frame, ITEM_REGULAR);
518 }
519 
dc_add_magic(int script,int * yield,int * preturnint,char * dcscript,int sequence,int frame)520 void dc_add_magic(int script, int* yield, int* preturnint, char* dcscript, int sequence, int frame)
521 {
522   add_item(dcscript, sequence, frame, ITEM_MAGIC);
523 }
524 
dc_add_exp(int script,int * yield,int * preturnint,int amount,int active_sprite)525 void dc_add_exp(int script, int* yield, int* preturnint, int amount, int active_sprite)
526 {
527   STOP_IF_BAD_SPRITE(active_sprite);
528 
529   if (dversion >= 108)
530     // fix - made work with all sprites when
531     // using add_exp DinkC command
532     add_exp_force(amount, active_sprite);
533   else
534     add_exp(amount, active_sprite);
535 }
536 
dc_kill_this_item(int script,int * yield,int * preturnint,char * dcscript)537 void dc_kill_this_item(int script, int* yield, int* preturnint, char* dcscript)
538 {
539   kill_item_script(dcscript);
540 }
541 
dc_kill_this_magic(int script,int * yield,int * preturnint,char * dcscript)542 void dc_kill_this_magic(int script, int* yield, int* preturnint, char* dcscript)
543 {
544   kill_mitem_script(dcscript);
545 }
546 
dc_show_bmp(int script,int * yield,int * preturnint,char * bmp_file,int show_map_dot,int unused)547 void dc_show_bmp(int script, int* yield, int* preturnint, char* bmp_file, int show_map_dot, int unused)
548 {
549   log_info("showing BMP");
550   wait4b.active = /*false*/0;
551   show_bmp(bmp_file, show_map_dot, script);
552   *yield = 1;
553 }
554 
dc_copy_bmp_to_screen(int script,int * yield,int * preturnint,char * bmp_file)555 void dc_copy_bmp_to_screen(int script, int* yield, int* preturnint, char* bmp_file)
556 {
557   log_info("copying BMP");
558   copy_bmp(bmp_file);
559 }
560 
dc_wait_for_button(int script,int * yield,int * preturnint)561 void dc_wait_for_button(int script, int* yield, int* preturnint)
562 {
563   log_info("waiting for button with script %d", script);
564   wait4b.script = script;
565   wait4b.active = /*true*/1;
566   wait4b.button = 0;
567   *yield = 1;
568 }
569 
dc_stop_wait_for_button(int script,int * yield,int * preturnint)570 void dc_stop_wait_for_button(int script, int* yield, int* preturnint)
571 {
572   wait4b.active = /*false*/0;
573 }
574 
dc_load_screen(int script,int * yield,int * preturnint)575 void dc_load_screen(int script, int* yield, int* preturnint)
576 {
577   /* STOP_IF_BAD_SPRITE(active_sprite); */
578 
579   //Msg("Loading map %d..",*pmap);
580   update_screen_time();
581   load_map(map.loc[*pmap]);
582 
583   // update indicator on mini-map
584   if (map.indoor[*pmap] == 0)
585     play.last_map = *pmap;
586 
587   return;
588 }
589 
590 /**
591  * Decipher a copy of 'text' (to avoid potentially realloc'ing it) and
592  * call 'say_text(...)'
593  */
say_text_from_dc(char * text,int active_sprite,int script)594 static int say_text_from_dc(char* text, int active_sprite, int script)
595 {
596   log_debug("[DinkC] %s:%d:%s(\"%s\", %d)", rinfo[script]->name,
597 	    rinfo[script]->debug_line, cur_funcname,
598 	    text, active_sprite);
599 
600   /* Translate text (before variable substitution) */
601   char* translation = NULL;
602   if (strlen(text) >= 2 && text[0] == '`')
603     {
604       char* temp = i18n_translate(rinfo[script]->name, rinfo[script]->debug_line, text+2);
605       translation = xmalloc(strlen(temp) + 2 + 1);
606       sprintf(translation, "%c%c%s", text[0], text[1], temp);
607       free(temp);
608     }
609   else
610     {
611       translation = i18n_translate(rinfo[script]->name, rinfo[script]->debug_line, text);
612     }
613 
614   /* Substitute variables */
615   char* expanded = strdup(translation);
616   free(translation);
617   decipher_string(&expanded, script);
618 
619   int text_sprite = say_text(expanded, active_sprite, script);
620   free(expanded);
621   return text_sprite;
622 }
623 
624 /**
625  * Decipher a copy of 'text' (to avoid potentially realloc'ing it) and
626  * call 'say_text_xy(...)'
627  */
say_text_xy_from_dc(char * text,int x,int y,int script)628 static int say_text_xy_from_dc(char* text, int x, int y, int script)
629 {
630   log_debug("[DinkC] %s:%d:%s(\"%s\", %d, %d)", rinfo[script]->name,
631 	    rinfo[script]->debug_line, cur_funcname,
632 	    text, x, y);
633 
634   /* Translate text (before variable substitution) */
635   char* translation = NULL;
636   if (strlen(text) >= 2 && text[0] == '`')
637     {
638       char* temp = i18n_translate(rinfo[script]->name, rinfo[script]->debug_line, text+2);
639       translation = xmalloc(strlen(temp) + 2 + 1);
640       sprintf(translation, "%c%c%s", text[0], text[1], temp);
641       free(temp);
642     }
643   else
644     {
645       translation = i18n_translate(rinfo[script]->name, rinfo[script]->debug_line, text);
646     }
647 
648   /* Substitute variables */
649   char* expanded = strdup(translation);
650   free(translation);
651   decipher_string(&expanded, script);
652 
653   int text_sprite = say_text_xy(expanded, x, y, script);
654   free(expanded);
655   return text_sprite;
656 }
657 
dc_say(int script,int * yield,int * preturnint,char * text,int active_sprite)658 void dc_say(int script, int* yield, int* preturnint, char* text, int active_sprite)
659 {
660   /* 1000 is a valid value, and bad values don't trigger segfaults
661      in this particular function; so don't validate active_sprite */
662   /* STOP_IF_BAD_SPRITE(active_sprite); */
663 
664   if (active_sprite == 0)
665     {
666       log_error("[DinkC] say_stop: Sprite 0 can talk? Yeah, didn't think so.");
667       return;
668     }
669 
670   if (active_sprite != 1000)
671     kill_text_owned_by(active_sprite);
672 
673   *preturnint = say_text_from_dc(text, active_sprite, script);
674 }
675 
dc_say_stop(int script,int * yield,int * preturnint,char * text,int active_sprite)676 void dc_say_stop(int script, int* yield, int* preturnint, char* text, int active_sprite)
677 {
678   /* STOP_IF_BAD_SPRITE(active_sprite); */
679 
680   if (active_sprite == 0)
681     {
682       log_error("[DinkC] say_stop: Sprite 0 can talk? Yeah, didn't think so.");
683       return;
684     }
685 
686   kill_text_owned_by(active_sprite);
687   kill_text_owned_by(1);
688   kill_returning_stuff(script);
689 
690   int sprite = say_text_from_dc(text, active_sprite, script);
691   *preturnint = sprite;
692 
693   spr[sprite].callback = script;
694   play.last_talk = script;
695   //Msg("Sprite %d marked callback true.", sprite);
696 
697   *yield = 1;
698 }
699 
dc_say_stop_npc(int script,int * yield,int * preturnint,char * text,int active_sprite)700 void dc_say_stop_npc(int script, int* yield, int* preturnint, char* text, int active_sprite)
701 {
702   /* STOP_IF_BAD_SPRITE(active_sprite); */
703 
704   /* no-op if already talking */
705   if (text_owned_by(active_sprite))
706     {
707       *preturnint = 0;
708       return;
709     }
710 
711   kill_returning_stuff(script);
712 
713   int sprite = say_text_from_dc(text, active_sprite, script);
714   spr[sprite].callback = script;
715 
716   *yield = 1;
717 }
718 
dc_say_stop_xy(int script,int * yield,int * preturnint,char * text,int x,int y)719 void dc_say_stop_xy(int script, int* yield, int* preturnint, char* text, int x, int y)
720 {
721   kill_returning_stuff(script);
722 
723   int sprite = say_text_xy_from_dc(text, x, y, script);
724   spr[sprite].callback = script;
725   spr[sprite].live = /*true*/1;
726   play.last_talk = script;
727   *yield = 1;
728 }
729 
dc_say_xy(int script,int * yield,int * preturnint,char * text,int x,int y)730 void dc_say_xy(int script, int* yield, int* preturnint, char* text, int x, int y)
731 {
732   kill_returning_stuff(script);
733   *preturnint = say_text_xy_from_dc(text, x, y, script);
734 }
735 
dc_draw_screen(int script,int * yield,int * preturnint)736 void dc_draw_screen(int script, int* yield, int* preturnint)
737 {
738   /* only refresh screen if not in a cut-scene */
739   /* do it before draw_map_game() because that one calls
740      kill_all_scripts(), which NULLifies rinfo[script] */
741   if (rinfo[script]->sprite != 1000)
742     *yield = 1;
743   draw_map_game();
744 }
745 
dc_free_items(int script,int * yield,int * preturnint)746 void dc_free_items(int script, int* yield, int* preturnint)
747 {
748   *preturnint = 0;
749   int i = 0;
750   for (; i < NB_ITEMS; i++)
751     {
752       if (play.item[i].active == 0)
753 	*preturnint += 1;
754     }
755 }
756 
dc_free_magic(int script,int * yield,int * preturnint)757 void dc_free_magic(int script, int* yield, int* preturnint)
758 {
759   *preturnint = 0;
760 
761   int i = 0;
762   for (; i < NB_MITEMS; i ++)
763     {
764       if (play.mitem[i-1].active == 0)
765 	*preturnint += 1;
766     }
767 }
768 
dc_kill_cur_item(int script,int * yield,int * preturnint)769 void dc_kill_cur_item(int script, int* yield, int* preturnint)
770 {
771   *preturnint = 0;
772   kill_cur_item();
773   *yield = 1;
774 }
775 
dc_kill_cur_magic(int script,int * yield,int * preturnint)776 void dc_kill_cur_magic(int script, int* yield, int* preturnint)
777 {
778   *preturnint = 0;
779   kill_cur_magic();
780   *yield = 1;
781 }
782 
dc_draw_status(int script,int * yield,int * preturnint)783 void dc_draw_status(int script, int* yield, int* preturnint)
784 {
785   draw_status_all();
786 }
787 
dc_arm_weapon(int script,int * yield,int * preturnint)788 void dc_arm_weapon(int script, int* yield, int* preturnint)
789 {
790   if (weapon_script != 0 && locate(weapon_script, "DISARM"))
791     run_script(weapon_script);
792 
793   weapon_script = load_script(play.item[*pcur_weapon - 1].name, 1000, /*false*/0);
794   if (locate(weapon_script, "ARM"))
795     run_script(weapon_script);
796 }
797 
dc_arm_magic(int script,int * yield,int * preturnint)798 void dc_arm_magic(int script, int* yield, int* preturnint)
799 {
800   if (magic_script != 0 && locate(magic_script, "DISARM"))
801     run_script(magic_script);
802 
803   magic_script = load_script(play.mitem[*pcur_magic - 1].name, 1000, /*false*/0);
804   if (locate(magic_script, "ARM"))
805     run_script(magic_script);
806 }
807 
dc_restart_game(int script,int * yield,int * preturnint)808 void dc_restart_game(int script, int* yield, int* preturnint)
809 {
810   int mainscript;
811   while (kill_last_sprite());
812   kill_repeat_sounds_all();
813   kill_all_scripts_for_real();
814   mode = 0;
815   screenlock = 0;
816   kill_all_vars();
817   memset(&hm, 0, sizeof(hm));
818   input_set_default_buttons();
819 
820   mainscript = load_script("main", 0, /*true*/1);
821 
822   locate(mainscript, "main");
823   run_script(mainscript);
824   //lets attach our vars to the scripts
825   attach();
826   *yield = 1;
827 }
828 
dc_wait(int script,int * yield,int * preturnint,int delayms)829 void dc_wait(int script, int* yield, int* preturnint, int delayms)
830 {
831   kill_returning_stuff(script);
832   add_callback("", delayms, 0, script);
833   *yield = 1;
834 }
835 
dc_preload_seq(int script,int * yield,int * preturnint,int sequence)836 void dc_preload_seq(int script, int* yield, int* preturnint, int sequence)
837 {
838   check_seq_status(sequence);
839 }
840 
dc_script_attach(int script,int * yield,int * preturnint,int sprite)841 void dc_script_attach(int script, int* yield, int* preturnint, int sprite)
842 {
843   /* STOP_IF_BAD_SPRITE(sprite); */
844   rinfo[script]->sprite = sprite;
845 }
846 
dc_draw_hard_sprite(int script,int * yield,int * preturnint,int sprite)847 void dc_draw_hard_sprite(int script, int* yield, int* preturnint, int sprite)
848 {
849   STOP_IF_BAD_SPRITE(sprite);
850 
851   update_play_changes();
852   int l = sprite;
853   rect mhard;
854   rect_copy(&mhard, &k[seq[spr[l].pseq].frame[spr[l].pframe]].hardbox);
855   rect_offset(&mhard, (spr[l].x- 20), spr[l].y);
856 
857   fill_hardxy(mhard);
858   fill_back_sprites();
859   fill_hard_sprites();
860 }
861 
862 
dc_activate_bow(int script,int * yield,int * preturnint)863 void dc_activate_bow(int script, int* yield, int* preturnint)
864 {
865   spr[1].seq = 0;
866   spr[1].pseq = 100+spr[1].dir;
867   spr[1].pframe = 1;
868   bow.active = /*true*/1;
869   bow.script = script;
870   bow.hitme = /*false*/0;
871   bow.time = 0;
872 
873   /*      bowsound->Release();
874 
875   //lpDS->DuplicateSoundBuffer(ssound[42].sound,&bowsound);
876   //bowsound->Play(0, 0, DSBPLAY_LOOPING);
877   */
878 
879   *yield = 1;
880 }
881 
dc_disable_all_sprites(int script,int * yield,int * preturnint)882 void dc_disable_all_sprites(int script, int* yield, int* preturnint)
883 {
884   int jj;
885   for (jj = 1; jj < last_sprite_created; jj++)
886     if (spr[jj].active) spr[jj].disabled = /*true*/1;
887 }
888 
dc_draw_background(int script,int * yield,int * preturnint)889 void dc_draw_background(int script, int* yield, int* preturnint)
890 {
891   // (sprite, direction, until, nohard);
892   draw_map_game_background();
893 }
894 
dc_draw_hard_map(int script,int * yield,int * preturnint)895 void dc_draw_hard_map(int script, int* yield, int* preturnint)
896 {
897   // (sprite, direction, until, nohard);
898   log_info("Drawing hard map..");
899   update_play_changes();
900   fill_whole_hard();
901   fill_hard_sprites();
902   fill_back_sprites();
903 }
904 
dc_enable_all_sprites(int script,int * yield,int * preturnint)905 void dc_enable_all_sprites(int script, int* yield, int* preturnint)
906 {
907   int jj;
908   for (jj = 1; jj < last_sprite_created; jj++)
909     if (spr[jj].active) spr[jj].disabled = /*false*/0;
910 }
911 
dc_fade_down(int script,int * yield,int * preturnint)912 void dc_fade_down(int script, int* yield, int* preturnint)
913 {
914   // (sprite, direction, until, nohard);
915   if (process_upcycle)
916     {
917       log_error("[DinkC] %s:%d: fade_down() called during fade_up(), ignoring fade_down()",
918                 rinfo[script]->name, rinfo[script]->debug_line);
919     }
920   else
921     {
922       process_downcycle = /*true*/1;
923       cycle_clock = thisTickCount+1000;
924       cycle_script = script;
925     }
926   *yield = 1;
927 }
928 
dc_fade_up(int script,int * yield,int * preturnint)929 void dc_fade_up(int script, int* yield, int* preturnint)
930 {
931   // (sprite, direction, until, nohard);
932   if (process_downcycle)
933     {
934       log_error("[DinkC] %s:%d: fade_up() called during fade_down(), forcing fade_up()",
935                 rinfo[script]->name, rinfo[script]->debug_line);
936     }
937   process_downcycle = 0; // priority over concurrent fade_down()
938   process_upcycle = /*true*/1;
939   cycle_script = script;
940   *yield = 1;
941 }
942 
dc_get_burn(int script,int * yield,int * preturnint)943 void dc_get_burn(int script, int* yield, int* preturnint)
944 {
945   *preturnint = 1;
946 }
947 
dc_get_last_bow_power(int script,int * yield,int * preturnint)948 void dc_get_last_bow_power(int script, int* yield, int* preturnint)
949 {
950   *preturnint = bow.last_power;
951 }
952 
dc_get_version(int script,int * yield,int * preturnint)953 void dc_get_version(int script, int* yield, int* preturnint)
954 {
955   *preturnint = dversion;
956 }
957 
dc_kill_all_sounds(int script,int * yield,int * preturnint)958 void dc_kill_all_sounds(int script, int* yield, int* preturnint)
959 {
960   kill_repeat_sounds_all();
961 }
962 
dc_kill_game(int script,int * yield,int * preturnint)963 void dc_kill_game(int script, int* yield, int* preturnint)
964 {
965   log_info("Was told to kill game, so doing it like a good boy.");
966   /* Send QUIT event to the main game loop,
967      which will cleanly exit */
968   SDL_Event ev;
969   ev.type = SDL_QUIT;
970   SDL_PushEvent(&ev);
971   *yield = 1;
972 }
973 
dc_kill_this_task(int script,int * yield,int * preturnint)974 void dc_kill_this_task(int script, int* yield, int* preturnint)
975 {
976   // (sprite, direction, until, nohard);
977   if (rinfo[script]->proc_return != 0)
978     {
979       run_script(rinfo[script]->proc_return);
980     }
981   kill_script(script);
982   *yield = 1;
983 }
984 
dc_scripts_used(int script,int * yield,int * preturnint)985 void dc_scripts_used(int script, int* yield, int* preturnint)
986 {
987   int m = 0;
988   int i;
989   for (i = 1; i < MAX_SCRIPTS; i++)
990     if (rinfo[i] != NULL) m++;
991   *preturnint = m;
992 }
993 
dc_stopcd(int script,int * yield,int * preturnint)994 void dc_stopcd(int script, int* yield, int* preturnint)
995 {
996   log_debug("Stopped cd");
997   killcd();
998 }
999 
dc_stopmidi(int script,int * yield,int * preturnint)1000 void dc_stopmidi(int script, int* yield, int* preturnint)
1001 {
1002   // (sprite, direction, until, nohard);
1003   StopMidi();
1004 }
1005 
dc_turn_midi_off(int script,int * yield,int * preturnint)1006 void dc_turn_midi_off(int script, int* yield, int* preturnint)
1007 {
1008   midi_active = /*false*/0;
1009 }
1010 
dc_turn_midi_on(int script,int * yield,int * preturnint)1011 void dc_turn_midi_on(int script, int* yield, int* preturnint)
1012 {
1013   midi_active = /*true*/1;
1014 }
1015 
dc_count_item(int script,int * yield,int * preturnint,char * dcscript)1016 void dc_count_item(int script, int* yield, int* preturnint, char* dcscript)
1017 {
1018   int i;
1019   *preturnint = 0;
1020   for (i = 0; i < NB_ITEMS; i++)
1021     {
1022       if (play.item[i].active
1023 	  && compare(play.item[i].name, dcscript))
1024 	returnint++;
1025     }
1026 }
1027 
dc_count_magic(int script,int * yield,int * preturnint,char * dcscript)1028 void dc_count_magic(int script, int* yield, int* preturnint, char* dcscript)
1029 {
1030   int i;
1031   *preturnint = 0;
1032   for (i = 0; i < NB_MITEMS; i++)
1033     {
1034       if (play.mitem[i].active
1035 	  && compare(play.mitem[i].name, dcscript))
1036 	returnint++;
1037     }
1038 }
1039 
dc_compare_sprite_script(int script,int * yield,int * preturnint,int sprite,char * dcscript)1040 void dc_compare_sprite_script(int script, int* yield, int* preturnint, int sprite, char* dcscript)
1041 {
1042   *preturnint = 0;
1043   STOP_IF_BAD_SPRITE(sprite);
1044 
1045   if (spr[sprite].active)
1046     {
1047       if (spr[sprite].script == 0)
1048 	{
1049 	  log_error("[DinkC] compare_sprite_script: Sprite %d has no script.", sprite);
1050 	  return;
1051 	}
1052       if (rinfo[spr[sprite].script] == NULL)
1053 	{
1054 	  log_error("[DinkC] compare_sprite_script: script %d for sprite %d was already killed!.",
1055 		    sprite, spr[sprite].script);
1056 	  return;
1057 	}
1058       if (compare(dcscript, rinfo[spr[sprite].script]->name))
1059 	{
1060 	  *preturnint = 1;
1061 	  return;
1062 	}
1063     }
1064   else
1065     {
1066       log_error("[DinkC] compare_sprite_script: Can't compare sprite script, sprite not active.");
1067     }
1068 }
1069 
1070 
1071 
dc_compare_weapon(int script,int * yield,int * preturnint,char * dcscript)1072 void dc_compare_weapon(int script, int* yield, int* preturnint, char* dcscript)
1073 {
1074   *preturnint = 0;
1075   if (*pcur_weapon >= 1 && *pcur_weapon <= NB_ITEMS)
1076     {
1077       if (compare(play.item[*pcur_weapon - 1].name, dcscript))
1078 	*preturnint = 1;
1079     }
1080 }
1081 
dc_compare_magic(int script,int * yield,int * preturnint,char * dcscript)1082 void dc_compare_magic(int script, int* yield, int* preturnint, char* dcscript)
1083 {
1084   *preturnint = 0;
1085 
1086   if (*pcur_magic >= 1 && *pcur_magic <= NB_MITEMS)
1087     {
1088       if (dversion >= 108)
1089 	{
1090 	  if (compare(play.mitem[*pcur_magic - 1].name, dcscript))
1091 	    *preturnint = 1;
1092 	}
1093       else
1094 	{
1095 	  /* reproduce v1.07 bug: compare with regular item rather than
1096 	     magic item */
1097 	  if (compare(play.item[*pcur_magic - 1].name, dcscript))
1098 	    *preturnint = 1;
1099 	}
1100     }
1101 }
1102 
dc_init(int script,int * yield,int * preturnint,char * dink_ini_line)1103 void dc_init(int script, int* yield, int* preturnint, char* dink_ini_line)
1104 {
1105   figure_out(dink_ini_line);
1106 }
1107 
dc_dink_can_walk_off_screen(int script,int * yield,int * preturnint,int can_walk_off_screen_p)1108 void dc_dink_can_walk_off_screen(int script, int* yield, int* preturnint, int can_walk_off_screen_p)
1109 {
1110   walk_off_screen = can_walk_off_screen_p;
1111 }
1112 
dc_push_active(int script,int * yield,int * preturnint,int dink_can_push_p)1113 void dc_push_active(int script, int* yield, int* preturnint, int dink_can_push_p)
1114 {
1115   push_active = dink_can_push_p;
1116 }
1117 
dc_stop_entire_game(int script,int * yield,int * preturnint,int stop_p)1118 void dc_stop_entire_game(int script, int* yield, int* preturnint, int stop_p)
1119 {
1120   stop_entire_game = stop_p;
1121   SDL_BlitSurface(GFX_lpDDSBack, NULL, GFX_lpDDSTwo, NULL);
1122 }
1123 
1124 
dc_editor_type(int script,int * yield,int * preturnint,int editor_sprite,int type)1125 void dc_editor_type(int script, int* yield, int* preturnint, int editor_sprite, int type)
1126 {
1127   if (editor_sprite < 0 || editor_sprite >= 100)
1128     return;
1129   *preturnint = change_edit_char(editor_sprite, type,
1130 				 &play.spmap[*pmap].type[editor_sprite]);
1131 }
dc_editor_seq(int script,int * yield,int * preturnint,int editor_sprite,int seq)1132 void dc_editor_seq(int script, int* yield, int* preturnint, int editor_sprite, int seq)
1133 {
1134   if (editor_sprite < 0 || editor_sprite >= 100)
1135     return;
1136   *preturnint = change_edit(editor_sprite, seq,
1137 			    &play.spmap[*pmap].seq[editor_sprite]);
1138 }
1139 
dc_editor_frame(int script,int * yield,int * preturnint,int editor_sprite,int frame)1140 void dc_editor_frame(int script, int* yield, int* preturnint, int editor_sprite, int frame)
1141 {
1142   if (editor_sprite < 0 || editor_sprite >= 100)
1143     return;
1144   *preturnint = change_edit_char(editor_sprite, frame,
1145 				 &play.spmap[*pmap].frame[editor_sprite]);
1146 }
1147 
1148 
1149 
dc_move(int script,int * yield,int * preturnint,int sprite,int direction,int destination_limit,int ignore_hardness_p)1150 void dc_move(int script, int* yield, int* preturnint,
1151 	     int sprite, int direction, int destination_limit, int ignore_hardness_p)
1152 {
1153   STOP_IF_BAD_SPRITE(sprite);
1154   spr[sprite].move_active = /*true*/1;
1155   spr[sprite].move_dir = direction;
1156   spr[sprite].move_num = destination_limit;
1157   spr[sprite].move_nohard = ignore_hardness_p;
1158   spr[sprite].move_script = 0;
1159   log_debug("Moving: Sprite %d, dir %d, num %d", sprite, direction, destination_limit);
1160 }
1161 
dc_spawn(int script,int * yield,int * preturnint,char * dcscript)1162 void dc_spawn(int script, int* yield, int* preturnint,
1163 	     char* dcscript)
1164 {
1165   int mysc = load_script(dcscript, 1000, /*true*/1);
1166   if (mysc == 0)
1167     {
1168       *preturnint = 0;
1169       return;
1170     }
1171   locate(mysc, "MAIN");
1172   int tempreturn = mysc;
1173   run_script(mysc);
1174   *preturnint = tempreturn;
1175 }
1176 
dc_run_script_by_number(int script,int * yield,int * preturnint,int script_index,char * funcname)1177 void dc_run_script_by_number(int script, int* yield, int* preturnint,
1178 			     int script_index, char* funcname)
1179 {
1180   if (locate(script_index, funcname))
1181     run_script(script_index);
1182 }
1183 
dc_playmidi(int script,int * yield,int * preturnint,char * midi_file)1184 void dc_playmidi(int script, int* yield, int* preturnint,
1185 		 char* midi_file)
1186 {
1187   //StopMidi();
1188   int regm = atol(midi_file);
1189   log_debug("Processing playmidi command.");
1190   if (regm > 1000)
1191     //cd directive
1192     {
1193       int cd_track = regm - 1000;
1194       log_info("playmidi - cd play command detected.");
1195 
1196       if (cd_inserted)
1197 	{
1198 	  if (cd_track == last_cd_track
1199 	      && cdplaying())
1200 	    {
1201 	      *yield = 1;
1202 	      return;
1203 	    }
1204 
1205 	  log_info("Playing CD track %d.", cd_track);
1206 	  if (PlayCD(cd_track) >= 0)
1207 	    return;
1208 	}
1209       else
1210 	{
1211 	  //cd isn't instered, can't play CD song!!!
1212 	  char buf[10+4+1];
1213 	  sprintf(buf, "%d.mid", cd_track);
1214 	  log_info("Playing midi %s.", buf);
1215 	  PlayMidi(buf);
1216 	  // then try to play 'midi_file' as well:
1217 	  // (necessary for START.c:playmidi("1003.mid"))
1218 	}
1219     }
1220   log_info("Playing midi %s.", midi_file);
1221   PlayMidi(midi_file);
1222 }
1223 
dc_playsound(int script,int * yield,int * preturnint,int sound_number,int min_speed,int rand_speed_to_add,int sprite,int repeat_p)1224 void dc_playsound(int script, int* yield, int* preturnint,
1225 		  int sound_number, int min_speed, int rand_speed_to_add, int sprite, int repeat_p)
1226 {
1227   if (sprite < 0 || sprite >= MAX_SPRITES_AT_ONCE)
1228     sprite = 0; // no "3d" volume effect... and no segfault :p
1229 
1230   if (sound_on)
1231     *preturnint = playsound(sound_number, min_speed, rand_speed_to_add, sprite, repeat_p);
1232   else
1233     *preturnint = 0;
1234 }
1235 
dc_sound_set_survive(int script,int * yield,int * preturnint,int sound_bank,int survive_p)1236 void dc_sound_set_survive(int script, int* yield, int* preturnint,
1237 			  int sound_bank, int survive_p)
1238 {
1239   //let's set one sound to survive
1240   if (sound_on && sound_bank > 0)
1241     sound_set_survive(sound_bank, survive_p);
1242 }
1243 
dc_sound_set_vol(int script,int * yield,int * preturnint,int sound_bank,int vol)1244 void dc_sound_set_vol(int script, int* yield, int* preturnint,
1245 		      int sound_bank, int vol)
1246 {
1247   if (sound_on && sound_bank > 0)
1248     sound_set_vol(sound_bank, vol);
1249 }
1250 
dc_sound_set_kill(int script,int * yield,int * preturnint,int sound_bank)1251 void dc_sound_set_kill(int script, int* yield, int* preturnint,
1252 		       int sound_bank)
1253 {
1254   if (sound_on && sound_bank > 0)
1255     sound_set_kill(sound_bank);
1256 }
1257 
1258 
dc_save_game(int script,int * yield,int * preturnint,int game_slot)1259 void dc_save_game(int script, int* yield, int* preturnint, int game_slot)
1260 {
1261   save_game(game_slot);
1262 }
1263 
dc_force_vision(int script,int * yield,int * preturnint,int vision)1264 void dc_force_vision(int script, int* yield, int* preturnint, int vision)
1265 {
1266   *pvision = vision;
1267   rinfo[script]->sprite = 1000;
1268   fill_whole_hard();
1269   draw_map_game();
1270 }
1271 
dc_fill_screen(int script,int * yield,int * preturnint,int palette_index)1272 void dc_fill_screen(int script, int* yield, int* preturnint, int palette_index)
1273 {
1274   fill_screen(palette_index);
1275 }
1276 
dc_load_game(int script,int * yield,int * preturnint,int game_slot)1277 void dc_load_game(int script, int* yield, int* preturnint, int game_slot)
1278 {
1279   kill_all_scripts_for_real();
1280   *preturnint = load_game(game_slot);
1281   log_info("load completed.");
1282   if (rinfo[script] == NULL)
1283     log_error("[DinkC] Script %d is suddenly null!", script);
1284   *pupdate_status = 1;
1285   draw_status_all();
1286   *yield = 1;
1287 }
1288 
dc_game_exist(int script,int * yield,int * preturnint,int game_slot)1289 void dc_game_exist(int script, int* yield, int* preturnint, int game_slot)
1290 {
1291   FILE *fp;
1292   if ((fp = paths_savegame_fopen(game_slot, "rb")) != NULL)
1293     {
1294       fclose(fp);
1295       *preturnint = 1;
1296     }
1297   else
1298     {
1299       *preturnint = 0;
1300     }
1301 }
1302 
dc_move_stop(int script,int * yield,int * preturnint,int sprite,int direction,int destination_limit,int ignore_hardness_p)1303 void dc_move_stop(int script, int* yield, int* preturnint,
1304 		  int sprite, int direction, int destination_limit, int ignore_hardness_p)
1305 {
1306   STOP_IF_BAD_SPRITE(sprite);
1307   spr[sprite].move_active = /*true*/1;
1308   spr[sprite].move_dir = direction;
1309   spr[sprite].move_num = destination_limit;
1310   spr[sprite].move_nohard = ignore_hardness_p;
1311   spr[sprite].move_script = script;
1312   log_debug("Move_stop: Sprite %d, dir %d, num %d", sprite, direction, destination_limit);
1313   *yield = 1;
1314 }
1315 
dc_load_sound(int script,int * yield,int * preturnint,char * wav_file,int sound_index)1316 void dc_load_sound(int script, int* yield, int* preturnint,
1317 		   char* wav_file, int sound_index)
1318 {
1319   if (sound_on)
1320     {
1321       log_info("getting %s..", wav_file);
1322       CreateBufferFromWaveFile(wav_file, sound_index);
1323     }
1324 }
1325 
dc_debug(int script,int * yield,int * preturnint,char * text)1326 void dc_debug(int script, int* yield, int* preturnint,
1327 	      char* text)
1328 {
1329   /* Convert from Latin-1 (.c) to UTF-8 (SDL) since the message is
1330      shown on the screen in debug mode */
1331   char* buf = latin1_to_utf8(text);
1332   decipher_string(&buf, script);
1333   log_debug(buf);
1334   free(buf);
1335 }
1336 
dc_busy(int script,int * yield,int * preturnint,int sprite)1337 void dc_busy(int script, int* yield, int* preturnint,
1338 	     int sprite)
1339 {
1340   STOP_IF_BAD_SPRITE(sprite);
1341   *preturnint = does_sprite_have_text(nlist[0]);
1342   log_debug("Busy: Return int is %d and %d.  Nlist got %d.",
1343 	    *preturnint, does_sprite_have_text(sprite), sprite);
1344 }
1345 
1346 
dc_make_global_int(int script,int * yield,int * preturnint,char * varname,int default_val)1347 void dc_make_global_int(int script, int* yield, int* preturnint,
1348 			char* varname, int default_val)
1349 {
1350   make_int(varname, default_val, 0, script);
1351 }
1352 
dc_inside_box(int script,int * yield,int * preturnint,int x,int y,int left,int right,int top,int bottom)1353 void dc_inside_box(int script, int* yield, int* preturnint,
1354 		   int x, int y, int left, int right, int top, int bottom)
1355 {
1356   rect myrect;
1357   rect_set(&myrect, left, right, top, bottom);
1358   *preturnint = inside_box(x, y, myrect);
1359   log_debug("Inbox is int is %d and %d.  Nlist got %d.", *preturnint, x, y);
1360 }
1361 
dc_random(int script,int * yield,int * preturnint,int range,int base)1362 void dc_random(int script, int* yield, int* preturnint,
1363 	       int range, int base)
1364 {
1365   *preturnint = (rand() % range) + base;
1366 }
1367 
dc_initfont(int script,int * yield,int * preturnint,char * fontname)1368 void dc_initfont(int script, int* yield, int* preturnint,
1369 		 char* fontname)
1370 {
1371   initfont(fontname);
1372   log_info("Initted font %s", fontname);
1373 }
1374 
dc_set_mode(int script,int * yield,int * preturnint,int newmode)1375 void dc_set_mode(int script, int* yield, int* preturnint,
1376 		 int newmode)
1377 {
1378   mode = newmode;
1379   *preturnint = mode;
1380 }
1381 
dc_kill_shadow(int script,int * yield,int * preturnint,int sprite)1382 void dc_kill_shadow(int script, int* yield, int* preturnint,
1383 		    int sprite)
1384 {
1385   /* STOP_IF_BAD_SPRITE(sprite); */
1386   int jj;
1387   for (jj = 1; jj <= last_sprite_created; jj++)
1388     {
1389       if (spr[jj].brain == 15 && spr[jj].brain_parm == sprite)
1390 	{
1391 	  spr[jj].active = 0;
1392 	}
1393     }
1394 }
1395 
dc_create_sprite(int script,int * yield,int * preturnint,int x,int y,int brain,int sequence,int frame)1396 void dc_create_sprite(int script, int* yield, int* preturnint,
1397 		      int x, int y, int brain, int sequence, int frame)
1398 {
1399   *preturnint = add_sprite_dumb(x, y, brain, sequence, frame, 100/*size*/);
1400 }
1401 
dc_sp(int script,int * yield,int * preturnint,int editor_sprite)1402 void dc_sp(int script, int* yield, int* preturnint,
1403 	   int editor_sprite)
1404 {
1405   int i = find_sprite(editor_sprite);
1406   if (i != 0) {
1407     log_debug("Sp returned %d.", i);
1408     *preturnint = i;
1409     return;
1410   }
1411   if (last_sprite_created == 1)
1412     log_warn("you can't call SP() from a screen-ref,"
1413 	     " no sprites have been created yet.");
1414   *preturnint = 0; /* not found */
1415 }
1416 
dc_is_script_attached(int script,int * yield,int * preturnint,int sprite)1417 void dc_is_script_attached(int script, int* yield, int* preturnint,
1418 			   int sprite)
1419 {
1420   STOP_IF_BAD_SPRITE(sprite);
1421   *preturnint = spr[sprite].script;
1422 }
1423 
dc_get_sprite_with_this_brain(int script,int * yield,int * preturnint,int brain,int sprite_ignore)1424 void dc_get_sprite_with_this_brain(int script, int* yield, int* preturnint,
1425 				   int brain, int sprite_ignore)
1426 {
1427   int i;
1428   for (i = 1; i <= last_sprite_created; i++)
1429     {
1430       if (spr[i].brain == brain && i != sprite_ignore && spr[i].active == 1)
1431 	{
1432 	  log_debug("Ok, sprite with brain %d is %d", brain, i);
1433 	  *preturnint = i;
1434 	  return;
1435 	}
1436     }
1437   *preturnint = 0; /* not found */
1438 }
1439 
dc_get_rand_sprite_with_this_brain(int script,int * yield,int * preturnint,int brain,int sprite_ignore)1440 void dc_get_rand_sprite_with_this_brain(int script, int* yield, int* preturnint,
1441 					int brain, int sprite_ignore)
1442 {
1443   int i;
1444   int nb_matches = 0;
1445   for (i = 1; i <= last_sprite_created; i++)
1446     {
1447       if (spr[i].brain == brain && i != sprite_ignore && spr[i].active == 1)
1448 	nb_matches++;
1449     }
1450   if (nb_matches == 0)
1451     {
1452       log_debug("Get rand brain can't find any brains with %d.", brain);
1453       *preturnint = 0;
1454       return;
1455     }
1456 
1457   int mypick = (rand() % nb_matches) + 1;
1458   int ii;
1459   int cur_match = 0;
1460   for (ii = 1; ii <= last_sprite_created; ii++)
1461     {
1462       if (spr[ii].brain == brain && ii != sprite_ignore && spr[ii].active == 1)
1463 	{
1464 	  cur_match++;
1465 	  if (cur_match == mypick)
1466 	    {
1467 	      *preturnint = ii;
1468 	      return;
1469 	    }
1470 	}
1471     }
1472   *preturnint = 0; /* not found */
1473 }
1474 
1475 /* BIG FAT WARNING: in DinkC, buttons are in [1, 10] (not [0, 9]) */
dc_set_button(int script,int * yield,int * preturnint,int button,int function)1476 void dc_set_button(int script, int* yield, int* preturnint,
1477 		   int button, int function)
1478 {
1479   input_set_button_action(button-1, function);
1480 }
1481 
dc_hurt(int script,int * yield,int * preturnint,int sprite,int damage)1482 void dc_hurt(int script, int* yield, int* preturnint,
1483 	     int sprite, int damage)
1484 {
1485   STOP_IF_BAD_SPRITE(sprite);
1486 
1487   if (dversion >= 108)
1488     {
1489       // With v1.07 hurt(&sthing, -1) would run hit(), with v1.08 it
1490       // doesn't (after redink1 tried to fix a game freeze bug that I
1491       // can't reproduce)
1492       if (damage < 0)
1493 	return;
1494     }
1495 
1496   if (hurt_thing(sprite, damage, 0) > 0)
1497     random_blood(spr[sprite].x, spr[sprite].y-40, sprite);
1498 
1499   if (spr[sprite].nohit != 1
1500       && spr[sprite].script != 0
1501       && locate(spr[sprite].script, "HIT"))
1502     {
1503       if (rinfo[script]->sprite != 1000)
1504 	{
1505 	  *penemy_sprite = rinfo[script]->sprite;
1506 	  //redink1 addition of missle_source stuff
1507 	  if (dversion >= 108)
1508 	    *pmissle_source = rinfo[script]->sprite;
1509 	}
1510       kill_returning_stuff(spr[sprite].script);
1511       run_script(spr[sprite].script);
1512     }
1513 }
1514 
dc_screenlock(int script,int * yield,int * preturnint,int param)1515 void dc_screenlock(int script, int* yield, int* preturnint,
1516 		   int param)
1517 {
1518   if (dversion >= 108)
1519     {
1520       // returns the screenlock value to DinkC
1521       if (param == 0 || param == 1)
1522 	screenlock = param;
1523       *preturnint = screenlock;
1524       /* Note: redink1's v1.08 always set returnint, even if too many
1525 	 parameters were passed. Since this breaks the logic of DinkC
1526 	 interpreter clarification (return a variable value when bad
1527 	 parameters), we won't reproduce this particular bug
1528 	 here. AFAICS no D-Mod abused 'screenlock' this way. */
1529     }
1530   else
1531     {
1532       screenlock = param;
1533     }
1534 }
1535 
1536 
1537 /****************/
1538 /*  v1.08-only  */
1539 /*              */
1540 /****************/
1541 
dc_sp_blood_num(int script,int * yield,int * preturnint,int sprite,int sparg)1542 void dc_sp_blood_num(int script, int* yield, int* preturnint, int sprite, int sparg)
1543 {
1544   RETURN_NEG_IF_BAD_SPRITE(sprite);
1545   change_sprite (sprite, sparg, &spr[sprite].bloodnum);
1546   *preturnint = spr[sprite].bloodseq;
1547 }
1548 
dc_sp_blood_seq(int script,int * yield,int * preturnint,int sprite,int sparg)1549 void dc_sp_blood_seq(int script, int* yield, int* preturnint, int sprite, int sparg)
1550 {
1551   RETURN_NEG_IF_BAD_SPRITE(sprite);
1552   change_sprite (sprite, sparg, &spr[sprite].bloodseq);
1553   *preturnint = spr[sprite].bloodseq;
1554 }
1555 
dc_sp_clip_bottom(int script,int * yield,int * preturnint,int sprite,int sparg)1556 void dc_sp_clip_bottom(int script, int* yield, int* preturnint, int sprite, int sparg)
1557 {
1558   RETURN_NEG_IF_BAD_SPRITE(sprite);
1559   change_sprite (sprite, sparg, &spr[sprite].alt.bottom);
1560   *preturnint = spr[sprite].alt.bottom;
1561 }
1562 
dc_sp_clip_left(int script,int * yield,int * preturnint,int sprite,int sparg)1563 void dc_sp_clip_left(int script, int* yield, int* preturnint, int sprite, int sparg)
1564 {
1565   RETURN_NEG_IF_BAD_SPRITE(sprite);
1566   change_sprite (sprite, sparg, &spr[sprite].alt.left);
1567   *preturnint = spr[sprite].alt.left;
1568 }
1569 
dc_sp_clip_right(int script,int * yield,int * preturnint,int sprite,int sparg)1570 void dc_sp_clip_right(int script, int* yield, int* preturnint, int sprite, int sparg)
1571 {
1572   RETURN_NEG_IF_BAD_SPRITE(sprite);
1573   change_sprite (sprite, sparg, &spr[sprite].alt.right);
1574   *preturnint = spr[sprite].alt.right;
1575 }
1576 
dc_sp_clip_top(int script,int * yield,int * preturnint,int sprite,int sparg)1577 void dc_sp_clip_top(int script, int* yield, int* preturnint, int sprite, int sparg)
1578 {
1579   RETURN_NEG_IF_BAD_SPRITE(sprite);
1580   change_sprite (sprite, sparg, &spr[sprite].alt.top);
1581   *preturnint = spr[sprite].alt.top;
1582 }
1583 
dc_sp_custom(int script,int * yield,int * preturnint,char * key,int sprite,int val)1584 void dc_sp_custom(int script, int* yield, int* preturnint, char* key, int sprite, int val)
1585 {
1586   RETURN_NEG_IF_BAD_SPRITE(sprite);
1587   if (spr[sprite].active == 0)
1588     {
1589       *preturnint = -1;
1590     }
1591   else
1592     {
1593       // Set the value
1594       if (val != -1)
1595 	dinkc_sp_custom_set(spr[sprite].custom, key, val);
1596       *preturnint = dinkc_sp_custom_get(spr[sprite].custom, key);
1597     }
1598 }
1599 
1600 
1601 /**
1602  * Like sp_mx but use change_sprite_noreturn, so allow setting the
1603  * value to -1.
1604  */
dc_sp_move_x(int script,int * yield,int * preturnint,int sprite,int dx)1605 void dc_sp_move_x(int script, int* yield, int* preturnint, int sprite, int dx)
1606   {
1607     STOP_IF_BAD_SPRITE(sprite);
1608     change_sprite_noreturn (sprite, dx, &spr[sprite].mx);
1609   }
1610 
1611 /**
1612  * Like sp_my but use change_sprite_noreturn, so allow setting the
1613  * value to -1.
1614  */
dc_sp_move_y(int script,int * yield,int * preturnint,int sprite,int dy)1615 void dc_sp_move_y(int script, int* yield, int* preturnint, int sprite, int dy)
1616   {
1617     STOP_IF_BAD_SPRITE(sprite);
1618     change_sprite_noreturn (sprite, dy, &spr[sprite].my);
1619   }
1620 
dc_sp_freeze(int script,int * yield,int * preturnint,int sprite,int frozen_p)1621 void dc_sp_freeze(int script, int* yield, int* preturnint, int sprite, int frozen_p)
1622 {
1623   STOP_IF_BAD_SPRITE(sprite);
1624   // Set the value
1625   if (frozen_p == 0)
1626     spr[sprite].freeze = 0;
1627   else if (frozen_p == 1)
1628     spr[sprite].freeze = script;
1629   /* else -> invalid value */
1630 
1631   // Return the (normalized) value
1632   *preturnint = (spr[sprite].freeze > 0);
1633 }
1634 
1635 
dc_clear_editor_info(int script,int * yield,int * preturnint)1636 void dc_clear_editor_info(int script, int* yield, int* preturnint)
1637 {
1638     int i;
1639     for (i = 0; i < 769; i++)
1640       {
1641 	int j;
1642 	for (j = 0; j < 100; j++)
1643 	  {
1644 	    play.spmap[i].seq[j] = 0;
1645 	    play.spmap[i].frame[j] = 0;
1646 	    play.spmap[i].type[j] = 0;
1647 	    play.spmap[i].last_time = 0;
1648 	  }
1649       }
1650     *preturnint = 1;
1651 }
1652 
dc_get_date_day(int script,int * yield,int * preturnint)1653 void dc_get_date_day(int script, int* yield, int* preturnint)
1654 {
1655     char mytime[5];
1656     time_t ct;
1657     struct tm* time_now;
1658     time (&ct);
1659     time_now = localtime (&ct);
1660     strftime (mytime, 5, "%d", time_now);
1661     *preturnint = atoi (mytime);
1662 }
1663 
dc_get_date_month(int script,int * yield,int * preturnint)1664 void dc_get_date_month(int script, int* yield, int* preturnint)
1665 {
1666     char mytime[5];
1667     time_t ct;
1668     struct tm* time_now;
1669     time (&ct);
1670     time_now = localtime (&ct);
1671     strftime (mytime, 5, "%m", time_now);
1672     *preturnint = atoi (mytime);
1673 }
1674 
dc_get_date_year(int script,int * yield,int * preturnint)1675 void dc_get_date_year(int script, int* yield, int* preturnint)
1676 {
1677     char mytime[5];
1678     time_t ct;
1679     struct tm* time_now;
1680     time (&ct);
1681     time_now = localtime (&ct);
1682     strftime (mytime, 5, "%Y", time_now);
1683     *preturnint = atoi (mytime);
1684 }
1685 
dc_get_time_game(int script,int * yield,int * preturnint)1686 void dc_get_time_game(int script, int* yield, int* preturnint)
1687 {
1688     time_t ct;
1689     time (&ct);
1690     *preturnint = play.minutes + (difftime (ct, time_start) / 60);
1691 }
1692 
dc_get_time_real(int script,int * yield,int * preturnint)1693 void dc_get_time_real(int script, int* yield, int* preturnint)
1694 {
1695     char mytime[5];
1696     time_t ct;
1697     struct tm* time_now;
1698     time (&ct);
1699     time_now = localtime (&ct);
1700     strftime (mytime, 5, "%M", time_now);
1701     *preturnint = atoi (mytime);
1702     strftime (mytime, 5, "%H", time_now);
1703     *preturnint += 60 * atoi (mytime);
1704 }
1705 
dc_get_truecolor(int script,int * yield,int * preturnint)1706 void dc_get_truecolor(int script, int* yield, int* preturnint)
1707 {
1708     *preturnint = truecolor;
1709 }
1710 
dc_show_console(int script,int * yield,int * preturnint)1711 void dc_show_console(int script, int* yield, int* preturnint)
1712 {
1713     console_active = 1;
1714 }
1715 
dc_show_inventory(int script,int * yield,int * preturnint)1716 void dc_show_inventory(int script, int* yield, int* preturnint)
1717 {
1718     show_inventory = 1;
1719 }
1720 
dc_var_used(int script,int * yield,int * preturnint)1721 void dc_var_used(int script, int* yield, int* preturnint)
1722 {
1723     int m = 0;
1724     int i;
1725     for (i = 1; i < MAX_VARS; i++)
1726       if (play.var[i].active == 1)
1727 	m++;
1728     *preturnint = m;
1729 }
1730 
1731 
dc_loopmidi(int script,int * yield,int * preturnint,int loop_midi)1732 void dc_loopmidi(int script, int* yield, int* preturnint, int loop_midi)
1733 {
1734   loopmidi(loop_midi);
1735 }
1736 
1737 
dc_math_abs(int script,int * yield,int * preturnint,int val)1738 void dc_math_abs(int script, int* yield, int* preturnint, int val)
1739 {
1740   *preturnint = abs(val);
1741 }
1742 
dc_math_sqrt(int script,int * yield,int * preturnint,int val)1743 void dc_math_sqrt(int script, int* yield, int* preturnint, int val)
1744 {
1745   *preturnint = sqrt(abs(val));
1746 }
1747 
dc_math_mod(int script,int * yield,int * preturnint,int val,int div)1748 void dc_math_mod(int script, int* yield, int* preturnint, int val, int div)
1749 {
1750   *preturnint = (val % div);
1751 }
1752 
dc_make_global_function(int script,int * yield,int * preturnint,char * dcscript,char * procname)1753 void dc_make_global_function(int script, int* yield, int* preturnint, char* dcscript, char* procname)
1754 {
1755   make_function(dcscript, procname);
1756 }
1757 
dc_set_save_game_info(int script,int * yield,int * preturnint,char * info)1758 void dc_set_save_game_info(int script, int* yield, int* preturnint, char* info)
1759 {
1760   strncpy(save_game_info, info, LEN_SAVE_GAME_INFO);
1761   save_game_info[LEN_SAVE_GAME_INFO - 1] = '\0';
1762 }
1763 
dc_load_map(int script,int * yield,int * preturnint,char * mapdat_file,char * dinkdat_file)1764 void dc_load_map(int script, int* yield, int* preturnint, char* mapdat_file, char* dinkdat_file)
1765 {
1766   // load a new map/dink.dat
1767   strcpy(current_map, mapdat_file);
1768   strcpy(current_dat, dinkdat_file);
1769   load_info();
1770 }
1771 
dc_load_tile(int script,int * yield,int * preturnint,char * tileset_file,int tileset_index)1772 void dc_load_tile(int script, int* yield, int* preturnint, char* tileset_file, int tileset_index)
1773 {
1774   // load new tiles
1775   if (tileset_index >= 1 && tileset_index <= GFX_TILES_NB_SETS)
1776     {
1777       //Load in the new tiles...
1778       tiles_load_slot(tileset_file, tileset_index);
1779 
1780       //Store in save game
1781       strncpy(play.tile[tileset_index].file, tileset_file, 50);
1782     }
1783   else
1784     {
1785       log_error("[DinkC] %s:%d:%s: dc_load_tile: invalid tileset index '%d'",
1786 		rinfo[script]->name, rinfo[script]->debug_line, cur_funcname,
1787 		tileset_index);
1788     }
1789 }
1790 
dc_map_tile(int script,int * yield,int * preturnint,int tile_position,int tile_index)1791 void dc_map_tile(int script, int* yield, int* preturnint, int tile_position, int tile_index)
1792 {
1793   // developers can change or see what tile is at any given position
1794   // Yeah... they can only modify valid tiles
1795   if (tile_position >= 1 && tile_position <= 96)
1796     {
1797       int max = GFX_TILES_NB_SQUARES - 1;
1798 
1799       if (tile_index >= 0 && tile_index <= max)
1800 	pam.t[tile_position - 1].square_full_idx0 = tile_index;
1801       else
1802 	log_error("[DinkC] %s:%d:%s: dc_map_tile: invalid tile index '%d'",
1803 		  rinfo[script]->name, rinfo[script]->debug_line, cur_funcname,
1804 		  tile_index);
1805 
1806       *preturnint = pam.t[tile_position - 1].square_full_idx0;
1807     }
1808 }
1809 
dc_map_hard_tile(int script,int * yield,int * preturnint,int tile_position,int hard_tile_index)1810 void dc_map_hard_tile(int script, int* yield, int* preturnint, int tile_position, int hard_tile_index)
1811 {
1812   // developers can retrieve/modify a hard tile
1813   // Yeah... they can only modify valid tiles
1814   if (tile_position >= 1 && tile_position <= 96)
1815     {
1816       //Only change the value if it is greater than 0...
1817       if (hard_tile_index > 0)
1818 	pam.t[tile_position - 1].althard = hard_tile_index;
1819       *preturnint = pam.t[tile_position - 1].althard;
1820     }
1821 }
1822 
1823 
dc_load_palette(int script,int * yield,int * preturnint,char * bmp_file)1824 void dc_load_palette(int script, int* yield, int* preturnint, char* bmp_file)
1825 {
1826   // load a palette from any bmp
1827   if (gfx_palette_set_from_bmp(bmp_file) < 0)
1828     log_error("[DinkC] Couldn't load palette from '%s': %s", bmp_file, SDL_GetError());
1829   gfx_palette_get_phys(GFX_real_pal);
1830 
1831   //Store in save game
1832   strncpy(play.palette, slist[0], 50);
1833 }
1834 
dc_get_item(int script,int * yield,int * preturnint,char * dcscript)1835 void dc_get_item(int script, int* yield, int* preturnint, char* dcscript)
1836 {
1837   // get index of specified item
1838   *preturnint = 0;
1839   {
1840     int i = 0;
1841     for (; i < NB_ITEMS; i++)
1842       {
1843 	if (play.item[i].active
1844 	    && compare(play.item[i].name, dcscript))
1845 	  {
1846 	    *preturnint = i + 1;
1847 	    break;
1848 	  }
1849       }
1850   }
1851 }
1852 
dc_get_magic(int script,int * yield,int * preturnint,char * dcscript)1853 void dc_get_magic(int script, int* yield, int* preturnint, char* dcscript)
1854 {
1855   // get index of specified magic spell
1856   *preturnint = 0;
1857   {
1858     int i = 0;
1859     for (; i < NB_MITEMS; i++)
1860       {
1861 	if (play.mitem[i].active
1862 	    && compare(play.mitem[i].name, dcscript))
1863 	  {
1864 	    *preturnint = i + 1;
1865 	    break;
1866 	  }
1867       }
1868   }
1869 }
1870 
dc_set_font_color(int script,int * yield,int * preturnint,int index,int r,int g,int b)1871 void dc_set_font_color(int script, int* yield, int* preturnint, int index, int r, int g, int b)
1872 {
1873   // sets font color
1874   set_font_color(index, r, g, b);
1875 }
1876 
dc_get_next_sprite_with_this_brain(int script,int * yield,int * preturnint,int brain,int sprite_ignore,int sprite_start_with)1877 void dc_get_next_sprite_with_this_brain(int script, int* yield, int* preturnint,
1878 					int brain, int sprite_ignore, int sprite_start_with)
1879 {
1880   // make Paul Pliska's life more fulfilling
1881   {
1882     int i = sprite_start_with;
1883     for (; i <= last_sprite_created; i++)
1884       {
1885 	if ((spr[i].brain == brain) && (i != sprite_ignore))
1886 	  if (spr[i].active == 1)
1887 	    {
1888 	      log_debug("Ok, sprite with brain %d is %d", brain, i);
1889 	      *preturnint = i;
1890 	      return;
1891 	    }
1892       }
1893   }
1894   log_debug("Ok, sprite with brain %d is 0", brain);
1895   *preturnint = 0; /* not found */
1896 }
1897 
dc_set_smooth_follow(int script,int * yield,int * preturnint,int smooth_p)1898 void dc_set_smooth_follow(int script, int* yield, int* preturnint, int smooth_p)
1899 {
1900   if (smooth_p == 0)
1901     smooth_follow = 0;
1902   else if (smooth_p == 1)
1903     smooth_follow = 1;
1904 }
dc_set_dink_base_push(int script,int * yield,int * preturnint,int base_sequence)1905 void dc_set_dink_base_push(int script, int* yield, int* preturnint, int base_sequence)
1906 {
1907   dink_base_push = base_sequence;
1908 }
1909 
dc_callback_kill(int script,int * yield,int * preturnint,int callback_index)1910 void dc_callback_kill(int script, int* yield, int* preturnint, int callback_index)
1911 {
1912   log_debug("setting callback random");
1913   kill_callback(callback_index);
1914 }
1915 
1916 
1917 /****************/
1918 /*  Hash table  */
1919 /*              */
1920 /****************/
1921 
1922 /* Map DinkC function with C function */
1923 #define NB_COMMON_ARGS 3
1924 struct binding
1925 {
1926   char* funcname; /* name of the function, as string */
1927   void* func;     /* pointer to the C function */
1928   int params[10]; /* DinkC specification of params e.g. {2,1,1,0,0,0,0,0,0,0} */
1929   enum dinkc_parser_state badparams_dcps; /* if the DinkC script has bad arguments, skip line or yield? */
1930   int badparams_returnint_p; /* overwrite returnint if bad arguments? */
1931   int badparams_returnint;   /* value for returnint if badparams_returnint_p is 1 */
1932 };
1933 
1934 /* Hash table of bindings, build dynamically (depending on 'dversion',
1935    not statically) */
1936 Hash_table* bindings = NULL;
1937 
1938 /* Auxiliary functions for hash */
dinkc_bindings_hasher(const void * x,size_t tablesize)1939 static size_t dinkc_bindings_hasher(const void *x, size_t tablesize)
1940 {
1941   return hash_string(((struct binding*)x)->funcname, tablesize);
1942   // We could also call 'hash_pjw' from module 'hash-pjw'
1943 }
1944 
dinkc_bindings_comparator(const void * a,const void * b)1945 static bool dinkc_bindings_comparator(const void* a, const void* b)
1946 {
1947   return !strcmp(((struct binding*)a)->funcname,
1948 		 ((struct binding*)b)->funcname);
1949 }
1950 
1951 /**
1952  * Search a binding by function name
1953  */
dinkc_bindings_lookup(dinkc_sp_custom hash,char * funcname)1954 struct binding* dinkc_bindings_lookup(dinkc_sp_custom hash, char* funcname)
1955 {
1956   struct binding search;
1957   struct binding *result;
1958   char* lcfuncname = strdup(funcname);
1959   char* pc;
1960   for (pc = lcfuncname; *pc != '\0'; pc++)
1961     *pc = tolower(*pc);
1962   search.funcname = lcfuncname;
1963 
1964   result = hash_lookup(hash, &search);
1965 
1966   free(lcfuncname);
1967   return result;
1968 }
1969 
1970 /**
1971  * Add a new binding to hash table 'hash'.
1972  */
dinkc_bindings_add(Hash_table * hash,struct binding * pbd)1973 static void dinkc_bindings_add(Hash_table* hash, struct binding* pbd)
1974 {
1975   void* slot = dinkc_bindings_lookup(hash, pbd->funcname);
1976   if (slot != NULL)
1977     {
1978       log_fatal("Internal error: attempting to redeclare DinkC function %s", pbd->funcname);
1979       exit(EXIT_FAILURE);
1980     }
1981 
1982   /* Copy uninitialized binding in hash table */
1983   struct binding* newslot = malloc(sizeof(struct binding));
1984   *newslot = *pbd;
1985   if (hash_insert(hash, newslot) == NULL)
1986     {
1987       log_fatal("Not enough memory to declare DinkC function %s", pbd->funcname);
1988       exit(EXIT_FAILURE);
1989     }
1990 }
1991 
1992 
1993 /**
1994  * Add a DinkC binding
1995  *
1996  * Simple macro to allow using struct initializer e.g. {2,1,1,0....}
1997  * when declaring a DinkC function.
1998  */
1999 #define DCBD_ADD(name, ...)                                 \
2000 {                                                           \
2001   struct binding bd = { #name, dc_ ## name, __VA_ARGS__ };  \
2002   dinkc_bindings_add(bindings, &bd);                        \
2003 }
2004 /**
2005  * Map DinkC functions to C functions, with their arguments
2006  */
dinkc_bindings_init()2007 void dinkc_bindings_init()
2008 {
2009   /* Set all string params pointers to NULL */
2010   int i = 0;
2011   for (; i < 10; i++)
2012     {
2013       /* alloc empty strings; will be replaced as needed in
2014 	 get_parm(...) */
2015       slist[i] = strdup("");
2016     }
2017 
2018   Hash_tuning* default_tuner = NULL;
2019   int start_size = 400; /* ~nbfuncs*2 to try and avoid collisions */
2020   bindings = hash_initialize(start_size, default_tuner,
2021 			     dinkc_bindings_hasher, dinkc_bindings_comparator,
2022 			     free);
2023 
2024 
2025   /* funcname, params, badparams_dcps, badparams_returnint_p, badparams_returnint */
2026 
2027   DCBD_ADD(sp_active,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2028   DCBD_ADD(sp_attack_hit_sound,       {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2029   DCBD_ADD(sp_attack_hit_sound_speed, {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2030   DCBD_ADD(sp_attack_wait,            {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2031   DCBD_ADD(sp_base_attack,            {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2032   DCBD_ADD(sp_base_die,               {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2033   DCBD_ADD(sp_base_hit,               {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2034   DCBD_ADD(sp_base_idle,              {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2035   DCBD_ADD(sp_base_walk,              {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2036   DCBD_ADD(sp_brain,                  {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2037   DCBD_ADD(sp_brain_parm,             {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2038   DCBD_ADD(sp_brain_parm2,            {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2039   DCBD_ADD(sp_defense,                {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2040   DCBD_ADD(sp_dir,                    {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2041   DCBD_ADD(sp_disabled,               {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2042   DCBD_ADD(sp_distance,               {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2043   DCBD_ADD(sp_exp,                    {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2044   DCBD_ADD(sp_flying,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2045   DCBD_ADD(sp_follow,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2046   DCBD_ADD(sp_frame,                  {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2047   DCBD_ADD(sp_frame_delay,            {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2048   DCBD_ADD(sp_gold,                   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2049   DCBD_ADD(sp_hard,                   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2050   DCBD_ADD(sp_hitpoints,              {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2051   DCBD_ADD(sp_move_nohard,            {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2052   DCBD_ADD(sp_mx,                     {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2053   DCBD_ADD(sp_my,                     {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2054   DCBD_ADD(sp_noclip,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2055   DCBD_ADD(sp_nocontrol,              {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2056   DCBD_ADD(sp_nodraw,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2057   DCBD_ADD(sp_nohit,                  {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2058   DCBD_ADD(sp_notouch,                {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2059   DCBD_ADD(sp_pframe,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2060   DCBD_ADD(sp_picfreeze,              {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2061   DCBD_ADD(sp_pseq,                   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2062   DCBD_ADD(sp_que,                    {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2063   DCBD_ADD(sp_range,                  {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2064   DCBD_ADD(sp_reverse,                {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2065   DCBD_ADD(sp_seq,                    {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2066   DCBD_ADD(sp_size,                   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2067   DCBD_ADD(sp_sound,                  {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2068   DCBD_ADD(sp_speed,                  {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2069   DCBD_ADD(sp_strength,               {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2070   DCBD_ADD(sp_target,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2071   DCBD_ADD(sp_timing,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2072   DCBD_ADD(sp_touch_damage,           {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2073   DCBD_ADD(sp_x,                      {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2074   DCBD_ADD(sp_y,                      {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2075 
2076   DCBD_ADD(sp_kill,                   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2077   DCBD_ADD(sp_editor_num,             {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2078   DCBD_ADD(sp_kill_wait,              {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2079   DCBD_ADD(sp_script,                 {1,2,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2080   /* sp_base_death is an alias for sp_base_die */
2081   struct binding bd_sp_base_death = *dinkc_bindings_lookup(bindings, "sp_base_die");
2082   bd_sp_base_death.funcname = "sp_base_death";
2083   dinkc_bindings_add(bindings, &bd_sp_base_death);
2084 
2085   DCBD_ADD(unfreeze,              {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2086   DCBD_ADD(freeze,                {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2087   DCBD_ADD(set_callback_random,   {2,1,1,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2088   DCBD_ADD(set_dink_speed,        {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2089   DCBD_ADD(reset_timer,          {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2090   DCBD_ADD(set_keep_mouse,        {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2091   DCBD_ADD(add_item,              {2,1,1,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2092   DCBD_ADD(add_magic,             {2,1,1,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2093   DCBD_ADD(add_exp,               {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2094   DCBD_ADD(kill_this_item,        {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2095   DCBD_ADD(kill_this_magic,       {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2096   DCBD_ADD(show_bmp,              {2,1,1,0,0,0,0,0,0,0}, DCPS_YIELD        , 0, 0);
2097   DCBD_ADD(copy_bmp_to_screen,    {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2098   DCBD_ADD(wait_for_button,      {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2099   DCBD_ADD(stop_wait_for_button, {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2100   DCBD_ADD(draw_screen,          {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2101   DCBD_ADD(free_items,           {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2102   DCBD_ADD(free_magic,           {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2103   DCBD_ADD(kill_cur_item,        {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2104   DCBD_ADD(kill_cur_magic,       {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2105   DCBD_ADD(draw_status,          {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2106   DCBD_ADD(arm_weapon,           {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2107   DCBD_ADD(arm_magic,            {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2108   DCBD_ADD(load_screen,          {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2109   DCBD_ADD(say,                   {2,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2110   DCBD_ADD(say_stop,              {2,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2111   DCBD_ADD(say_stop_npc,          {2,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2112   DCBD_ADD(say_stop_xy,           {2,1,1,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2113   DCBD_ADD(say_xy,                {2,1,1,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2114   DCBD_ADD(restart_game,         {-1,0,0,0,0,0,0,0,0,0}, -1                , 0, 0);
2115   DCBD_ADD(wait,                  {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2116   DCBD_ADD(preload_seq,           {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2117   DCBD_ADD(script_attach,         {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2118   DCBD_ADD(draw_hard_sprite,      {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2119 
2120   DCBD_ADD(activate_bow,        {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2121   DCBD_ADD(disable_all_sprites, {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2122   DCBD_ADD(draw_background,     {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2123   DCBD_ADD(draw_hard_map,       {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2124   DCBD_ADD(enable_all_sprites,  {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2125   DCBD_ADD(fade_down,           {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2126   DCBD_ADD(fade_up,             {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2127   DCBD_ADD(get_burn,            {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2128   DCBD_ADD(get_last_bow_power,  {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2129   DCBD_ADD(get_version,         {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2130   DCBD_ADD(kill_all_sounds,     {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2131   DCBD_ADD(kill_game,           {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2132   DCBD_ADD(kill_this_task,      {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2133   DCBD_ADD(scripts_used,        {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2134   DCBD_ADD(stopcd,              {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2135   DCBD_ADD(stopmidi,            {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2136   DCBD_ADD(turn_midi_off,       {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2137   DCBD_ADD(turn_midi_on,        {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2138 
2139   DCBD_ADD(count_item,               {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2140   DCBD_ADD(count_magic,              {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2141   DCBD_ADD(compare_sprite_script,    {1,2,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2142   DCBD_ADD(compare_weapon,           {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2143   DCBD_ADD(compare_magic,            {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2144   DCBD_ADD(init,                     {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2145   DCBD_ADD(dink_can_walk_off_screen, {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2146   DCBD_ADD(push_active,              {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2147   DCBD_ADD(stop_entire_game,         {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2148 
2149   DCBD_ADD(editor_type,  {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2150   DCBD_ADD(editor_seq,   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2151   DCBD_ADD(editor_frame, {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2152 
2153   DCBD_ADD(move,                 {1,1,1,1,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2154   DCBD_ADD(spawn,                {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2155   DCBD_ADD(run_script_by_number, {1,2,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2156   DCBD_ADD(playmidi,             {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2157   DCBD_ADD(playsound,            {1,1,1,1,1,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, 0);
2158   DCBD_ADD(sound_set_survive,    {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2159   DCBD_ADD(sound_set_vol,        {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2160   DCBD_ADD(sound_set_kill,       {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2161 
2162   DCBD_ADD(save_game,                 {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2163   DCBD_ADD(force_vision,              {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2164   DCBD_ADD(fill_screen,               {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2165   DCBD_ADD(load_game,                 {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2166   DCBD_ADD(game_exist,                {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2167   DCBD_ADD(move_stop,                 {1,1,1,1,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2168   DCBD_ADD(load_sound,                {2,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2169   DCBD_ADD(debug,                     {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2170   DCBD_ADD(busy,                      {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2171 
2172   DCBD_ADD(make_global_int,            {2,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2173   DCBD_ADD(inside_box,                 {1,1,1,1,1,1,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2174   DCBD_ADD(random,                     {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2175   DCBD_ADD(initfont,                   {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2176   DCBD_ADD(set_mode,                   {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2177   DCBD_ADD(kill_shadow,                {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2178   DCBD_ADD(create_sprite,              {1,1,1,1,1,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, 0);
2179   DCBD_ADD(sp,                         {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, 0);
2180   DCBD_ADD(is_script_attached,         {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2181   DCBD_ADD(get_sprite_with_this_brain,      {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, 0);
2182   DCBD_ADD(get_rand_sprite_with_this_brain, {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, 0);
2183   DCBD_ADD(set_button,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2184   DCBD_ADD(hurt,                       {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2185   DCBD_ADD(screenlock,                 {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2186 
2187   if (dversion >= 108)
2188     {
2189       DCBD_ADD(sp_blood_num,   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2190       DCBD_ADD(sp_blood_seq,   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2191       DCBD_ADD(sp_clip_bottom, {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2192       DCBD_ADD(sp_clip_left,   {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2193       DCBD_ADD(sp_clip_right,  {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2194       DCBD_ADD(sp_clip_top,    {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2195 
2196       DCBD_ADD(sp_custom,      {2,1,1,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2197 
2198       DCBD_ADD(sp_move_x, {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2199       DCBD_ADD(sp_move_y, {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2200       DCBD_ADD(sp_freeze, {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2201 
2202 
2203       DCBD_ADD(clear_editor_info, {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2204       DCBD_ADD(get_date_day,      {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2205       DCBD_ADD(get_date_month,    {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2206       DCBD_ADD(get_date_year,     {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2207       DCBD_ADD(get_time_game,     {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2208       DCBD_ADD(get_time_real,     {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2209       DCBD_ADD(get_truecolor,     {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2210       DCBD_ADD(show_console,      {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2211       DCBD_ADD(show_inventory,    {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2212       DCBD_ADD(var_used,          {-1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2213 
2214       DCBD_ADD(loopmidi,           {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2215 
2216       DCBD_ADD(math_abs,                 {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2217       DCBD_ADD(math_sqrt,                {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2218       DCBD_ADD(math_mod,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2219       DCBD_ADD(make_global_function,     {2,2,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2220       DCBD_ADD(set_save_game_info,       {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2221       DCBD_ADD(load_map,                 {2,2,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2222       DCBD_ADD(load_tile,                {2,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2223       DCBD_ADD(map_tile,                 {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2224       DCBD_ADD(map_hard_tile,            {1,1,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2225       DCBD_ADD(load_palette,             {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2226       DCBD_ADD(get_item,                 {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2227       DCBD_ADD(get_magic,                {2,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2228       DCBD_ADD(set_font_color,           {1,1,1,1,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2229       DCBD_ADD(set_smooth_follow,        {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, -1);
2230       DCBD_ADD(set_dink_base_push,       {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2231       DCBD_ADD(callback_kill,            {1,0,0,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 0, 0);
2232       DCBD_ADD(get_next_sprite_with_this_brain,  {1,1,1,0,0,0,0,0,0,0}, DCPS_GOTO_NEXTLINE, 1, 0);
2233     }
2234 }
2235 
dinkc_bindings_quit()2236 void dinkc_bindings_quit()
2237 {
2238   if (bindings != NULL)
2239     hash_free(bindings);
2240   bindings = NULL;
2241 
2242   int i = 0;
2243   for (; i < 10; i++)
2244     {
2245       if (slist[i] != NULL)
2246 	free(slist[i]);
2247       slist[i] = NULL;
2248     }
2249 }
2250 
2251 
2252 /******************/
2253 /*  DinkC parser  */
2254 /*                */
2255 /******************/
2256 
attach(void)2257 void attach(void)
2258 {
2259   /* Make sure the "system" variable exists - otherwise we might use a
2260      NULL pointer below */
2261   char* var_names[22] = { "&life", "&vision", "&result", "&speed",
2262 		     "&timing", "&lifemax", "&exp", "&strength",
2263 		     "&defense", "&gold", "&magic", "&level",
2264 		     "&player_map", "&cur_weapon", "&cur_magic",
2265 		     "&last_text", "&magic_level", "&update_status",
2266 		     "&missile_target", "&enemy_sprite", "&magic_cost",
2267 		     "&missle_source" };
2268   int n, i;
2269   for (n = 0; n < 22; n++)
2270     {
2271       if (!var_exists(var_names[n], 0)) /* 0 = global scope */
2272 	make_int(var_names[n], 0, 0, -1);
2273       /* TODO: setting script to -1 is asking for troubles... */
2274     }
2275 
2276   for (i = 1; i < MAX_VARS; i++)
2277     {
2278       if (compare("&life", play.var[i].name)) plife = &play.var[i].var;
2279       if (compare("&vision", play.var[i].name)) pvision = &play.var[i].var;
2280       if (compare("&result", play.var[i].name)) presult = &play.var[i].var;
2281       if (compare("&speed", play.var[i].name)) pspeed = &play.var[i].var;
2282       if (compare("&timing", play.var[i].name))	ptiming = &play.var[i].var;
2283       if (compare("&lifemax", play.var[i].name)) plifemax = &play.var[i].var;
2284       if (compare("&exp", play.var[i].name)) pexper = &play.var[i].var;
2285       if (compare("&strength", play.var[i].name))  pstrength = &play.var[i].var;
2286       if (compare("&defense", play.var[i].name))  pdefense = &play.var[i].var;
2287       if (compare("&gold", play.var[i].name))  pgold = &play.var[i].var;
2288       if (compare("&magic", play.var[i].name))  pmagic = &play.var[i].var;
2289       if (compare("&level", play.var[i].name))  plevel = &play.var[i].var;
2290       if (compare("&player_map", play.var[i].name)) pmap = &play.var[i].var;
2291       if (compare("&cur_weapon", play.var[i].name)) pcur_weapon = &play.var[i].var;
2292       if (compare("&cur_magic", play.var[i].name)) pcur_magic = &play.var[i].var;
2293       if (compare("&last_text", play.var[i].name)) plast_text = &play.var[i].var;
2294       if (compare("&magic_level", play.var[i].name)) pmagic_level = &play.var[i].var;
2295       if (compare("&update_status", play.var[i].name)) pupdate_status = &play.var[i].var;
2296       if (compare("&missile_target", play.var[i].name)) pmissile_target = &play.var[i].var;
2297       if (compare("&enemy_sprite", play.var[i].name)) penemy_sprite = &play.var[i].var;
2298       if (compare("&magic_cost", play.var[i].name)) pmagic_cost = &play.var[i].var;
2299       if (compare("&missle_source", play.var[i].name)) pmissle_source = &play.var[i].var;
2300     }
2301 }
2302 
2303 
2304 /**
2305  * Process DinkC dialog choice stanza
2306  */
talk_get(int script)2307 /*bool*/int talk_get(int script)
2308 {
2309   char* line = NULL;
2310   int cur = 1;
2311   int retnum = 0;
2312   clear_talk();
2313   talk.newy = -5000;
2314   while(1)
2315     {
2316     redo:
2317       line = read_next_line(script);
2318       if (line == NULL)
2319 	line = strdup(""); // compatibility
2320 
2321       strip_beginning_spaces(line);
2322       //Msg("Comparing to %s.", line);
2323 
2324       char* word = get_word(line, 1);
2325       if (compare(word, "set_y"))
2326         {
2327 	  free(word);
2328 	  word = get_word(line, 2);
2329 	  talk.newy = atol(word);
2330 	  free(word);
2331 	  free(line);
2332 	  goto redo;
2333         }
2334 
2335       if (compare(word, "set_title_color"))
2336         {
2337 	  free(word);
2338 	  word = get_word(line, 2);
2339 	  talk.color = atol(word);
2340 	  free(word);
2341 	  free(line);
2342 	  goto redo;
2343         }
2344       free(word);
2345 
2346       strip_beginning_spaces(line);
2347       if (compare(line, "\n"))
2348 	{
2349 	  free(line);
2350 	  goto redo;
2351 	}
2352 
2353       char* directive = NULL;
2354 morestuff:
2355       directive = separate_string(line, 1, '(');
2356       strip_beginning_spaces(directive);
2357 
2358       if (compare(directive, "title_start"))
2359 	{
2360 	  free(line);
2361 	  while((line = read_next_line(script)) != NULL)
2362 	    {
2363 	      strip_beginning_spaces(line);
2364 	      free(directive);
2365 
2366 	      directive = separate_string(line, 1, '(');
2367 	      if (directive != NULL)
2368 		{
2369 		  strip_beginning_spaces(directive);
2370 
2371 		  if (compare(directive, "title_end"))
2372 		    {
2373 		      replace_norealloc("\n\n\n\n", "\n \n", talk.buffer);
2374 		      replace_norealloc("\n\n", "\n", talk.buffer);
2375 		      free(directive);
2376 		      free(line);
2377 		      goto redo;
2378 		    }
2379 		}
2380 
2381 	      /* drop '\n', this messes translations */
2382 	      line[strlen(line)-1] = '\0';
2383 	      /* Translate text (before variable substitution) */
2384 	      char* translation = i18n_translate(rinfo[script]->name, rinfo[script]->debug_line, line);
2385 	      decipher_string(&translation, script);
2386 	      int cur_len = strlen(talk.buffer);
2387 	      strncat(talk.buffer, translation, TALK_TITLE_BUFSIZ - 1 - cur_len - 1);
2388 	      free(translation);
2389 	      /* put '\n' back */
2390 	      strcat(talk.buffer, "\n");
2391 	      talk.buffer[TALK_TITLE_BUFSIZ-1] = '\0';
2392 	      free(line);
2393 	    }
2394 
2395 	  free(directive);
2396 	  goto redo;
2397 	}
2398 
2399       if (compare(directive, "choice_end"))
2400 	{
2401 	  if (cur-1 == 0)
2402 	    {
2403 	      log_debug("Error: choice() has 0 options in script %s, offset %d.",
2404 			rinfo[script]->name, rinfo[script]->current);
2405 
2406 	      free(directive);
2407 	      free(line);
2408 	      return /*false*/0;
2409 	    }
2410 	  //all done, lets jam
2411 	  //Msg("found choice_end, leaving!");
2412 	  talk.last = cur-1;
2413 	  talk.cur = 1;
2414 	  talk.active = /*true*/1;
2415 	  talk.page = 1;
2416 	  talk.cur_view = 1;
2417 	  talk.script = script;
2418 
2419 	  free(directive);
2420 	  free(line);
2421 	  return /*true*/1;
2422 	}
2423       free(directive);
2424 
2425       char* condition = separate_string(line, 1, '"');
2426       strip_beginning_spaces(condition);
2427 
2428       if (strlen(condition) > 2)
2429 	{
2430 	  //found conditional statement
2431 	  if (strchr(condition, '(') == NULL)
2432 	    {
2433 	      log_error("[DinkC] Error with choice() statement in script %s, offset %d. (%s?)",
2434 			rinfo[script]->name, rinfo[script]->current, condition);
2435 
2436 	      free(condition);
2437 	      free(line);
2438 	      return /*false*/0;
2439 	    }
2440 
2441 	  char* temp = separate_string(condition, 2, '(');
2442 	  free(condition);
2443 	  condition = separate_string(temp, 1, ')');
2444 	  free(temp);
2445 
2446 	  //Msg("Running %s through var figure..", check);
2447 	  if (var_figure(condition, script) == 0)
2448 	    {
2449 	      log_debug("Answer is no.");
2450 	      retnum++;
2451 
2452 	      free(condition);
2453 	      free(line);
2454 	      goto redo;
2455 	      //said NO to statement
2456 	    }
2457 	  //Msg("Answer is yes.");
2458 	  free(condition);
2459 
2460 	  /* Resume processing stripping the first condition (there
2461 	     may be several conditions on a single dialog ligne, which
2462 	     are AND'ed) */
2463 	  char* p = strchr(line, ')') + 1;
2464 	  int i = 0;
2465 	  for (; *p != '\0'; i++, p++)
2466 	    line[i] = *p;
2467 	  line[i] = '\0';
2468 	  goto morestuff;
2469 	}
2470       free(condition);
2471 
2472       retnum++;
2473       char* text = separate_string(line, 2, '"');
2474       if (strlen(text) > 0)
2475 	{
2476 	  /* Translate text (before variable substitution) */
2477 	  char* translation = i18n_translate(rinfo[script]->name, rinfo[script]->debug_line, text);
2478 	  strip_beginning_spaces(translation);
2479 
2480 	  decipher_savegame = retnum;
2481 	  decipher_string(&translation, script);
2482 	  decipher_savegame = 0;
2483 	  strncpy(talk.line[cur], translation, TALK_LINE_BUFSIZ-1);
2484 	  talk.line[cur][TALK_LINE_BUFSIZ-1] = '\0';
2485 	  free(translation);
2486 	}
2487       else
2488 	{
2489 	  /* Handle empty text separately because _("") has a special
2490 	     meaning (returns .mo meta-data). */
2491 	  strcpy(talk.line[cur], "");
2492 	}
2493       free(text);
2494       talk.line_return[cur] = retnum;
2495       cur++;
2496       free(line);
2497     }
2498 }
2499 
2500 
2501 /**
2502  * Utility function for 'process_line', to separate and store the current procedure arguments.
2503  *
2504  * proc_name: named of the called function
2505  * script: script id
2506  * str_params: string to parse (what was after the function name)
2507  * spec: describe the function's parameters:
2508  *    1=int
2509  *    2=string
2510  *    0=no more args (10 args max)
2511  *
2512  * Known compatibility issue: passing no argument to a function
2513  * expecting 1 int argument is considered valid..
2514  *
2515  * Return: 0 if parse error, 1 if success
2516  */
get_parms(char proc_name[20],int script,char * str_params,int * spec)2517 int get_parms(char proc_name[20], int script, char *str_params, int* spec)
2518 {
2519   /* Clean-up parameters */
2520   memset(nlist, 0, 10 * sizeof (int));
2521   {
2522     int i = 0;
2523     for (; i < 10; i++)
2524       slist[i][0] = '\0';
2525   }
2526 
2527   /* Safety */
2528   char* limit = str_params + strlen(str_params);
2529 
2530   strip_beginning_spaces(str_params);
2531   if (str_params[0] == '(')
2532     {
2533       //Msg("Found first (.");
2534       str_params++;
2535     }
2536   else
2537     {
2538       log_error("[DinkC] Missing '(' in %s, offset %d.", rinfo[script]->name, rinfo[script]->current);
2539       return 0;
2540     }
2541 
2542   int i = 0;
2543   for (; i < 10; i++)
2544     {
2545       strip_beginning_spaces(str_params);
2546 
2547       if (spec[i] == 1) // type=int
2548 	{
2549 	  // Get next parameter (until ',' or ')' is reached)
2550 	  char* parm = NULL;
2551 	  if (strchr(str_params, ',') != NULL)
2552 	    parm = separate_string(str_params, 1, ',');
2553 	  else if (strchr(str_params, ')') != NULL)
2554 	    parm = separate_string(str_params, 1, ')');
2555 	  else
2556 	    parm = strdup("");
2557 
2558 	  // move to next param
2559 	  str_params += strlen(parm);
2560 
2561 	  int intval = -1;
2562 	  if (parm[0] == '&')
2563 	    {
2564 	      replace_norealloc(" ", "", parm);
2565 	      intval = decipher(parm, script);
2566 	    }
2567 	  else
2568 	    {
2569 	      intval = atol(parm);
2570 	    }
2571 	  // store parameter of type 'int'
2572 	  nlist[i] = intval;
2573 	  free(parm);
2574 	}
2575       else if (spec[i] == 2) // type=string
2576 	{
2577 	  // Checking for string
2578 	  char* parm = NULL;
2579 	  parm = separate_string(str_params, 2, '"');
2580 
2581 	  // replace DinkC string parameter
2582 	  free(slist[i]);
2583 	  slist[i] = parm;
2584 
2585 	  // move to next param
2586 	  str_params += strlen(parm) + 2; // 2x"
2587 	  if (str_params > limit) str_params = limit;
2588 	}
2589 
2590       if ((i+1) == 10 || spec[i+1] == 0) // this was the last arg
2591 	{
2592 	  //finish
2593 	  strip_beginning_spaces(str_params);
2594 
2595 	  if (str_params[0] == ')')
2596 	    {
2597 	      str_params++;
2598 	    }
2599 	  else
2600 	    {
2601 	      return 0;
2602 	    }
2603 	  strip_beginning_spaces(str_params);
2604 	  return 1;
2605 	}
2606 
2607       //got a parm, but there is more to get, lets make sure there is a comma there
2608       strip_beginning_spaces(str_params);
2609 
2610       if (str_params[0] == ',')
2611 	{
2612 	  str_params++;
2613 	}
2614       else
2615 	{
2616 	  return 0;
2617 	}
2618     }
2619   return 1;
2620 }
2621 
2622 /**
2623  * Are these 2 function signatures identical?
2624  */
signatures_eq_p(int * params1,int * params2)2625 static int signatures_eq_p(int* params1, int* params2)
2626 {
2627   int i = 0;
2628   for (; i < 10; i++)
2629     if (params1[i] != params2[i])
2630       return 0;
2631   return 1;
2632 }
2633 
2634 /**
2635  * Process one line of DinkC and returns directive to the DinkC
2636  * interpreter.
2637  *
2638  * Cf. doc/HACKING_dinkc.txt for understanding in progress ;)
2639  **/
2640 enum dinkc_parser_state
process_line(int script,char * s,int doelse)2641 process_line(int script, char *s, /*bool*/int doelse)
2642 {
2643   char *h, *p;
2644   char* ev[3];
2645 
2646   memset(&ev, 0, sizeof(ev));
2647 
2648   if (rinfo[script]->level < 1)
2649     rinfo[script]->level = 1;
2650 
2651   h = s;
2652   if (h[0] == '\0')
2653     return 0;
2654 
2655   if ((h[0] == '/') && (h[1] == '/'))
2656     {
2657       //Msg("It was a comment!");
2658       goto bad;
2659     }
2660 
2661   /* Cut line */
2662   ev[0] = separate_string(h, 1, ' ');
2663   ev[1] = separate_string(h, 2, ' ');
2664   ev[2] = separate_string(h, 3, ' ');
2665   /* Prepare free on return */
2666 #define PL_RETURN(intval) {free(ev[0]), free(ev[1]), free(ev[2]); return intval;}
2667 
2668   if (compare(ev[0], "VOID"))
2669     {
2670       if (rinfo[script]->proc_return != 0)
2671 	{
2672 	  run_script(rinfo[script]->proc_return);
2673 	  kill_script(script);
2674 	}
2675       PL_RETURN(DCPS_YIELD);
2676     }
2677 
2678   /* goto label? */
2679   if (ev[0][strlen(ev[0]) -1] == ':' && strlen(ev[1]) < 2)
2680     {
2681       if (dversion >= 108)
2682 	{
2683 	  /* Attempt to avoid considering:
2684 			   say("bonus: 5 points", 1); // would not display any text at all!
2685 			   as a label */
2686 	  if (strncmp (ev[0], "say", 3) != 0)
2687 	    {
2688 	      PL_RETURN(0); //its a label
2689 	    }
2690 	}
2691       else
2692 	{
2693 	  PL_RETURN(0); //its a label
2694 	}
2695     }
2696 
2697   /** Expression between parenthesis **/
2698   if (ev[0][0] == '(')
2699     {
2700       //this procedure has been passed a conditional statement finder
2701       //what kind of conditional statement is it?
2702       p = h;
2703       char* temp = separate_string(h, 2, ')');
2704       free(ev[0]);
2705       ev[0] = separate_string(h, 1, ')');
2706 
2707       // Msg("Ok, turned h %s to  ev1 %s.",h,ev[0]);
2708       p += strlen(ev[0]) + 1;
2709 
2710       strip_beginning_spaces(p);
2711 
2712       if (strchr(temp, '=') != NULL)
2713 	{
2714 	  h++;
2715 	  strip_beginning_spaces(h);
2716 	  process_line(script, h, /*false*/0);
2717 	  replace_norealloc("==", "", temp);
2718 	  char* expr = xmalloc(20 + 4 + strlen(temp) + 1);
2719 	  sprintf(expr, "%d == %s", returnint, temp);
2720 	  returnint = var_figure(expr, script);
2721 	  strcpy(h, "\n");
2722 	  free(expr);
2723 	  free(temp);
2724 	  PL_RETURN(0);
2725 	}
2726 
2727       if (strchr(temp, '>') != NULL)
2728 	{
2729 	  h++;
2730 	  strip_beginning_spaces(h);
2731 	  process_line(script, h, /*false*/0);
2732 	  replace_norealloc("==", "", temp);
2733 	  char* expr = xmalloc(20 + 3 + strlen(temp) + 1);
2734 	  sprintf(expr, "%d > %s", returnint, temp);
2735 	  returnint = var_figure(expr, script);
2736 	  strcpy(h, "\n");
2737 	  free(expr);
2738 	  free(temp);
2739 	  PL_RETURN(0);
2740 	}
2741 
2742       if (strchr(temp, '<') != NULL)
2743 	{
2744 	  h++;
2745 	  strip_beginning_spaces(h);
2746 	  process_line(script, h, /*false*/0);
2747 	  replace_norealloc("==", "", temp);
2748 	  char* expr = xmalloc(20 + 3 + strlen(temp) + 1);
2749 	  sprintf(expr, "%d < %s", returnint, temp);
2750 	  returnint = var_figure(expr, script);
2751 	  strcpy(h, "\n");
2752 	  free(expr);
2753 	  free(temp);
2754 	  PL_RETURN(0);
2755 	}
2756 
2757       /* Beuc: This should be converted to a set of "if ... else
2758        * if... else if ..." and multi-character constants should be
2759        * removed. However, this may cause the interpreter to behave
2760        * differently, so be careful. */
2761       /* For now, I'll rewrite the code in an equivalent warning-free
2762        * inelegant way: strchr(str, 'ab') <=> strchr(str, 'b') */
2763       /* if (strchr (temp, '<=') != NULL) */
2764       if (strchr(temp, '=') != NULL)
2765 	{
2766 	  h++;
2767 	  strip_beginning_spaces(h);
2768 	  process_line(script, h, /*false*/0);
2769 	  replace_norealloc("==", "", temp);
2770 	  char* expr = xmalloc(20 + 4 + strlen(temp) + 1);
2771 	  sprintf(expr, "%d <= %s", returnint, temp);
2772 	  returnint = var_figure(expr, script);
2773 	  strcpy(h, "\n");
2774 	  free(expr);
2775 	  free(temp);
2776 	  PL_RETURN(0);
2777 	}
2778       /* if (strchr (temp, '>=') != NULL) */
2779       if (strchr (temp, '=') != NULL)
2780 	{
2781 	  h++;
2782 	  strip_beginning_spaces(h);
2783 	  process_line(script, h, /*false*/0);
2784 	  replace_norealloc("==", "", temp);
2785 	  char* expr = xmalloc(20 + 4 + strlen(temp) + 1);
2786 	  sprintf(expr, "%d >= %s", returnint, temp);
2787 	  returnint = var_figure(expr, script);
2788 	  strcpy(h, "\n");
2789 	  free(expr);
2790 	  free(temp);
2791 	  PL_RETURN(0);
2792 	}
2793       /* if (strchr (temp, '!=') != NULL) */
2794       if (strchr (temp, '=') != NULL)
2795 	{
2796 	  h++;
2797 	  strip_beginning_spaces(h);
2798 	  process_line(script, h, /*false*/0);
2799 	  replace_norealloc("==", "", temp);
2800 	  char* expr = xmalloc(20 + 4 + strlen(temp) + 1);
2801 	  sprintf(expr, "%d != %s", returnint, temp);
2802 	  returnint = var_figure(expr, script);
2803 	  strcpy(h, "\n");
2804 	  free(expr);
2805 	  free(temp);
2806 	  PL_RETURN(0);
2807 	}
2808       free(temp);
2809 
2810 
2811       if (p[0] == ')')
2812 	{
2813 	  //its a procedure in the if statement!!!
2814 	  h++;
2815 	  p++;
2816 	  char* line_copy = strdup(p);
2817 	  process_line(script, h, /*false*/0);
2818 	  log_debug("Returned %d for the returnint", returnint);
2819 	  strcpy(s, line_copy); /* strlen(s) >= strlen(line_copy) */
2820 	  free(line_copy);
2821 	  h = s;
2822 
2823 	  PL_RETURN(0);
2824 	}
2825       else
2826 	{
2827 	  h++;
2828 
2829 	  char* expr = separate_string(h, 1,')');
2830 	  h += strlen(expr) + 1;
2831 	  returnint = var_figure(expr, script);
2832 	  free(expr);
2833 
2834 	  strcpy_nooverlap(s, h);
2835 
2836 	  PL_RETURN(0);
2837 	}
2838 
2839       strip_beginning_spaces(h);
2840       strip_beginning_spaces(ev[0]);
2841 
2842       s = h;
2843     } /* END expression between parenthesis */
2844 
2845 
2846   if (strchr(ev[0], '(') != NULL)
2847     {
2848       //Msg("Has a (, lets change it");
2849       free(ev[0]);
2850       ev[0] = separate_string(h, 1, '(');
2851       //Msg("Ok, first is now %s",ev[0]);
2852     }
2853 
2854   /** { Bloc } **/
2855   char first = ev[0][0];
2856   if (first == '{')
2857     {
2858       rinfo[script]->level++;
2859       //Msg("Went up level, now at %d.", rinfo[script]->level);
2860       h++;
2861       if (rinfo[script]->skipnext)
2862 	{
2863 	  /* Skip the whole { section } */
2864 	  rinfo[script]->skipnext = /*false*/0;
2865 	  rinfo[script]->onlevel = ( rinfo[script]->level - 1);
2866 	}
2867       goto good;
2868     }
2869 
2870   if (first == '}')
2871     {
2872       rinfo[script]->level--;
2873       //Msg("Went down a level, now at %d.", rinfo[script]->level);
2874       h++;
2875 
2876       if (rinfo[script]->onlevel > 0 && rinfo[script]->level == rinfo[script]->onlevel)
2877 	{
2878 	  /* Finished skipping the { section }, preparing to run 'else' */
2879 	  strip_beginning_spaces(h);
2880 	  strcpy_nooverlap(s, h);
2881 	  PL_RETURN(DCPS_DOELSE_ONCE);
2882 	}
2883       goto good;
2884     }
2885 
2886   /* Fix if there are too many closing '}' */
2887   if (rinfo[script]->level < 0)
2888     {
2889       rinfo[script]->level = 0;
2890     }
2891 
2892 
2893   /* Note: that's the 2nd time we compare with "VOID" -
2894      cf. above. However ev[0] was modified in between, so this
2895      section may still be called if the first comparison didn't
2896      match. */
2897   if (compare(ev[0], "void"))
2898     {
2899       //     Msg("Next procedure starting, lets quit");
2900       strcpy_nooverlap(s, h);
2901       if (rinfo[script]->proc_return != 0)
2902 	{
2903 	  run_script(rinfo[script]->proc_return);
2904 	  kill_script(script);
2905 	}
2906 
2907       PL_RETURN(DCPS_YIELD);
2908     }
2909 
2910 
2911   /* Stop processing if we're skipping the current { section } */
2912   if (rinfo[script]->onlevel > 0 && rinfo[script]->level > rinfo[script]->onlevel)
2913     {
2914       PL_RETURN(0);
2915     }
2916 
2917   rinfo[script]->onlevel = 0;
2918 
2919   /* Skip the current line if the previous 'if' or 'else' said so */
2920   if (rinfo[script]->skipnext)
2921     {
2922       //sorry, can't do it, you were told to skip the next thing
2923       rinfo[script]->skipnext = /*false*/0;
2924       strcpy(s, "\n"); /* jump to next line */
2925       //PL_RETURN(3);
2926       PL_RETURN(DCPS_DOELSE_ONCE);
2927     }
2928 
2929 
2930 
2931   if (compare(ev[0], "void"))
2932     {
2933       log_error("[DinkC] Missing } in %s, offset %d.", rinfo[script]->name,rinfo[script]->current);
2934       strcpy_nooverlap(s, h);
2935       PL_RETURN(DCPS_YIELD);
2936     }
2937 
2938   /** if **/
2939   if (compare(ev[0], "if"))
2940     {
2941       h += strlen(ev[0]);
2942       strip_beginning_spaces(h);
2943 
2944       process_line(script, h, /*false*/0);
2945       // Result is 'returnint'
2946 
2947       if (returnint != 0)
2948 	{
2949 	  log_debug("If returned true");
2950 	}
2951       else
2952 	{
2953 	  //don't do it!
2954 	  rinfo[script]->skipnext = /*true*/1;
2955 	  log_debug("If returned false, skipping next thing");
2956 	}
2957 
2958       strcpy_nooverlap(s, h);
2959       //g("continuing to run line %s..", h);
2960 
2961       //PL_RETURN(5);
2962       PL_RETURN(DCPS_DOELSE_ONCE);
2963       /* state 5 should actually be state DCPS_CONTINUE, but keeping
2964 	 it that way (e.g. with doelse=1 for the next line) for
2965 	 compatibility, just in case somebody abused it */
2966     }
2967 
2968   if (compare(ev[0], "else"))
2969     {
2970       //Msg("Found else!");
2971       h += strlen(ev[0]);
2972 
2973       if (doelse)
2974 	{
2975 	  // Yes to else
2976 	}
2977       else
2978 	{
2979 	  // No to else...
2980 	  // they shouldn't run the next thing
2981 	  rinfo[script]->skipnext = /*true*/1;
2982 	}
2983       strcpy_nooverlap(s, h);
2984       PL_RETURN(1);
2985     }
2986 
2987   /** Dialog **/
2988   if (compare(ev[0], "choice_start"))
2989     {
2990       kill_text_owned_by(1);
2991       if (talk_get(script))
2992 	{
2993 	  // Question(s) gathered successfully
2994 	  PL_RETURN(DCPS_YIELD);
2995 	}
2996       PL_RETURN(0);
2997     }
2998 
2999   /** Jump **/
3000   if (compare(ev[0], "goto"))
3001     {
3002       locate_goto(ev[1], script);
3003       PL_RETURN(0);
3004     }
3005 
3006   /** Definition **/
3007   if (compare(ev[0], "int"))
3008     {
3009       int_prepare(h, script);
3010       h += strlen(ev[0]);
3011 
3012       if (strchr(h, '=') != NULL)
3013 	{
3014 	  strip_beginning_spaces(h);
3015 	  //Msg("Found =...continuing equation");
3016 	  strcpy_nooverlap(s, h);
3017 	  PL_RETURN(DCPS_CONTINUE);
3018 	}
3019       else
3020 	{
3021 	  PL_RETURN(DCPS_GOTO_NEXTLINE);
3022 	}
3023     }
3024 
3025   /** "return;" and "return something;" **/
3026   if (compare(ev[0], "return;"))
3027     {
3028       log_debug("Found return; statement");
3029 
3030       if (rinfo[script]->proc_return != 0)
3031 	{
3032 	  bKeepReturnInt = 1; /* v1.08 */
3033 	  run_script(rinfo[script]->proc_return);
3034 	  kill_script(script);
3035 	}
3036 
3037       PL_RETURN(DCPS_YIELD);
3038     }
3039 
3040   if (dversion >= 108)
3041     {
3042       /* "return", without trailing ';' */
3043       /* added so we can have return values and crap. */
3044       /* see also "return;" above */
3045       if (compare (ev[0], "return"))
3046 	{
3047 	  log_debug("Found return; statement");
3048 	  h += strlen(ev[0]);
3049 	  strip_beginning_spaces (h);
3050 	  process_line (script, h, 0);
3051 	  if (rinfo[script]->proc_return != 0)
3052 	    {
3053 	      bKeepReturnInt = 1;
3054 	      run_script (rinfo[script]->proc_return);
3055 	      kill_script (script);
3056 	    }
3057 	  PL_RETURN(DCPS_YIELD);
3058 	}
3059     }
3060 
3061   /********************/
3062   /*  DinkC bindings  */
3063   /*                  */
3064   /********************/
3065 
3066   /** Lookup bindings **/
3067   char* funcname = ev[0];
3068   char* str_args = h + strlen(ev[0]);
3069   struct binding* pbd = NULL;
3070   pbd = dinkc_bindings_lookup(bindings, funcname);
3071 
3072   if (pbd != NULL)
3073     {
3074       /* Common arguments */
3075       int* yield = alloca(sizeof(int)*1);
3076       yield[0] = 0; /* don't yield by default) */
3077 
3078       /* Specific arguments */
3079       int* params = pbd->params;
3080       if (params[0] != -1) /* no args == no checks*/
3081 	{
3082 	  if (!get_parms(funcname, script, str_args, params))
3083 	    {
3084 	      /* Invalid parameters in the DinkC script - output an
3085 		 error message */
3086 	      int i = 0;
3087 	      while (params[i] != 0 && i < 10)
3088 		i++;
3089 	      log_error("[DinkC] %s:%d: procedure '%s' takes %d parameters",
3090 			rinfo[script]->name, rinfo[script]->debug_line,
3091 			funcname, i);
3092 
3093 	      /* Set 'returnint' if necessary */
3094 	      if (pbd->badparams_returnint_p == 1)
3095 		returnint = pbd->badparams_returnint;
3096 	      /* Fallback parser state */
3097 	      PL_RETURN(pbd->badparams_dcps);
3098 	    }
3099 	}
3100 
3101       /* Call C function */
3102       cur_funcname = pbd->funcname; /* for error messages */
3103       int sig_void[10]        = {-1,0,0,0,0,0,0,0,0,0};
3104       int sig_int[10]         =  {1,0,0,0,0,0,0,0,0,0};
3105       int sig_str[10]         =  {2,0,0,0,0,0,0,0,0,0};
3106       int sig_int_int[10]     =  {1,1,0,0,0,0,0,0,0,0};
3107       int sig_int_str[10]     =  {1,2,0,0,0,0,0,0,0,0};
3108       int sig_str_int[10]     =  {2,1,0,0,0,0,0,0,0,0};
3109       int sig_str_str[10]     =  {2,2,0,0,0,0,0,0,0,0};
3110       int sig_int_int_int[10] =  {1,1,1,0,0,0,0,0,0,0};
3111       int sig_str_int_int[10] =  {2,1,1,0,0,0,0,0,0,0};
3112       int sig_int_int_int_int[10] =  {1,1,1,1,0,0,0,0,0,0};
3113       int sig_int_int_int_int_int[10] =  {1,1,1,1,1,0,0,0,0,0};
3114       int sig_int_int_int_int_int_int[10] =  {1,1,1,1,1,1,0,0,0,0};
3115 
3116       /* {-1,0,0,0,0,0,0,0,0,0} */
3117       if (signatures_eq_p(pbd->params, sig_void))
3118 	{
3119 	  void (*pf)(int, int*, int*) = pbd->func;
3120 	  (*pf)(script, yield, &returnint);
3121 	}
3122       /* {1,0,0,0,0,0,0,0,0,0} */
3123       else if (signatures_eq_p(pbd->params, sig_int))
3124 	{
3125 	  void (*pf)(int, int*, int* , int) = pbd->func;
3126 	  (*pf)(script, yield, &returnint , nlist[0]);
3127 	}
3128       /* {2,0,0,0,0,0,0,0,0,0} */
3129       else if (signatures_eq_p(pbd->params, sig_str))
3130 	{
3131 	  void (*pf)(int, int*, int* , char*) = pbd->func;
3132 	  (*pf)(script, yield, &returnint , slist[0]);
3133 	}
3134       /* {1,1,0,0,0,0,0,0,0,0} */
3135       else if (signatures_eq_p(pbd->params, sig_int_int))
3136 	{
3137 	  void (*pf)(int, int*, int* , int, int) = pbd->func;
3138 	  (*pf)(script, yield, &returnint , nlist[0], nlist[1]);
3139 	}
3140       /* {1,2,0,0,0,0,0,0,0,0} */
3141       else if (signatures_eq_p(pbd->params, sig_int_str))
3142 	{
3143 	  void (*pf)(int, int*, int* , int, char*) = pbd->func;
3144 	  (*pf)(script, yield, &returnint , nlist[0], slist[1]);
3145 	}
3146       /* {2,1,0,0,0,0,0,0,0,0} */
3147       else if (signatures_eq_p(pbd->params, sig_str_int))
3148 	{
3149 	  void (*pf)(int, int*, int* , char*, int) = pbd->func;
3150 	  (*pf)(script, yield, &returnint , slist[0], nlist[1]);
3151 	}
3152       /* {2,2,0,0,0,0,0,0,0,0} */
3153       else if (signatures_eq_p(pbd->params, sig_str_str))
3154 	{
3155 	  void (*pf)(int, int*, int* , char*, int) = pbd->func;
3156 	  (*pf)(script, yield, &returnint , slist[0], nlist[1]);
3157 	}
3158       /* {1,1,1,0,0,0,0,0,0,0} */
3159       else if (signatures_eq_p(pbd->params, sig_int_int_int))
3160 	{
3161 	  void (*pf)(int, int*, int* , int, int, int) = pbd->func;
3162 	  (*pf)(script, yield, &returnint , nlist[0], nlist[1], nlist[2]);
3163 	}
3164       /* {2,2,1,0,0,0,0,0,0,0} */
3165       else if (signatures_eq_p(pbd->params, sig_str_int_int))
3166 	{
3167 	  void (*pf)(int, int*, int* , char*, int, int) = pbd->func;
3168 	  (*pf)(script, yield, &returnint , slist[0], nlist[1], nlist[2]);
3169 	}
3170       /* {1,1,1,1,0,0,0,0,0,0} */
3171       else if (signatures_eq_p(pbd->params, sig_int_int_int_int))
3172 	{
3173 	  void (*pf)(int, int*, int* , int, int, int, int) = pbd->func;
3174 	  (*pf)(script, yield, &returnint , nlist[0], nlist[1], nlist[2], nlist[3]);
3175 	}
3176       /* {1,1,1,1,1,0,0,0,0,0} */
3177       else if (signatures_eq_p(pbd->params, sig_int_int_int_int_int))
3178 	{
3179 	  void (*pf)(int, int*, int* , int, int, int, int, int) = pbd->func;
3180 	  (*pf)(script, yield, &returnint , nlist[0], nlist[1], nlist[2], nlist[3], nlist[4]);
3181 	}
3182       /* {1,1,1,1,1,1,0,0,0,0} */
3183       else if (signatures_eq_p(pbd->params, sig_int_int_int_int_int_int))
3184 	{
3185 	  void (*pf)(int, int*, int* , int, int, int, int, int, int) = pbd->func;
3186 	  (*pf)(script, yield, &returnint , nlist[0], nlist[1], nlist[2], nlist[3], nlist[4], nlist[5]);
3187 	}
3188       else
3189 	{
3190 	  log_fatal("Internal error: DinkC function %s has unknown signature",
3191 		    pbd->funcname);
3192 	  exit(EXIT_FAILURE);
3193 	}
3194       cur_funcname = "";
3195       /* the function can manipulation returnint through argument #3 */
3196 
3197       if (*yield == 0)
3198 	{
3199 	  PL_RETURN(DCPS_GOTO_NEXTLINE);
3200 	}
3201       else if (*yield == 1)
3202 	{
3203 	  PL_RETURN(DCPS_YIELD);
3204 	}
3205       else
3206 	{
3207 	  log_fatal("Internal error: DinkC function %s requested invalid state %d",
3208 		    pbd->funcname, *yield);
3209 	  exit(EXIT_FAILURE);
3210 	}
3211     }
3212 
3213 
3214   /***************/
3215   /** Operators **/
3216   /**           **/
3217   /***************/
3218 
3219   /* Beware: this works on ev[1], not ev[0]; position in the code is
3220      critical! */
3221 
3222   if (compare(ev[1], "="))
3223     {
3224       h += strlen(ev[0]);
3225       strip_beginning_spaces(h);
3226       h++;
3227       strip_beginning_spaces(h);
3228       var_equals(ev[0], ev[2], '=', script, h);
3229       strcpy_nooverlap(s, h);
3230       PL_RETURN(0);
3231     }
3232 
3233   if (compare(ev[1], "+="))
3234     {
3235       h += strlen(ev[0]);
3236       strip_beginning_spaces(h);
3237       h += 2;
3238       strip_beginning_spaces(h);
3239       var_equals(ev[0], ev[2], '+', script, h);
3240       strcpy_nooverlap(s, h);
3241       PL_RETURN(0);
3242     }
3243 
3244   if (compare(ev[1], "*="))
3245     {
3246       h += strlen(ev[0]);
3247       strip_beginning_spaces(h);
3248       h += 2;
3249       strip_beginning_spaces(h);
3250       var_equals(ev[0], ev[2], '*', script, h);
3251       strcpy_nooverlap(s, h);
3252       PL_RETURN(0);
3253     }
3254 
3255   if (compare(ev[1], "-="))
3256     {
3257       h += strlen(ev[0]);
3258       strip_beginning_spaces(h);
3259       h += 2;
3260       strip_beginning_spaces(h);
3261 
3262       var_equals(ev[0], ev[2], '-', script, h);
3263 
3264       strcpy_nooverlap(s, h);
3265       PL_RETURN(0);
3266     }
3267 
3268   if (compare(ev[1], "/")
3269       || (dversion >= 108 && compare(ev[1], "/=")))
3270     {
3271       h += strlen(ev[0]);
3272       strip_beginning_spaces(h);
3273       h++;
3274       strip_beginning_spaces(h);
3275 
3276       var_equals(ev[0], ev[2], '/', script, h);
3277 
3278       strcpy_nooverlap(s, h);
3279       PL_RETURN(0);
3280     }
3281 
3282   if (compare(ev[1], "*"))
3283     {
3284       h += strlen(ev[0]);
3285       strip_beginning_spaces(h);
3286       h++;
3287       strip_beginning_spaces(h);
3288 
3289       var_equals(ev[0], ev[2], '*', script, h);
3290 
3291       strcpy_nooverlap(s, h);
3292       PL_RETURN(0);
3293     }
3294 
3295 
3296   /***************************************/
3297   /** New DinkC user-defined procedures **/
3298   /**                                   **/
3299   /***************************************/
3300   if (dversion >= 108)
3301     {
3302       if (compare (ev[0], "external"))
3303 	{
3304 	  h += strlen(ev[0]);
3305 	  int p[20] = { 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 };
3306 	  {
3307 	    int i = 0;
3308 	    for (; i < 10; i++)
3309 	      slist[i][0] = '\0';
3310 	  }
3311 	  get_parms(ev[0], script, h, p);
3312 	  if (strlen(slist[0]) > 0 && strlen(slist[1]) > 0)
3313 	    {
3314 	      int myscript1 = load_script(slist[0], rinfo[script]->sprite, 0);
3315 	      if (myscript1 == 0)
3316 		{
3317 		  log_error("[DinkC] external: Couldn't find %s.c (for procedure %s)",
3318 		       slist[0], slist[1]);
3319 		  PL_RETURN(0);
3320 		}
3321 	      rinfo[myscript1]->arg1 = nlist[2];
3322 	      rinfo[myscript1]->arg2 = nlist[3];
3323 	      rinfo[myscript1]->arg3 = nlist[4];
3324 	      rinfo[myscript1]->arg4 = nlist[5];
3325 	      rinfo[myscript1]->arg5 = nlist[6];
3326 	      rinfo[myscript1]->arg6 = nlist[7];
3327 	      rinfo[myscript1]->arg7 = nlist[8];
3328 	      rinfo[myscript1]->arg8 = nlist[9];
3329 	      if (locate (myscript1, slist[1]))
3330 		{
3331 		  rinfo[myscript1]->proc_return = script;
3332 		  run_script (myscript1);
3333 		  PL_RETURN(DCPS_YIELD);
3334 		}
3335 	      else
3336 		{
3337 		  log_error("[DinkC] external: Couldn't find procedure %s in %s.",
3338 			    slist[1], slist[0]);
3339 		  kill_script (myscript1);
3340 		}
3341 	    }
3342 	  strcpy (s, h);
3343 	  PL_RETURN(0);
3344 	}
3345 
3346       if (strchr (h, '(') != NULL)
3347 	{
3348 	  //lets attempt to run a procedure
3349 	  int myscript = load_script (rinfo[script]->name, rinfo[script]->sprite, 0);
3350 	  h += strlen(ev[0]);
3351 	  int p[20] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
3352 	  get_parms(ev[0], script, h, p);
3353 	  if (locate(myscript, ev[0]))
3354 	    {
3355 	      /* Custom procedure in the current script */
3356 	      rinfo[myscript]->arg1 = nlist[0];
3357 	      rinfo[myscript]->arg2 = nlist[1];
3358 	      rinfo[myscript]->arg3 = nlist[2];
3359 	      rinfo[myscript]->arg4 = nlist[3];
3360 	      rinfo[myscript]->arg5 = nlist[4];
3361 	      rinfo[myscript]->arg6 = nlist[5];
3362 	      rinfo[myscript]->arg7 = nlist[6];
3363 	      rinfo[myscript]->arg8 = nlist[7];
3364 	      rinfo[myscript]->arg9 = nlist[8];
3365 	      rinfo[myscript]->proc_return = script;
3366 	      run_script(myscript);
3367 	      PL_RETURN(DCPS_YIELD);
3368 	    }
3369 	  else
3370 	    {
3371 	      /* Try custom global procedure */
3372 	      int i = 0;
3373 	      for (; i < 100; i++)
3374 		{
3375 		  /* Skip empty slots */
3376 		  if (strlen (play.func[i].func) == 0)
3377 		    continue;
3378 
3379 		  if (compare(play.func[i].func, ev[0]))
3380 		    {
3381 		      myscript = load_script(play.func[i].file, rinfo[script]->sprite, 0);
3382 		      rinfo[myscript]->arg1 = nlist[0];
3383 		      rinfo[myscript]->arg2 = nlist[1];
3384 		      rinfo[myscript]->arg3 = nlist[2];
3385 		      rinfo[myscript]->arg4 = nlist[3];
3386 		      rinfo[myscript]->arg5 = nlist[4];
3387 		      rinfo[myscript]->arg6 = nlist[5];
3388 		      rinfo[myscript]->arg7 = nlist[6];
3389 		      rinfo[myscript]->arg8 = nlist[7];
3390 		      rinfo[myscript]->arg9 = nlist[8];
3391 		      if (locate(myscript, ev[0]))
3392 			{
3393 			  rinfo[myscript]->proc_return = script;
3394 			  run_script (myscript);
3395 			  PL_RETURN(DCPS_YIELD);
3396 			}
3397 		      break;
3398 		    }
3399 		}
3400 	      log_error("[DinkC] Procedure void %s( void ); not found in script %s. (word 2 was %s)",
3401 			ev[0], ev[1], rinfo[myscript] != NULL ? rinfo[myscript]->name : "");
3402 	      kill_script (myscript);
3403 	    }
3404 
3405 	  /*seperate_string(h, 1,'(',line);
3406 
3407 	    int myscript = load_script(rinfo[script]->name, rinfo[script]->sprite, false);
3408 
3409 	    if (locate( myscript, line))
3410 	    {
3411 	    rinfo[myscript]->proc_return = script;
3412 	    run_script(myscript);
3413 	    PL_RETURN(DCPS_YIELD);
3414 	    } else
3415 	    {
3416 	    Msg("ERROR:  Procedure void %s( void ); not found in script %s. (word 2 was %s) ", line,
3417 	    ev[1], rinfo[myscript]->name);
3418 	    kill_script(myscript);
3419 	    } */
3420 	  PL_RETURN(0);
3421 	}
3422     }
3423   else
3424     {
3425       /* v1.07 function that are implemented differently than in v1.08 */
3426       if (compare(ev[0], "external"))
3427 	{
3428 	  h += strlen(ev[0]);
3429 	  int p[20] = {2,2,0,0,0,0,0,0,0,0};
3430 	  if (get_parms(ev[0], script, h, p))
3431 	    {
3432 	      int myscript1 = load_script(slist[0], rinfo[script]->sprite, /*false*/0);
3433 	      if (myscript1 == 0)
3434 		{
3435 		  log_error("[DinkC] external: Couldn't find %s.c (for procedure %s)", slist[0], slist[1]);
3436 		  PL_RETURN(0);
3437 		}
3438 	      if (locate(myscript1, slist[1]))
3439 		{
3440 		  rinfo[myscript1]->proc_return = script;
3441 		  run_script(myscript1);
3442 		  PL_RETURN(DCPS_YIELD);
3443 		}
3444 	      else
3445 		{
3446 		  log_error("[DinkC] external: Couldn't find procedure %s in %s.", slist[1], slist[0]);
3447 		  kill_script(myscript1);
3448 		}
3449 	    }
3450 	  else
3451 	    {
3452 	      log_error("[DinkC] %s: procedure 'external' takes 2 parameters (offset %d)",
3453 			rinfo[script]->name, rinfo[script]->current);
3454 	    }
3455 	  strcpy_nooverlap(s, h);
3456 	  PL_RETURN(0);
3457 	}
3458 
3459       if (strchr(h, '(') != NULL)
3460 	{
3461 	  //lets attempt to run a procedure
3462 	  char* proc = separate_string(h, 1, '(');
3463 	  int myscript = load_script(rinfo[script]->name, rinfo[script]->sprite, /*false*/0);
3464 
3465 	  if (locate(myscript, proc))
3466 	    {
3467 	      rinfo[myscript]->proc_return = script;
3468 	      run_script(myscript);
3469 	      free(proc);
3470 	      PL_RETURN(DCPS_YIELD);
3471 	    }
3472 	  else
3473 	    {
3474 	      log_error("[DinkC] Procedure void %s( void ); not found in script %s. (word 2 was %s) ",
3475 			proc, ev[1], rinfo[myscript]->name);
3476 	      kill_script(myscript);
3477 	    }
3478 	  free(proc);
3479 	  PL_RETURN(0);
3480 	}
3481 
3482       log_error("[DinkC] \"%s\" unknown in %s, offset %d.",
3483 		ev[0], rinfo[script]->name,rinfo[script]->current);
3484       //in a thingie, ready to go
3485     }
3486 
3487 bad:
3488   strcpy(s, "\n"); /* jump to next line */
3489   //PL_RETURN(0);
3490   PL_RETURN(DCPS_CONTINUE);
3491 
3492  good:
3493   strcpy_nooverlap(s, h);
3494   //s = h
3495   //Msg("ok, continuing with running %s..",s);
3496   PL_RETURN(DCPS_CONTINUE);
3497 }
3498