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