1 /*  Sarien - A Sierra AGI resource interpreter engine
2  *  Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka
3  *
4  *  $Id: op_cmd.c,v 1.118 2001/11/03 20:16:10 cmatsuoka Exp $
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; see docs/COPYING for further details.
9  */
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include "sarien.h"
14 #include "agi.h"
15 #include "rand.h"
16 #include "sprite.h"
17 #include "graphics.h"
18 #include "keyboard.h"
19 #include "opcodes.h"
20 #include "menu.h"
21 #include "savegame.h"
22 #include "text.h"
23 
24 #define p0	(p[0])
25 #define p1	(p[1])
26 #define p2	(p[2])
27 #define p3	(p[3])
28 #define p4	(p[4])
29 #define p5	(p[5])
30 #define p6	(p[6])
31 
32 #define ip	cur_logic->cIP
33 #define vt	game.view_table[p0]
34 
35 static struct agi_logic *cur_logic;
36 
37 int timer_hack;		/* Workaround for timer loop in MH1 */
38 
39 #define _v game.vars
40 #define cmd(x) static void cmd_##x (UINT8 *p)
41 
cmd(increment)42 cmd(increment)		{ if (_v[p0] != 0xff) ++_v[p0]; }
cmd(decrement)43 cmd(decrement)		{ if (_v[p0] != 0) --_v[p0]; }
cmd(assignn)44 cmd(assignn)		{ _v[p0] = p1; }
cmd(addn)45 cmd(addn)		{ _v[p0] += p1; }
cmd(subn)46 cmd(subn)		{ _v[p0] -= p1; }
cmd(assignv)47 cmd(assignv)		{ _v[p0] = _v[p1]; }
cmd(addv)48 cmd(addv)		{ _v[p0] += _v[p1]; }
cmd(subv)49 cmd(subv)		{ _v[p0] -= _v[p1]; }
cmd(mul_n)50 cmd(mul_n)		{ _v[p0] *= p1; }
cmd(mul_v)51 cmd(mul_v)		{ _v[p0] *= _v[p1]; }
cmd(div_n)52 cmd(div_n)		{ _v[p0] /= p1; }
cmd(div_v)53 cmd(div_v)		{ _v[p0] /= _v[p1]; }
cmd(random)54 cmd(random)		{ _v[p2] = rnd (1 + (p1 - p0)) + p0; }
cmd(lindirectn)55 cmd(lindirectn)		{ _v[_v[p0]] = p1; }
cmd(lindirectv)56 cmd(lindirectv)		{ _v[_v[p0]] = _v[p1]; }
cmd(rindirect)57 cmd(rindirect)		{ _v[p0] = _v[_v[p1]]; }
cmd(set)58 cmd(set)		{ setflag (*p, TRUE); }
cmd(reset)59 cmd(reset)		{ setflag (*p, FALSE); }
cmd(toggle)60 cmd(toggle)		{ setflag (*p, !getflag (*p)); }
cmd(set_v)61 cmd(set_v)		{ setflag (_v[p0], TRUE); }
cmd(reset_v)62 cmd(reset_v)		{ setflag (_v[p0], FALSE); }
cmd(toggle_v)63 cmd(toggle_v)		{ setflag (_v[p0], !getflag (*p)); }
cmd(new_room)64 cmd(new_room)		{ new_room (p0); }
cmd(new_room_f)65 cmd(new_room_f)		{ new_room (_v[p0]); }
cmd(load_view)66 cmd(load_view)		{ agi_load_resource (rVIEW, p0); }
cmd(load_logic)67 cmd(load_logic)		{ agi_load_resource (rLOGIC, p0); }
cmd(load_sound)68 cmd(load_sound)		{ agi_load_resource (rSOUND, p0); }
cmd(load_view_f)69 cmd(load_view_f)	{ agi_load_resource (rVIEW, _v[p0]); }
cmd(load_logic_f)70 cmd(load_logic_f)	{ agi_load_resource (rLOGIC, _v[p0] ); }
cmd(discard_view)71 cmd(discard_view)	{ agi_unload_resource (rVIEW, p0); }
cmd(object_on_anything)72 cmd(object_on_anything)	{ vt.flags &= ~(ON_WATER | ON_LAND); }
cmd(object_on_land)73 cmd(object_on_land)	{ _D ("p0 = %d", p0); vt.flags |= ON_LAND; }
cmd(object_on_water)74 cmd(object_on_water)	{ _D ("p0 = %d", p0); vt.flags |= ON_WATER; }
cmd(observe_horizon)75 cmd(observe_horizon)	{ _D ("p0 = %d", p0); vt.flags &= ~IGNORE_HORIZON; }
cmd(ignore_horizon)76 cmd(ignore_horizon)	{ _D ("p0 = %d", p0); vt.flags |= IGNORE_HORIZON; }
cmd(observe_objs)77 cmd(observe_objs)	{ _D ("p0 = %d", p0); vt.flags &= ~IGNORE_OBJECTS; }
cmd(ignore_objs)78 cmd(ignore_objs)	{ _D ("p0 = %d", p0); vt.flags |= IGNORE_OBJECTS; }
cmd(observe_blocks)79 cmd(observe_blocks)	{ _D ("p0 = %d", p0); vt.flags &= ~IGNORE_BLOCKS; }
cmd(ignore_blocks)80 cmd(ignore_blocks)	{ _D ("p0 = %d", p0); vt.flags |= IGNORE_BLOCKS; }
cmd(set_horizon)81 cmd(set_horizon)	{ _D ("p0 = %d", p0); game.horizon = p0; }
cmd(get_priority)82 cmd(get_priority)	{ _v[p1] = vt.priority; }
cmd(set_priority)83 cmd(set_priority)	{ vt.flags |= FIXED_PRIORITY; vt.priority = p1; }
cmd(set_priority_f)84 cmd(set_priority_f)	{ vt.flags |= FIXED_PRIORITY; vt.priority = _v[p1]; }
cmd(release_priority)85 cmd(release_priority)	{ vt.flags &= ~FIXED_PRIORITY; }
cmd(set_upper_left)86 cmd(set_upper_left)	{ /* do nothing (AGI 2.917) */ }
cmd(start_update)87 cmd(start_update)	{ start_update (&vt); }
cmd(stop_update)88 cmd(stop_update)	{ stop_update (&vt); }
cmd(current_view)89 cmd(current_view)	{ _v[p1] = vt.current_view; }
cmd(current_cel)90 cmd(current_cel)	{ _v[p1] = vt.current_cel; _D ("v%d=%d", p1, _v[p1]); }
cmd(current_loop)91 cmd(current_loop)	{ _v[p1] = vt.current_loop; }
cmd(last_cel)92 cmd(last_cel)		{ _v[p1] = vt.loop_data->num_cels - 1; }
cmd(set_cel)93 cmd(set_cel)		{ set_cel (&vt, p1); vt.flags &= ~DONTUPDATE; }
cmd(set_cel_f)94 cmd(set_cel_f)		{ set_cel (&vt, _v[p1]); vt.flags &= ~DONTUPDATE; }
cmd(set_view)95 cmd(set_view)		{ set_view (&vt, p1); }
cmd(set_view_f)96 cmd(set_view_f)		{ set_view (&vt, _v[p1]); }
cmd(set_loop)97 cmd(set_loop)		{ set_loop (&vt, p1); }
cmd(set_loop_f)98 cmd(set_loop_f)		{ set_loop (&vt, _v[p1]); }
cmd(number_of_loops)99 cmd(number_of_loops)	{ _v[p1] = vt.num_loops; }
cmd(fix_loop)100 cmd(fix_loop)		{ vt.flags |= FIX_LOOP; }
cmd(release_loop)101 cmd(release_loop)	{ vt.flags &= ~FIX_LOOP; }
cmd(step_size)102 cmd(step_size)		{ vt.step_size = _v[p1]; }
cmd(step_time)103 cmd(step_time)		{ vt.step_time = vt.step_time_count = _v[p1]; }
cmd(cycle_time)104 cmd(cycle_time)		{ vt.cycle_time = vt.cycle_time_count = _v[p1]; }
cmd(stop_cycling)105 cmd(stop_cycling)	{ vt.flags &= ~CYCLING; }
cmd(start_cycling)106 cmd(start_cycling)	{ vt.flags |= CYCLING; }
cmd(normal_cycle)107 cmd(normal_cycle)	{ vt.cycle = CYCLE_NORMAL; vt.flags |= CYCLING; }
cmd(reverse_cycle)108 cmd(reverse_cycle)	{ vt.cycle = CYCLE_REVERSE; vt.flags |= CYCLING; }
cmd(set_dir)109 cmd(set_dir)		{ vt.direction = _v[p1]; }
cmd(get_dir)110 cmd(get_dir)		{ _v[p1] = vt.direction; }
cmd(get_room_f)111 cmd(get_room_f)		{ _v[p1] = object_get_location (_v[p0]); }
cmd(put)112 cmd(put)		{ object_set_location (p0, _v[p1]); }
cmd(put_f)113 cmd(put_f)		{ object_set_location (_v[p0], _v[p1]); }
cmd(drop)114 cmd(drop)		{ object_set_location (p0, 0); }
cmd(get)115 cmd(get)		{ object_set_location (p0, EGO_OWNED); }
cmd(get_f)116 cmd(get_f)		{ object_set_location (_v[p0], EGO_OWNED); }
cmd(parse)117 cmd(parse)		{ dictionary_words (agi_sprintf(game.strings[p0])); }
cmd(set_text_attribute)118 cmd(set_text_attribute)	{ game.color_fg = p0; game.color_bg = p1; }
cmd(shake_screen)119 cmd(shake_screen)	{ shake_screen (p0); }
cmd(word_to_string)120 cmd(word_to_string)	{ strcpy (game.strings[p0], game.ego_words[p1].word); }
cmd(open_dialogue)121 cmd(open_dialogue)	{ _D ("p0 = %d", p0); game.has_window = TRUE; }
cmd(close_dialogue)122 cmd(close_dialogue)	{ _D ("p0 = %d", p0); game.has_window = FALSE; }
cmd(close_window)123 cmd(close_window)	{ close_window (); }
cmd(status_line_on)124 cmd(status_line_on) 	{ game.status_line = TRUE; write_status (); }
cmd(status_line_off)125 cmd(status_line_off)	{ game.status_line = FALSE; write_status (); }
cmd(show_obj)126 cmd(show_obj)		{ show_obj (p0); }
cmd(show_obj_v)127 cmd(show_obj_v)		{ show_obj (_v[p0]); }
cmd(sound)128 cmd(sound)		{ start_sound (p0, p1); }
cmd(stop_sound)129 cmd(stop_sound)		{ stop_sound (); }
cmd(accept_input)130 cmd(accept_input)	{ new_input_mode (INPUT_NORMAL); }
cmd(prevent_input)131 cmd(prevent_input)	{ new_input_mode (INPUT_NONE); }
cmd(menu_input)132 cmd(menu_input)		{ new_input_mode (INPUT_MENU); }
cmd(enable_item)133 cmd(enable_item)	{ menu_set_item (p0, TRUE); }
cmd(disable_item)134 cmd(disable_item)	{ menu_set_item (p0, FALSE); }
cmd(submit_menu)135 cmd(submit_menu)	{ submit_menu (); }
cmd(set_scan_start)136 cmd(set_scan_start)	{ cur_logic->sIP = cur_logic->cIP; }
cmd(reset_scan_start)137 cmd(reset_scan_start)	{ cur_logic->sIP = 2; }
cmd(save_game)138 cmd(save_game)		{ savegame_dialog (); }
cmd(load_game)139 cmd(load_game)		{ loadgame_dialog (); }
cmd(init_disk)140 cmd(init_disk)		{ /* do nothing */ }
cmd(log)141 cmd(log)		{ /* do nothing */ }
cmd(trace_on)142 cmd(trace_on)		{ /* do nothing */ }
cmd(trace_info)143 cmd(trace_info)		{ /* do nothing */ }
cmd(show_mem)144 cmd(show_mem)		{ message_box ("Enough memory"); }
cmd(init_joy)145 cmd(init_joy)		{ /* do nothing */; }
cmd(script_size)146 cmd(script_size)	{ report ("script.size(%d)\n", p0); }
cmd(cancel_line)147 cmd(cancel_line)	{ report ("cancel.line\n"); }
cmd(obj_status_f)148 cmd(obj_status_f)	{ report ("obj.status.f\n"); }
149 
150 /* unknown commands:
151  * unk_170: Force savegame name -- j5
152  * unk_171: script save -- j5
153  * unk_172: script restore -- j5
154  * unk_173: Activate keypressed control (ego only moves while key is pressed)
155  * unk_174: Change priority table (used in KQ4) -- j5
156  * unk_177: Disable menus completely -- j5
157  * unk_181: Deactivate keypressed control (default control of ego)
158  */
cmd(set_simple)159 cmd(set_simple)		{ report ("set.simple\n"); }
cmd(pop_script)160 cmd(pop_script)		{ report ("pop.script\n"); }
cmd(hold_key)161 cmd(hold_key)		{ report ("hold.key\n"); }
cmd(discard_sound)162 cmd(discard_sound)	{ report ("discard.sound\n"); }
cmd(hide_mouse)163 cmd(hide_mouse)		{ report ("hide.mouse\n"); }
cmd(allow_menu)164 cmd(allow_menu)		{ report ("allow.menu\n"); }
cmd(show_mouse)165 cmd(show_mouse)		{ report ("show.mouse\n"); }
cmd(fence_mouse)166 cmd(fence_mouse)	{ report ("fence.mouse\n"); }
cmd(release_key)167 cmd(release_key)	{ report ("release.key\n"); }
cmd(adj_ego_move_to_xy)168 cmd(adj_ego_move_to_xy)	{ game.view_table[0].flags |= ADJ_EGO_XY; }
169 
170 
cmd(call)171 cmd(call) {
172 	int old_cIP;
173 	int old_lognum;
174 
175 	/* CM: we don't save sIP because set.scan.start can be
176 	 *     used in a called script (fixes xmas demo)
177 	 */
178 	old_cIP = cur_logic->cIP;
179 	old_lognum = game.lognum;
180 
181 	run_logic (p0);
182 
183 	game.lognum = old_lognum;
184 	cur_logic = &game.logics[game.lognum];
185 	cur_logic->cIP = old_cIP;
186 }
187 
cmd(call_f)188 cmd(call_f) {
189 	cmd_call (&_v[p0]);
190 }
191 
cmd(draw_pic)192 cmd(draw_pic) {
193 	_D (_D_WARN "=== draw pic %d ===", _v[p0]);
194 	erase_both ();
195 	decode_picture (_v[p0], TRUE);
196 	blit_both ();
197 	game.picture_shown = 0;
198 	_D (_D_WARN "--- end of draw pic %d ---", _v[p0]);
199 }
200 
cmd(show_pic)201 cmd(show_pic) {
202 	_D (_D_WARN "=== show pic ===");
203 	setflag (F_output_mode, FALSE);
204 	cmd_close_window (NULL);
205 	show_pic ();
206 	game.picture_shown = 1;
207 	_D (_D_WARN "--- end of show pic ---");
208 }
209 
cmd(load_pic)210 cmd(load_pic) {
211 	erase_both ();
212 	agi_load_resource (rPICTURE, _v[p0]);
213 	blit_both ();
214 }
215 
cmd(discard_pic)216 cmd(discard_pic) {
217 	_D (_D_WARN "--- discard pic ---");
218 	/* do nothing */
219 }
220 
cmd(overlay_pic)221 cmd(overlay_pic) {
222 	_D (_D_WARN "--- overlay pic ---");
223 	erase_both ();
224 	decode_picture (_v[p0], FALSE);
225 	blit_both ();
226 	game.picture_shown = 0;
227 	commit_both ();
228 }
229 
cmd(show_pri_screen)230 cmd(show_pri_screen) {
231 #ifdef USE_CONSOLE
232 	debug.priority = 1;
233 	erase_both();
234 	show_pic ();
235 	blit_both ();
236 	wait_key ();
237 	debug.priority = 0;
238 	erase_both();
239 	show_pic ();
240 	blit_both ();
241 #endif
242 }
243 
cmd(animate_obj)244 cmd(animate_obj) {
245 	if (vt.flags & ANIMATED)
246 		return;
247 
248 	_D (_D_WARN "animate vt entry #%d", p0);
249 	vt.flags = ANIMATED | UPDATE | CYCLING;
250 	vt.motion = MOTION_NORMAL;
251 	vt.cycle = CYCLE_NORMAL;
252 	vt.direction = 0;
253 }
254 
cmd(unanimate_all)255 cmd(unanimate_all) {
256 	int i;
257 	for (i = 0; i < MAX_VIEWTABLE; i++)
258 		game.view_table[i].flags &= ~(ANIMATED | DRAWN);
259 }
260 
cmd(draw)261 cmd(draw) {
262 	if (vt.flags & DRAWN)
263 		return;
264 
265 	if (vt.y_size <= 0 || vt.x_size <= 0)
266 		return;
267 
268 	vt.flags |= UPDATE;
269 	fix_position (p0);
270 	vt.x_pos2 = vt.x_pos;
271 	vt.y_pos2 = vt.y_pos;
272 	vt.cel_data_2 = vt.cel_data;
273 	erase_upd_sprites ();
274 	vt.flags |= DRAWN;
275 	blit_upd_sprites ();
276 	vt.flags &= ~DONTUPDATE;
277 
278 	commit_block (vt.x_pos, vt.y_pos - vt.y_size + 1,
279 		vt.x_pos + vt.x_size - 1, vt.y_pos);
280 
281 	_D ("vt entry #%d flags = %02x", p0, vt.flags);
282 }
283 
cmd(erase)284 cmd(erase) {
285 	if (~vt.flags & DRAWN)
286 		return;
287 
288 	erase_upd_sprites ();
289 	if (vt.flags & UPDATE) {
290 		vt.flags &= ~DRAWN;
291 	} else {
292 		erase_nonupd_sprites ();
293 		vt.flags &= ~DRAWN;
294 		blit_nonupd_sprites ();
295 	}
296 	blit_upd_sprites ();
297 
298 	commit_block (vt.x_pos, vt.y_pos - vt.y_size + 1,
299 		vt.x_pos + vt.x_size - 1, vt.y_pos);
300 }
301 
cmd(position)302 cmd(position) {
303 	vt.x_pos = vt.x_pos2 = p1;
304 	vt.y_pos = vt.y_pos2 = p2;
305 }
306 
cmd(position_f)307 cmd(position_f) {
308 	vt.x_pos = vt.x_pos2 = _v[p1];
309 	vt.y_pos = vt.y_pos2 = _v[p2];
310 }
311 
cmd(get_posn)312 cmd(get_posn) {
313 	game.vars[p1] = (unsigned char)vt.x_pos;
314 	game.vars[p2] = (unsigned char)vt.y_pos;
315 }
316 
cmd(reposition)317 cmd(reposition) {
318 	int dx = (SINT8)_v[p1], dy = (SINT8)_v[p2];
319 
320 	_D ("dx=%d, dy=%d", dx, dy);
321 	vt.flags |= UPDATE_POS;
322 
323 	if (dx < 0 && vt.x_pos < dx)
324 		vt.x_pos = 0;
325 	else
326 		vt.x_pos += dx;
327 
328 	if (dy < 0 && vt.y_pos < dy)
329 		vt.y_pos = 0;
330 	else
331 		vt.y_pos += dy;
332 
333 	fix_position (p0);
334 }
335 
cmd(reposition_to)336 cmd(reposition_to) {
337 	vt.x_pos = p1;
338 	vt.y_pos = p2;
339 	vt.flags |= UPDATE_POS;
340 	fix_position (p0);
341 }
342 
cmd(reposition_to_f)343 cmd(reposition_to_f) {
344 	vt.x_pos = _v[p1];
345 	vt.y_pos = _v[p2];
346 	vt.flags |= UPDATE_POS;
347 	fix_position (p0);
348 }
349 
cmd(add_to_pic)350 cmd(add_to_pic) {
351 	add_to_pic (p0, p1, p2, p3, p4, p5, p6);
352 }
353 
cmd(add_to_pic_f)354 cmd(add_to_pic_f) {
355 	add_to_pic (_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]);
356 }
357 
cmd(force_update)358 cmd(force_update) {
359 	erase_both ();
360 	blit_both ();
361 	commit_both ();
362 }
363 
cmd(reverse_loop)364 cmd(reverse_loop) {
365 	vt.cycle = CYCLE_REV_LOOP;
366 	vt.flags |= (DONTUPDATE|UPDATE|CYCLING);
367 	vt.parm1 = p1;
368 	setflag (p1, FALSE);
369 }
370 
cmd(end_of_loop)371 cmd(end_of_loop) {
372 	_D (_D_WARN "p0 = %d", p0);
373 	vt.flags |= (DONTUPDATE|UPDATE|CYCLING);
374 	vt.cycle = CYCLE_END_OF_LOOP;
375 	vt.parm1 = p1;
376 }
377 
cmd(block)378 cmd(block) {
379 	_D (_D_WARN "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3);
380 	game.block.active = TRUE;
381 	game.block.x1 = p0;
382 	game.block.y1 = p1;
383 	game.block.x2 = p2;
384 	game.block.y2 = p4;
385 }
386 
cmd(unblock)387 cmd(unblock) {
388 	game.block.active = FALSE;
389 }
390 
cmd(normal_motion)391 cmd(normal_motion) {
392 	vt.motion = MOTION_NORMAL;
393 }
394 
cmd(stop_motion)395 cmd(stop_motion) {
396 	vt.direction = 0;
397 	vt.motion = MOTION_NORMAL;
398 	if (p0 == 0) {		/* ego only */
399 		_v[V_ego_dir] = 0;
400 		game.player_control = FALSE;
401 	}
402 }
403 
cmd(start_motion)404 cmd(start_motion) {
405 	vt.motion = MOTION_NORMAL;
406 	if (p0 == 0) {		/* ego only */
407 		_v[V_ego_dir] = 0;
408 		game.player_control = TRUE;
409 	}
410 }
411 
cmd(player_control)412 cmd(player_control) {
413 	game.player_control = TRUE;
414 	game.view_table[0].motion = MOTION_NORMAL;
415 }
416 
cmd(program_control)417 cmd(program_control) {
418 	game.player_control = FALSE;
419 }
420 
cmd(follow_ego)421 cmd(follow_ego) {
422 	vt.motion = MOTION_FOLLOW_EGO;
423 	vt.parm1 = p1 > vt.step_size ? p1 : vt.step_size;
424 	vt.parm2 = p2;
425 	vt.parm3 = 0xff;
426 	setflag (p2, FALSE);
427 	vt.flags |= UPDATE;
428 }
429 
cmd(move_obj)430 cmd(move_obj) {
431 	_D (_D_WARN "o=%d, x=%d, y=%d, s=%d, f=%d", p0, p1, p2, p3, p4);
432 
433 	vt.motion = MOTION_MOVE_OBJ;
434 	vt.parm1 = p1;
435 	vt.parm2 = p2;
436 	vt.parm3 = vt.step_size;
437 	vt.parm4 = p4;
438 
439 	if (p3 != 0)
440 		vt.step_size = p3;
441 
442 	setflag (p4, FALSE);
443 	vt.flags |= UPDATE;
444 
445 	if (p0 == 0)
446 		game.player_control = FALSE;
447 
448 	move_obj (&vt);
449 }
450 
cmd(move_obj_f)451 cmd(move_obj_f) {
452 	vt.motion = MOTION_MOVE_OBJ;
453 	vt.parm1 = _v[p1];
454 	vt.parm2 = _v[p2];
455 	vt.parm3 = vt.step_size;
456 	vt.parm4 = p4;
457 
458 	if (_v[p3] != 0)
459 		vt.step_size = _v[p3];
460 
461 	setflag (p4, FALSE);
462 	vt.flags |= UPDATE;
463 
464 	if (p0 == 0)
465 		game.player_control = FALSE;
466 
467 	move_obj (&vt);
468 }
469 
cmd(wander)470 cmd(wander) {
471 	if (p0 == 0)
472 		game.player_control = FALSE;
473 	vt.motion = MOTION_WANDER;
474 	vt.flags |= UPDATE;
475 }
476 
477 
cmd(set_game_id)478 cmd(set_game_id) {
479 	if (cur_logic->texts && (p0 - 1) <= cur_logic->num_texts)
480 		strncpy (game.id, cur_logic->texts[p0 - 1], 8);
481 	else
482 		game.id[0] = 0;
483 
484 	report ("Game ID: \"%s\"\n", game.id);
485 }
486 
cmd(pause)487 cmd(pause) {
488 	int tmp = game.clock_enabled;
489 	char *b[] = { "Continue", NULL };
490 
491 	game.clock_enabled = FALSE;
492 	selection_box ("  Game is paused.  \n\n\n", b);
493 	game.clock_enabled = tmp;
494 }
495 
cmd(set_menu)496 cmd(set_menu) {
497 	_D ("text %02x of %02x", p0, cur_logic->num_texts);
498 	if (cur_logic->texts != NULL && p0 < cur_logic->num_texts)
499 		add_menu (cur_logic->texts[p0 - 1]);
500 }
501 
cmd(set_menu_item)502 cmd(set_menu_item) {
503 	_D ("text %02x of %02x", p0, cur_logic->num_texts);
504 	if (cur_logic->texts != NULL && p0 < cur_logic->num_texts)
505 		add_menu_item (cur_logic->texts[p0 - 1], p1);
506 }
507 
cmd(version)508 cmd(version) {
509 	char ver_msg[] = TITLE " v" VERSION;
510 	char ver2_msg[] =
511 		"\n"
512 		"                             \n\n"
513         	"Emulating Sierra AGI v%x.%03x\n";
514 	char ver3_msg[]=
515     		"\n"
516        		"                             \n\n"
517        		"  Emulating AGI v%x.002.%03x\n";
518 		/* no Sierra as it wraps textbox */
519 	char *r, *q;
520 	int ver, maj, min;
521 	char msg[256];
522 
523 	ver = agi_get_release ();
524 	maj = (ver >> 12) & 0xf;
525 	min = ver & 0xfff;
526 
527 	q = maj == 2 ? ver2_msg : ver3_msg;
528 	r = strchr (q+1, '\n');
529 
530 	strncpy (q+1 + ((r-q > 0 ? r - q : 1) / 4), ver_msg, strlen (ver_msg));
531 	sprintf (msg, q, maj, min);
532 	message_box (msg);
533 }
534 
cmd(configure_screen)535 cmd(configure_screen) {
536 	game.line_min_print = p0;
537 	game.line_user_input = p1;
538 	game.line_status = p2;
539 }
540 
cmd(text_screen)541 cmd(text_screen) {
542 	_D (_D_WARN "switching to text mode");
543 	game.gfx_mode = FALSE;
544 	/*
545 	 * Simulates the "bright background bit" of the PC video
546 	 * controller.
547 	 */
548 	if (game.color_bg)
549 		game.color_bg |= 0x08;
550 	clear_screen (game.color_bg);
551 }
552 
cmd(graphics)553 cmd(graphics) {
554 	_D (_D_WARN "switching to graphics mode");
555 	if (!game.gfx_mode) {
556 		game.gfx_mode = TRUE;
557 		clear_screen (0);
558 		show_pic ();
559  		write_status ();
560 	}
561 }
562 
cmd(status)563 cmd(status) {
564 	inventory();
565 }
566 
cmd(quit)567 cmd(quit) {
568 	char *buttons[] = { "Quit", "Continue", NULL };
569 
570 	stop_sound ();
571 	if (p0) {
572 		game.quit_prog_now = TRUE;
573 	} else {
574 		if (selection_box (" Quit the game, or continue? \n\n\n",
575 			buttons) == 0)
576 		{
577 			game.quit_prog_now = TRUE;
578 		}
579 	}
580 }
581 
cmd(restart_game)582 cmd(restart_game) {
583 	char *buttons[] = { "Restart", "Continue", NULL };
584 
585 	stop_sound ();
586 	/* FIXME: Test flag 16 */
587 
588 	if (selection_box (" Restart game, or continue? \n\n\n",
589 		buttons) == 0)
590 	{
591 		game.quit_prog_now = 0xff;
592 		setflag (F_restart_game, TRUE);
593 	}
594 }
595 
cmd(distance)596 cmd(distance) {
597 	SINT16 x1, y1, x2, y2, d;
598 	struct vt_entry *v0 = &game.view_table[p0];
599 	struct vt_entry *v1 = &game.view_table[p1];
600 
601 	if (v0->flags & DRAWN && v1->flags & DRAWN) {
602 		x1 = v0->x_pos + v0->x_size / 2;
603 		y1 = v0->y_pos;
604 		x2 = v1->x_pos + v1->x_size / 2;
605 		y2 = v1->y_pos;
606 		d = abs (x1 - x2) + abs (y1 - y2);
607 		if (d > 0xfe) d = 0xfe;
608 	} else {
609 		d = 0xff;
610 	}
611 	_v[p2] = (unsigned char)d;
612 }
613 
cmd(get_string)614 cmd(get_string) {
615 	_D ("%d %d %d %d %d", p0, p1, p2, p3, p4);
616 	new_input_mode (INPUT_GETSTRING);
617 
618 	if (cur_logic->texts != NULL && cur_logic->num_texts >= (p1 - 1)) {
619 		int len = strlen (cur_logic->texts[p1 - 1]);
620 		print_text (cur_logic->texts[p1 - 1], 0, p3,
621 			p2, len, game.color_fg, game.color_bg);
622 		get_string (p3 + len - 1, p2, p4, p0);
623 
624 		/* SGEO : display input char */
625 		print_character ((p3 + len ), p2, game.cursor_char,
626 			game.color_fg, game.color_bg);
627 	}
628 
629 	do {
630 		main_cycle ();
631 	} while (game.input_mode == INPUT_GETSTRING);
632 }
633 
634 
cmd(get_num)635 cmd(get_num) {
636 	_D ("%d %d", p0, p1);
637 	new_input_mode (INPUT_GETSTRING);
638 
639 	if (cur_logic->texts != NULL && cur_logic->num_texts >= (p0 - 1)) {
640 		int len = strlen (cur_logic->texts[p0 - 1]);
641 		print_text (cur_logic->texts[p0 - 1], 0, 0, 22, len,
642 			game.color_fg, game.color_bg);
643 		get_string (len - 1, 22, 3, MAX_WORDS2);
644 	}
645 
646 	do {
647 		main_cycle ();
648 	} while (game.input_mode == INPUT_GETSTRING);
649 
650 	_v[p1] = atoi (game.strings[MAX_WORDS2]);
651 	_D (_D_WARN "[%s] -> %d", game.strings[MAX_WORDS2], _v[p1]);
652 	clear_lines (22, 22, game.color_bg);
653 	flush_lines (22, 22);
654 }
655 
cmd(set_cursor_char)656 cmd(set_cursor_char)
657 {
658 	if (cur_logic->texts != NULL && (p0 - 1) <= cur_logic->num_texts) {
659 		game.cursor_char = *cur_logic->texts[p0 - 1];
660 	} else {
661 		/* default */
662 		game.cursor_char = '_';
663 	}
664 }
665 
cmd(set_key)666 cmd(set_key) {
667 	_D ("%d %d %d", p0, p1, p2);
668 	if (p0 && p1) {
669 		_D (_D_WARN "FIXME: not registered!");
670 		return;
671 	}
672 	if (p0) {		/* keypress */
673 		game.ev_keyp[p2].data = p0;
674 		game.ev_keyp[p2].occured = FALSE;
675 	} else {		/* scancode */
676 		game.ev_scan[p2].data = p1;
677 		game.ev_scan[p2].occured = FALSE;
678 	}
679 }
680 
cmd(set_string)681 cmd(set_string) {
682 	/* CM: to avoid crash in Groza (str = 150) */
683 	if (p0 > MAX_WORDS1) return;
684 	strcpy (game.strings[p0], cur_logic->texts[p1 - 1]);
685 }
686 
cmd(display)687 cmd(display) {
688 	print_text (cur_logic->texts[p2 - 1], p1, 0, p0, 40,
689 		game.color_fg, game.color_bg);
690 }
691 
cmd(display_f)692 cmd(display_f) {
693 	_D ("p0 = %d", p0);
694 	print_text (cur_logic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40,
695 		game.color_fg, game.color_bg);
696 }
697 
cmd(clear_text_rect)698 cmd(clear_text_rect) {
699 	int c, x1, y1, x2, y2;
700 
701 	if ((c = p4) != 0) c = 15;
702 	x1 = p1 * CHAR_COLS;
703 	y1 = p0 * CHAR_LINES;
704 	x2 = (p3 + 1) * CHAR_COLS - 1;
705 	y2 = (p2 + 1) * CHAR_LINES - 1;
706 
707 	/* Added to prevent crash with x2 = 40 in the iigs demo */
708 	if (x1 > GFX_WIDTH) x1 = GFX_WIDTH - 1;
709 	if (x2 > GFX_WIDTH) x2 = GFX_WIDTH - 1;
710 	if (y1 > GFX_HEIGHT) y1 = GFX_HEIGHT - 1;
711 	if (y2 > GFX_HEIGHT) y2 = GFX_HEIGHT - 1;
712 
713 	draw_rectangle (x1, y1, x2, y2, c);
714 	flush_block (x1, y1, x2, y2);
715 }
716 
cmd(toggle_monitor)717 cmd(toggle_monitor)
718 {
719 	report ("toggle.monitor\n");
720 #ifdef USE_HIRES
721 	opt.hires = !opt.hires;
722 	erase_both();
723 	show_pic ();
724 	blit_both ();
725 #endif
726 }
727 
cmd(echo_line)728 cmd(echo_line) {
729 	strcpy (game.input_buffer, game.echo_buffer);
730 	game.cursor_pos = strlen ((char*)game.input_buffer);
731 	game.has_prompt = 0;
732 }
733 
cmd(clear_lines)734 cmd(clear_lines) {
735 	clear_lines (p0, p1, p2);
736 	flush_lines (p0, p1);
737 }
738 
cmd(print)739 cmd(print) {
740 	int n = p0 < 1 ? 1 : p0;
741 	print (cur_logic->texts[n - 1], 0, 0, 0);
742 }
743 
cmd(print_f)744 cmd(print_f) {
745 	int n = _v[p0] < 1 ? 1 : _v[p0];
746 	print (cur_logic->texts[n - 1], 0, 0, 0);
747 }
748 
cmd(print_at)749 cmd(print_at) {
750 	int n = p0 < 1 ? 1 : p0;
751 	print (cur_logic->texts[n - 1], p1, p2, p3);
752 }
753 
cmd(print_at_v)754 cmd(print_at_v)	{
755 	int n = _v[p0] < 1 ? 1 : _v[p0];
756 	print (cur_logic->texts[n - 1], p1, p2, p3);
757 }
758 
cmd(push_script)759 cmd(push_script) {
760 #ifdef USE_MOUSE
761 	if (opt.agimouse) {
762 		game.vars[27] = mouse.button ? 1 : 0;
763 		game.vars[28] = mouse.x;
764 		game.vars[29] = mouse.y;
765 	} else
766 #endif
767 		report ("push.script\n");
768 }
769 
cmd(set_pri_base)770 cmd(set_pri_base) {
771 	int i, x, pri;
772 
773 	report ("Priority base set to %d\n", p0);
774 
775 	game.alt_pri = TRUE;
776 	x = (_HEIGHT - p0) * _HEIGHT / 10;
777 
778 	for (i = 0; i < _HEIGHT; i++) {
779 		pri = (i - p0) < 0 ? 4 : (i - p0) * _HEIGHT / x + 5;
780 		if (pri > 15)
781 			pri = 15;
782 		game.pri_table[i] = pri;
783 	}
784 }
785 
cmd(mouse_posn)786 cmd(mouse_posn)	{
787 #ifdef USE_MOUSE
788 	_v[p0] = WIN_TO_PIC_X(mouse.x);
789 	_v[p1] = WIN_TO_PIC_Y(mouse.y);
790 #endif
791 }
792 
793 
794 static void (*agi_command[183])(UINT8 *) = {
795 	NULL,				/* 0x00 */
796 	cmd_increment,
797 	cmd_decrement,
798 	cmd_assignn,
799 	cmd_assignv,
800 	cmd_addn,
801 	cmd_addv,
802 	cmd_subn,
803 	cmd_subv,			/* 0x08 */
804 	cmd_lindirectv,
805 	cmd_rindirect,
806 	cmd_lindirectn,
807 	cmd_set,
808 	cmd_reset,
809 	cmd_toggle,
810 	cmd_set_v,
811 	cmd_reset_v,			/* 0x10 */
812 	cmd_toggle_v,
813 	cmd_new_room,
814 	cmd_new_room_f,
815 	cmd_load_logic,
816 	cmd_load_logic_f,
817 	cmd_call,
818 	cmd_call_f,
819 	cmd_load_pic,			/* 0x18 */
820 	cmd_draw_pic,
821 	cmd_show_pic,
822 	cmd_discard_pic,
823 	cmd_overlay_pic,
824 	cmd_show_pri_screen,
825 	cmd_load_view,
826 	cmd_load_view_f,
827 	cmd_discard_view,		/* 0x20 */
828 	cmd_animate_obj,
829 	cmd_unanimate_all,
830 	cmd_draw,
831 	cmd_erase,
832 	cmd_position,
833 	cmd_position_f,
834 	cmd_get_posn,
835 	cmd_reposition,			/* 0x28 */
836 	cmd_set_view,
837 	cmd_set_view_f,
838 	cmd_set_loop,
839 	cmd_set_loop_f,
840 	cmd_fix_loop,
841 	cmd_release_loop,
842 	cmd_set_cel,
843 	cmd_set_cel_f,			/* 0x30 */
844 	cmd_last_cel,
845 	cmd_current_cel,
846 	cmd_current_loop,
847 	cmd_current_view,
848 	cmd_number_of_loops,
849 	cmd_set_priority,
850 	cmd_set_priority_f,
851 	cmd_release_priority,		/* 0x38 */
852 	cmd_get_priority,
853 	cmd_stop_update,
854 	cmd_start_update,
855 	cmd_force_update,
856 	cmd_ignore_horizon,
857 	cmd_observe_horizon,
858 	cmd_set_horizon,
859 	cmd_object_on_water,		/* 0x40 */
860 	cmd_object_on_land,
861 	cmd_object_on_anything,
862 	cmd_ignore_objs,
863 	cmd_observe_objs,
864 	cmd_distance,
865 	cmd_stop_cycling,
866 	cmd_start_cycling,
867 	cmd_normal_cycle,		/* 0x48 */
868 	cmd_end_of_loop,
869 	cmd_reverse_cycle,
870 	cmd_reverse_loop,
871 	cmd_cycle_time,
872 	cmd_stop_motion,
873 	cmd_start_motion,
874 	cmd_step_size,
875 	cmd_step_time,			/* 0x50 */
876 	cmd_move_obj,
877 	cmd_move_obj_f,
878 	cmd_follow_ego,
879 	cmd_wander,
880 	cmd_normal_motion,
881 	cmd_set_dir,
882 	cmd_get_dir,
883 	cmd_ignore_blocks,		/* 0x58 */
884 	cmd_observe_blocks,
885 	cmd_block,
886 	cmd_unblock,
887 	cmd_get,
888 	cmd_get_f,
889 	cmd_drop,
890 	cmd_put,
891 	cmd_put_f,			/* 0x60 */
892 	cmd_get_room_f,
893 	cmd_load_sound,
894 	cmd_sound,
895 	cmd_stop_sound,
896 	cmd_print,
897 	cmd_print_f,
898 	cmd_display,
899 	cmd_display_f,			/* 0x68 */
900 	cmd_clear_lines,
901 	cmd_text_screen,
902 	cmd_graphics,
903 	cmd_set_cursor_char,
904 	cmd_set_text_attribute,
905 	cmd_shake_screen,
906 	cmd_configure_screen,
907 	cmd_status_line_on,		/* 0x70 */
908 	cmd_status_line_off,
909 	cmd_set_string,
910 	cmd_get_string,
911 	cmd_word_to_string,
912 	cmd_parse,
913 	cmd_get_num,
914 	cmd_prevent_input,
915 	cmd_accept_input,		/* 0x78 */
916 	cmd_set_key,
917 	cmd_add_to_pic,
918 	cmd_add_to_pic_f,
919 	cmd_status,
920 	cmd_save_game,
921 	cmd_load_game,
922 	cmd_init_disk,
923 	cmd_restart_game,		/* 0x80 */
924 	cmd_show_obj,
925 	cmd_random,
926 	cmd_program_control,
927 	cmd_player_control,
928 	cmd_obj_status_f,
929 	cmd_quit,
930 	cmd_show_mem,
931 	cmd_pause,			/* 0x88 */
932 	cmd_echo_line,
933 	cmd_cancel_line,
934 	cmd_init_joy,
935 	cmd_toggle_monitor,
936 	cmd_version,
937 	cmd_script_size,
938 	cmd_set_game_id,
939 	cmd_log,			/* 0x90 */
940 	cmd_set_scan_start,
941 	cmd_reset_scan_start,
942 	cmd_reposition_to,
943 	cmd_reposition_to_f,
944 	cmd_trace_on,
945 	cmd_trace_info,
946 	cmd_print_at,
947 	cmd_print_at_v,			/* 0x98 */
948 	cmd_discard_view,
949 	cmd_clear_text_rect,
950 	cmd_set_upper_left,
951 	cmd_set_menu,
952 	cmd_set_menu_item,
953 	cmd_submit_menu,
954 	cmd_enable_item,
955 	cmd_disable_item,		/* 0xa0 */
956 	cmd_menu_input,
957 	cmd_show_obj_v,
958 	cmd_open_dialogue,
959 	cmd_close_dialogue,
960 	cmd_mul_n,
961 	cmd_mul_v,
962 	cmd_div_n,
963 	cmd_div_v,			/* 0xa8 */
964 	cmd_close_window,
965 	cmd_set_simple,
966 	cmd_push_script,
967 	cmd_pop_script,
968 	cmd_hold_key,
969 	cmd_set_pri_base,
970 	cmd_discard_sound,
971 	cmd_hide_mouse,			/* 0xb0 */
972 	cmd_allow_menu,
973 	cmd_show_mouse,
974 	cmd_fence_mouse,
975 	cmd_mouse_posn,
976 	cmd_release_key,
977 	cmd_adj_ego_move_to_xy
978 };
979 
980 
981 #define CMD_BSIZE 12
982 
983 /**
984  * Execute a logic script
985  * @param n  Number of the logic resource to execute
986  */
run_logic(int n)987 int run_logic (int n)
988 {
989 	UINT8 op			= 0;
990 	UINT8 p[CMD_BSIZE]		= {0};
991 	UINT8 *code			= NULL;
992 	int num				= 0;
993 
994 	/* If logic not loaded, load it */
995 	if (~game.dir_logic[n].flags & RES_LOADED) {
996 		_D (_D_WARN "logic %d not loaded!", n);
997 		agi_load_resource (rLOGIC, n);
998 	}
999 
1000 	game.lognum = n;
1001 	cur_logic = &game.logics[game.lognum];
1002 
1003 	code = cur_logic->data;
1004 	cur_logic->cIP = cur_logic->sIP;
1005 
1006 	timer_hack = 0;
1007 	while (ip < game.logics[n].size && !game.quit_prog_now) {
1008 #ifdef USE_CONSOLE
1009 		if (debug.enabled) {
1010 			if (debug.steps > 0) {
1011 				if (debug.logic0 || n) {
1012 					debug_console (n,
1013 						lCOMMAND_MODE, NULL);
1014 					debug.steps--;
1015 				}
1016 			} else {
1017 				blit_both ();
1018 				console_prompt ();
1019 				do {
1020 					main_cycle ();
1021 				} while (!debug.steps && debug.enabled);
1022 				console_lock ();
1023 				erase_both ();
1024 			}
1025 		}
1026 #endif
1027 
1028 		switch (op = *(code + ip++)) {
1029 		case 0xff:			/* if (open/close) */
1030 			test_if_code (n);
1031 			break;
1032 		case 0xfe:			/* goto */
1033 			/* +2 covers goto size */
1034 			ip += 2 + ((SINT16)lohi_getword (code + ip));
1035 			/* timer must keep running even in goto loops,
1036 			 * but Sarien can't do that :(
1037 			 */
1038 			if (timer_hack > 20) {
1039 				poll_timer ();
1040 				update_timer ();
1041 				timer_hack = 0;
1042 			}
1043 			break;
1044 		case 0x00:			/* return */
1045 			return 1;
1046 		default:
1047 			num = logic_names_cmd[op].num_args;
1048 			memmove (p, code + ip, num);
1049 			memset (p + num, 0, CMD_BSIZE - num);
1050 			agi_command[op](p);
1051 			ip += num;
1052 		}
1053 
1054 		if (game.exit_all_logics)
1055 			break;
1056 	}
1057 
1058 	return 0;	/* after executing new.room() */
1059 }
1060 
1061 
execute_agi_command(UINT8 op,UINT8 * p)1062 void execute_agi_command (UINT8 op, UINT8 *p)
1063 {
1064 	_D (_D_WARN "%s %d %d %d", logic_names_cmd[op].name, p[0], p[1], p[2]);
1065 	agi_command[op](p);
1066 }
1067 
1068