From d5d2c7f38588f6f7ad29054c4c34a19b5c265ffd Mon Sep 17 00:00:00 2001 From: Jason Stevens Date: Sun, 25 Feb 2024 10:40:55 +0000 Subject: [PATCH] Revert "Added pc speaker/DosBeep" This reverts commit 14bc373fd258aec67e45882d82f6ae923522c162. --- Makefile | 5 +- Makefile.gnu | 35 - Makefile.os2 | 32 - agi.c | 450 ++++----- agi_v2.c | 648 ++++++------ agi_v3.c | 778 +++++++-------- agi_v4.c | 1656 +++++++++++++++---------------- checks.c | 626 ++++++------ cli.c | 628 ++++++------ console.c | 1916 ++++++++++++++++++------------------ cycle.c | 845 ++++++++-------- dummy.c | 83 +- fileglob.c | 260 ++--- font.c | 824 ++++++++-------- getopt.c | 2008 +++++++++++++++++++------------------- getopt1.c | 386 ++++---- global.c | 300 +++--- graphics.c | 1424 +++++++++++++-------------- hirespic.c | 480 ++++----- id.c | 762 +++++++-------- include/agi.h | 550 +++++------ include/console.h | 122 +-- include/getopt.h | 266 ++--- include/graphics.h | 190 ++-- include/keyboard.h | 162 +-- include/list.h | 290 +++--- include/logic.h | 74 +- include/lzw.h | 48 +- include/menu.h | 74 +- include/opcodes.h | 86 +- include/picture.h | 70 +- include/portdefs.h | 372 +++---- include/rand.h | 52 +- include/sarien.h | 604 ++++++------ include/savegame.h | 74 +- include/scale2x.h | 2262 +++++++++++++++++++++--------------------- include/sound.h | 222 ++--- include/sprite.h | 74 +- include/text.h | 74 +- include/view.h | 274 +++--- inv.c | 410 ++++---- keyboard.c | 752 +++++++------- logic.c | 214 ++-- lzw.c | 364 +++---- main.c | 524 +++++----- menu.c | 1038 ++++++++++---------- motion.c | 460 ++++----- nothing.c | 8 - nullvid.c | 1090 ++++++++++----------- objects.c | 356 +++---- op_cmd.c | 2326 ++++++++++++++++++++++---------------------- op_dbg.c | 684 ++++++------- op_test.c | 862 ++++++++-------- patches.c | 260 ++--- path.c | 156 +-- pccga.c | 442 ++++----- pcvga.c | 456 ++++----- pharcga.c | 526 +++++----- pharvid.c | 442 ++++----- picture.c | 1686 ++++++++++++++++---------------- picview.c | 340 +++---- rand.c | 146 +-- sarien.ini | 200 ++-- sarien.lnk | 8 +- silent.c | 72 +- sound.c | 1395 +++++++++++++++----------- sprite.c | 1814 +++++++++++++++++----------------- text.c | 1378 +++++++++++++------------- view.c | 794 +++++++-------- words.c | 692 ++++++------- 70 files changed, 20018 insertions(+), 19963 deletions(-) delete mode 100644 Makefile.gnu delete mode 100644 Makefile.os2 delete mode 100644 nothing.c diff --git a/Makefile b/Makefile index fe75605..7ee8d16 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,7 @@ OBJ = agi.obj agi_v2.obj agi_v3.obj agi_v4.obj checks.obj cli.obj console.obj cy font.obj getopt.obj getopt1.obj global.obj graphics.obj hirespic.obj id.obj inv.obj \ keyboard.obj logic.obj lzw.obj main.obj menu.obj motion.obj objects.obj op_cmd.obj \ op_dbg.obj op_test.obj patches.obj path.obj picture.obj picview.obj rand.obj savegame.obj \ -silent.obj sound.obj sprite.obj text.obj view.obj words.obj fileglob.obj nothing.obj +silent.obj sound.obj sprite.obj text.obj view.obj words.obj fileglob.obj INVOLVED = fileglob.obj @@ -80,14 +80,13 @@ include ..\-justcompile.mak #include ..\-plainassembly.mak sarien: $(OBJ) $(NULL) - SET LIB=C:\cl386-research\lib2 $(OS2LINK) @sarien.lnk mcopy -i %QEMUPATH%\dummy.vfd -D o sarien.exe :: qemuos2 clean: - del $(OBJ) $(NULL) + del $(OBJ) del sarien.exe del *.asm *.a1 *.a diff --git a/Makefile.gnu b/Makefile.gnu deleted file mode 100644 index e5442e7..0000000 --- a/Makefile.gnu +++ /dev/null @@ -1,35 +0,0 @@ - -DEFS = -D__32BIT__ -DM_I386 -D _MSC_VER=6 -DKEYS_WORK -DNEED_NOTHING -INC = -Iinclude -#OPT = /G3 /O -#OPT = /G3 /Ogilt /Gs -DEBUG = #/Zi -LDEBUG = #-debug:full -CC=gcc -OS2LINK = LINK386.EXE - -CFLAGS= $(INC) $(DEFS) $(OPT) - -OBJ = agi.obj agi_v2.obj agi_v3.obj agi_v4.obj checks.obj cli.obj console.obj cycle.obj \ - font.obj getopt.obj getopt1.obj global.obj graphics.obj hirespic.obj id.obj inv.obj \ -keyboard.obj logic.obj lzw.obj main.obj menu.obj motion.obj objects.obj op_cmd.obj \ -op_dbg.obj op_test.obj patches.obj path.obj picture.obj picview.obj rand.obj savegame.obj \ -silent.obj sound.obj sprite.obj text.obj view.obj words.obj nothing.obj - -sarien: $(OBJ) - -# gnu make (cross compiled) -%.obj: %.c - $(CC) $(CFLAGS) -c $*.c - o2obj $*.o - rm $*.o -# nmake -#.c.obj: -# @emxomf -o $*.obj $*.o -# @del $*.o - - -clean: - del $(OBJ) - del sarien.exe - del *.asm *.a1 *.a diff --git a/Makefile.os2 b/Makefile.os2 deleted file mode 100644 index 0dc5085..0000000 --- a/Makefile.os2 +++ /dev/null @@ -1,32 +0,0 @@ - -DEFS = -D__32BIT__ -DM_I386 -D _MSC_VER=6 -DKEYS_WORK -INC = /u /w -Iinclude -OPT = /G3 /Ox -#OPT = /G3 /Ogilt /Gs -DEBUG = #/Zi -LDEBUG = #-debug:full -CC=cl386 -OS2LINK = LINK386.EXE - -CFLAGS= $(INC) $(DEFS) $(OPT) - -OBJ = agi.obj agi_v2.obj agi_v3.obj agi_v4.obj checks.obj cli.obj console.obj cycle.obj \ - font.obj getopt.obj getopt1.obj global.obj graphics.obj hirespic.obj id.obj inv.obj \ -keyboard.obj logic.obj lzw.obj main.obj menu.obj motion.obj objects.obj op_cmd.obj \ -op_dbg.obj op_test.obj patches.obj path.obj picture.obj picview.obj rand.obj savegame.obj \ -silent.obj sound.obj sprite.obj text.obj view.obj words.obj fileglob.obj -INVOLVED = fileglob.obj -HARD = dummy.obj pccga.obj pcvga.obj pharcga.obj pharvid.obj -NULL = dummy.obj nullvid.obj - -sarien: $(OBJ) $(NULL) - $(OS2LINK) @sarien.lnk - -.c.obj: - $(CC) $(CFLAGS) /c $*.c - - -clean: - @del $(OBJ) - @del sarien.exe - @del *.asm *.a1 *.a diff --git a/agi.c b/agi.c index 15ca006..5251ec0 100644 --- a/agi.c +++ b/agi.c @@ -1,225 +1,225 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: agi.c,v 1.65 2003/08/31 16:05:05 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "opcodes.h" -#include "keyboard.h" -#include "rand.h" -#include "menu.h" -#include "savegame.h" - -static struct agi_loader *loader; /* loader */ - - -#ifndef PALMOS -extern struct agi_loader agi_v2; -extern struct agi_loader agi_v3; -#else -extern struct agi_loader agi_v4; -#endif - - -static void init_pri_table () -{ - int i, p, y = 0; - - for (p = 1; p < 15; p++) { - for (i = 0; i < 12; i++) { - game.pri_table[y++] = p < 4 ? 4 : p; - } - } -} - - -int agi_init () -{ - int ec, i; - - _D ("initializing"); - _D (_D_WARN "game.ver = 0x%x", game.ver); - - /* reset all flags to false and all variables to 0 */ - for (i = 0; i < MAX_FLAGS; i++) - game.flags[i] = 0; - for (i = 0; i < MAX_VARS; i++) - game.vars[i] = 0; - - /* clear all resources and events */ - for (i = 0; i < MAX_DIRS; i++) { - memset (&game.views[i], 0, sizeof (struct agi_view)); - memset (&game.pictures[i], 0, sizeof (struct agi_picture)); - memset (&game.logics[i], 0, sizeof (struct agi_logic)); - memset (&game.sounds[i], 0, sizeof (struct agi_sound)); - } - - /* clear view table */ - for (i = 0; i < MAX_VIEWTABLE; i++) - memset (&game.view_table[i], 0, sizeof (struct vt_entry)); - - init_words (); - set_rnd_seed (); - menu_init (); - init_pri_table (); - - /* clear string buffer */ - for (i = 0; i < MAX_STRINGS; i++) - game.strings[i][0] = 0; - - /* setup emulation */ - - switch (loader->int_version >> 12) { - case 2: - report ("Emulating Sierra AGI v%x.%03x\n", - (int)(loader->int_version >> 12) & 0xF, - (int)(loader->int_version) & 0xFFF); - break; - case 3: - report ("Emulating Sierra AGI v%x.002.%03x\n", - (int)(loader->int_version >> 12) & 0xF, - (int)(loader->int_version) & 0xFFF); - break; - } - - game.game_flags |= opt.amiga ? ID_AMIGA : 0; - game.game_flags |= opt.agds ? ID_AGDS : 0; - - if (game.game_flags & ID_AMIGA) - report ("Amiga padded game detected.\n"); - - if (game.game_flags & ID_AGDS) - report ("AGDS mode enabled.\n"); - - ec = loader->init (); /* load vol files, etc */ - - if (ec == err_OK) - ec = loader->load_objects(OBJECTS); - - /* note: demogs has no words.tok */ - if(ec == err_OK) - ec = loader->load_words(WORDS); - - /* FIXME: load IIgs instruments and samples */ - /* load_instruments("kq.sys16"); */ - - /* Load logic 0 into memory */ - if (ec == err_OK) - ec = loader->load_resource (rLOGIC, 0); - - return ec; -} - - -/* - * Public functions - */ - -void agi_unload_resources () -{ - int i; - - /* Make sure logic 0 is always loaded */ - for (i = 1; i < MAX_DIRS; i++) { - loader->unload_resource (rLOGIC, i); - } - for (i = 0; i < MAX_DIRS; i++) { - loader->unload_resource (rVIEW, i); - loader->unload_resource (rPICTURE, i); - loader->unload_resource (rSOUND, i); - } -} - -int agi_deinit () -{ - int ec; - - clean_input (); /* remove all words from memory */ - agi_unload_resources (); /* unload resources in memory */ - loader->unload_resource (rLOGIC, 0); - ec = loader->deinit (); - unload_objects(); - unload_words(); - - clear_image_stack(); - - return ec; -} - -int agi_detect_game (char *gn) -{ - int ec = err_OK; - -#ifdef DREAMCAST - strcpy(g_gamename, UNKNOWN_GAME); -#endif - -#ifndef PALMOS - _D ("(gn = %s)", gn); - if (gn == NULL) /* assume current directory */ - gn = get_current_directory (); - - loader = &agi_v2; - ec = loader->detect_game (gn); - -#ifndef FAKE_PALMOS - if (ec != err_OK) { - loader = &agi_v3; - ec = loader->detect_game (gn); - } -#endif - -#else /* PALMOS */ - loader = &agi_v4; - ec = loader->detect_game(gn); -#endif - - return ec; -} - - -int agi_version () -{ - return loader->version; -} - - -int agi_get_release () -{ - return loader->int_version; -} - - -void agi_set_release (int n) -{ - loader->int_version = n; -} - - -int agi_load_resource (int r, int n) -{ - int i; - - i = loader->load_resource (r, n); -#ifdef PATCH_LOGIC - if (r == rLOGIC) - patch_logic (n); -#endif - - return i; -} - - -int agi_unload_resource (int r, int n) -{ - return loader->unload_resource (r, n); -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: agi.c,v 1.65 2003/08/31 16:05:05 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "opcodes.h" +#include "keyboard.h" +#include "rand.h" +#include "menu.h" +#include "savegame.h" + +static struct agi_loader *loader; /* loader */ + + +#ifndef PALMOS +extern struct agi_loader agi_v2; +extern struct agi_loader agi_v3; +#else +extern struct agi_loader agi_v4; +#endif + + +static void init_pri_table () +{ + int i, p, y = 0; + + for (p = 1; p < 15; p++) { + for (i = 0; i < 12; i++) { + game.pri_table[y++] = p < 4 ? 4 : p; + } + } +} + + +int agi_init () +{ + int ec, i; + + _D ("initializing"); + _D (_D_WARN "game.ver = 0x%x", game.ver); + + /* reset all flags to false and all variables to 0 */ + for (i = 0; i < MAX_FLAGS; i++) + game.flags[i] = 0; + for (i = 0; i < MAX_VARS; i++) + game.vars[i] = 0; + + /* clear all resources and events */ + for (i = 0; i < MAX_DIRS; i++) { + memset (&game.views[i], 0, sizeof (struct agi_view)); + memset (&game.pictures[i], 0, sizeof (struct agi_picture)); + memset (&game.logics[i], 0, sizeof (struct agi_logic)); + memset (&game.sounds[i], 0, sizeof (struct agi_sound)); + } + + /* clear view table */ + for (i = 0; i < MAX_VIEWTABLE; i++) + memset (&game.view_table[i], 0, sizeof (struct vt_entry)); + + init_words (); + set_rnd_seed (); + menu_init (); + init_pri_table (); + + /* clear string buffer */ + for (i = 0; i < MAX_STRINGS; i++) + game.strings[i][0] = 0; + + /* setup emulation */ + + switch (loader->int_version >> 12) { + case 2: + report ("Emulating Sierra AGI v%x.%03x\n", + (int)(loader->int_version >> 12) & 0xF, + (int)(loader->int_version) & 0xFFF); + break; + case 3: + report ("Emulating Sierra AGI v%x.002.%03x\n", + (int)(loader->int_version >> 12) & 0xF, + (int)(loader->int_version) & 0xFFF); + break; + } + + game.game_flags |= opt.amiga ? ID_AMIGA : 0; + game.game_flags |= opt.agds ? ID_AGDS : 0; + + if (game.game_flags & ID_AMIGA) + report ("Amiga padded game detected.\n"); + + if (game.game_flags & ID_AGDS) + report ("AGDS mode enabled.\n"); + + ec = loader->init (); /* load vol files, etc */ + + if (ec == err_OK) + ec = loader->load_objects(OBJECTS); + + /* note: demogs has no words.tok */ + if(ec == err_OK) + ec = loader->load_words(WORDS); + + /* FIXME: load IIgs instruments and samples */ + /* load_instruments("kq.sys16"); */ + + /* Load logic 0 into memory */ + if (ec == err_OK) + ec = loader->load_resource (rLOGIC, 0); + + return ec; +} + + +/* + * Public functions + */ + +void agi_unload_resources () +{ + int i; + + /* Make sure logic 0 is always loaded */ + for (i = 1; i < MAX_DIRS; i++) { + loader->unload_resource (rLOGIC, i); + } + for (i = 0; i < MAX_DIRS; i++) { + loader->unload_resource (rVIEW, i); + loader->unload_resource (rPICTURE, i); + loader->unload_resource (rSOUND, i); + } +} + +int agi_deinit () +{ + int ec; + + clean_input (); /* remove all words from memory */ + agi_unload_resources (); /* unload resources in memory */ + loader->unload_resource (rLOGIC, 0); + ec = loader->deinit (); + unload_objects(); + unload_words(); + + clear_image_stack(); + + return ec; +} + +int agi_detect_game (char *gn) +{ + int ec = err_OK; + +#ifdef DREAMCAST + strcpy(g_gamename, UNKNOWN_GAME); +#endif + +#ifndef PALMOS + _D ("(gn = %s)", gn); + if (gn == NULL) /* assume current directory */ + gn = get_current_directory (); + + loader = &agi_v2; + ec = loader->detect_game (gn); + +#ifndef FAKE_PALMOS + if (ec != err_OK) { + loader = &agi_v3; + ec = loader->detect_game (gn); + } +#endif + +#else /* PALMOS */ + loader = &agi_v4; + ec = loader->detect_game(gn); +#endif + + return ec; +} + + +int agi_version () +{ + return loader->version; +} + + +int agi_get_release () +{ + return loader->int_version; +} + + +void agi_set_release (int n) +{ + loader->int_version = n; +} + + +int agi_load_resource (int r, int n) +{ + int i; + + i = loader->load_resource (r, n); +#ifdef PATCH_LOGIC + if (r == rLOGIC) + patch_logic (n); +#endif + + return i; +} + + +int agi_unload_resource (int r, int n) +{ + return loader->unload_resource (r, n); +} + diff --git a/agi_v2.c b/agi_v2.c index a0bda76..b134ebb 100644 --- a/agi_v2.c +++ b/agi_v2.c @@ -1,324 +1,324 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: agi_v2.c,v 1.41 2002/04/03 21:08:25 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef PALMOS - -#include -#include -#include "sarien.h" -#include "agi.h" - -static int agi_v2_init (void); -static int agi_v2_deinit (void); -static int agi_v2_detect_game (char *); -static int agi_v2_load_resource (int, int); -static int agi_v2_unload_resource (int, int); -static int agi_v2_load_objects(char *); -static int agi_v2_load_words(char *); - -struct agi_loader agi_v2 = { - 2, - 0, - agi_v2_init, - agi_v2_deinit, - agi_v2_detect_game, - agi_v2_load_resource, - agi_v2_unload_resource, - agi_v2_load_objects, - agi_v2_load_words -}; - - -static int agi_v2_detect_game (char *gn) -{ - strncpy (game.dir, gn, MAX_PATH); - _D (_D_WARN "game.dir = %s", game.dir); - - if ( !file_isthere (fixpath (NO_GAMEDIR, LOGDIR)) || - !file_isthere (fixpath (NO_GAMEDIR, PICDIR)) || - !file_isthere (fixpath (NO_GAMEDIR, SNDDIR)) || - !file_isthere (fixpath (NO_GAMEDIR, VIEWDIR))) - { - return err_InvalidAGIFile; - } - - agi_v2.int_version = 0x2917; /* setup for 2.917 */ -#ifdef __MPW__ - return err_OK; -#else - return v2id_game (); -#endif -} - - -static int agi_v2_load_dir (struct agi_dir *agid, char *fname) -{ - FILE *fp; - UINT8 *mem; - UINT32 flen; - unsigned int i; - char *path; - - path = fixpath (NO_GAMEDIR, fname); - report ("Loading directory: %s\n", path); - - if ((fp = fopen (path, "rb")) == NULL) { - return err_BadFileOpen; - } - - fseek (fp, 0, SEEK_END); - flen = ftell (fp); - fseek (fp, 0, SEEK_SET); - - if ((mem = malloc (flen + 32)) == NULL) { - fclose (fp); - return err_NotEnoughMemory; - } - - fread (mem, 1, flen, fp); - - /* set all directory resources to gone */ - for (i = 0; i < MAX_DIRS; i++) { - agid[i].volume = 0xff; - agid[i].offset = _EMPTY; - } - - /* build directory entries */ - for (i = 0; i < flen; i += 3) { - agid[i / 3].volume = hilo_getbyte (mem + i) >> 4; - agid[i / 3].offset = hilo_getpword (mem + i) & (UINT32)_EMPTY; - /* _D ("%d: volume %d, offset 0x%05x", i / 3, - agid[i / 3].volume, agid[i / 3].offset); */ - } - - free (mem); - fclose (fp); - - return err_OK; -} - - -static int agi_v2_init () -{ - int ec = err_OK; - - /* load directory files */ - ec = agi_v2_load_dir (game.dir_logic, LOGDIR); - if (ec == err_OK) - ec = agi_v2_load_dir (game.dir_pic, PICDIR); - if (ec == err_OK) - ec = agi_v2_load_dir (game.dir_view, VIEWDIR); - if (ec == err_OK) - ec = agi_v2_load_dir (game.dir_sound, SNDDIR); - - return ec; -} - - -static int agi_v2_deinit () -{ - int ec = err_OK; - -#if 0 - /* unload words */ - agi_v2_unload_words (); - - /* unload objects */ - agi_v2_unload_objects (); -#endif - - return ec; -} - -static int agi_v2_unload_resource (int t, int n) -{ - /* _D ("unload resource"); */ - - switch (t) { - case rLOGIC: - unload_logic (n); - break; - case rPICTURE: - unload_picture (n); - break; - case rVIEW: - unload_view (n); - break; - case rSOUND: - unload_sound (n); - break; - } - - return err_OK; -} - - -/* - * This function does noting but load a raw resource into memory, - * if further decoding is required, it must be done by another - * routine. NULL is returned if unsucsessfull. - */ - -static UINT8* agi_v2_load_vol_res (struct agi_dir *agid) -{ - UINT8 *data = NULL; - char x[MAX_PATH], *path; - FILE *fp; - unsigned int sig; - - sprintf (x, "vol.%i", agid->volume); - path = fixpath (NO_GAMEDIR, x); - _D ("path = %s", path); - - if (agid->offset != _EMPTY && (fp = fopen (path, "rb")) != NULL) { - _D ("loading resource at offset %d", agid->offset); - if (fseek (fp, agid->offset, SEEK_SET) < 0) { - agid->offset = _EMPTY; - return NULL; - } - fread (&x, 1, 5, fp); - if ((sig = hilo_getword ((UINT8*)x)) == 0x1234) { - agid->len = lohi_getword ((UINT8*)x + 3); - data = calloc (1, agid->len + 32); - if (data != NULL) { - fread (data, 1, agid->len, fp); - } else { - abort (); - } - } else { -#if 0 - /* FIXME: call some panic handler instead of - * deiniting directly - */ - deinit_video_mode (); -#endif - report ("Error: bad signature %04x\n", sig); - /* fprintf (stderr, "ACK! BAD RESOURCE!!!\n"); */ - return 0; - } - fclose (fp); - } else { - /* we have a bad volume resource */ - /* set that resource to NA */ - agid->offset = _EMPTY; - } - - return data; -} - - -/* - * Loads a resource into memory, a raw resource is loaded in - * with above routine, then further decoded here. - */ -int agi_v2_load_resource (int t, int n) -{ - int ec = err_OK; - UINT8 *data = NULL; - - _D (_D_WARN "(t = %d, n = %d)", t, n); - if (n > MAX_DIRS) - return err_BadResource; - - switch (t) { - case rLOGIC: - if (~game.dir_logic[n].flags & RES_LOADED) { - _D (_D_WARN "loading logic resource %d", n); - agi_v2.unload_resource (rLOGIC, n); - - /* load raw resource into data */ - data = agi_v2_load_vol_res (&game.dir_logic[n]); - - game.logics[n].data = data; - ec = data ? decode_logic (n) : err_BadResource; - - game.logics[n].sIP = 2; - } - - /* if logic was cached, we get here */ - /* reset code pointers incase it was cached */ - - game.logics[n].cIP = game.logics[n].sIP; - break; - case rPICTURE: - /* if picture is currently NOT loaded *OR* cacheing is off, - * unload the resource (caching == off) and reload it - */ - - _D (_D_WARN "loading picture resource %d", n); - if (game.dir_pic[n].flags & RES_LOADED) - break; - - /* if loaded but not cached, unload it */ - /* if cached but not loaded, etc */ - agi_v2.unload_resource (rPICTURE, n); - data = agi_v2_load_vol_res (&game.dir_pic[n]); - - if (data != NULL) { - game.pictures[n].rdata = data; - game.dir_pic[n].flags |= RES_LOADED; - } else { - ec = err_BadResource; - } - break; - case rSOUND: - _D (_D_WARN "loading sound resource %d", n); - if (game.dir_sound[n].flags & RES_LOADED) - break; - - data = agi_v2_load_vol_res (&game.dir_sound[n]); - - if (data != NULL) { - game.sounds[n].rdata = data; - game.dir_sound[n].flags |= RES_LOADED; - decode_sound (n); - } else { - ec = err_BadResource; - } - break; - case rVIEW: - /* Load a VIEW resource into memory... - * Since VIEWS alter the view table ALL the time - * can we cache the view? or must we reload it all - * the time? - */ - if (game.dir_view[n].flags & RES_LOADED) - break; - - _D (_D_WARN "loading view resource %d", n); - agi_v2.unload_resource (rVIEW, n); - data = agi_v2_load_vol_res (&game.dir_view[n]); - if (data) { - game.views[n].rdata = data; - game.dir_view[n].flags |= RES_LOADED; - ec = decode_view (n); - } else { - ec=err_BadResource; - } - break; - default: - ec = err_BadResource; - break; - } - - return ec; -} - -static int agi_v2_load_objects(char *fname) -{ - return load_objects(fname); -} - -static int agi_v2_load_words(char *fname) -{ - return load_words(fname); -} - -#endif /* PALMOS */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: agi_v2.c,v 1.41 2002/04/03 21:08:25 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef PALMOS + +#include +#include +#include "sarien.h" +#include "agi.h" + +static int agi_v2_init (void); +static int agi_v2_deinit (void); +static int agi_v2_detect_game (char *); +static int agi_v2_load_resource (int, int); +static int agi_v2_unload_resource (int, int); +static int agi_v2_load_objects(char *); +static int agi_v2_load_words(char *); + +struct agi_loader agi_v2 = { + 2, + 0, + agi_v2_init, + agi_v2_deinit, + agi_v2_detect_game, + agi_v2_load_resource, + agi_v2_unload_resource, + agi_v2_load_objects, + agi_v2_load_words +}; + + +static int agi_v2_detect_game (char *gn) +{ + strncpy (game.dir, gn, MAX_PATH); + _D (_D_WARN "game.dir = %s", game.dir); + + if ( !file_isthere (fixpath (NO_GAMEDIR, LOGDIR)) || + !file_isthere (fixpath (NO_GAMEDIR, PICDIR)) || + !file_isthere (fixpath (NO_GAMEDIR, SNDDIR)) || + !file_isthere (fixpath (NO_GAMEDIR, VIEWDIR))) + { + return err_InvalidAGIFile; + } + + agi_v2.int_version = 0x2917; /* setup for 2.917 */ +#ifdef __MPW__ + return err_OK; +#else + return v2id_game (); +#endif +} + + +static int agi_v2_load_dir (struct agi_dir *agid, char *fname) +{ + FILE *fp; + UINT8 *mem; + UINT32 flen; + unsigned int i; + char *path; + + path = fixpath (NO_GAMEDIR, fname); + report ("Loading directory: %s\n", path); + + if ((fp = fopen (path, "rb")) == NULL) { + return err_BadFileOpen; + } + + fseek (fp, 0, SEEK_END); + flen = ftell (fp); + fseek (fp, 0, SEEK_SET); + + if ((mem = malloc (flen + 32)) == NULL) { + fclose (fp); + return err_NotEnoughMemory; + } + + fread (mem, 1, flen, fp); + + /* set all directory resources to gone */ + for (i = 0; i < MAX_DIRS; i++) { + agid[i].volume = 0xff; + agid[i].offset = _EMPTY; + } + + /* build directory entries */ + for (i = 0; i < flen; i += 3) { + agid[i / 3].volume = hilo_getbyte (mem + i) >> 4; + agid[i / 3].offset = hilo_getpword (mem + i) & (UINT32)_EMPTY; + /* _D ("%d: volume %d, offset 0x%05x", i / 3, + agid[i / 3].volume, agid[i / 3].offset); */ + } + + free (mem); + fclose (fp); + + return err_OK; +} + + +static int agi_v2_init () +{ + int ec = err_OK; + + /* load directory files */ + ec = agi_v2_load_dir (game.dir_logic, LOGDIR); + if (ec == err_OK) + ec = agi_v2_load_dir (game.dir_pic, PICDIR); + if (ec == err_OK) + ec = agi_v2_load_dir (game.dir_view, VIEWDIR); + if (ec == err_OK) + ec = agi_v2_load_dir (game.dir_sound, SNDDIR); + + return ec; +} + + +static int agi_v2_deinit () +{ + int ec = err_OK; + +#if 0 + /* unload words */ + agi_v2_unload_words (); + + /* unload objects */ + agi_v2_unload_objects (); +#endif + + return ec; +} + +static int agi_v2_unload_resource (int t, int n) +{ + /* _D ("unload resource"); */ + + switch (t) { + case rLOGIC: + unload_logic (n); + break; + case rPICTURE: + unload_picture (n); + break; + case rVIEW: + unload_view (n); + break; + case rSOUND: + unload_sound (n); + break; + } + + return err_OK; +} + + +/* + * This function does noting but load a raw resource into memory, + * if further decoding is required, it must be done by another + * routine. NULL is returned if unsucsessfull. + */ + +static UINT8* agi_v2_load_vol_res (struct agi_dir *agid) +{ + UINT8 *data = NULL; + char x[MAX_PATH], *path; + FILE *fp; + unsigned int sig; + + sprintf (x, "vol.%i", agid->volume); + path = fixpath (NO_GAMEDIR, x); + _D ("path = %s", path); + + if (agid->offset != _EMPTY && (fp = fopen (path, "rb")) != NULL) { + _D ("loading resource at offset %d", agid->offset); + if (fseek (fp, agid->offset, SEEK_SET) < 0) { + agid->offset = _EMPTY; + return NULL; + } + fread (&x, 1, 5, fp); + if ((sig = hilo_getword ((UINT8*)x)) == 0x1234) { + agid->len = lohi_getword ((UINT8*)x + 3); + data = calloc (1, agid->len + 32); + if (data != NULL) { + fread (data, 1, agid->len, fp); + } else { + abort (); + } + } else { +#if 0 + /* FIXME: call some panic handler instead of + * deiniting directly + */ + deinit_video_mode (); +#endif + report ("Error: bad signature %04x\n", sig); + /* fprintf (stderr, "ACK! BAD RESOURCE!!!\n"); */ + return 0; + } + fclose (fp); + } else { + /* we have a bad volume resource */ + /* set that resource to NA */ + agid->offset = _EMPTY; + } + + return data; +} + + +/* + * Loads a resource into memory, a raw resource is loaded in + * with above routine, then further decoded here. + */ +int agi_v2_load_resource (int t, int n) +{ + int ec = err_OK; + UINT8 *data = NULL; + + _D (_D_WARN "(t = %d, n = %d)", t, n); + if (n > MAX_DIRS) + return err_BadResource; + + switch (t) { + case rLOGIC: + if (~game.dir_logic[n].flags & RES_LOADED) { + _D (_D_WARN "loading logic resource %d", n); + agi_v2.unload_resource (rLOGIC, n); + + /* load raw resource into data */ + data = agi_v2_load_vol_res (&game.dir_logic[n]); + + game.logics[n].data = data; + ec = data ? decode_logic (n) : err_BadResource; + + game.logics[n].sIP = 2; + } + + /* if logic was cached, we get here */ + /* reset code pointers incase it was cached */ + + game.logics[n].cIP = game.logics[n].sIP; + break; + case rPICTURE: + /* if picture is currently NOT loaded *OR* cacheing is off, + * unload the resource (caching == off) and reload it + */ + + _D (_D_WARN "loading picture resource %d", n); + if (game.dir_pic[n].flags & RES_LOADED) + break; + + /* if loaded but not cached, unload it */ + /* if cached but not loaded, etc */ + agi_v2.unload_resource (rPICTURE, n); + data = agi_v2_load_vol_res (&game.dir_pic[n]); + + if (data != NULL) { + game.pictures[n].rdata = data; + game.dir_pic[n].flags |= RES_LOADED; + } else { + ec = err_BadResource; + } + break; + case rSOUND: + _D (_D_WARN "loading sound resource %d", n); + if (game.dir_sound[n].flags & RES_LOADED) + break; + + data = agi_v2_load_vol_res (&game.dir_sound[n]); + + if (data != NULL) { + game.sounds[n].rdata = data; + game.dir_sound[n].flags |= RES_LOADED; + decode_sound (n); + } else { + ec = err_BadResource; + } + break; + case rVIEW: + /* Load a VIEW resource into memory... + * Since VIEWS alter the view table ALL the time + * can we cache the view? or must we reload it all + * the time? + */ + if (game.dir_view[n].flags & RES_LOADED) + break; + + _D (_D_WARN "loading view resource %d", n); + agi_v2.unload_resource (rVIEW, n); + data = agi_v2_load_vol_res (&game.dir_view[n]); + if (data) { + game.views[n].rdata = data; + game.dir_view[n].flags |= RES_LOADED; + ec = decode_view (n); + } else { + ec=err_BadResource; + } + break; + default: + ec = err_BadResource; + break; + } + + return ec; +} + +static int agi_v2_load_objects(char *fname) +{ + return load_objects(fname); +} + +static int agi_v2_load_words(char *fname) +{ + return load_words(fname); +} + +#endif /* PALMOS */ diff --git a/agi_v3.c b/agi_v3.c index 3d23684..c7e2c36 100644 --- a/agi_v3.c +++ b/agi_v3.c @@ -1,389 +1,389 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: agi_v3.c,v 1.40 2003/08/26 00:53:16 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#if !defined(PALMOS) && !defined(FAKE_PALMOS) - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "lzw.h" - -static int agi_v3_init (void); -static int agi_v3_deinit (void); -static int agi_v3_detect_game (char *); -static int agi_v3_load_resource (int, int); -static int agi_v3_unload_resource (int, int); -static int agi_v3_load_objects(char *); -static int agi_v3_load_words(char *); - -struct agi_loader agi_v3 = { - 3, - 0, - agi_v3_init, - agi_v3_deinit, - agi_v3_detect_game, - agi_v3_load_resource, - agi_v3_unload_resource, - agi_v3_load_objects, - agi_v3_load_words -}; - - -int agi_v3_detect_game (char *gn) -{ - int ec = err_Unk; - char x[MAX_PATH], *xname, *path; - int l; - - _D ("(\"%s\")", gn); - strncpy (game.dir, gn, MAX_PATH); - - strcpy (x, "*vol.0"); - path = fixpath (GAMEDIR, x); - - _D (_D_WARN "path = %s", path); - if (file_isthere (path)) { - _D(_D_WARN "getting xname for path = %s", path); - xname = file_name (path); - /* remove the DIR from xname */ - l = strlen (xname); - if (l >= 5) - l -= 5; - xname[l] = 0; - strncpy (game.name, xname, 8); - _D (_D_WARN "game.name = %s", game.name); - - agi_v3.int_version = 0x3149; /* setup for 3.002.149 */ - ec = v3id_game(); - } else { - _D (_D_CRIT "not found"); - ec = err_InvalidAGIFile; - } - - return ec; -} - - -static int agi_v3_load_dir (struct agi_dir *agid, FILE *fp, UINT32 offs, UINT32 len) -{ - int ec = err_OK; - UINT8 *mem; - unsigned int i; - - fseek (fp, offs, SEEK_SET); - if ((mem = malloc (len + 32)) != NULL) { - fread(mem, 1, len, fp); - - /* set all directory resources to gone */ - for (i = 0; i < MAX_DIRS; i++) { - agid[i].volume = 0xff; - agid[i].offset = _EMPTY; - } - - /* build directory entries */ - for (i = 0; i < len; i += 3) { - agid[i / 3].volume = hilo_getbyte (mem + i) >> 4; - agid[i / 3].offset = - hilo_getpword (mem + i) & (UINT32)_EMPTY; - } - - free(mem); - } else { - ec = err_NotEnoughMemory; - } - - return ec; -} - - -struct agi3vol { - UINT32 sddr; - UINT32 len; -}; - -int agi_v3_init (void) -{ - int ec = err_OK; - struct agi3vol agi_vol3[4]; - int i; - UINT16 xd[4]; - FILE *fp; - char *path; - - path = fixpath (GAMEDIR, DIR_); - - if ((fp = fopen(path, "rb")) == NULL) { - printf ("Failed to open \"%s\"\n", path); - return err_BadFileOpen; - } - /* build offset table for v3 directory format */ - fread (&xd, 1, 8, fp); - fseek (fp, 0, SEEK_END); - - for(i = 0; i < 4; i++) - agi_vol3[i].sddr = lohi_getword((UINT8 *)&xd[i]); - - agi_vol3[0].len = agi_vol3[1].sddr - agi_vol3[0].sddr; - agi_vol3[1].len = agi_vol3[2].sddr - agi_vol3[1].sddr; - agi_vol3[2].len = agi_vol3[3].sddr - agi_vol3[2].sddr; - agi_vol3[3].len = ftell(fp) - agi_vol3[3].sddr; - - if (agi_vol3[3].len > 256 * 3) - agi_vol3[3].len = 256 * 3; - - fseek(fp, 0, SEEK_SET); - - /* read in directory files */ - ec = agi_v3_load_dir (game.dir_logic, fp, agi_vol3[0].sddr, - agi_vol3[0].len); - - if(ec == err_OK) { - ec = agi_v3_load_dir (game.dir_pic, fp, agi_vol3[1].sddr, - agi_vol3[1].len); - } - - if(ec == err_OK) { - ec = agi_v3_load_dir (game.dir_view, fp, agi_vol3[2].sddr, - agi_vol3[2].len); - } - - if(ec == err_OK) { - ec = agi_v3_load_dir (game.dir_sound, fp, agi_vol3[3].sddr, - agi_vol3[3].len); - } - - return ec; -} - - -int agi_v3_deinit () -{ - int ec=err_OK; - -#if 0 - /* unload words */ - agi_v3_unload_words(); - - /* unload objects */ - agi_v3_unload_objects(); -#endif - - return ec; -} - - -int agi_v3_unload_resource (int t, int n) -{ - switch (t) { - case rLOGIC: - unload_logic(n); - break; - case rPICTURE: - unload_picture(n); - break; - case rVIEW: - unload_view(n); - break; - case rSOUND: - unload_sound(n); - break; - } - - return err_OK; -} - - -/* - * This function does noting but load a raw resource into memory. - * If further decoding is required, it must be done by another - * routine. - * - * NULL is returned if unsucsessful. - */ - -UINT8* agi_v3_load_vol_res (struct agi_dir *agid) -{ - char x[MAX_PATH], *path; - UINT8 *data = NULL, *comp_buffer; - FILE *fp; - - _D ("(%p)", agid); - sprintf (x, "vol.%i", agid->volume); - path = fixpath (GAMEDIR, x); - - if (agid->offset != _EMPTY && (fp = fopen((char*)path, "rb")) != NULL) { - fseek (fp, agid->offset, SEEK_SET); - fread (&x, 1, 7, fp); - - if (hilo_getword((UINT8 *)x) != 0x1234) { -#if 0 - /* FIXME */ - deinit_video_mode(); -#endif - _D (_D_CRIT "path = %s", path); - _D (_D_CRIT "offset = %d", agid->offset); - _D (_D_CRIT "x = %x %x", x[0], x[1]); - printf ("ACK! BAD RESOURCE!!!\n"); - exit(0); - } - - agid->len = lohi_getword((UINT8 *)x + 3);/* uncompressed size */ - agid->clen = lohi_getword((UINT8 *)x + 5);/* compressed len */ - - comp_buffer = calloc (1, agid->clen + 32); - fread (comp_buffer, 1, agid->clen, fp); - - if (x[2] & 0x80 || agid->len == agid->clen) { - /* do not decompress */ - data = comp_buffer; - -#if 0 - /* CM: added to avoid problems in - * convert_v2_v3_pic() when clen > len - * e.g. Sierra demo 4, first picture - * (Tue Mar 16 13:13:43 EST 1999) - */ - agid->len = agid->clen; - - /* Now removed to fix Gold Rush! in demo4 */ -#endif - } else { - /* it is compressed */ - data = calloc (1, agid->len + 32); - LZW_expand (comp_buffer, data, agid->len); - free (comp_buffer); - agid->flags |= RES_COMPRESSED; - } - - fclose(fp); - } else { - /* we have a bad volume resource */ - /* set that resource to NA */ - agid->offset = _EMPTY; - } - - return data; -} - - -/* - * Loads a resource into memory, a raw resource is loaded in - * with above routine, then further decoded here. - */ - -int agi_v3_load_resource (int t, int n) -{ - int ec = err_OK; - UINT8 *data = NULL; - - if (n > MAX_DIRS) - return err_BadResource; - - switch (t) { - case rLOGIC: - /* load resource into memory, decrypt messages at the end - * and build the message list (if logic is in memory) - */ - if (~game.dir_logic[n].flags & RES_LOADED) { - /* if logic is already in memory, unload it */ - agi_v3.unload_resource (rLOGIC, n); - - /* load raw resource into data */ - data = agi_v3_load_vol_res (&game.dir_logic[n]); - game.logics[n].data=data; - - /* uncompressed logic files need to be decrypted */ - if (data != NULL) { - /* resloaded flag gets set by decode logic */ - /* needed to build string table */ - ec = decode_logic(n); - game.logics[n].sIP=2; - } else { - ec=err_BadResource; - } - - /*logics[n].sIP=2;*/ /* saved IP = 2 */ - /*logics[n].cIP=2;*/ /* current IP = 2 */ - - game.logics[n].cIP = game.logics[n].sIP; - } - - /* if logic was cached, we get here */ - /* reset code pointers incase it was cached */ - - game.logics[n].cIP = game.logics[n].sIP; - break; - case rPICTURE: - /* if picture is currently NOT loaded *OR* cacheing is off, - * unload the resource (caching==off) and reload it - */ - if (~game.dir_pic[n].flags & RES_LOADED) { - agi_v3.unload_resource (rPICTURE, n); - data = agi_v3_load_vol_res (&game.dir_pic[n]); - if (data != NULL) { - data = convert_v3_pic (data, - game.dir_pic[n].len); - game.pictures[n].rdata = data; - game.dir_pic[n].flags |= RES_LOADED; - } else { - ec=err_BadResource; - } - } - break; - case rSOUND: - if (game.dir_sound[n].flags & RES_LOADED) - break; - - if ((data = agi_v3_load_vol_res (&game.dir_sound[n])) != NULL) { - game.sounds[n].rdata = data; - game.dir_sound[n].flags |= RES_LOADED; - decode_sound (n); - } else { - ec = err_BadResource; - } - break; - case rVIEW: - /* Load a VIEW resource into memory... - * Since VIEWS alter the view table ALL the time can we - * cache the view? or must we reload it all the time? - */ - /* load a raw view from a VOL file into data */ - if (game.dir_view[n].flags & RES_LOADED) - break; - - agi_v3.unload_resource (rVIEW, n); - if ((data = agi_v3_load_vol_res (&game.dir_view[n])) != NULL) { - game.views[n].rdata = data; - game.dir_view[n].flags |= RES_LOADED; - ec = decode_view(n); - } else { - ec = err_BadResource; - } - break; - default: - ec = err_BadResource; - break; - } - - return ec; -} - -static int agi_v3_load_objects(char *fname) -{ - return load_objects(fname); -} - -static int agi_v3_load_words(char *fname) -{ - return load_words(fname); -} - -#endif /* !PALMOS && !FAKE_PALMOS */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: agi_v3.c,v 1.40 2003/08/26 00:53:16 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#if !defined(PALMOS) && !defined(FAKE_PALMOS) + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "lzw.h" + +static int agi_v3_init (void); +static int agi_v3_deinit (void); +static int agi_v3_detect_game (char *); +static int agi_v3_load_resource (int, int); +static int agi_v3_unload_resource (int, int); +static int agi_v3_load_objects(char *); +static int agi_v3_load_words(char *); + +struct agi_loader agi_v3 = { + 3, + 0, + agi_v3_init, + agi_v3_deinit, + agi_v3_detect_game, + agi_v3_load_resource, + agi_v3_unload_resource, + agi_v3_load_objects, + agi_v3_load_words +}; + + +int agi_v3_detect_game (char *gn) +{ + int ec = err_Unk; + char x[MAX_PATH], *xname, *path; + int l; + + _D ("(\"%s\")", gn); + strncpy (game.dir, gn, MAX_PATH); + + strcpy (x, "*vol.0"); + path = fixpath (GAMEDIR, x); + + _D (_D_WARN "path = %s", path); + if (file_isthere (path)) { + _D(_D_WARN "getting xname for path = %s", path); + xname = file_name (path); + /* remove the DIR from xname */ + l = strlen (xname); + if (l >= 5) + l -= 5; + xname[l] = 0; + strncpy (game.name, xname, 8); + _D (_D_WARN "game.name = %s", game.name); + + agi_v3.int_version = 0x3149; /* setup for 3.002.149 */ + ec = v3id_game(); + } else { + _D (_D_CRIT "not found"); + ec = err_InvalidAGIFile; + } + + return ec; +} + + +static int agi_v3_load_dir (struct agi_dir *agid, FILE *fp, UINT32 offs, UINT32 len) +{ + int ec = err_OK; + UINT8 *mem; + unsigned int i; + + fseek (fp, offs, SEEK_SET); + if ((mem = malloc (len + 32)) != NULL) { + fread(mem, 1, len, fp); + + /* set all directory resources to gone */ + for (i = 0; i < MAX_DIRS; i++) { + agid[i].volume = 0xff; + agid[i].offset = _EMPTY; + } + + /* build directory entries */ + for (i = 0; i < len; i += 3) { + agid[i / 3].volume = hilo_getbyte (mem + i) >> 4; + agid[i / 3].offset = + hilo_getpword (mem + i) & (UINT32)_EMPTY; + } + + free(mem); + } else { + ec = err_NotEnoughMemory; + } + + return ec; +} + + +struct agi3vol { + UINT32 sddr; + UINT32 len; +}; + +int agi_v3_init (void) +{ + int ec = err_OK; + struct agi3vol agi_vol3[4]; + int i; + UINT16 xd[4]; + FILE *fp; + char *path; + + path = fixpath (GAMEDIR, DIR_); + + if ((fp = fopen(path, "rb")) == NULL) { + printf ("Failed to open \"%s\"\n", path); + return err_BadFileOpen; + } + /* build offset table for v3 directory format */ + fread (&xd, 1, 8, fp); + fseek (fp, 0, SEEK_END); + + for(i = 0; i < 4; i++) + agi_vol3[i].sddr = lohi_getword((UINT8 *)&xd[i]); + + agi_vol3[0].len = agi_vol3[1].sddr - agi_vol3[0].sddr; + agi_vol3[1].len = agi_vol3[2].sddr - agi_vol3[1].sddr; + agi_vol3[2].len = agi_vol3[3].sddr - agi_vol3[2].sddr; + agi_vol3[3].len = ftell(fp) - agi_vol3[3].sddr; + + if (agi_vol3[3].len > 256 * 3) + agi_vol3[3].len = 256 * 3; + + fseek(fp, 0, SEEK_SET); + + /* read in directory files */ + ec = agi_v3_load_dir (game.dir_logic, fp, agi_vol3[0].sddr, + agi_vol3[0].len); + + if(ec == err_OK) { + ec = agi_v3_load_dir (game.dir_pic, fp, agi_vol3[1].sddr, + agi_vol3[1].len); + } + + if(ec == err_OK) { + ec = agi_v3_load_dir (game.dir_view, fp, agi_vol3[2].sddr, + agi_vol3[2].len); + } + + if(ec == err_OK) { + ec = agi_v3_load_dir (game.dir_sound, fp, agi_vol3[3].sddr, + agi_vol3[3].len); + } + + return ec; +} + + +int agi_v3_deinit () +{ + int ec=err_OK; + +#if 0 + /* unload words */ + agi_v3_unload_words(); + + /* unload objects */ + agi_v3_unload_objects(); +#endif + + return ec; +} + + +int agi_v3_unload_resource (int t, int n) +{ + switch (t) { + case rLOGIC: + unload_logic(n); + break; + case rPICTURE: + unload_picture(n); + break; + case rVIEW: + unload_view(n); + break; + case rSOUND: + unload_sound(n); + break; + } + + return err_OK; +} + + +/* + * This function does noting but load a raw resource into memory. + * If further decoding is required, it must be done by another + * routine. + * + * NULL is returned if unsucsessful. + */ + +UINT8* agi_v3_load_vol_res (struct agi_dir *agid) +{ + char x[MAX_PATH], *path; + UINT8 *data = NULL, *comp_buffer; + FILE *fp; + + _D ("(%p)", agid); + sprintf (x, "vol.%i", agid->volume); + path = fixpath (GAMEDIR, x); + + if (agid->offset != _EMPTY && (fp = fopen((char*)path, "rb")) != NULL) { + fseek (fp, agid->offset, SEEK_SET); + fread (&x, 1, 7, fp); + + if (hilo_getword((UINT8 *)x) != 0x1234) { +#if 0 + /* FIXME */ + deinit_video_mode(); +#endif + _D (_D_CRIT "path = %s", path); + _D (_D_CRIT "offset = %d", agid->offset); + _D (_D_CRIT "x = %x %x", x[0], x[1]); + printf ("ACK! BAD RESOURCE!!!\n"); + exit(0); + } + + agid->len = lohi_getword((UINT8 *)x + 3);/* uncompressed size */ + agid->clen = lohi_getword((UINT8 *)x + 5);/* compressed len */ + + comp_buffer = calloc (1, agid->clen + 32); + fread (comp_buffer, 1, agid->clen, fp); + + if (x[2] & 0x80 || agid->len == agid->clen) { + /* do not decompress */ + data = comp_buffer; + +#if 0 + /* CM: added to avoid problems in + * convert_v2_v3_pic() when clen > len + * e.g. Sierra demo 4, first picture + * (Tue Mar 16 13:13:43 EST 1999) + */ + agid->len = agid->clen; + + /* Now removed to fix Gold Rush! in demo4 */ +#endif + } else { + /* it is compressed */ + data = calloc (1, agid->len + 32); + LZW_expand (comp_buffer, data, agid->len); + free (comp_buffer); + agid->flags |= RES_COMPRESSED; + } + + fclose(fp); + } else { + /* we have a bad volume resource */ + /* set that resource to NA */ + agid->offset = _EMPTY; + } + + return data; +} + + +/* + * Loads a resource into memory, a raw resource is loaded in + * with above routine, then further decoded here. + */ + +int agi_v3_load_resource (int t, int n) +{ + int ec = err_OK; + UINT8 *data = NULL; + + if (n > MAX_DIRS) + return err_BadResource; + + switch (t) { + case rLOGIC: + /* load resource into memory, decrypt messages at the end + * and build the message list (if logic is in memory) + */ + if (~game.dir_logic[n].flags & RES_LOADED) { + /* if logic is already in memory, unload it */ + agi_v3.unload_resource (rLOGIC, n); + + /* load raw resource into data */ + data = agi_v3_load_vol_res (&game.dir_logic[n]); + game.logics[n].data=data; + + /* uncompressed logic files need to be decrypted */ + if (data != NULL) { + /* resloaded flag gets set by decode logic */ + /* needed to build string table */ + ec = decode_logic(n); + game.logics[n].sIP=2; + } else { + ec=err_BadResource; + } + + /*logics[n].sIP=2;*/ /* saved IP = 2 */ + /*logics[n].cIP=2;*/ /* current IP = 2 */ + + game.logics[n].cIP = game.logics[n].sIP; + } + + /* if logic was cached, we get here */ + /* reset code pointers incase it was cached */ + + game.logics[n].cIP = game.logics[n].sIP; + break; + case rPICTURE: + /* if picture is currently NOT loaded *OR* cacheing is off, + * unload the resource (caching==off) and reload it + */ + if (~game.dir_pic[n].flags & RES_LOADED) { + agi_v3.unload_resource (rPICTURE, n); + data = agi_v3_load_vol_res (&game.dir_pic[n]); + if (data != NULL) { + data = convert_v3_pic (data, + game.dir_pic[n].len); + game.pictures[n].rdata = data; + game.dir_pic[n].flags |= RES_LOADED; + } else { + ec=err_BadResource; + } + } + break; + case rSOUND: + if (game.dir_sound[n].flags & RES_LOADED) + break; + + if ((data = agi_v3_load_vol_res (&game.dir_sound[n])) != NULL) { + game.sounds[n].rdata = data; + game.dir_sound[n].flags |= RES_LOADED; + decode_sound (n); + } else { + ec = err_BadResource; + } + break; + case rVIEW: + /* Load a VIEW resource into memory... + * Since VIEWS alter the view table ALL the time can we + * cache the view? or must we reload it all the time? + */ + /* load a raw view from a VOL file into data */ + if (game.dir_view[n].flags & RES_LOADED) + break; + + agi_v3.unload_resource (rVIEW, n); + if ((data = agi_v3_load_vol_res (&game.dir_view[n])) != NULL) { + game.views[n].rdata = data; + game.dir_view[n].flags |= RES_LOADED; + ec = decode_view(n); + } else { + ec = err_BadResource; + } + break; + default: + ec = err_BadResource; + break; + } + + return ec; +} + +static int agi_v3_load_objects(char *fname) +{ + return load_objects(fname); +} + +static int agi_v3_load_words(char *fname) +{ + return load_words(fname); +} + +#endif /* !PALMOS && !FAKE_PALMOS */ diff --git a/agi_v4.c b/agi_v4.c index c5cb671..bf88919 100644 --- a/agi_v4.c +++ b/agi_v4.c @@ -1,828 +1,828 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: agi_v4.c,v 1.8 2001/09/06 18:52:14 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" - -#if defined PALMOS - -static int agi_v4_init (void); -static int agi_v4_deinit (void); -static int agi_v4_detect_game (char *); -static int agi_v4_load_resource (int, int); -static int agi_v4_unload_resource (int, int); -static int agi_v4_load_objects(char *); -static int agi_v4_load_words(char *); - -UINT32 pdb_read_dword(UINT8 *mem); -UINT16 pdb_read_word(UINT8 *mem); -int load_v2_dir(struct agi_dir *agid, int offset, UINT32 flen, FILE *fp); -int load_v3_dir(struct agi_dir *agid, int offs, UINT32 len, FILE *fp); - -extern struct agi_picture pictures[]; -extern struct agi_logic logics[]; -extern struct agi_view views[]; -extern struct agi_sound sounds[]; - -struct agi_loader agi_v4 = { - 4, - 0, - agi_v4_init, - agi_v4_deinit, - agi_v4_detect_game, - agi_v4_load_resource, - agi_v4_unload_resource, - agi_v4_load_objects, - agi_v4_load_words -}; - - -/* this must be kept synchronous with the AGI2PDB headers */ -#define PDB_OPT_AGDS 0x0001 -#define PDB_OPT_AMIGA 0x0002 - -#ifdef __WATCOMC__ -#pragma pack(1) -#endif - -struct pdb_pdbheader -{ - UINT8 name[32]; - /* - String - This is the name of the database - on the PalmPilot device. - It need not match the name of the PDB file - in the environment in which it is created. - */ - UINT16 fileAttributes; - /* - Attributes of the pdb file. - 0x0002 Read-Only - 0x0004 Dirty AppInfoArea - 0x0008 Backup this database - (i.e. no conduit exists) - 0x0010 Okay to install newer over existing - copy, if present on PalmPilot - 0x0020 Force the PalmPilot to reset after - this database is installed - */ - UINT16 version; - /* - Defined by the application. - */ - UINT32 creationDate; - /* - Expressed as the number of seconds since - January 1, 1904. The database will not - install if this value is zero. (PalmOS - 1.0.6) - */ - UINT32 modificationDate; - /* - Expressed as the number of seconds since - January 1, 1904. - The database will not install if this - value is zero. (PalmOS 1.0.6) - */ - UINT32 lastBackupDate; - /* - Expressed as the number of seconds since - January 1, 1904. This can be left at zero - and the database will install. - */ - UINT32 modificationNumber; - /* - Set to zero. - */ - UINT32 appInfoArea; - /* - The byte number in the PDB file (counting - from zero) at which the AppInfoArea is - located. This must be the first entry - in the Data portion of the PDB file. - If this database does not have an - AppInfoArea, set this value to zero. - */ - UINT32 sortInfoArea; - /* - The byte number in the PDB file (counting - from zero) at which the SortInfoArea is - located. This must be placed immediately - after the AppInfoArea, if one exists, - within the Data portion of the PDB file. - If this database does not have a - SortInfoArea, set this value to zero. - Do not use this. See Note C below for - further details. - */ - UINT8 databaseType[4]; - /* - String - Set this to the desired value. - Generally it should match the Database Type - used by the corresponding application. - This is 4 characters long and does not have - a terminating null. - */ - UINT8 creatorID[4]; - /* - String - Set this to the desired value. - Generally it should match the Creator ID - used by the corresponding application. In - all cases, you should always register your - Creator ID before using it. This is 4 - characters long and does not have a - terminating null. - */ - UINT32 uniqueIDSeed; - /* - This is used to generate the Unique ID - number of subsequent records. Generally, - this should be set to zero. - */ - UINT32 nextRecordListID; - /* - Set this to zero. (This does not appear - to be used, but that has not been - verified by a third party.) - */ - UINT16 numberOfRecords; - /* - This contains the number of records - */ -} -#ifdef __GNUC__ -__attribute__((packed)) -#endif -; - -struct pdb_recheader{ - UINT32 recordDataOffset; - /* - The byte number in the PDB file (counting - from zero) at which the record is located. - */ - UINT8 recordAttributes; - /* - The records attributes. - 0x10 Secret record bit. - 0x20 Record in use (busy bit). - 0x40 Dirty record bit. - 0x80 Delete record on next HotSync. - The least significant four bits are used - to represent the category values. - */ - UINT8 uniqueID[3]; - /* - Set this to zero and do not try to - second-guess what PalmOS will do with - this value. - */ -} -#ifdef __GNUC__ -__attribute__((packed)) -#endif -; - -struct agi3vol { - UINT32 sddr; - UINT32 len; -}; - -/* a agi v2.xxx game format */ -struct PalmOSAGI2 -{ - UINT32 logdir[2]; - UINT32 picdir[2]; - UINT32 viewdir[2]; - UINT32 snddir[2]; - - UINT32 object[2]; - UINT32 words[2]; - - UINT32 vol[16*2]; /* 0=offs, 1=len */ -}; - -/* an agi v3.xx.yyy game format */ -struct PalmOSAGI3 -{ - UINT32 dir[2]; - UINT32 object[2]; - UINT32 words[2]; - UINT32 vol[16*2]; /* 0=offs, 1=len */ -}; - -union PalmOSAGI4 -{ - struct PalmOSAGI2 v2; - struct PalmOSAGI3 v3; -}; - -/* PalmOS AGI Header */ -struct PalmOSAGI -{ - char name[32]; - UINT16 version; - UINT16 emulation; - UINT32 options; - UINT32 crc; - - union PalmOSAGI4 v4; -}; - -#ifdef __WATCOMC__ -#pragma pack() -#endif - -struct PalmOSAGI palmagi; -struct pdb_pdbheader PDBHeader; - -/* our PDB file that contains everything */ -char pdb_file[MAX_PATH]; -UINT32 pdb_start; - -static int agi_v4_detect_game (char *gn) -{ - FILE *fp; - int ec= err_InvalidAGIFile; - int offset; - struct pdb_recheader rh; - - /* gn is filename for a .pdb! */ - - memset(&PDBHeader, 0x0, sizeof(struct pdb_pdbheader)); - memset(&palmagi, 0x0, sizeof(struct PalmOSAGI)); - strcpy(pdb_file, gn); - - fp = fopen (pdb_file, "rb"); - if(fp!=NULL) - { - fread(&PDBHeader, 1, sizeof(struct pdb_pdbheader), fp); - - if(PDBHeader.creatorID[0]=='F' && PDBHeader.creatorID[1]=='A' && - PDBHeader.creatorID[2]=='G' && PDBHeader.creatorID[3]=='I') - { - /* valid palm database with Sarien Creator ID */ - /* now skip record headers, read in v4 Header */ - - fread(&rh, 1, sizeof(struct pdb_recheader), fp); - - offset=(int)pdb_read_dword((UINT8*)&rh.recordDataOffset); - - /* our data all starts from here. add this to all offsets */ - pdb_start=offset; - - fseek(fp, offset, SEEK_SET); - fread(&palmagi, 1, sizeof(struct PalmOSAGI), fp); - - palmagi.crc=pdb_read_dword((UINT8*)&palmagi.crc); - palmagi.options=pdb_read_word((UINT8*)&palmagi.options); - palmagi.emulation=pdb_read_word((UINT8*)&palmagi.version); - palmagi.version=pdb_read_word((UINT8*)&palmagi.version); - - /* setup our options before we call setup game! */ - if((palmagi.options&PDB_OPT_AGDS)) - opt.agds=1; - - if((palmagi.options&PDB_OPT_AMIGA)) - opt.amiga=1; - - v4id_game(palmagi.crc); - - /* if the game is a v2 */ - - /* use agi_get_release instead of palmagi.emulation */ - if((agi_get_release()>>12)==0x2) - agi_v4.int_version = 0x2917; /* setup for 2.917 */ - else - agi_v4.int_version = 0x3149; /* setup for 3.002.149 */ - - ec=err_OK; - } - - fclose(fp); - } - - return ec; -} - - -static int agi_v4_load_dir (struct agi_dir *agid, int intDirType) -{ - int ec=err_OK; - -#ifndef PALMOS - FILE *fp; - struct agi3vol agi_vol3[4]; - UINT32 offs, flen; - UINT16 xd[4]; - int i; - - if ((fp = fopen (pdb_file, "rb")) == NULL) { - return err_BadFileOpen; - } - - if((palmagi.emulation>>12)==2) - { - /* load singledir v2 style */ - switch(intDirType) - { - case rLOGIC: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.logdir[0], palmagi.v4.v2.logdir[1], fp); break; - case rPICTURE: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.picdir[0], palmagi.v4.v2.picdir[1], fp); break; - case rSOUND: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.snddir[0], palmagi.v4.v2.snddir[1], fp); break; - case rVIEW: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.viewdir[0], palmagi.v4.v2.viewdir[1], fp); break; - } - } - else - { - /* load v3 gamedir style */ - offs=pdb_start + palmagi.v4.v3.dir[0]; - flen=palmagi.v4.v3.dir[1]; - - fseek(fp, offs, SEEK_SET); - - /* FIXME: Not Endian Aware */ - fread (&xd, 1, 8, fp); - - for(i = 0; i < 4; i++) - agi_vol3[i].sddr = offs + xd[i]; - - agi_vol3[0].len = agi_vol3[1].sddr - agi_vol3[0].sddr; - agi_vol3[1].len = agi_vol3[2].sddr - agi_vol3[1].sddr; - agi_vol3[2].len = agi_vol3[3].sddr - agi_vol3[2].sddr; - agi_vol3[3].len = ftell(fp) - agi_vol3[3].sddr; - - if (agi_vol3[3].len > 256 * 3) - agi_vol3[3].len = 256 * 3; - - /* read in all directory file info */ - ec=load_v3_dir(game.dir_logic, agi_vol3[0].sddr, agi_vol3[0].len, fp); - if(ec==err_OK) - ec=load_v3_dir(game.dir_pic, agi_vol3[1].sddr, agi_vol3[1].len, fp); - if(ec==err_OK) - ec=load_v3_dir(game.dir_view, agi_vol3[2].sddr, agi_vol3[2].len, fp); - if(ec==err_OK) - ec=load_v3_dir(game.dir_sound, agi_vol3[3].sddr, agi_vol3[3].len, fp); - } - - fclose(fp); -#endif - - return ec; -} - -int load_v2_dir(struct agi_dir *agid, int offset, UINT32 flen, FILE *fp) -{ - UINT8 *mem; - int i; - - if ((mem = malloc (flen + 32)) == NULL) { - fclose (fp); - return err_NotEnoughMemory; - } - - fseek (fp, offset, SEEK_SET); - fread (mem, 1, flen, fp); - - /* set all directory resources to gone */ - for (i = 0; i < MAX_DIRS; i++) { - agid[i].volume = 0xff; - agid[i].offset = _EMPTY; - } - - /* build directory entries */ - for (i = 0; i < flen; i+=3) { - agid[i/3].volume = hilo_getbyte (mem+i) >> 4; - agid[i/3].offset = hilo_getpword (mem+i) & _EMPTY; - } - - free (mem); - - return err_OK; -} - -int load_v3_dir(struct agi_dir *agid, int offs, UINT32 len, FILE *fp) -{ - int ec = err_OK; - UINT8 *mem; - int i; - - fseek (fp, offs, SEEK_SET); - if ((mem = malloc (len + 32)) != NULL) { - fread(mem, 1, len, fp); - - /* set all directory resources to gone */ - for(i = 0; i < MAX_DIRS; i++) { - agid[i].volume = 0xFF; - agid[i].offset = _EMPTY; - } - - /* build directory entries */ - for(i = 0; i < len; i += 3) { - agid[i / 3].volume = hilo_getbyte (mem + i) >> 4; - agid[i / 3].offset = hilo_getpword (mem+i) & _EMPTY; - } - - free(mem); - } else { - ec = err_NotEnoughMemory; - } - - return ec; -} - - -static int agi_v4_init () -{ - int ec = err_OK; - - /* load directory files */ - switch((palmagi.emulation>>12)) - { - case 2: - ec = agi_v4_load_dir (game.dir_logic, rLOGIC); - if (ec == err_OK) - ec = agi_v4_load_dir (game.dir_pic, rPICTURE); - if (ec == err_OK) - ec = agi_v4_load_dir (game.dir_view, rVIEW); - if (ec == err_OK) - ec = agi_v4_load_dir (game.dir_sound, rSOUND); - break; - case 3: - /* a v3 game load will load all DIR files, - so below is just dummy code */ - ec=agi_v4_load_dir(game.dir_logic, rLOGIC); - break; - } - - return ec; -} - - -static int agi_v4_deinit () -{ - int ec = err_OK; - return ec; -} - - - -static int agi_v4_unload_resource (int restype, int resnum) -{ - switch (restype) { - case rLOGIC: - unload_logic (resnum); - break; - case rPICTURE: - unload_picture (resnum); - break; - case rVIEW: - unload_view (resnum); - break; - case rSOUND: - unload_sound (resnum); - break; - } - - return err_OK; -} - - -/* - * This function does noting but load a raw resource into memory, - * if further decoding is required, it must be done by another - * routine. NULL is returned if unsucsessfull. - */ - -UINT8* agi_v4v2_load_vol_res (struct agi_dir *agid) -{ -#ifndef PALMOS - UINT8 *data = NULL; - FILE *fp; - UINT32 offs; - char x[16]; - - /* fill offs with volume offset*/ - - offs = pdb_start + palmagi.v4.v2.vol[(2*agid->volume)]; - - /* loading a bad resource */ - if(offs==pdb_start) - agid->offset=_EMPTY; - - _D ("(agi_dir = [offset:%ld, len:%ld])", agid->offset, agid->len); - - if (agid->offset != _EMPTY && (fp = fopen (pdb_file, "rb")) != NULL) { - _D ("loading resource"); - fseek (fp, offs + agid->offset, SEEK_SET); - fread (&x, 1, 5, fp); - if (hilo_getword (x) == 0x1234) { - agid->len = lohi_getword (x + 3); - data = calloc (1, agid->len + 32); - if (data != NULL) - fread (data, 1, agid->len, fp); - } else { - /* FIXME: call some panic handler instead of - * deiniting directly - */ - deinit_video_mode (); - fprintf (stderr, "ACK! BAD RESOURCE!!!\n"); - exit (0); - } - fclose (fp); - } else { - /* we have a bad volume resource */ - /* set that resource to NA */ - agid->offset = _EMPTY; - } - - return data; -#endif -} - -UINT8* agi_v4v3_load_vol_res (struct agi_dir *agid) -{ -#ifndef PALMOS - UINT8 x[MAX_PATH], *data = NULL, *comp_buffer; - FILE *fp; - UINT32 offs; - - _D ("(%p)", agid); - - offs = pdb_start + palmagi.v4.v3.vol[2*agid->volume]; - /* loading a bad resource */ - if(offs==pdb_start) - agid->offset=_EMPTY; - - if (agid->offset != _EMPTY && (fp = fopen(pdb_file, "rb")) != NULL) { - fseek (fp, offs + agid->offset, SEEK_SET); - fread (&x, 1, 7, fp); - - if (hilo_getword(x) != 0x1234) { - /* FIXME */ - deinit_video_mode(); - printf("ACK! BAD RESOURCE!!!\n"); - exit(0); - } - - agid->len = lohi_getword (x + 3); /* uncompressed size */ - agid->clen = lohi_getword (x + 5); /* compressed len */ - - comp_buffer = calloc (1, agid->clen + 32); - fread (comp_buffer, 1, agid->clen, fp); - - if (x[2] & 0x80 || agid->len == agid->clen) { - /* do not decompress */ - data = comp_buffer; - } else { - /* it is compressed */ - data = calloc (1, agid->len + 32); - LZW_expand (comp_buffer, data, agid->len); - free (comp_buffer); - agid->flags |= RES_COMPRESSED; - } - - fclose(fp); - } else { - /* we have a bad volume resource */ - /* set that resource to NA */ - agid->offset = _EMPTY; - } - - return data; -#endif -} - - - -/* - * Loads a resource into memory, a raw resource is loaded in - * with above routine, then further decoded here. - */ -int agi_v4_load_resource (int restype, int resnum) -{ - int ec = err_OK; - UINT8 *data = NULL; - - - _D (_D_WARN "(restype = %d, resnum = %d)", restype, resnum); - if (resnum > MAX_DIRS) - return err_BadResource; - - switch (restype) { - case rLOGIC: - if (~game.dir_logic[resnum].flags & RES_LOADED) { - _D (_D_WARN "loading logic resource %d", resnum); - agi_v4.unload_resource (rLOGIC, resnum); - /* load raw resource into data */ - if((palmagi.emulation>>12)==2) - data = agi_v4v2_load_vol_res (&game.dir_logic[resnum]); - else - data = agi_v4v3_load_vol_res(&game.dir_logic[resnum]); - - ec = (logics[resnum].data = data) ? - decode_logic (resnum) : err_BadResource; - - logics[resnum].sIP = 2; - } - - logics[resnum].cIP = logics[resnum].sIP; - break; - case rPICTURE: - /* if picture is currently NOT loaded *OR* cacheing is off, - * unload the resource (caching == off) and reload it - */ - - _D (_D_WARN "loading picture resource %d", resnum); - if (game.dir_pic[resnum].flags & RES_LOADED) - break; - - /* if loaded but not cached, unload it */ - /* if cached but not loaded, etc */ - agi_v4.unload_resource (rPICTURE, resnum); - - if((palmagi.emulation>>12)==2) - { - data = agi_v4v2_load_vol_res (&game.dir_pic[resnum]); - if (data != NULL) { - pictures[resnum].rdata = data; - game.dir_pic[resnum].flags |= RES_LOADED; - } else { - ec = err_BadResource; - } - } - else - { - data = agi_v4v3_load_vol_res(&game.dir_pic[resnum]); - if (data != NULL) { - data = convert_v3_pic (data, - game.dir_pic[resnum].len); - pictures[resnum].rdata = data; - game.dir_pic[resnum].flags |= RES_LOADED; - } else { - ec=err_BadResource; - } - } - - break; - case rSOUND: - _D (_D_WARN "loading sound resource %d", resnum); - if (game.dir_sound[resnum].flags & RES_LOADED) - break; - - if((palmagi.emulation>>12)==2) - data = agi_v4v2_load_vol_res (&game.dir_sound[resnum]); - else - data = agi_v4v3_load_vol_res(&game.dir_sound[resnum]); - - if (data != NULL) { - sounds[resnum].rdata = data; - game.dir_sound[resnum].flags |= RES_LOADED; - decode_sound (resnum); - } else { - ec = err_BadResource; - } - break; - case rVIEW: - /* Load a VIEW resource into memory... - * Since VIEWS alter the view table ALL the time - * can we cache the view? or must we reload it all - * the time? - */ - if (game.dir_view[resnum].flags & RES_LOADED) - break; - - _D (_D_WARN "loading view resource %d", resnum); - agi_v4.unload_resource (rVIEW, resnum); - - if((palmagi.emulation>>12)==2) - { - if ((data = agi_v4v2_load_vol_res (&game.dir_view[resnum]))) { - views[resnum].rdata = data; - game.dir_view[resnum].flags |= RES_LOADED; - ec = decode_view (resnum); - } else { - ec=err_BadResource; - } - } - else - { - if ((data = agi_v4v3_load_vol_res (&game.dir_view[resnum]))) { - views[resnum].rdata = data; - game.dir_view[resnum].flags |= RES_LOADED; - ec = decode_view (resnum); - } else { - ec=err_BadResource; - } - } - break; - default: - ec = err_BadResource; - break; - } - - return ec; -} - - -UINT16 pdb_read_word(UINT8 *mem) -{ - UINT16 w; - - w = (UINT16)mem[1]; - w += (UINT16)mem[0]<<8; - - return w; -} - -UINT32 pdb_read_dword(UINT8 *mem) -{ - UINT32 w; - - w = (UINT32)mem[3]; - w += (UINT32)mem[2]<<8; - w += (UINT32)mem[1]<<16; - w += (UINT32)mem[0]<<24; - - return w; -} - -static int agi_v4_load_objects(char *fname) -{ - int ec=err_OK; -#ifndef PALMOS - FILE *fp; - UINT8 *mem; - UINT32 len; - UINT32 offs; - - game.num_objects=0; - fp=fopen(pdb_file, "rb"); - if(fp!=NULL) - { - if((palmagi.emulation>>12)==2) - { - offs=palmagi.v4.v2.object[0]; - len=palmagi.v4.v2.object[1]; - } - else - { - offs=palmagi.v4.v3.object[0]; - len=palmagi.v4.v3.object[1]; - } - - fseek(fp, pdb_start + offs, SEEK_SET); - mem=(UINT8*)malloc(32+len); - fread(mem, 1, len, fp); - ec=decode_objects(mem, len); - - free(mem); - fclose(fp); - } -#endif - return ec; -} - -static int agi_v4_load_words(char *fname) -{ - int ec=err_OK; -#ifndef PALMOS - FILE *fp; - UINT8 *mem; - UINT32 len; - UINT32 offs; - - fp=fopen(pdb_file, "rb"); - if(fp!=NULL) - { - if((palmagi.emulation>>12)==2) - { - offs=palmagi.v4.v2.words[0]; - len=palmagi.v4.v2.words[1]; - } - else - { - offs=palmagi.v4.v3.words[0]; - len=palmagi.v4.v3.words[1]; - } - - fseek(fp, pdb_start + offs, SEEK_SET); - mem=(UINT8*)malloc(32+len); - fread(mem, 1, len, fp); - ec=decode_words(mem, len); - free(mem); - fclose(fp); - } -#endif - return ec; -} - -#endif /* PALMOS */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: agi_v4.c,v 1.8 2001/09/06 18:52:14 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" + +#if defined PALMOS + +static int agi_v4_init (void); +static int agi_v4_deinit (void); +static int agi_v4_detect_game (char *); +static int agi_v4_load_resource (int, int); +static int agi_v4_unload_resource (int, int); +static int agi_v4_load_objects(char *); +static int agi_v4_load_words(char *); + +UINT32 pdb_read_dword(UINT8 *mem); +UINT16 pdb_read_word(UINT8 *mem); +int load_v2_dir(struct agi_dir *agid, int offset, UINT32 flen, FILE *fp); +int load_v3_dir(struct agi_dir *agid, int offs, UINT32 len, FILE *fp); + +extern struct agi_picture pictures[]; +extern struct agi_logic logics[]; +extern struct agi_view views[]; +extern struct agi_sound sounds[]; + +struct agi_loader agi_v4 = { + 4, + 0, + agi_v4_init, + agi_v4_deinit, + agi_v4_detect_game, + agi_v4_load_resource, + agi_v4_unload_resource, + agi_v4_load_objects, + agi_v4_load_words +}; + + +/* this must be kept synchronous with the AGI2PDB headers */ +#define PDB_OPT_AGDS 0x0001 +#define PDB_OPT_AMIGA 0x0002 + +#ifdef __WATCOMC__ +#pragma pack(1) +#endif + +struct pdb_pdbheader +{ + UINT8 name[32]; + /* + String - This is the name of the database + on the PalmPilot device. + It need not match the name of the PDB file + in the environment in which it is created. + */ + UINT16 fileAttributes; + /* + Attributes of the pdb file. + 0x0002 Read-Only + 0x0004 Dirty AppInfoArea + 0x0008 Backup this database + (i.e. no conduit exists) + 0x0010 Okay to install newer over existing + copy, if present on PalmPilot + 0x0020 Force the PalmPilot to reset after + this database is installed + */ + UINT16 version; + /* + Defined by the application. + */ + UINT32 creationDate; + /* + Expressed as the number of seconds since + January 1, 1904. The database will not + install if this value is zero. (PalmOS + 1.0.6) + */ + UINT32 modificationDate; + /* + Expressed as the number of seconds since + January 1, 1904. + The database will not install if this + value is zero. (PalmOS 1.0.6) + */ + UINT32 lastBackupDate; + /* + Expressed as the number of seconds since + January 1, 1904. This can be left at zero + and the database will install. + */ + UINT32 modificationNumber; + /* + Set to zero. + */ + UINT32 appInfoArea; + /* + The byte number in the PDB file (counting + from zero) at which the AppInfoArea is + located. This must be the first entry + in the Data portion of the PDB file. + If this database does not have an + AppInfoArea, set this value to zero. + */ + UINT32 sortInfoArea; + /* + The byte number in the PDB file (counting + from zero) at which the SortInfoArea is + located. This must be placed immediately + after the AppInfoArea, if one exists, + within the Data portion of the PDB file. + If this database does not have a + SortInfoArea, set this value to zero. + Do not use this. See Note C below for + further details. + */ + UINT8 databaseType[4]; + /* + String - Set this to the desired value. + Generally it should match the Database Type + used by the corresponding application. + This is 4 characters long and does not have + a terminating null. + */ + UINT8 creatorID[4]; + /* + String - Set this to the desired value. + Generally it should match the Creator ID + used by the corresponding application. In + all cases, you should always register your + Creator ID before using it. This is 4 + characters long and does not have a + terminating null. + */ + UINT32 uniqueIDSeed; + /* + This is used to generate the Unique ID + number of subsequent records. Generally, + this should be set to zero. + */ + UINT32 nextRecordListID; + /* + Set this to zero. (This does not appear + to be used, but that has not been + verified by a third party.) + */ + UINT16 numberOfRecords; + /* + This contains the number of records + */ +} +#ifdef __GNUC__ +__attribute__((packed)) +#endif +; + +struct pdb_recheader{ + UINT32 recordDataOffset; + /* + The byte number in the PDB file (counting + from zero) at which the record is located. + */ + UINT8 recordAttributes; + /* + The records attributes. + 0x10 Secret record bit. + 0x20 Record in use (busy bit). + 0x40 Dirty record bit. + 0x80 Delete record on next HotSync. + The least significant four bits are used + to represent the category values. + */ + UINT8 uniqueID[3]; + /* + Set this to zero and do not try to + second-guess what PalmOS will do with + this value. + */ +} +#ifdef __GNUC__ +__attribute__((packed)) +#endif +; + +struct agi3vol { + UINT32 sddr; + UINT32 len; +}; + +/* a agi v2.xxx game format */ +struct PalmOSAGI2 +{ + UINT32 logdir[2]; + UINT32 picdir[2]; + UINT32 viewdir[2]; + UINT32 snddir[2]; + + UINT32 object[2]; + UINT32 words[2]; + + UINT32 vol[16*2]; /* 0=offs, 1=len */ +}; + +/* an agi v3.xx.yyy game format */ +struct PalmOSAGI3 +{ + UINT32 dir[2]; + UINT32 object[2]; + UINT32 words[2]; + UINT32 vol[16*2]; /* 0=offs, 1=len */ +}; + +union PalmOSAGI4 +{ + struct PalmOSAGI2 v2; + struct PalmOSAGI3 v3; +}; + +/* PalmOS AGI Header */ +struct PalmOSAGI +{ + char name[32]; + UINT16 version; + UINT16 emulation; + UINT32 options; + UINT32 crc; + + union PalmOSAGI4 v4; +}; + +#ifdef __WATCOMC__ +#pragma pack() +#endif + +struct PalmOSAGI palmagi; +struct pdb_pdbheader PDBHeader; + +/* our PDB file that contains everything */ +char pdb_file[MAX_PATH]; +UINT32 pdb_start; + +static int agi_v4_detect_game (char *gn) +{ + FILE *fp; + int ec= err_InvalidAGIFile; + int offset; + struct pdb_recheader rh; + + /* gn is filename for a .pdb! */ + + memset(&PDBHeader, 0x0, sizeof(struct pdb_pdbheader)); + memset(&palmagi, 0x0, sizeof(struct PalmOSAGI)); + strcpy(pdb_file, gn); + + fp = fopen (pdb_file, "rb"); + if(fp!=NULL) + { + fread(&PDBHeader, 1, sizeof(struct pdb_pdbheader), fp); + + if(PDBHeader.creatorID[0]=='F' && PDBHeader.creatorID[1]=='A' && + PDBHeader.creatorID[2]=='G' && PDBHeader.creatorID[3]=='I') + { + /* valid palm database with Sarien Creator ID */ + /* now skip record headers, read in v4 Header */ + + fread(&rh, 1, sizeof(struct pdb_recheader), fp); + + offset=(int)pdb_read_dword((UINT8*)&rh.recordDataOffset); + + /* our data all starts from here. add this to all offsets */ + pdb_start=offset; + + fseek(fp, offset, SEEK_SET); + fread(&palmagi, 1, sizeof(struct PalmOSAGI), fp); + + palmagi.crc=pdb_read_dword((UINT8*)&palmagi.crc); + palmagi.options=pdb_read_word((UINT8*)&palmagi.options); + palmagi.emulation=pdb_read_word((UINT8*)&palmagi.version); + palmagi.version=pdb_read_word((UINT8*)&palmagi.version); + + /* setup our options before we call setup game! */ + if((palmagi.options&PDB_OPT_AGDS)) + opt.agds=1; + + if((palmagi.options&PDB_OPT_AMIGA)) + opt.amiga=1; + + v4id_game(palmagi.crc); + + /* if the game is a v2 */ + + /* use agi_get_release instead of palmagi.emulation */ + if((agi_get_release()>>12)==0x2) + agi_v4.int_version = 0x2917; /* setup for 2.917 */ + else + agi_v4.int_version = 0x3149; /* setup for 3.002.149 */ + + ec=err_OK; + } + + fclose(fp); + } + + return ec; +} + + +static int agi_v4_load_dir (struct agi_dir *agid, int intDirType) +{ + int ec=err_OK; + +#ifndef PALMOS + FILE *fp; + struct agi3vol agi_vol3[4]; + UINT32 offs, flen; + UINT16 xd[4]; + int i; + + if ((fp = fopen (pdb_file, "rb")) == NULL) { + return err_BadFileOpen; + } + + if((palmagi.emulation>>12)==2) + { + /* load singledir v2 style */ + switch(intDirType) + { + case rLOGIC: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.logdir[0], palmagi.v4.v2.logdir[1], fp); break; + case rPICTURE: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.picdir[0], palmagi.v4.v2.picdir[1], fp); break; + case rSOUND: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.snddir[0], palmagi.v4.v2.snddir[1], fp); break; + case rVIEW: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.viewdir[0], palmagi.v4.v2.viewdir[1], fp); break; + } + } + else + { + /* load v3 gamedir style */ + offs=pdb_start + palmagi.v4.v3.dir[0]; + flen=palmagi.v4.v3.dir[1]; + + fseek(fp, offs, SEEK_SET); + + /* FIXME: Not Endian Aware */ + fread (&xd, 1, 8, fp); + + for(i = 0; i < 4; i++) + agi_vol3[i].sddr = offs + xd[i]; + + agi_vol3[0].len = agi_vol3[1].sddr - agi_vol3[0].sddr; + agi_vol3[1].len = agi_vol3[2].sddr - agi_vol3[1].sddr; + agi_vol3[2].len = agi_vol3[3].sddr - agi_vol3[2].sddr; + agi_vol3[3].len = ftell(fp) - agi_vol3[3].sddr; + + if (agi_vol3[3].len > 256 * 3) + agi_vol3[3].len = 256 * 3; + + /* read in all directory file info */ + ec=load_v3_dir(game.dir_logic, agi_vol3[0].sddr, agi_vol3[0].len, fp); + if(ec==err_OK) + ec=load_v3_dir(game.dir_pic, agi_vol3[1].sddr, agi_vol3[1].len, fp); + if(ec==err_OK) + ec=load_v3_dir(game.dir_view, agi_vol3[2].sddr, agi_vol3[2].len, fp); + if(ec==err_OK) + ec=load_v3_dir(game.dir_sound, agi_vol3[3].sddr, agi_vol3[3].len, fp); + } + + fclose(fp); +#endif + + return ec; +} + +int load_v2_dir(struct agi_dir *agid, int offset, UINT32 flen, FILE *fp) +{ + UINT8 *mem; + int i; + + if ((mem = malloc (flen + 32)) == NULL) { + fclose (fp); + return err_NotEnoughMemory; + } + + fseek (fp, offset, SEEK_SET); + fread (mem, 1, flen, fp); + + /* set all directory resources to gone */ + for (i = 0; i < MAX_DIRS; i++) { + agid[i].volume = 0xff; + agid[i].offset = _EMPTY; + } + + /* build directory entries */ + for (i = 0; i < flen; i+=3) { + agid[i/3].volume = hilo_getbyte (mem+i) >> 4; + agid[i/3].offset = hilo_getpword (mem+i) & _EMPTY; + } + + free (mem); + + return err_OK; +} + +int load_v3_dir(struct agi_dir *agid, int offs, UINT32 len, FILE *fp) +{ + int ec = err_OK; + UINT8 *mem; + int i; + + fseek (fp, offs, SEEK_SET); + if ((mem = malloc (len + 32)) != NULL) { + fread(mem, 1, len, fp); + + /* set all directory resources to gone */ + for(i = 0; i < MAX_DIRS; i++) { + agid[i].volume = 0xFF; + agid[i].offset = _EMPTY; + } + + /* build directory entries */ + for(i = 0; i < len; i += 3) { + agid[i / 3].volume = hilo_getbyte (mem + i) >> 4; + agid[i / 3].offset = hilo_getpword (mem+i) & _EMPTY; + } + + free(mem); + } else { + ec = err_NotEnoughMemory; + } + + return ec; +} + + +static int agi_v4_init () +{ + int ec = err_OK; + + /* load directory files */ + switch((palmagi.emulation>>12)) + { + case 2: + ec = agi_v4_load_dir (game.dir_logic, rLOGIC); + if (ec == err_OK) + ec = agi_v4_load_dir (game.dir_pic, rPICTURE); + if (ec == err_OK) + ec = agi_v4_load_dir (game.dir_view, rVIEW); + if (ec == err_OK) + ec = agi_v4_load_dir (game.dir_sound, rSOUND); + break; + case 3: + /* a v3 game load will load all DIR files, + so below is just dummy code */ + ec=agi_v4_load_dir(game.dir_logic, rLOGIC); + break; + } + + return ec; +} + + +static int agi_v4_deinit () +{ + int ec = err_OK; + return ec; +} + + + +static int agi_v4_unload_resource (int restype, int resnum) +{ + switch (restype) { + case rLOGIC: + unload_logic (resnum); + break; + case rPICTURE: + unload_picture (resnum); + break; + case rVIEW: + unload_view (resnum); + break; + case rSOUND: + unload_sound (resnum); + break; + } + + return err_OK; +} + + +/* + * This function does noting but load a raw resource into memory, + * if further decoding is required, it must be done by another + * routine. NULL is returned if unsucsessfull. + */ + +UINT8* agi_v4v2_load_vol_res (struct agi_dir *agid) +{ +#ifndef PALMOS + UINT8 *data = NULL; + FILE *fp; + UINT32 offs; + char x[16]; + + /* fill offs with volume offset*/ + + offs = pdb_start + palmagi.v4.v2.vol[(2*agid->volume)]; + + /* loading a bad resource */ + if(offs==pdb_start) + agid->offset=_EMPTY; + + _D ("(agi_dir = [offset:%ld, len:%ld])", agid->offset, agid->len); + + if (agid->offset != _EMPTY && (fp = fopen (pdb_file, "rb")) != NULL) { + _D ("loading resource"); + fseek (fp, offs + agid->offset, SEEK_SET); + fread (&x, 1, 5, fp); + if (hilo_getword (x) == 0x1234) { + agid->len = lohi_getword (x + 3); + data = calloc (1, agid->len + 32); + if (data != NULL) + fread (data, 1, agid->len, fp); + } else { + /* FIXME: call some panic handler instead of + * deiniting directly + */ + deinit_video_mode (); + fprintf (stderr, "ACK! BAD RESOURCE!!!\n"); + exit (0); + } + fclose (fp); + } else { + /* we have a bad volume resource */ + /* set that resource to NA */ + agid->offset = _EMPTY; + } + + return data; +#endif +} + +UINT8* agi_v4v3_load_vol_res (struct agi_dir *agid) +{ +#ifndef PALMOS + UINT8 x[MAX_PATH], *data = NULL, *comp_buffer; + FILE *fp; + UINT32 offs; + + _D ("(%p)", agid); + + offs = pdb_start + palmagi.v4.v3.vol[2*agid->volume]; + /* loading a bad resource */ + if(offs==pdb_start) + agid->offset=_EMPTY; + + if (agid->offset != _EMPTY && (fp = fopen(pdb_file, "rb")) != NULL) { + fseek (fp, offs + agid->offset, SEEK_SET); + fread (&x, 1, 7, fp); + + if (hilo_getword(x) != 0x1234) { + /* FIXME */ + deinit_video_mode(); + printf("ACK! BAD RESOURCE!!!\n"); + exit(0); + } + + agid->len = lohi_getword (x + 3); /* uncompressed size */ + agid->clen = lohi_getword (x + 5); /* compressed len */ + + comp_buffer = calloc (1, agid->clen + 32); + fread (comp_buffer, 1, agid->clen, fp); + + if (x[2] & 0x80 || agid->len == agid->clen) { + /* do not decompress */ + data = comp_buffer; + } else { + /* it is compressed */ + data = calloc (1, agid->len + 32); + LZW_expand (comp_buffer, data, agid->len); + free (comp_buffer); + agid->flags |= RES_COMPRESSED; + } + + fclose(fp); + } else { + /* we have a bad volume resource */ + /* set that resource to NA */ + agid->offset = _EMPTY; + } + + return data; +#endif +} + + + +/* + * Loads a resource into memory, a raw resource is loaded in + * with above routine, then further decoded here. + */ +int agi_v4_load_resource (int restype, int resnum) +{ + int ec = err_OK; + UINT8 *data = NULL; + + + _D (_D_WARN "(restype = %d, resnum = %d)", restype, resnum); + if (resnum > MAX_DIRS) + return err_BadResource; + + switch (restype) { + case rLOGIC: + if (~game.dir_logic[resnum].flags & RES_LOADED) { + _D (_D_WARN "loading logic resource %d", resnum); + agi_v4.unload_resource (rLOGIC, resnum); + /* load raw resource into data */ + if((palmagi.emulation>>12)==2) + data = agi_v4v2_load_vol_res (&game.dir_logic[resnum]); + else + data = agi_v4v3_load_vol_res(&game.dir_logic[resnum]); + + ec = (logics[resnum].data = data) ? + decode_logic (resnum) : err_BadResource; + + logics[resnum].sIP = 2; + } + + logics[resnum].cIP = logics[resnum].sIP; + break; + case rPICTURE: + /* if picture is currently NOT loaded *OR* cacheing is off, + * unload the resource (caching == off) and reload it + */ + + _D (_D_WARN "loading picture resource %d", resnum); + if (game.dir_pic[resnum].flags & RES_LOADED) + break; + + /* if loaded but not cached, unload it */ + /* if cached but not loaded, etc */ + agi_v4.unload_resource (rPICTURE, resnum); + + if((palmagi.emulation>>12)==2) + { + data = agi_v4v2_load_vol_res (&game.dir_pic[resnum]); + if (data != NULL) { + pictures[resnum].rdata = data; + game.dir_pic[resnum].flags |= RES_LOADED; + } else { + ec = err_BadResource; + } + } + else + { + data = agi_v4v3_load_vol_res(&game.dir_pic[resnum]); + if (data != NULL) { + data = convert_v3_pic (data, + game.dir_pic[resnum].len); + pictures[resnum].rdata = data; + game.dir_pic[resnum].flags |= RES_LOADED; + } else { + ec=err_BadResource; + } + } + + break; + case rSOUND: + _D (_D_WARN "loading sound resource %d", resnum); + if (game.dir_sound[resnum].flags & RES_LOADED) + break; + + if((palmagi.emulation>>12)==2) + data = agi_v4v2_load_vol_res (&game.dir_sound[resnum]); + else + data = agi_v4v3_load_vol_res(&game.dir_sound[resnum]); + + if (data != NULL) { + sounds[resnum].rdata = data; + game.dir_sound[resnum].flags |= RES_LOADED; + decode_sound (resnum); + } else { + ec = err_BadResource; + } + break; + case rVIEW: + /* Load a VIEW resource into memory... + * Since VIEWS alter the view table ALL the time + * can we cache the view? or must we reload it all + * the time? + */ + if (game.dir_view[resnum].flags & RES_LOADED) + break; + + _D (_D_WARN "loading view resource %d", resnum); + agi_v4.unload_resource (rVIEW, resnum); + + if((palmagi.emulation>>12)==2) + { + if ((data = agi_v4v2_load_vol_res (&game.dir_view[resnum]))) { + views[resnum].rdata = data; + game.dir_view[resnum].flags |= RES_LOADED; + ec = decode_view (resnum); + } else { + ec=err_BadResource; + } + } + else + { + if ((data = agi_v4v3_load_vol_res (&game.dir_view[resnum]))) { + views[resnum].rdata = data; + game.dir_view[resnum].flags |= RES_LOADED; + ec = decode_view (resnum); + } else { + ec=err_BadResource; + } + } + break; + default: + ec = err_BadResource; + break; + } + + return ec; +} + + +UINT16 pdb_read_word(UINT8 *mem) +{ + UINT16 w; + + w = (UINT16)mem[1]; + w += (UINT16)mem[0]<<8; + + return w; +} + +UINT32 pdb_read_dword(UINT8 *mem) +{ + UINT32 w; + + w = (UINT32)mem[3]; + w += (UINT32)mem[2]<<8; + w += (UINT32)mem[1]<<16; + w += (UINT32)mem[0]<<24; + + return w; +} + +static int agi_v4_load_objects(char *fname) +{ + int ec=err_OK; +#ifndef PALMOS + FILE *fp; + UINT8 *mem; + UINT32 len; + UINT32 offs; + + game.num_objects=0; + fp=fopen(pdb_file, "rb"); + if(fp!=NULL) + { + if((palmagi.emulation>>12)==2) + { + offs=palmagi.v4.v2.object[0]; + len=palmagi.v4.v2.object[1]; + } + else + { + offs=palmagi.v4.v3.object[0]; + len=palmagi.v4.v3.object[1]; + } + + fseek(fp, pdb_start + offs, SEEK_SET); + mem=(UINT8*)malloc(32+len); + fread(mem, 1, len, fp); + ec=decode_objects(mem, len); + + free(mem); + fclose(fp); + } +#endif + return ec; +} + +static int agi_v4_load_words(char *fname) +{ + int ec=err_OK; +#ifndef PALMOS + FILE *fp; + UINT8 *mem; + UINT32 len; + UINT32 offs; + + fp=fopen(pdb_file, "rb"); + if(fp!=NULL) + { + if((palmagi.emulation>>12)==2) + { + offs=palmagi.v4.v2.words[0]; + len=palmagi.v4.v2.words[1]; + } + else + { + offs=palmagi.v4.v3.words[0]; + len=palmagi.v4.v3.words[1]; + } + + fseek(fp, pdb_start + offs, SEEK_SET); + mem=(UINT8*)malloc(32+len); + fread(mem, 1, len, fp); + ec=decode_words(mem, len); + free(mem); + fclose(fp); + } +#endif + return ec; +} + +#endif /* PALMOS */ diff --git a/checks.c b/checks.c index 25730df..eacaa5d 100644 --- a/checks.c +++ b/checks.c @@ -1,313 +1,313 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: checks.c,v 1.32 2002/11/09 17:05:21 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include "sarien.h" -#include "agi.h" - - -static int check_position (struct vt_entry *v) -{ - _D ("check position @ %d, %d", v->x_pos, v->y_pos); - - if (v->x_pos < 0 || - v->x_pos + v->x_size > _WIDTH || - v->y_pos - v->y_size + 1 < 0 || - v->y_pos >= _HEIGHT || - ((~v->flags & IGNORE_HORIZON) && v->y_pos <= game.horizon)) - { - _D (_D_WARN "check position failed: x=%d, y=%d, h=%d, w=%d", - v->x_pos, v->y_pos, v->x_size, v->y_size); - return 0; - } - - /* MH1 needs this, but it breaks LSL1 */ - if (agi_get_release() >= 0x3000) { - if (v->y_pos < v->y_size) - return 0; - } - - return 1; -} - -/** - * Check if there's another object on the way - */ -static int check_collision (struct vt_entry *v) -{ - struct vt_entry *u; - - if (v->flags & IGNORE_OBJECTS) - return 0; - - for_each_vt_entry (u) { - if ((u->flags & (ANIMATED|DRAWN)) != (ANIMATED|DRAWN)) - continue; - - if (u->flags & IGNORE_OBJECTS) - continue; - - /* Same object, check next */ - if (v->entry == u->entry) - continue; - - /* No horizontal overlap, check next */ - if (v->x_pos + v->x_size < u->x_pos || - v->x_pos > u->x_pos + u->x_size) - continue; - - /* Same y, return error! */ - if (v->y_pos == u->y_pos) - goto return_1; - - /* Crossed the baseline, return error! */ - if ((v->y_pos > u->y_pos && v->y_pos2 < u->y_pos2) || - (v->y_pos < u->y_pos && v->y_pos2 > u->y_pos2)) - { - goto return_1; - } - } - - return 0; - -return_1: - _D (_D_WARN "check returns 1 (object %d)", v->entry); - return 1; -} - -static int check_priority (struct vt_entry *v) -{ - int i, trigger, water, pass, pri; - UINT8 *p0; - - if (~v->flags & FIXED_PRIORITY) { - /* Priority bands */ - v->priority = game.pri_table[v->y_pos]; - } - - trigger = 0; - water = 0; - pass = 1; - - if (v->priority == 0x0f) - goto _check_ego; - - water = 1; - - p0 = &game.sbuf[v->x_pos + v->y_pos * _WIDTH]; - - for (i = 0; i < v->x_size; i++, p0++) { - pri = *p0 >> 4; - - if (pri == 0) { /* unconditional black. no go at all! */ - pass = 0; - break; - } - - if (pri == 3) /* water surface */ - continue; - - water = 0; - - if (pri == 1) { /* conditional blue */ - if (v->flags & IGNORE_BLOCKS) - continue; - - _D (_D_WARN "Blocks observed!"); - pass = 0; - break; - } - - - if (pri == 2) { /* trigger */ - /* _D (_D_WARN "stepped on trigger"); */ -#ifdef USE_CONSOLE - if (!debug.ignoretriggers) -#endif - trigger = 1; - } - } - - if (pass) { - if (!water && v->flags & ON_WATER) - pass = 0; - if (water && v->flags & ON_LAND) - pass = 0; - } - -_check_ego: - if (v->entry == 0) { - setflag (F_ego_touched_p2, trigger ? TRUE : FALSE); - setflag (F_ego_water, water ? TRUE : FALSE); - } - - return pass; -} - -/* - * Public functions - */ - -/** - * Update position of objects - * This function updates the position of all animated, updating view - * table entries according to its motion type, step size, etc. The - * new position must be valid according to the sprite positioning - * rules, otherwise the previous position will be kept. - */ -void update_position () -{ - struct vt_entry *v; - int x, y, old_x, old_y, border; - - game.vars[V_border_code] = 0; - game.vars[V_border_touch_ego] = 0; - game.vars[V_border_touch_obj] = 0; - - for_each_vt_entry (v) { - if ((v->flags & (ANIMATED|UPDATE|DRAWN)) - != (ANIMATED|UPDATE|DRAWN)) - { - continue; - } - - if (v->step_time_count != 0) { - if (--v->step_time_count != 0) - continue; - } - - v->step_time_count = v->step_time; - - x = old_x = v->x_pos; - y = old_y = v->y_pos; - - /* If object has moved, update its position */ - if (~v->flags & UPDATE_POS) { - int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; - int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 }; - x += v->step_size * dx[v->direction]; - y += v->step_size * dy[v->direction]; - } - - /* Now check if it touched the borders */ - border = 0; - - /* Check left/right borders */ - if (x < 0) { - x = 0; - border = 4; - } else if (x <= 0 && agi_get_release() == 0x3086) { /* KQ4 */ - x = 0; /* See bug #590462 */ - border = 4; - } else if (v->entry == 0 && x == 0 && v->flags & ADJ_EGO_XY) { - /* Extra test to walk west clicking the mouse */ - x = 0; - border = 4; - } else if (x + v->x_size > _WIDTH) { - x = _WIDTH - v->x_size; - border = 2; - } - - /* Check top/bottom borders. */ - if (y - v->y_size + 1 < 0) { - y = v->y_size - 1; - border = 1; - } else if (y > _HEIGHT - 1) { - y = _HEIGHT - 1; - border = 3; - } else if ((~v->flags & IGNORE_HORIZON) && y <= game.horizon) { - _D (_D_WARN "y = %d, horizon = %d", y, game.horizon); - y = game.horizon + 1; - border = 1; - } - - /* Test new position. rollback if test fails */ - v->x_pos = x; - v->y_pos = y; - if (check_collision (v) || !check_priority (v)) { - v->x_pos = old_x; - v->y_pos = old_y; - border = 0; - fix_position (v->entry); - } - - if (border != 0) { - if_is_ego_view (v) { - game.vars[V_border_touch_ego] = border; - } else { - game.vars[V_border_code] = v->entry; - game.vars[V_border_touch_obj] = border; - } - if (v->motion == MOTION_MOVE_OBJ) { - in_destination (v); - } - } - - v->flags &= ~UPDATE_POS; - } -} - -/** - * Adjust position of a sprite - * This function adjusts the position of a sprite moving it until - * certain criteria is matched. According to priority and control line - * data, a sprite may not always appear at the location we specified. - * This behaviour is also known as the "Budin-Sonneveld effect". - * - * @param n view table entry number - */ -void fix_position (int n) -{ - struct vt_entry *v = &game.view_table[n]; - int count, dir, size; - - /* _D (_D_WARN "adjusting view table entry #%d (%d,%d)", - n, v->x_pos, v->y_pos); */ - - /* test horizon */ - if ((~v->flags & IGNORE_HORIZON) && v->y_pos <= game.horizon) - v->y_pos = game.horizon + 1; - - dir = 0; - count = size = 1; - - while (!check_position(v) || check_collision(v) || !check_priority(v)) { - switch (dir) { - case 0: /* west */ - v->x_pos--; - if (--count) continue; - dir = 1; - break; - case 1: /* south */ - v->y_pos++; - if (--count) continue; - dir = 2; - size++; - break; - case 2: /* east */ - v->x_pos++; - if (--count) continue; - dir = 3; - break; - case 3: /* north */ - v->y_pos--; - if (--count) continue; - dir = 0; - size++; - break; - } - - count = size; - } - - _D (_D_WARN "view table entry #%d position adjusted to (%d,%d)", - n, v->x_pos, v->y_pos); -} - -/* end: checks.c */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: checks.c,v 1.32 2002/11/09 17:05:21 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include "sarien.h" +#include "agi.h" + + +static int check_position (struct vt_entry *v) +{ + _D ("check position @ %d, %d", v->x_pos, v->y_pos); + + if (v->x_pos < 0 || + v->x_pos + v->x_size > _WIDTH || + v->y_pos - v->y_size + 1 < 0 || + v->y_pos >= _HEIGHT || + ((~v->flags & IGNORE_HORIZON) && v->y_pos <= game.horizon)) + { + _D (_D_WARN "check position failed: x=%d, y=%d, h=%d, w=%d", + v->x_pos, v->y_pos, v->x_size, v->y_size); + return 0; + } + + /* MH1 needs this, but it breaks LSL1 */ + if (agi_get_release() >= 0x3000) { + if (v->y_pos < v->y_size) + return 0; + } + + return 1; +} + +/** + * Check if there's another object on the way + */ +static int check_collision (struct vt_entry *v) +{ + struct vt_entry *u; + + if (v->flags & IGNORE_OBJECTS) + return 0; + + for_each_vt_entry (u) { + if ((u->flags & (ANIMATED|DRAWN)) != (ANIMATED|DRAWN)) + continue; + + if (u->flags & IGNORE_OBJECTS) + continue; + + /* Same object, check next */ + if (v->entry == u->entry) + continue; + + /* No horizontal overlap, check next */ + if (v->x_pos + v->x_size < u->x_pos || + v->x_pos > u->x_pos + u->x_size) + continue; + + /* Same y, return error! */ + if (v->y_pos == u->y_pos) + goto return_1; + + /* Crossed the baseline, return error! */ + if ((v->y_pos > u->y_pos && v->y_pos2 < u->y_pos2) || + (v->y_pos < u->y_pos && v->y_pos2 > u->y_pos2)) + { + goto return_1; + } + } + + return 0; + +return_1: + _D (_D_WARN "check returns 1 (object %d)", v->entry); + return 1; +} + +static int check_priority (struct vt_entry *v) +{ + int i, trigger, water, pass, pri; + UINT8 *p0; + + if (~v->flags & FIXED_PRIORITY) { + /* Priority bands */ + v->priority = game.pri_table[v->y_pos]; + } + + trigger = 0; + water = 0; + pass = 1; + + if (v->priority == 0x0f) + goto _check_ego; + + water = 1; + + p0 = &game.sbuf[v->x_pos + v->y_pos * _WIDTH]; + + for (i = 0; i < v->x_size; i++, p0++) { + pri = *p0 >> 4; + + if (pri == 0) { /* unconditional black. no go at all! */ + pass = 0; + break; + } + + if (pri == 3) /* water surface */ + continue; + + water = 0; + + if (pri == 1) { /* conditional blue */ + if (v->flags & IGNORE_BLOCKS) + continue; + + _D (_D_WARN "Blocks observed!"); + pass = 0; + break; + } + + + if (pri == 2) { /* trigger */ + /* _D (_D_WARN "stepped on trigger"); */ +#ifdef USE_CONSOLE + if (!debug.ignoretriggers) +#endif + trigger = 1; + } + } + + if (pass) { + if (!water && v->flags & ON_WATER) + pass = 0; + if (water && v->flags & ON_LAND) + pass = 0; + } + +_check_ego: + if (v->entry == 0) { + setflag (F_ego_touched_p2, trigger ? TRUE : FALSE); + setflag (F_ego_water, water ? TRUE : FALSE); + } + + return pass; +} + +/* + * Public functions + */ + +/** + * Update position of objects + * This function updates the position of all animated, updating view + * table entries according to its motion type, step size, etc. The + * new position must be valid according to the sprite positioning + * rules, otherwise the previous position will be kept. + */ +void update_position () +{ + struct vt_entry *v; + int x, y, old_x, old_y, border; + + game.vars[V_border_code] = 0; + game.vars[V_border_touch_ego] = 0; + game.vars[V_border_touch_obj] = 0; + + for_each_vt_entry (v) { + if ((v->flags & (ANIMATED|UPDATE|DRAWN)) + != (ANIMATED|UPDATE|DRAWN)) + { + continue; + } + + if (v->step_time_count != 0) { + if (--v->step_time_count != 0) + continue; + } + + v->step_time_count = v->step_time; + + x = old_x = v->x_pos; + y = old_y = v->y_pos; + + /* If object has moved, update its position */ + if (~v->flags & UPDATE_POS) { + int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; + int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 }; + x += v->step_size * dx[v->direction]; + y += v->step_size * dy[v->direction]; + } + + /* Now check if it touched the borders */ + border = 0; + + /* Check left/right borders */ + if (x < 0) { + x = 0; + border = 4; + } else if (x <= 0 && agi_get_release() == 0x3086) { /* KQ4 */ + x = 0; /* See bug #590462 */ + border = 4; + } else if (v->entry == 0 && x == 0 && v->flags & ADJ_EGO_XY) { + /* Extra test to walk west clicking the mouse */ + x = 0; + border = 4; + } else if (x + v->x_size > _WIDTH) { + x = _WIDTH - v->x_size; + border = 2; + } + + /* Check top/bottom borders. */ + if (y - v->y_size + 1 < 0) { + y = v->y_size - 1; + border = 1; + } else if (y > _HEIGHT - 1) { + y = _HEIGHT - 1; + border = 3; + } else if ((~v->flags & IGNORE_HORIZON) && y <= game.horizon) { + _D (_D_WARN "y = %d, horizon = %d", y, game.horizon); + y = game.horizon + 1; + border = 1; + } + + /* Test new position. rollback if test fails */ + v->x_pos = x; + v->y_pos = y; + if (check_collision (v) || !check_priority (v)) { + v->x_pos = old_x; + v->y_pos = old_y; + border = 0; + fix_position (v->entry); + } + + if (border != 0) { + if_is_ego_view (v) { + game.vars[V_border_touch_ego] = border; + } else { + game.vars[V_border_code] = v->entry; + game.vars[V_border_touch_obj] = border; + } + if (v->motion == MOTION_MOVE_OBJ) { + in_destination (v); + } + } + + v->flags &= ~UPDATE_POS; + } +} + +/** + * Adjust position of a sprite + * This function adjusts the position of a sprite moving it until + * certain criteria is matched. According to priority and control line + * data, a sprite may not always appear at the location we specified. + * This behaviour is also known as the "Budin-Sonneveld effect". + * + * @param n view table entry number + */ +void fix_position (int n) +{ + struct vt_entry *v = &game.view_table[n]; + int count, dir, size; + + /* _D (_D_WARN "adjusting view table entry #%d (%d,%d)", + n, v->x_pos, v->y_pos); */ + + /* test horizon */ + if ((~v->flags & IGNORE_HORIZON) && v->y_pos <= game.horizon) + v->y_pos = game.horizon + 1; + + dir = 0; + count = size = 1; + + while (!check_position(v) || check_collision(v) || !check_priority(v)) { + switch (dir) { + case 0: /* west */ + v->x_pos--; + if (--count) continue; + dir = 1; + break; + case 1: /* south */ + v->y_pos++; + if (--count) continue; + dir = 2; + size++; + break; + case 2: /* east */ + v->x_pos++; + if (--count) continue; + dir = 3; + break; + case 3: /* north */ + v->y_pos--; + if (--count) continue; + dir = 0; + size++; + break; + } + + count = size; + } + + _D (_D_WARN "view table entry #%d position adjusted to (%d,%d)", + n, v->x_pos, v->y_pos); +} + +/* end: checks.c */ diff --git a/cli.c b/cli.c index fdf4448..c94be07 100644 --- a/cli.c +++ b/cli.c @@ -1,314 +1,314 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: cli.c,v 1.39 2002/09/12 01:09:01 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include "sarien.h" - -#ifdef USE_COMMAND_LINE - -#include -#include -#include - -#include "sound.h" - -extern char *optarg; - - -static void help (int argc, char **argv) -{ - /* printf() breaks GCC 3.0 build */ - fprintf (stdout, -"Syntax is -:- %s [switches] [gamedir]\n" -"\n" -"Where [switches] are optionally:\n" -#ifdef AGDS_SUPPORT -" -a --agds Enables sarien to play AGDS created games.\n" -#endif -" -A --amiga Forces the game to be seen as an Amiga word padded game.\n" -" -C --crc CRC and identify the game files and stop.\n" -#ifndef PCCGA -" -c --cga-palette Use PC CGA video mode emulation.\n" -#endif -#ifdef OPT_LIST_DICT -" -d --list-dictionary\n" -" List dictionary words.\n" -#endif -#ifndef PCCGA -" -e --ega-palette Use PC EGA palette instead of amiga-ish palette\n" -#endif -" -L --list-games List all the games in the ID file\n" -" -F --full-screen Run in full-screen mode if allowed by the graphics device\n" -" -g --no-gfx-optimizations\n" -" Disable optimized graphic driver hacks (if available).\n" -#ifdef USE_HIRES -" -H --hires {0|1} Enable/disable hi-res mode.\n" -#endif -" -h --help Display this help screen.\n" -#ifdef USE_MOUSE -#ifndef __MSDOS__ -" -m --agimouse AGI Mouse 1.0 compatibility mode.\n" -#endif -#endif -" -n --no-sound Disable sound output.\n" -#ifdef OPT_PICTURE_VIEWER -" -p --picture-viewer\n" -" Interactive picture viewer.\n" -#endif -#ifdef OPT_LIST_OBJECTS -" -o --list-objects List objects.\n" -#endif -#ifndef __MSDOS__ -" -S --scale {num} Window size scale (only for windowed graphics).\n" -#ifndef __MSDOS__ -" -s --emulate-sound {type}\n" -" Emulate the sound of Sierra AGI running in different\n" -" computers. Valid emulations are pc, mac and amiga\n" -#endif -" -r --aspect-ratio {0|1}\n" -" Adjust aspect ratio to match the PC EGA 320x200 screen.\n" -#endif -" -v --emulate-version {version}\n" -" Force version to emulate. Valid v2 game versions are:\n" -" 2.089, 2.272, 2.440, 2.917, 2.936. Valid v3 games are:\n" -" 3.002.086, 3.002.149.\n" -" -V --version Display version information.\n" -#ifndef __MSDOS__ -" -x --no-x-shm Disable X shared memory extension (if available).\n" -#endif -#if 0 -" -xd --dga Use XFree86 DGA extension (if available).\n" -#endif -"\n" -"[gamedir] is optionally the directory the game is in, if no directory is\n" -"specified, the current directory is assumed.\n" -"\n" -"Example: %s -v2.272 /games/sierra/sq1\n", argv[0], argv[0]); -} - - -int parse_cli (int argc, char **argv) -{ - int i; - int ec = err_OK; - - struct { - UINT16 vers; - char *string; - } cmp_versions[]= { - { 0x2089, "2.089" }, - { 0x2272, "2.272" }, - { 0x2440, "2.440" }, - { 0x2917, "2.917" }, - { 0x2936, "2.936" }, - { 0x3086, "3.002.086" }, - { 0x3149, "3.002.149" }, - { 0x0, "" } - }; - int o, optidx = 0; -#define OPTIONS "AaCcDdE:eFgH:hLlmnopr:skS:Vv:x" - static struct option lopt[] = { - { "version", 0, 0, 'V' }, - { "help", 0, 0, 'h' }, -#ifdef AGDS_SUPPORT - { "agds", 0, 0, 'a' }, -#endif - { "amiga", 0, 0, 'A'}, - { "emulate-version", 1, 0, 'v' }, - { "crc", 0, 0, 'C'}, -#ifndef PCCGA - { "cga-palette", 0, 0, 'c'}, -#endif - { "list-games", 0, 0, 'L'}, -#ifdef OPT_LIST_DICT - { "list-dictionary", 0, 0, 'd' }, -#endif -#ifndef PCCGA - { "ega-palette", 0, 0, 'e' }, -#endif - { "full-screen", 0, 0, 'F' }, -#ifdef USE_HIRES - { "hires", 1, 0, 'H' }, -#endif - { "no-sound", 0, 0, 'n' }, -#ifdef OPT_LIST_OBJECTS - { "list-objects", 0, 0, 'o' }, -#endif -#ifdef OPT_PICTURE_VIEWER - { "picture-viewer", 0, 0, 'p' }, -#endif - { "wait-key", 0, 0, 'k' }, - { "no-x-shm", 0, 0, 'x' }, - { "aspect-ratio", 1, 0, 'r' }, -#ifdef USE_MOUSE - { "agimouse", 0, 0, 'm' }, -#endif - { "scale", 1, 0, 'S' }, -#ifndef __MSDOS__ - { "emulate-sound", 1, 0, 's' }, -#endif - { "no-gfx-optimizations",0,0, 'g' } - }; - - /* FIXME: Add support for a rc file for UNIX */ - - /* Set defaults */ - memset (&opt, 0, sizeof (struct sarien_options)); - opt.gamerun = GAMERUN_RUNGAME; - opt.scale = 2; - opt.fixratio = TRUE; - opt.gfxhacks = TRUE; -#ifdef USE_HIRES - opt.hires = TRUE; -#endif -#ifdef MITSHM - opt.mitshm = TRUE; -#endif - opt.soundemu = SOUND_EMU_NONE; - - while ((o = getopt_long (argc, argv, OPTIONS, lopt, &optidx)) != -1) { - switch (o) { - case 'V': - printf ("Version : " VERSION " Compiled on " __DATE__ "; " __TIME__ "\n"); - printf ("Logic patching is "); -#ifdef PATCH_LOGIC - printf ("enabled\n"); -#else - printf ("disabled\n"); -#endif - printf("AGDS games and Russian/Cyrillic font is "); -#ifdef AGDS_SUPPORT - printf("supported\n"); -#else - printf("not supported\n"); -#endif - printf("Listing Objects is "); -#ifdef OPT_LIST_OBJECTS - printf("supported\n"); -#else - printf("not supported\n"); -#endif - printf("Dictionary Listing is "); -#ifdef OPT_LIST_DICT - printf("enabled\n"); -#else - printf("disabled\n"); -#endif - exit (0); - case 'A': - opt.amiga = TRUE; - break; - case 'a': - opt.agds = TRUE; - break; - case 'C': - opt.gamerun = GAMERUN_CRC; - break; -#ifndef PCCGA - case 'c': - opt.cgaemu = TRUE; - break; -#endif -#ifdef OPT_LIST_DICT - case 'd': - opt.gamerun = GAMERUN_WORDS; - break; -#endif -#ifndef PCCGA - case 'e': - opt.egapal = TRUE; - break; -#endif - case 'F': - opt.fullscreen = TRUE; - break; - case 'L': - opt.gamerun = GAMERUN_GAMES; - break; - case 'g': - opt.gfxhacks = FALSE; - break; -#ifdef USE_HIRES - case 'H': - opt.hires = strtoul (optarg, NULL, 0); - break; -#endif -#ifdef USE_MOUSE - case 'm': - opt.agimouse = TRUE; - break; -#endif - case 'n': - opt.nosound = TRUE; - break; -#ifdef OPT_LIST_OBJECTS - case 'o': - opt.gamerun = GAMERUN_OBJECTS; - break; -#endif -#ifdef OPT_PICTURE_VIEWER - case 'p': - opt.gamerun = GAMERUN_PICVIEW; - break; -#endif -#ifndef __MSDOS__ - case 'r': - opt.fixratio = strtoul (optarg, NULL, 0); - break; - case 'S': - opt.scale = strtoul (optarg, NULL, 0); - if (opt.scale < 1) - opt.scale = 1; - if (opt.scale > 4) - opt.scale = 4; - break; - case 's': - if (!strcmp (optarg, "pc")) - opt.soundemu = SOUND_EMU_PC; - else if (!strcmp (optarg, "mac")) - opt.soundemu = SOUND_EMU_MAC; - else if (!strcmp (optarg, "amiga")) - opt.soundemu = SOUND_EMU_AMIGA; - else { - fprintf (stderr, "Sound emulation \"%s\" is " - "unknown\n", optarg); - exit (0); - } - break; -#endif - case 'v': - for (i = 0; cmp_versions[i].vers; i++) { - if (!strcmp (optarg, cmp_versions[i].string)) { - opt.emuversion = cmp_versions[i].vers; - break; - } - } - if (!opt.emuversion) { - printf ("Error: bad AGI version number \"%s\"\n", - optarg); - exit (-1); - } - break; -#ifdef MITSHM - case 'x': - opt.mitshm = FALSE; - break; -#endif - case 'h': - help (argc, argv); - default: - exit (-1); - } - } - - return ec; -} - -#endif /* USE_COMMAND_LINE */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: cli.c,v 1.39 2002/09/12 01:09:01 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include "sarien.h" + +#ifdef USE_COMMAND_LINE + +#include +#include +#include + +#include "sound.h" + +extern char *optarg; + + +static void help (int argc, char **argv) +{ + /* printf() breaks GCC 3.0 build */ + fprintf (stdout, +"Syntax is -:- %s [switches] [gamedir]\n" +"\n" +"Where [switches] are optionally:\n" +#ifdef AGDS_SUPPORT +" -a --agds Enables sarien to play AGDS created games.\n" +#endif +" -A --amiga Forces the game to be seen as an Amiga word padded game.\n" +" -C --crc CRC and identify the game files and stop.\n" +#ifndef PCCGA +" -c --cga-palette Use PC CGA video mode emulation.\n" +#endif +#ifdef OPT_LIST_DICT +" -d --list-dictionary\n" +" List dictionary words.\n" +#endif +#ifndef PCCGA +" -e --ega-palette Use PC EGA palette instead of amiga-ish palette\n" +#endif +" -L --list-games List all the games in the ID file\n" +" -F --full-screen Run in full-screen mode if allowed by the graphics device\n" +" -g --no-gfx-optimizations\n" +" Disable optimized graphic driver hacks (if available).\n" +#ifdef USE_HIRES +" -H --hires {0|1} Enable/disable hi-res mode.\n" +#endif +" -h --help Display this help screen.\n" +#ifdef USE_MOUSE +#ifndef __MSDOS__ +" -m --agimouse AGI Mouse 1.0 compatibility mode.\n" +#endif +#endif +" -n --no-sound Disable sound output.\n" +#ifdef OPT_PICTURE_VIEWER +" -p --picture-viewer\n" +" Interactive picture viewer.\n" +#endif +#ifdef OPT_LIST_OBJECTS +" -o --list-objects List objects.\n" +#endif +#ifndef __MSDOS__ +" -S --scale {num} Window size scale (only for windowed graphics).\n" +#ifndef __MSDOS__ +" -s --emulate-sound {type}\n" +" Emulate the sound of Sierra AGI running in different\n" +" computers. Valid emulations are pc, mac and amiga\n" +#endif +" -r --aspect-ratio {0|1}\n" +" Adjust aspect ratio to match the PC EGA 320x200 screen.\n" +#endif +" -v --emulate-version {version}\n" +" Force version to emulate. Valid v2 game versions are:\n" +" 2.089, 2.272, 2.440, 2.917, 2.936. Valid v3 games are:\n" +" 3.002.086, 3.002.149.\n" +" -V --version Display version information.\n" +#ifndef __MSDOS__ +" -x --no-x-shm Disable X shared memory extension (if available).\n" +#endif +#if 0 +" -xd --dga Use XFree86 DGA extension (if available).\n" +#endif +"\n" +"[gamedir] is optionally the directory the game is in, if no directory is\n" +"specified, the current directory is assumed.\n" +"\n" +"Example: %s -v2.272 /games/sierra/sq1\n", argv[0], argv[0]); +} + + +int parse_cli (int argc, char **argv) +{ + int i; + int ec = err_OK; + + struct { + UINT16 vers; + char *string; + } cmp_versions[]= { + { 0x2089, "2.089" }, + { 0x2272, "2.272" }, + { 0x2440, "2.440" }, + { 0x2917, "2.917" }, + { 0x2936, "2.936" }, + { 0x3086, "3.002.086" }, + { 0x3149, "3.002.149" }, + { 0x0, "" } + }; + int o, optidx = 0; +#define OPTIONS "AaCcDdE:eFgH:hLlmnopr:skS:Vv:x" + static struct option lopt[] = { + { "version", 0, 0, 'V' }, + { "help", 0, 0, 'h' }, +#ifdef AGDS_SUPPORT + { "agds", 0, 0, 'a' }, +#endif + { "amiga", 0, 0, 'A'}, + { "emulate-version", 1, 0, 'v' }, + { "crc", 0, 0, 'C'}, +#ifndef PCCGA + { "cga-palette", 0, 0, 'c'}, +#endif + { "list-games", 0, 0, 'L'}, +#ifdef OPT_LIST_DICT + { "list-dictionary", 0, 0, 'd' }, +#endif +#ifndef PCCGA + { "ega-palette", 0, 0, 'e' }, +#endif + { "full-screen", 0, 0, 'F' }, +#ifdef USE_HIRES + { "hires", 1, 0, 'H' }, +#endif + { "no-sound", 0, 0, 'n' }, +#ifdef OPT_LIST_OBJECTS + { "list-objects", 0, 0, 'o' }, +#endif +#ifdef OPT_PICTURE_VIEWER + { "picture-viewer", 0, 0, 'p' }, +#endif + { "wait-key", 0, 0, 'k' }, + { "no-x-shm", 0, 0, 'x' }, + { "aspect-ratio", 1, 0, 'r' }, +#ifdef USE_MOUSE + { "agimouse", 0, 0, 'm' }, +#endif + { "scale", 1, 0, 'S' }, +#ifndef __MSDOS__ + { "emulate-sound", 1, 0, 's' }, +#endif + { "no-gfx-optimizations",0,0, 'g' } + }; + + /* FIXME: Add support for a rc file for UNIX */ + + /* Set defaults */ + memset (&opt, 0, sizeof (struct sarien_options)); + opt.gamerun = GAMERUN_RUNGAME; + opt.scale = 2; + opt.fixratio = TRUE; + opt.gfxhacks = TRUE; +#ifdef USE_HIRES + opt.hires = TRUE; +#endif +#ifdef MITSHM + opt.mitshm = TRUE; +#endif + opt.soundemu = SOUND_EMU_NONE; + + while ((o = getopt_long (argc, argv, OPTIONS, lopt, &optidx)) != -1) { + switch (o) { + case 'V': + printf ("Version : " VERSION " Compiled on " __DATE__ "; " __TIME__ "\n"); + printf ("Logic patching is "); +#ifdef PATCH_LOGIC + printf ("enabled\n"); +#else + printf ("disabled\n"); +#endif + printf("AGDS games and Russian/Cyrillic font is "); +#ifdef AGDS_SUPPORT + printf("supported\n"); +#else + printf("not supported\n"); +#endif + printf("Listing Objects is "); +#ifdef OPT_LIST_OBJECTS + printf("supported\n"); +#else + printf("not supported\n"); +#endif + printf("Dictionary Listing is "); +#ifdef OPT_LIST_DICT + printf("enabled\n"); +#else + printf("disabled\n"); +#endif + exit (0); + case 'A': + opt.amiga = TRUE; + break; + case 'a': + opt.agds = TRUE; + break; + case 'C': + opt.gamerun = GAMERUN_CRC; + break; +#ifndef PCCGA + case 'c': + opt.cgaemu = TRUE; + break; +#endif +#ifdef OPT_LIST_DICT + case 'd': + opt.gamerun = GAMERUN_WORDS; + break; +#endif +#ifndef PCCGA + case 'e': + opt.egapal = TRUE; + break; +#endif + case 'F': + opt.fullscreen = TRUE; + break; + case 'L': + opt.gamerun = GAMERUN_GAMES; + break; + case 'g': + opt.gfxhacks = FALSE; + break; +#ifdef USE_HIRES + case 'H': + opt.hires = strtoul (optarg, NULL, 0); + break; +#endif +#ifdef USE_MOUSE + case 'm': + opt.agimouse = TRUE; + break; +#endif + case 'n': + opt.nosound = TRUE; + break; +#ifdef OPT_LIST_OBJECTS + case 'o': + opt.gamerun = GAMERUN_OBJECTS; + break; +#endif +#ifdef OPT_PICTURE_VIEWER + case 'p': + opt.gamerun = GAMERUN_PICVIEW; + break; +#endif +#ifndef __MSDOS__ + case 'r': + opt.fixratio = strtoul (optarg, NULL, 0); + break; + case 'S': + opt.scale = strtoul (optarg, NULL, 0); + if (opt.scale < 1) + opt.scale = 1; + if (opt.scale > 4) + opt.scale = 4; + break; + case 's': + if (!strcmp (optarg, "pc")) + opt.soundemu = SOUND_EMU_PC; + else if (!strcmp (optarg, "mac")) + opt.soundemu = SOUND_EMU_MAC; + else if (!strcmp (optarg, "amiga")) + opt.soundemu = SOUND_EMU_AMIGA; + else { + fprintf (stderr, "Sound emulation \"%s\" is " + "unknown\n", optarg); + exit (0); + } + break; +#endif + case 'v': + for (i = 0; cmp_versions[i].vers; i++) { + if (!strcmp (optarg, cmp_versions[i].string)) { + opt.emuversion = cmp_versions[i].vers; + break; + } + } + if (!opt.emuversion) { + printf ("Error: bad AGI version number \"%s\"\n", + optarg); + exit (-1); + } + break; +#ifdef MITSHM + case 'x': + opt.mitshm = FALSE; + break; +#endif + case 'h': + help (argc, argv); + default: + exit (-1); + } + } + + return ec; +} + +#endif /* USE_COMMAND_LINE */ + diff --git a/console.c b/console.c index c991af1..14c1012 100644 --- a/console.c +++ b/console.c @@ -1,958 +1,958 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999,2002 Stuart George and Claudio Matsuoka - * - * $Id: console.c,v 1.60 2003/07/10 23:47:30 almightyjustin Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include "sarien.h" - -#ifdef USE_CONSOLE - -/* - * The console has been added to sarien in version 0.4.9. The main - * interpreter engine has not been designed to have a console, and a few - * kludges were needed to make the console work. First of all, the main - * interpreter loop works at cycle level, not instruction level. To keep - * the illusion that the console is threaded, a console updating function - * is called from loops inside instructions such as get.string(). - */ - -#include -#include -#include -#include -#include -#include "agi.h" -#include "graphics.h" -#include "sprite.h" -#include "text.h" -#include "keyboard.h" -#include "opcodes.h" -#include "console.h" - -#define CONSOLE_LINES_ONSCREEN 20 -#define CONSOLE_PROMPT "$" -#define CONSOLE_CURSOR_HOLLOW 1 -#define CONSOLE_CURSOR_SOLID 2 -#define CONSOLE_CURSOR_EMPTY 3 -#define CONSOLE_COLOR 14 -#define CONSOLE_SCROLLUP_KEY KEY_PGUP -#define CONSOLE_SCROLLDN_KEY KEY_PGDN -#define CONSOLE_START_KEY KEY_HOME -#define CONSOLE_END_KEY KEY_END -#define CONSOLE_INPUT_SIZE 39 - - -struct console_command { - char cmd[8]; - char dsc[40]; - void (*handler)(void); -}; - -struct sarien_console console; -struct sarien_debug debug; - -/* This used to be a linked list, but we reduce total memory footprint - * by implementing it as a statically allocated array. - */ -#define MAX_CCMD 16 -static struct console_command ccmd_list[MAX_CCMD]; -static int num_ccmd = 0; - -static UINT8 has_console = 0; -static UINT8 console_input = 0; - -static char *_p0, *_p1, *_p2, *_p3, *_p4, *_p5; /* FIXME: array */ -static char _p[80]; -static int _pn; - - - -/* - * Console line management - */ - -static int first_line = 0; - -static void add_console_line (char *s) -{ - int last_line; - - last_line = (CONSOLE_LINES_BUFFER - 1 + first_line) % - CONSOLE_LINES_BUFFER; - - strncpy (console.line[last_line], s, CONSOLE_LINE_SIZE); - first_line %= CONSOLE_LINES_BUFFER; -} - -static char *get_console_line (int n) -{ - return console.line[(n + first_line) % CONSOLE_LINES_BUFFER]; -} - -static char *get_last_console_line () -{ - int last_line = (CONSOLE_LINES_BUFFER - 1 + first_line) % - CONSOLE_LINES_BUFFER; - - return console.line[last_line]; -} - - -/* - * Console command parsing - * 'o' commands added by Shaun Jackman , 11 Apr 2002 - */ - -static UINT8 console_parse (char *b) -{ - struct console_command *d; - int i; - - for (; *b && *b == ' '; b++) {} /* eat spaces */ - for (; *b && b[strlen(b) - 1] == ' '; b[strlen(b) - 1] = 0) {} - if (!*b) - return 0; - - /* get or set flag/var/obj values */ - if ((b[0] == 'f' || b[0] == 'v' || b[0] == 'o') && isdigit (b[1])) { - char *e; - int f = (int)strtoul (&b[1], &e, 10); - if (*e == 0) { - if (f >= 0 && f <= 255) { - switch (b[0]) { - case 'f': - report (getflag (f) ? - "TRUE\n" : "FALSE\n"); - break; - case 'v': - report ("%3d\n", getvar (f)); - break; - case 'o': - report ("%3d]%-24s(%3d)\n", f, object_name (f), - object_get_location (f)); - break; - } - return 0; - } - return -1; - } else if (*e == '=') { - int n = (int)strtoul (e + 1, NULL, 0); - switch (b[0]) { - case 'f': - setflag (f, !!n); - break; - case 'v': - setvar (f, n); - break; - case 'o': - object_set_location (f, n); - break; - } - return 0; - } - } - - /* tokenize the input line */ - if (strchr (b, ' ')) - strcpy (_p, strchr (b, ' ') + 1); - _p0 = strtok (b, " "); - _p1 = strtok (NULL, " "); - _p2 = strtok (NULL, " "); - _p3 = strtok (NULL, " "); - _p4 = strtok (NULL, " "); - _p5 = strtok (NULL, " "); - - /* set number of parameters. ugh, must rewrite this later */ - _pn = 5; - if (!_p5) _pn = 4; - if (!_p4) _pn = 3; - if (!_p3) _pn = 2; - if (!_p2) _pn = 1; - if (!_p1) _pn = 0; -#ifndef __APPLE__ - _D (_D_WARN "number of parameters: %d", _pn); -#endif - - for (i = 0; i < num_ccmd; i++) { - d = &ccmd_list[i]; - if (!strcmp (_p0, d->cmd) && d->handler) { - d->handler (); - return 0; - } - } - - for (i = 0; logic_names_cmd[i].name; i++) { - if (!strcmp (_p0, logic_names_cmd[i].name)) { - UINT8 p[16]; - if (_pn != logic_names_cmd[i].num_args) { - report ("AGI command wants %d arguments\n", - logic_names_cmd[i].num_args); - return 0; - } - p[0] = _p1 ? (char)strtoul (_p1, NULL, 0) : 0; - p[1] = _p2 ? (char)strtoul (_p2, NULL, 0) : 0; - p[2] = _p3 ? (char)strtoul (_p3, NULL, 0) : 0; - p[3] = _p4 ? (char)strtoul (_p4, NULL, 0) : 0; - p[4] = _p5 ? (char)strtoul (_p5, NULL, 0) : 0; -#ifndef __APPLE__ - _D (_D_WARN "ccmd: %s %d %d %d", - logic_names_cmd[i].name, p[0], p[1], p[2]); -#endif - - execute_agi_command (i, p); - - return 0; - } - } - - return -1; -} - - -/* - * Console commands - */ - -static void ccmd_help () -{ - int i; - - if (!_p1) { - report ("Command Description\n"); - report ("------- --------------------------------\n"); - for (i = 0; i < num_ccmd; i++) - report ("%-8s%s\n", ccmd_list[i].cmd, ccmd_list[i].dsc); - return; - } - - for (i = 0; i < num_ccmd; i++) { - if (!strcmp (ccmd_list[i].cmd, _p1) && ccmd_list[i].handler) { - report ("%s\n", ccmd_list[i].dsc); - return; - } - } - - report ("Unknown command or no help available\n"); - - return; -} - -static void ccmd_ver () -{ - report (VERSION "\n"); - return; -} - -static void ccmd_crc () -{ - char name[80]; - report ("0x%05x\n", game.crc); - if (match_crc (game.crc, get_config_file(), name, 80)) - report("%s\n", name); - else - report("Unknown game\n(config file: %s)\n", get_config_file()); - return; -} - -static void ccmd_load () -{ - stop_sound (); - - if (game.state >= STATE_LOADED) { - report ("AGI game already loaded.\n"); - return; - } - - report ("Opening \"%s\".\n", _p1); - if (agi_detect_game (_p1) == err_OK) { - game.state = STATE_RUNNING; - report ("AGI game successfully loaded.\n"); - console_prompt (); - return; - } - - report ("AGI game load failed.\n"); - return; -} - -static void ccmd_quit () -{ - deinit_video (); - /* deinit_machine (); */ - exit (0); -} - -#if 0 -static void ccmd_exec () -{ - if (game.state < STATE_LOADED) { - report ("No game loaded.\n"); - return; - } - - if (game.state >= STATE_RUNNING) { - report ("Game already running.\n"); - return; - } - - report ("Executing AGI game.\n"); - game.state = STATE_RUNNING; -} -#endif - -#ifdef USE_HIRES - -static void ccmd_hires () -{ - if (_pn != 1 || (strcmp (_p1, "on") && strcmp (_p1, "off"))) { - report ("Usage: hires on|off\n"); - return; - } - - opt.hires = !strcmp (_p1, "on"); - erase_both (); - show_pic (); - blit_both (); - return; -} - -#endif - -static void ccmd_agiver () -{ - int ver, maj, min; - - ver = agi_get_release (); - maj = (ver >> 12) & 0xf; - min = ver & 0xfff; - - report (maj <= 2 ? "%x.%03x\n" : "%x.002.%03x\n", maj, min); - return; -} - -static void ccmd_flags () -{ - int i, j; - - report (" "); - for (j = 0; j < 10; j++) - report ("%d ", j); - report ("\n"); - - for (i = 0; i < 255;) { - report ("%3d ", i); - for (j = 0; j < 10; j++, i++) { - report ("%c ", getflag (i) ? 'T' : 'F'); - } - report ("\n"); - } - return; -} - -static void ccmd_vars () -{ - int i, j; - - for (i = 0; i < 255;) { - for (j = 0; j < 5; j++, i++) { - report ("%03d:%3d ", i, getvar (i)); - } - report ("\n"); - } - return; -} - -#if 0 - -static void ccmd_say () -{ - setflag (F_entered_cli, TRUE); - dictionary_words (_p); -} - -static void ccmd_inv () -{ - unsigned int i, j; - - for (j = i = 0; i < game.num_objects; i++) { - if (object_get_location (i) == EGO_OWNED) { - report ("%3d]%-16.16s", i, object_name (i)); - if (j % 2) - report ("\n"); - j++; - } - } - if (j == 0) { - report ("none\n"); - return; - } - if (j % 2) - report ("\n"); -} - -#endif - -static void ccmd_objs () -{ - unsigned int i; - - for (i = 0; i < game.num_objects; i++) { - report ("%3d]%-24s(%3d)\n", i, object_name (i), - object_get_location (i)); - } - return; -} - -static void ccmd_opcode () -{ - if (_pn != 1 || (strcmp (_p1, "on") && strcmp (_p1, "off"))) { - report ("Usage: opcode on|off\n"); - return; - } - - debug.opcodes = !strcmp (_p1, "on"); - return; -} - -static void ccmd_logic0 () -{ - if (_pn != 1 || (strcmp (_p1, "on") && strcmp (_p1, "off"))) { - report ("Usage: logic0 on|off\n"); - return; - } - - debug.logic0 = !strcmp (_p1, "on"); - return; -} - -static void ccmd_trigger () -{ - if (_pn != 1 || (strcmp (_p1, "on") && strcmp (_p1, "off"))) { - report ("Usage: trigger on|off\n"); - return; - } - - debug.ignoretriggers = strcmp (_p1, "on"); - return; -} - -static void ccmd_step () -{ - debug.enabled = 1; - - if (_pn == 0) { - debug.steps = 1; - return; - } - - debug.steps = strtoul (_p1, NULL, 0); - return; -} - -static void ccmd_debug () -{ - debug.enabled = 1; - debug.steps = 0; - return; -} - -static void ccmd_cont () -{ - debug.enabled = 0; - debug.steps = 0; - return; -} - - -/* - * Register console commands - */ -static void console_cmd (char *cmd, char *dsc, void (*handler)(void)) -{ - assert (num_ccmd < MAX_CCMD); - - strcpy (ccmd_list[num_ccmd].cmd, cmd); - strcpy (ccmd_list[num_ccmd].dsc, dsc); - ccmd_list[num_ccmd].handler = handler; - - num_ccmd++; -} - - -/* Console reporting */ - -/* A slightly modified strtok() for report() */ -static char *get_token (char *s, char d) -{ - static char *x; - char *n, *m; - - if (s) - x = s; - - m = x; - n = strchr (x, d); - - if (n) { - *n = 0; - x = n + 1; - } else { - x = strchr (x, 0); - } - - return m; -} - - -static void build_console_lines (int n) -{ - int j, y1; - char *line; - - clear_console_screen (GFX_HEIGHT - n * 10); - - for (j = CONSOLE_LINES_ONSCREEN - n; j < CONSOLE_LINES_ONSCREEN; j++) { - line = get_console_line (console.first_line + j); - print_text_console (line, 0, j, strlen (line) + 1, - CONSOLE_COLOR, 0); - } - - y1 = console.y - n * 10; - if (y1 < 0) - y1 = 0; - - /* CM: - * This will cause blinking when using menus+console, but this - * function is called by report() which can be called from any - * point with or without sprites placed. If we protect the - * flush_block() call with redraw/release sprites cloning will - * happen when activating the console. This could be fixed by - * keeping a control flag in redraw/release to not do the - * actions twice, but I don't want to do that -- not yet. - */ - flush_block (0, y1, GFX_WIDTH - 1, console.y); -} - - -/* - * Public functions - */ - -int console_init () -{ - console_cmd ("agiver", "Show emulated Sierra AGI version", ccmd_agiver); - console_cmd ("cont", "Resume interpreter execution", ccmd_cont); - console_cmd ("debug", "Stop interpreter execution", ccmd_debug); - console_cmd ("crc", "Show AGI game CRC", ccmd_crc); -#if 0 - console_cmd ("exec", "Execute loaded AGI game", ccmd_exec); -#endif - console_cmd ("flags", "Dump all AGI flags", ccmd_flags); - console_cmd ("help", "List available commands", ccmd_help); -#ifdef USE_HIRES - console_cmd ("hires", "Turn hi-res mode on/off", ccmd_hires); -#endif - console_cmd ("logic0", "Turn logic 0 debugging on/off", ccmd_logic0); - console_cmd ("load", "Load AGI game", ccmd_load); - console_cmd ("objs", "List all objects and locations", ccmd_objs); - console_cmd ("opcode", "Turn opcodes on/off in debug", ccmd_opcode); - console_cmd ("quit", "Quit the interpreter", ccmd_quit); -#if 0 - console_cmd ("inv", "List current inventory", ccmd_inv); - console_cmd ("say", "Pass argument to the AGI parser", ccmd_say); -#endif - console_cmd ("step", "Execute the next AGI instruction", ccmd_step); - console_cmd ("trigger","Turn trigger lines on/off", ccmd_trigger); - console_cmd ("vars", "Dump all AGI variables", ccmd_vars); - console_cmd ("ver", "Show interpreter version", ccmd_ver); - - console.active = 1; - console.input_active = 1; - console.index = 0; - console.max_y = 150; - console.y = console.max_y; - console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN; - - debug.enabled = 0; - debug.opcodes = 0; - debug.logic0 = 1; - debug.priority = 0; - - has_console = 1; - clear_screen (0); - - return err_OK; -} - -static void build_console_layer () -{ - build_console_lines (console.max_y / 10); -} - - -void report (char *message, ...) -{ - char x[512], y[512], z[64], *msg, *n; - va_list args; - int i, s, len; - - if (!has_console) - return; - - va_start (args, message); -#ifdef HAVE_VSNPRINTF - vsnprintf (y, 510, (char*)message, args); -#else - vsprintf (y, (char*)message, args); -#endif - va_end (args); - - printf("%s\n", y); - - if (console_input) { - strcpy (z, get_last_console_line ()); - strcpy (x, ">"); - } else { - strcpy (x, get_last_console_line ()); - } - - strcat (x, y); - - len = 40; - msg = n = word_wrap_string (x, &len); - - for (s = 1; *n; n++) - if (*n == '\n') - s++; - - add_console_line (get_token (msg, '\n')); - for (i = 1; i < s; i++) { - first_line++; - n = get_token (NULL, '\n'); - add_console_line (n); - } - - console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN; - - if (console_input) { - add_console_line (z); - } - - /* Build layer */ - if (console.y) { - if (s > 1) - build_console_layer (); - else - build_console_lines (1); - } - - free (msg); - - do_update (); -} - - - -void console_cycle () -{ - static int old_y = 0; - static int blink = 0; - static char cursor[] = " "; - - /* If no game has been loaded, keep the console visible! */ - if (game.state < STATE_RUNNING) { - console.active = 1; - console.count = 10; - } - - /* Initial console auto-hide timer */ - if (console.count > 0) - console.count--; - if (console.count == 0) { - console.active = 0; - console.count = -1; - } - - if (console.active) { - if (console.y < console.max_y) - console.y += 15; - else - console.y = console.max_y; - } else { - console.count = -1; - - if (console.y > 0) - console.y -= 15; - else - console.y = 0; - } - - /* console shading animation */ - if (old_y != console.y) { - int y = console.y; - if (old_y > console.y) { - /* going up */ - y = old_y; - } - flush_block (0, 0, GFX_WIDTH - 1, y); - old_y = console.y; - } - - blink++; - blink %= 16; - if (console.input_active) { - *cursor = blink < 8 ? - CONSOLE_CURSOR_SOLID : CONSOLE_CURSOR_EMPTY; - } else { - *cursor = CONSOLE_CURSOR_HOLLOW; - } - if (console.y > 0 && console.first_line == CONSOLE_LINES_BUFFER - - CONSOLE_LINES_ONSCREEN) - { - SINT16 y1 = console.y - 10, y2 = console.y - 1; - if (y1 < 0) y1 = 0; - if (y2 < 0) y2 = 0; - print_text_console (cursor, - (1 + console.index), 19, 2, CONSOLE_COLOR, 0); - flush_block ((1 + console.index) * 8, y1, - (1 + console.index) * 8 + 7, y2 - 1); - } - - do_update (); -} - - -/* Return TRUE if key was handled */ -int console_keyhandler (int k) -{ - static char buffer[CONSOLE_INPUT_SIZE]; - SINT16 y1,y2; - char m[2]; - -#ifdef USE_MOUSE - /* Right button switches console on/off*/ - if (!opt.agimouse) /* AGI Mouse uses right button */ - if (k == BUTTON_RIGHT) - k = CONSOLE_ACTIVATE_KEY; -#endif - - if (!console.active) { - if (k == CONSOLE_ACTIVATE_KEY) { - console.active = 1; - return TRUE; - } - return FALSE; - } - - if (!console.input_active) { - if (k == CONSOLE_SWITCH_KEY) { - console.input_active = 1; - return TRUE; - } - if (k == CONSOLE_ACTIVATE_KEY) { - console.active = 0; - return TRUE; - } - return FALSE; - } - - y1 = console.y - 10; - y2 = console.y - 1; - - if (y1 < 0) y1 = 0; - if (y2 < 0) y2 = 0; - -#ifdef USE_MOUSE - /* Ignore left button in console */ - if (k == BUTTON_LEFT) - return TRUE; -#endif - - /* this code breaks scrolling up, maybe it shoud only be executed - * in the default case? - */ - if (k) { - /* make sure it's not enter or a scroll key */ - if ((k != KEY_ENTER) && (k != CONSOLE_SCROLLUP_KEY) && - (k != CONSOLE_SCROLLDN_KEY) && (k != CONSOLE_START_KEY)) { - /* on any other input reset the console to the bottom */ - if (console.first_line != CONSOLE_LINES_BUFFER - - CONSOLE_LINES_ONSCREEN) { - console.first_line = CONSOLE_LINES_BUFFER - - CONSOLE_LINES_ONSCREEN; - build_console_layer (); - } - console.count = -1; - } - } - - switch (k) { - case KEY_ENTER: - console_lock (); - console.index = 0; - report ("\n"); - - if (console_parse (buffer) != 0) - report ("What? Where?\n"); - - buffer[0] = 0; - console_prompt (); - break; - case KEY_BACKSPACE: { - char *x; - if (!console.index) - break; - x = get_last_console_line (); - x[console.index] = 0; - *m = CONSOLE_CURSOR_EMPTY; - print_text_console (m, (console.index+1), 19, 2, - CONSOLE_COLOR, 0); - flush_block ((console.index + 1) * CHAR_COLS, y1, - (console.index + 1 + 1) * CHAR_COLS - 1, y2); - console.index--; - buffer[console.index] = 0; - } break; - case CONSOLE_ACTIVATE_KEY: - console.active = !console.active; - if (console.active) - build_console_layer (); - break; - case CONSOLE_SWITCH_KEY: - console.count = -1; - if (console.y) - console.input_active = !console.input_active; - break; - case CONSOLE_SCROLLUP_KEY: - console.count = -1; - if (!console.y) - break; - if (console.first_line > (CONSOLE_LINES_ONSCREEN / 2)) - console.first_line -= CONSOLE_LINES_ONSCREEN / 2; - else - console.first_line = 0; - build_console_layer (); - break; - case CONSOLE_SCROLLDN_KEY: - console.count = -1; - if (!console.y) - break; - if (console.first_line < (CONSOLE_LINES_BUFFER - - CONSOLE_LINES_ONSCREEN - CONSOLE_LINES_ONSCREEN / 2)) - console.first_line += CONSOLE_LINES_ONSCREEN / 2; - else - console.first_line = CONSOLE_LINES_BUFFER - - CONSOLE_LINES_ONSCREEN; - build_console_layer (); - break; - case CONSOLE_START_KEY: - console.count = -1; - if (console.y) - console.first_line = 0; - break; - case CONSOLE_END_KEY: - console.count = -1; - if (console.y) - console.first_line = CONSOLE_LINES_BUFFER - - CONSOLE_LINES_ONSCREEN; - break; - default: - if (k >= 0x20 && k <= 0x7f && (console.index < CONSOLE_INPUT_SIZE - 2)) - { - char l[42]; - buffer[console.index] = k; - *m=k;m[1]=0; - console.index++; - - sprintf (l, "%s%c", get_last_console_line (), k); - strncpy (get_last_console_line (), l, - CONSOLE_LINE_SIZE); - - buffer[console.index] = 0; - print_text_console (m, console.index, 19, 2, - CONSOLE_COLOR, 0); - flush_block (console.index*8, y1, console.index*8+7, y2); - } - break; - } - - do_update (); - - return TRUE; -} - -void console_prompt () -{ - report (CONSOLE_PROMPT); - console_input = 1; -} - - -void console_lock () -{ - console_input = 0; -} - - -#else - -void *debug; - -#include -#include -void report (char *message, ...) -{ - char y[512]; - va_list args; - - va_start (args, message); -// vsnprintf (y, 510, (char*)message, args); - vsprintf (y, (char*)message, args); - va_end (args); - - /* dummy */ - printf("%s\n", y); -} - -int console_init () -{ - return 0; -} - -/* Date: Sun, 14 Oct 2001 23:02:02 -0700 - * From: Vasyl Tsvirkunov - * - * This one was rather harmless and affected only builds without console. - * In SQ1&2 (and likely some others) name entry screen did not update - * properly. The bug caused by implicit assumption in cycle.c that - * console_cycle() updates the screen. Well, it does, if console is enabled. - * The fix is simple. In the second version of console_cycle() in console.c - * (the "dummy" one) add call to do_update(). The thing raises some - * questions about overall architecture of main cycle, but otherwise the fix - * works just fine. - */ -void console_cycle () -{ - do_update (); -} - -void console_lock () -{ - /* dummy */ -} - -void console_prompt () -{ - /* dummy */ -} - -int console_keyhandler (int i) -{ - return FALSE; -} - -#endif /* USE_CONSOLE */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999,2002 Stuart George and Claudio Matsuoka + * + * $Id: console.c,v 1.60 2003/07/10 23:47:30 almightyjustin Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include "sarien.h" + +#ifdef USE_CONSOLE + +/* + * The console has been added to sarien in version 0.4.9. The main + * interpreter engine has not been designed to have a console, and a few + * kludges were needed to make the console work. First of all, the main + * interpreter loop works at cycle level, not instruction level. To keep + * the illusion that the console is threaded, a console updating function + * is called from loops inside instructions such as get.string(). + */ + +#include +#include +#include +#include +#include +#include "agi.h" +#include "graphics.h" +#include "sprite.h" +#include "text.h" +#include "keyboard.h" +#include "opcodes.h" +#include "console.h" + +#define CONSOLE_LINES_ONSCREEN 20 +#define CONSOLE_PROMPT "$" +#define CONSOLE_CURSOR_HOLLOW 1 +#define CONSOLE_CURSOR_SOLID 2 +#define CONSOLE_CURSOR_EMPTY 3 +#define CONSOLE_COLOR 14 +#define CONSOLE_SCROLLUP_KEY KEY_PGUP +#define CONSOLE_SCROLLDN_KEY KEY_PGDN +#define CONSOLE_START_KEY KEY_HOME +#define CONSOLE_END_KEY KEY_END +#define CONSOLE_INPUT_SIZE 39 + + +struct console_command { + char cmd[8]; + char dsc[40]; + void (*handler)(void); +}; + +struct sarien_console console; +struct sarien_debug debug; + +/* This used to be a linked list, but we reduce total memory footprint + * by implementing it as a statically allocated array. + */ +#define MAX_CCMD 16 +static struct console_command ccmd_list[MAX_CCMD]; +static int num_ccmd = 0; + +static UINT8 has_console = 0; +static UINT8 console_input = 0; + +static char *_p0, *_p1, *_p2, *_p3, *_p4, *_p5; /* FIXME: array */ +static char _p[80]; +static int _pn; + + + +/* + * Console line management + */ + +static int first_line = 0; + +static void add_console_line (char *s) +{ + int last_line; + + last_line = (CONSOLE_LINES_BUFFER - 1 + first_line) % + CONSOLE_LINES_BUFFER; + + strncpy (console.line[last_line], s, CONSOLE_LINE_SIZE); + first_line %= CONSOLE_LINES_BUFFER; +} + +static char *get_console_line (int n) +{ + return console.line[(n + first_line) % CONSOLE_LINES_BUFFER]; +} + +static char *get_last_console_line () +{ + int last_line = (CONSOLE_LINES_BUFFER - 1 + first_line) % + CONSOLE_LINES_BUFFER; + + return console.line[last_line]; +} + + +/* + * Console command parsing + * 'o' commands added by Shaun Jackman , 11 Apr 2002 + */ + +static UINT8 console_parse (char *b) +{ + struct console_command *d; + int i; + + for (; *b && *b == ' '; b++) {} /* eat spaces */ + for (; *b && b[strlen(b) - 1] == ' '; b[strlen(b) - 1] = 0) {} + if (!*b) + return 0; + + /* get or set flag/var/obj values */ + if ((b[0] == 'f' || b[0] == 'v' || b[0] == 'o') && isdigit (b[1])) { + char *e; + int f = (int)strtoul (&b[1], &e, 10); + if (*e == 0) { + if (f >= 0 && f <= 255) { + switch (b[0]) { + case 'f': + report (getflag (f) ? + "TRUE\n" : "FALSE\n"); + break; + case 'v': + report ("%3d\n", getvar (f)); + break; + case 'o': + report ("%3d]%-24s(%3d)\n", f, object_name (f), + object_get_location (f)); + break; + } + return 0; + } + return -1; + } else if (*e == '=') { + int n = (int)strtoul (e + 1, NULL, 0); + switch (b[0]) { + case 'f': + setflag (f, !!n); + break; + case 'v': + setvar (f, n); + break; + case 'o': + object_set_location (f, n); + break; + } + return 0; + } + } + + /* tokenize the input line */ + if (strchr (b, ' ')) + strcpy (_p, strchr (b, ' ') + 1); + _p0 = strtok (b, " "); + _p1 = strtok (NULL, " "); + _p2 = strtok (NULL, " "); + _p3 = strtok (NULL, " "); + _p4 = strtok (NULL, " "); + _p5 = strtok (NULL, " "); + + /* set number of parameters. ugh, must rewrite this later */ + _pn = 5; + if (!_p5) _pn = 4; + if (!_p4) _pn = 3; + if (!_p3) _pn = 2; + if (!_p2) _pn = 1; + if (!_p1) _pn = 0; +#ifndef __APPLE__ + _D (_D_WARN "number of parameters: %d", _pn); +#endif + + for (i = 0; i < num_ccmd; i++) { + d = &ccmd_list[i]; + if (!strcmp (_p0, d->cmd) && d->handler) { + d->handler (); + return 0; + } + } + + for (i = 0; logic_names_cmd[i].name; i++) { + if (!strcmp (_p0, logic_names_cmd[i].name)) { + UINT8 p[16]; + if (_pn != logic_names_cmd[i].num_args) { + report ("AGI command wants %d arguments\n", + logic_names_cmd[i].num_args); + return 0; + } + p[0] = _p1 ? (char)strtoul (_p1, NULL, 0) : 0; + p[1] = _p2 ? (char)strtoul (_p2, NULL, 0) : 0; + p[2] = _p3 ? (char)strtoul (_p3, NULL, 0) : 0; + p[3] = _p4 ? (char)strtoul (_p4, NULL, 0) : 0; + p[4] = _p5 ? (char)strtoul (_p5, NULL, 0) : 0; +#ifndef __APPLE__ + _D (_D_WARN "ccmd: %s %d %d %d", + logic_names_cmd[i].name, p[0], p[1], p[2]); +#endif + + execute_agi_command (i, p); + + return 0; + } + } + + return -1; +} + + +/* + * Console commands + */ + +static void ccmd_help () +{ + int i; + + if (!_p1) { + report ("Command Description\n"); + report ("------- --------------------------------\n"); + for (i = 0; i < num_ccmd; i++) + report ("%-8s%s\n", ccmd_list[i].cmd, ccmd_list[i].dsc); + return; + } + + for (i = 0; i < num_ccmd; i++) { + if (!strcmp (ccmd_list[i].cmd, _p1) && ccmd_list[i].handler) { + report ("%s\n", ccmd_list[i].dsc); + return; + } + } + + report ("Unknown command or no help available\n"); + + return; +} + +static void ccmd_ver () +{ + report (VERSION "\n"); + return; +} + +static void ccmd_crc () +{ + char name[80]; + report ("0x%05x\n", game.crc); + if (match_crc (game.crc, get_config_file(), name, 80)) + report("%s\n", name); + else + report("Unknown game\n(config file: %s)\n", get_config_file()); + return; +} + +static void ccmd_load () +{ + stop_sound (); + + if (game.state >= STATE_LOADED) { + report ("AGI game already loaded.\n"); + return; + } + + report ("Opening \"%s\".\n", _p1); + if (agi_detect_game (_p1) == err_OK) { + game.state = STATE_RUNNING; + report ("AGI game successfully loaded.\n"); + console_prompt (); + return; + } + + report ("AGI game load failed.\n"); + return; +} + +static void ccmd_quit () +{ + deinit_video (); + /* deinit_machine (); */ + exit (0); +} + +#if 0 +static void ccmd_exec () +{ + if (game.state < STATE_LOADED) { + report ("No game loaded.\n"); + return; + } + + if (game.state >= STATE_RUNNING) { + report ("Game already running.\n"); + return; + } + + report ("Executing AGI game.\n"); + game.state = STATE_RUNNING; +} +#endif + +#ifdef USE_HIRES + +static void ccmd_hires () +{ + if (_pn != 1 || (strcmp (_p1, "on") && strcmp (_p1, "off"))) { + report ("Usage: hires on|off\n"); + return; + } + + opt.hires = !strcmp (_p1, "on"); + erase_both (); + show_pic (); + blit_both (); + return; +} + +#endif + +static void ccmd_agiver () +{ + int ver, maj, min; + + ver = agi_get_release (); + maj = (ver >> 12) & 0xf; + min = ver & 0xfff; + + report (maj <= 2 ? "%x.%03x\n" : "%x.002.%03x\n", maj, min); + return; +} + +static void ccmd_flags () +{ + int i, j; + + report (" "); + for (j = 0; j < 10; j++) + report ("%d ", j); + report ("\n"); + + for (i = 0; i < 255;) { + report ("%3d ", i); + for (j = 0; j < 10; j++, i++) { + report ("%c ", getflag (i) ? 'T' : 'F'); + } + report ("\n"); + } + return; +} + +static void ccmd_vars () +{ + int i, j; + + for (i = 0; i < 255;) { + for (j = 0; j < 5; j++, i++) { + report ("%03d:%3d ", i, getvar (i)); + } + report ("\n"); + } + return; +} + +#if 0 + +static void ccmd_say () +{ + setflag (F_entered_cli, TRUE); + dictionary_words (_p); +} + +static void ccmd_inv () +{ + unsigned int i, j; + + for (j = i = 0; i < game.num_objects; i++) { + if (object_get_location (i) == EGO_OWNED) { + report ("%3d]%-16.16s", i, object_name (i)); + if (j % 2) + report ("\n"); + j++; + } + } + if (j == 0) { + report ("none\n"); + return; + } + if (j % 2) + report ("\n"); +} + +#endif + +static void ccmd_objs () +{ + unsigned int i; + + for (i = 0; i < game.num_objects; i++) { + report ("%3d]%-24s(%3d)\n", i, object_name (i), + object_get_location (i)); + } + return; +} + +static void ccmd_opcode () +{ + if (_pn != 1 || (strcmp (_p1, "on") && strcmp (_p1, "off"))) { + report ("Usage: opcode on|off\n"); + return; + } + + debug.opcodes = !strcmp (_p1, "on"); + return; +} + +static void ccmd_logic0 () +{ + if (_pn != 1 || (strcmp (_p1, "on") && strcmp (_p1, "off"))) { + report ("Usage: logic0 on|off\n"); + return; + } + + debug.logic0 = !strcmp (_p1, "on"); + return; +} + +static void ccmd_trigger () +{ + if (_pn != 1 || (strcmp (_p1, "on") && strcmp (_p1, "off"))) { + report ("Usage: trigger on|off\n"); + return; + } + + debug.ignoretriggers = strcmp (_p1, "on"); + return; +} + +static void ccmd_step () +{ + debug.enabled = 1; + + if (_pn == 0) { + debug.steps = 1; + return; + } + + debug.steps = strtoul (_p1, NULL, 0); + return; +} + +static void ccmd_debug () +{ + debug.enabled = 1; + debug.steps = 0; + return; +} + +static void ccmd_cont () +{ + debug.enabled = 0; + debug.steps = 0; + return; +} + + +/* + * Register console commands + */ +static void console_cmd (char *cmd, char *dsc, void (*handler)(void)) +{ + assert (num_ccmd < MAX_CCMD); + + strcpy (ccmd_list[num_ccmd].cmd, cmd); + strcpy (ccmd_list[num_ccmd].dsc, dsc); + ccmd_list[num_ccmd].handler = handler; + + num_ccmd++; +} + + +/* Console reporting */ + +/* A slightly modified strtok() for report() */ +static char *get_token (char *s, char d) +{ + static char *x; + char *n, *m; + + if (s) + x = s; + + m = x; + n = strchr (x, d); + + if (n) { + *n = 0; + x = n + 1; + } else { + x = strchr (x, 0); + } + + return m; +} + + +static void build_console_lines (int n) +{ + int j, y1; + char *line; + + clear_console_screen (GFX_HEIGHT - n * 10); + + for (j = CONSOLE_LINES_ONSCREEN - n; j < CONSOLE_LINES_ONSCREEN; j++) { + line = get_console_line (console.first_line + j); + print_text_console (line, 0, j, strlen (line) + 1, + CONSOLE_COLOR, 0); + } + + y1 = console.y - n * 10; + if (y1 < 0) + y1 = 0; + + /* CM: + * This will cause blinking when using menus+console, but this + * function is called by report() which can be called from any + * point with or without sprites placed. If we protect the + * flush_block() call with redraw/release sprites cloning will + * happen when activating the console. This could be fixed by + * keeping a control flag in redraw/release to not do the + * actions twice, but I don't want to do that -- not yet. + */ + flush_block (0, y1, GFX_WIDTH - 1, console.y); +} + + +/* + * Public functions + */ + +int console_init () +{ + console_cmd ("agiver", "Show emulated Sierra AGI version", ccmd_agiver); + console_cmd ("cont", "Resume interpreter execution", ccmd_cont); + console_cmd ("debug", "Stop interpreter execution", ccmd_debug); + console_cmd ("crc", "Show AGI game CRC", ccmd_crc); +#if 0 + console_cmd ("exec", "Execute loaded AGI game", ccmd_exec); +#endif + console_cmd ("flags", "Dump all AGI flags", ccmd_flags); + console_cmd ("help", "List available commands", ccmd_help); +#ifdef USE_HIRES + console_cmd ("hires", "Turn hi-res mode on/off", ccmd_hires); +#endif + console_cmd ("logic0", "Turn logic 0 debugging on/off", ccmd_logic0); + console_cmd ("load", "Load AGI game", ccmd_load); + console_cmd ("objs", "List all objects and locations", ccmd_objs); + console_cmd ("opcode", "Turn opcodes on/off in debug", ccmd_opcode); + console_cmd ("quit", "Quit the interpreter", ccmd_quit); +#if 0 + console_cmd ("inv", "List current inventory", ccmd_inv); + console_cmd ("say", "Pass argument to the AGI parser", ccmd_say); +#endif + console_cmd ("step", "Execute the next AGI instruction", ccmd_step); + console_cmd ("trigger","Turn trigger lines on/off", ccmd_trigger); + console_cmd ("vars", "Dump all AGI variables", ccmd_vars); + console_cmd ("ver", "Show interpreter version", ccmd_ver); + + console.active = 1; + console.input_active = 1; + console.index = 0; + console.max_y = 150; + console.y = console.max_y; + console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN; + + debug.enabled = 0; + debug.opcodes = 0; + debug.logic0 = 1; + debug.priority = 0; + + has_console = 1; + clear_screen (0); + + return err_OK; +} + +static void build_console_layer () +{ + build_console_lines (console.max_y / 10); +} + + +void report (char *message, ...) +{ + char x[512], y[512], z[64], *msg, *n; + va_list args; + int i, s, len; + + if (!has_console) + return; + + va_start (args, message); +#ifdef HAVE_VSNPRINTF + vsnprintf (y, 510, (char*)message, args); +#else + vsprintf (y, (char*)message, args); +#endif + va_end (args); + + printf("%s\n", y); + + if (console_input) { + strcpy (z, get_last_console_line ()); + strcpy (x, ">"); + } else { + strcpy (x, get_last_console_line ()); + } + + strcat (x, y); + + len = 40; + msg = n = word_wrap_string (x, &len); + + for (s = 1; *n; n++) + if (*n == '\n') + s++; + + add_console_line (get_token (msg, '\n')); + for (i = 1; i < s; i++) { + first_line++; + n = get_token (NULL, '\n'); + add_console_line (n); + } + + console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN; + + if (console_input) { + add_console_line (z); + } + + /* Build layer */ + if (console.y) { + if (s > 1) + build_console_layer (); + else + build_console_lines (1); + } + + free (msg); + + do_update (); +} + + + +void console_cycle () +{ + static int old_y = 0; + static int blink = 0; + static char cursor[] = " "; + + /* If no game has been loaded, keep the console visible! */ + if (game.state < STATE_RUNNING) { + console.active = 1; + console.count = 10; + } + + /* Initial console auto-hide timer */ + if (console.count > 0) + console.count--; + if (console.count == 0) { + console.active = 0; + console.count = -1; + } + + if (console.active) { + if (console.y < console.max_y) + console.y += 15; + else + console.y = console.max_y; + } else { + console.count = -1; + + if (console.y > 0) + console.y -= 15; + else + console.y = 0; + } + + /* console shading animation */ + if (old_y != console.y) { + int y = console.y; + if (old_y > console.y) { + /* going up */ + y = old_y; + } + flush_block (0, 0, GFX_WIDTH - 1, y); + old_y = console.y; + } + + blink++; + blink %= 16; + if (console.input_active) { + *cursor = blink < 8 ? + CONSOLE_CURSOR_SOLID : CONSOLE_CURSOR_EMPTY; + } else { + *cursor = CONSOLE_CURSOR_HOLLOW; + } + if (console.y > 0 && console.first_line == CONSOLE_LINES_BUFFER - + CONSOLE_LINES_ONSCREEN) + { + SINT16 y1 = console.y - 10, y2 = console.y - 1; + if (y1 < 0) y1 = 0; + if (y2 < 0) y2 = 0; + print_text_console (cursor, + (1 + console.index), 19, 2, CONSOLE_COLOR, 0); + flush_block ((1 + console.index) * 8, y1, + (1 + console.index) * 8 + 7, y2 - 1); + } + + do_update (); +} + + +/* Return TRUE if key was handled */ +int console_keyhandler (int k) +{ + static char buffer[CONSOLE_INPUT_SIZE]; + SINT16 y1,y2; + char m[2]; + +#ifdef USE_MOUSE + /* Right button switches console on/off*/ + if (!opt.agimouse) /* AGI Mouse uses right button */ + if (k == BUTTON_RIGHT) + k = CONSOLE_ACTIVATE_KEY; +#endif + + if (!console.active) { + if (k == CONSOLE_ACTIVATE_KEY) { + console.active = 1; + return TRUE; + } + return FALSE; + } + + if (!console.input_active) { + if (k == CONSOLE_SWITCH_KEY) { + console.input_active = 1; + return TRUE; + } + if (k == CONSOLE_ACTIVATE_KEY) { + console.active = 0; + return TRUE; + } + return FALSE; + } + + y1 = console.y - 10; + y2 = console.y - 1; + + if (y1 < 0) y1 = 0; + if (y2 < 0) y2 = 0; + +#ifdef USE_MOUSE + /* Ignore left button in console */ + if (k == BUTTON_LEFT) + return TRUE; +#endif + + /* this code breaks scrolling up, maybe it shoud only be executed + * in the default case? + */ + if (k) { + /* make sure it's not enter or a scroll key */ + if ((k != KEY_ENTER) && (k != CONSOLE_SCROLLUP_KEY) && + (k != CONSOLE_SCROLLDN_KEY) && (k != CONSOLE_START_KEY)) { + /* on any other input reset the console to the bottom */ + if (console.first_line != CONSOLE_LINES_BUFFER - + CONSOLE_LINES_ONSCREEN) { + console.first_line = CONSOLE_LINES_BUFFER - + CONSOLE_LINES_ONSCREEN; + build_console_layer (); + } + console.count = -1; + } + } + + switch (k) { + case KEY_ENTER: + console_lock (); + console.index = 0; + report ("\n"); + + if (console_parse (buffer) != 0) + report ("What? Where?\n"); + + buffer[0] = 0; + console_prompt (); + break; + case KEY_BACKSPACE: { + char *x; + if (!console.index) + break; + x = get_last_console_line (); + x[console.index] = 0; + *m = CONSOLE_CURSOR_EMPTY; + print_text_console (m, (console.index+1), 19, 2, + CONSOLE_COLOR, 0); + flush_block ((console.index + 1) * CHAR_COLS, y1, + (console.index + 1 + 1) * CHAR_COLS - 1, y2); + console.index--; + buffer[console.index] = 0; + } break; + case CONSOLE_ACTIVATE_KEY: + console.active = !console.active; + if (console.active) + build_console_layer (); + break; + case CONSOLE_SWITCH_KEY: + console.count = -1; + if (console.y) + console.input_active = !console.input_active; + break; + case CONSOLE_SCROLLUP_KEY: + console.count = -1; + if (!console.y) + break; + if (console.first_line > (CONSOLE_LINES_ONSCREEN / 2)) + console.first_line -= CONSOLE_LINES_ONSCREEN / 2; + else + console.first_line = 0; + build_console_layer (); + break; + case CONSOLE_SCROLLDN_KEY: + console.count = -1; + if (!console.y) + break; + if (console.first_line < (CONSOLE_LINES_BUFFER - + CONSOLE_LINES_ONSCREEN - CONSOLE_LINES_ONSCREEN / 2)) + console.first_line += CONSOLE_LINES_ONSCREEN / 2; + else + console.first_line = CONSOLE_LINES_BUFFER - + CONSOLE_LINES_ONSCREEN; + build_console_layer (); + break; + case CONSOLE_START_KEY: + console.count = -1; + if (console.y) + console.first_line = 0; + break; + case CONSOLE_END_KEY: + console.count = -1; + if (console.y) + console.first_line = CONSOLE_LINES_BUFFER - + CONSOLE_LINES_ONSCREEN; + break; + default: + if (k >= 0x20 && k <= 0x7f && (console.index < CONSOLE_INPUT_SIZE - 2)) + { + char l[42]; + buffer[console.index] = k; + *m=k;m[1]=0; + console.index++; + + sprintf (l, "%s%c", get_last_console_line (), k); + strncpy (get_last_console_line (), l, + CONSOLE_LINE_SIZE); + + buffer[console.index] = 0; + print_text_console (m, console.index, 19, 2, + CONSOLE_COLOR, 0); + flush_block (console.index*8, y1, console.index*8+7, y2); + } + break; + } + + do_update (); + + return TRUE; +} + +void console_prompt () +{ + report (CONSOLE_PROMPT); + console_input = 1; +} + + +void console_lock () +{ + console_input = 0; +} + + +#else + +void *debug; + +#include +#include +void report (char *message, ...) +{ + char y[512]; + va_list args; + + va_start (args, message); +// vsnprintf (y, 510, (char*)message, args); + vsprintf (y, (char*)message, args); + va_end (args); + + /* dummy */ + printf("%s\n", y); +} + +int console_init () +{ + return 0; +} + +/* Date: Sun, 14 Oct 2001 23:02:02 -0700 + * From: Vasyl Tsvirkunov + * + * This one was rather harmless and affected only builds without console. + * In SQ1&2 (and likely some others) name entry screen did not update + * properly. The bug caused by implicit assumption in cycle.c that + * console_cycle() updates the screen. Well, it does, if console is enabled. + * The fix is simple. In the second version of console_cycle() in console.c + * (the "dummy" one) add call to do_update(). The thing raises some + * questions about overall architecture of main cycle, but otherwise the fix + * works just fine. + */ +void console_cycle () +{ + do_update (); +} + +void console_lock () +{ + /* dummy */ +} + +void console_prompt () +{ + /* dummy */ +} + +int console_keyhandler (int i) +{ + return FALSE; +} + +#endif /* USE_CONSOLE */ diff --git a/cycle.c b/cycle.c index e295dc3..64b62da 100644 --- a/cycle.c +++ b/cycle.c @@ -1,423 +1,422 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999, 2007-2003 Stuart George and Claudio Matsuoka - * - * $Id: cycle.c,v 1.103 2003/08/17 20:33:56 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include "sarien.h" -#include "agi.h" -#include "text.h" -#include "sprite.h" -#include "graphics.h" -#include "keyboard.h" -#include "menu.h" -#include "savegame.h" - -#define TICK_SECONDS 20 - -#ifdef USE_MOUSE -struct mouse mouse; -#endif - -#ifndef MACOSX_SDL -volatile UINT32 clock_ticks; -volatile UINT32 clock_count; -#endif - - -/** - * Set up new room. - * This function is called when ego enters a new room. - * @param n room number - */ -void new_room (int n) -{ - struct vt_entry *v; - int i; - - _D (_D_WARN "*** room %d ***", n); - stop_sound (); - - i = 0; - for_each_vt_entry (v) { - v->entry = i++; - v->flags &= ~(ANIMATED|DRAWN); - v->flags |= UPDATE; - v->step_time = 1; - v->step_time_count = 1; - v->cycle_time = 1; - v->cycle_time_count = 1; - v->step_size = 1; - } - - agi_unload_resources (); - - game.player_control = TRUE; - game.block.active = FALSE; - game.horizon = 36; - game.vars[V_prev_room] = game.vars[V_cur_room]; - game.vars[V_cur_room] = n; - game.vars[V_border_touch_obj] = 0; - game.vars[V_border_code] = 0; - game.vars[V_ego_view_resource] = game.view_table[0].current_view; - - agi_load_resource (rLOGIC, n); - - /* Reposition ego in the new room */ - switch (game.vars[V_border_touch_ego]) { - case 1: - game.view_table[0].y_pos = _HEIGHT - 1; - break; - case 2: - game.view_table[0].x_pos = 0; - break; - case 3: - game.view_table[0].y_pos = HORIZON + 1; - break; - case 4: - game.view_table[0].x_pos = _WIDTH - game.view_table[0].x_size; - break; - } - - game.vars[V_border_touch_ego] = 0; - setflag (F_new_room_exec, TRUE); - - game.exit_all_logics = TRUE; - - write_status (); - write_prompt (); -} - -static void reset_controllers () -{ - int i; - - for (i = 0; i < MAX_DIRS; i++) { - game.ev_keyp[i].occured = FALSE; - } -} - -static void interpret_cycle () -{ - int old_sound, old_score; - - if (game.player_control) - game.vars[V_ego_dir] = game.view_table[0].direction; - else - game.view_table[0].direction = game.vars[V_ego_dir]; - - check_all_motions (); - - old_score = game.vars[V_score]; - old_sound = getflag (F_sound_on); - - game.exit_all_logics = FALSE; - while (run_logic (0) == 0 && !game.quit_prog_now) { - game.vars[V_word_not_found] = 0; - game.vars[V_border_touch_obj] = 0; - game.vars[V_border_code] = 0; - old_score = game.vars[V_score]; - setflag (F_entered_cli, FALSE); - game.exit_all_logics = FALSE; - reset_controllers (); - } - reset_controllers (); - - game.view_table[0].direction = game.vars[V_ego_dir]; - - if (game.vars[V_score] != old_score || getflag(F_sound_on) != old_sound) - write_status (); - - game.vars[V_border_touch_obj] = 0; - game.vars[V_border_code] = 0; - setflag (F_new_room_exec, FALSE); - setflag (F_restart_game, FALSE); - setflag (F_restore_just_ran, FALSE); - - if (game.gfx_mode) { - update_viewtable (); - do_update (); - } -} - -/** - * Update AGI interpreter timer. - */ -void update_timer () -{ - clock_count++; -play_sound(); - if (clock_count <= TICK_SECONDS) - return; - - clock_count -= TICK_SECONDS; - - if (!game.clock_enabled) - return; - - setvar (V_seconds, getvar (V_seconds) + 1); - if (getvar (V_seconds) < 60) - return; - - setvar (V_seconds, 0); - setvar (V_minutes, getvar (V_minutes) + 1); - if (getvar (V_minutes) < 60) - return; - - setvar (V_minutes, 0); - setvar (V_hours, getvar (V_hours) + 1); - if (getvar (V_hours) < 24) - return; - - setvar (V_hours, 0); - setvar (V_days, getvar (V_days) + 1); -} - - -static int old_mode = -1; -void new_input_mode (int i) -{ - old_mode = game.input_mode; - game.input_mode = i; -} - -void old_input_mode () -{ - game.input_mode = old_mode; -} - - -/* If main_cycle returns FALSE, don't process more events! */ -int main_cycle () -{ - unsigned int key, kascii; - struct vt_entry *v = &game.view_table[0]; - - poll_timer (); /* msdos driver -> does nothing */ - update_timer (); - - if (game.ver == 0) { - message_box ("Warning: game CRC not listed, assuming " - "AGI version 2.917."); - game.ver = -1; - } - - key = do_poll_keyboard (); - -#ifdef USE_MOUSE - /* In AGI Mouse emulation mode we must update the mouse-related - * vars in every interpreter cycle. - */ - if (opt.agimouse) { - game.vars[28] = mouse.x / 2; - game.vars[29] = mouse.y; - } -#endif - -#ifdef USE_CONSOLE - if (key == KEY_PRIORITY) { - erase_both (); - debug.priority = !debug.priority; - show_pic (); - blit_both (); - commit_both (); - key = 0; - } - - if (key == KEY_STATUSLN) { - debug.statusline = !debug.statusline; - write_status (); - key = 0; - } -#endif - - /* Click-to-walk mouse interface */ - if (game.player_control && v->flags & ADJ_EGO_XY) { - v->direction = get_direction (v->x_pos, v->y_pos, - v->parm1, v->parm2, v->step_size); - - if (v->direction == 0) - in_destination (v); - } - - kascii = KEY_ASCII (key); - - if (!console_keyhandler (key)) { - if (kascii) setvar (V_key, kascii); -process_key: - switch (game.input_mode) { - case INPUT_NORMAL: - if (!handle_controller (key)) { - if (key == 0 || !game.input_enabled) - break; - handle_keys (key); - - /* if ESC pressed, activate menu before - * accept.input from the interpreter cycle - * sets the input mode to normal again - * (closes: #540856) - */ - if (key == KEY_ESCAPE) { - key = 0; - goto process_key; - } - - /* commented out to close bug #438872 - * if (key) game.keypress = key; - */ - } - break; - case INPUT_GETSTRING: - handle_controller (key); - handle_getstring (key); - setvar (V_key, 0); /* clear ENTER key */ - break; - case INPUT_MENU: - menu_keyhandler (key); - console_cycle (); - return FALSE; - case INPUT_NONE: - handle_controller (key); - if (key) game.keypress = key; - break; - } - } else { - if (game.input_mode == INPUT_MENU) { - console_cycle (); - return FALSE; - } - } - - console_cycle (); - - if (game.msg_box_ticks > 0) - game.msg_box_ticks--; - - return TRUE; -} - -static int play_game () -{ - int ec = err_OK; - - _D (_D_WARN "initializing..."); - _D (_D_WARN "game.ver = 0x%x", game.ver); - stop_sound (); - clear_screen (0); - - game.horizon = HORIZON; - game.player_control = FALSE; - - setflag (F_logic_zero_firsttime, TRUE); /* not in 2.917 */ - setflag (F_new_room_exec, TRUE); /* needed for MUMG and SQ2! */ - setflag (F_sound_on, TRUE); /* enable sound */ - setvar (V_time_delay, 2); /* "normal" speed */ - - game.gfx_mode = TRUE; - game.quit_prog_now = FALSE; - game.clock_enabled = TRUE; - game.line_user_input = 22; - -#ifdef USE_MOUSE - if (opt.agimouse) - report ("Using AGI Mouse 1.0 protocol\n"); -#endif - - report ("Running AGI script.\n"); - -#ifdef USE_CONSOLE - console.count = 5; - console_prompt (); -#endif - - setflag (F_entered_cli, FALSE); - setflag (F_said_accepted_input, FALSE); - game.vars[V_word_not_found] = 0; - game.vars[V_key] = 0; - - _D (_D_WARN "Entering main loop"); - do { - - if (!main_cycle ()) - continue; - - if (getvar (V_time_delay) == 0 || - (1 + clock_count) % getvar (V_time_delay) == 0) - { - if (!game.has_prompt && game.input_mode == INPUT_NORMAL) { - write_prompt (); - game.has_prompt = 1; - } else - if (game.has_prompt && game.input_mode == INPUT_NONE) { - write_prompt (); - game.has_prompt = 0; - } - - interpret_cycle (); - - setflag (F_entered_cli, FALSE); - setflag (F_said_accepted_input, FALSE); - game.vars[V_word_not_found] = 0; - game.vars[V_key] = 0; - } - - if (game.quit_prog_now == 0xff) - ec = err_RestartGame; - - } while (game.quit_prog_now == 0); - - stop_sound (); - - return ec; -} - - -int run_game () -{ - int i, ec = err_OK; - -#ifdef USE_HIRES - if (opt.cgaemu) - opt.hires = 0; -#endif - - for (i = 0; i < MAX_DIRS; i++) - memset (&game.ev_keyp[i], 0, sizeof (struct agi_event)); - - /* Execute the game */ - do { - _D(_D_WARN "game loop"); - _D(_D_WARN "game.ver = 0x%x", game.ver); - - if (agi_init () != err_OK) - break; - //add_s9_words(); - if (ec == err_RestartGame) - setflag (F_restart_game, TRUE); - - setvar (V_computer, 0); /* IBM PC (4 = Atari ST) */ - setvar (V_soundgen, 1); /* IBM PC SOUND */ - setvar (V_monitor, 0x3); /* EGA monitor */ - setvar (V_max_input_chars, 38); - game.input_mode = INPUT_NONE; - game.input_enabled = 0; - game.has_prompt = 0; - - game.state = STATE_RUNNING; - ec = play_game(); - game.state = STATE_LOADED; - agi_deinit (); - } while (ec == err_RestartGame); - - menu_deinit(); - - release_image_stack(); - - return ec; -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999, 2007-2003 Stuart George and Claudio Matsuoka + * + * $Id: cycle.c,v 1.103 2003/08/17 20:33:56 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include "sarien.h" +#include "agi.h" +#include "text.h" +#include "sprite.h" +#include "graphics.h" +#include "keyboard.h" +#include "menu.h" +#include "savegame.h" + +#define TICK_SECONDS 20 + +#ifdef USE_MOUSE +struct mouse mouse; +#endif + +#ifndef MACOSX_SDL +volatile UINT32 clock_ticks; +volatile UINT32 clock_count; +#endif + + +/** + * Set up new room. + * This function is called when ego enters a new room. + * @param n room number + */ +void new_room (int n) +{ + struct vt_entry *v; + int i; + + _D (_D_WARN "*** room %d ***", n); + stop_sound (); + + i = 0; + for_each_vt_entry (v) { + v->entry = i++; + v->flags &= ~(ANIMATED|DRAWN); + v->flags |= UPDATE; + v->step_time = 1; + v->step_time_count = 1; + v->cycle_time = 1; + v->cycle_time_count = 1; + v->step_size = 1; + } + + agi_unload_resources (); + + game.player_control = TRUE; + game.block.active = FALSE; + game.horizon = 36; + game.vars[V_prev_room] = game.vars[V_cur_room]; + game.vars[V_cur_room] = n; + game.vars[V_border_touch_obj] = 0; + game.vars[V_border_code] = 0; + game.vars[V_ego_view_resource] = game.view_table[0].current_view; + + agi_load_resource (rLOGIC, n); + + /* Reposition ego in the new room */ + switch (game.vars[V_border_touch_ego]) { + case 1: + game.view_table[0].y_pos = _HEIGHT - 1; + break; + case 2: + game.view_table[0].x_pos = 0; + break; + case 3: + game.view_table[0].y_pos = HORIZON + 1; + break; + case 4: + game.view_table[0].x_pos = _WIDTH - game.view_table[0].x_size; + break; + } + + game.vars[V_border_touch_ego] = 0; + setflag (F_new_room_exec, TRUE); + + game.exit_all_logics = TRUE; + + write_status (); + write_prompt (); +} + +static void reset_controllers () +{ + int i; + + for (i = 0; i < MAX_DIRS; i++) { + game.ev_keyp[i].occured = FALSE; + } +} + +static void interpret_cycle () +{ + int old_sound, old_score; + + if (game.player_control) + game.vars[V_ego_dir] = game.view_table[0].direction; + else + game.view_table[0].direction = game.vars[V_ego_dir]; + + check_all_motions (); + + old_score = game.vars[V_score]; + old_sound = getflag (F_sound_on); + + game.exit_all_logics = FALSE; + while (run_logic (0) == 0 && !game.quit_prog_now) { + game.vars[V_word_not_found] = 0; + game.vars[V_border_touch_obj] = 0; + game.vars[V_border_code] = 0; + old_score = game.vars[V_score]; + setflag (F_entered_cli, FALSE); + game.exit_all_logics = FALSE; + reset_controllers (); + } + reset_controllers (); + + game.view_table[0].direction = game.vars[V_ego_dir]; + + if (game.vars[V_score] != old_score || getflag(F_sound_on) != old_sound) + write_status (); + + game.vars[V_border_touch_obj] = 0; + game.vars[V_border_code] = 0; + setflag (F_new_room_exec, FALSE); + setflag (F_restart_game, FALSE); + setflag (F_restore_just_ran, FALSE); + + if (game.gfx_mode) { + update_viewtable (); + do_update (); + } +} + +/** + * Update AGI interpreter timer. + */ +void update_timer () +{ + clock_count++; + if (clock_count <= TICK_SECONDS) + return; + + clock_count -= TICK_SECONDS; + + if (!game.clock_enabled) + return; + + setvar (V_seconds, getvar (V_seconds) + 1); + if (getvar (V_seconds) < 60) + return; + + setvar (V_seconds, 0); + setvar (V_minutes, getvar (V_minutes) + 1); + if (getvar (V_minutes) < 60) + return; + + setvar (V_minutes, 0); + setvar (V_hours, getvar (V_hours) + 1); + if (getvar (V_hours) < 24) + return; + + setvar (V_hours, 0); + setvar (V_days, getvar (V_days) + 1); +} + + +static int old_mode = -1; +void new_input_mode (int i) +{ + old_mode = game.input_mode; + game.input_mode = i; +} + +void old_input_mode () +{ + game.input_mode = old_mode; +} + + +/* If main_cycle returns FALSE, don't process more events! */ +int main_cycle () +{ + unsigned int key, kascii; + struct vt_entry *v = &game.view_table[0]; + + poll_timer (); /* msdos driver -> does nothing */ + update_timer (); + + if (game.ver == 0) { + message_box ("Warning: game CRC not listed, assuming " + "AGI version 2.917."); + game.ver = -1; + } + + key = do_poll_keyboard (); + +#ifdef USE_MOUSE + /* In AGI Mouse emulation mode we must update the mouse-related + * vars in every interpreter cycle. + */ + if (opt.agimouse) { + game.vars[28] = mouse.x / 2; + game.vars[29] = mouse.y; + } +#endif + +#ifdef USE_CONSOLE + if (key == KEY_PRIORITY) { + erase_both (); + debug.priority = !debug.priority; + show_pic (); + blit_both (); + commit_both (); + key = 0; + } + + if (key == KEY_STATUSLN) { + debug.statusline = !debug.statusline; + write_status (); + key = 0; + } +#endif + + /* Click-to-walk mouse interface */ + if (game.player_control && v->flags & ADJ_EGO_XY) { + v->direction = get_direction (v->x_pos, v->y_pos, + v->parm1, v->parm2, v->step_size); + + if (v->direction == 0) + in_destination (v); + } + + kascii = KEY_ASCII (key); + + if (!console_keyhandler (key)) { + if (kascii) setvar (V_key, kascii); +process_key: + switch (game.input_mode) { + case INPUT_NORMAL: + if (!handle_controller (key)) { + if (key == 0 || !game.input_enabled) + break; + handle_keys (key); + + /* if ESC pressed, activate menu before + * accept.input from the interpreter cycle + * sets the input mode to normal again + * (closes: #540856) + */ + if (key == KEY_ESCAPE) { + key = 0; + goto process_key; + } + + /* commented out to close bug #438872 + * if (key) game.keypress = key; + */ + } + break; + case INPUT_GETSTRING: + handle_controller (key); + handle_getstring (key); + setvar (V_key, 0); /* clear ENTER key */ + break; + case INPUT_MENU: + menu_keyhandler (key); + console_cycle (); + return FALSE; + case INPUT_NONE: + handle_controller (key); + if (key) game.keypress = key; + break; + } + } else { + if (game.input_mode == INPUT_MENU) { + console_cycle (); + return FALSE; + } + } + + console_cycle (); + + if (game.msg_box_ticks > 0) + game.msg_box_ticks--; + + return TRUE; +} + +static int play_game () +{ + int ec = err_OK; + + _D (_D_WARN "initializing..."); + _D (_D_WARN "game.ver = 0x%x", game.ver); + stop_sound (); + clear_screen (0); + + game.horizon = HORIZON; + game.player_control = FALSE; + + setflag (F_logic_zero_firsttime, TRUE); /* not in 2.917 */ + setflag (F_new_room_exec, TRUE); /* needed for MUMG and SQ2! */ + setflag (F_sound_on, TRUE); /* enable sound */ + setvar (V_time_delay, 2); /* "normal" speed */ + + game.gfx_mode = TRUE; + game.quit_prog_now = FALSE; + game.clock_enabled = TRUE; + game.line_user_input = 22; + +#ifdef USE_MOUSE + if (opt.agimouse) + report ("Using AGI Mouse 1.0 protocol\n"); +#endif + + report ("Running AGI script.\n"); + +#ifdef USE_CONSOLE + console.count = 5; + console_prompt (); +#endif + + setflag (F_entered_cli, FALSE); + setflag (F_said_accepted_input, FALSE); + game.vars[V_word_not_found] = 0; + game.vars[V_key] = 0; + + _D (_D_WARN "Entering main loop"); + do { + + if (!main_cycle ()) + continue; + + if (getvar (V_time_delay) == 0 || + (1 + clock_count) % getvar (V_time_delay) == 0) + { + if (!game.has_prompt && game.input_mode == INPUT_NORMAL) { + write_prompt (); + game.has_prompt = 1; + } else + if (game.has_prompt && game.input_mode == INPUT_NONE) { + write_prompt (); + game.has_prompt = 0; + } + + interpret_cycle (); + + setflag (F_entered_cli, FALSE); + setflag (F_said_accepted_input, FALSE); + game.vars[V_word_not_found] = 0; + game.vars[V_key] = 0; + } + + if (game.quit_prog_now == 0xff) + ec = err_RestartGame; + + } while (game.quit_prog_now == 0); + + stop_sound (); + + return ec; +} + + +int run_game () +{ + int i, ec = err_OK; + +#ifdef USE_HIRES + if (opt.cgaemu) + opt.hires = 0; +#endif + + for (i = 0; i < MAX_DIRS; i++) + memset (&game.ev_keyp[i], 0, sizeof (struct agi_event)); + + /* Execute the game */ + do { + _D(_D_WARN "game loop"); + _D(_D_WARN "game.ver = 0x%x", game.ver); + + if (agi_init () != err_OK) + break; + //add_s9_words(); + if (ec == err_RestartGame) + setflag (F_restart_game, TRUE); + + setvar (V_computer, 0); /* IBM PC (4 = Atari ST) */ + setvar (V_soundgen, 1); /* IBM PC SOUND */ + setvar (V_monitor, 0x3); /* EGA monitor */ + setvar (V_max_input_chars, 38); + game.input_mode = INPUT_NONE; + game.input_enabled = 0; + game.has_prompt = 0; + + game.state = STATE_RUNNING; + ec = play_game(); + game.state = STATE_LOADED; + agi_deinit (); + } while (ec == err_RestartGame); + + menu_deinit(); + + release_image_stack(); + + return ec; +} + diff --git a/dummy.c b/dummy.c index 9cd95ab..fd10af6 100644 --- a/dummy.c +++ b/dummy.c @@ -1,39 +1,44 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: dummy.c,v 1.7 2001/11/30 14:59:24 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include "sarien.h" -#include "console.h" -#include "sound.h" - -static int dummy2_init_sound (SINT16 *buffer); -static void dummy2_close_sound (void); - -static struct sound_driver sound_dummy2 = { - "Dummy sound driver", - dummy2_init_sound, - dummy2_close_sound -}; - - -void __init_sound () -{ - snd = &sound_dummy2; -} - -static int dummy2_init_sound (SINT16 *buffer) -{ - report ("sound_dummy: sound output disabled\n"); - return 0; -} - -static void dummy2_close_sound () -{ -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: dummy.c,v 1.7 2001/11/30 14:59:24 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include "sarien.h" +#include "console.h" +#include "sound.h" + +static int dummy2_init_sound (SINT16 *buffer); +static void dummy2_close_sound (void); + +static struct sound_driver sound_dummy2 = { + "Dummy sound driver", + dummy2_init_sound, + dummy2_close_sound +}; + + +void __init_sound () +{ + snd = &sound_dummy2; +} + +static int dummy2_init_sound (SINT16 *buffer) +{ + report ("sound_dummy: sound output disabled\n"); + return -1; +} + +static void dummy2_close_sound () +{ +} + +void nosound(){} +void sound(){} + + + diff --git a/fileglob.c b/fileglob.c index 1faa32f..2ea5a4c 100644 --- a/fileglob.c +++ b/fileglob.c @@ -1,130 +1,130 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999,2001 Stuart George and Claudio Matsuoka - * - * $Id: fileglob.c,v 1.2 2001/11/29 05:22:25 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#define __32BIT__ 1 -#define M_I386 1 -#define _MSC_VER 6 - -#define INC_VIO -#include - -#define FILE_ALL 0x0007 /* Read-only, sys, hidden, & normal */ -#define FILE_INVALID 0 /* The filename was invalid */ -#define FILE_PATH 1 /* The filename was a path */ -#define FILE_VALID 2 /* The filename was valid */ - -#include -#include -#include - -#include "sarien.h" -#include "agi.h" - -int file_exists (char *fname) -{ - HDIR hDir = 1; - ULONG ulFiles; - USHORT attr; - FILEFINDBUF2 ffb; - int rc; - - attr=FILE_ALL; - DosFindFirst("*.*", (PHDIR)&hDir,attr,\ - (PFILEFINDBUF2)&ffb, sizeof(FILEFINDBUF2),&ulFiles, FIL_STANDARD); -rc=1; -if(ulFiles>0) - rc=0; -return(!rc); -// return !_dos_findfirst (fname, _A_NORMAL | _A_ARCH | _A_RDONLY, &fdata); -} - -int file_isthere (char *fname) -{ -// struct find_t fdata; -// return !_dos_findfirst (fname, _A_NORMAL | _A_ARCH | _A_RDONLY, &fdata); -return(file_exists(fname)); -} - - -char* file_name (char *fname) -{ - int rc; -#if 0 - struct find_t fdata; - - _D ("(\"%s\")", fname); - fdata.name[0] = 0; - rc = _dos_findfirst((char*)fname, _A_NORMAL, &fdata); - while (rc == 0) { - rc = _dos_findnext(&fdata); - if(rc == 0) { - strlwr (fdata.name); - if (strstr (fdata.name, "dir.")!=NULL) - rc = 1; - } - } - - return strdup (fdata.name); -#else - HDIR hDir = 1; - ULONG ulFiles; - USHORT attr; - FILEFINDBUF2 ffb; - char fnamebuf[15]; - char *p; - -attr=FILE_ALL; - DosFindFirst(fname, (PHDIR)&hDir,attr,\ - (PFILEFINDBUF2)&ffb, sizeof(FILEFINDBUF2),&ulFiles, FIL_STANDARD); - if(ulFiles) - { -p=ffb.achName;p+=2; -sprintf(fnamebuf,p); - } -else - memset(fnamebuf,0x0,sizeof(fnamebuf)); - - return strdup(fnamebuf); -#endif -} - - - -char *fixpath (int flag, char *fname) -{ - static char path[MAX_PATH]; - char *p; - - strcpy (path, game.dir); - - if (*path && (path[strlen(path)-1]!='\\' && path[strlen(path)-1] != '/')) - { - if(path[strlen(path)-1]==':') - strcat(path, "./"); - else - strcat(path, "/"); - } - - if (flag==1) - strcat (path, game.name); - - strcat (path, fname); - - p = path; - - while(*p) { - if (*p=='\\') - *p='/'; - p++; - } - - return path; -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999,2001 Stuart George and Claudio Matsuoka + * + * $Id: fileglob.c,v 1.2 2001/11/29 05:22:25 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#define __32BIT__ 1 +#define M_I386 1 +#define _MSC_VER 6 + +#define INC_VIO +#include + +#define FILE_ALL 0x0007 /* Read-only, sys, hidden, & normal */ +#define FILE_INVALID 0 /* The filename was invalid */ +#define FILE_PATH 1 /* The filename was a path */ +#define FILE_VALID 2 /* The filename was valid */ + +#include +#include +#include + +#include "sarien.h" +#include "agi.h" + +int file_exists (char *fname) +{ + HDIR hDir = 1; + ULONG ulFiles; + USHORT attr; + FILEFINDBUF2 ffb; + int rc; + + attr=FILE_ALL; + DosFindFirst("*.*", (PHDIR)&hDir,attr,\ + (PFILEFINDBUF2)&ffb, sizeof(FILEFINDBUF2),&ulFiles, FIL_STANDARD); +rc=1; +if(ulFiles>0) + rc=0; +return(!rc); +// return !_dos_findfirst (fname, _A_NORMAL | _A_ARCH | _A_RDONLY, &fdata); +} + +int file_isthere (char *fname) +{ +// struct find_t fdata; +// return !_dos_findfirst (fname, _A_NORMAL | _A_ARCH | _A_RDONLY, &fdata); +return(file_exists(fname)); +} + + +char* file_name (char *fname) +{ + int rc; +#if 0 + struct find_t fdata; + + _D ("(\"%s\")", fname); + fdata.name[0] = 0; + rc = _dos_findfirst((char*)fname, _A_NORMAL, &fdata); + while (rc == 0) { + rc = _dos_findnext(&fdata); + if(rc == 0) { + strlwr (fdata.name); + if (strstr (fdata.name, "dir.")!=NULL) + rc = 1; + } + } + + return strdup (fdata.name); +#else + HDIR hDir = 1; + ULONG ulFiles; + USHORT attr; + FILEFINDBUF2 ffb; + char fnamebuf[15]; + char *p; + +attr=FILE_ALL; + DosFindFirst(fname, (PHDIR)&hDir,attr,\ + (PFILEFINDBUF2)&ffb, sizeof(FILEFINDBUF2),&ulFiles, FIL_STANDARD); + if(ulFiles) + { +p=ffb.achName;p+=2; +sprintf(fnamebuf,p); + } +else + memset(fnamebuf,0x0,sizeof(fnamebuf)); + + return strdup(fnamebuf); +#endif +} + + + +char *fixpath (int flag, char *fname) +{ + static char path[MAX_PATH]; + char *p; + + strcpy (path, game.dir); + + if (*path && (path[strlen(path)-1]!='\\' && path[strlen(path)-1] != '/')) + { + if(path[strlen(path)-1]==':') + strcat(path, "./"); + else + strcat(path, "/"); + } + + if (flag==1) + strcat (path, game.name); + + strcat (path, fname); + + p = path; + + while(*p) { + if (*p=='\\') + *p='/'; + p++; + } + + return path; +} + diff --git a/font.c b/font.c index 3b2c38b..802b7a4 100644 --- a/font.c +++ b/font.c @@ -1,412 +1,412 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: font.c,v 1.12 2001/11/06 21:27:59 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include "sarien.h" - -#if defined PALMOS || defined FAKE_PALMOS - -/* small 4x6 font patterns */ -UINT8 cur_font[]= { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe0, 0xd0, 0xd0, 0xd0, 0xd0, 0xe0, /* cursor hollow */ - 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, /* cursor solid */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cursor empty */ - 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, - 0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, - 0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, - 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, - 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, - 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* \n */ - 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, - 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, - 0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, - 0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, - 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, - 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, - 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, - 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, - 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, - 0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, - 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, - 0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, - 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, - 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, - 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, - 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, - 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, - 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* */ - 0x40, 0x40, 0x40, 0x00, 0x40, 0x00, /* ! */ - 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, /* " */ - 0x60, 0xf0, 0x60, 0xf0, 0x60, 0x00, /* # */ - 0x40, 0x60, 0xc0, 0x20, 0xc0, 0x40, /* $ */ - 0xa0, 0x20, 0x40, 0x80, 0xa0, 0x00, /* % */ - 0x40, 0x80, 0x40, 0x80, 0x40, 0x00, /* & */ - 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, /* ' */ - 0x20, 0x40, 0x40, 0x40, 0x20, 0x00, /* ( */ - 0x80, 0x40, 0x40, 0x40, 0x80, 0x00, /* ) */ - 0xa0, 0x40, 0xe0, 0x40, 0xa0, 0x00, /* * */ - 0x00, 0x40, 0xe0, 0x40, 0x00, 0x00, /* + */ - 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, /* , */ - 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, /* - */ - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, /* . */ - 0x20, 0x20, 0x40, 0x80, 0x80, 0x00, /* / */ - 0x40, 0xa0, 0xa0, 0xa0, 0x40, 0x00, /* 0 */ - 0x40, 0xc0, 0x40, 0x40, 0xe0, 0x00, - 0xe0, 0x20, 0xe0, 0x80, 0xe0, 0x00, - 0xe0, 0x20, 0x60, 0x20, 0xe0, 0x00, /* 3 */ - 0xa0, 0xa0, 0xe0, 0x20, 0x20, 0x00, - 0xe0, 0x80, 0xc0, 0x20, 0xc0, 0x00, - 0xe0, 0x80, 0xe0, 0xa0, 0xe0, 0x00, /* 6 */ - 0xe0, 0x20, 0x40, 0x40, 0x40, 0x00, - 0xe0, 0xa0, 0xe0, 0xa0, 0xe0, 0x00, - 0xe0, 0xa0, 0xe0, 0x20, 0xe0, 0x00, /* 9 */ - 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, /* : */ - 0x00, 0x30, 0x40, 0x00, 0x40, 0x80, /* ; */ - 0x00, 0x20, 0x40, 0x20, 0x00, 0x00, /* < */ - 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x0E, /* = */ - 0x00, 0x80, 0x40, 0x80, 0x00, 0x00, /* > */ - 0xe0, 0x20, 0x60, 0x00, 0x40, 0x00, /* ? */ - 0xe0, 0xa0, 0xe0, 0x80, 0xe0, 0x00, /* @ */ - 0x40, 0xa0, 0xe0, 0xa0, 0xa0, 0x00, /* A */ - 0xc0, 0xa0, 0xc0, 0xa0, 0xc0, 0x00, - 0x60, 0x80, 0x80, 0x80, 0x60, 0x00, - 0xc0, 0xa0, 0xa0, 0xa0, 0xc0, 0x00, - 0xe0, 0x80, 0xc0, 0x80, 0xe0, 0x00, - 0xe0, 0x80, 0xc0, 0x80, 0x80, 0x00, /* F */ - 0x60, 0x80, 0xa0, 0xa0, 0x60, 0x00, - 0xa0, 0xa0, 0xe0, 0xa0, 0xa0, 0x00, - 0xe0, 0x40, 0x40, 0x40, 0xe0, 0x00, - 0x20, 0x20, 0x20, 0xa0, 0x40, 0x00, - 0xa0, 0xa0, 0xc0, 0xa0, 0xa0, 0x00, /* K */ - 0x80, 0x80, 0x80, 0x80, 0xe0, 0x00, - 0xa0, 0xe0, 0xa0, 0xa0, 0xa0, 0x00, - 0xa0, 0xe0, 0xe0, 0xa0, 0xa0, 0x00, - 0xe0, 0xa0, 0xa0, 0xa0, 0xe0, 0x00, - 0xc0, 0xa0, 0xc0, 0x80, 0x80, 0x00, /* P */ - 0xe0, 0xa0, 0xa0, 0xa0, 0xc0, 0x00, - 0xc0, 0xa0, 0xc0, 0xa0, 0xa0, 0x00, - 0x60, 0x80, 0x40, 0x20, 0xc0, 0x00, - 0xe0, 0x40, 0x40, 0x40, 0x40, 0x00, - 0xa0, 0xa0, 0xa0, 0xa0, 0xe0, 0x00, /* U */ - 0xa0, 0xa0, 0xa0, 0xa0, 0x40, 0x00, - 0xa0, 0xa0, 0xa0, 0xe0, 0xa0, 0x00, - 0xa0, 0xa0, 0x40, 0xa0, 0xa0, 0x00, - 0xa0, 0xa0, 0x40, 0x40, 0x40, 0x00, - 0xe0, 0x20, 0x40, 0x80, 0xe0, 0x00, /* Z */ - 0x60, 0x40, 0x40, 0x40, 0x60, 0x00, /* [ */ - 0x80, 0x80, 0x40, 0x20, 0x20, 0x00, /* \ */ - 0xc0, 0x40, 0x40, 0x40, 0xc0, 0x00, /* ] */ - 0x40, 0xa0, 0x00, 0x00, 0x00, 0x00, /* ^ */ - 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, /* _ */ - 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, /* ` */ - 0x00, 0x60, 0xa0, 0xa0, 0x60, 0x00, /* a */ - 0x80, 0xc0, 0xa0, 0xa0, 0xc0, 0x00, - 0x00, 0x60, 0x80, 0x80, 0x60, 0x00, - 0x20, 0x60, 0xa0, 0xa0, 0x60, 0x00, - 0x00, 0x60, 0xa0, 0xc0, 0x60, 0x00, - 0x40, 0x80, 0xc0, 0x80, 0x80, 0x00, /* f */ - 0x00, 0x60, 0xa0, 0xe0, 0x20, 0xc0, - 0x80, 0xc0, 0xa0, 0xa0, 0xa0, 0x00, - 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, - 0x40, 0x00, 0x40, 0x40, 0x40, 0xc0, - 0x80, 0x80, 0xa0, 0xc0, 0xa0, 0x00, /* k */ - 0xc0, 0x40, 0x40, 0x40, 0x40, 0x00, - 0x00, 0xc0, 0xe0, 0xe0, 0xa0, 0x00, - 0x00, 0xc0, 0xa0, 0xa0, 0xa0, 0x00, - 0x00, 0x40, 0xa0, 0xa0, 0x40, 0x00, - 0x00, 0xc0, 0xa0, 0xa0, 0xc0, 0x80, /* p */ - 0x00, 0x60, 0xa0, 0xa0, 0x60, 0x20, - 0x00, 0xc0, 0xa0, 0x80, 0x80, 0x00, - 0x00, 0x60, 0xc0, 0x20, 0xc0, 0x00, - 0x40, 0xe0, 0x40, 0x40, 0x20, 0x00, - 0x00, 0xa0, 0xa0, 0xa0, 0x60, 0x00, /* u */ - 0x00, 0xa0, 0xa0, 0xa0, 0x40, 0x00, - 0x00, 0xe0, 0xe0, 0xe0, 0x60, 0x00, - 0x00, 0xa0, 0x40, 0xa0, 0xa0, 0x00, - 0x00, 0xa0, 0xa0, 0x60, 0x20, 0xc0, - 0x00, 0x0e, 0x40, 0x80, 0xe0, 0x00, /* z */ - 0x02, 0x40, 0xc0, 0x40, 0x02, 0x00, /* { */ - 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, /* | */ - 0x80, 0x40, 0x60, 0x40, 0x80, 0x00, /* } */ - 0xc0, 0x60, 0x00, 0x00, 0x00, 0x00, /* ~ */ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /*replacement 0x7F*/ -}; - -#else - -/* 8x8 font patterns */ -UINT8 cur_font[]= { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, /* cursor hollow */ - 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, /* cursor solid */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cursor empty */ - 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, - 0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00, - 0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00, - 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, - 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, - 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* \n */ - 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, - 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, - 0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00, - 0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C, - 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, - 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, - 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, - 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, - 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00, - 0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, - 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E, - 0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00, - 0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00, - 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, - 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, - 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, - 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, - 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, - 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, - 0x6C, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, - 0x10, 0x7C, 0xD0, 0x7C, 0x16, 0xFC, 0x10, 0x00, - 0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00, - 0x38, 0x4C, 0x38, 0x78, 0xCE, 0xCC, 0x7A, 0x00, - 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, - 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, - 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, - 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, - 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00, - 0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xE6, 0x7C, 0x00, - 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x00, - 0x7C, 0xC6, 0x06, 0x1C, 0x70, 0xC6, 0xFE, 0x00, - 0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00, - 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, - 0xFE, 0xC0, 0xFC, 0x06, 0x06, 0xC6, 0x7C, 0x00, - 0x7C, 0xC6, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00, - 0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, - 0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, - 0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, - 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, - 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, - 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, - 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, - 0x7C, 0x82, 0x9E, 0xA6, 0x9E, 0x80, 0x7C, 0x00, - 0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, - 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, - 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, - 0xFC, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, - 0x7C, 0xC6, 0xC6, 0xC0, 0xCE, 0xC6, 0x7E, 0x00, - 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, - 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, - 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, - 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, - 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, - 0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, - 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, - 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, - 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, - 0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x06, - 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xE6, 0x00, - 0x7C, 0xC6, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00, - 0x7E, 0x5A, 0x5A, 0x18, 0x18, 0x18, 0x3C, 0x00, - 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, - 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, - 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x82, 0x00, - 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, - 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00, - 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, - 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, - 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, - 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, - 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, - 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, - 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00, - 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, - 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00, - 0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, - 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x78, - 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, - 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, - 0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0x78, - 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, - 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, - 0x00, 0x00, 0xCC, 0xFE, 0xD6, 0xD6, 0xD6, 0x00, - 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00, - 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, - 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, - 0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, - 0x00, 0x00, 0xDE, 0x76, 0x60, 0x60, 0xF0, 0x00, - 0x00, 0x00, 0x7C, 0xC0, 0x7C, 0x06, 0x7C, 0x00, - 0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00, - 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, - 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, - 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, - 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, - 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, - 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, - 0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00, - 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, - 0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00, - 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /*0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,*/ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*replacement 0x7F*/ -#ifdef AGDS_SUPPORT - 0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, - 0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, - 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, - 0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, - 0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6, - 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, - 0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00, - 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, - 0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, - 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, - 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, - 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, - 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, - 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, - 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, - 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, - 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, - 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, - 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, - 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, - 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00, - 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03, - 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, - 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00, - 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03, - 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, - 0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00, - 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, - 0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00, - 0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00, - 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00, - 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00, - 0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00, - 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00, - 0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00, - 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6, - 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, - 0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00, - 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00, - 0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00, - 0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00, - 0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, - 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00, - 0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, - 0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, - 0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, - 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, - 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, - 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, - 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, - 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, - 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, - 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, - 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, - 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, - 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, - 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, - 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, - 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, - 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, - 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, - 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00, - 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00, - 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03, - 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00, - 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00, - 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03, - 0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00, - 0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00, - 0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00, - 0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00, - 0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00, - 0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00, - 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, - 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00, - 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, - 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, - 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70, - 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, - 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, - 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, - 0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10, - 0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C, - 0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00 -#endif /* AGDS_SUPPORT */ -}; - -#endif /* PALMOS */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: font.c,v 1.12 2001/11/06 21:27:59 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include "sarien.h" + +#if defined PALMOS || defined FAKE_PALMOS + +/* small 4x6 font patterns */ +UINT8 cur_font[]= { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xd0, 0xd0, 0xd0, 0xd0, 0xe0, /* cursor hollow */ + 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, /* cursor solid */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cursor empty */ + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, + 0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, + 0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, + 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* \n */ + 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, + 0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, + 0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, + 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, + 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, + 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, + 0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, + 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, + 0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, + 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, + 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, + 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, + 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* */ + 0x40, 0x40, 0x40, 0x00, 0x40, 0x00, /* ! */ + 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, /* " */ + 0x60, 0xf0, 0x60, 0xf0, 0x60, 0x00, /* # */ + 0x40, 0x60, 0xc0, 0x20, 0xc0, 0x40, /* $ */ + 0xa0, 0x20, 0x40, 0x80, 0xa0, 0x00, /* % */ + 0x40, 0x80, 0x40, 0x80, 0x40, 0x00, /* & */ + 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, /* ' */ + 0x20, 0x40, 0x40, 0x40, 0x20, 0x00, /* ( */ + 0x80, 0x40, 0x40, 0x40, 0x80, 0x00, /* ) */ + 0xa0, 0x40, 0xe0, 0x40, 0xa0, 0x00, /* * */ + 0x00, 0x40, 0xe0, 0x40, 0x00, 0x00, /* + */ + 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, /* , */ + 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, /* - */ + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, /* . */ + 0x20, 0x20, 0x40, 0x80, 0x80, 0x00, /* / */ + 0x40, 0xa0, 0xa0, 0xa0, 0x40, 0x00, /* 0 */ + 0x40, 0xc0, 0x40, 0x40, 0xe0, 0x00, + 0xe0, 0x20, 0xe0, 0x80, 0xe0, 0x00, + 0xe0, 0x20, 0x60, 0x20, 0xe0, 0x00, /* 3 */ + 0xa0, 0xa0, 0xe0, 0x20, 0x20, 0x00, + 0xe0, 0x80, 0xc0, 0x20, 0xc0, 0x00, + 0xe0, 0x80, 0xe0, 0xa0, 0xe0, 0x00, /* 6 */ + 0xe0, 0x20, 0x40, 0x40, 0x40, 0x00, + 0xe0, 0xa0, 0xe0, 0xa0, 0xe0, 0x00, + 0xe0, 0xa0, 0xe0, 0x20, 0xe0, 0x00, /* 9 */ + 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, /* : */ + 0x00, 0x30, 0x40, 0x00, 0x40, 0x80, /* ; */ + 0x00, 0x20, 0x40, 0x20, 0x00, 0x00, /* < */ + 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x0E, /* = */ + 0x00, 0x80, 0x40, 0x80, 0x00, 0x00, /* > */ + 0xe0, 0x20, 0x60, 0x00, 0x40, 0x00, /* ? */ + 0xe0, 0xa0, 0xe0, 0x80, 0xe0, 0x00, /* @ */ + 0x40, 0xa0, 0xe0, 0xa0, 0xa0, 0x00, /* A */ + 0xc0, 0xa0, 0xc0, 0xa0, 0xc0, 0x00, + 0x60, 0x80, 0x80, 0x80, 0x60, 0x00, + 0xc0, 0xa0, 0xa0, 0xa0, 0xc0, 0x00, + 0xe0, 0x80, 0xc0, 0x80, 0xe0, 0x00, + 0xe0, 0x80, 0xc0, 0x80, 0x80, 0x00, /* F */ + 0x60, 0x80, 0xa0, 0xa0, 0x60, 0x00, + 0xa0, 0xa0, 0xe0, 0xa0, 0xa0, 0x00, + 0xe0, 0x40, 0x40, 0x40, 0xe0, 0x00, + 0x20, 0x20, 0x20, 0xa0, 0x40, 0x00, + 0xa0, 0xa0, 0xc0, 0xa0, 0xa0, 0x00, /* K */ + 0x80, 0x80, 0x80, 0x80, 0xe0, 0x00, + 0xa0, 0xe0, 0xa0, 0xa0, 0xa0, 0x00, + 0xa0, 0xe0, 0xe0, 0xa0, 0xa0, 0x00, + 0xe0, 0xa0, 0xa0, 0xa0, 0xe0, 0x00, + 0xc0, 0xa0, 0xc0, 0x80, 0x80, 0x00, /* P */ + 0xe0, 0xa0, 0xa0, 0xa0, 0xc0, 0x00, + 0xc0, 0xa0, 0xc0, 0xa0, 0xa0, 0x00, + 0x60, 0x80, 0x40, 0x20, 0xc0, 0x00, + 0xe0, 0x40, 0x40, 0x40, 0x40, 0x00, + 0xa0, 0xa0, 0xa0, 0xa0, 0xe0, 0x00, /* U */ + 0xa0, 0xa0, 0xa0, 0xa0, 0x40, 0x00, + 0xa0, 0xa0, 0xa0, 0xe0, 0xa0, 0x00, + 0xa0, 0xa0, 0x40, 0xa0, 0xa0, 0x00, + 0xa0, 0xa0, 0x40, 0x40, 0x40, 0x00, + 0xe0, 0x20, 0x40, 0x80, 0xe0, 0x00, /* Z */ + 0x60, 0x40, 0x40, 0x40, 0x60, 0x00, /* [ */ + 0x80, 0x80, 0x40, 0x20, 0x20, 0x00, /* \ */ + 0xc0, 0x40, 0x40, 0x40, 0xc0, 0x00, /* ] */ + 0x40, 0xa0, 0x00, 0x00, 0x00, 0x00, /* ^ */ + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, /* _ */ + 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, /* ` */ + 0x00, 0x60, 0xa0, 0xa0, 0x60, 0x00, /* a */ + 0x80, 0xc0, 0xa0, 0xa0, 0xc0, 0x00, + 0x00, 0x60, 0x80, 0x80, 0x60, 0x00, + 0x20, 0x60, 0xa0, 0xa0, 0x60, 0x00, + 0x00, 0x60, 0xa0, 0xc0, 0x60, 0x00, + 0x40, 0x80, 0xc0, 0x80, 0x80, 0x00, /* f */ + 0x00, 0x60, 0xa0, 0xe0, 0x20, 0xc0, + 0x80, 0xc0, 0xa0, 0xa0, 0xa0, 0x00, + 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, + 0x40, 0x00, 0x40, 0x40, 0x40, 0xc0, + 0x80, 0x80, 0xa0, 0xc0, 0xa0, 0x00, /* k */ + 0xc0, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0xc0, 0xe0, 0xe0, 0xa0, 0x00, + 0x00, 0xc0, 0xa0, 0xa0, 0xa0, 0x00, + 0x00, 0x40, 0xa0, 0xa0, 0x40, 0x00, + 0x00, 0xc0, 0xa0, 0xa0, 0xc0, 0x80, /* p */ + 0x00, 0x60, 0xa0, 0xa0, 0x60, 0x20, + 0x00, 0xc0, 0xa0, 0x80, 0x80, 0x00, + 0x00, 0x60, 0xc0, 0x20, 0xc0, 0x00, + 0x40, 0xe0, 0x40, 0x40, 0x20, 0x00, + 0x00, 0xa0, 0xa0, 0xa0, 0x60, 0x00, /* u */ + 0x00, 0xa0, 0xa0, 0xa0, 0x40, 0x00, + 0x00, 0xe0, 0xe0, 0xe0, 0x60, 0x00, + 0x00, 0xa0, 0x40, 0xa0, 0xa0, 0x00, + 0x00, 0xa0, 0xa0, 0x60, 0x20, 0xc0, + 0x00, 0x0e, 0x40, 0x80, 0xe0, 0x00, /* z */ + 0x02, 0x40, 0xc0, 0x40, 0x02, 0x00, /* { */ + 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, /* | */ + 0x80, 0x40, 0x60, 0x40, 0x80, 0x00, /* } */ + 0xc0, 0x60, 0x00, 0x00, 0x00, 0x00, /* ~ */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /*replacement 0x7F*/ +}; + +#else + +/* 8x8 font patterns */ +UINT8 cur_font[]= { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, /* cursor hollow */ + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, /* cursor solid */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cursor empty */ + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00, + 0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, + 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* \n */ + 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, + 0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00, + 0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C, + 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, + 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, + 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00, + 0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, + 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E, + 0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, + 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, + 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x6C, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, + 0x10, 0x7C, 0xD0, 0x7C, 0x16, 0xFC, 0x10, 0x00, + 0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00, + 0x38, 0x4C, 0x38, 0x78, 0xCE, 0xCC, 0x7A, 0x00, + 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00, + 0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xE6, 0x7C, 0x00, + 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x00, + 0x7C, 0xC6, 0x06, 0x1C, 0x70, 0xC6, 0xFE, 0x00, + 0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00, + 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, + 0xFE, 0xC0, 0xFC, 0x06, 0x06, 0xC6, 0x7C, 0x00, + 0x7C, 0xC6, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00, + 0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, + 0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, + 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, + 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7C, 0x82, 0x9E, 0xA6, 0x9E, 0x80, 0x7C, 0x00, + 0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, + 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, + 0xFC, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, + 0x7C, 0xC6, 0xC6, 0xC0, 0xCE, 0xC6, 0x7E, 0x00, + 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, + 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, + 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, + 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, + 0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, + 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, + 0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x06, + 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xE6, 0x00, + 0x7C, 0xC6, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00, + 0x7E, 0x5A, 0x5A, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, + 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x82, 0x00, + 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, + 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00, + 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00, + 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00, + 0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x78, + 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, + 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0x78, + 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, + 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x00, 0xCC, 0xFE, 0xD6, 0xD6, 0xD6, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, + 0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, + 0x00, 0x00, 0xDE, 0x76, 0x60, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x7C, 0xC0, 0x7C, 0x06, 0x7C, 0x00, + 0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, + 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, + 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, + 0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /*0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,*/ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*replacement 0x7F*/ +#ifdef AGDS_SUPPORT + 0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, + 0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, + 0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6, + 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, + 0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00, + 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, + 0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, + 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, + 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, + 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, + 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, + 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, + 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, + 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, + 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00, + 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03, + 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03, + 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00, + 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00, + 0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00, + 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00, + 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00, + 0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00, + 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6, + 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, + 0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00, + 0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00, + 0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, + 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, + 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, + 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, + 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00, + 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00, + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03, + 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00, + 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00, + 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03, + 0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00, + 0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00, + 0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00, + 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, + 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00, + 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, + 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, + 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70, + 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, + 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, + 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, + 0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10, + 0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C, + 0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00 +#endif /* AGDS_SUPPORT */ +}; + +#endif /* PALMOS */ diff --git a/getopt.c b/getopt.c index b51e14e..ec5c1e9 100644 --- a/getopt.c +++ b/getopt.c @@ -1,1004 +1,1004 @@ -#if !defined(PALMOS) && !defined(WIN32) - -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu - before changing it! - - Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 - Free Software Foundation, Inc. - - This file is part of the GNU C Library. Its master source is NOT part of - the C library, however. The master source lives in /gd/gnu/lib. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* This tells Alpha OSF/1 not to define a getopt prototype in . - Ditto for AIX 3.2 and . */ -#ifndef _NO_PROTO -#define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if !defined (__STDC__) || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 -#include -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -#include -#include -#endif /* GNU C library. */ - -#ifdef VMS -#include -#if HAVE_STRING_H - 0 -#include -#endif -#endif - -#if defined (WIN32) && !defined (__CYGWIN32__) -/* It's not Unix, really. See? Capital letters. */ -#include -#define getpid() GetCurrentProcessId() -#endif - -#ifndef _ -/* This is for other GNU distributions with internationalized messages. - When compiling libc, the _ macro is predefined. */ -#ifdef HAVE_LIBINTL_H -# include -# define _(msgid) gettext (msgid) -#else -# define _(msgid) (msgid) -#endif -#endif - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg = NULL; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* 1003.2 says this must be 1 before any call. */ -int optind = 1; - -/* Formerly, initialization of getopt depended on optind==0, which - causes problems with re-calling getopt as programs generally don't - know that. */ - -int __getopt_initialized = 0; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return -1 with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -#include -#define my_index strchr -#else - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -char *getenv (); - -static char * -my_index (str, chr) - const char *str; - int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. - That was relevant to code that was here before. */ -#if !defined (__STDC__) || !__STDC__ -/* gcc with -traditional declares the built-in strlen to return int, - and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -#endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -#ifdef _LIBC -/* Bash 2.0 gives us an environment variable containing flags - indicating ARGV elements that should not be considered arguments. */ - -static const char *nonoption_flags; -static int nonoption_flags_len; - -static int original_argc; -static char *const *original_argv; - -/* Make sure the environment variable bash 2.0 puts in the environment - is valid for the getopt call we must make sure that the ARGV passed - to getopt is that one passed to the process. */ -static void store_args (int argc, char *const *argv) __attribute__ ((unused)); -static void -store_args (int argc, char *const *argv) -{ - /* XXX This is no good solution. We should rather copy the args so - that we can compare them later. But we must not use malloc(3). */ - original_argc = argc; - original_argv = argv; -} -text_set_element (__libc_subinit, store_args); -#endif - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -#if defined (__STDC__) && __STDC__ -static void exchange (char **); -#endif - -static void -exchange (argv) - char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -#if defined (__STDC__) && __STDC__ -static const char *_getopt_initialize (int, char *const *, const char *); -#endif -static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind = 1; - - nextchar = NULL; - - posixly_correct = getenv ("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - -#ifdef _LIBC - if (posixly_correct == NULL - && argc == original_argc && argv == original_argv) - { - /* Bash 2.0 puts a special variable in the environment for each - command it runs, specifying which ARGV elements are the results of - file name wildcard expansion and therefore should not be - considered as options. */ - char var[100]; - sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ()); - nonoption_flags = getenv (var); - if (nonoption_flags == NULL) - nonoption_flags_len = 0; - else - nonoption_flags_len = strlen (nonoption_flags); - } - else - nonoption_flags_len = 0; -#endif - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns -1. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; -{ - optarg = NULL; - - if (!__getopt_initialized || optind == 0) - { - optstring = _getopt_initialize (argc, argv, optstring); - optind = 1; /* Don't scan ARGV[0], the program name. */ - __getopt_initialized = 1; - } - - /* Test whether ARGV[optind] points to a non-option argument. - Either it does not have option syntax, or there is an environment flag - from the shell indicating it is not an option. The later information - is only used when the used in the GNU libc. */ -#ifdef _LIBC -#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && nonoption_flags[optind] == '1')) -#else -#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') -#endif - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; - - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - _("%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - _("%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); - - nextchar += strlen (nextchar); - - optopt = pfound->val; - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: illegal option -- %c\n"), - argv[0], c); - else - fprintf (stderr, _("%s: invalid option -- %c\n"), - argv[0], c); - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - fprintf (stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == -1) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ - -#endif /* !PALMOS && !WIN32 */ +#if !defined(PALMOS) && !defined(WIN32) + +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 + Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#include +#endif /* GNU C library. */ + +#ifdef VMS +#include +#if HAVE_STRING_H - 0 +#include +#endif +#endif + +#if defined (WIN32) && !defined (__CYGWIN32__) +/* It's not Unix, really. See? Capital letters. */ +#include +#define getpid() GetCurrentProcessId() +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +#else +# define _(msgid) (msgid) +#endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +static const char *nonoption_flags; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void store_args (int argc, char *const *argv) __attribute__ ((unused)); +static void +store_args (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +text_set_element (__libc_subinit, store_args); +#endif + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined (__STDC__) && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined (__STDC__) && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + /* Bash 2.0 puts a special variable in the environment for each + command it runs, specifying which ARGV elements are the results of + file name wildcard expansion and therefore should not be + considered as options. */ + char var[100]; + sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ()); + nonoption_flags = getenv (var); + if (nonoption_flags == NULL) + nonoption_flags_len = 0; + else + nonoption_flags_len = strlen (nonoption_flags); + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (!__getopt_initialized || optind == 0) + { + optstring = _getopt_initialize (argc, argv, optstring); + optind = 1; /* Don't scan ARGV[0], the program name. */ + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && nonoption_flags[optind] == '1')) +#else +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ + +#endif /* !PALMOS && !WIN32 */ diff --git a/getopt1.c b/getopt1.c index 66f3bf1..9f7fe05 100644 --- a/getopt1.c +++ b/getopt1.c @@ -1,193 +1,193 @@ -#if !defined(PALMOS) && !defined(WIN32) - -/* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. - - This file is part of the GNU C Library. Its master source is NOT part of - the C library, however. The master source lives in /gd/gnu/lib. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "getopt.h" - -#if !defined (__STDC__) || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 -#include -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); -} - - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -#include - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ - -#endif /* !PALMOS && !WIN32 */ +#if !defined(PALMOS) && !defined(WIN32) + +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ + +#endif /* !PALMOS && !WIN32 */ diff --git a/global.c b/global.c index 52bae7e..4b6baff 100644 --- a/global.c +++ b/global.c @@ -1,150 +1,150 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: global.c,v 1.21 2003/08/31 16:05:05 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" - -/** - * - */ -UINT8 hilo_getbyte (UINT8 *mem) -{ - return mem[0]; -} - -/** - * - */ -UINT16 hilo_getword (UINT8 *mem) -{ - return ((UINT16)mem[0] << 8) + (mem[1]); -} - -/** - * - */ -UINT32 hilo_getpword (UINT8 *mem) -{ - return ((UINT32)mem[0] << 16) + ((UINT32)mem[1] << 8) + (mem[2]); -} - -/** - * - */ -UINT32 hilo_getdword (UINT8 *mem) -{ - return ((UINT32)mem[0] << 24) + ((UINT32)mem[1] << 16) + - ((UINT32)mem[2] << 8) + (mem[3]); -} - -/** - * - */ -UINT8 lohi_getbyte (UINT8 *mem) -{ - return mem[0]; -} - -/** - * - */ -UINT16 lohi_getword (UINT8 *mem) -{ - return ((UINT16)mem[1] << 8) + (mem[0]); -} - -/** - * - */ -UINT32 lohi_getpword (UINT8 *mem) -{ - return ((UINT32)mem[2] << 16) + ((UINT32)mem[1] << 8) + (mem[0]); -} - -/** - * - */ -UINT32 lohi_getdword (UINT8 *mem) -{ - return ((UINT32)mem[3] << 24) + ((UINT32)mem[2] << 16) + - ((UINT32)mem[1] << 8) + (mem[0]); - -} - -/** - * - */ -int getflag (int n) -{ - UINT8 *set = (UINT8 *)&game.flags; - - set += n >> 3; - return (*set & (1 << (n & 0x07))) != 0; -} - -/** - * - */ -void setflag (int n, int v) -{ - UINT8 *set = (UINT8 *)&game.flags; - - set += n >> 3; - if (v) - *set |= 1 << (n & 0x07); /* set bit */ - else - *set &= ~(1 << (n & 0x07)); /* clear bit */ -} - -/** - * - */ -void flipflag (int n) -{ - UINT8 *set = (UINT8 *)&game.flags; - - set += n >> 3; - *set ^= 1 << (n & 0x07); /* flip bit */ -} - -/** - * - */ -void setvar (int var, int val) -{ - game.vars[var] = val; -} - -/** - * - */ -int getvar (int var) -{ - return game.vars[var]; -} - -/** - * - */ -void decrypt (UINT8 *mem, int len) -{ - UINT8 *key; - int i; - - key = opt.agds ? (UINT8*)CRYPT_KEY_AGDS : (UINT8*)CRYPT_KEY_SIERRA; - - for (i = 0; i < len; i++) - *(mem + i) ^= *(key + (i % 11)); -} - -/* end: global.c */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: global.c,v 1.21 2003/08/31 16:05:05 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" + +/** + * + */ +UINT8 hilo_getbyte (UINT8 *mem) +{ + return mem[0]; +} + +/** + * + */ +UINT16 hilo_getword (UINT8 *mem) +{ + return ((UINT16)mem[0] << 8) + (mem[1]); +} + +/** + * + */ +UINT32 hilo_getpword (UINT8 *mem) +{ + return ((UINT32)mem[0] << 16) + ((UINT32)mem[1] << 8) + (mem[2]); +} + +/** + * + */ +UINT32 hilo_getdword (UINT8 *mem) +{ + return ((UINT32)mem[0] << 24) + ((UINT32)mem[1] << 16) + + ((UINT32)mem[2] << 8) + (mem[3]); +} + +/** + * + */ +UINT8 lohi_getbyte (UINT8 *mem) +{ + return mem[0]; +} + +/** + * + */ +UINT16 lohi_getword (UINT8 *mem) +{ + return ((UINT16)mem[1] << 8) + (mem[0]); +} + +/** + * + */ +UINT32 lohi_getpword (UINT8 *mem) +{ + return ((UINT32)mem[2] << 16) + ((UINT32)mem[1] << 8) + (mem[0]); +} + +/** + * + */ +UINT32 lohi_getdword (UINT8 *mem) +{ + return ((UINT32)mem[3] << 24) + ((UINT32)mem[2] << 16) + + ((UINT32)mem[1] << 8) + (mem[0]); + +} + +/** + * + */ +int getflag (int n) +{ + UINT8 *set = (UINT8 *)&game.flags; + + set += n >> 3; + return (*set & (1 << (n & 0x07))) != 0; +} + +/** + * + */ +void setflag (int n, int v) +{ + UINT8 *set = (UINT8 *)&game.flags; + + set += n >> 3; + if (v) + *set |= 1 << (n & 0x07); /* set bit */ + else + *set &= ~(1 << (n & 0x07)); /* clear bit */ +} + +/** + * + */ +void flipflag (int n) +{ + UINT8 *set = (UINT8 *)&game.flags; + + set += n >> 3; + *set ^= 1 << (n & 0x07); /* flip bit */ +} + +/** + * + */ +void setvar (int var, int val) +{ + game.vars[var] = val; +} + +/** + * + */ +int getvar (int var) +{ + return game.vars[var]; +} + +/** + * + */ +void decrypt (UINT8 *mem, int len) +{ + UINT8 *key; + int i; + + key = opt.agds ? (UINT8*)CRYPT_KEY_AGDS : (UINT8*)CRYPT_KEY_SIERRA; + + for (i = 0; i < len; i++) + *(mem + i) ^= *(key + (i % 11)); +} + +/* end: global.c */ + diff --git a/graphics.c b/graphics.c index bf2a20c..83c3c47 100644 --- a/graphics.c +++ b/graphics.c @@ -1,712 +1,712 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999, 2007-2003 Stuart George and Claudio Matsuoka - * - * $Id: graphics.c,v 1.60 2003/09/06 13:33:12 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "graphics.h" - -#if defined PALMOS || defined FAKE_PALMOS -# define DEV_X0(x) (x) -# define DEV_X1(x) (x) -# define DEV_Y(x) ((x) * PIC_HEIGHT / 168) -#else -# define DEV_X0(x) ((x) << 1) -# define DEV_X1(x) (((x) << 1) + 1) -# define DEV_Y(x) (x) -#endif - -#ifndef MAX_INT -# define MAX_INT (int)((unsigned)~0 >> 1) -#endif - -static pixel_t *sarien_screen; -#ifdef USE_CONSOLE -static UINT8 *console_screen; -#endif - -extern UINT8 cur_font[]; - -/** - * 16 color RGB palette (plus 16 transparent colors). - * This array contains the 6-bit RGB values of the EGA palette exported - * to the console drivers. - */ -UINT8 ega_palette [16 * 3] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x2a, - 0x00, 0x2a, 0x00, - 0x00, 0x2a, 0x2a, - 0x2a, 0x00, 0x00, - 0x2a, 0x00, 0x2a, - 0x2a, 0x15, 0x00, - 0x2a, 0x2a, 0x2a, - 0x15, 0x15, 0x15, - 0x15, 0x15, 0x3f, - 0x15, 0x3f, 0x15, - 0x15, 0x3f, 0x3f, - 0x3f, 0x15, 0x15, - 0x3f, 0x15, 0x3f, - 0x3f, 0x3f, 0x15, - 0x3f, 0x3f, 0x3f -}; - -/** - * 16 color amiga-ish palette. - */ -UINT8 new_palette[16 * 3]= { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3f, - 0x00, 0x2A, 0x00, - 0x00, 0x2A, 0x2A, - 0x33, 0x00, 0x00, - 0x2f, 0x1c, 0x37, - 0x23, 0x14, 0x00, - 0x2f, 0x2f, 0x2f, - 0x15, 0x15, 0x15, - 0x00, 0x2f, 0x3f, - 0x00, 0x33, 0x15, - 0x15, 0x3F, 0x3F, - 0x3f, 0x27, 0x23, - 0x3f, 0x15, 0x3f, - 0x3b, 0x3b, 0x00, - 0x3F, 0x3F, 0x3F -}; - -UINT8 palette[32 * 3]; - - -static UINT16 cga_map[16] = { - 0x0000, /* 0 - black */ - 0x0d00, /* 1 - blue */ - 0x0b00, /* 2 - green */ - 0x0f00, /* 3 - cyan */ - 0x000b, /* 4 - red */ - 0x0b0d, /* 5 - magenta */ - 0x000d, /* 6 - brown */ - 0x0b0b, /* 7 - gray */ - 0x0d0d, /* 8 - dark gray */ - 0x0b0f, /* 9 - light blue */ - 0x0b0d, /* 10 - light green */ - 0x0f0d, /* 11 - light cyan */ - 0x0f0d, /* 12 - light red */ - 0x0f00, /* 13 - light magenta */ - 0x0f0b, /* 14 - yellow */ - 0x0f0f /* 15 - white */ -}; - -struct update_block { - int x1, y1; - int x2, y2; -}; - - -static struct update_block update = { - MAX_INT, MAX_INT, 0, 0 -}; - -struct gfx_driver *gfx; /* graphics driver */ - - - - -/* - * Layer 4: 640x480? ================== User display - * ^ - * | do_update(), put_block() - * | - * Layer 3: 640x480? ================== Framebuffer - * ^ - * | flush_block(), put_pixels() - * | - * Layer 2: 320x200 ================== Sarien screen (console), put_pixel() - * | - * Layer 1: 160x168 ================== AGI screen - */ - -#ifdef USE_CONSOLE - -/** - * Draws a row of pixels in the output device framebuffer. - * This function adds the console layer using transparent colors if - * appropriate. - */ -static void put_pixels (const int x, const int y, const int w, UINT8 *p) -{ - int i; - UINT8 _b[GFX_WIDTH] = { 0 }; - UINT8 *b, *c = NULL; - - if (console.y <= y) { - gfx->put_pixels (x, y, w, p); - return; - } - - b = &_b[0]; - c = &console_screen[x + (y + GFX_HEIGHT - 1 - console.y) * GFX_WIDTH]; - - for (i = 0; i < w; i++, c++, p++) { - *b++ = *c ? *c : *p + 16; - } - - gfx->put_pixels (x, y, w, _b); -} - -static void init_console () -{ - int i; - - /* Console */ - console.line[0] = calloc (CONSOLE_LINES_BUFFER, CONSOLE_LINE_SIZE + 1); - for (i = 1; i < CONSOLE_LINES_BUFFER; i++) - console.line[i] = console.line[i - 1] + CONSOLE_LINE_SIZE + 1; -} - -#else - -static void put_pixels (const int x, const int y, const int w, pixel_t *p) -{ - gfx->put_pixels (x, y, w, p); -} - -static void init_console () -{ -} - -#endif /* USE_CONSOLE */ - - -#define SHAKE_MAG 3 -static pixel_t *shake_h, *shake_v; - -void shake_start () -{ - int i; - - if ((shake_h = malloc (GFX_WIDTH * SHAKE_MAG * sizeof(pixel_t))) == NULL) - return; - - if ((shake_v = malloc (SHAKE_MAG * (GFX_HEIGHT - SHAKE_MAG) * sizeof(pixel_t))) == NULL) { - free (shake_h); - return; - } - - for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) { - memcpy (shake_v + i * SHAKE_MAG, - sarien_screen + i * GFX_WIDTH, SHAKE_MAG * sizeof(pixel_t)); - } - - for (i = 0; i < SHAKE_MAG; i++) { - memcpy (shake_h + i * GFX_WIDTH, sarien_screen + i * GFX_WIDTH, - GFX_WIDTH * sizeof(pixel_t)); - } -} - - -void shake_screen (int n) -{ - int i; - - if (n == 0) { - for (i = 0; i < (GFX_HEIGHT - SHAKE_MAG); i++) { - memmove (&sarien_screen[GFX_WIDTH * i], - &sarien_screen[GFX_WIDTH * (i + SHAKE_MAG) + - SHAKE_MAG], (GFX_WIDTH - SHAKE_MAG) * sizeof(pixel_t)); - } - } else { - for (i = GFX_HEIGHT - SHAKE_MAG - 1; i >= 0; i--) { - memmove (&sarien_screen[GFX_WIDTH * (i + SHAKE_MAG) + - SHAKE_MAG], &sarien_screen[GFX_WIDTH * i], - (GFX_WIDTH - SHAKE_MAG) * sizeof(pixel_t)); - } - } -} - - -void shake_end () -{ - int i; - - for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) { - memcpy (sarien_screen + i * GFX_WIDTH, - shake_v + i * SHAKE_MAG, SHAKE_MAG * sizeof(pixel_t)); - } - - for (i = 0; i < SHAKE_MAG; i++) { - memcpy (sarien_screen + i * GFX_WIDTH, - shake_h + i * GFX_WIDTH, GFX_WIDTH * sizeof(pixel_t)); - } - - flush_block (0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); - - free (shake_v); - free (shake_h); -} - - -void put_text_character (int l, int x, int y, unsigned int c, int fg, int bg) -{ - int x1, y1, xx, yy, cc; - pixel_t *p; - -#if defined PALMOS || defined FAKE_PALMOS - if (c & 0x80) - c = 1; -#endif - - p = cur_font + ((unsigned int)c * CHAR_LINES); - for (y1 = 0; y1 < CHAR_LINES; y1++) { - for (x1 = 0; x1 < CHAR_COLS; x1 ++) { - xx = x + x1; - yy = y + y1; - cc = (*p & (1 << (7 - x1))) ? fg : bg; -#ifdef USE_CONSOLE - if (l) { - console_screen[xx + yy * GFX_WIDTH] = cc; - } else -#endif - { - sarien_screen [xx + yy * GFX_WIDTH] = cc; - } - } - - p++; - } - /* FIXME: we don't want this when we're writing on the - * console! - */ - flush_block (x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1); -} - - -void draw_rectangle (int x1, int y1, int x2, int y2, int c) -{ - int y, w, h; - pixel_t *p0; - - if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; - if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; - if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; - if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; - - w = x2 - x1 + 1; - h = y2 - y1 + 1; - p0 = &sarien_screen[x1 + y1 * GFX_WIDTH]; - for (y = 0; y < h; y++) { - memset (p0, c, w * sizeof(pixel_t)); - p0 += GFX_WIDTH; - } -} - - -static void draw_frame (int x1, int y1, int x2, int y2, int c1, int c2) -{ - int y, w; - pixel_t *p0; - - /* top line */ - w = x2 - x1 + 1; - p0 = &sarien_screen[x1 + y1 * GFX_WIDTH]; - memset (p0, c1, w * sizeof(pixel_t)); - - /* bottom line */ - p0 = &sarien_screen[x1 + y2 * GFX_WIDTH]; - memset (p0, c2, w * sizeof(pixel_t)); - - /* side lines */ - for (y = y1; y <= y2; y++) { - sarien_screen[x1 + y * GFX_WIDTH] = c1; - sarien_screen[x2 + y * GFX_WIDTH] = c2; - } -} - - -void draw_box (int x1, int y1, int x2, int y2, int colour1, int colour2, int m) -{ - x1 += m; - y1 += m; - x2 -= m; - y2 -= m; - - draw_rectangle (x1, y1, x2, y2, colour1); - draw_frame (x1 + 2, y1 + 2, x2 - 2, y2 - 2, colour2, colour2); - flush_block (x1, y1, x2, y2); -} - - -void print_character (int x, int y, char c, int fg, int bg) -{ - x *= CHAR_COLS; - y *= CHAR_LINES; - - put_text_character (0, x, y, c, fg, bg); - /* redundant! already inside put_text_character! */ - /* flush_block (x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1); */ -} - -/** - * Draw button - * @param x x coordinate of the button - * @param y y coordinate of the button - * @param a set if the button has focus - * @param p set if the button is pressed - */ -void draw_button (int x, int y, char *s, int a, int p) -{ - int len = strlen (s); - int x1, y1, x2, y2; - - x1 = x - 3; - y1 = y - 3; - x2 = x + CHAR_COLS * len + 2; - y2 = y + CHAR_LINES + 2; - - while (*s) { - put_text_character (0, x + (!!p), y + (!!p), *s++, - a ? 15 : 0, - a ? 0 : 15); - x += CHAR_COLS; - } - - x1 -= 2; y1 -= 2; - x2 += 2; y2 += 2; - - flush_block (x1, y1, x2, y2); -} - -#ifdef USE_MOUSE -int test_button (int x, int y, char *s) -{ - int len = strlen (s); - int x1, y1, x2, y2; - - x1 = x - 3; - y1 = y - 3; - x2 = x + CHAR_COLS * len + 2; - y2 = y + CHAR_LINES + 2; - - if (mouse.x >= x1 && mouse.y >= y1 && mouse.x <= x2 && mouse.y <= y2) - return TRUE; - - return FALSE; -} -#endif - -void put_block (int x1, int y1, int x2, int y2) -{ - gfx->put_block (x1, y1, x2, y2); -} - -void put_screen () -{ - put_block (0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); -} - -void poll_timer () -{ - gfx->poll_timer (); -} - - -int get_key () -{ - return gfx->get_key (); -} - - -int keypress () -{ - return gfx->keypress (); -} - - -/* - * Public functions - */ - -/** - * Initialize the color palette - * This function initializes the color palette using the specified 16-color - * RGB palette and creates 16 extra palette entries with translucent colors - * for the interpreter console. - * @param p A pointer to the 16-color RGB palette. - */ -void init_palette (UINT8 *p) -{ - int i; - - for (i = 0; i < 48; i++) { - palette[i] = p[i]; - palette[i + 48] = (p[i] + 0x30) >> 2; - } -} - -/** - * Initialize graphics device. - * - * @see deinit_video() - */ -int init_video () -{ - if (opt.egapal) - init_palette (ega_palette); - else - init_palette (new_palette); - - init_console (); - - if ((sarien_screen = calloc (GFX_WIDTH, GFX_HEIGHT * sizeof(pixel_t))) == NULL) - return err_NotEnoughMemory; - -#ifdef USE_CONSOLE - if ((console_screen = calloc (GFX_WIDTH, GFX_HEIGHT)) == NULL) { - free (sarien_screen); - return err_NotEnoughMemory; - } -#endif - - return gfx->init_video_mode (); -} - -/** - * Deinitialize graphics device. - * - * @see init_video() - */ -int deinit_video () -{ - int rc; - - rc = gfx->deinit_video_mode (); - free (sarien_screen); -#ifdef USE_CONSOLE - free (console_screen); -#endif - - return rc; -} - - -/** - * Write pixels on the output device. - * This function writes a row of pixels on the output device. Only the - * lower 4 bits of each pixel in the row will be used, making this - * function suitable for use with rows from the AGI screen. - * @param x x coordinate of the row start (AGI coord.) - * @param y y coordinate of the row start (AGI coord.) - * @param n number of pixels in the row - * @param p pointer to the row start in the AGI screen - */ -void put_pixels_a (int x, int y, int n, pixel_t *p) -{ - -#ifdef FAKE_PALMOS - for (; n--; p++, x ++) { - *(pixel_t *)&sarien_screen[x + DEV_Y(y) * GFX_WIDTH] = *p & 0x0f; - } -#else - - if (opt.cgaemu) { - for (x *= 2; n--; p++, x += 2) { - register UINT16 q = (cga_map[(*p & 0xf0) >> 4] << 4) | - cga_map[*p & 0x0f]; -#ifdef USE_CONSOLE - if (debug.priority) q >>= 4; -#endif - *(UINT16 *)&sarien_screen[x + y * GFX_WIDTH] = - q & 0x0f0f; - } - } else { - for (x *= 2; n--; p++, x += 2) { - register UINT16 q = ((UINT16)*p << 8) | *p; -#ifdef USE_CONSOLE - if (debug.priority) q >>= 4; -#endif - *(UINT16 *)&sarien_screen[x + y * GFX_WIDTH] = - q & 0x0f0f; - } - } -#endif -} - -#ifdef USE_HIRES - -void put_pixels_hires (int x, int y, int n, UINT8 *p) -{ - /* y += CHAR_LINES; */ - for (; n--; p++, x++) { - UINT8 q = *p; -#ifdef USE_CONSOLE - if (debug.priority) q >>= 4; -#endif - sarien_screen[x + y * GFX_WIDTH] = q & 0x0f; - } -} - -#endif - - -/** - * Schedule blocks for blitting on the output device. - * This function gets the coordinates of a block in the AGI screen and - * schedule it to be updated in the output device. - * @param x1 x coordinate of the upper left corner of the block (AGI coord.) - * @param y1 y coordinate of the upper left corner of the block (AGI coord.) - * @param x2 x coordinate of the lower right corner of the block (AGI coord.) - * @param y2 y coordinate of the lower right corner of the block (AGI coord.) - * - * @see do_update() - */ -void schedule_update (int x1, int y1, int x2, int y2) -{ - if (x1 < update.x1) update.x1 = x1; - if (y1 < update.y1) update.y1 = y1; - if (x2 > update.x2) update.x2 = x2; - if (y2 > update.y2) update.y2 = y2; -} - -/** - * Update scheduled blocks on the output device. - * This function exposes the blocks scheduled for updating to the output - * device. Blocks can be scheduled at any point of the AGI cycle. - * - * @see schedule_update() - */ -void do_update () -{ - if (update.x1 <= update.x2 && update.y1 <= update.y2) { - gfx->put_block (update.x1, update.y1, update.x2, update.y2); - } - - /* reset update block variables */ - update.x1 = MAX_INT; - update.y1 = MAX_INT; - update.x2 = 0; - update.y2 = 0; -} - - -/** - * Updates a block of the framebuffer with contents of the Sarien screen. - * This function updates a block in the output device with the contents of - * the Sarien screen, handling console transparency. - * @param x1 x coordinate of the upper left corner of the block - * @param y1 y coordinate of the upper left corner of the block - * @param x2 x coordinate of the lower right corner of the block - * @param y2 y coordinate of the lower right corner of the block - * - * @see flush_block_a() - */ -void flush_block (int x1, int y1, int x2, int y2) -{ - int y, w; - pixel_t *p0; - - schedule_update (x1, y1, x2, y2); - - p0 = &sarien_screen[x1 + y1 * GFX_WIDTH]; - w = x2 - x1 + 1; - - for (y = y1; y <= y2; y++) { - put_pixels (x1, y, w, p0); - p0 += GFX_WIDTH; - } -} - -/** - * Updates a block of the framebuffer receiving AGI picture coordinates. - * @param x1 x AGI picture coordinate of the upper left corner of the block - * @param y1 y AGI picture coordinate of the upper left corner of the block - * @param x2 x AGI picture coordinate of the lower right corner of the block - * @param y2 y AGI picture coordinate of the lower right corner of the block - * - * @see flush_block() - */ -void flush_block_a (int x1, int y1, int x2, int y2) -{ - /* y1 += 8; - y2 += 8; */ - flush_block (DEV_X0(x1), DEV_Y(y1), DEV_X1(x2), DEV_Y(y2)); -} - -/** - * Updates the framebuffer with contents of the Sarien screen (console-aware). - * This function updates the output device with the contents of the AGI - * screen, handling console transparency. - */ -void flush_screen () -{ - flush_block (0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); -} - -/** - * Clear the output device screen (console-aware). - * This function clears the output device screen and updates the - * output device. Contents of the AGI screen are left untouched. This - * function can be used to simulate a switch to a text mode screen in - * a graphic-only device. - * @param c color to clear the screen - */ -void clear_screen (int c) -{ - memset (sarien_screen, c, GFX_WIDTH * GFX_HEIGHT * sizeof(pixel_t)); - flush_screen (); -} - -#ifdef USE_CONSOLE -/** - * Clear the console screen. - * This function clears the top n lines of the console screen. - * @param n number of lines to clear (in pixels) - */ -void clear_console_screen (int n) -{ - memset (console_screen + n * GFX_WIDTH, 0, (GFX_HEIGHT - n) * GFX_WIDTH * sizeof(pixel_t)); -} -#endif - -/** - * Save a block of the Sarien screen - */ -void save_block (int x1, int y1, int x2, int y2, pixel_t *b) -{ - pixel_t *p0; - int w, h; - - p0 = &sarien_screen[x1 + GFX_WIDTH * y1]; - w = x2 - x1 + 1; - h = y2 - y1 + 1; - while (h--) { - memcpy (b, p0, w * sizeof(pixel_t)); - b += w; - p0 += GFX_WIDTH; - } -} - -/** - * Restore a block of the Sarien screen - */ -void restore_block (int x1, int y1, int x2, int y2, pixel_t *b) -{ - pixel_t *p0; - int w, h; - - p0 = &sarien_screen[x1 + GFX_WIDTH * y1]; - w = x2 - x1 + 1; - h = y2 - y1 + 1; - while (h--) { - memcpy (p0, b, w * sizeof(pixel_t)); - b += w; - p0 += GFX_WIDTH; - } - flush_block (x1, y1, x2, y2); -} - -/* end: graphics.c */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999, 2007-2003 Stuart George and Claudio Matsuoka + * + * $Id: graphics.c,v 1.60 2003/09/06 13:33:12 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "graphics.h" + +#if defined PALMOS || defined FAKE_PALMOS +# define DEV_X0(x) (x) +# define DEV_X1(x) (x) +# define DEV_Y(x) ((x) * PIC_HEIGHT / 168) +#else +# define DEV_X0(x) ((x) << 1) +# define DEV_X1(x) (((x) << 1) + 1) +# define DEV_Y(x) (x) +#endif + +#ifndef MAX_INT +# define MAX_INT (int)((unsigned)~0 >> 1) +#endif + +static pixel_t *sarien_screen; +#ifdef USE_CONSOLE +static UINT8 *console_screen; +#endif + +extern UINT8 cur_font[]; + +/** + * 16 color RGB palette (plus 16 transparent colors). + * This array contains the 6-bit RGB values of the EGA palette exported + * to the console drivers. + */ +UINT8 ega_palette [16 * 3] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x2a, + 0x00, 0x2a, 0x00, + 0x00, 0x2a, 0x2a, + 0x2a, 0x00, 0x00, + 0x2a, 0x00, 0x2a, + 0x2a, 0x15, 0x00, + 0x2a, 0x2a, 0x2a, + 0x15, 0x15, 0x15, + 0x15, 0x15, 0x3f, + 0x15, 0x3f, 0x15, + 0x15, 0x3f, 0x3f, + 0x3f, 0x15, 0x15, + 0x3f, 0x15, 0x3f, + 0x3f, 0x3f, 0x15, + 0x3f, 0x3f, 0x3f +}; + +/** + * 16 color amiga-ish palette. + */ +UINT8 new_palette[16 * 3]= { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, + 0x00, 0x2A, 0x00, + 0x00, 0x2A, 0x2A, + 0x33, 0x00, 0x00, + 0x2f, 0x1c, 0x37, + 0x23, 0x14, 0x00, + 0x2f, 0x2f, 0x2f, + 0x15, 0x15, 0x15, + 0x00, 0x2f, 0x3f, + 0x00, 0x33, 0x15, + 0x15, 0x3F, 0x3F, + 0x3f, 0x27, 0x23, + 0x3f, 0x15, 0x3f, + 0x3b, 0x3b, 0x00, + 0x3F, 0x3F, 0x3F +}; + +UINT8 palette[32 * 3]; + + +static UINT16 cga_map[16] = { + 0x0000, /* 0 - black */ + 0x0d00, /* 1 - blue */ + 0x0b00, /* 2 - green */ + 0x0f00, /* 3 - cyan */ + 0x000b, /* 4 - red */ + 0x0b0d, /* 5 - magenta */ + 0x000d, /* 6 - brown */ + 0x0b0b, /* 7 - gray */ + 0x0d0d, /* 8 - dark gray */ + 0x0b0f, /* 9 - light blue */ + 0x0b0d, /* 10 - light green */ + 0x0f0d, /* 11 - light cyan */ + 0x0f0d, /* 12 - light red */ + 0x0f00, /* 13 - light magenta */ + 0x0f0b, /* 14 - yellow */ + 0x0f0f /* 15 - white */ +}; + +struct update_block { + int x1, y1; + int x2, y2; +}; + + +static struct update_block update = { + MAX_INT, MAX_INT, 0, 0 +}; + +struct gfx_driver *gfx; /* graphics driver */ + + + + +/* + * Layer 4: 640x480? ================== User display + * ^ + * | do_update(), put_block() + * | + * Layer 3: 640x480? ================== Framebuffer + * ^ + * | flush_block(), put_pixels() + * | + * Layer 2: 320x200 ================== Sarien screen (console), put_pixel() + * | + * Layer 1: 160x168 ================== AGI screen + */ + +#ifdef USE_CONSOLE + +/** + * Draws a row of pixels in the output device framebuffer. + * This function adds the console layer using transparent colors if + * appropriate. + */ +static void put_pixels (const int x, const int y, const int w, UINT8 *p) +{ + int i; + UINT8 _b[GFX_WIDTH] = { 0 }; + UINT8 *b, *c = NULL; + + if (console.y <= y) { + gfx->put_pixels (x, y, w, p); + return; + } + + b = &_b[0]; + c = &console_screen[x + (y + GFX_HEIGHT - 1 - console.y) * GFX_WIDTH]; + + for (i = 0; i < w; i++, c++, p++) { + *b++ = *c ? *c : *p + 16; + } + + gfx->put_pixels (x, y, w, _b); +} + +static void init_console () +{ + int i; + + /* Console */ + console.line[0] = calloc (CONSOLE_LINES_BUFFER, CONSOLE_LINE_SIZE + 1); + for (i = 1; i < CONSOLE_LINES_BUFFER; i++) + console.line[i] = console.line[i - 1] + CONSOLE_LINE_SIZE + 1; +} + +#else + +static void put_pixels (const int x, const int y, const int w, pixel_t *p) +{ + gfx->put_pixels (x, y, w, p); +} + +static void init_console () +{ +} + +#endif /* USE_CONSOLE */ + + +#define SHAKE_MAG 3 +static pixel_t *shake_h, *shake_v; + +void shake_start () +{ + int i; + + if ((shake_h = malloc (GFX_WIDTH * SHAKE_MAG * sizeof(pixel_t))) == NULL) + return; + + if ((shake_v = malloc (SHAKE_MAG * (GFX_HEIGHT - SHAKE_MAG) * sizeof(pixel_t))) == NULL) { + free (shake_h); + return; + } + + for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) { + memcpy (shake_v + i * SHAKE_MAG, + sarien_screen + i * GFX_WIDTH, SHAKE_MAG * sizeof(pixel_t)); + } + + for (i = 0; i < SHAKE_MAG; i++) { + memcpy (shake_h + i * GFX_WIDTH, sarien_screen + i * GFX_WIDTH, + GFX_WIDTH * sizeof(pixel_t)); + } +} + + +void shake_screen (int n) +{ + int i; + + if (n == 0) { + for (i = 0; i < (GFX_HEIGHT - SHAKE_MAG); i++) { + memmove (&sarien_screen[GFX_WIDTH * i], + &sarien_screen[GFX_WIDTH * (i + SHAKE_MAG) + + SHAKE_MAG], (GFX_WIDTH - SHAKE_MAG) * sizeof(pixel_t)); + } + } else { + for (i = GFX_HEIGHT - SHAKE_MAG - 1; i >= 0; i--) { + memmove (&sarien_screen[GFX_WIDTH * (i + SHAKE_MAG) + + SHAKE_MAG], &sarien_screen[GFX_WIDTH * i], + (GFX_WIDTH - SHAKE_MAG) * sizeof(pixel_t)); + } + } +} + + +void shake_end () +{ + int i; + + for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) { + memcpy (sarien_screen + i * GFX_WIDTH, + shake_v + i * SHAKE_MAG, SHAKE_MAG * sizeof(pixel_t)); + } + + for (i = 0; i < SHAKE_MAG; i++) { + memcpy (sarien_screen + i * GFX_WIDTH, + shake_h + i * GFX_WIDTH, GFX_WIDTH * sizeof(pixel_t)); + } + + flush_block (0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); + + free (shake_v); + free (shake_h); +} + + +void put_text_character (int l, int x, int y, unsigned int c, int fg, int bg) +{ + int x1, y1, xx, yy, cc; + pixel_t *p; + +#if defined PALMOS || defined FAKE_PALMOS + if (c & 0x80) + c = 1; +#endif + + p = cur_font + ((unsigned int)c * CHAR_LINES); + for (y1 = 0; y1 < CHAR_LINES; y1++) { + for (x1 = 0; x1 < CHAR_COLS; x1 ++) { + xx = x + x1; + yy = y + y1; + cc = (*p & (1 << (7 - x1))) ? fg : bg; +#ifdef USE_CONSOLE + if (l) { + console_screen[xx + yy * GFX_WIDTH] = cc; + } else +#endif + { + sarien_screen [xx + yy * GFX_WIDTH] = cc; + } + } + + p++; + } + /* FIXME: we don't want this when we're writing on the + * console! + */ + flush_block (x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1); +} + + +void draw_rectangle (int x1, int y1, int x2, int y2, int c) +{ + int y, w, h; + pixel_t *p0; + + if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; + if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; + if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; + if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; + + w = x2 - x1 + 1; + h = y2 - y1 + 1; + p0 = &sarien_screen[x1 + y1 * GFX_WIDTH]; + for (y = 0; y < h; y++) { + memset (p0, c, w * sizeof(pixel_t)); + p0 += GFX_WIDTH; + } +} + + +static void draw_frame (int x1, int y1, int x2, int y2, int c1, int c2) +{ + int y, w; + pixel_t *p0; + + /* top line */ + w = x2 - x1 + 1; + p0 = &sarien_screen[x1 + y1 * GFX_WIDTH]; + memset (p0, c1, w * sizeof(pixel_t)); + + /* bottom line */ + p0 = &sarien_screen[x1 + y2 * GFX_WIDTH]; + memset (p0, c2, w * sizeof(pixel_t)); + + /* side lines */ + for (y = y1; y <= y2; y++) { + sarien_screen[x1 + y * GFX_WIDTH] = c1; + sarien_screen[x2 + y * GFX_WIDTH] = c2; + } +} + + +void draw_box (int x1, int y1, int x2, int y2, int colour1, int colour2, int m) +{ + x1 += m; + y1 += m; + x2 -= m; + y2 -= m; + + draw_rectangle (x1, y1, x2, y2, colour1); + draw_frame (x1 + 2, y1 + 2, x2 - 2, y2 - 2, colour2, colour2); + flush_block (x1, y1, x2, y2); +} + + +void print_character (int x, int y, char c, int fg, int bg) +{ + x *= CHAR_COLS; + y *= CHAR_LINES; + + put_text_character (0, x, y, c, fg, bg); + /* redundant! already inside put_text_character! */ + /* flush_block (x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1); */ +} + +/** + * Draw button + * @param x x coordinate of the button + * @param y y coordinate of the button + * @param a set if the button has focus + * @param p set if the button is pressed + */ +void draw_button (int x, int y, char *s, int a, int p) +{ + int len = strlen (s); + int x1, y1, x2, y2; + + x1 = x - 3; + y1 = y - 3; + x2 = x + CHAR_COLS * len + 2; + y2 = y + CHAR_LINES + 2; + + while (*s) { + put_text_character (0, x + (!!p), y + (!!p), *s++, + a ? 15 : 0, + a ? 0 : 15); + x += CHAR_COLS; + } + + x1 -= 2; y1 -= 2; + x2 += 2; y2 += 2; + + flush_block (x1, y1, x2, y2); +} + +#ifdef USE_MOUSE +int test_button (int x, int y, char *s) +{ + int len = strlen (s); + int x1, y1, x2, y2; + + x1 = x - 3; + y1 = y - 3; + x2 = x + CHAR_COLS * len + 2; + y2 = y + CHAR_LINES + 2; + + if (mouse.x >= x1 && mouse.y >= y1 && mouse.x <= x2 && mouse.y <= y2) + return TRUE; + + return FALSE; +} +#endif + +void put_block (int x1, int y1, int x2, int y2) +{ + gfx->put_block (x1, y1, x2, y2); +} + +void put_screen () +{ + put_block (0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); +} + +void poll_timer () +{ + gfx->poll_timer (); +} + + +int get_key () +{ + return gfx->get_key (); +} + + +int keypress () +{ + return gfx->keypress (); +} + + +/* + * Public functions + */ + +/** + * Initialize the color palette + * This function initializes the color palette using the specified 16-color + * RGB palette and creates 16 extra palette entries with translucent colors + * for the interpreter console. + * @param p A pointer to the 16-color RGB palette. + */ +void init_palette (UINT8 *p) +{ + int i; + + for (i = 0; i < 48; i++) { + palette[i] = p[i]; + palette[i + 48] = (p[i] + 0x30) >> 2; + } +} + +/** + * Initialize graphics device. + * + * @see deinit_video() + */ +int init_video () +{ + if (opt.egapal) + init_palette (ega_palette); + else + init_palette (new_palette); + + init_console (); + + if ((sarien_screen = calloc (GFX_WIDTH, GFX_HEIGHT * sizeof(pixel_t))) == NULL) + return err_NotEnoughMemory; + +#ifdef USE_CONSOLE + if ((console_screen = calloc (GFX_WIDTH, GFX_HEIGHT)) == NULL) { + free (sarien_screen); + return err_NotEnoughMemory; + } +#endif + + return gfx->init_video_mode (); +} + +/** + * Deinitialize graphics device. + * + * @see init_video() + */ +int deinit_video () +{ + int rc; + + rc = gfx->deinit_video_mode (); + free (sarien_screen); +#ifdef USE_CONSOLE + free (console_screen); +#endif + + return rc; +} + + +/** + * Write pixels on the output device. + * This function writes a row of pixels on the output device. Only the + * lower 4 bits of each pixel in the row will be used, making this + * function suitable for use with rows from the AGI screen. + * @param x x coordinate of the row start (AGI coord.) + * @param y y coordinate of the row start (AGI coord.) + * @param n number of pixels in the row + * @param p pointer to the row start in the AGI screen + */ +void put_pixels_a (int x, int y, int n, pixel_t *p) +{ + +#ifdef FAKE_PALMOS + for (; n--; p++, x ++) { + *(pixel_t *)&sarien_screen[x + DEV_Y(y) * GFX_WIDTH] = *p & 0x0f; + } +#else + + if (opt.cgaemu) { + for (x *= 2; n--; p++, x += 2) { + register UINT16 q = (cga_map[(*p & 0xf0) >> 4] << 4) | + cga_map[*p & 0x0f]; +#ifdef USE_CONSOLE + if (debug.priority) q >>= 4; +#endif + *(UINT16 *)&sarien_screen[x + y * GFX_WIDTH] = + q & 0x0f0f; + } + } else { + for (x *= 2; n--; p++, x += 2) { + register UINT16 q = ((UINT16)*p << 8) | *p; +#ifdef USE_CONSOLE + if (debug.priority) q >>= 4; +#endif + *(UINT16 *)&sarien_screen[x + y * GFX_WIDTH] = + q & 0x0f0f; + } + } +#endif +} + +#ifdef USE_HIRES + +void put_pixels_hires (int x, int y, int n, UINT8 *p) +{ + /* y += CHAR_LINES; */ + for (; n--; p++, x++) { + UINT8 q = *p; +#ifdef USE_CONSOLE + if (debug.priority) q >>= 4; +#endif + sarien_screen[x + y * GFX_WIDTH] = q & 0x0f; + } +} + +#endif + + +/** + * Schedule blocks for blitting on the output device. + * This function gets the coordinates of a block in the AGI screen and + * schedule it to be updated in the output device. + * @param x1 x coordinate of the upper left corner of the block (AGI coord.) + * @param y1 y coordinate of the upper left corner of the block (AGI coord.) + * @param x2 x coordinate of the lower right corner of the block (AGI coord.) + * @param y2 y coordinate of the lower right corner of the block (AGI coord.) + * + * @see do_update() + */ +void schedule_update (int x1, int y1, int x2, int y2) +{ + if (x1 < update.x1) update.x1 = x1; + if (y1 < update.y1) update.y1 = y1; + if (x2 > update.x2) update.x2 = x2; + if (y2 > update.y2) update.y2 = y2; +} + +/** + * Update scheduled blocks on the output device. + * This function exposes the blocks scheduled for updating to the output + * device. Blocks can be scheduled at any point of the AGI cycle. + * + * @see schedule_update() + */ +void do_update () +{ + if (update.x1 <= update.x2 && update.y1 <= update.y2) { + gfx->put_block (update.x1, update.y1, update.x2, update.y2); + } + + /* reset update block variables */ + update.x1 = MAX_INT; + update.y1 = MAX_INT; + update.x2 = 0; + update.y2 = 0; +} + + +/** + * Updates a block of the framebuffer with contents of the Sarien screen. + * This function updates a block in the output device with the contents of + * the Sarien screen, handling console transparency. + * @param x1 x coordinate of the upper left corner of the block + * @param y1 y coordinate of the upper left corner of the block + * @param x2 x coordinate of the lower right corner of the block + * @param y2 y coordinate of the lower right corner of the block + * + * @see flush_block_a() + */ +void flush_block (int x1, int y1, int x2, int y2) +{ + int y, w; + pixel_t *p0; + + schedule_update (x1, y1, x2, y2); + + p0 = &sarien_screen[x1 + y1 * GFX_WIDTH]; + w = x2 - x1 + 1; + + for (y = y1; y <= y2; y++) { + put_pixels (x1, y, w, p0); + p0 += GFX_WIDTH; + } +} + +/** + * Updates a block of the framebuffer receiving AGI picture coordinates. + * @param x1 x AGI picture coordinate of the upper left corner of the block + * @param y1 y AGI picture coordinate of the upper left corner of the block + * @param x2 x AGI picture coordinate of the lower right corner of the block + * @param y2 y AGI picture coordinate of the lower right corner of the block + * + * @see flush_block() + */ +void flush_block_a (int x1, int y1, int x2, int y2) +{ + /* y1 += 8; + y2 += 8; */ + flush_block (DEV_X0(x1), DEV_Y(y1), DEV_X1(x2), DEV_Y(y2)); +} + +/** + * Updates the framebuffer with contents of the Sarien screen (console-aware). + * This function updates the output device with the contents of the AGI + * screen, handling console transparency. + */ +void flush_screen () +{ + flush_block (0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); +} + +/** + * Clear the output device screen (console-aware). + * This function clears the output device screen and updates the + * output device. Contents of the AGI screen are left untouched. This + * function can be used to simulate a switch to a text mode screen in + * a graphic-only device. + * @param c color to clear the screen + */ +void clear_screen (int c) +{ + memset (sarien_screen, c, GFX_WIDTH * GFX_HEIGHT * sizeof(pixel_t)); + flush_screen (); +} + +#ifdef USE_CONSOLE +/** + * Clear the console screen. + * This function clears the top n lines of the console screen. + * @param n number of lines to clear (in pixels) + */ +void clear_console_screen (int n) +{ + memset (console_screen + n * GFX_WIDTH, 0, (GFX_HEIGHT - n) * GFX_WIDTH * sizeof(pixel_t)); +} +#endif + +/** + * Save a block of the Sarien screen + */ +void save_block (int x1, int y1, int x2, int y2, pixel_t *b) +{ + pixel_t *p0; + int w, h; + + p0 = &sarien_screen[x1 + GFX_WIDTH * y1]; + w = x2 - x1 + 1; + h = y2 - y1 + 1; + while (h--) { + memcpy (b, p0, w * sizeof(pixel_t)); + b += w; + p0 += GFX_WIDTH; + } +} + +/** + * Restore a block of the Sarien screen + */ +void restore_block (int x1, int y1, int x2, int y2, pixel_t *b) +{ + pixel_t *p0; + int w, h; + + p0 = &sarien_screen[x1 + GFX_WIDTH * y1]; + w = x2 - x1 + 1; + h = y2 - y1 + 1; + while (h--) { + memcpy (p0, b, w * sizeof(pixel_t)); + b += w; + p0 += GFX_WIDTH; + } + flush_block (x1, y1, x2, y2); +} + +/* end: graphics.c */ diff --git a/hirespic.c b/hirespic.c index 179f00e..cadfe23 100644 --- a/hirespic.c +++ b/hirespic.c @@ -1,240 +1,240 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: hirespic.c,v 1.27 2003/08/23 14:47:00 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifdef USE_HIRES - -static void fix_pixel_bothsides (int x, int y) -{ - UINT8 *p, *s; - - if (x >= (_WIDTH * 2) - 2) - return; - - /* Sometimes a solid color area in the lo-res pic is made - * with lines, and we want to keep this effect in the - * hi-res pic. - */ - p = &game.hires[y * (_WIDTH * 2) + x]; - if ((*(p - 2) & 0x0f) == scr_colour) - put_virt_pixel (x - 1, y, 2); - if ((*(p + 2) & 0x0f) == scr_colour) - put_virt_pixel (x + 1, y, 2); - - /* If two lines are contiguous in the lo-res pic, make them - * contiguous in the hi-res pic. This condition is needed - * in some scenes like in front of Lefty's in LSL1, to draw - * the pole. Note: it adds artifacts in some cases. - */ - s = &game.sbuf[y * _WIDTH + x / 2]; - if ((*(p - 1) & 0x0f) != (*(s - 1) & 0x0f)) - put_virt_pixel (x - 1, y, 2); -} - -/************************************************************************** -** okToFill -**************************************************************************/ -static INLINE int hires_fill_here (int x, int y) -{ - UINT8 *p, *s; - - if (x < 0 || x >= _WIDTH || y < 0 || y >= _HEIGHT) - return FALSE; - - if (!scr_on && !pri_on) - return FALSE; - - p = &game.hires[(SINT32)y * (_WIDTH * 2) + x * 2]; - s = &game.sbuf[y * _WIDTH + x]; - - if (scr_on) { - if (scr_colour == 0x0f) - return FALSE; - if ((*p & 0x0f) != 0x0f || (*(p + 1) & 0x0f) != 0x0f) - return FALSE; - if ((*s & 0x0f) != scr_colour) - return FALSE; - } - - if (pri_on) { - if (pri_colour == 0x04) - return FALSE; - if ((*p >> 4) != 0x04 || (*(p + 1) >> 4) != 0x04) - return FALSE; - if ((*s >> 4) != pri_colour) - return FALSE; - } - - return TRUE; -} - - -static void fix_pixel_left (int x, int y) -{ - UINT8 *p; - - if (!scr_on) - return; - - p = &game.hires[y * (_WIDTH * 2) + x * 2 + 1]; - if ((*p & 0x0f) == 0x0f) - put_virt_pixel (2 * x + 1, y, 2); - else if ((*p & 0x0f) == (*(p - 1) & 0x0f)) - put_virt_pixel (2 * x + 1, y, 2); -} - -static void fix_pixel_right (int x, int y) -{ - int idx = y * (_WIDTH * 2) + x * 2; - - if (idx >= 160 * 168) - return; - - if (scr_on && (game.hires[idx] & 0x0f) == 0x0f) - put_virt_pixel (2 * x, y, 2); -} - -static void fix_pixel_here (int x, int y) -{ - UINT8 p; - - p = game.hires[y * (_WIDTH * 2) + x * 2 + 1]; - if (scr_on && (p & 0x0f) == 0x0f) - put_virt_pixel (2 * x + 1, y, 2); -} - - -/************************************************************************** -** agiFill -**************************************************************************/ -static void hires_fill_scanline (int x, int y) -{ - unsigned int c; - int newspan_up, newspan_down; - - if (!hires_fill_here (x, y)) - return; - - /* Scan for left border */ - for (c = x - 1; c > 0 && hires_fill_here (c, y); c--); - fix_pixel_left (c, y); - - newspan_up = newspan_down = 1; - for (c++; hires_fill_here (c, y); c++) { - put_virt_pixel (c * 2, y, 2); - fix_pixel_here (c, y); - - if (hires_fill_here (c, y - 1)) { - if (newspan_up) { - _PUSH (c + 320 * (y - 1)); - newspan_up = 0; - } - } else { - newspan_up = 1; - } - - if (hires_fill_here (c, y + 1)) { - if (newspan_down) { - _PUSH (c + 320 * (y + 1)); - newspan_down = 0; - } - } else { - newspan_down = 1; - } - } - - fix_pixel_right (c, y); -} - -static void _hires_fill (unsigned int x, unsigned int y) -{ - _PUSH (x + 320 * y); - - while (42) { - UINT16 c = _POP(); - - /* Exit if stack is empty */ - if (c == 0xffff) - break; - - x = c % 320; - y = c / 320; - - hires_fill_scanline (x, y); - } - - stack_ptr = 0; -} - - -/************************************************************************** -** fill -** -** AGI flood fill. (drawing action 0xF8) -**************************************************************************/ -static void hires_fill () -{ - int x1, y1; - - while ((x1 = next_byte) < 0xf0 && (y1 = next_byte) < 0xf0) { - _hires_fill (x1, y1); - } - - foffs--; -} - - -/** - * Show AGI picture. - * This function copies a ``hidden'' AGI picture to the output device. - */ -void show_hires_pic () -{ - int y, offset; - SINT32 i; - - i = 0; - offset = game.line_min_print * CHAR_LINES; - for (y = 0; y < _HEIGHT; y++) { - put_pixels_hires (0, y + offset, _WIDTH * 2, - &game.hires[i]); - i += _WIDTH * 2; - } - - flush_screen (); -} - -void fix_hires_picture () -{ - UINT8 *p, *b; - int i; - - p = game.hires; - b = game.sbuf; - - for (i = 0; p < &game.hires[_WIDTH * _HEIGHT * 2] - 1; p++, i++) { - if ((*p & 0x0f) == 0x0f && (*b & 0x0f) != 0x0f) { - if ((*(p + 1) & 0x0f) != 0x0f) - *p = *(p + 1); - else - *p = *b; - } - if ((*p >> 4) == 4 && (*b >> 4) != 4 && - (*(b + 1) >> 4) != 4) - { - *p = (*p & 0x0f) | (*b & 0xf0); - } - b += (i & 1); - } -} - -#endif /* USE_HIRES */ - -/* end: hirespic.c */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: hirespic.c,v 1.27 2003/08/23 14:47:00 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifdef USE_HIRES + +static void fix_pixel_bothsides (int x, int y) +{ + UINT8 *p, *s; + + if (x >= (_WIDTH * 2) - 2) + return; + + /* Sometimes a solid color area in the lo-res pic is made + * with lines, and we want to keep this effect in the + * hi-res pic. + */ + p = &game.hires[y * (_WIDTH * 2) + x]; + if ((*(p - 2) & 0x0f) == scr_colour) + put_virt_pixel (x - 1, y, 2); + if ((*(p + 2) & 0x0f) == scr_colour) + put_virt_pixel (x + 1, y, 2); + + /* If two lines are contiguous in the lo-res pic, make them + * contiguous in the hi-res pic. This condition is needed + * in some scenes like in front of Lefty's in LSL1, to draw + * the pole. Note: it adds artifacts in some cases. + */ + s = &game.sbuf[y * _WIDTH + x / 2]; + if ((*(p - 1) & 0x0f) != (*(s - 1) & 0x0f)) + put_virt_pixel (x - 1, y, 2); +} + +/************************************************************************** +** okToFill +**************************************************************************/ +static INLINE int hires_fill_here (int x, int y) +{ + UINT8 *p, *s; + + if (x < 0 || x >= _WIDTH || y < 0 || y >= _HEIGHT) + return FALSE; + + if (!scr_on && !pri_on) + return FALSE; + + p = &game.hires[(SINT32)y * (_WIDTH * 2) + x * 2]; + s = &game.sbuf[y * _WIDTH + x]; + + if (scr_on) { + if (scr_colour == 0x0f) + return FALSE; + if ((*p & 0x0f) != 0x0f || (*(p + 1) & 0x0f) != 0x0f) + return FALSE; + if ((*s & 0x0f) != scr_colour) + return FALSE; + } + + if (pri_on) { + if (pri_colour == 0x04) + return FALSE; + if ((*p >> 4) != 0x04 || (*(p + 1) >> 4) != 0x04) + return FALSE; + if ((*s >> 4) != pri_colour) + return FALSE; + } + + return TRUE; +} + + +static void fix_pixel_left (int x, int y) +{ + UINT8 *p; + + if (!scr_on) + return; + + p = &game.hires[y * (_WIDTH * 2) + x * 2 + 1]; + if ((*p & 0x0f) == 0x0f) + put_virt_pixel (2 * x + 1, y, 2); + else if ((*p & 0x0f) == (*(p - 1) & 0x0f)) + put_virt_pixel (2 * x + 1, y, 2); +} + +static void fix_pixel_right (int x, int y) +{ + int idx = y * (_WIDTH * 2) + x * 2; + + if (idx >= 160 * 168) + return; + + if (scr_on && (game.hires[idx] & 0x0f) == 0x0f) + put_virt_pixel (2 * x, y, 2); +} + +static void fix_pixel_here (int x, int y) +{ + UINT8 p; + + p = game.hires[y * (_WIDTH * 2) + x * 2 + 1]; + if (scr_on && (p & 0x0f) == 0x0f) + put_virt_pixel (2 * x + 1, y, 2); +} + + +/************************************************************************** +** agiFill +**************************************************************************/ +static void hires_fill_scanline (int x, int y) +{ + unsigned int c; + int newspan_up, newspan_down; + + if (!hires_fill_here (x, y)) + return; + + /* Scan for left border */ + for (c = x - 1; c > 0 && hires_fill_here (c, y); c--); + fix_pixel_left (c, y); + + newspan_up = newspan_down = 1; + for (c++; hires_fill_here (c, y); c++) { + put_virt_pixel (c * 2, y, 2); + fix_pixel_here (c, y); + + if (hires_fill_here (c, y - 1)) { + if (newspan_up) { + _PUSH (c + 320 * (y - 1)); + newspan_up = 0; + } + } else { + newspan_up = 1; + } + + if (hires_fill_here (c, y + 1)) { + if (newspan_down) { + _PUSH (c + 320 * (y + 1)); + newspan_down = 0; + } + } else { + newspan_down = 1; + } + } + + fix_pixel_right (c, y); +} + +static void _hires_fill (unsigned int x, unsigned int y) +{ + _PUSH (x + 320 * y); + + while (42) { + UINT16 c = _POP(); + + /* Exit if stack is empty */ + if (c == 0xffff) + break; + + x = c % 320; + y = c / 320; + + hires_fill_scanline (x, y); + } + + stack_ptr = 0; +} + + +/************************************************************************** +** fill +** +** AGI flood fill. (drawing action 0xF8) +**************************************************************************/ +static void hires_fill () +{ + int x1, y1; + + while ((x1 = next_byte) < 0xf0 && (y1 = next_byte) < 0xf0) { + _hires_fill (x1, y1); + } + + foffs--; +} + + +/** + * Show AGI picture. + * This function copies a ``hidden'' AGI picture to the output device. + */ +void show_hires_pic () +{ + int y, offset; + SINT32 i; + + i = 0; + offset = game.line_min_print * CHAR_LINES; + for (y = 0; y < _HEIGHT; y++) { + put_pixels_hires (0, y + offset, _WIDTH * 2, + &game.hires[i]); + i += _WIDTH * 2; + } + + flush_screen (); +} + +void fix_hires_picture () +{ + UINT8 *p, *b; + int i; + + p = game.hires; + b = game.sbuf; + + for (i = 0; p < &game.hires[_WIDTH * _HEIGHT * 2] - 1; p++, i++) { + if ((*p & 0x0f) == 0x0f && (*b & 0x0f) != 0x0f) { + if ((*(p + 1) & 0x0f) != 0x0f) + *p = *(p + 1); + else + *p = *b; + } + if ((*p >> 4) == 4 && (*b >> 4) != 4 && + (*(b + 1) >> 4) != 4) + { + *p = (*p & 0x0f) | (*b & 0xf0); + } + b += (i & 1); + } +} + +#endif /* USE_HIRES */ + +/* end: hirespic.c */ + diff --git a/id.c b/id.c index 4ba479d..f4cc738 100644 --- a/id.c +++ b/id.c @@ -1,381 +1,381 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: id.c,v 1.48 2003/07/13 14:27:33 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef PALMOS - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "opcodes.h" - -/* - * Determine what AGI v2 system to emulate, these are the major version - * to emulate, thus 2.915 comes under 2.917, 2.4xxx is 2.440, etc. - * - * 0x2089 - * 0x2272 - * 0x2440 - * 0x2917 - * 0x2936 - */ - -int setup_v2_game(int ver, UINT32 crc); -int setup_v3_game(int ver, UINT32 crc); -int v4id_game (UINT32 crc); - -#ifdef USE_COMMAND_LINE - -void list_games () -{ - FILE *f; - char *c, *t, buf[256]; - UINT32 id, ver; - int min, maj, i = 0; - - if ((f = fopen (get_config_file(), "r")) == NULL) { - printf ("Configuration file not found.\n"); - return; - } - - printf ( -"Game# AGI ver. Title CRC\n" -"------ ---------- ---------------------------------------- -------\n" - ); - - while (!feof (f)) { - fgets (buf, 256, f); - c = strchr (buf, '#'); - if (c) *c = 0; - - /* Remove spaces at end of line */ - if (strlen (buf)) { - for (c = buf + strlen (buf) - 1; - *c == ' ' || *c == '\t'; *c-- = 0) {} - } - - - t = strtok (buf, " \t\r\n"); - if (t == NULL) - continue; - id = strtoul (t, NULL, 0); - - t = strtok (NULL, " \t\r\n"); - if (t == NULL) - continue; - ver = strtoul (t, NULL, 0); - maj = (ver >> 12) & 0xf; - min = ver & 0xfff; - - t = strtok (NULL, "\n\r"); - - if (maj == 2) { - printf ("[%3d] %x.%03x %-40.40s 0x%05x\n", - ++i, maj, min, t, id); - } else { - printf ("[%3d] %x.002.%03x %-40.40s 0x%05x\n", - ++i, maj, min, t, id); - } - } - - fclose (f); -} - -#endif - -UINT32 match_crc (UINT32 crc, char *path, char *name, int len) -{ - FILE *f; - char *c, *t, buf[256]; - UINT32 id, ver; - - if ((f = fopen (path, "r")) == NULL) - return 0; - - while (!feof (f)) { - if ( !fgets (buf, 256, f) ) - return 0; - - if (strstr(buf, "# End of sarien.conf") != NULL) - break; - c = strchr (buf, '#'); - if (c) *c = 0; - - /* Remove spaces at end of line */ - if (strlen (buf)) { - for (c = buf + strlen (buf) - 1; - *c == ' ' || *c == '\t'; *c-- = 0) {} - } - - t = strtok (buf, " \t\r\n"); - if (t == NULL) - continue; - id = strtoul (t, NULL, 0); - - t = strtok (NULL, " \t\r\n"); - if (t == NULL) - continue; - ver = strtoul (t, NULL, 0); - - t = strtok (NULL, "\n\r"); - for (; *t == ' ' || *t == '\t'; t++); - - if (id == crc) { - /* Now we must check options enclosed in brackets - * like [A] for Amiga - */ - - if (*t == '[') { - while (*t != ']') { - switch (*t++) { - case 'A': - opt.amiga = TRUE; - break; - case 'a': - opt.agds = TRUE; - break; -#ifdef USE_MOUSE - case 'm': - opt.agimouse = TRUE; - break; -#endif - } - } - t++; - - for (; *t == ' ' || *t == '\t'; t++) {} - } - - strncpy (name, t, len); - fclose (f); -#ifdef DREAMCAST - strcpy(g_gamename, t); -#endif - return ver; - } - } - - fclose (f); - - return 0; -} - - -static UINT32 match_version (UINT32 crc) -{ - int ver; - char name[80]; - - if ((ver = match_crc(crc, get_config_file(), name, 80)) > 0) - report ("AGI game detected: %s\n\n", name); - - return ver; -} - - -int v2id_game () -{ -#ifdef __MPW__ - return err_OK; /* FIXME! */ -#else - int y, ver; - UINT32 len, c, crc; - UINT8 *buff; - FILE *fp; - char *fn[] = { "viewdir", "logdir", "picdir", "snddir", - "words.tok", "object", "" }; - - buff = malloc (8192); - - for (crc = y = 0; fn[y][0]; y++) { - char *path = fixpath (NO_GAMEDIR, fn[y]); - if ((fp = fopen (path, "rb")) != NULL) { - for (len = 1; len > 0; ) { - memset (buff, 0, 8192); - len = fread (buff, 1, 8000, fp); - for (c = 0; c < len; c++) - crc += *(buff + c); - } - fclose (fp); - } - } - free (buff); - - report ("Computed CRC: 0x%05x\n", crc); - ver = match_version (crc); - game.crc = crc; - game.ver = ver; - _D (_D_WARN "game.ver = 0x%x", game.ver); - agi_set_release (ver); - return setup_v2_game(ver, crc); -#endif -} - -/* - * Currently, there is no known difference between v3.002.098 -> v3.002.149 - * So version emulated; - * - * 0x0086, - * 0x0149 - */ - -int v3id_game () -{ - int ec = err_OK, y, ver; - UINT32 len, c, crc; - UINT8 *buff; - FILE *fp; - char *path, *fn[] = { "words.tok", "object", "" }; - - buff = malloc (8192); - - for (crc = 0, y = 0; fn[y][0] != 0x0; y++) { - path = fixpath (NO_GAMEDIR, fn[y]); - if ((fp = fopen (path, "rb")) != NULL) { - len = 1; - while (len > 0) { - memset (buff, 0, 8192); - len = fread (buff, 1, 8000, fp); - for (c = 0; c < len; c++) - crc += *(buff + c); - } - fclose(fp); - } - } - - /* now do the directory file */ - - path = fixpath (GAMEDIR, DIR_); - - if ((fp = fopen(path, "rb")) != NULL) { - for (len = 1; len > 0; ) { - memset (buff, 0, 8192); - len = fread (buff, 1, 8000, fp); - for (c = 0; c < len; c++) - crc += *(buff + c); - } - fclose (fp); - } - - free (buff); - - report ("Computed CRC: 0x%05x\n", crc); - ver = match_version (crc); - game.crc = crc; - game.ver = ver; - agi_set_release (ver); - - ec = setup_v3_game(ver, crc); - - return ec; -} - - -#ifdef PALMOS - -int v4id_game (UINT32 ver) -{ - int ec = err_OK; - - game.crc = 0; - game.ver = ver; - agi_set_release (ver); - - switch ((ver>>12)&0xFF) { - case 2: - ec = setup_v2_game (ver, 0); - break; - case 3: - ec = setup_v3_game (ver, 0); - break; - } - - return ec; -} - -#endif - -/** - * - */ -int setup_v2_game (int ver, UINT32 crc) -{ - int ec=err_OK; - - if (ver == 0) { - report ("Unknown v2 Sierra game: %08x\n\n", crc); - agi_set_release (0x2917); - } - - /* setup the differences in the opcodes and other bits in the - * AGI v2 specs - */ - if (opt.emuversion) - agi_set_release (opt.emuversion); - - if (opt.agds) - agi_set_release (0x2440);/* ALL AGDS games built for 2.440 */ - - switch(agi_get_release ()) { - case 0x2089: - logic_names_cmd[0x86].num_args = 0; /* quit: 0 args */ - logic_names_cmd[0x97].num_args = 3; /* print.at: 3 args */ - logic_names_cmd[0x98].num_args = 3; /* print.at.v: 3 args*/ - break; - case 0x2272: - /* KQ3 0x88673 (2.272) requires print.at with 4 arguments */ - break; - case 0x2440: - break; - case 0x2917: - break; - case 0x2936: - break; - default: - report ("** Cannot setup for unknown version\n"); - ec = err_UnknownAGIVersion; - break; - } - - return ec; -} - -/** - * - */ -int setup_v3_game (int ver, UINT32 crc) -{ - int ec = err_OK; - - if (ver == 0) { - report ("Unknown v3 Sierra game: %08x\n\n", crc); - agi_set_release (ver = 0x3149); - } - - if (opt.emuversion) - agi_set_release (ver = opt.emuversion); - - switch(ver) { - case 0x3086: - logic_names_cmd[0xad].num_args = 1; /* 173 : 1 args */ - break; - case 0x3149: - logic_names_cmd[0xad].num_args = 0; /* 173 : 0 args */ - break; - default: - report ("Error: cannot setup for unknown version\n"); - ec = err_UnknownAGIVersion; - break; - } - - return ec; -} - -#endif +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: id.c,v 1.48 2003/07/13 14:27:33 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef PALMOS + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "opcodes.h" + +/* + * Determine what AGI v2 system to emulate, these are the major version + * to emulate, thus 2.915 comes under 2.917, 2.4xxx is 2.440, etc. + * + * 0x2089 + * 0x2272 + * 0x2440 + * 0x2917 + * 0x2936 + */ + +int setup_v2_game(int ver, UINT32 crc); +int setup_v3_game(int ver, UINT32 crc); +int v4id_game (UINT32 crc); + +#ifdef USE_COMMAND_LINE + +void list_games () +{ + FILE *f; + char *c, *t, buf[256]; + UINT32 id, ver; + int min, maj, i = 0; + + if ((f = fopen (get_config_file(), "r")) == NULL) { + printf ("Configuration file not found.\n"); + return; + } + + printf ( +"Game# AGI ver. Title CRC\n" +"------ ---------- ---------------------------------------- -------\n" + ); + + while (!feof (f)) { + fgets (buf, 256, f); + c = strchr (buf, '#'); + if (c) *c = 0; + + /* Remove spaces at end of line */ + if (strlen (buf)) { + for (c = buf + strlen (buf) - 1; + *c == ' ' || *c == '\t'; *c-- = 0) {} + } + + + t = strtok (buf, " \t\r\n"); + if (t == NULL) + continue; + id = strtoul (t, NULL, 0); + + t = strtok (NULL, " \t\r\n"); + if (t == NULL) + continue; + ver = strtoul (t, NULL, 0); + maj = (ver >> 12) & 0xf; + min = ver & 0xfff; + + t = strtok (NULL, "\n\r"); + + if (maj == 2) { + printf ("[%3d] %x.%03x %-40.40s 0x%05x\n", + ++i, maj, min, t, id); + } else { + printf ("[%3d] %x.002.%03x %-40.40s 0x%05x\n", + ++i, maj, min, t, id); + } + } + + fclose (f); +} + +#endif + +UINT32 match_crc (UINT32 crc, char *path, char *name, int len) +{ + FILE *f; + char *c, *t, buf[256]; + UINT32 id, ver; + + if ((f = fopen (path, "r")) == NULL) + return 0; + + while (!feof (f)) { + if ( !fgets (buf, 256, f) ) + return 0; + + if (strstr(buf, "# End of sarien.conf") != NULL) + break; + c = strchr (buf, '#'); + if (c) *c = 0; + + /* Remove spaces at end of line */ + if (strlen (buf)) { + for (c = buf + strlen (buf) - 1; + *c == ' ' || *c == '\t'; *c-- = 0) {} + } + + t = strtok (buf, " \t\r\n"); + if (t == NULL) + continue; + id = strtoul (t, NULL, 0); + + t = strtok (NULL, " \t\r\n"); + if (t == NULL) + continue; + ver = strtoul (t, NULL, 0); + + t = strtok (NULL, "\n\r"); + for (; *t == ' ' || *t == '\t'; t++); + + if (id == crc) { + /* Now we must check options enclosed in brackets + * like [A] for Amiga + */ + + if (*t == '[') { + while (*t != ']') { + switch (*t++) { + case 'A': + opt.amiga = TRUE; + break; + case 'a': + opt.agds = TRUE; + break; +#ifdef USE_MOUSE + case 'm': + opt.agimouse = TRUE; + break; +#endif + } + } + t++; + + for (; *t == ' ' || *t == '\t'; t++) {} + } + + strncpy (name, t, len); + fclose (f); +#ifdef DREAMCAST + strcpy(g_gamename, t); +#endif + return ver; + } + } + + fclose (f); + + return 0; +} + + +static UINT32 match_version (UINT32 crc) +{ + int ver; + char name[80]; + + if ((ver = match_crc(crc, get_config_file(), name, 80)) > 0) + report ("AGI game detected: %s\n\n", name); + + return ver; +} + + +int v2id_game () +{ +#ifdef __MPW__ + return err_OK; /* FIXME! */ +#else + int y, ver; + UINT32 len, c, crc; + UINT8 *buff; + FILE *fp; + char *fn[] = { "viewdir", "logdir", "picdir", "snddir", + "words.tok", "object", "" }; + + buff = malloc (8192); + + for (crc = y = 0; fn[y][0]; y++) { + char *path = fixpath (NO_GAMEDIR, fn[y]); + if ((fp = fopen (path, "rb")) != NULL) { + for (len = 1; len > 0; ) { + memset (buff, 0, 8192); + len = fread (buff, 1, 8000, fp); + for (c = 0; c < len; c++) + crc += *(buff + c); + } + fclose (fp); + } + } + free (buff); + + report ("Computed CRC: 0x%05x\n", crc); + ver = match_version (crc); + game.crc = crc; + game.ver = ver; + _D (_D_WARN "game.ver = 0x%x", game.ver); + agi_set_release (ver); + return setup_v2_game(ver, crc); +#endif +} + +/* + * Currently, there is no known difference between v3.002.098 -> v3.002.149 + * So version emulated; + * + * 0x0086, + * 0x0149 + */ + +int v3id_game () +{ + int ec = err_OK, y, ver; + UINT32 len, c, crc; + UINT8 *buff; + FILE *fp; + char *path, *fn[] = { "words.tok", "object", "" }; + + buff = malloc (8192); + + for (crc = 0, y = 0; fn[y][0] != 0x0; y++) { + path = fixpath (NO_GAMEDIR, fn[y]); + if ((fp = fopen (path, "rb")) != NULL) { + len = 1; + while (len > 0) { + memset (buff, 0, 8192); + len = fread (buff, 1, 8000, fp); + for (c = 0; c < len; c++) + crc += *(buff + c); + } + fclose(fp); + } + } + + /* now do the directory file */ + + path = fixpath (GAMEDIR, DIR_); + + if ((fp = fopen(path, "rb")) != NULL) { + for (len = 1; len > 0; ) { + memset (buff, 0, 8192); + len = fread (buff, 1, 8000, fp); + for (c = 0; c < len; c++) + crc += *(buff + c); + } + fclose (fp); + } + + free (buff); + + report ("Computed CRC: 0x%05x\n", crc); + ver = match_version (crc); + game.crc = crc; + game.ver = ver; + agi_set_release (ver); + + ec = setup_v3_game(ver, crc); + + return ec; +} + + +#ifdef PALMOS + +int v4id_game (UINT32 ver) +{ + int ec = err_OK; + + game.crc = 0; + game.ver = ver; + agi_set_release (ver); + + switch ((ver>>12)&0xFF) { + case 2: + ec = setup_v2_game (ver, 0); + break; + case 3: + ec = setup_v3_game (ver, 0); + break; + } + + return ec; +} + +#endif + +/** + * + */ +int setup_v2_game (int ver, UINT32 crc) +{ + int ec=err_OK; + + if (ver == 0) { + report ("Unknown v2 Sierra game: %08x\n\n", crc); + agi_set_release (0x2917); + } + + /* setup the differences in the opcodes and other bits in the + * AGI v2 specs + */ + if (opt.emuversion) + agi_set_release (opt.emuversion); + + if (opt.agds) + agi_set_release (0x2440);/* ALL AGDS games built for 2.440 */ + + switch(agi_get_release ()) { + case 0x2089: + logic_names_cmd[0x86].num_args = 0; /* quit: 0 args */ + logic_names_cmd[0x97].num_args = 3; /* print.at: 3 args */ + logic_names_cmd[0x98].num_args = 3; /* print.at.v: 3 args*/ + break; + case 0x2272: + /* KQ3 0x88673 (2.272) requires print.at with 4 arguments */ + break; + case 0x2440: + break; + case 0x2917: + break; + case 0x2936: + break; + default: + report ("** Cannot setup for unknown version\n"); + ec = err_UnknownAGIVersion; + break; + } + + return ec; +} + +/** + * + */ +int setup_v3_game (int ver, UINT32 crc) +{ + int ec = err_OK; + + if (ver == 0) { + report ("Unknown v3 Sierra game: %08x\n\n", crc); + agi_set_release (ver = 0x3149); + } + + if (opt.emuversion) + agi_set_release (ver = opt.emuversion); + + switch(ver) { + case 0x3086: + logic_names_cmd[0xad].num_args = 1; /* 173 : 1 args */ + break; + case 0x3149: + logic_names_cmd[0xad].num_args = 0; /* 173 : 0 args */ + break; + default: + report ("Error: cannot setup for unknown version\n"); + ec = err_UnknownAGIVersion; + break; + } + + return ec; +} + +#endif diff --git a/include/agi.h b/include/agi.h index ac387b8..e31d5d4 100644 --- a/include/agi.h +++ b/include/agi.h @@ -1,275 +1,275 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: agi.h,v 1.62 2003/07/29 19:20:37 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_H -#define __AGI_H - -#ifdef __cplusplus -extern "C"{ -#endif - -/* AGI resources */ -#include "view.h" -#include "picture.h" -#include "logic.h" -#include "sound.h" - -#define WIN_TO_PIC_X(x) ((x) / 2) -#define WIN_TO_PIC_Y(y) ((y) < 8 ? 999 : (y) >= (8 + _HEIGHT) ? 999 : (y) - 8) - -/** - * AGI variables. - */ -enum { - V_cur_room = 0, /* 0 */ - V_prev_room, - V_border_touch_ego, - V_score, - V_border_code, - V_border_touch_obj, /* 5 */ - V_ego_dir, - V_max_score, - V_free_pages, - V_word_not_found, - V_time_delay, /* 10 */ - V_seconds, - V_minutes, - V_hours, - V_days, - V_joystick_sensitivity, /* 15 */ - V_ego_view_resource, - V_agi_err_code, - V_agi_err_code_info, - V_key, - V_computer, /* 20 */ - V_window_reset, - V_soundgen, - V_volume, - V_max_input_chars, - V_sel_item, /* 25 */ - V_monitor -}; - -/** - * AGI flags - */ -enum { - F_ego_water = 0, /* 0 */ - F_ego_invisible, - F_entered_cli, - F_ego_touched_p2, - F_said_accepted_input, - F_new_room_exec, /* 5 */ - F_restart_game, - F_script_blocked, - F_joy_sensitivity, - F_sound_on, - F_debugger_on, /* 10 */ - F_logic_zero_firsttime, - F_restore_just_ran, - F_status_selects_items, - F_menus_work, - F_output_mode, /* 15 */ - F_auto_restart -}; - -struct agi_event { - UINT16 data; - UINT8 occured; -}; - -struct agi_object { - int location; - char *name; -}; - -struct agi_word { - int id; - char *word; -}; - - -struct agi_dir { - UINT8 volume; - UINT32 offset; - UINT32 len; - UINT32 clen; - UINT8 flags; - /* 0 = not in mem, can be freed - * 1 = in mem, can be released - * 2 = not in mem, cant be released - * 3 = in mem, cant be released - * 0x40 = was compressed - */ -}; - -struct agi_block { - int active; - int x1, y1; - int x2, y2; - UINT8 *buffer; /* used for window background */ -}; - -#define EGO_VIEW_TABLE 0 -#define HORIZON 36 -#define _WIDTH 160 -#define _HEIGHT 168 - -/** - * AGI game structure. - * This structure contains all global data of an AGI game executed - * by the interpreter. - */ -struct agi_game { -#define STATE_INIT 0x00 -#define STATE_LOADED 0x01 -#define STATE_RUNNING 0x02 - int state; /**< state of the interpreter */ - - char name[8]; /**< lead in id (e.g. `GR' for goldrush) */ - char id[8]; /**< game id */ - char dir[MAX_PATH]; /**< game dir */ - UINT32 crc; /**< game CRC */ - - /* game flags and variables */ - UINT8 flags[MAX_FLAGS]; /**< 256 1-bit flags */ - UINT8 vars[MAX_VARS]; /**< 256 variables */ - - /* internal variables */ - int horizon; /**< horizon y coordinate */ - int line_status; /**< line number to put status on */ - int line_user_input; /**< line to put user input on */ - int line_min_print; /**< num lines to print on */ - int cursor_pos; /**< column where the input cursor is */ - UINT8 input_buffer[40]; /**< buffer for user input */ - UINT8 echo_buffer[40]; /**< buffer for echo.line */ - int keypress; -#define INPUT_NORMAL 0x01 -#define INPUT_GETSTRING 0x02 -#define INPUT_MENU 0x03 -#define INPUT_NONE 0x04 - int input_mode; /**< keyboard input mode */ - int input_enabled; /**< keyboard input enabled */ - int lognum; /**< current logic number */ - - /* internal flags */ - int player_control; /**< player is in control */ - int quit_prog_now; /**< quit now */ - int status_line; /**< status line on/off */ - int clock_enabled; /**< clock is on/off */ - int exit_all_logics; /**< break cycle after new.room */ - int picture_shown; /**< show.pic has been issued */ - int has_prompt; /**< input prompt has been printed */ -#define ID_AGDS 0x00000001 -#define ID_AMIGA 0x00000002 - int game_flags; /**< Sarien options flags */ - - UINT8 pri_table[_HEIGHT]; /**< priority table */ - - /* windows */ - UINT32 msg_box_ticks; /**< timed message box tick counter */ - struct agi_block block; - struct agi_block window; - int has_window; - - /* graphics & text*/ - int gfx_mode; - char cursor_char; - unsigned int color_fg; - unsigned int color_bg; - UINT8 *sbuf; /**< 160x168 AGI screen buffer */ -#ifdef USE_HIRES - UINT8 *hires; /**< 320x168 hi-res buffer */ -#endif - - /* player command line */ - struct agi_word ego_words[MAX_WORDS]; - int num_ego_words; - - unsigned int num_objects; - - struct agi_event ev_keyp[MAX_DIRS]; /**< keyboard keypress events */ - char strings[MAX_STRINGS + 1][MAX_STRINGLEN]; /**< strings */ - - /* directory entries for resources */ - struct agi_dir dir_logic[MAX_DIRS]; - struct agi_dir dir_pic[MAX_DIRS]; - struct agi_dir dir_view[MAX_DIRS]; - struct agi_dir dir_sound[MAX_DIRS]; - - /* resources */ - struct agi_picture pictures[MAX_DIRS]; /**< AGI picture resources */ - struct agi_logic logics[MAX_DIRS]; /**< AGI logic resources */ - struct agi_view views[MAX_DIRS]; /**< AGI view resources */ - struct agi_sound sounds[MAX_DIRS]; /**< AGI sound resources */ - - /* view table */ - struct vt_entry view_table[MAX_VIEWTABLE]; - - SINT32 ver; /**< detected game version */ - - int simple_save; /**< select simple savegames */ -}; - -/** - * - */ -struct agi_loader { - int version; - int int_version; - int (*init)(void); - int (*deinit)(void); - int (*detect_game)(char *); - int (*load_resource)(int, int); - int (*unload_resource)(int, int); - int (*load_objects)(char *); - int (*load_words)(char *); -}; - - -extern struct agi_game game; - -int agi_init (void); -int agi_deinit (void); -int agi_version (void); -int agi_get_release (void); -void agi_set_release (int); -int agi_detect_game (char *); -int agi_load_resource (int, int); -int agi_unload_resource (int, int); -void agi_unload_resources (void); - -/* words */ -int show_words (void); -int load_words (char *); -void unload_words (void); -int find_word (char *word, int *flen); -void dictionary_words(char *); - -/* objects */ -int show_objects (void); -int load_objects (char *fname); -int alloc_objects (int); -void unload_objects (void); -char* object_name (unsigned int); -int object_get_location (unsigned int); -void object_set_location (unsigned int, int); - -void new_input_mode (int); -void old_input_mode (void); - -int run_logic (int); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_H */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: agi.h,v 1.62 2003/07/29 19:20:37 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_H +#define __AGI_H + +#ifdef __cplusplus +extern "C"{ +#endif + +/* AGI resources */ +#include "view.h" +#include "picture.h" +#include "logic.h" +#include "sound.h" + +#define WIN_TO_PIC_X(x) ((x) / 2) +#define WIN_TO_PIC_Y(y) ((y) < 8 ? 999 : (y) >= (8 + _HEIGHT) ? 999 : (y) - 8) + +/** + * AGI variables. + */ +enum { + V_cur_room = 0, /* 0 */ + V_prev_room, + V_border_touch_ego, + V_score, + V_border_code, + V_border_touch_obj, /* 5 */ + V_ego_dir, + V_max_score, + V_free_pages, + V_word_not_found, + V_time_delay, /* 10 */ + V_seconds, + V_minutes, + V_hours, + V_days, + V_joystick_sensitivity, /* 15 */ + V_ego_view_resource, + V_agi_err_code, + V_agi_err_code_info, + V_key, + V_computer, /* 20 */ + V_window_reset, + V_soundgen, + V_volume, + V_max_input_chars, + V_sel_item, /* 25 */ + V_monitor +}; + +/** + * AGI flags + */ +enum { + F_ego_water = 0, /* 0 */ + F_ego_invisible, + F_entered_cli, + F_ego_touched_p2, + F_said_accepted_input, + F_new_room_exec, /* 5 */ + F_restart_game, + F_script_blocked, + F_joy_sensitivity, + F_sound_on, + F_debugger_on, /* 10 */ + F_logic_zero_firsttime, + F_restore_just_ran, + F_status_selects_items, + F_menus_work, + F_output_mode, /* 15 */ + F_auto_restart +}; + +struct agi_event { + UINT16 data; + UINT8 occured; +}; + +struct agi_object { + int location; + char *name; +}; + +struct agi_word { + int id; + char *word; +}; + + +struct agi_dir { + UINT8 volume; + UINT32 offset; + UINT32 len; + UINT32 clen; + UINT8 flags; + /* 0 = not in mem, can be freed + * 1 = in mem, can be released + * 2 = not in mem, cant be released + * 3 = in mem, cant be released + * 0x40 = was compressed + */ +}; + +struct agi_block { + int active; + int x1, y1; + int x2, y2; + UINT8 *buffer; /* used for window background */ +}; + +#define EGO_VIEW_TABLE 0 +#define HORIZON 36 +#define _WIDTH 160 +#define _HEIGHT 168 + +/** + * AGI game structure. + * This structure contains all global data of an AGI game executed + * by the interpreter. + */ +struct agi_game { +#define STATE_INIT 0x00 +#define STATE_LOADED 0x01 +#define STATE_RUNNING 0x02 + int state; /**< state of the interpreter */ + + char name[8]; /**< lead in id (e.g. `GR' for goldrush) */ + char id[8]; /**< game id */ + char dir[MAX_PATH]; /**< game dir */ + UINT32 crc; /**< game CRC */ + + /* game flags and variables */ + UINT8 flags[MAX_FLAGS]; /**< 256 1-bit flags */ + UINT8 vars[MAX_VARS]; /**< 256 variables */ + + /* internal variables */ + int horizon; /**< horizon y coordinate */ + int line_status; /**< line number to put status on */ + int line_user_input; /**< line to put user input on */ + int line_min_print; /**< num lines to print on */ + int cursor_pos; /**< column where the input cursor is */ + UINT8 input_buffer[40]; /**< buffer for user input */ + UINT8 echo_buffer[40]; /**< buffer for echo.line */ + int keypress; +#define INPUT_NORMAL 0x01 +#define INPUT_GETSTRING 0x02 +#define INPUT_MENU 0x03 +#define INPUT_NONE 0x04 + int input_mode; /**< keyboard input mode */ + int input_enabled; /**< keyboard input enabled */ + int lognum; /**< current logic number */ + + /* internal flags */ + int player_control; /**< player is in control */ + int quit_prog_now; /**< quit now */ + int status_line; /**< status line on/off */ + int clock_enabled; /**< clock is on/off */ + int exit_all_logics; /**< break cycle after new.room */ + int picture_shown; /**< show.pic has been issued */ + int has_prompt; /**< input prompt has been printed */ +#define ID_AGDS 0x00000001 +#define ID_AMIGA 0x00000002 + int game_flags; /**< Sarien options flags */ + + UINT8 pri_table[_HEIGHT]; /**< priority table */ + + /* windows */ + UINT32 msg_box_ticks; /**< timed message box tick counter */ + struct agi_block block; + struct agi_block window; + int has_window; + + /* graphics & text*/ + int gfx_mode; + char cursor_char; + unsigned int color_fg; + unsigned int color_bg; + UINT8 *sbuf; /**< 160x168 AGI screen buffer */ +#ifdef USE_HIRES + UINT8 *hires; /**< 320x168 hi-res buffer */ +#endif + + /* player command line */ + struct agi_word ego_words[MAX_WORDS]; + int num_ego_words; + + unsigned int num_objects; + + struct agi_event ev_keyp[MAX_DIRS]; /**< keyboard keypress events */ + char strings[MAX_STRINGS + 1][MAX_STRINGLEN]; /**< strings */ + + /* directory entries for resources */ + struct agi_dir dir_logic[MAX_DIRS]; + struct agi_dir dir_pic[MAX_DIRS]; + struct agi_dir dir_view[MAX_DIRS]; + struct agi_dir dir_sound[MAX_DIRS]; + + /* resources */ + struct agi_picture pictures[MAX_DIRS]; /**< AGI picture resources */ + struct agi_logic logics[MAX_DIRS]; /**< AGI logic resources */ + struct agi_view views[MAX_DIRS]; /**< AGI view resources */ + struct agi_sound sounds[MAX_DIRS]; /**< AGI sound resources */ + + /* view table */ + struct vt_entry view_table[MAX_VIEWTABLE]; + + SINT32 ver; /**< detected game version */ + + int simple_save; /**< select simple savegames */ +}; + +/** + * + */ +struct agi_loader { + int version; + int int_version; + int (*init)(void); + int (*deinit)(void); + int (*detect_game)(char *); + int (*load_resource)(int, int); + int (*unload_resource)(int, int); + int (*load_objects)(char *); + int (*load_words)(char *); +}; + + +extern struct agi_game game; + +int agi_init (void); +int agi_deinit (void); +int agi_version (void); +int agi_get_release (void); +void agi_set_release (int); +int agi_detect_game (char *); +int agi_load_resource (int, int); +int agi_unload_resource (int, int); +void agi_unload_resources (void); + +/* words */ +int show_words (void); +int load_words (char *); +void unload_words (void); +int find_word (char *word, int *flen); +void dictionary_words(char *); + +/* objects */ +int show_objects (void); +int load_objects (char *fname); +int alloc_objects (int); +void unload_objects (void); +char* object_name (unsigned int); +int object_get_location (unsigned int); +void object_set_location (unsigned int, int); + +void new_input_mode (int); +void old_input_mode (void); + +int run_logic (int); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_H */ + diff --git a/include/console.h b/include/console.h index aca60fe..9af5b31 100644 --- a/include/console.h +++ b/include/console.h @@ -1,61 +1,61 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: console.h,v 1.13 2002/11/09 17:05:21 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_CONSOLE_H -#define __AGI_CONSOLE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef USE_CONSOLE - -#define CONSOLE_LINES_BUFFER 80 -#define CONSOLE_LINE_SIZE (GFX_WIDTH / 8) -#define CONSOLE_ACTIVATE_KEY '`' -#define CONSOLE_SWITCH_KEY '~' - -struct sarien_console { - int active; - int input_active; - int index; - int y; - int max_y; - int first_line; - int count; - char *line[CONSOLE_LINES_BUFFER]; -}; - -struct sarien_debug { - int enabled; - int opcodes; - int logic0; - int steps; - int priority; - int statusline; - int ignoretriggers; -}; - -extern struct sarien_console console; - -#endif /* USE_CONSOLE */ - -int console_keyhandler (int); -int console_init (void); -void console_cycle (void); -void console_lock (void); -void console_prompt (void); -void report (char *, ...); - -#ifdef __cplusplus -} -#endif - -#endif /* __AGI_CONSOLE_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: console.h,v 1.13 2002/11/09 17:05:21 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_CONSOLE_H +#define __AGI_CONSOLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef USE_CONSOLE + +#define CONSOLE_LINES_BUFFER 80 +#define CONSOLE_LINE_SIZE (GFX_WIDTH / 8) +#define CONSOLE_ACTIVATE_KEY '`' +#define CONSOLE_SWITCH_KEY '~' + +struct sarien_console { + int active; + int input_active; + int index; + int y; + int max_y; + int first_line; + int count; + char *line[CONSOLE_LINES_BUFFER]; +}; + +struct sarien_debug { + int enabled; + int opcodes; + int logic0; + int steps; + int priority; + int statusline; + int ignoretriggers; +}; + +extern struct sarien_console console; + +#endif /* USE_CONSOLE */ + +int console_keyhandler (int); +int console_init (void); +void console_cycle (void); +void console_lock (void); +void console_prompt (void); +void report (char *, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* __AGI_CONSOLE_H */ diff --git a/include/getopt.h b/include/getopt.h index 7dad11b..0329d77 100644 --- a/include/getopt.h +++ b/include/getopt.h @@ -1,133 +1,133 @@ -/* Declarations for getopt. - Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. - - This file is part of the GNU C Library. Its master source is NOT part of - the C library, however. The master source lives in /gd/gnu/lib. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -#if defined (__STDC__) && __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if defined (__STDC__) && __STDC__ -#ifdef __GNU_LIBRARY__ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* __GNU_LIBRARY__ */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -#endif /* __STDC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _GETOPT_H */ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/include/graphics.h b/include/graphics.h index 3e379c2..619feeb 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -1,95 +1,95 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999,2001 Stuart George and Claudio Matsuoka - * - * $Id: graphics.h,v 1.16 2002/09/07 18:32:37 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_GRAPHICS_H -#define __AGI_GRAPHICS_H - -#ifdef __cplusplus -extern "C"{ -#endif - -#if defined PALMOS || defined FAKE_PALMOS - -#define GFX_WIDTH 160 -#define GFX_HEIGHT 160 -#define CHAR_COLS 4 -#define CHAR_LINES 6 -#define PIC_HEIGHT (22 * CHAR_LINES) - -#else - -#define GFX_WIDTH 320 -#define GFX_HEIGHT 200 -#define CHAR_COLS 8 -#define CHAR_LINES 8 - -#endif - -struct gfx_driver { - int (*init_video_mode)(void); - int (*deinit_video_mode)(void); - void (*put_block)(int x1, int y1, int x2, int y2); - void (*put_pixels)(int x, int y, int w, pixel_t *p); - void (*poll_timer)(void); - int (*keypress)(void); - int (*get_key)(void); -}; - -extern UINT8 palette[]; - - -/* Transparent layer */ -extern UINT8 layer1_data[]; -extern UINT8 layer2_data[]; - - -void put_text_character(int, int, int, unsigned int, int, int); -void shake_screen (int); -void shake_start (void); -void shake_end (void); -void save_screen (void); -void restore_screen (void); - -int init_video (void); -int deinit_video (void); -void schedule_update (int, int, int, int); -void do_update (void); -void put_screen (void); -void flush_block (int, int, int, int); -void flush_block_a (int, int, int, int); -void put_pixels_a (int, int, int, pixel_t *); -void flush_screen (void); -void clear_screen (int); -void clear_console_screen (int); -void draw_box (int, int, int, int, int, int, int); -void draw_button (int, int, char *, int, int); -int test_button (int, int, char *); -void draw_rectangle (int, int, int, int, int); -void save_block (int, int, int, int, pixel_t *); -void restore_block (int, int, int, int, pixel_t *); -void init_palette (UINT8 *); - -void put_pixel (int, int, int); - - -#ifdef USE_HIRES -void put_pixels_hires (int x, int y, int n, UINT8 *p); -#endif -int keypress (void); -int get_key (void); -void print_character (int, int, char, int, int); -void poll_timer (void); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_GRAPHICS_H */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999,2001 Stuart George and Claudio Matsuoka + * + * $Id: graphics.h,v 1.16 2002/09/07 18:32:37 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_GRAPHICS_H +#define __AGI_GRAPHICS_H + +#ifdef __cplusplus +extern "C"{ +#endif + +#if defined PALMOS || defined FAKE_PALMOS + +#define GFX_WIDTH 160 +#define GFX_HEIGHT 160 +#define CHAR_COLS 4 +#define CHAR_LINES 6 +#define PIC_HEIGHT (22 * CHAR_LINES) + +#else + +#define GFX_WIDTH 320 +#define GFX_HEIGHT 200 +#define CHAR_COLS 8 +#define CHAR_LINES 8 + +#endif + +struct gfx_driver { + int (*init_video_mode)(void); + int (*deinit_video_mode)(void); + void (*put_block)(int x1, int y1, int x2, int y2); + void (*put_pixels)(int x, int y, int w, pixel_t *p); + void (*poll_timer)(void); + int (*keypress)(void); + int (*get_key)(void); +}; + +extern UINT8 palette[]; + + +/* Transparent layer */ +extern UINT8 layer1_data[]; +extern UINT8 layer2_data[]; + + +void put_text_character(int, int, int, unsigned int, int, int); +void shake_screen (int); +void shake_start (void); +void shake_end (void); +void save_screen (void); +void restore_screen (void); + +int init_video (void); +int deinit_video (void); +void schedule_update (int, int, int, int); +void do_update (void); +void put_screen (void); +void flush_block (int, int, int, int); +void flush_block_a (int, int, int, int); +void put_pixels_a (int, int, int, pixel_t *); +void flush_screen (void); +void clear_screen (int); +void clear_console_screen (int); +void draw_box (int, int, int, int, int, int, int); +void draw_button (int, int, char *, int, int); +int test_button (int, int, char *); +void draw_rectangle (int, int, int, int, int); +void save_block (int, int, int, int, pixel_t *); +void restore_block (int, int, int, int, pixel_t *); +void init_palette (UINT8 *); + +void put_pixel (int, int, int); + + +#ifdef USE_HIRES +void put_pixels_hires (int x, int y, int n, UINT8 *p); +#endif +int keypress (void); +int get_key (void); +void print_character (int, int, char, int, int); +void poll_timer (void); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_GRAPHICS_H */ + diff --git a/include/keyboard.h b/include/keyboard.h index a828527..1d489aa 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -1,81 +1,81 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: keyboard.h,v 1.24 2003/09/02 01:10:55 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_KEYBOARD_H -#define __AGI_KEYBOARD_H - -#ifdef __cplusplus -extern "C"{ -#endif - -/* QNX4 has a KEY_DOWN defined which we don't need to care about */ -#undef KEY_DOWN - -/* Allegro defines these */ -#undef KEY_BACKSPACE -#undef KEY_ENTER -#undef KEY_LEFT -#undef KEY_RIGHT -#undef KEY_UP -#undef KEY_PGUP -#undef KEY_PGDN -#undef KEY_HOME -#undef KEY_END - -#define KEY_BACKSPACE 0x08 -#define KEY_ESCAPE 0x1B -#define KEY_ENTER 0x0D -#define KEY_UP 0x4800 -#define KEY_DOWN 0x5000 -#define KEY_LEFT 0x4B00 -#define KEY_STATIONARY 0x4C00 -#define KEY_RIGHT 0x4D00 - -#define KEY_DOWN_LEFT 0x4F00 -#define KEY_DOWN_RIGHT 0x5100 -#define KEY_UP_LEFT 0x4700 -#define KEY_UP_RIGHT 0x4900 - -#define KEY_STATUSLN 0xd900 /* F11 */ -#define KEY_PRIORITY 0xda00 /* F12 */ - -#define KEY_PGUP 0x4900 /* Page Up (fixed by Ziv Barber) */ -#define KEY_PGDN 0x5100 /* Page Down */ -#define KEY_HOME 0x4700 /* Home */ -#define KEY_END 0x4f00 /* End * */ - -#ifdef USE_MOUSE -#define BUTTON_LEFT 0xF101 /* Left mouse button */ -#define BUTTON_RIGHT 0xF202 /* Right mouse button */ -#endif - -#define KEY_SCAN(k) (k >> 8) -#define KEY_ASCII(k) (k & 0xff) - -extern UINT8 scancode_table[]; - - -void init_words (void); -void clean_input (void); -int do_poll_keyboard (void); -void clean_keyboard (void); -void handle_keys (int); -void handle_getstring(int); -int handle_controller(int); -void get_string (int, int, int, int); -UINT16 agi_get_keypress(void); -int wait_key (void); -int wait_any_key (void); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_KEYBOARD_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: keyboard.h,v 1.24 2003/09/02 01:10:55 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_KEYBOARD_H +#define __AGI_KEYBOARD_H + +#ifdef __cplusplus +extern "C"{ +#endif + +/* QNX4 has a KEY_DOWN defined which we don't need to care about */ +#undef KEY_DOWN + +/* Allegro defines these */ +#undef KEY_BACKSPACE +#undef KEY_ENTER +#undef KEY_LEFT +#undef KEY_RIGHT +#undef KEY_UP +#undef KEY_PGUP +#undef KEY_PGDN +#undef KEY_HOME +#undef KEY_END + +#define KEY_BACKSPACE 0x08 +#define KEY_ESCAPE 0x1B +#define KEY_ENTER 0x0D +#define KEY_UP 0x4800 +#define KEY_DOWN 0x5000 +#define KEY_LEFT 0x4B00 +#define KEY_STATIONARY 0x4C00 +#define KEY_RIGHT 0x4D00 + +#define KEY_DOWN_LEFT 0x4F00 +#define KEY_DOWN_RIGHT 0x5100 +#define KEY_UP_LEFT 0x4700 +#define KEY_UP_RIGHT 0x4900 + +#define KEY_STATUSLN 0xd900 /* F11 */ +#define KEY_PRIORITY 0xda00 /* F12 */ + +#define KEY_PGUP 0x4900 /* Page Up (fixed by Ziv Barber) */ +#define KEY_PGDN 0x5100 /* Page Down */ +#define KEY_HOME 0x4700 /* Home */ +#define KEY_END 0x4f00 /* End * */ + +#ifdef USE_MOUSE +#define BUTTON_LEFT 0xF101 /* Left mouse button */ +#define BUTTON_RIGHT 0xF202 /* Right mouse button */ +#endif + +#define KEY_SCAN(k) (k >> 8) +#define KEY_ASCII(k) (k & 0xff) + +extern UINT8 scancode_table[]; + + +void init_words (void); +void clean_input (void); +int do_poll_keyboard (void); +void clean_keyboard (void); +void handle_keys (int); +void handle_getstring(int); +int handle_controller(int); +void get_string (int, int, int, int); +UINT16 agi_get_keypress(void); +int wait_key (void); +int wait_any_key (void); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_KEYBOARD_H */ diff --git a/include/list.h b/include/list.h index 6eccd07..af10eb4 100644 --- a/include/list.h +++ b/include/list.h @@ -1,145 +1,145 @@ -/* - * $Id: list.h,v 1.2 2001/06/17 12:59:54 cmatsuoka Exp $ - * - * List management macros from the Linux kernel - */ - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -/** - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static INLINE void __list_add(struct list_head * new, - struct list_head * prev, - struct list_head * next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * add a new entry - * Insert a new entry after the specified head. - * This is good for implementing stacks. - * - * @param new new entry to be added - * @param head list head to add it after - */ -static INLINE void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -/** - * add a new entry - * Insert a new entry before the specified head. - * This is useful for implementing queues. - * - * @new: new entry to be added - * @head: list head to add it before - */ -static INLINE void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/** - * Delete a list entry (makes prev/next entries point to each other) - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static INLINE void __list_del(struct list_head * prev, - struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * deletes entry from list. - * @param entry the element to delete from the list. - */ -static INLINE void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); -} - -/** - * tests whether a list is empty - * @param head the list to test. - */ -static INLINE int list_empty(struct list_head *head) -{ - return head->next == head; -} - -/** - * join two lists - * @param list the new list to add. - * @param head the place to add it in the first list. - */ -static INLINE void list_splice(struct list_head *list, struct list_head *head) -{ - struct list_head *first = list->next; - - if (first != list) { - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; - } -} - -/** - * get the struct for this entry - * @param ptr the &struct list_head pointer. - * @param type the type of the struct this is embedded in. - * @param member the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) - -/** - * iterate over a list - * @param pos the &struct list_head to use as a loop counter. - * @param head the head for your list. - */ -#define list_for_each(pos, head, next) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -#endif - +/* + * $Id: list.h,v 1.2 2001/06/17 12:59:54 cmatsuoka Exp $ + * + * List management macros from the Linux kernel + */ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +/** + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static INLINE void __list_add(struct list_head * new, + struct list_head * prev, + struct list_head * next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * add a new entry + * Insert a new entry after the specified head. + * This is good for implementing stacks. + * + * @param new new entry to be added + * @param head list head to add it after + */ +static INLINE void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * add a new entry + * Insert a new entry before the specified head. + * This is useful for implementing queues. + * + * @new: new entry to be added + * @head: list head to add it before + */ +static INLINE void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/** + * Delete a list entry (makes prev/next entries point to each other) + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static INLINE void __list_del(struct list_head * prev, + struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * deletes entry from list. + * @param entry the element to delete from the list. + */ +static INLINE void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * tests whether a list is empty + * @param head the list to test. + */ +static INLINE int list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * join two lists + * @param list the new list to add. + * @param head the place to add it in the first list. + */ +static INLINE void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *first = list->next; + + if (first != list) { + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +/** + * get the struct for this entry + * @param ptr the &struct list_head pointer. + * @param type the type of the struct this is embedded in. + * @param member the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * iterate over a list + * @param pos the &struct list_head to use as a loop counter. + * @param head the head for your list. + */ +#define list_for_each(pos, head, next) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#endif + diff --git a/include/logic.h b/include/logic.h index 0d034fc..b1fc881 100644 --- a/include/logic.h +++ b/include/logic.h @@ -1,37 +1,37 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: logic.h,v 1.5 2001/06/17 12:59:54 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_LOGIC_H -#define __AGI_LOGIC_H - -#ifdef __cplusplus -extern "C"{ -#endif - -/** - * AGI logic resource structure. - */ -struct agi_logic { - UINT8 *data; /**< raw resource data */ - int size; /**< size of data */ - int sIP; /**< saved IP */ - int cIP; /**< current IP */ - int num_texts; /**< number of messages */ - char **texts; /**< message list */ -}; - -int decode_logic (int); -void unload_logic (int); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_LOGIC_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: logic.h,v 1.5 2001/06/17 12:59:54 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_LOGIC_H +#define __AGI_LOGIC_H + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * AGI logic resource structure. + */ +struct agi_logic { + UINT8 *data; /**< raw resource data */ + int size; /**< size of data */ + int sIP; /**< saved IP */ + int cIP; /**< current IP */ + int num_texts; /**< number of messages */ + char **texts; /**< message list */ +}; + +int decode_logic (int); +void unload_logic (int); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_LOGIC_H */ diff --git a/include/lzw.h b/include/lzw.h index ef6d6af..d080322 100644 --- a/include/lzw.h +++ b/include/lzw.h @@ -1,24 +1,24 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: lzw.h,v 1.2 2001/04/14 01:00:10 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_LZW_H -#define __AGI_LZW_H - -#ifdef __cplusplus -extern "C"{ -#endif - -void LZW_expand (UINT8 *, UINT8 *, SINT32); - -#ifdef __cplusplus -}; -#endif - -#endif +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: lzw.h,v 1.2 2001/04/14 01:00:10 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_LZW_H +#define __AGI_LZW_H + +#ifdef __cplusplus +extern "C"{ +#endif + +void LZW_expand (UINT8 *, UINT8 *, SINT32); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/include/menu.h b/include/menu.h index fc4b9f4..a38969e 100644 --- a/include/menu.h +++ b/include/menu.h @@ -1,37 +1,37 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: menu.h,v 1.8 2003/08/07 06:41:24 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_MENU_H -#define __AGI_MENU_H - -#ifdef __cplusplus -extern "C"{ -#endif - -#define MENU_BG 0x0f /* White */ -#define MENU_DISABLED 0x07 /* Grey */ - -#define MENU_FG 0x00 /* Black */ -#define MENU_LINE 0x00 /* Black */ - -void menu_init (void); -void menu_deinit (void); -void menu_add (char *); -void menu_add_item (char *, int); -void menu_submit (void); -void menu_set_item (int, int); -int menu_keyhandler (int); -void menu_enable_all (void); - -#ifdef __cplusplus -}; -#endif - -#endif +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: menu.h,v 1.8 2003/08/07 06:41:24 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_MENU_H +#define __AGI_MENU_H + +#ifdef __cplusplus +extern "C"{ +#endif + +#define MENU_BG 0x0f /* White */ +#define MENU_DISABLED 0x07 /* Grey */ + +#define MENU_FG 0x00 /* Black */ +#define MENU_LINE 0x00 /* Black */ + +void menu_init (void); +void menu_deinit (void); +void menu_add (char *); +void menu_add_item (char *, int); +void menu_submit (void); +void menu_set_item (int, int); +int menu_keyhandler (int); +void menu_enable_all (void); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/include/opcodes.h b/include/opcodes.h index 60b3a2e..31e4f30 100644 --- a/include/opcodes.h +++ b/include/opcodes.h @@ -1,43 +1,43 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: opcodes.h,v 1.13 2002/07/30 02:16:01 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_OPCODES_H -#define __AGI_OPCODES_H - -#ifdef __cplusplus -extern "C"{ -#endif - -struct agi_logicnames { -#ifdef USE_CONSOLE /* ifndef NO_DEBUG */ - char *name; -#endif - UINT16 num_args; - UINT16 arg_mask; -}; - -extern struct agi_logicnames logic_names_test[]; -extern struct agi_logicnames logic_names_cmd[]; -extern struct agi_logicnames logic_names_if[]; - -void debug_console (int, int, char *); -int test_if_code (int); -void new_room (int); -void execute_agi_command (UINT8, UINT8 *); - -#ifdef PATCH_LOGIC -void patch_logic (int); -#endif - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_OPCODES_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: opcodes.h,v 1.13 2002/07/30 02:16:01 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_OPCODES_H +#define __AGI_OPCODES_H + +#ifdef __cplusplus +extern "C"{ +#endif + +struct agi_logicnames { +#ifdef USE_CONSOLE /* ifndef NO_DEBUG */ + char *name; +#endif + UINT16 num_args; + UINT16 arg_mask; +}; + +extern struct agi_logicnames logic_names_test[]; +extern struct agi_logicnames logic_names_cmd[]; +extern struct agi_logicnames logic_names_if[]; + +void debug_console (int, int, char *); +int test_if_code (int); +void new_room (int); +void execute_agi_command (UINT8, UINT8 *); + +#ifdef PATCH_LOGIC +void patch_logic (int); +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_OPCODES_H */ diff --git a/include/picture.h b/include/picture.h index 2b42b23..3598b4a 100644 --- a/include/picture.h +++ b/include/picture.h @@ -1,35 +1,35 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: picture.h,v 1.10 2001/06/19 15:09:19 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_PICTURE_H -#define __AGI_PICTURE_H - -#ifdef __cplusplus -extern "C"{ -#endif - -/** - * AGI picture resource. - */ -struct agi_picture { - UINT32 flen; /**< size of raw data */ - UINT8 *rdata; /**< raw vector image data */ -}; - -int decode_picture (int, int); -int unload_picture (int); -void show_pic (void); -UINT8* convert_v3_pic (UINT8 *data, UINT32 len); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_PICTURE_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: picture.h,v 1.10 2001/06/19 15:09:19 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_PICTURE_H +#define __AGI_PICTURE_H + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * AGI picture resource. + */ +struct agi_picture { + UINT32 flen; /**< size of raw data */ + UINT8 *rdata; /**< raw vector image data */ +}; + +int decode_picture (int, int); +int unload_picture (int); +void show_pic (void); +UINT8* convert_v3_pic (UINT8 *data, UINT32 len); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_PICTURE_H */ diff --git a/include/portdefs.h b/include/portdefs.h index c40c925..e978b3e 100644 --- a/include/portdefs.h +++ b/include/portdefs.h @@ -1,186 +1,186 @@ -/* $Id: portdefs.h,v 1.21 2002/11/06 07:41:23 cmatsuoka Exp $ */ - -/* - * This file contains port-specific definitions. Port makefiles may - * set a different include path to override definitions in sarien.h - */ - - -/* - * Features - */ -//#define FAKE_PALMOS - -#ifdef DREAMCAST -# define DC_BASE_PATH "/cd" -# define DC_GFX_PATH "/cd/gfx" -# define VMU_PATH "/vmu/%s/SDC-%s-%d" -# define UNKNOWN_GAME "Unknown" -# undef USE_COMMAND_LINE -char g_gamename[255]; -static char g_vmu_port[2]; -#endif - -#ifdef __TURBOC__ -# undef USE_PCM_SOUND -# undef USE_MOUSE -#endif - -#ifdef PCCGA -# undef USE_HIRES -#endif - -#ifdef PALMOS -# include -# undef USE_CONSOLE -# undef USE_PCM_SOUND -# undef USE_HIRES -# undef USE_COMMAND_LINE -# undef AGDS_SUPPORT -# undef OPT_LIST_OBJECTS -# undef OPT_PICTURE_VIEWER -# undef OPT_LIST_DICT -# define assert(x) do { if (x) {}; } while (0) -#else -# include -# include - typedef signed int Err; -#endif -//#define _TRACE -#ifdef CIBYL -# include -# include -# include -# include -# include -# define HAVE_VSNPRINTF -# define FAKE_PALMOS -# define fopen cibyl_open - -struct dirent *cibyl_readdir(DIR *dir); -extern DIR *cibyl_opendir(const char *name); -extern int cibyl_closedir(DIR *dir); - -extern char **cibyl_read_cibar_directory(char *base_dir); -#endif - -#ifdef FAKE_PALMOS -# undef USE_CONSOLE -# undef USE_PCM_SOUND -# undef USE_HIRES -# undef USE_COMMAND_LINE -# undef AGDS_SUPPORT -# undef OPT_LIST_OBJECTS -# undef OPT_PICTURE_VIEWER -# undef OPT_LIST_DICT -#endif - -#ifdef _MSC_VER -# undef USE_CONSOLE -# undef USE_PCM_SOUND -# undef USE_HIRES -# undef USE_COMMAND_LINE -# undef AGDS_SUPPORT -# undef OPT_LIST_OBJECTS -# undef OPT_PICTURE_VIEWER -# undef OPT_LIST_DICT -# undef USE_MOUSE -# undef _TRACE -#endif - -/* - * Memory allocation - */ - -/* - * From the Turbo C FAQ: - * - * Q. I have a working program that dynamically allocates memory - * using malloc() or calloc() in small data models (tiny, small, - * and medium). When I compile this program in large data models - * (compact, large, and huge), my program hangs. - * A. Make sure that you have #include in your program. - */ -//#ifdef __TURBOC__ -#ifdef _MSC_VER -#include -#else -# include -#endif - -#ifdef PALMOS -/* Mappings between standard c functions and PalmOS equivalents. - * Should be done for all functions used by Sarien that are available - * in the PalmOS API since it creates smaller (and perhaps faster) code. - */ -/* Memory Manager (incomplete) */ -# define malloc(x) MemPtrNew(x) -# define free(x) MemPtrFree(x) -/* String Manager (includes all obviously equivalent functions) */ -# define atoi(str) StrAToI(str) -# define strcat(dst,src) StrCat(dst,src) -# define strchr(str,chr) StrChr(str,chr) -# define strcpy(dst,src) StrCopy(dst,src) -# define strlen(str) StrLen(str) -# define strncpy(dst,src,n) StrNCopy(dst,src,n) -# define strstr(str,token) StrStr(str,token) -#endif - - -/* Environment variable containing the path name for the users's - * private files ($HOME in Unix, %USERPROFILE% in Win32) - * DATADIR conflicts with ObjIdl.h in win32 SDK, renamed to DATA_DIR - */ -#if defined (WIN32) || defined (__MSDOS__) -# define HOMEDIR "USERPROFILE" -# define DATA_DIR "Sarien" -#else -# define HOMEDIR "HOME" -# define DATA_DIR ".sarien" -#endif - - -/* - * Data types - */ -#if defined(PALMOS) - typedef UInt8 UINT8; - typedef UInt16 UINT16; - typedef UInt32 UINT32; - typedef Int8 SINT8; - typedef Int16 SINT16; - typedef Int32 SINT32; -#elif defined(__MSDOS__) - typedef unsigned char UINT8; - typedef signed char SINT8; - typedef unsigned short UINT16; - typedef signed short SINT16; - typedef unsigned long UINT32; - typedef signed long SINT32; -#elif defined(WIN32) - typedef unsigned char UINT8; - typedef signed char SINT8; - typedef unsigned short UINT16; - typedef signed short SINT16; -# ifndef _BASETSD_H - typedef unsigned int UINT32; -# endif - typedef signed int SINT32; -#else - typedef unsigned char UINT8; - typedef signed char SINT8; - typedef unsigned short UINT16; - typedef signed short SINT16; - typedef unsigned int UINT32; - typedef signed int SINT32; -#endif - - -/* - * Version and other definitions - */ -#ifdef NATIVE_WIN32 -# define INLINE __inline -# define VERSION __TIMESTAMP__ -#endif - +/* $Id: portdefs.h,v 1.21 2002/11/06 07:41:23 cmatsuoka Exp $ */ + +/* + * This file contains port-specific definitions. Port makefiles may + * set a different include path to override definitions in sarien.h + */ + + +/* + * Features + */ +//#define FAKE_PALMOS + +#ifdef DREAMCAST +# define DC_BASE_PATH "/cd" +# define DC_GFX_PATH "/cd/gfx" +# define VMU_PATH "/vmu/%s/SDC-%s-%d" +# define UNKNOWN_GAME "Unknown" +# undef USE_COMMAND_LINE +char g_gamename[255]; +static char g_vmu_port[2]; +#endif + +#ifdef __TURBOC__ +# undef USE_PCM_SOUND +# undef USE_MOUSE +#endif + +#ifdef PCCGA +# undef USE_HIRES +#endif + +#ifdef PALMOS +# include +# undef USE_CONSOLE +# undef USE_PCM_SOUND +# undef USE_HIRES +# undef USE_COMMAND_LINE +# undef AGDS_SUPPORT +# undef OPT_LIST_OBJECTS +# undef OPT_PICTURE_VIEWER +# undef OPT_LIST_DICT +# define assert(x) do { if (x) {}; } while (0) +#else +# include +# include + typedef signed int Err; +#endif +//#define _TRACE +#ifdef CIBYL +# include +# include +# include +# include +# include +# define HAVE_VSNPRINTF +# define FAKE_PALMOS +# define fopen cibyl_open + +struct dirent *cibyl_readdir(DIR *dir); +extern DIR *cibyl_opendir(const char *name); +extern int cibyl_closedir(DIR *dir); + +extern char **cibyl_read_cibar_directory(char *base_dir); +#endif + +#ifdef FAKE_PALMOS +# undef USE_CONSOLE +# undef USE_PCM_SOUND +# undef USE_HIRES +# undef USE_COMMAND_LINE +# undef AGDS_SUPPORT +# undef OPT_LIST_OBJECTS +# undef OPT_PICTURE_VIEWER +# undef OPT_LIST_DICT +#endif + +#ifdef _MSC_VER +# undef USE_CONSOLE +# undef USE_PCM_SOUND +# undef USE_HIRES +# undef USE_COMMAND_LINE +# undef AGDS_SUPPORT +# undef OPT_LIST_OBJECTS +# undef OPT_PICTURE_VIEWER +# undef OPT_LIST_DICT +# undef USE_MOUSE +# undef _TRACE +#endif + +/* + * Memory allocation + */ + +/* + * From the Turbo C FAQ: + * + * Q. I have a working program that dynamically allocates memory + * using malloc() or calloc() in small data models (tiny, small, + * and medium). When I compile this program in large data models + * (compact, large, and huge), my program hangs. + * A. Make sure that you have #include in your program. + */ +//#ifdef __TURBOC__ +#ifdef _MSC_VER +#include +#else +# include +#endif + +#ifdef PALMOS +/* Mappings between standard c functions and PalmOS equivalents. + * Should be done for all functions used by Sarien that are available + * in the PalmOS API since it creates smaller (and perhaps faster) code. + */ +/* Memory Manager (incomplete) */ +# define malloc(x) MemPtrNew(x) +# define free(x) MemPtrFree(x) +/* String Manager (includes all obviously equivalent functions) */ +# define atoi(str) StrAToI(str) +# define strcat(dst,src) StrCat(dst,src) +# define strchr(str,chr) StrChr(str,chr) +# define strcpy(dst,src) StrCopy(dst,src) +# define strlen(str) StrLen(str) +# define strncpy(dst,src,n) StrNCopy(dst,src,n) +# define strstr(str,token) StrStr(str,token) +#endif + + +/* Environment variable containing the path name for the users's + * private files ($HOME in Unix, %USERPROFILE% in Win32) + * DATADIR conflicts with ObjIdl.h in win32 SDK, renamed to DATA_DIR + */ +#if defined (WIN32) || defined (__MSDOS__) +# define HOMEDIR "USERPROFILE" +# define DATA_DIR "Sarien" +#else +# define HOMEDIR "HOME" +# define DATA_DIR ".sarien" +#endif + + +/* + * Data types + */ +#if defined(PALMOS) + typedef UInt8 UINT8; + typedef UInt16 UINT16; + typedef UInt32 UINT32; + typedef Int8 SINT8; + typedef Int16 SINT16; + typedef Int32 SINT32; +#elif defined(__MSDOS__) + typedef unsigned char UINT8; + typedef signed char SINT8; + typedef unsigned short UINT16; + typedef signed short SINT16; + typedef unsigned long UINT32; + typedef signed long SINT32; +#elif defined(WIN32) + typedef unsigned char UINT8; + typedef signed char SINT8; + typedef unsigned short UINT16; + typedef signed short SINT16; +# ifndef _BASETSD_H + typedef unsigned int UINT32; +# endif + typedef signed int SINT32; +#else + typedef unsigned char UINT8; + typedef signed char SINT8; + typedef unsigned short UINT16; + typedef signed short SINT16; + typedef unsigned int UINT32; + typedef signed int SINT32; +#endif + + +/* + * Version and other definitions + */ +#ifdef NATIVE_WIN32 +# define INLINE __inline +# define VERSION __TIMESTAMP__ +#endif + diff --git a/include/rand.h b/include/rand.h index 3021aca..b891d65 100644 --- a/include/rand.h +++ b/include/rand.h @@ -1,26 +1,26 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: rand.h,v 1.3 2001/06/17 12:59:54 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_RANDOM_H -#define __AGI_RANDOM_H - -#ifdef __cplusplus -extern "C"{ -#endif - -SINT32 get_rnd_seed (void); -void set_rnd_seed (void); -SINT32 rnd (SINT32 maxrnd); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_RANDOM_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: rand.h,v 1.3 2001/06/17 12:59:54 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_RANDOM_H +#define __AGI_RANDOM_H + +#ifdef __cplusplus +extern "C"{ +#endif + +SINT32 get_rnd_seed (void); +void set_rnd_seed (void); +SINT32 rnd (SINT32 maxrnd); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_RANDOM_H */ diff --git a/include/sarien.h b/include/sarien.h index a7bc1bc..7265f4d 100644 --- a/include/sarien.h +++ b/include/sarien.h @@ -1,305 +1,299 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: sarien.h,v 1.97 2003/08/07 07:32:55 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __SARIEN_H -#define __SARIEN_H - -#define VERSION "0.8.0-j2me" - -#ifdef __cplusplus -extern "C"{ -#endif - -#ifdef DMALLOC -# include -# include -#endif - -/* Default features -- can be overriden in portdefs.h */ -#define USE_CONSOLE -#define USE_PCM_SOUND -#define USE_IIGS_SOUND -#define USE_HIRES -#define USE_COMMAND_LINE -#define USE_MOUSE -#define AGDS_SUPPORT -#define OPT_LIST_OBJECTS -#define OPT_PICTURE_VIEWER -#define OPT_LIST_DICT - -#include "console.h" - -#define TITLE "Sarien" - -#define DIR_ "dir." -#define LOGDIR "logdir" -#define PICDIR "picdir" -#define VIEWDIR "viewdir" -#define SNDDIR "snddir" -#define OBJECTS "object" -#define WORDS "words.tok" - -#define MAX_DIRS 256 -#define MAX_VARS 256 -#define MAX_FLAGS (256 >> 3) -#define MAX_VIEWTABLE 255 /* KQ3 uses o255! */ -#define MAX_WORDS 20 -#define MAX_STRINGS 24 /* MAX_STRINGS + 1 used for get.num */ -#define MAX_STRINGLEN 40 -#ifndef MAX_PATH -#define MAX_PATH 260 -#endif - -#define _EMPTY 0xfffff -#define EGO_OWNED 0xff - -#define CRYPT_KEY_SIERRA "Avis Durgan" -#define CRYPT_KEY_AGDS "Alex Simkin" - - //#define _TRACE - -#if 0 -/* You'll need an ANSI terminal to use these :\ */ -#ifdef _TRACE -# include -# ifdef __GNUC__ -# define _D_INFO "\x1b[33m" -# define _D_CRIT "\x1b[31m" -# define _D_WARN "\x1b[36m" -# define _D(args...) do { \ - printf("\x1b[33m%s \x1b[37m[%s:%d] " _D_INFO, __PRETTY_FUNCTION__, \ - __FILE__, __LINE__); printf (args); printf ("\x1b[0m\n"); \ - } while (0) -# else -# define _D_INFO "I: " -# define _D_CRIT "C: " -# define _D_WARN "W: " -# define _D printf("\n%s:%d: ", __FILE__, __LINE__); printf -# endif /* __GNUC__ */ -#else /* !_TRACE */ -# define _D_INFO -# define _D_CRIT -# define _D_WARN -# ifdef _D -# undef _D -# endif -# if defined(__GNUC__) /* && !defined(MACOSX) */ -//# define _D(args...) -# else -// void _D(char *, ...); -# endif -#endif /* _TRACE */ -//yuck -# define _D_INFO -# define _D_CRIT -# define _D_WARN -#endif - -#define _D_INFO -#define _D_CRIT -#define _D_WARN -#define _D nothing - -/* Include port-specific definitions - * - * In most C compiler implementation, quoted form of #include - * searches in the same folder first. On the contrary, angle-bracket - * form starts search in compiler predefined order. So, #include - * would be more correct. --Vasyl - */ -#include - -typedef UINT8 pixel_t; - - -#ifndef FALSE -# define FALSE 0 -# define TRUE (!FALSE) -#endif - -#ifndef INLINE -# define INLINE -#endif - -#ifndef USE_PCM_SOUND -# undef USE_IIGS_SOUND -#endif - -#define MSG_BOX_COLOUR 0x0f /* White */ -#define MSG_BOX_TEXT 0x00 /* Black */ -#define MSG_BOX_LINE 0x04 /* Red */ -#define STATUS_FG 0x00 /* Black */ -#define STATUS_BG 0x0f /* White */ -#define PATCH_LOGIC /* disable copy protection on some games */ - -UINT8 lohi_getbyte (UINT8 *); -UINT16 lohi_getword (UINT8 *); -UINT32 lohi_getpword (UINT8 *); -UINT32 lohi_getdword (UINT8 *); -UINT8 hilo_getbyte (UINT8 *); -UINT16 hilo_getword (UINT8 *); -UINT32 hilo_getpword (UINT8 *); -UINT32 hilo_getdword (UINT8 *); -int getflag (int); -void setflag (int, int); -void flipflag (int); -int getvar (int); -void setvar (int, int); -void decrypt (UINT8 *mem, int len); -void release_sprites (void); -int main_cycle (void); -int view_pictures (void); -int parse_cli (int, char **); -int run_game (void); -int init_machine (void); //int, char **); -int deinit_machine (void); -int file_isthere (char *fname); /* Allegro has file_exists() */ -char* file_name (char *fname); -char* fixpath (int flag, char *fname); -int get_direction (int x, int y, int x0, int y0, int s); -void inventory (void); -void list_games (void); -UINT32 match_crc (UINT32, char *, char *, int); -int v2id_game (void); -int v3id_game (void); -int v4id_game (UINT32 ver); -void update_timer (void); -/* - * get_current_directory() returns the current working - * directory name in a platform independent manner. On - * Unix, DOS, and Win32, it just returns a "." string. - * On MacOS, there is no concept of a "." directory, so - * more detailed (and platform dependent) code would be - * needed there. Hence the need for abstraction. - * - * Return values from this function should be considered - * read-only, static, and non-thread safe. Assume that - * each call to this function will overwrite the previously - * returned data. - * - * Implementations of this function are in src/filesys/. - */ -char* get_current_directory (void); -char* get_config_file (void); -int get_app_dir (char *app_dir, unsigned int size); - - -enum { - NO_GAMEDIR = 0, - GAMEDIR -}; - -enum error { - err_OK = 0, - err_DoNothing, - err_BadCLISwitch, - err_InvalidAGIFile, - err_BadFileOpen, - err_NotEnoughMemory, - err_BadResource, - err_UnknownAGIVersion, - err_RestartGame, - err_NoLoopsInView, - err_ViewDataError, - err_NoGameList, - - err_Unk = 127 -}; - -/** - * AGI resources. - */ -enum { - rLOGIC = 1, - rSOUND, - rVIEW, - rPICTURE -}; - -enum { - RES_LOADED = 1, - RES_COMPRESSED = 0x40 -}; - -enum { - lCOMMAND_MODE = 1, - lTEST_MODE -}; - -struct game_id_list { - struct game_id_list *next; - UINT32 version; - UINT32 crc; - char *gName; - char *switches; -}; - -#ifdef USE_MOUSE -struct mouse { - int button; - unsigned int x; - unsigned int y; -}; -#endif - -/** - * Command-line options. - */ -struct sarien_options { -#define GAMERUN_RUNGAME 0 -#define GAMERUN_PICVIEW 1 -#define GAMERUN_WORDS 2 -#define GAMERUN_OBJECTS 3 -#define GAMERUN_GAMES 4 -#define GAMERUN_CRC 5 - int gamerun; /**< game run mode*/ - int emuversion; /**< AGI version to emulate */ - int scale; /**< window scale factor */ - int fixratio; /**< fix aspect ratio */ - int agds; /**< enable AGDS mode */ - int amiga; /**< enable Amiga mode */ - int fullscreen; /**< use full screen mode if available */ - int nosound; /**< disable sound */ - int egapal; /**< use PC EGA palette */ - int cgaemu; /**< use PC CGA emulation */ -#ifdef MITSHM - int mitshm; /**< use shared memory extension */ -#endif -#ifdef USE_HIRES - int hires; /**< use hi-res pictures */ -#endif - int soundemu; /**< sound emulation mode */ - int gfxhacks; /**< enable graphics driver optimizations */ -#ifdef USE_MOUSE - int agimouse; /**< AGI Mouse 1.0 emulation */ -#endif -}; - -extern struct sarien_options opt; -extern UINT8 *exec_name; - -extern volatile UINT32 clock_ticks; -extern volatile UINT32 clock_count; -extern volatile UINT32 msg_box_secs2; - -#ifdef USE_CONSOLE -extern struct sarien_debug debug; -#endif - -#ifdef USE_MOUSE -extern struct mouse mouse; -#endif - -#ifdef __cplusplus -}; -#endif - -#endif /* __SARIEN_H */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: sarien.h,v 1.97 2003/08/07 07:32:55 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __SARIEN_H +#define __SARIEN_H + +#define VERSION "0.8.0-j2me" + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifdef DMALLOC +# include +# include +#endif + +/* Default features -- can be overriden in portdefs.h */ +#define USE_CONSOLE +#define USE_PCM_SOUND +#define USE_IIGS_SOUND +#define USE_HIRES +#define USE_COMMAND_LINE +#define USE_MOUSE +#define AGDS_SUPPORT +#define OPT_LIST_OBJECTS +#define OPT_PICTURE_VIEWER +#define OPT_LIST_DICT + +#include "console.h" + +#define TITLE "Sarien" + +#define DIR_ "dir." +#define LOGDIR "logdir" +#define PICDIR "picdir" +#define VIEWDIR "viewdir" +#define SNDDIR "snddir" +#define OBJECTS "object" +#define WORDS "words.tok" + +#define MAX_DIRS 256 +#define MAX_VARS 256 +#define MAX_FLAGS (256 >> 3) +#define MAX_VIEWTABLE 255 /* KQ3 uses o255! */ +#define MAX_WORDS 20 +#define MAX_STRINGS 24 /* MAX_STRINGS + 1 used for get.num */ +#define MAX_STRINGLEN 40 +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +#define _EMPTY 0xfffff +#define EGO_OWNED 0xff + +#define CRYPT_KEY_SIERRA "Avis Durgan" +#define CRYPT_KEY_AGDS "Alex Simkin" + + //#define _TRACE + +/* You'll need an ANSI terminal to use these :\ */ +#ifdef _TRACE +# include +# ifdef __GNUC__ +# define _D_INFO "\x1b[33m" +# define _D_CRIT "\x1b[31m" +# define _D_WARN "\x1b[36m" +# define _D(args...) do { \ + printf("\x1b[33m%s \x1b[37m[%s:%d] " _D_INFO, __PRETTY_FUNCTION__, \ + __FILE__, __LINE__); printf (args); printf ("\x1b[0m\n"); \ + } while (0) +# else +# define _D_INFO "I: " +# define _D_CRIT "C: " +# define _D_WARN "W: " +# define _D printf("\n%s:%d: ", __FILE__, __LINE__); printf +# endif /* __GNUC__ */ +#else /* !_TRACE */ +# define _D_INFO +# define _D_CRIT +# define _D_WARN +# ifdef _D +# undef _D +# endif +# if defined(__GNUC__) /* && !defined(MACOSX) */ +# define _D(args...) +# else + void _D(char *, ...); +# endif +#endif /* _TRACE */ +//yuck +# define _D_INFO +# define _D_CRIT +# define _D_WARN + + +/* Include port-specific definitions + * + * In most C compiler implementation, quoted form of #include + * searches in the same folder first. On the contrary, angle-bracket + * form starts search in compiler predefined order. So, #include + * would be more correct. --Vasyl + */ +#include + +typedef UINT8 pixel_t; + + +#ifndef FALSE +# define FALSE 0 +# define TRUE (!FALSE) +#endif + +#ifndef INLINE +# define INLINE +#endif + +#ifndef USE_PCM_SOUND +# undef USE_IIGS_SOUND +#endif + +#define MSG_BOX_COLOUR 0x0f /* White */ +#define MSG_BOX_TEXT 0x00 /* Black */ +#define MSG_BOX_LINE 0x04 /* Red */ +#define STATUS_FG 0x00 /* Black */ +#define STATUS_BG 0x0f /* White */ +#define PATCH_LOGIC /* disable copy protection on some games */ + +UINT8 lohi_getbyte (UINT8 *); +UINT16 lohi_getword (UINT8 *); +UINT32 lohi_getpword (UINT8 *); +UINT32 lohi_getdword (UINT8 *); +UINT8 hilo_getbyte (UINT8 *); +UINT16 hilo_getword (UINT8 *); +UINT32 hilo_getpword (UINT8 *); +UINT32 hilo_getdword (UINT8 *); +int getflag (int); +void setflag (int, int); +void flipflag (int); +int getvar (int); +void setvar (int, int); +void decrypt (UINT8 *mem, int len); +void release_sprites (void); +int main_cycle (void); +int view_pictures (void); +int parse_cli (int, char **); +int run_game (void); +int init_machine (void); //int, char **); +int deinit_machine (void); +int file_isthere (char *fname); /* Allegro has file_exists() */ +char* file_name (char *fname); +char* fixpath (int flag, char *fname); +int get_direction (int x, int y, int x0, int y0, int s); +void inventory (void); +void list_games (void); +UINT32 match_crc (UINT32, char *, char *, int); +int v2id_game (void); +int v3id_game (void); +int v4id_game (UINT32 ver); +void update_timer (void); +/* + * get_current_directory() returns the current working + * directory name in a platform independent manner. On + * Unix, DOS, and Win32, it just returns a "." string. + * On MacOS, there is no concept of a "." directory, so + * more detailed (and platform dependent) code would be + * needed there. Hence the need for abstraction. + * + * Return values from this function should be considered + * read-only, static, and non-thread safe. Assume that + * each call to this function will overwrite the previously + * returned data. + * + * Implementations of this function are in src/filesys/. + */ +char* get_current_directory (void); +char* get_config_file (void); +int get_app_dir (char *app_dir, unsigned int size); + + +enum { + NO_GAMEDIR = 0, + GAMEDIR +}; + +enum error { + err_OK = 0, + err_DoNothing, + err_BadCLISwitch, + err_InvalidAGIFile, + err_BadFileOpen, + err_NotEnoughMemory, + err_BadResource, + err_UnknownAGIVersion, + err_RestartGame, + err_NoLoopsInView, + err_ViewDataError, + err_NoGameList, + + err_Unk = 127 +}; + +/** + * AGI resources. + */ +enum { + rLOGIC = 1, + rSOUND, + rVIEW, + rPICTURE +}; + +enum { + RES_LOADED = 1, + RES_COMPRESSED = 0x40 +}; + +enum { + lCOMMAND_MODE = 1, + lTEST_MODE +}; + +struct game_id_list { + struct game_id_list *next; + UINT32 version; + UINT32 crc; + char *gName; + char *switches; +}; + +#ifdef USE_MOUSE +struct mouse { + int button; + unsigned int x; + unsigned int y; +}; +#endif + +/** + * Command-line options. + */ +struct sarien_options { +#define GAMERUN_RUNGAME 0 +#define GAMERUN_PICVIEW 1 +#define GAMERUN_WORDS 2 +#define GAMERUN_OBJECTS 3 +#define GAMERUN_GAMES 4 +#define GAMERUN_CRC 5 + int gamerun; /**< game run mode*/ + int emuversion; /**< AGI version to emulate */ + int scale; /**< window scale factor */ + int fixratio; /**< fix aspect ratio */ + int agds; /**< enable AGDS mode */ + int amiga; /**< enable Amiga mode */ + int fullscreen; /**< use full screen mode if available */ + int nosound; /**< disable sound */ + int egapal; /**< use PC EGA palette */ + int cgaemu; /**< use PC CGA emulation */ +#ifdef MITSHM + int mitshm; /**< use shared memory extension */ +#endif +#ifdef USE_HIRES + int hires; /**< use hi-res pictures */ +#endif + int soundemu; /**< sound emulation mode */ + int gfxhacks; /**< enable graphics driver optimizations */ +#ifdef USE_MOUSE + int agimouse; /**< AGI Mouse 1.0 emulation */ +#endif +}; + +extern struct sarien_options opt; +extern UINT8 *exec_name; + +extern volatile UINT32 clock_ticks; +extern volatile UINT32 clock_count; +extern volatile UINT32 msg_box_secs2; + +#ifdef USE_CONSOLE +extern struct sarien_debug debug; +#endif + +#ifdef USE_MOUSE +extern struct mouse mouse; +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* __SARIEN_H */ + diff --git a/include/savegame.h b/include/savegame.h index 7cdb70d..c00768d 100644 --- a/include/savegame.h +++ b/include/savegame.h @@ -1,37 +1,37 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999,2001 Stuart George and Claudio Matsuoka - * - * $Id: savegame.h,v 1.6 2003/07/29 19:20:37 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_SAVEGAME_H -#define __AGI_SAVEGAME_H - -#ifdef __cplusplus -extern "C"{ -#endif - -int savegame_dialog (void); -int loadgame_dialog (void); -int savegame_simple (void); -int loadgame_simple (void); - - -/* Image stack support */ -#define ADD_PIC 1 -#define ADD_VIEW 2 - -void clear_image_stack(void); -void record_image_stack_call(UINT8 type, SINT16 p1, SINT16 p2, SINT16 p3, SINT16 p4, SINT16 p5, SINT16 p6, SINT16 p7); -void replay_image_stack_call(UINT8 type, SINT16 p1, SINT16 p2, SINT16 p3, SINT16 p4, SINT16 p5, SINT16 p6, SINT16 p7); -void release_image_stack(void); - -#ifdef __cplusplus -}; -#endif - -#endif +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999,2001 Stuart George and Claudio Matsuoka + * + * $Id: savegame.h,v 1.6 2003/07/29 19:20:37 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_SAVEGAME_H +#define __AGI_SAVEGAME_H + +#ifdef __cplusplus +extern "C"{ +#endif + +int savegame_dialog (void); +int loadgame_dialog (void); +int savegame_simple (void); +int loadgame_simple (void); + + +/* Image stack support */ +#define ADD_PIC 1 +#define ADD_VIEW 2 + +void clear_image_stack(void); +void record_image_stack_call(UINT8 type, SINT16 p1, SINT16 p2, SINT16 p3, SINT16 p4, SINT16 p5, SINT16 p6, SINT16 p7); +void replay_image_stack_call(UINT8 type, SINT16 p1, SINT16 p2, SINT16 p3, SINT16 p4, SINT16 p5, SINT16 p6, SINT16 p7); +void release_image_stack(void); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/include/scale2x.h b/include/scale2x.h index a06a512..2360a88 100644 --- a/include/scale2x.h +++ b/include/scale2x.h @@ -1,1131 +1,1131 @@ -/* - * This file is part of the Scale2x project. - * - * Copyright (C) 2001-2002 Andrea Mazzoleni - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Modifications for Sarien by Claudio Matsuoka, Sun Jul 13 16:33:48 BRT 2003 - * (while listening to The Utterly Fantastic and Totally Unbelievable Sounds of - * Los Straitjackets) - * - * - added scale2x_*_map() functions - * - source is always (uint8 *) - * - handle count < 2 instead of assert - * - mmx functions commented out - */ - -/* - * This file contains a C and MMX implentation of the Scale2x effect. - * - * You can found an high level description of the effect at : - * - * http://scale2x.sourceforge.net/scale2x.html - * - * Alternatively at the previous license terms, you are allowed to use this - * code in your program with these conditions: - * - the program is not used in commercial activities. - * - the whole source code of the program is released with the binary. - * - derivative works of the program are allowed. - */ - -#ifndef __SCALE2X_H -#define __SCALE2X_H - -/* #include */ - -/***************************************************************************/ -/* basic types */ - -typedef unsigned char scale2x_uint8; -typedef unsigned short scale2x_uint16; -typedef unsigned scale2x_uint32; - -/***************************************************************************/ -/* internal_scale2x */ - -#define scale2x_8_map(d1,d2,s1,s2,s3,m,c) scale2x_8_def(d1,d2,s1,s2,s3,c) - -/** - * Scale by a factor of 2 a row of pixels of 8 bits. - * The function is implemented in C. - * The pixels over the left and right borders are assumed of the same color of - * the pixels on the border. - * \param src0 Pointer at the first pixel of the previous row. - * \param src1 Pointer at the first pixel of the current row. - * \param src2 Pointer at the first pixel of the next row. - * \param count Length in pixels of the src0, src1 and src2 rows. - * It must be at least 2. - * \param dst0 First destination row, double length in pixels. - * \param dst1 Second destination row, double length in pixels. - */ -static INLINE void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) -{ - /* assert(count >= 2); */ - if (count < 1) - return; - - /* first pixel */ - dst0[0] = src1[0]; - dst1[0] = src1[0]; - if (src1[1] == src0[0] && src2[0] != src0[0]) - dst0[1] = src0[0]; - else - dst0[1] = src1[0]; - if (src1[1] == src2[0] && src0[0] != src2[0]) - dst1[1] = src2[0]; - else - dst1[1] = src1[0]; - - if (count < 2) - return; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - - /* central pixels */ - count -= 2; - while (count) { - if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) - dst0[0] = src0[0]; - else - dst0[0] = src1[0]; - if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) - dst0[1] = src0[0]; - else - dst0[1] = src1[0]; - - if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) - dst1[0] = src2[0]; - else - dst1[0] = src1[0]; - if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) - dst1[1] = src2[0]; - else - dst1[1] = src1[0]; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - --count; - } - - /* last pixel */ - if (src1[-1] == src0[0] && src2[0] != src0[0]) - dst0[0] = src0[0]; - else - dst0[0] = src1[0]; - if (src1[-1] == src2[0] && src0[0] != src2[0]) - dst1[0] = src2[0]; - else - dst1[0] = src1[0]; - dst0[1] = src1[0]; - dst1[1] = src1[0]; -} - -/** - * Scale by a factor of 2 a row of pixels of 16 bits. - * This function operates like scale2x_8_def() but for 16 bits pixels. - * \param src0 Pointer at the first pixel of the previous row. - * \param src1 Pointer at the first pixel of the current row. - * \param src2 Pointer at the first pixel of the next row. - * \param count Length in pixels of the src0, src1 and src2 rows. - * It must be at least 2. - * \param dst0 First destination row, double length in pixels. - * \param dst1 Second destination row, double length in pixels. - */ -static INLINE void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) -{ - /*assert(count >= 2);*/ - if (count < 1) - return; - - /* first pixel */ - dst0[0] = src1[0]; - dst1[0] = src1[0]; - if (src1[1] == src0[0] && src2[0] != src0[0]) - dst0[1] =src0[0]; - else - dst0[1] =src1[0]; - if (src1[1] == src2[0] && src0[0] != src2[0]) - dst1[1] =src2[0]; - else - dst1[1] =src1[0]; - - if (count < 2) - return; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - - /* central pixels */ - count -= 2; - while (count) { - if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) - dst0[0] = src0[0]; - else - dst0[0] = src1[0]; - if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) - dst0[1] =src0[0]; - else - dst0[1] =src1[0]; - - if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) - dst1[0] =src2[0]; - else - dst1[0] =src1[0]; - if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) - dst1[1] =src2[0]; - else - dst1[1] =src1[0]; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - --count; - } - - /* last pixel */ - if (src1[-1] == src0[0] && src2[0] != src0[0]) - dst0[0] =src0[0]; - else - dst0[0] =src1[0]; - if (src1[-1] == src2[0] && src0[0] != src2[0]) - dst1[0] =src2[0]; - else - dst1[0] =src1[0]; - dst0[1] =src1[0]; - dst1[1] =src1[0]; -} - -static INLINE void scale2x_16_map(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, const scale2x_uint32 *map, unsigned count) -{ - /*assert(count >= 2);*/ - if (count < 1) - return; - - /* first pixel */ - dst0[0] = map[src1[0]]; - dst1[0] = map[src1[0]]; - if (src1[1] == src0[0] && src2[0] != src0[0]) - dst0[1] = map[src0[0]]; - else - dst0[1] = map[src1[0]]; - if (src1[1] == src2[0] && src0[0] != src2[0]) - dst1[1] = map[src2[0]]; - else - dst1[1] = map[src1[0]]; - - if (count < 2) - return; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - - /* central pixels */ - count -= 2; - while (count) { - if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) - dst0[0] = map[src0[0]]; - else - dst0[0] = map[src1[0]]; - if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) - dst0[1] = map[src0[0]]; - else - dst0[1] = map[src1[0]]; - - if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) - dst1[0] = map[src2[0]]; - else - dst1[0] = map[src1[0]]; - if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) - dst1[1] = map[src2[0]]; - else - dst1[1] = map[src1[0]]; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - --count; - } - - /* last pixel */ - if (src1[-1] == src0[0] && src2[0] != src0[0]) - dst0[0] = map[src0[0]]; - else - dst0[0] = map[src1[0]]; - if (src1[-1] == src2[0] && src0[0] != src2[0]) - dst1[0] = map[src2[0]]; - else - dst1[0] = map[src1[0]]; - dst0[1] = map[src1[0]]; - dst1[1] = map[src1[0]]; -} - -/** - * Scale by a factor of 2 a row of pixels of 32 bits. - * This function operates like scale2x_8_def() but for 32 bits pixels. - * \param src0 Pointer at the first pixel of the previous row. - * \param src1 Pointer at the first pixel of the current row. - * \param src2 Pointer at the first pixel of the next row. - * \param count Length in pixels of the src0, src1 and src2 rows. - * It must be at least 2. - * \param dst0 First destination row, double length in pixels. - * \param dst1 Second destination row, double length in pixels. - */ - -static INLINE void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) -{ - /* assert(count >= 2); */ - if (count < 1) - return; - - /* first pixel */ - dst0[0] = src1[0]; - dst1[0] = src1[0]; - if (src1[1] == src0[0] && src2[0] != src0[0]) - dst0[1] = src0[0]; - else - dst0[1] = src1[0]; - if (src1[1] == src2[0] && src0[0] != src2[0]) - dst1[1] = src2[0]; - else - dst1[1] = src1[0]; - - if (count < 2) - return; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - - /* central pixels */ - count -= 2; - while (count) { - if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) - dst0[0] = src0[0]; - else - dst0[0] = src1[0]; - if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) - dst0[1] = src0[0]; - else - dst0[1] = src1[0]; - - if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) - dst1[0] = src2[0]; - else - dst1[0] = src1[0]; - if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) - dst1[1] = src2[0]; - else - dst1[1] = src1[0]; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - --count; - } - - /* last pixel */ - if (src1[-1] == src0[0] && src2[0] != src0[0]) - dst0[0] = src0[0]; - else - dst0[0] = src1[0]; - if (src1[-1] == src2[0] && src0[0] != src2[0]) - dst1[0] = src2[0]; - else - dst1[0] = src1[0]; - dst0[1] = src1[0]; - dst1[1] = src1[0]; -} - -static INLINE void scale2x_32_map(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, const scale2x_uint32* map, unsigned count) -{ - /* assert(count >= 2); */ - if (count < 1) - return; - - /* first pixel */ - dst0[0] = map[src1[0]]; - dst1[0] = map[src1[0]]; - if (src1[1] == src0[0] && src2[0] != src0[0]) - dst0[1] = map[src0[0]]; - else - dst0[1] = map[src1[0]]; - if (src1[1] == src2[0] && src0[0] != src2[0]) - dst1[1] = map[src2[0]]; - else - dst1[1] = map[src1[0]]; - - if (count < 2) - return; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - - /* central pixels */ - count -= 2; - while (count) { - if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) - dst0[0] = map[src0[0]]; - else - dst0[0] = map[src1[0]]; - if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) - dst0[1] = map[src0[0]]; - else - dst0[1] = map[src1[0]]; - - if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) - dst1[0] = map[src2[0]]; - else - dst1[0] = map[src1[0]]; - if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) - dst1[1] = map[src2[0]]; - else - dst1[1] = map[src1[0]]; - - ++src0; - ++src1; - ++src2; - dst0 += 2; - dst1 += 2; - --count; - } - - /* last pixel */ - if (src1[-1] == src0[0] && src2[0] != src0[0]) - dst0[0] = map[src0[0]]; - else - dst0[0] = map[src1[0]]; - if (src1[-1] == src2[0] && src0[0] != src2[0]) - dst1[0] = map[src2[0]]; - else - dst1[0] = map[src1[0]]; - dst0[1] = map[src1[0]]; - dst1[1] = map[src1[0]]; -} - -#if 0 -#if defined(__GNUC__) && defined(__i386__) - -/* - * Apply the Scale2x effect at a single row. - * This function must be called only by the other scale2x functions. - * - * Considering the pixel map : - * - * ABC (src0) - * DEF (src1) - * GHI (src2) - * - * this functions compute 2 new pixels in substitution of the source pixel E - * like this map : - * - * ab (dst) - * - * with these variables : - * - * ¤t -> E - * ¤t_left -> D - * ¤t_right -> F - * ¤t_upper -> B - * ¤t_lower -> H - * - * %0 -> current_upper - * %1 -> current - * %2 -> current_lower - * %3 -> dst - * %4 -> counter - * - * %mm0 -> *current_left - * %mm1 -> *current_next - * %mm2 -> tmp0 - * %mm3 -> tmp1 - * %mm4 -> tmp2 - * %mm5 -> tmp3 - * %mm6 -> *current_upper - * %mm7 -> *current - */ -static __inline__ void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) -{ - assert(count >= 16); - assert(count % 8 == 0); - - /* always do the first and last run */ - count -= 2*8; - - __asm__ __volatile__( -/* first run */ - /* set the current, current_pre, current_next registers */ - "movq 0(%1),%%mm0\n" - "movq 0(%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psllq $56,%%mm0\n" - "psllq $56,%%mm1\n" - "psrlq $56,%%mm0\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $8,%%mm2\n" - "psrlq $8,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqb %%mm6,%%mm2\n" - "pcmpeqb %%mm6,%%mm4\n" - "pcmpeqb (%2),%%mm3\n" - "pcmpeqb (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqb %%mm1,%%mm2\n" - "pcmpeqb %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklbw %%mm4,%%mm2\n" - "punpckhbw %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - -/* central runs */ - "shrl $3,%4\n" - "jz 1f\n" - - "0:\n" - - /* set the current, current_pre, current_next registers */ - "movq -8(%1),%%mm0\n" - "movq (%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psrlq $56,%%mm0\n" - "psllq $56,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $8,%%mm2\n" - "psrlq $8,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqb %%mm6,%%mm2\n" - "pcmpeqb %%mm6,%%mm4\n" - "pcmpeqb (%2),%%mm3\n" - "pcmpeqb (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqb %%mm1,%%mm2\n" - "pcmpeqb %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklbw %%mm4,%%mm2\n" - "punpckhbw %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - - "decl %4\n" - "jnz 0b\n" - "1:\n" - -/* final run */ - /* set the current, current_pre, current_next registers */ - "movq (%1),%%mm1\n" - "movq (%1),%%mm7\n" - "movq -8(%1),%%mm0\n" - "psrlq $56,%%mm1\n" - "psrlq $56,%%mm0\n" - "psllq $56,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $8,%%mm2\n" - "psrlq $8,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqb %%mm6,%%mm2\n" - "pcmpeqb %%mm6,%%mm4\n" - "pcmpeqb (%2),%%mm3\n" - "pcmpeqb (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqb %%mm1,%%mm2\n" - "pcmpeqb %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklbw %%mm4,%%mm2\n" - "punpckhbw %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) - : - : "cc" - ); -} - -static __inline__ void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) -{ - assert(count >= 8); - assert(count % 4 == 0); - - /* always do the first and last run */ - count -= 2*4; - - __asm__ __volatile__( -/* first run */ - /* set the current, current_pre, current_next registers */ - "movq 0(%1),%%mm0\n" - "movq 0(%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psllq $48,%%mm0\n" - "psllq $48,%%mm1\n" - "psrlq $48,%%mm0\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $16,%%mm2\n" - "psrlq $16,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqw %%mm6,%%mm2\n" - "pcmpeqw %%mm6,%%mm4\n" - "pcmpeqw (%2),%%mm3\n" - "pcmpeqw (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqw %%mm1,%%mm2\n" - "pcmpeqw %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklwd %%mm4,%%mm2\n" - "punpckhwd %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - -/* central runs */ - "shrl $2,%4\n" - "jz 1f\n" - - "0:\n" - - /* set the current, current_pre, current_next registers */ - "movq -8(%1),%%mm0\n" - "movq (%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psrlq $48,%%mm0\n" - "psllq $48,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $16,%%mm2\n" - "psrlq $16,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqw %%mm6,%%mm2\n" - "pcmpeqw %%mm6,%%mm4\n" - "pcmpeqw (%2),%%mm3\n" - "pcmpeqw (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqw %%mm1,%%mm2\n" - "pcmpeqw %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklwd %%mm4,%%mm2\n" - "punpckhwd %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - - "decl %4\n" - "jnz 0b\n" - "1:\n" - -/* final run */ - /* set the current, current_pre, current_next registers */ - "movq (%1),%%mm1\n" - "movq (%1),%%mm7\n" - "movq -8(%1),%%mm0\n" - "psrlq $48,%%mm1\n" - "psrlq $48,%%mm0\n" - "psllq $48,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $16,%%mm2\n" - "psrlq $16,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqw %%mm6,%%mm2\n" - "pcmpeqw %%mm6,%%mm4\n" - "pcmpeqw (%2),%%mm3\n" - "pcmpeqw (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqw %%mm1,%%mm2\n" - "pcmpeqw %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklwd %%mm4,%%mm2\n" - "punpckhwd %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) - : - : "cc" - ); -} - -static __inline__ void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) -{ - assert(count >= 4); - assert(count % 2 == 0); - - /* always do the first and last run */ - count -= 2*2; - - __asm__ __volatile__( -/* first run */ - /* set the current, current_pre, current_next registers */ - "movq 0(%1),%%mm0\n" - "movq 0(%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psllq $32,%%mm0\n" - "psllq $32,%%mm1\n" - "psrlq $32,%%mm0\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $32,%%mm2\n" - "psrlq $32,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqd %%mm6,%%mm2\n" - "pcmpeqd %%mm6,%%mm4\n" - "pcmpeqd (%2),%%mm3\n" - "pcmpeqd (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqd %%mm1,%%mm2\n" - "pcmpeqd %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpckldq %%mm4,%%mm2\n" - "punpckhdq %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - -/* central runs */ - "shrl $1,%4\n" - "jz 1f\n" - - "0:\n" - - /* set the current, current_pre, current_next registers */ - "movq -8(%1),%%mm0\n" - "movq (%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psrlq $32,%%mm0\n" - "psllq $32,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $32,%%mm2\n" - "psrlq $32,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqd %%mm6,%%mm2\n" - "pcmpeqd %%mm6,%%mm4\n" - "pcmpeqd (%2),%%mm3\n" - "pcmpeqd (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqd %%mm1,%%mm2\n" - "pcmpeqd %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpckldq %%mm4,%%mm2\n" - "punpckhdq %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - - "decl %4\n" - "jnz 0b\n" - "1:\n" - -/* final run */ - /* set the current, current_pre, current_next registers */ - "movq (%1),%%mm1\n" - "movq (%1),%%mm7\n" - "movq -8(%1),%%mm0\n" - "psrlq $32,%%mm1\n" - "psrlq $32,%%mm0\n" - "psllq $32,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $32,%%mm2\n" - "psrlq $32,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqd %%mm6,%%mm2\n" - "pcmpeqd %%mm6,%%mm4\n" - "pcmpeqd (%2),%%mm3\n" - "pcmpeqd (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqd %%mm1,%%mm2\n" - "pcmpeqd %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpckldq %%mm4,%%mm2\n" - "punpckhdq %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) - : - : "cc" - ); -} - -/** - * Scale by a factor of 2 a row of pixels of 8 bits. - * This is a very fast MMX implementation. - * The implementation uses a combination of cmp/and/not operations to - * completly remove the need of conditional jumps. This trick give the - * major speed improvement. - * Also, using the 8 bytes MMX registers more than one pixel are computed - * at the same time. - * Before calling this function you must ensure that the currenct CPU supports - * the MMX instruction set. After calling it you must be sure to call the EMMS - * instruction before any floating-point operation. - * The pixels over the left and right borders are assumed of the same color of - * the pixels on the border. - * \param src0 Pointer at the first pixel of the previous row. - * \param src1 Pointer at the first pixel of the current row. - * \param src2 Pointer at the first pixel of the next row. - * \param count Length in pixels of the src0, src1 and src2 rows. It must - * be at least 16 and a multiple of 8. - * \param dst0 First destination row, double length in pixels. - * \param dst1 Second destination row, double length in pixels. - */ -static void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) -{ - assert(count >= 16); - assert(count % 8 == 0); - - scale2x_8_mmx_single(dst0, src0, src1, src2, count); - scale2x_8_mmx_single(dst1, src2, src1, src0, count); -} - -/** - * Scale by a factor of 2 a row of pixels of 16 bits. - * This function operates like scale2x_8_mmx() but for 16 bits pixels. - * \param src0 Pointer at the first pixel of the previous row. - * \param src1 Pointer at the first pixel of the current row. - * \param src2 Pointer at the first pixel of the next row. - * \param count Length in pixels of the src0, src1 and src2 rows. It must - * be at least 8 and a multiple of 4. - * \param dst0 First destination row, double length in pixels. - * \param dst1 Second destination row, double length in pixels. - */ -static void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) -{ - assert(count >= 8); - assert(count % 4 == 0); - - scale2x_16_mmx_single(dst0, src0, src1, src2, count); - scale2x_16_mmx_single(dst1, src2, src1, src0, count); -} - -/** - * Scale by a factor of 2 a row of pixels of 32 bits. - * This function operates like scale2x_8_mmx() but for 32 bits pixels. - * \param src0 Pointer at the first pixel of the previous row. - * \param src1 Pointer at the first pixel of the current row. - * \param src2 Pointer at the first pixel of the next row. - * \param count Length in pixels of the src0, src1 and src2 rows. It must - * be at least 4 and a multiple of 2. - * \param dst0 First destination row, double length in pixels. - * \param dst1 Second destination row, double length in pixels. - */ -static void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) -{ - assert(count >= 4); - assert(count % 2 == 0); - - scale2x_32_mmx_single(dst0, src0, src1, src2, count); - scale2x_32_mmx_single(dst1, src2, src1, src0, count); -} - -#endif -#endif - -#endif +/* + * This file is part of the Scale2x project. + * + * Copyright (C) 2001-2002 Andrea Mazzoleni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Modifications for Sarien by Claudio Matsuoka, Sun Jul 13 16:33:48 BRT 2003 + * (while listening to The Utterly Fantastic and Totally Unbelievable Sounds of + * Los Straitjackets) + * + * - added scale2x_*_map() functions + * - source is always (uint8 *) + * - handle count < 2 instead of assert + * - mmx functions commented out + */ + +/* + * This file contains a C and MMX implentation of the Scale2x effect. + * + * You can found an high level description of the effect at : + * + * http://scale2x.sourceforge.net/scale2x.html + * + * Alternatively at the previous license terms, you are allowed to use this + * code in your program with these conditions: + * - the program is not used in commercial activities. + * - the whole source code of the program is released with the binary. + * - derivative works of the program are allowed. + */ + +#ifndef __SCALE2X_H +#define __SCALE2X_H + +/* #include */ + +/***************************************************************************/ +/* basic types */ + +typedef unsigned char scale2x_uint8; +typedef unsigned short scale2x_uint16; +typedef unsigned scale2x_uint32; + +/***************************************************************************/ +/* internal_scale2x */ + +#define scale2x_8_map(d1,d2,s1,s2,s3,m,c) scale2x_8_def(d1,d2,s1,s2,s3,c) + +/** + * Scale by a factor of 2 a row of pixels of 8 bits. + * The function is implemented in C. + * The pixels over the left and right borders are assumed of the same color of + * the pixels on the border. + * \param src0 Pointer at the first pixel of the previous row. + * \param src1 Pointer at the first pixel of the current row. + * \param src2 Pointer at the first pixel of the next row. + * \param count Length in pixels of the src0, src1 and src2 rows. + * It must be at least 2. + * \param dst0 First destination row, double length in pixels. + * \param dst1 Second destination row, double length in pixels. + */ +static INLINE void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ + /* assert(count >= 2); */ + if (count < 1) + return; + + /* first pixel */ + dst0[0] = src1[0]; + dst1[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] = src0[0]; + else + dst0[1] = src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] = src2[0]; + else + dst1[1] = src1[0]; + + if (count < 2) + return; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] = src0[0]; + else + dst0[1] = src1[0]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] = src2[0]; + else + dst1[0] = src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] = src2[0]; + else + dst1[1] = src1[0]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] = src2[0]; + else + dst1[0] = src1[0]; + dst0[1] = src1[0]; + dst1[1] = src1[0]; +} + +/** + * Scale by a factor of 2 a row of pixels of 16 bits. + * This function operates like scale2x_8_def() but for 16 bits pixels. + * \param src0 Pointer at the first pixel of the previous row. + * \param src1 Pointer at the first pixel of the current row. + * \param src2 Pointer at the first pixel of the next row. + * \param count Length in pixels of the src0, src1 and src2 rows. + * It must be at least 2. + * \param dst0 First destination row, double length in pixels. + * \param dst1 Second destination row, double length in pixels. + */ +static INLINE void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ + /*assert(count >= 2);*/ + if (count < 1) + return; + + /* first pixel */ + dst0[0] = src1[0]; + dst1[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] =src0[0]; + else + dst0[1] =src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] =src2[0]; + else + dst1[1] =src1[0]; + + if (count < 2) + return; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] =src0[0]; + else + dst0[1] =src1[0]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] =src2[0]; + else + dst1[0] =src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] =src2[0]; + else + dst1[1] =src1[0]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] =src0[0]; + else + dst0[0] =src1[0]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] =src2[0]; + else + dst1[0] =src1[0]; + dst0[1] =src1[0]; + dst1[1] =src1[0]; +} + +static INLINE void scale2x_16_map(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, const scale2x_uint32 *map, unsigned count) +{ + /*assert(count >= 2);*/ + if (count < 1) + return; + + /* first pixel */ + dst0[0] = map[src1[0]]; + dst1[0] = map[src1[0]]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] = map[src0[0]]; + else + dst0[1] = map[src1[0]]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] = map[src2[0]]; + else + dst1[1] = map[src1[0]]; + + if (count < 2) + return; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = map[src0[0]]; + else + dst0[0] = map[src1[0]]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] = map[src0[0]]; + else + dst0[1] = map[src1[0]]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] = map[src2[0]]; + else + dst1[0] = map[src1[0]]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] = map[src2[0]]; + else + dst1[1] = map[src1[0]]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] = map[src0[0]]; + else + dst0[0] = map[src1[0]]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] = map[src2[0]]; + else + dst1[0] = map[src1[0]]; + dst0[1] = map[src1[0]]; + dst1[1] = map[src1[0]]; +} + +/** + * Scale by a factor of 2 a row of pixels of 32 bits. + * This function operates like scale2x_8_def() but for 32 bits pixels. + * \param src0 Pointer at the first pixel of the previous row. + * \param src1 Pointer at the first pixel of the current row. + * \param src2 Pointer at the first pixel of the next row. + * \param count Length in pixels of the src0, src1 and src2 rows. + * It must be at least 2. + * \param dst0 First destination row, double length in pixels. + * \param dst1 Second destination row, double length in pixels. + */ + +static INLINE void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +{ + /* assert(count >= 2); */ + if (count < 1) + return; + + /* first pixel */ + dst0[0] = src1[0]; + dst1[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] = src0[0]; + else + dst0[1] = src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] = src2[0]; + else + dst1[1] = src1[0]; + + if (count < 2) + return; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] = src0[0]; + else + dst0[1] = src1[0]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] = src2[0]; + else + dst1[0] = src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] = src2[0]; + else + dst1[1] = src1[0]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] = src2[0]; + else + dst1[0] = src1[0]; + dst0[1] = src1[0]; + dst1[1] = src1[0]; +} + +static INLINE void scale2x_32_map(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, const scale2x_uint32* map, unsigned count) +{ + /* assert(count >= 2); */ + if (count < 1) + return; + + /* first pixel */ + dst0[0] = map[src1[0]]; + dst1[0] = map[src1[0]]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] = map[src0[0]]; + else + dst0[1] = map[src1[0]]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] = map[src2[0]]; + else + dst1[1] = map[src1[0]]; + + if (count < 2) + return; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = map[src0[0]]; + else + dst0[0] = map[src1[0]]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] = map[src0[0]]; + else + dst0[1] = map[src1[0]]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] = map[src2[0]]; + else + dst1[0] = map[src1[0]]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] = map[src2[0]]; + else + dst1[1] = map[src1[0]]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] = map[src0[0]]; + else + dst0[0] = map[src1[0]]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] = map[src2[0]]; + else + dst1[0] = map[src1[0]]; + dst0[1] = map[src1[0]]; + dst1[1] = map[src1[0]]; +} + +#if 0 +#if defined(__GNUC__) && defined(__i386__) + +/* + * Apply the Scale2x effect at a single row. + * This function must be called only by the other scale2x functions. + * + * Considering the pixel map : + * + * ABC (src0) + * DEF (src1) + * GHI (src2) + * + * this functions compute 2 new pixels in substitution of the source pixel E + * like this map : + * + * ab (dst) + * + * with these variables : + * + * ¤t -> E + * ¤t_left -> D + * ¤t_right -> F + * ¤t_upper -> B + * ¤t_lower -> H + * + * %0 -> current_upper + * %1 -> current + * %2 -> current_lower + * %3 -> dst + * %4 -> counter + * + * %mm0 -> *current_left + * %mm1 -> *current_next + * %mm2 -> tmp0 + * %mm3 -> tmp1 + * %mm4 -> tmp2 + * %mm5 -> tmp3 + * %mm6 -> *current_upper + * %mm7 -> *current + */ +static __inline__ void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ + assert(count >= 16); + assert(count % 8 == 0); + + /* always do the first and last run */ + count -= 2*8; + + __asm__ __volatile__( +/* first run */ + /* set the current, current_pre, current_next registers */ + "movq 0(%1),%%mm0\n" + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psllq $56,%%mm0\n" + "psllq $56,%%mm1\n" + "psrlq $56,%%mm0\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $8,%%mm2\n" + "psrlq $8,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqb %%mm6,%%mm2\n" + "pcmpeqb %%mm6,%%mm4\n" + "pcmpeqb (%2),%%mm3\n" + "pcmpeqb (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqb %%mm1,%%mm2\n" + "pcmpeqb %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklbw %%mm4,%%mm2\n" + "punpckhbw %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + +/* central runs */ + "shrl $3,%4\n" + "jz 1f\n" + + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $56,%%mm0\n" + "psllq $56,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $8,%%mm2\n" + "psrlq $8,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqb %%mm6,%%mm2\n" + "pcmpeqb %%mm6,%%mm4\n" + "pcmpeqb (%2),%%mm3\n" + "pcmpeqb (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqb %%mm1,%%mm2\n" + "pcmpeqb %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklbw %%mm4,%%mm2\n" + "punpckhbw %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + +/* final run */ + /* set the current, current_pre, current_next registers */ + "movq (%1),%%mm1\n" + "movq (%1),%%mm7\n" + "movq -8(%1),%%mm0\n" + "psrlq $56,%%mm1\n" + "psrlq $56,%%mm0\n" + "psllq $56,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $8,%%mm2\n" + "psrlq $8,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqb %%mm6,%%mm2\n" + "pcmpeqb %%mm6,%%mm4\n" + "pcmpeqb (%2),%%mm3\n" + "pcmpeqb (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqb %%mm1,%%mm2\n" + "pcmpeqb %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklbw %%mm4,%%mm2\n" + "punpckhbw %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +} + +static __inline__ void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +{ + assert(count >= 8); + assert(count % 4 == 0); + + /* always do the first and last run */ + count -= 2*4; + + __asm__ __volatile__( +/* first run */ + /* set the current, current_pre, current_next registers */ + "movq 0(%1),%%mm0\n" + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psllq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "psrlq $48,%%mm0\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + +/* central runs */ + "shrl $2,%4\n" + "jz 1f\n" + + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + +/* final run */ + /* set the current, current_pre, current_next registers */ + "movq (%1),%%mm1\n" + "movq (%1),%%mm7\n" + "movq -8(%1),%%mm0\n" + "psrlq $48,%%mm1\n" + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +} + +static __inline__ void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +{ + assert(count >= 4); + assert(count % 2 == 0); + + /* always do the first and last run */ + count -= 2*2; + + __asm__ __volatile__( +/* first run */ + /* set the current, current_pre, current_next registers */ + "movq 0(%1),%%mm0\n" + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psllq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "psrlq $32,%%mm0\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + +/* central runs */ + "shrl $1,%4\n" + "jz 1f\n" + + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + +/* final run */ + /* set the current, current_pre, current_next registers */ + "movq (%1),%%mm1\n" + "movq (%1),%%mm7\n" + "movq -8(%1),%%mm0\n" + "psrlq $32,%%mm1\n" + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +} + +/** + * Scale by a factor of 2 a row of pixels of 8 bits. + * This is a very fast MMX implementation. + * The implementation uses a combination of cmp/and/not operations to + * completly remove the need of conditional jumps. This trick give the + * major speed improvement. + * Also, using the 8 bytes MMX registers more than one pixel are computed + * at the same time. + * Before calling this function you must ensure that the currenct CPU supports + * the MMX instruction set. After calling it you must be sure to call the EMMS + * instruction before any floating-point operation. + * The pixels over the left and right borders are assumed of the same color of + * the pixels on the border. + * \param src0 Pointer at the first pixel of the previous row. + * \param src1 Pointer at the first pixel of the current row. + * \param src2 Pointer at the first pixel of the next row. + * \param count Length in pixels of the src0, src1 and src2 rows. It must + * be at least 16 and a multiple of 8. + * \param dst0 First destination row, double length in pixels. + * \param dst1 Second destination row, double length in pixels. + */ +static void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ + assert(count >= 16); + assert(count % 8 == 0); + + scale2x_8_mmx_single(dst0, src0, src1, src2, count); + scale2x_8_mmx_single(dst1, src2, src1, src0, count); +} + +/** + * Scale by a factor of 2 a row of pixels of 16 bits. + * This function operates like scale2x_8_mmx() but for 16 bits pixels. + * \param src0 Pointer at the first pixel of the previous row. + * \param src1 Pointer at the first pixel of the current row. + * \param src2 Pointer at the first pixel of the next row. + * \param count Length in pixels of the src0, src1 and src2 rows. It must + * be at least 8 and a multiple of 4. + * \param dst0 First destination row, double length in pixels. + * \param dst1 Second destination row, double length in pixels. + */ +static void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +{ + assert(count >= 8); + assert(count % 4 == 0); + + scale2x_16_mmx_single(dst0, src0, src1, src2, count); + scale2x_16_mmx_single(dst1, src2, src1, src0, count); +} + +/** + * Scale by a factor of 2 a row of pixels of 32 bits. + * This function operates like scale2x_8_mmx() but for 32 bits pixels. + * \param src0 Pointer at the first pixel of the previous row. + * \param src1 Pointer at the first pixel of the current row. + * \param src2 Pointer at the first pixel of the next row. + * \param count Length in pixels of the src0, src1 and src2 rows. It must + * be at least 4 and a multiple of 2. + * \param dst0 First destination row, double length in pixels. + * \param dst1 Second destination row, double length in pixels. + */ +static void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +{ + assert(count >= 4); + assert(count % 2 == 0); + + scale2x_32_mmx_single(dst0, src0, src1, src2, count); + scale2x_32_mmx_single(dst1, src2, src1, src0, count); +} + +#endif +#endif + +#endif diff --git a/include/sound.h b/include/sound.h index 4d5463f..8026713 100644 --- a/include/sound.h +++ b/include/sound.h @@ -1,111 +1,111 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: sound.h,v 1.10 2001/09/14 12:15:51 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_SOUND_H -#define __AGI_SOUND_H - -#ifdef __cplusplus -extern "C"{ -#endif - -#define BUFFER_SIZE 410 - -#define SOUND_EMU_NONE 0 -#define SOUND_EMU_PC 1 -#define SOUND_EMU_TANDY 2 -#define SOUND_EMU_MAC 3 -#define SOUND_EMU_AMIGA 4 - -#define SOUND_PLAYING 0x01 -#define WAVEFORM_SIZE 64 -#define ENV_ATTACK 10000 /**< envelope attack rate */ -#define ENV_DECAY 1000 /**< envelope decay rate */ -#define ENV_SUSTAIN 100 /**< envelope sustain level */ -#define ENV_RELEASE 7500 /**< envelope release rate */ -#define NUM_CHANNELS 7 /**< number of sound channels */ - -/** - * Sarien sound driver structure. - */ -struct sound_driver { - char *description; - int (*init)(SINT16 *buffer); - void (*deinit)(void); -}; - -/** - * AGI sound resource structure. - */ -struct agi_sound { - UINT32 flen; /**< size of raw data */ - UINT8 *rdata; /**< raw sound data */ - UINT8 flags; /**< sound flags */ - UINT16 type; /**< sound resource type */ -}; - -/** - * AGI sound note structure. - */ -struct agi_note { - UINT8 dur_lo; /**< LSB of note duration */ - UINT8 dur_hi; /**< MSB of note duration */ - UINT8 frq_0; /**< LSB of note frequency */ - UINT8 frq_1; /**< MSB of note frequency */ - UINT8 vol; /**< note volume */ -}; - -/** - * Sarien sound channel structure. - */ -struct channel_info { -#define AGI_SOUND_SAMPLE 0x0001 -#define AGI_SOUND_MIDI 0x0002 -#define AGI_SOUND_4CHN 0x0008 - UINT32 type; - struct agi_note *ptr; -#ifdef USE_PCM_SOUND - SINT16 *ins; - SINT32 size; - UINT32 phase; -#endif -#define AGI_SOUND_LOOP 0x0001 -#define AGI_SOUND_ENVELOPE 0x0002 - UINT32 flags; -#define AGI_SOUND_ENV_ATTACK 3 -#define AGI_SOUND_ENV_DECAY 2 -#define AGI_SOUND_ENV_SUSTAIN 1 -#define AGI_SOUND_ENV_RELEASE 0 - UINT32 adsr; - SINT32 timer; - UINT32 end; - UINT32 freq; - UINT32 vol; - UINT32 env; -}; - -void decode_sound (int); -void unload_sound (int); -void play_sound (void); -int init_sound (void); -void deinit_sound (void); -void start_sound (int, int); -void stop_sound (void); -UINT32 mix_sound (void); -void __init_sound (void); -int load_instruments (char *fname); - -extern struct sound_driver *snd; - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_SOUND_H */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: sound.h,v 1.10 2001/09/14 12:15:51 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_SOUND_H +#define __AGI_SOUND_H + +#ifdef __cplusplus +extern "C"{ +#endif + +#define BUFFER_SIZE 410 + +#define SOUND_EMU_NONE 0 +#define SOUND_EMU_PC 1 +#define SOUND_EMU_TANDY 2 +#define SOUND_EMU_MAC 3 +#define SOUND_EMU_AMIGA 4 + +#define SOUND_PLAYING 0x01 +#define WAVEFORM_SIZE 64 +#define ENV_ATTACK 10000 /**< envelope attack rate */ +#define ENV_DECAY 1000 /**< envelope decay rate */ +#define ENV_SUSTAIN 100 /**< envelope sustain level */ +#define ENV_RELEASE 7500 /**< envelope release rate */ +#define NUM_CHANNELS 7 /**< number of sound channels */ + +/** + * Sarien sound driver structure. + */ +struct sound_driver { + char *description; + int (*init)(SINT16 *buffer); + void (*deinit)(void); +}; + +/** + * AGI sound resource structure. + */ +struct agi_sound { + UINT32 flen; /**< size of raw data */ + UINT8 *rdata; /**< raw sound data */ + UINT8 flags; /**< sound flags */ + UINT16 type; /**< sound resource type */ +}; + +/** + * AGI sound note structure. + */ +struct agi_note { + UINT8 dur_lo; /**< LSB of note duration */ + UINT8 dur_hi; /**< MSB of note duration */ + UINT8 frq_0; /**< LSB of note frequency */ + UINT8 frq_1; /**< MSB of note frequency */ + UINT8 vol; /**< note volume */ +}; + +/** + * Sarien sound channel structure. + */ +struct channel_info { +#define AGI_SOUND_SAMPLE 0x0001 +#define AGI_SOUND_MIDI 0x0002 +#define AGI_SOUND_4CHN 0x0008 + UINT32 type; + struct agi_note *ptr; +#ifdef USE_PCM_SOUND + SINT16 *ins; + SINT32 size; + UINT32 phase; +#endif +#define AGI_SOUND_LOOP 0x0001 +#define AGI_SOUND_ENVELOPE 0x0002 + UINT32 flags; +#define AGI_SOUND_ENV_ATTACK 3 +#define AGI_SOUND_ENV_DECAY 2 +#define AGI_SOUND_ENV_SUSTAIN 1 +#define AGI_SOUND_ENV_RELEASE 0 + UINT32 adsr; + SINT32 timer; + UINT32 end; + UINT32 freq; + UINT32 vol; + UINT32 env; +}; + +void decode_sound (int); +void unload_sound (int); +void play_sound (void); +int init_sound (void); +void deinit_sound (void); +void start_sound (int, int); +void stop_sound (void); +UINT32 mix_sound (void); +void __init_sound (void); +int load_instruments (char *fname); + +extern struct sound_driver *snd; + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_SOUND_H */ + diff --git a/include/sprite.h b/include/sprite.h index 2a8fe1b..cb493c7 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -1,37 +1,37 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: sprite.h,v 1.8 2002/04/06 04:13:07 vasyl Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_SPRITE_H -#define __AGI_SPRITE_H - -#ifdef __cplusplus -extern "C"{ -#endif - -int init_sprites (void); -void deinit_sprites (void); -void erase_upd_sprites (void); -void erase_nonupd_sprites (void); -void erase_both (void); -void blit_upd_sprites (void); -void blit_nonupd_sprites (void); -void blit_both (void); -void commit_upd_sprites (void); -void commit_nonupd_sprites (void); -void commit_both (void); -void add_to_pic (int, int, int, int, int, int, int); -void show_obj (int); -void commit_block (int, int, int, int); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_SPRITE_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: sprite.h,v 1.8 2002/04/06 04:13:07 vasyl Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_SPRITE_H +#define __AGI_SPRITE_H + +#ifdef __cplusplus +extern "C"{ +#endif + +int init_sprites (void); +void deinit_sprites (void); +void erase_upd_sprites (void); +void erase_nonupd_sprites (void); +void erase_both (void); +void blit_upd_sprites (void); +void blit_nonupd_sprites (void); +void blit_both (void); +void commit_upd_sprites (void); +void commit_nonupd_sprites (void); +void commit_both (void); +void add_to_pic (int, int, int, int, int, int, int); +void show_obj (int); +void commit_block (int, int, int, int); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_SPRITE_H */ diff --git a/include/text.h b/include/text.h index 7131a49..0e29daa 100644 --- a/include/text.h +++ b/include/text.h @@ -1,37 +1,37 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: text.h,v 1.17 2002/11/10 13:36:26 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_TEXT_H -#define __AGI_TEXT_H - -#ifdef __cplusplus -extern "C"{ -#endif - -int message_box (char *); -int selection_box (char *, char **); -void close_window (void); -void draw_window (int, int, int, int); -void print_text (char *, int, int, int, int, int, int); -void print_text_console - (char *, int, int, int, int, int); -int print (char *, int, int, int); -char *word_wrap_string (char *, int *); -char *agi_sprintf (char *); -void write_status (void); -void write_prompt (void); -void clear_lines (int, int, int); -void flush_lines (int, int); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_TEXT_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: text.h,v 1.17 2002/11/10 13:36:26 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_TEXT_H +#define __AGI_TEXT_H + +#ifdef __cplusplus +extern "C"{ +#endif + +int message_box (char *); +int selection_box (char *, char **); +void close_window (void); +void draw_window (int, int, int, int); +void print_text (char *, int, int, int, int, int, int); +void print_text_console + (char *, int, int, int, int, int); +int print (char *, int, int, int); +char *word_wrap_string (char *, int *); +char *agi_sprintf (char *); +void write_status (void); +void write_prompt (void); +void clear_lines (int, int, int); +void flush_lines (int, int); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_TEXT_H */ diff --git a/include/view.h b/include/view.h index 096c054..8b3bb85 100644 --- a/include/view.h +++ b/include/view.h @@ -1,137 +1,137 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: view.h,v 1.11 2001/08/05 16:02:48 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef __AGI_VIEW_H -#define __AGI_VIEW_H - -#ifdef __cplusplus -extern "C"{ -#endif - -struct view_cel { - UINT8 height; - UINT8 width; - UINT8 transparency; - UINT8 mirror_loop; - UINT8 mirror; - UINT8 *data; -}; - -struct view_loop { - int num_cels; - struct view_cel *cel; -}; - -/** - * AGI view resource structure. - */ -struct agi_view { - int num_loops; - struct view_loop *loop; - char *descr; - UINT8 *rdata; -}; - -/** - * AGI view table entry - */ -struct vt_entry { - UINT8 step_time; - UINT8 step_time_count; - UINT8 entry; - SINT16 x_pos; - SINT16 y_pos; - UINT8 current_view; - struct agi_view *view_data; - UINT8 current_loop; - UINT8 num_loops; - struct view_loop *loop_data; - UINT8 current_cel; - UINT8 num_cels; - struct view_cel *cel_data; - struct view_cel *cel_data_2; - SINT16 x_pos2; - SINT16 y_pos2; - void *s; - SINT16 x_size; - SINT16 y_size; - UINT8 step_size; - UINT8 cycle_time; - UINT8 cycle_time_count; - UINT8 direction; - -#define MOTION_NORMAL 0 -#define MOTION_WANDER 1 -#define MOTION_FOLLOW_EGO 2 -#define MOTION_MOVE_OBJ 3 - UINT8 motion; - -#define CYCLE_NORMAL 0 -#define CYCLE_END_OF_LOOP 1 -#define CYCLE_REV_LOOP 2 -#define CYCLE_REVERSE 3 - UINT8 cycle; - - UINT8 priority; - -#define DRAWN 0x0001 -#define IGNORE_BLOCKS 0x0002 -#define FIXED_PRIORITY 0x0004 -#define IGNORE_HORIZON 0x0008 -#define UPDATE 0x0010 -#define CYCLING 0x0020 -#define ANIMATED 0x0040 -#define MOTION 0x0080 -#define ON_WATER 0x0100 -#define IGNORE_OBJECTS 0x0200 -#define UPDATE_POS 0x0400 -#define ON_LAND 0x0800 -#define DONTUPDATE 0x1000 -#define FIX_LOOP 0x2000 -#define DIDNT_MOVE 0x4000 -#define ADJ_EGO_XY 0x8000 - UINT16 flags; - - UINT8 parm1; - UINT8 parm2; - UINT8 parm3; - UINT8 parm4; -}; /* struct vt_entry */ - -#define for_each_vt_entry(x) \ - for (x = game.view_table; (x) < &game.view_table[MAX_VIEWTABLE]; (x)++) -#define if_is_ego_view(x) \ - if ((x) == game.view_table) - -/* Motion */ -void check_all_motions (void); -void move_obj (struct vt_entry *); -void in_destination (struct vt_entry *); -void fix_position (int); -void update_position (void); - -/* View table management */ -void set_cel (struct vt_entry *, int); -void set_loop (struct vt_entry *, int); -void set_view (struct vt_entry *, int); -void start_update (struct vt_entry *); -void stop_update (struct vt_entry *); -void update_viewtable(void); - -void unload_view (int); -int decode_view (int); -void add_to_pic (int, int, int, int, int, int, int); -void draw_obj (int); - -#ifdef __cplusplus -}; -#endif - -#endif /* __AGI_VIEW_H */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: view.h,v 1.11 2001/08/05 16:02:48 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef __AGI_VIEW_H +#define __AGI_VIEW_H + +#ifdef __cplusplus +extern "C"{ +#endif + +struct view_cel { + UINT8 height; + UINT8 width; + UINT8 transparency; + UINT8 mirror_loop; + UINT8 mirror; + UINT8 *data; +}; + +struct view_loop { + int num_cels; + struct view_cel *cel; +}; + +/** + * AGI view resource structure. + */ +struct agi_view { + int num_loops; + struct view_loop *loop; + char *descr; + UINT8 *rdata; +}; + +/** + * AGI view table entry + */ +struct vt_entry { + UINT8 step_time; + UINT8 step_time_count; + UINT8 entry; + SINT16 x_pos; + SINT16 y_pos; + UINT8 current_view; + struct agi_view *view_data; + UINT8 current_loop; + UINT8 num_loops; + struct view_loop *loop_data; + UINT8 current_cel; + UINT8 num_cels; + struct view_cel *cel_data; + struct view_cel *cel_data_2; + SINT16 x_pos2; + SINT16 y_pos2; + void *s; + SINT16 x_size; + SINT16 y_size; + UINT8 step_size; + UINT8 cycle_time; + UINT8 cycle_time_count; + UINT8 direction; + +#define MOTION_NORMAL 0 +#define MOTION_WANDER 1 +#define MOTION_FOLLOW_EGO 2 +#define MOTION_MOVE_OBJ 3 + UINT8 motion; + +#define CYCLE_NORMAL 0 +#define CYCLE_END_OF_LOOP 1 +#define CYCLE_REV_LOOP 2 +#define CYCLE_REVERSE 3 + UINT8 cycle; + + UINT8 priority; + +#define DRAWN 0x0001 +#define IGNORE_BLOCKS 0x0002 +#define FIXED_PRIORITY 0x0004 +#define IGNORE_HORIZON 0x0008 +#define UPDATE 0x0010 +#define CYCLING 0x0020 +#define ANIMATED 0x0040 +#define MOTION 0x0080 +#define ON_WATER 0x0100 +#define IGNORE_OBJECTS 0x0200 +#define UPDATE_POS 0x0400 +#define ON_LAND 0x0800 +#define DONTUPDATE 0x1000 +#define FIX_LOOP 0x2000 +#define DIDNT_MOVE 0x4000 +#define ADJ_EGO_XY 0x8000 + UINT16 flags; + + UINT8 parm1; + UINT8 parm2; + UINT8 parm3; + UINT8 parm4; +}; /* struct vt_entry */ + +#define for_each_vt_entry(x) \ + for (x = game.view_table; (x) < &game.view_table[MAX_VIEWTABLE]; (x)++) +#define if_is_ego_view(x) \ + if ((x) == game.view_table) + +/* Motion */ +void check_all_motions (void); +void move_obj (struct vt_entry *); +void in_destination (struct vt_entry *); +void fix_position (int); +void update_position (void); + +/* View table management */ +void set_cel (struct vt_entry *, int); +void set_loop (struct vt_entry *, int); +void set_view (struct vt_entry *, int); +void start_update (struct vt_entry *); +void stop_update (struct vt_entry *); +void update_viewtable(void); + +void unload_view (int); +int decode_view (int); +void add_to_pic (int, int, int, int, int, int, int); +void draw_obj (int); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AGI_VIEW_H */ diff --git a/inv.c b/inv.c index ee32b07..1cf20bc 100644 --- a/inv.c +++ b/inv.c @@ -1,205 +1,205 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: inv.c,v 1.35 2002/03/30 13:34:15 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include - -#include "sarien.h" -#include "agi.h" -#include "sprite.h" -#include "graphics.h" -#include "keyboard.h" -#include "text.h" -#include "keyboard.h" - - -/* - * Messages and coordinates - */ - -#define NOTHING_X 16 -#define NOTHING_Y 3 -#define NOTHING_MSG "nothing" - -#define ANY_KEY_X 4 -#define ANY_KEY_Y 24 -#define ANY_KEY_MSG "Press a key to return to the game" - -#define YOUHAVE_X 11 -#define YOUHAVE_Y 0 -#define YOUHAVE_MSG "You are carrying:" - -#define SELECT_X 2 -#define SELECT_Y 24 -#define SELECT_MSG "Press ENTER to select, ESC to cancel" - - -static UINT8 *intobj = NULL; - - - -static void print_item (int n, int fg, int bg) -{ - print_text (object_name (intobj[n]), 0, - n % 2 ? 39 - strlen (object_name (intobj[n])) : 1, - (n / 2) + 2, 40, fg, bg); -} - -#ifdef USE_MOUSE -static int find_item () -{ - int r, c; - - r = mouse.y / CHAR_LINES; - c = mouse.x / CHAR_COLS; - - _D (_D_WARN "r = %d, c = %d", r, c); - - if (r < 2) - return -1; - - return (r - 2) * 2 + (c > 20); -} -#endif - -static int show_items () -{ - unsigned int x, i; - - for (x = i = 0; x < game.num_objects; x++) { - if (object_get_location (x) == EGO_OWNED) { - /* add object to our list! */ - intobj[i] = x; - print_item (i, STATUS_FG, STATUS_BG); - i++; - } - } - - if (i == 0) { - print_text (NOTHING_MSG, 0, NOTHING_X, NOTHING_Y, 40, - STATUS_FG, STATUS_BG); - } - - return i; -} - -static void select_items (int n) -{ - int fsel = 0; - - while (42) { - if (n > 0) - print_item (fsel, STATUS_BG, STATUS_FG); - - switch (wait_any_key ()) { - case KEY_ENTER: - setvar (V_sel_item, intobj[fsel]); - goto exit_select; - case KEY_ESCAPE: - setvar (V_sel_item, 0xff); - goto exit_select; - case KEY_UP: - if (fsel >= 2) fsel -= 2; - break; - case KEY_DOWN: - if (fsel + 2 < n) fsel += 2; - break; - case KEY_LEFT: - if (fsel % 2 == 1) fsel--; - break; - case KEY_RIGHT: - if (fsel % 2 == 0 && fsel + 1 < n) fsel++; - break; -#ifdef USE_MOUSE - case BUTTON_LEFT: { - int i = find_item (); - if (i >= 0 && i < n) { - setvar (V_sel_item, intobj[fsel = i]); - _D (_D_WARN "item found: %d", fsel); - show_items (); - print_item (fsel, STATUS_BG, STATUS_FG); - do_update (); - goto exit_select; - } - break; } -#endif - default: - break; - } - - show_items (); - do_update (); - } -exit_select: - _D ("selected: %d", fsel); -} - -/* - * Public functions - */ - -/** - * Display inventory items. - */ -void inventory () -{ - int old_fg, old_bg; - int n; - - /* screen is white with black text */ - old_fg = game.color_fg; - old_bg = game.color_bg; - game.color_fg = 0; - game.color_bg = 15; - clear_screen (game.color_bg); - - print_text (YOUHAVE_MSG, 0, YOUHAVE_X, YOUHAVE_Y, 40, - STATUS_FG, STATUS_BG); - - /* FIXME: doesn't check if objects overflow off screen... */ - - intobj = malloc (4 + game.num_objects); - memset(intobj, 0, (4 + game.num_objects)); - - n = show_items (); - - if (getflag (F_status_selects_items)) { - print_text (SELECT_MSG, 0, SELECT_X, SELECT_Y, 40, - STATUS_FG, STATUS_BG); - } else { - print_text (ANY_KEY_MSG, 0, ANY_KEY_X, ANY_KEY_Y, 40, - STATUS_FG, STATUS_BG); - } - - flush_screen (); - - /* If flag 13 is set, we want to highlight & select an item. - * opon selection, put objnum in var 25. Then on esc put in - * var 25 = 0xff. - */ - - if (getflag (F_status_selects_items)) - select_items (n); - - free (intobj); - - if (!getflag (F_status_selects_items)) - wait_any_key(); - - clear_screen (0); - write_status (); - show_pic (); - game.color_fg = old_fg; - game.color_bg = old_bg; - game.has_prompt = 0; - flush_lines (game.line_user_input, 24); -} - - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: inv.c,v 1.35 2002/03/30 13:34:15 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include + +#include "sarien.h" +#include "agi.h" +#include "sprite.h" +#include "graphics.h" +#include "keyboard.h" +#include "text.h" +#include "keyboard.h" + + +/* + * Messages and coordinates + */ + +#define NOTHING_X 16 +#define NOTHING_Y 3 +#define NOTHING_MSG "nothing" + +#define ANY_KEY_X 4 +#define ANY_KEY_Y 24 +#define ANY_KEY_MSG "Press a key to return to the game" + +#define YOUHAVE_X 11 +#define YOUHAVE_Y 0 +#define YOUHAVE_MSG "You are carrying:" + +#define SELECT_X 2 +#define SELECT_Y 24 +#define SELECT_MSG "Press ENTER to select, ESC to cancel" + + +static UINT8 *intobj = NULL; + + + +static void print_item (int n, int fg, int bg) +{ + print_text (object_name (intobj[n]), 0, + n % 2 ? 39 - strlen (object_name (intobj[n])) : 1, + (n / 2) + 2, 40, fg, bg); +} + +#ifdef USE_MOUSE +static int find_item () +{ + int r, c; + + r = mouse.y / CHAR_LINES; + c = mouse.x / CHAR_COLS; + + _D (_D_WARN "r = %d, c = %d", r, c); + + if (r < 2) + return -1; + + return (r - 2) * 2 + (c > 20); +} +#endif + +static int show_items () +{ + unsigned int x, i; + + for (x = i = 0; x < game.num_objects; x++) { + if (object_get_location (x) == EGO_OWNED) { + /* add object to our list! */ + intobj[i] = x; + print_item (i, STATUS_FG, STATUS_BG); + i++; + } + } + + if (i == 0) { + print_text (NOTHING_MSG, 0, NOTHING_X, NOTHING_Y, 40, + STATUS_FG, STATUS_BG); + } + + return i; +} + +static void select_items (int n) +{ + int fsel = 0; + + while (42) { + if (n > 0) + print_item (fsel, STATUS_BG, STATUS_FG); + + switch (wait_any_key ()) { + case KEY_ENTER: + setvar (V_sel_item, intobj[fsel]); + goto exit_select; + case KEY_ESCAPE: + setvar (V_sel_item, 0xff); + goto exit_select; + case KEY_UP: + if (fsel >= 2) fsel -= 2; + break; + case KEY_DOWN: + if (fsel + 2 < n) fsel += 2; + break; + case KEY_LEFT: + if (fsel % 2 == 1) fsel--; + break; + case KEY_RIGHT: + if (fsel % 2 == 0 && fsel + 1 < n) fsel++; + break; +#ifdef USE_MOUSE + case BUTTON_LEFT: { + int i = find_item (); + if (i >= 0 && i < n) { + setvar (V_sel_item, intobj[fsel = i]); + _D (_D_WARN "item found: %d", fsel); + show_items (); + print_item (fsel, STATUS_BG, STATUS_FG); + do_update (); + goto exit_select; + } + break; } +#endif + default: + break; + } + + show_items (); + do_update (); + } +exit_select: + _D ("selected: %d", fsel); +} + +/* + * Public functions + */ + +/** + * Display inventory items. + */ +void inventory () +{ + int old_fg, old_bg; + int n; + + /* screen is white with black text */ + old_fg = game.color_fg; + old_bg = game.color_bg; + game.color_fg = 0; + game.color_bg = 15; + clear_screen (game.color_bg); + + print_text (YOUHAVE_MSG, 0, YOUHAVE_X, YOUHAVE_Y, 40, + STATUS_FG, STATUS_BG); + + /* FIXME: doesn't check if objects overflow off screen... */ + + intobj = malloc (4 + game.num_objects); + memset(intobj, 0, (4 + game.num_objects)); + + n = show_items (); + + if (getflag (F_status_selects_items)) { + print_text (SELECT_MSG, 0, SELECT_X, SELECT_Y, 40, + STATUS_FG, STATUS_BG); + } else { + print_text (ANY_KEY_MSG, 0, ANY_KEY_X, ANY_KEY_Y, 40, + STATUS_FG, STATUS_BG); + } + + flush_screen (); + + /* If flag 13 is set, we want to highlight & select an item. + * opon selection, put objnum in var 25. Then on esc put in + * var 25 = 0xff. + */ + + if (getflag (F_status_selects_items)) + select_items (n); + + free (intobj); + + if (!getflag (F_status_selects_items)) + wait_any_key(); + + clear_screen (0); + write_status (); + show_pic (); + game.color_fg = old_fg; + game.color_bg = old_bg; + game.has_prompt = 0; + flush_lines (game.line_user_input, 24); +} + + diff --git a/keyboard.c b/keyboard.c index 7d0c5a3..6e960e3 100644 --- a/keyboard.c +++ b/keyboard.c @@ -1,376 +1,376 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: keyboard.c,v 1.78 2003/07/16 18:32:05 bootstrap666 Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include - -#ifndef PALMOS -#include -#endif - -#include "sarien.h" -#include "agi.h" -#include "graphics.h" -#include "keyboard.h" -#include "menu.h" -#include "text.h" /* remove later */ - -char last_sentence[40]; - -#ifdef USE_CONSOLE -extern struct sarien_console console; -#endif - -/* FIXME */ -extern int open_dialogue; - -struct string_data { - int x; - int y; - int len; - int str; -}; - -struct string_data stringdata; - -/* - * IBM-PC keyboard scancodes - */ -UINT8 scancode_table[26] = { - 30, /* A */ - 48, /* B */ - 46, /* C */ - 32, /* D */ - 18, /* E */ - 33, /* F */ - 34, /* G */ - 35, /* H */ - 23, /* I */ - 36, /* J */ - 37, /* K */ - 38, /* L */ - 50, /* M */ - 49, /* N */ - 24, /* O */ - 25, /* P */ - 16, /* Q */ - 19, /* R */ - 31, /* S */ - 20, /* T */ - 22, /* U */ - 47, /* V */ - 17, /* W */ - 45, /* X */ - 21, /* Y */ - 44 /* Z */ -}; - - -void init_words () -{ - game.num_ego_words = 0; -} - - -void clean_input () -{ - while (game.num_ego_words) - free (game.ego_words[--game.num_ego_words].word); -} - - -void get_string (int x, int y, int len, int str) -{ - new_input_mode (INPUT_GETSTRING); - stringdata.x = x; - stringdata.y = y; - stringdata.len = len; - stringdata.str = str; -} - - -/** - * Raw key grabber. - * poll_keyboard() is the raw key grabber (above the gfx driver, that is). - * It handles console keys and insulates AGI from the console. In the main - * loop, handle_keys() handles keyboard input and ego movement. - */ -int do_poll_keyboard () -{ - int key = 0; - - /* If a key is ready, rip it */ - if (keypress ()) { - key = get_key (); - _D ("key %02x pressed", key); - } - - return key; -} - - -int handle_controller (int key) -{ - struct vt_entry *v = &game.view_table[0]; - int i; - - /* The Black Cauldron needs KEY_ESCAPE to use menus */ - if (key == 0 /*|| key == KEY_ESCAPE*/) - return FALSE; - - _D (_D_WARN "key = %04x", key); - - for (i = 0; i < MAX_DIRS; i++) { - if (game.ev_keyp[i].data == key) { - _D ("event %d: key press", i); - game.ev_keyp[i].occured = TRUE; - //report ("event AC:%i occured\n", i); - return TRUE; - } - } - -#ifdef USE_MOUSE - if (key == BUTTON_LEFT) { - if (getflag (F_menus_work) && mouse.y <= CHAR_LINES) { - new_input_mode (INPUT_MENU); - return TRUE; - } - } -#endif - - if (game.player_control) { - int d = 0; - - if (!KEY_ASCII (key)) { - switch (key) { - case KEY_UP: d = 1; break; - case KEY_DOWN: d = 5; break; - case KEY_LEFT: d = 7; break; - case KEY_RIGHT: d = 3; break; - case KEY_UP_RIGHT: d = 2; break; - case KEY_DOWN_RIGHT: d = 4; break; - case KEY_UP_LEFT: d = 8; break; - case KEY_DOWN_LEFT: d = 6; break; - } - } - -#ifdef USE_MOUSE - if (!opt.agimouse) { - /* Handle mouse button events */ - if (key == BUTTON_LEFT) { - v->flags |= ADJ_EGO_XY; - v->parm1 = WIN_TO_PIC_X(mouse.x); - v->parm2 = WIN_TO_PIC_Y(mouse.y); - return TRUE; - } - } -#endif - - v->flags &= ~ADJ_EGO_XY; - - if (d || key == KEY_STATIONARY) { - v->direction = v->direction == d ? 0 : d; - return TRUE; - } - } - - return FALSE; -} - - -void handle_getstring (int key) -{ - static int pos = 0; /* Cursor position */ - static char buf[40]; - - if (KEY_ASCII(key) == 0) - return; - - _D ("handling key: %02x", key); - - switch (key) { - case KEY_ENTER: - _D ("KEY_ENTER"); - game.has_prompt = 0; - buf[pos] = 0; - strcpy (game.strings[stringdata.str], buf); - _D (_D_WARN "buffer=[%s]", buf); - buf[pos = 0] = 0; - new_input_mode (INPUT_NORMAL); - print_character (stringdata.x + strlen (game.strings[stringdata.str]) + 1, stringdata.y, - ' ', game.color_fg, game.color_bg); - return; - case KEY_ESCAPE: - _D ("KEY_ESCAPE"); - game.has_prompt = 0; - buf[pos = 0] = 0; - strcpy (game.strings[stringdata.str], buf); - new_input_mode (INPUT_NORMAL); - /* new_input_mode (INPUT_MENU); */ - break; - case KEY_BACKSPACE: /*0x08:*/ - if (!pos) - break; - - print_character (stringdata.x + (pos + 1), stringdata.y, - ' ', game.color_fg, game.color_bg); - - pos--; - buf[pos] = 0; - break; - default: - if (key < 0x20 || key > 0x7f) - break; - - if (pos >= stringdata.len) - break; - - buf[pos++] = key; - buf[pos] = 0; - - /* Echo */ - print_character (stringdata.x + pos, stringdata.y, - buf[pos - 1], game.color_fg, game.color_bg); - - break; - } - - /* print cursor */ - print_character (stringdata.x + pos + 1, stringdata.y, - (char)game.cursor_char, game.color_fg, game.color_bg); -} - - -void handle_keys (int key) -{ - UINT8 *p=NULL; - int c = 0; - static UINT8 formated_entry[256]; - int l = game.line_user_input; - int fg = game.color_fg, bg = game.color_bg; - - setvar (V_word_not_found, 0); - - _D ("handling key: %02x", key); - - switch (key) { - case KEY_ENTER: - _D (("KEY_ENTER")); - game.keypress = 0; - - /* Remove all leading spaces */ - for (p = game.input_buffer; *p && *p == 0x20; p++); - - /* Copy to internal buffer */ - for (; *p; p++) { - /* Squash spaces */ - if (*p == 0x20 && *(p + 1) == 0x20) { - p++; - continue; - } - formated_entry[c++] = tolower (*p); - } - formated_entry[c++] = 0; - - /* Handle string only if it's not empty */ - if (formated_entry[0]) { - strcpy (game.echo_buffer, game.input_buffer); - strcpy (last_sentence, formated_entry); - dictionary_words (last_sentence); - } - - /* Clear to start a new line*/ - game.has_prompt = 0; - game.input_buffer[game.cursor_pos = 0] = 0; - _D (_D_WARN "clear lines"); - clear_lines (l, l + 1, bg); - flush_lines (l, l + 1); - - break; - case KEY_ESCAPE: - _D (("KEY_ESCAPE")); - new_input_mode (INPUT_MENU); - break; - case KEY_BACKSPACE: - /* Ignore backspace at start of line */ - if (game.cursor_pos == 0) break; - - /* erase cursor */ - print_character (game.cursor_pos + 1, l, ' ', fg, bg); - game.input_buffer[--game.cursor_pos] = 0; - /* Print cursor */ - print_character (game.cursor_pos + 1, l, game.cursor_char, fg, bg ); - break; - default: - /* Ignore invalid keystrokes */ - if (key < 0x20 || key > 0x7f) - break; - - /* Maximum input size reached */ - if (game.cursor_pos >= getvar (V_max_input_chars)) - break; - - game.input_buffer[game.cursor_pos++] = key; - game.input_buffer[game.cursor_pos] = 0; - - /* echo */ - print_character (game.cursor_pos, l, - game.input_buffer[game.cursor_pos - 1], fg, bg); - - /* Print cursor */ - print_character (game.cursor_pos + 1, l, game.cursor_char, fg, bg); - break; - } -} - - -int wait_key () -{ - int key; - - /* clear key queue */ - while (keypress ()) { get_key (); } - - _D (_D_WARN "waiting..."); - while (42) { - poll_timer (); /* msdos driver -> does nothing */ - key = do_poll_keyboard (); - if (!console_keyhandler (key)) { - if (key == KEY_ENTER || key == KEY_ESCAPE -#ifdef USE_MOUSE - || key == BUTTON_LEFT -#endif - ) - break; - } - console_cycle (); - } - return key; -} - - -int wait_any_key () -{ - int key; - - /* clear key queue */ - while (keypress ()) { get_key (); } - - _D (_D_WARN "waiting..."); - while (42) { - poll_timer (); /* msdos driver -> does nothing */ - key = do_poll_keyboard (); - if (!console_keyhandler (key) && key) - break; - console_cycle (); - } - return key; -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: keyboard.c,v 1.78 2003/07/16 18:32:05 bootstrap666 Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include + +#ifndef PALMOS +#include +#endif + +#include "sarien.h" +#include "agi.h" +#include "graphics.h" +#include "keyboard.h" +#include "menu.h" +#include "text.h" /* remove later */ + +char last_sentence[40]; + +#ifdef USE_CONSOLE +extern struct sarien_console console; +#endif + +/* FIXME */ +extern int open_dialogue; + +struct string_data { + int x; + int y; + int len; + int str; +}; + +struct string_data stringdata; + +/* + * IBM-PC keyboard scancodes + */ +UINT8 scancode_table[26] = { + 30, /* A */ + 48, /* B */ + 46, /* C */ + 32, /* D */ + 18, /* E */ + 33, /* F */ + 34, /* G */ + 35, /* H */ + 23, /* I */ + 36, /* J */ + 37, /* K */ + 38, /* L */ + 50, /* M */ + 49, /* N */ + 24, /* O */ + 25, /* P */ + 16, /* Q */ + 19, /* R */ + 31, /* S */ + 20, /* T */ + 22, /* U */ + 47, /* V */ + 17, /* W */ + 45, /* X */ + 21, /* Y */ + 44 /* Z */ +}; + + +void init_words () +{ + game.num_ego_words = 0; +} + + +void clean_input () +{ + while (game.num_ego_words) + free (game.ego_words[--game.num_ego_words].word); +} + + +void get_string (int x, int y, int len, int str) +{ + new_input_mode (INPUT_GETSTRING); + stringdata.x = x; + stringdata.y = y; + stringdata.len = len; + stringdata.str = str; +} + + +/** + * Raw key grabber. + * poll_keyboard() is the raw key grabber (above the gfx driver, that is). + * It handles console keys and insulates AGI from the console. In the main + * loop, handle_keys() handles keyboard input and ego movement. + */ +int do_poll_keyboard () +{ + int key = 0; + + /* If a key is ready, rip it */ + if (keypress ()) { + key = get_key (); + _D ("key %02x pressed", key); + } + + return key; +} + + +int handle_controller (int key) +{ + struct vt_entry *v = &game.view_table[0]; + int i; + + /* The Black Cauldron needs KEY_ESCAPE to use menus */ + if (key == 0 /*|| key == KEY_ESCAPE*/) + return FALSE; + + _D (_D_WARN "key = %04x", key); + + for (i = 0; i < MAX_DIRS; i++) { + if (game.ev_keyp[i].data == key) { + _D ("event %d: key press", i); + game.ev_keyp[i].occured = TRUE; + //report ("event AC:%i occured\n", i); + return TRUE; + } + } + +#ifdef USE_MOUSE + if (key == BUTTON_LEFT) { + if (getflag (F_menus_work) && mouse.y <= CHAR_LINES) { + new_input_mode (INPUT_MENU); + return TRUE; + } + } +#endif + + if (game.player_control) { + int d = 0; + + if (!KEY_ASCII (key)) { + switch (key) { + case KEY_UP: d = 1; break; + case KEY_DOWN: d = 5; break; + case KEY_LEFT: d = 7; break; + case KEY_RIGHT: d = 3; break; + case KEY_UP_RIGHT: d = 2; break; + case KEY_DOWN_RIGHT: d = 4; break; + case KEY_UP_LEFT: d = 8; break; + case KEY_DOWN_LEFT: d = 6; break; + } + } + +#ifdef USE_MOUSE + if (!opt.agimouse) { + /* Handle mouse button events */ + if (key == BUTTON_LEFT) { + v->flags |= ADJ_EGO_XY; + v->parm1 = WIN_TO_PIC_X(mouse.x); + v->parm2 = WIN_TO_PIC_Y(mouse.y); + return TRUE; + } + } +#endif + + v->flags &= ~ADJ_EGO_XY; + + if (d || key == KEY_STATIONARY) { + v->direction = v->direction == d ? 0 : d; + return TRUE; + } + } + + return FALSE; +} + + +void handle_getstring (int key) +{ + static int pos = 0; /* Cursor position */ + static char buf[40]; + + if (KEY_ASCII(key) == 0) + return; + + _D ("handling key: %02x", key); + + switch (key) { + case KEY_ENTER: + _D ("KEY_ENTER"); + game.has_prompt = 0; + buf[pos] = 0; + strcpy (game.strings[stringdata.str], buf); + _D (_D_WARN "buffer=[%s]", buf); + buf[pos = 0] = 0; + new_input_mode (INPUT_NORMAL); + print_character (stringdata.x + strlen (game.strings[stringdata.str]) + 1, stringdata.y, + ' ', game.color_fg, game.color_bg); + return; + case KEY_ESCAPE: + _D ("KEY_ESCAPE"); + game.has_prompt = 0; + buf[pos = 0] = 0; + strcpy (game.strings[stringdata.str], buf); + new_input_mode (INPUT_NORMAL); + /* new_input_mode (INPUT_MENU); */ + break; + case KEY_BACKSPACE: /*0x08:*/ + if (!pos) + break; + + print_character (stringdata.x + (pos + 1), stringdata.y, + ' ', game.color_fg, game.color_bg); + + pos--; + buf[pos] = 0; + break; + default: + if (key < 0x20 || key > 0x7f) + break; + + if (pos >= stringdata.len) + break; + + buf[pos++] = key; + buf[pos] = 0; + + /* Echo */ + print_character (stringdata.x + pos, stringdata.y, + buf[pos - 1], game.color_fg, game.color_bg); + + break; + } + + /* print cursor */ + print_character (stringdata.x + pos + 1, stringdata.y, + (char)game.cursor_char, game.color_fg, game.color_bg); +} + + +void handle_keys (int key) +{ + UINT8 *p=NULL; + int c = 0; + static UINT8 formated_entry[256]; + int l = game.line_user_input; + int fg = game.color_fg, bg = game.color_bg; + + setvar (V_word_not_found, 0); + + _D ("handling key: %02x", key); + + switch (key) { + case KEY_ENTER: + _D (("KEY_ENTER")); + game.keypress = 0; + + /* Remove all leading spaces */ + for (p = game.input_buffer; *p && *p == 0x20; p++); + + /* Copy to internal buffer */ + for (; *p; p++) { + /* Squash spaces */ + if (*p == 0x20 && *(p + 1) == 0x20) { + p++; + continue; + } + formated_entry[c++] = tolower (*p); + } + formated_entry[c++] = 0; + + /* Handle string only if it's not empty */ + if (formated_entry[0]) { + strcpy (game.echo_buffer, game.input_buffer); + strcpy (last_sentence, formated_entry); + dictionary_words (last_sentence); + } + + /* Clear to start a new line*/ + game.has_prompt = 0; + game.input_buffer[game.cursor_pos = 0] = 0; + _D (_D_WARN "clear lines"); + clear_lines (l, l + 1, bg); + flush_lines (l, l + 1); + + break; + case KEY_ESCAPE: + _D (("KEY_ESCAPE")); + new_input_mode (INPUT_MENU); + break; + case KEY_BACKSPACE: + /* Ignore backspace at start of line */ + if (game.cursor_pos == 0) break; + + /* erase cursor */ + print_character (game.cursor_pos + 1, l, ' ', fg, bg); + game.input_buffer[--game.cursor_pos] = 0; + /* Print cursor */ + print_character (game.cursor_pos + 1, l, game.cursor_char, fg, bg ); + break; + default: + /* Ignore invalid keystrokes */ + if (key < 0x20 || key > 0x7f) + break; + + /* Maximum input size reached */ + if (game.cursor_pos >= getvar (V_max_input_chars)) + break; + + game.input_buffer[game.cursor_pos++] = key; + game.input_buffer[game.cursor_pos] = 0; + + /* echo */ + print_character (game.cursor_pos, l, + game.input_buffer[game.cursor_pos - 1], fg, bg); + + /* Print cursor */ + print_character (game.cursor_pos + 1, l, game.cursor_char, fg, bg); + break; + } +} + + +int wait_key () +{ + int key; + + /* clear key queue */ + while (keypress ()) { get_key (); } + + _D (_D_WARN "waiting..."); + while (42) { + poll_timer (); /* msdos driver -> does nothing */ + key = do_poll_keyboard (); + if (!console_keyhandler (key)) { + if (key == KEY_ENTER || key == KEY_ESCAPE +#ifdef USE_MOUSE + || key == BUTTON_LEFT +#endif + ) + break; + } + console_cycle (); + } + return key; +} + + +int wait_any_key () +{ + int key; + + /* clear key queue */ + while (keypress ()) { get_key (); } + + _D (_D_WARN "waiting..."); + while (42) { + poll_timer (); /* msdos driver -> does nothing */ + key = do_poll_keyboard (); + if (!console_keyhandler (key) && key) + break; + console_cycle (); + } + return key; +} + diff --git a/logic.c b/logic.c index 99dc649..34090af 100644 --- a/logic.c +++ b/logic.c @@ -1,107 +1,107 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999,2001 Stuart George and Claudio Matsuoka - * - * $Id: logic.c,v 1.14 2002/01/01 12:23:32 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" - - -/** - * Decode logic resource - * This function decodes messages from the specified raw logic resource - * into a message list. - * @param n The number of the logic resource to decode. - */ -int decode_logic (int n) -{ - int ec = err_OK; - int mstart, mend, mc; - UINT8 *m0; - - /* decrypt messages at end of logic + build message list */ - - /* report ("decoding logic #%d\n", n); */ - m0 = game.logics[n].data; - - mstart = lohi_getword (m0) + 2; - mc = lohi_getbyte (m0 + mstart); - mend = lohi_getword (m0 + mstart + 1); - m0 += mstart + 3; /* cover header info */ - mstart = mc << 1; - - /* if the logic was not compressed, decrypt the text messages - * only if there are more than 0 messages - */ - if ((~game.dir_logic[n].flags & RES_COMPRESSED) && mc > 0) - decrypt (m0 + mstart, mend - mstart); /* decrypt messages */ - - /* build message list */ - m0 = game.logics[n].data; - mstart = lohi_getword (m0) + 2; /* +2 covers pointer */ - game.logics[n].num_texts = lohi_getbyte (m0 + mstart); - - /* resetp logic pointers */ - game.logics[n].sIP = 2; - game.logics[n].cIP = 2; - game.logics[n].size = lohi_getword (m0) + 2; /* logic end pointer */ - - /* allocate list of pointers to point into our data */ - game.logics[n].texts = calloc (1 + game.logics[n].num_texts, - sizeof (char*)); - - /* cover header info */ - m0 += mstart+3; - - if (game.logics[n].texts != NULL) { - /* move list of strings into list to make real pointers */ - for(mc = 0; mc < game.logics[n].num_texts; mc++) { - mend = lohi_getword(m0+mc*2); - game.logics[n].texts[mc] = mend ? - (char *)m0 + mend - 2 : ""; - } - /* set loaded flag now its all completly loaded */ - game.dir_logic[n].flags |= RES_LOADED; - } else { - /* unload data - * blah DF YA WANKER!!@!@# frag. i'm so dumb. not every logic - * has text - */ - free (game.logics[n].data); - ec = err_NotEnoughMemory; - } - - return ec; -} - - -/** - * Unload logic resource - * This function unloads the specified logic resource, freeing any - * memory chunks allocated for this resource. - * @param n The number of the logic resource to unload - */ -void unload_logic (int n) -{ - if (game.dir_logic[n].flags & RES_LOADED) { - free (game.logics[n].data); - if (game.logics[n].num_texts) - free (game.logics[n].texts); - game.logics[n].num_texts = 0; - game.dir_logic[n].flags &= ~RES_LOADED; - } - - /* if cached, we end up here */ - game.logics[n].sIP = 2; - game.logics[n].cIP = 2; -} - -/* end: logic.c */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999,2001 Stuart George and Claudio Matsuoka + * + * $Id: logic.c,v 1.14 2002/01/01 12:23:32 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" + + +/** + * Decode logic resource + * This function decodes messages from the specified raw logic resource + * into a message list. + * @param n The number of the logic resource to decode. + */ +int decode_logic (int n) +{ + int ec = err_OK; + int mstart, mend, mc; + UINT8 *m0; + + /* decrypt messages at end of logic + build message list */ + + /* report ("decoding logic #%d\n", n); */ + m0 = game.logics[n].data; + + mstart = lohi_getword (m0) + 2; + mc = lohi_getbyte (m0 + mstart); + mend = lohi_getword (m0 + mstart + 1); + m0 += mstart + 3; /* cover header info */ + mstart = mc << 1; + + /* if the logic was not compressed, decrypt the text messages + * only if there are more than 0 messages + */ + if ((~game.dir_logic[n].flags & RES_COMPRESSED) && mc > 0) + decrypt (m0 + mstart, mend - mstart); /* decrypt messages */ + + /* build message list */ + m0 = game.logics[n].data; + mstart = lohi_getword (m0) + 2; /* +2 covers pointer */ + game.logics[n].num_texts = lohi_getbyte (m0 + mstart); + + /* resetp logic pointers */ + game.logics[n].sIP = 2; + game.logics[n].cIP = 2; + game.logics[n].size = lohi_getword (m0) + 2; /* logic end pointer */ + + /* allocate list of pointers to point into our data */ + game.logics[n].texts = calloc (1 + game.logics[n].num_texts, + sizeof (char*)); + + /* cover header info */ + m0 += mstart+3; + + if (game.logics[n].texts != NULL) { + /* move list of strings into list to make real pointers */ + for(mc = 0; mc < game.logics[n].num_texts; mc++) { + mend = lohi_getword(m0+mc*2); + game.logics[n].texts[mc] = mend ? + (char *)m0 + mend - 2 : ""; + } + /* set loaded flag now its all completly loaded */ + game.dir_logic[n].flags |= RES_LOADED; + } else { + /* unload data + * blah DF YA WANKER!!@!@# frag. i'm so dumb. not every logic + * has text + */ + free (game.logics[n].data); + ec = err_NotEnoughMemory; + } + + return ec; +} + + +/** + * Unload logic resource + * This function unloads the specified logic resource, freeing any + * memory chunks allocated for this resource. + * @param n The number of the logic resource to unload + */ +void unload_logic (int n) +{ + if (game.dir_logic[n].flags & RES_LOADED) { + free (game.logics[n].data); + if (game.logics[n].num_texts) + free (game.logics[n].texts); + game.logics[n].num_texts = 0; + game.dir_logic[n].flags &= ~RES_LOADED; + } + + /* if cached, we end up here */ + game.logics[n].sIP = 2; + game.logics[n].cIP = 2; +} + +/* end: logic.c */ + diff --git a/lzw.c b/lzw.c index 1c26658..1ef76a2 100644 --- a/lzw.c +++ b/lzw.c @@ -1,182 +1,182 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: lzw.c,v 1.6 2002/03/31 00:15:08 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -/*************************************************************************** -** decomp.c -** -** Routines that deal with AGI version 3 specific features. -** The original LZW code is from DJJ, October 1989, p.86. -** It has been modified to handle AGI compression. -** -** (c) 1997 Lance Ewing -***************************************************************************/ - -#include -#include - -#include "sarien.h" -#include "lzw.h" - -#define MAXBITS 12 -#define TABLE_SIZE 18041 /* strange number */ -#define START_BITS 9 - -static SINT32 BITS, MAX_VALUE, MAX_CODE; -static UINT32 *prefix_code; -static UINT8 *append_character; -static UINT8 *decode_stack; -static SINT32 input_bit_count=0; /* Number of bits in input bit buffer */ -static UINT32 input_bit_buffer=0L; - -static void initLZW () -{ - decode_stack = calloc (1, 8192); - prefix_code= malloc (TABLE_SIZE * sizeof(UINT32)); - append_character= malloc (TABLE_SIZE * sizeof(UINT8)); - input_bit_count = 0; /* Number of bits in input bit buffer */ - input_bit_buffer = 0L; -} - -static void closeLZW () -{ - free (decode_stack); - free (prefix_code); - free (append_character); -} - -/*************************************************************************** -** setBITS -** -** Purpose: To adjust the number of bits used to store codes to the value -** passed in. -***************************************************************************/ -int setBITS (SINT32 value) -{ - if (value == MAXBITS) - return TRUE; - - BITS = value; - MAX_VALUE = (1 << BITS) - 1; - MAX_CODE = MAX_VALUE - 1; - - return FALSE; -} - -/*************************************************************************** -** decode_string -** -** Purpose: To return the string that the code taken from the input buffer -** represents. The string is returned as a stack, i.e. the characters are -** in reverse order. -***************************************************************************/ -static UINT8 *decode_string(UINT8 *buffer, UINT32 code) -{ - UINT32 i; - - for (i = 0; code > 255; ) { - *buffer++ = append_character[code]; - code=prefix_code[code]; - if (i++ >= 4000) { - fprintf (stderr, "lzw: error in code expansion.\n"); - abort (); - } - } - *buffer = code; - - return buffer; -} - -/*************************************************************************** -** input_code -** -** Purpose: To return the next code from the input buffer. -***************************************************************************/ -static UINT32 input_code (UINT8 **input) -{ - UINT32 r; - - while (input_bit_count <= 24) { - input_bit_buffer |= (UINT32) *(*input)++ << input_bit_count; - input_bit_count += 8; - } - r = (input_bit_buffer & 0x7FFF) % (1 << BITS); - input_bit_buffer >>= BITS; - input_bit_count -= BITS; - - return r; -} - -/*************************************************************************** -** expand -** -** Purpose: To uncompress the data contained in the input buffer and store -** the result in the output buffer. The fileLength parameter says how -** many bytes to uncompress. The compression itself is a form of LZW that -** adjusts the number of bits that it represents its codes in as it fills -** up the available codes. Two codes have special meaning: -** -** code 256 = start over -** code 257 = end of data -***************************************************************************/ -void LZW_expand(UINT8 *in, UINT8 *out, SINT32 len) -{ - SINT32 c, lzwnext, lzwnew, lzwold; - UINT8 *s, *end; - - initLZW(); - - setBITS(START_BITS); /* Starts at 9-bits */ - lzwnext = 257; /* Next available code to define */ - - end = (unsigned char *)((long)out + (long)len); - - lzwold = input_code(&in); /* Read in the first code */ - c = lzwold; - lzwnew = input_code(&in); - - while ((out < end) && (lzwnew != 0x101)) { - if (lzwnew == 0x100) { - /* Code to "start over" */ - lzwnext = 258; - setBITS(START_BITS); - lzwold = input_code(&in); - c = lzwold; - *out++ = (char)c; - lzwnew = input_code(&in); - } else { - if (lzwnew >= lzwnext) { - /* Handles special LZW scenario */ - *decode_stack = c; - s = decode_string(decode_stack+1, lzwold); - } - else - s = decode_string(decode_stack, lzwnew); - - /* Reverse order of decoded string and - * store in out buffer - */ - c = *s; - while (s >= decode_stack) - *out++ = *s--; - - if (lzwnext > MAX_CODE) - setBITS(BITS + 1); - - prefix_code[lzwnext] = lzwold; - append_character[lzwnext] = c; - lzwnext++; - lzwold = lzwnew; - - lzwnew = input_code(&in); - } - } - closeLZW (); -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: lzw.c,v 1.6 2002/03/31 00:15:08 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +/*************************************************************************** +** decomp.c +** +** Routines that deal with AGI version 3 specific features. +** The original LZW code is from DJJ, October 1989, p.86. +** It has been modified to handle AGI compression. +** +** (c) 1997 Lance Ewing +***************************************************************************/ + +#include +#include + +#include "sarien.h" +#include "lzw.h" + +#define MAXBITS 12 +#define TABLE_SIZE 18041 /* strange number */ +#define START_BITS 9 + +static SINT32 BITS, MAX_VALUE, MAX_CODE; +static UINT32 *prefix_code; +static UINT8 *append_character; +static UINT8 *decode_stack; +static SINT32 input_bit_count=0; /* Number of bits in input bit buffer */ +static UINT32 input_bit_buffer=0L; + +static void initLZW () +{ + decode_stack = calloc (1, 8192); + prefix_code= malloc (TABLE_SIZE * sizeof(UINT32)); + append_character= malloc (TABLE_SIZE * sizeof(UINT8)); + input_bit_count = 0; /* Number of bits in input bit buffer */ + input_bit_buffer = 0L; +} + +static void closeLZW () +{ + free (decode_stack); + free (prefix_code); + free (append_character); +} + +/*************************************************************************** +** setBITS +** +** Purpose: To adjust the number of bits used to store codes to the value +** passed in. +***************************************************************************/ +int setBITS (SINT32 value) +{ + if (value == MAXBITS) + return TRUE; + + BITS = value; + MAX_VALUE = (1 << BITS) - 1; + MAX_CODE = MAX_VALUE - 1; + + return FALSE; +} + +/*************************************************************************** +** decode_string +** +** Purpose: To return the string that the code taken from the input buffer +** represents. The string is returned as a stack, i.e. the characters are +** in reverse order. +***************************************************************************/ +static UINT8 *decode_string(UINT8 *buffer, UINT32 code) +{ + UINT32 i; + + for (i = 0; code > 255; ) { + *buffer++ = append_character[code]; + code=prefix_code[code]; + if (i++ >= 4000) { + fprintf (stderr, "lzw: error in code expansion.\n"); + abort (); + } + } + *buffer = code; + + return buffer; +} + +/*************************************************************************** +** input_code +** +** Purpose: To return the next code from the input buffer. +***************************************************************************/ +static UINT32 input_code (UINT8 **input) +{ + UINT32 r; + + while (input_bit_count <= 24) { + input_bit_buffer |= (UINT32) *(*input)++ << input_bit_count; + input_bit_count += 8; + } + r = (input_bit_buffer & 0x7FFF) % (1 << BITS); + input_bit_buffer >>= BITS; + input_bit_count -= BITS; + + return r; +} + +/*************************************************************************** +** expand +** +** Purpose: To uncompress the data contained in the input buffer and store +** the result in the output buffer. The fileLength parameter says how +** many bytes to uncompress. The compression itself is a form of LZW that +** adjusts the number of bits that it represents its codes in as it fills +** up the available codes. Two codes have special meaning: +** +** code 256 = start over +** code 257 = end of data +***************************************************************************/ +void LZW_expand(UINT8 *in, UINT8 *out, SINT32 len) +{ + SINT32 c, lzwnext, lzwnew, lzwold; + UINT8 *s, *end; + + initLZW(); + + setBITS(START_BITS); /* Starts at 9-bits */ + lzwnext = 257; /* Next available code to define */ + + end = (unsigned char *)((long)out + (long)len); + + lzwold = input_code(&in); /* Read in the first code */ + c = lzwold; + lzwnew = input_code(&in); + + while ((out < end) && (lzwnew != 0x101)) { + if (lzwnew == 0x100) { + /* Code to "start over" */ + lzwnext = 258; + setBITS(START_BITS); + lzwold = input_code(&in); + c = lzwold; + *out++ = (char)c; + lzwnew = input_code(&in); + } else { + if (lzwnew >= lzwnext) { + /* Handles special LZW scenario */ + *decode_stack = c; + s = decode_string(decode_stack+1, lzwold); + } + else + s = decode_string(decode_stack, lzwnew); + + /* Reverse order of decoded string and + * store in out buffer + */ + c = *s; + while (s >= decode_stack) + *out++ = *s--; + + if (lzwnext > MAX_CODE) + setBITS(BITS + 1); + + prefix_code[lzwnext] = lzwold; + append_character[lzwnext] = c; + lzwnext++; + lzwold = lzwnew; + + lzwnew = input_code(&in); + } + } + closeLZW (); +} + diff --git a/main.c b/main.c index bf4ede5..c414816 100644 --- a/main.c +++ b/main.c @@ -1,262 +1,262 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: main.c,v 1.87 2003/09/02 01:10:55 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include - -#ifdef HAVE_ALLEGRO -#include -#endif - -#include "sarien.h" -#include "agi.h" -#include "text.h" -#include "graphics.h" -#include "sprite.h" - -extern int optind; - -struct sarien_options opt; -struct game_id_list game_info; -struct agi_game game; - -#if (!defined(_TRACE) && !defined(__GNUC__)) -INLINE void _D (char *s, ...) { s = s; } -#endif - - -#ifdef MACOSX -# ifdef MACOSX_SDL -# define main SDL_main -# else - /* real main for OS X is in src/graphics/cocoa/cocoa.m */ -# define main gamemain -# endif -#endif - - -int OLDmain () //int argc, char *argv[]) -{ - int ec; - - /* we must do this before _ANYTHING_ else if using allegro!! */ -#ifdef HAVE_ALLEGRO - allegro_init (); - install_keyboard (); -#endif - -#ifdef __MSDOS__ - exec_name = strdup(argv[0]); -#endif - - game.clock_enabled = FALSE; - game.state = STATE_INIT; - - opt.scale = 1; - -#ifdef USE_COMMAND_LINE - if ((ec = parse_cli (argc, argv)) != err_OK) - goto bail_out; - - if (opt.gamerun == GAMERUN_CRC) { - char name[80]; - agi_detect_game (argc > 1 ? argv[optind] : - get_current_directory ()); - printf ("CRC: 0x%x (Ver 0x%x)\n", game.crc, game.ver); - if (match_crc (game.crc, get_config_file(), name, 80)) - printf(" AGI game detected: %s\n", name); - else - printf(" Unknown game (config file: %s)\n", - get_config_file()); - exit (0); - } - - if (opt.gamerun == GAMERUN_GAMES) { - list_games (); - exit (0); - } -#ifdef OPT_LIST_OBJECTS - if (opt.gamerun == GAMERUN_OBJECTS) { - agi_detect_game(get_current_directory()); //argc > 1 ? argv[optind] : get_current_directory()); - agi_init(); - show_objects(); - - /* errgh!! ugly goto */ - goto bail_out; - } -#endif -#ifdef OPT_LIST_DICT - if (opt.gamerun == GAMERUN_WORDS){ - agi_detect_game(argc > 1 ? argv[optind] : get_current_directory()); - agi_init(); - show_words(); - - goto bail_out; - } -#endif -#endif - - init_machine(); // (argc, argv); - - game.color_fg = 15; - game.color_bg = 0; - - if ((game.sbuf = calloc (_WIDTH, _HEIGHT)) == NULL) { - ec = err_NotEnoughMemory; - goto bail_out; - } -#ifdef USE_HIRES - if ((game.hires = calloc (_WIDTH * 2, _HEIGHT)) == NULL) { - ec = err_NotEnoughMemory; - goto bail_out_2; - }; -#endif - - if (init_sprites () != err_OK) { - ec = err_NotEnoughMemory; - goto bail_out_3; - } - - if (init_video () != err_OK) { - ec = err_Unk; - goto bail_out_4; - } - - -#ifdef OPT_PICTURE_VIEWER - if (opt.gamerun == GAMERUN_PICVIEW) { - console.y = 0; - if (agi_detect_game (argc > 1 ? argv[optind] : - get_current_directory ()) == err_OK) - { - agi_init (); - view_pictures (); - } - - goto bail_out; - } -#endif - -#if !defined (__MSDOS__) - /* printf() breaks GCC 3.0 build */ - fprintf (stdout, -TITLE " " VERSION " - A Sierra AGI resource interpreter engine.\n" -"Copyright (C) 1999-2003 Stuart George\n" -"Portions Copyright (C) 1998 Lance Ewing, (C) 1999 Felipe Rosinha,\n" -" (C) 1999-2003 Claudio Matsuoka, (C) 1999-2001 Igor Nesterov,\n" -" (C) 2001,2002 Vasyl Tsvirkunov, (C) 2001,2002 Thomas Akesson\n" -"Scale2x Copyright (C) 2001-2002 Andrea Mazzoleni\n" -#ifndef HAVE_GETOPT_LONG -"Portions Copyright (C) 1989-1997 Free Software Foundation, Inc.\n" -#endif -"\n" -"This program is free software; you can redistribute it and/or modify it\n" -"under the terms of the GNU General Public License, version 2 or later,\n" -"as published by the the Free Software Foundation.\n" -"\n"); -#endif - - report ("Enabling interpreter console\n"); - console_init (); - report ("--- Starting console ---\n\n"); - if (!opt.gfxhacks) - report ("Graphics driver hacks disabled (if any)\n"); - - game.ver = -1; /* Don't display the conf file warning */ - - _D ("Detect game"); -#if 0 - if (agi_detect_game (argc > 1 ? argv[optind] : - get_current_directory ()) == err_OK) - { - game.state = STATE_LOADED; - _D (_D_WARN "game loaded"); - } else { - if (argc > optind) { - report ("Could not open AGI game \"%s\".\n\n", - argv[optind]); - } - } -#else - agi_detect_game(""); -game.state = STATE_LOADED; -#endif - - _D ("Init sound"); - init_sound (); - - report (" \nSarien " VERSION " is ready.\n"); - if (game.state < STATE_LOADED) { - console_prompt (); - do { main_cycle (); } while (game.state < STATE_RUNNING); - if (game.ver < 0) game.ver = 0; /* Enable conf file warning */ - } - - ec = run_game (); - - deinit_sound (); - deinit_video (); - -bail_out_4: - deinit_sprites (); -bail_out_3: -#ifdef USE_HIRES - free (game.hires); -#endif -bail_out_2: - free (game.sbuf); -bail_out: - if (ec == err_OK || ec == err_DoNothing) { - deinit_machine (); - exit (ec); - } - - printf ("Error %04i: ", ec); - - switch (ec) { - case err_BadCLISwitch: - printf("Bad CLI switch.\n"); - break; - case err_InvalidAGIFile: - printf("Invalid or inexistent AGI file.\n"); - break; - case err_BadFileOpen: - printf("Unable to open file.\n"); - break; - case err_NotEnoughMemory: - printf("Not enough memory.\n"); - break; - case err_BadResource: - printf("Error in resource.\n"); - break; - case err_UnknownAGIVersion: - printf("Unknown AGI version.\n"); - break; - case err_NoGameList: - printf("No game ID List was found!\n"); - break; - } - printf("\nUse parameter -h to list the command line options\n"); - - deinit_machine (); - -#ifdef HAVE_ALLEGRO - remove_keyboard(); -#endif -#ifdef __MSDOS__ - free(exec_name); -#endif - - return ec; -} -#ifdef HAVE_ALLEGRO -END_OF_MAIN() -#endif - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: main.c,v 1.87 2003/09/02 01:10:55 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include + +#ifdef HAVE_ALLEGRO +#include +#endif + +#include "sarien.h" +#include "agi.h" +#include "text.h" +#include "graphics.h" +#include "sprite.h" + +extern int optind; + +struct sarien_options opt; +struct game_id_list game_info; +struct agi_game game; + +#if (!defined(_TRACE) && !defined(__GNUC__)) +INLINE void _D (char *s, ...) { s = s; } +#endif + + +#ifdef MACOSX +# ifdef MACOSX_SDL +# define main SDL_main +# else + /* real main for OS X is in src/graphics/cocoa/cocoa.m */ +# define main gamemain +# endif +#endif + + +int OLDmain () //int argc, char *argv[]) +{ + int ec; + + /* we must do this before _ANYTHING_ else if using allegro!! */ +#ifdef HAVE_ALLEGRO + allegro_init (); + install_keyboard (); +#endif + +#ifdef __MSDOS__ + exec_name = strdup(argv[0]); +#endif + + game.clock_enabled = FALSE; + game.state = STATE_INIT; + + opt.scale = 1; + +#ifdef USE_COMMAND_LINE + if ((ec = parse_cli (argc, argv)) != err_OK) + goto bail_out; + + if (opt.gamerun == GAMERUN_CRC) { + char name[80]; + agi_detect_game (argc > 1 ? argv[optind] : + get_current_directory ()); + printf ("CRC: 0x%x (Ver 0x%x)\n", game.crc, game.ver); + if (match_crc (game.crc, get_config_file(), name, 80)) + printf(" AGI game detected: %s\n", name); + else + printf(" Unknown game (config file: %s)\n", + get_config_file()); + exit (0); + } + + if (opt.gamerun == GAMERUN_GAMES) { + list_games (); + exit (0); + } +#ifdef OPT_LIST_OBJECTS + if (opt.gamerun == GAMERUN_OBJECTS) { + agi_detect_game(get_current_directory()); //argc > 1 ? argv[optind] : get_current_directory()); + agi_init(); + show_objects(); + + /* errgh!! ugly goto */ + goto bail_out; + } +#endif +#ifdef OPT_LIST_DICT + if (opt.gamerun == GAMERUN_WORDS){ + agi_detect_game(argc > 1 ? argv[optind] : get_current_directory()); + agi_init(); + show_words(); + + goto bail_out; + } +#endif +#endif + + init_machine(); // (argc, argv); + + game.color_fg = 15; + game.color_bg = 0; + + if ((game.sbuf = calloc (_WIDTH, _HEIGHT)) == NULL) { + ec = err_NotEnoughMemory; + goto bail_out; + } +#ifdef USE_HIRES + if ((game.hires = calloc (_WIDTH * 2, _HEIGHT)) == NULL) { + ec = err_NotEnoughMemory; + goto bail_out_2; + }; +#endif + + if (init_sprites () != err_OK) { + ec = err_NotEnoughMemory; + goto bail_out_3; + } + + if (init_video () != err_OK) { + ec = err_Unk; + goto bail_out_4; + } + + +#ifdef OPT_PICTURE_VIEWER + if (opt.gamerun == GAMERUN_PICVIEW) { + console.y = 0; + if (agi_detect_game (argc > 1 ? argv[optind] : + get_current_directory ()) == err_OK) + { + agi_init (); + view_pictures (); + } + + goto bail_out; + } +#endif + +#if !defined (__MSDOS__) + /* printf() breaks GCC 3.0 build */ + fprintf (stdout, +TITLE " " VERSION " - A Sierra AGI resource interpreter engine.\n" +"Copyright (C) 1999-2003 Stuart George\n" +"Portions Copyright (C) 1998 Lance Ewing, (C) 1999 Felipe Rosinha,\n" +" (C) 1999-2003 Claudio Matsuoka, (C) 1999-2001 Igor Nesterov,\n" +" (C) 2001,2002 Vasyl Tsvirkunov, (C) 2001,2002 Thomas Akesson\n" +"Scale2x Copyright (C) 2001-2002 Andrea Mazzoleni\n" +#ifndef HAVE_GETOPT_LONG +"Portions Copyright (C) 1989-1997 Free Software Foundation, Inc.\n" +#endif +"\n" +"This program is free software; you can redistribute it and/or modify it\n" +"under the terms of the GNU General Public License, version 2 or later,\n" +"as published by the the Free Software Foundation.\n" +"\n"); +#endif + + report ("Enabling interpreter console\n"); + console_init (); + report ("--- Starting console ---\n\n"); + if (!opt.gfxhacks) + report ("Graphics driver hacks disabled (if any)\n"); + + game.ver = -1; /* Don't display the conf file warning */ + + _D ("Detect game"); +#if 0 + if (agi_detect_game (argc > 1 ? argv[optind] : + get_current_directory ()) == err_OK) + { + game.state = STATE_LOADED; + _D (_D_WARN "game loaded"); + } else { + if (argc > optind) { + report ("Could not open AGI game \"%s\".\n\n", + argv[optind]); + } + } +#else + agi_detect_game(""); +game.state = STATE_LOADED; +#endif + + _D ("Init sound"); + init_sound (); + + report (" \nSarien " VERSION " is ready.\n"); + if (game.state < STATE_LOADED) { + console_prompt (); + do { main_cycle (); } while (game.state < STATE_RUNNING); + if (game.ver < 0) game.ver = 0; /* Enable conf file warning */ + } + + ec = run_game (); + + deinit_sound (); + deinit_video (); + +bail_out_4: + deinit_sprites (); +bail_out_3: +#ifdef USE_HIRES + free (game.hires); +#endif +bail_out_2: + free (game.sbuf); +bail_out: + if (ec == err_OK || ec == err_DoNothing) { + deinit_machine (); + exit (ec); + } + + printf ("Error %04i: ", ec); + + switch (ec) { + case err_BadCLISwitch: + printf("Bad CLI switch.\n"); + break; + case err_InvalidAGIFile: + printf("Invalid or inexistent AGI file.\n"); + break; + case err_BadFileOpen: + printf("Unable to open file.\n"); + break; + case err_NotEnoughMemory: + printf("Not enough memory.\n"); + break; + case err_BadResource: + printf("Error in resource.\n"); + break; + case err_UnknownAGIVersion: + printf("Unknown AGI version.\n"); + break; + case err_NoGameList: + printf("No game ID List was found!\n"); + break; + } + printf("\nUse parameter -h to list the command line options\n"); + + deinit_machine (); + +#ifdef HAVE_ALLEGRO + remove_keyboard(); +#endif +#ifdef __MSDOS__ + free(exec_name); +#endif + + return ec; +} +#ifdef HAVE_ALLEGRO +END_OF_MAIN() +#endif + diff --git a/menu.c b/menu.c index 1fb1abe..54e88d3 100644 --- a/menu.c +++ b/menu.c @@ -1,519 +1,519 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999,2002 Stuart George and Claudio Matsuoka - * - * $Id: menu.c,v 1.59 2003/07/10 20:20:19 bootstrap666 Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "sprite.h" -#include "graphics.h" -#include "keyboard.h" -#include "menu.h" -#include "text.h" -#include "list.h" - - -struct agi_menu { - struct list_head list; /**< list head for menubar list */ - struct list_head down; /**< list head for menu options */ - int index; /**< number of menu in menubar */ - int width; /**< width of menu in characters */ - int height; /**< height of menu in characters */ - int col; /**< column of menubar entry */ - int wincol; /**< column of menu window */ - char *text; /**< menu name */ -}; - -struct agi_menu_option { - struct list_head list; /**< list head for menu options */ - int enabled; /**< option is enabled or disabled */ - int event; /**< menu event */ - int index; /**< number of option in this menu */ - char *text; /**< text of menu option */ -}; - -static LIST_HEAD(menubar); - -static int h_cur_menu; -static int v_cur_menu; - - -static struct agi_menu *get_menu (int i) -{ - struct list_head *h; - struct agi_menu *m; - - list_for_each (h, &menubar, next) { - m = list_entry (h, struct agi_menu, list); - if (m->index == i) - return m; - } - - return NULL; -} - -static struct agi_menu_option *get_menu_option (int i, int j) -{ - struct list_head *h; - struct agi_menu *m; - struct agi_menu_option *d; - - m = get_menu (i); - - list_for_each (h, &m->down, next) { - d = list_entry (h, struct agi_menu_option, list); - if (d->index == j) - return d; - } - - return NULL; -} - -static void draw_menu_bar () -{ - struct list_head *h; - struct agi_menu *m; - - clear_lines (0, 0, MENU_BG); - flush_lines (0, 0); - - list_for_each (h, &menubar, next) { - m = list_entry (h, struct agi_menu, list); - print_text (m->text, 0, m->col, 0, 40, MENU_FG, MENU_BG); - } - -} - -static void draw_menu_hilite (int cur_menu) -{ - struct agi_menu *m; - - m = get_menu (cur_menu); - _D ("[%s]", m->text); - print_text (m->text, 0, m->col, 0, 40, MENU_BG, MENU_FG); - flush_lines (0, 0); -} - -/* draw box and pulldowns. */ -static void draw_menu_option (int h_menu) -{ - struct list_head *h; - struct agi_menu *m = NULL; - struct agi_menu_option *d = NULL; - - /* find which vertical menu it is */ - m = get_menu (h_menu); - - draw_box (m->wincol * CHAR_COLS, 1 * CHAR_LINES, - (m->wincol + m->width + 2) * CHAR_COLS, - (1 + m->height + 2) * CHAR_LINES, MENU_BG, MENU_LINE, 0); - - list_for_each (h, &m->down, next) { - d = list_entry (h, struct agi_menu_option, list); - print_text (d->text, 0, m->wincol + 1, d->index + 2, - m->width + 2, - d->enabled ? MENU_FG : MENU_DISABLED, MENU_BG); - } -} - -static void draw_menu_option_hilite (int h_menu, int v_menu) -{ - struct agi_menu *m; - struct agi_menu_option *d; - - m = get_menu (h_menu); - d = get_menu_option (h_menu, v_menu); - - print_text (d->text, 0, m->wincol + 1, v_menu + 2, m->width + 2, - MENU_BG, d->enabled ? MENU_FG : MENU_DISABLED); -} - - -static void new_menu_selected (i) -{ - show_pic (); - draw_menu_bar (); - draw_menu_hilite (i); - draw_menu_option (i); -} - -#ifdef USE_MOUSE -static int mouse_over_text (unsigned int line, unsigned int col, char *s) -{ - if (mouse.x < col * CHAR_COLS) - return FALSE; - - if (mouse.x > (col + strlen (s)) * CHAR_COLS) - return FALSE; - - if (mouse.y < line * CHAR_LINES) - return FALSE; - - if (mouse.y >= (line + 1) * CHAR_LINES) - return FALSE; - - return TRUE; -} -#endif - -static int h_index; -static int v_index; -static int h_col; -static int h_max_menu; -static int v_max_menu[10]; - - -#if 0 -static void add_about_option () -{ - struct agi_menu *m; - struct agi_menu_option *d; - char text[] = "About Sarien"; - - d = malloc (sizeof (struct agi_menu_option)); - d->text = strdup (text); - d->enabled = TRUE; - d->event = 255; - d->index = (v_max_menu[0] += 1); - - m = list_entry (menubar.next, struct agi_menu, list); - list_add_tail (&d->list, &m->down); - m->height++; - if (m->width < strlen (text)) - m->width = strlen (text); -} -#endif - -/* - * Public functions - */ - -void menu_init () -{ - h_index = 0; - h_col = 1; - h_cur_menu = 0; - v_cur_menu = 0; -} - - -void menu_deinit () -{ - struct list_head *h, *h2, *v, *v2; - struct agi_menu *m = NULL; - struct agi_menu_option *d = NULL; - - for (h = (&menubar)->prev; h != (&menubar); h = h2) { - m = list_entry (h, struct agi_menu, list); - h2 = h->prev; - _D ("deiniting hmenu %s", m->text); - for (v = (&m->down)->prev; v != (&m->down); v = v2) { - d = list_entry (v, struct agi_menu_option, list); - v2 = v->prev; - _D (" deiniting vmenu %s", d->text); - list_del (v); - free (d->text); - free (d); - } - list_del (h); - free (m->text); - free (m); - } -} - - -void menu_add (char *s) -{ - struct agi_menu *m; - - m = malloc (sizeof (struct agi_menu)); - m->text = strdup (s); - while (m->text[strlen(m->text) - 1] == ' ') - m->text[strlen(m->text) - 1] = 0; - m->down.next = &m->down; - m->down.prev = &m->down; - m->width = 0; - m->height = 0; - m->index = h_index++; - m->col = h_col; - m->wincol = h_col - 1; - v_index = 0; - v_max_menu[m->index] = 0; - h_col += strlen (m->text) + 1; - h_max_menu = m->index; - - //_D (_D_WARN "add menu: '%s' %02x", s, m->text[strlen(m->text)]); - list_add_tail (&m->list, &menubar); -} - - -void menu_add_item (char *s, int code) -{ - struct agi_menu *m; - struct agi_menu_option *d; - int l; - - d = malloc (sizeof (struct agi_menu_option)); - d->text = strdup (s); - d->enabled = TRUE; - d->event = code; - d->index = v_index++; - - m = list_entry (menubar.prev, struct agi_menu, list); - m->height++; - - v_max_menu[m->index] = d->index; - - l = strlen (d->text); - if (l > 40) - l = 38; - if (m->wincol + l > 38) - m->wincol = 38 - l; - if (l > m->width) - m->width = l; - - //_D (_D_WARN "Adding menu item: %s (size = %d)", s, m->height); - list_add_tail (&d->list, &m->down); -} - -void menu_submit () -{ - struct list_head *h, *h2; - struct agi_menu *m = NULL; - - //_D (_D_WARN "Submitting menu"); - - /* add_about_option (); */ - - /* If a menu has no options, delete it */ - for (h = (&menubar)->prev; h != (&menubar); h = h2) { - m = list_entry (h, struct agi_menu, list); - h2 = h->prev; - if ((&m->down)->prev == (&m->down)) { - list_del (h); - free (m->text); - free (m); - h_max_menu--; - } - } -} - -int menu_keyhandler (int key) -{ - static int clock_val; - static int menu_active = FALSE; - struct agi_menu_option *d; - struct list_head *h; - struct agi_menu *m; - static int button_used = 0; - - if (!getflag (F_menus_work)) - return FALSE; - - if (!menu_active) { - clock_val = game.clock_enabled; - game.clock_enabled = FALSE; - draw_menu_bar (); - } - -#ifdef USE_MOUSE - /* - * Mouse handling - */ - if (mouse.button) { - int hmenu, vmenu; - - button_used = 1; /* Button has been used at least once */ - if (mouse.y <= CHAR_LINES) { - /* on the menubar */ - hmenu = 0; - - list_for_each (h, &menubar, next) { - m = list_entry (h, struct agi_menu, list); - if (mouse_over_text (0, m->col, m->text)) { - break; - } else { - hmenu++; - } - } - - if (hmenu <= h_max_menu) { - if (h_cur_menu != hmenu) { - v_cur_menu = -1; - new_menu_selected (hmenu); - } - h_cur_menu = hmenu; - } - } else { - /* not in menubar */ - struct agi_menu_option *d; - - vmenu = 0; - - m = get_menu (h_cur_menu); - list_for_each (h, &m->down, next) { - d = list_entry (h, struct agi_menu_option, list); - if (mouse_over_text (2 + d->index, - m->wincol + 1, d->text)) - { - break; - } else { - vmenu++; - } - } - - if (vmenu <= v_max_menu[h_cur_menu]) { - if (v_cur_menu != vmenu) { - draw_menu_option (h_cur_menu); - draw_menu_option_hilite (h_cur_menu, - vmenu); - } - v_cur_menu = vmenu; - } - } - } else if (button_used) { - /* Button released */ - button_used = 0; - - //_D (_D_WARN "button released!"); - - if (v_cur_menu < 0) - v_cur_menu = 0; - - draw_menu_option_hilite (h_cur_menu, v_cur_menu); - - if (mouse.y <= CHAR_LINES) { - /* on the menubar */ - } else { - /* see which option we selected */ - m = get_menu (h_cur_menu); - list_for_each (h, &m->down, next) { - d = list_entry (h, struct agi_menu_option, list); - if (mouse_over_text (2 + d->index, m->wincol + 1, d->text)) { - /* activate that option */ - if (d->enabled) { - _D ("event %d registered", d->event); - game.ev_keyp[d->event].occured = TRUE; - game.ev_keyp[d->event].data = d->event; - goto exit_menu; - } - } - } - goto exit_menu; - } - } -#endif /* USE_MOUSE */ - - if (!menu_active) { - if (h_cur_menu >= 0) { - draw_menu_hilite (h_cur_menu); - draw_menu_option (h_cur_menu); - if (!button_used && v_cur_menu >= 0) - draw_menu_option_hilite(h_cur_menu, v_cur_menu); - } - menu_active = TRUE; - } - - switch (key) { - case KEY_ESCAPE: - //_D (_D_WARN "KEY_ESCAPE"); - goto exit_menu; - case KEY_ENTER: - //_D (_D_WARN "KEY_ENTER"); - d = get_menu_option (h_cur_menu, v_cur_menu); - if (d->enabled) { - _D ("event %d registered", d->event); - game.ev_keyp[d->event].occured = TRUE; - goto exit_menu; - } - break; - case KEY_DOWN: - case KEY_UP: - v_cur_menu += key == KEY_DOWN ? 1 : -1; - - if (v_cur_menu < 0) - v_cur_menu = 0; - if (v_cur_menu > v_max_menu[h_cur_menu]) - v_cur_menu = v_max_menu[h_cur_menu]; - - draw_menu_option (h_cur_menu); - draw_menu_option_hilite (h_cur_menu, v_cur_menu); - break; - case KEY_RIGHT: - case KEY_LEFT: - h_cur_menu += key == KEY_RIGHT ? 1 : -1; - - if (h_cur_menu < 0) - h_cur_menu = h_max_menu; - if (h_cur_menu > h_max_menu) - h_cur_menu = 0; - - v_cur_menu = 0; - new_menu_selected (h_cur_menu); - draw_menu_option_hilite (h_cur_menu, v_cur_menu); - break; - } - - return TRUE; - -exit_menu: - button_used = 0; - show_pic (); - write_status (); - - setvar (V_key, 0); - game.keypress = 0; - game.clock_enabled = clock_val; - old_input_mode (); - //_D (_D_WARN "exit_menu: input mode reset to %d", game.input_mode); - menu_active = FALSE; - - return TRUE; -} - -void menu_set_item (int event, int state) -{ - struct list_head *h, *v; - struct agi_menu *m = NULL; - struct agi_menu_option *d = NULL; - - /* scan all menus for event number # */ - - //_D (_D_WARN "event = %d, state = %d", event, state); - list_for_each (h, &menubar, next) { - m = list_entry (h, struct agi_menu, list); - list_for_each (v, &m->down, next) { - d = list_entry (v, struct agi_menu_option, list); - if (d->event == event) { - d->enabled = state; - return; - } - } - } -} - -void menu_enable_all () -{ - struct list_head *h, *v; - struct agi_menu *m = NULL; - struct agi_menu_option *d = NULL; - - list_for_each (h, &menubar, next) { - m = list_entry (h, struct agi_menu, list); - list_for_each (v, &m->down, next) { - d = list_entry (v, struct agi_menu_option, list); - d->enabled = TRUE; - } - } - -} - -/* end of file: menu.c */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999,2002 Stuart George and Claudio Matsuoka + * + * $Id: menu.c,v 1.59 2003/07/10 20:20:19 bootstrap666 Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "sprite.h" +#include "graphics.h" +#include "keyboard.h" +#include "menu.h" +#include "text.h" +#include "list.h" + + +struct agi_menu { + struct list_head list; /**< list head for menubar list */ + struct list_head down; /**< list head for menu options */ + int index; /**< number of menu in menubar */ + int width; /**< width of menu in characters */ + int height; /**< height of menu in characters */ + int col; /**< column of menubar entry */ + int wincol; /**< column of menu window */ + char *text; /**< menu name */ +}; + +struct agi_menu_option { + struct list_head list; /**< list head for menu options */ + int enabled; /**< option is enabled or disabled */ + int event; /**< menu event */ + int index; /**< number of option in this menu */ + char *text; /**< text of menu option */ +}; + +static LIST_HEAD(menubar); + +static int h_cur_menu; +static int v_cur_menu; + + +static struct agi_menu *get_menu (int i) +{ + struct list_head *h; + struct agi_menu *m; + + list_for_each (h, &menubar, next) { + m = list_entry (h, struct agi_menu, list); + if (m->index == i) + return m; + } + + return NULL; +} + +static struct agi_menu_option *get_menu_option (int i, int j) +{ + struct list_head *h; + struct agi_menu *m; + struct agi_menu_option *d; + + m = get_menu (i); + + list_for_each (h, &m->down, next) { + d = list_entry (h, struct agi_menu_option, list); + if (d->index == j) + return d; + } + + return NULL; +} + +static void draw_menu_bar () +{ + struct list_head *h; + struct agi_menu *m; + + clear_lines (0, 0, MENU_BG); + flush_lines (0, 0); + + list_for_each (h, &menubar, next) { + m = list_entry (h, struct agi_menu, list); + print_text (m->text, 0, m->col, 0, 40, MENU_FG, MENU_BG); + } + +} + +static void draw_menu_hilite (int cur_menu) +{ + struct agi_menu *m; + + m = get_menu (cur_menu); + _D ("[%s]", m->text); + print_text (m->text, 0, m->col, 0, 40, MENU_BG, MENU_FG); + flush_lines (0, 0); +} + +/* draw box and pulldowns. */ +static void draw_menu_option (int h_menu) +{ + struct list_head *h; + struct agi_menu *m = NULL; + struct agi_menu_option *d = NULL; + + /* find which vertical menu it is */ + m = get_menu (h_menu); + + draw_box (m->wincol * CHAR_COLS, 1 * CHAR_LINES, + (m->wincol + m->width + 2) * CHAR_COLS, + (1 + m->height + 2) * CHAR_LINES, MENU_BG, MENU_LINE, 0); + + list_for_each (h, &m->down, next) { + d = list_entry (h, struct agi_menu_option, list); + print_text (d->text, 0, m->wincol + 1, d->index + 2, + m->width + 2, + d->enabled ? MENU_FG : MENU_DISABLED, MENU_BG); + } +} + +static void draw_menu_option_hilite (int h_menu, int v_menu) +{ + struct agi_menu *m; + struct agi_menu_option *d; + + m = get_menu (h_menu); + d = get_menu_option (h_menu, v_menu); + + print_text (d->text, 0, m->wincol + 1, v_menu + 2, m->width + 2, + MENU_BG, d->enabled ? MENU_FG : MENU_DISABLED); +} + + +static void new_menu_selected (i) +{ + show_pic (); + draw_menu_bar (); + draw_menu_hilite (i); + draw_menu_option (i); +} + +#ifdef USE_MOUSE +static int mouse_over_text (unsigned int line, unsigned int col, char *s) +{ + if (mouse.x < col * CHAR_COLS) + return FALSE; + + if (mouse.x > (col + strlen (s)) * CHAR_COLS) + return FALSE; + + if (mouse.y < line * CHAR_LINES) + return FALSE; + + if (mouse.y >= (line + 1) * CHAR_LINES) + return FALSE; + + return TRUE; +} +#endif + +static int h_index; +static int v_index; +static int h_col; +static int h_max_menu; +static int v_max_menu[10]; + + +#if 0 +static void add_about_option () +{ + struct agi_menu *m; + struct agi_menu_option *d; + char text[] = "About Sarien"; + + d = malloc (sizeof (struct agi_menu_option)); + d->text = strdup (text); + d->enabled = TRUE; + d->event = 255; + d->index = (v_max_menu[0] += 1); + + m = list_entry (menubar.next, struct agi_menu, list); + list_add_tail (&d->list, &m->down); + m->height++; + if (m->width < strlen (text)) + m->width = strlen (text); +} +#endif + +/* + * Public functions + */ + +void menu_init () +{ + h_index = 0; + h_col = 1; + h_cur_menu = 0; + v_cur_menu = 0; +} + + +void menu_deinit () +{ + struct list_head *h, *h2, *v, *v2; + struct agi_menu *m = NULL; + struct agi_menu_option *d = NULL; + + for (h = (&menubar)->prev; h != (&menubar); h = h2) { + m = list_entry (h, struct agi_menu, list); + h2 = h->prev; + _D ("deiniting hmenu %s", m->text); + for (v = (&m->down)->prev; v != (&m->down); v = v2) { + d = list_entry (v, struct agi_menu_option, list); + v2 = v->prev; + _D (" deiniting vmenu %s", d->text); + list_del (v); + free (d->text); + free (d); + } + list_del (h); + free (m->text); + free (m); + } +} + + +void menu_add (char *s) +{ + struct agi_menu *m; + + m = malloc (sizeof (struct agi_menu)); + m->text = strdup (s); + while (m->text[strlen(m->text) - 1] == ' ') + m->text[strlen(m->text) - 1] = 0; + m->down.next = &m->down; + m->down.prev = &m->down; + m->width = 0; + m->height = 0; + m->index = h_index++; + m->col = h_col; + m->wincol = h_col - 1; + v_index = 0; + v_max_menu[m->index] = 0; + h_col += strlen (m->text) + 1; + h_max_menu = m->index; + + //_D (_D_WARN "add menu: '%s' %02x", s, m->text[strlen(m->text)]); + list_add_tail (&m->list, &menubar); +} + + +void menu_add_item (char *s, int code) +{ + struct agi_menu *m; + struct agi_menu_option *d; + int l; + + d = malloc (sizeof (struct agi_menu_option)); + d->text = strdup (s); + d->enabled = TRUE; + d->event = code; + d->index = v_index++; + + m = list_entry (menubar.prev, struct agi_menu, list); + m->height++; + + v_max_menu[m->index] = d->index; + + l = strlen (d->text); + if (l > 40) + l = 38; + if (m->wincol + l > 38) + m->wincol = 38 - l; + if (l > m->width) + m->width = l; + + //_D (_D_WARN "Adding menu item: %s (size = %d)", s, m->height); + list_add_tail (&d->list, &m->down); +} + +void menu_submit () +{ + struct list_head *h, *h2; + struct agi_menu *m = NULL; + + //_D (_D_WARN "Submitting menu"); + + /* add_about_option (); */ + + /* If a menu has no options, delete it */ + for (h = (&menubar)->prev; h != (&menubar); h = h2) { + m = list_entry (h, struct agi_menu, list); + h2 = h->prev; + if ((&m->down)->prev == (&m->down)) { + list_del (h); + free (m->text); + free (m); + h_max_menu--; + } + } +} + +int menu_keyhandler (int key) +{ + static int clock_val; + static int menu_active = FALSE; + struct agi_menu_option *d; + struct list_head *h; + struct agi_menu *m; + static int button_used = 0; + + if (!getflag (F_menus_work)) + return FALSE; + + if (!menu_active) { + clock_val = game.clock_enabled; + game.clock_enabled = FALSE; + draw_menu_bar (); + } + +#ifdef USE_MOUSE + /* + * Mouse handling + */ + if (mouse.button) { + int hmenu, vmenu; + + button_used = 1; /* Button has been used at least once */ + if (mouse.y <= CHAR_LINES) { + /* on the menubar */ + hmenu = 0; + + list_for_each (h, &menubar, next) { + m = list_entry (h, struct agi_menu, list); + if (mouse_over_text (0, m->col, m->text)) { + break; + } else { + hmenu++; + } + } + + if (hmenu <= h_max_menu) { + if (h_cur_menu != hmenu) { + v_cur_menu = -1; + new_menu_selected (hmenu); + } + h_cur_menu = hmenu; + } + } else { + /* not in menubar */ + struct agi_menu_option *d; + + vmenu = 0; + + m = get_menu (h_cur_menu); + list_for_each (h, &m->down, next) { + d = list_entry (h, struct agi_menu_option, list); + if (mouse_over_text (2 + d->index, + m->wincol + 1, d->text)) + { + break; + } else { + vmenu++; + } + } + + if (vmenu <= v_max_menu[h_cur_menu]) { + if (v_cur_menu != vmenu) { + draw_menu_option (h_cur_menu); + draw_menu_option_hilite (h_cur_menu, + vmenu); + } + v_cur_menu = vmenu; + } + } + } else if (button_used) { + /* Button released */ + button_used = 0; + + //_D (_D_WARN "button released!"); + + if (v_cur_menu < 0) + v_cur_menu = 0; + + draw_menu_option_hilite (h_cur_menu, v_cur_menu); + + if (mouse.y <= CHAR_LINES) { + /* on the menubar */ + } else { + /* see which option we selected */ + m = get_menu (h_cur_menu); + list_for_each (h, &m->down, next) { + d = list_entry (h, struct agi_menu_option, list); + if (mouse_over_text (2 + d->index, m->wincol + 1, d->text)) { + /* activate that option */ + if (d->enabled) { + _D ("event %d registered", d->event); + game.ev_keyp[d->event].occured = TRUE; + game.ev_keyp[d->event].data = d->event; + goto exit_menu; + } + } + } + goto exit_menu; + } + } +#endif /* USE_MOUSE */ + + if (!menu_active) { + if (h_cur_menu >= 0) { + draw_menu_hilite (h_cur_menu); + draw_menu_option (h_cur_menu); + if (!button_used && v_cur_menu >= 0) + draw_menu_option_hilite(h_cur_menu, v_cur_menu); + } + menu_active = TRUE; + } + + switch (key) { + case KEY_ESCAPE: + //_D (_D_WARN "KEY_ESCAPE"); + goto exit_menu; + case KEY_ENTER: + //_D (_D_WARN "KEY_ENTER"); + d = get_menu_option (h_cur_menu, v_cur_menu); + if (d->enabled) { + _D ("event %d registered", d->event); + game.ev_keyp[d->event].occured = TRUE; + goto exit_menu; + } + break; + case KEY_DOWN: + case KEY_UP: + v_cur_menu += key == KEY_DOWN ? 1 : -1; + + if (v_cur_menu < 0) + v_cur_menu = 0; + if (v_cur_menu > v_max_menu[h_cur_menu]) + v_cur_menu = v_max_menu[h_cur_menu]; + + draw_menu_option (h_cur_menu); + draw_menu_option_hilite (h_cur_menu, v_cur_menu); + break; + case KEY_RIGHT: + case KEY_LEFT: + h_cur_menu += key == KEY_RIGHT ? 1 : -1; + + if (h_cur_menu < 0) + h_cur_menu = h_max_menu; + if (h_cur_menu > h_max_menu) + h_cur_menu = 0; + + v_cur_menu = 0; + new_menu_selected (h_cur_menu); + draw_menu_option_hilite (h_cur_menu, v_cur_menu); + break; + } + + return TRUE; + +exit_menu: + button_used = 0; + show_pic (); + write_status (); + + setvar (V_key, 0); + game.keypress = 0; + game.clock_enabled = clock_val; + old_input_mode (); + //_D (_D_WARN "exit_menu: input mode reset to %d", game.input_mode); + menu_active = FALSE; + + return TRUE; +} + +void menu_set_item (int event, int state) +{ + struct list_head *h, *v; + struct agi_menu *m = NULL; + struct agi_menu_option *d = NULL; + + /* scan all menus for event number # */ + + //_D (_D_WARN "event = %d, state = %d", event, state); + list_for_each (h, &menubar, next) { + m = list_entry (h, struct agi_menu, list); + list_for_each (v, &m->down, next) { + d = list_entry (v, struct agi_menu_option, list); + if (d->event == event) { + d->enabled = state; + return; + } + } + } +} + +void menu_enable_all () +{ + struct list_head *h, *v; + struct agi_menu *m = NULL; + struct agi_menu_option *d = NULL; + + list_for_each (h, &menubar, next) { + m = list_entry (h, struct agi_menu, list); + list_for_each (v, &m->down, next) { + d = list_entry (v, struct agi_menu_option, list); + d->enabled = TRUE; + } + } + +} + +/* end of file: menu.c */ + diff --git a/motion.c b/motion.c index d0220c1..b4b1d00 100644 --- a/motion.c +++ b/motion.c @@ -1,230 +1,230 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: motion.c,v 1.11 2002/11/05 19:03:28 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include "sarien.h" -#include "agi.h" -#include "rand.h" - - -static int check_step (int delta, int step) -{ - return (-step >= delta) ? 0 : (step <= delta) ? 2 : 1; -} - -static int check_block (int x, int y) -{ - if (x <= game.block.x1 || x >= game.block.x2) - return FALSE; - - if (y <= game.block.y1 || y >= game.block.y2) - return FALSE; - - return TRUE; -} - -static void changepos (struct vt_entry *v) -{ - int b, x, y; - int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; - int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 }; - - x = v->x_pos; - y = v->y_pos; - b = check_block (x, y); - - x += v->step_size * dx[v->direction]; - y += v->step_size * dy[v->direction]; - - if (check_block (x, y) == b) { - v->flags &= ~MOTION; - } else { - v->flags |= MOTION; - v->direction = 0; - if_is_ego_view (v) - game.vars[V_ego_dir] = 0; - } -} - -static void motion_wander (struct vt_entry *v) -{ - if (v->parm1--) { - if (~v->flags & DIDNT_MOVE) - return; - } - - v->direction = rnd (9); - - if_is_ego_view (v) { - game.vars[V_ego_dir] = v->direction; - while (v->parm1 < 6) { - v->parm1 = rnd (51); /* huh? */ - } - } -} - -static void motion_followego (struct vt_entry *v) -{ - int ego_x, ego_y; - int obj_x, obj_y; - int dir; - - ego_x = game.view_table[0].x_pos + game.view_table[0].x_size / 2; - ego_y = game.view_table[0].y_pos; - - obj_x = v->x_pos + v->x_size / 2; - obj_y = v->y_pos; - - /* Get direction to reach ego */ - dir = get_direction (obj_x, obj_y, ego_x, ego_y, v->parm1); - - /* Already at ego coordinates */ - if (dir == 0) { - v->direction = 0; - v->motion = MOTION_NORMAL; - setflag (v->parm2, TRUE); - return; - } - - if (v->parm3 == 0xff) { - v->parm3 = 0; - } else if (v->flags & DIDNT_MOVE) { - int d; - - while ((v->direction = rnd (9)) == 0) {} - - d = (abs (ego_y - obj_y) + abs (ego_x - obj_x)) / 2 + 1; - - if (d <= v->step_size) { - v->parm3 = v->step_size; - return; - } - - while ((v->parm3 = rnd (d)) < v->step_size) {} - return; - } - - if (v->parm3 != 0) { - int k; - - /* DF: this is ugly and I dont know why this works, but - * other line does not! (watcom complained about lvalue) - * - * if (((SINT8)v->parm3 -= v->step_size) < 0) - * v->parm3 = 0; - */ - k = v->parm3; - k -= v->step_size; - v->parm3 = k; - - if ((SINT8)v->parm3 < 0) - v->parm3 = 0; - } else { - v->direction = dir; - } -} - -static void motion_moveobj (struct vt_entry *v) -{ - v->direction = get_direction (v->x_pos, v->y_pos, v->parm1, - v->parm2, v->step_size); - - /* Update V6 if ego */ - if_is_ego_view (v) - game.vars[V_ego_dir] = v->direction; - - if (v->direction == 0) - in_destination (v); -} - -static void check_motion (struct vt_entry *v) -{ - switch (v->motion) { - case MOTION_WANDER: - motion_wander (v); - break; - case MOTION_FOLLOW_EGO: - motion_followego (v); - break; - case MOTION_MOVE_OBJ: - motion_moveobj (v); - break; - } - - if ((game.block.active && (~v->flags & IGNORE_BLOCKS)) && v->direction) - changepos (v); -} - - -/* - * Public functions - */ - -/** - * - */ -void check_all_motions () -{ - struct vt_entry *v; - - for_each_vt_entry (v) { - if ((v->flags & (ANIMATED|UPDATE|DRAWN)) == - (ANIMATED|UPDATE|DRAWN) && v->step_time_count == 1) - { - check_motion (v); - } - } -} - -/** - * Check if given entry is at destination point. - * This function is used to updated the flags of an object with move.obj - * type motion that * has reached its final destination coordinates. - * @param v Pointer to view table entry - */ -void in_destination (struct vt_entry *v) -{ - if (v->motion == MOTION_MOVE_OBJ) { - v->step_size = v->parm3; - setflag (v->parm4, TRUE); - } - v->motion = MOTION_NORMAL; - if_is_ego_view (v) - game.player_control = TRUE; -} - -/** - * Wrapper for static function motion_moveobj(). - * This function is used by cmd_move_object() in the first motion cycle - * after setting the motion mode to MOTION_MOVE_OBJ. - * @param v Pointer to view table entry - */ -void move_obj (struct vt_entry *v) -{ - motion_moveobj (v); -} - -/** - * Get direction from motion coordinates - * This function gets the motion direction from the current and previous - * object coordinates and the step size. - * @param x0 Original x coordinate of the object - * @param y0 Original y coordinate of the object - * @param x x coordinate of the object - * @param y y coordinate of the object - * @param s step size - */ -int get_direction (int x0, int y0, int x, int y, int s) -{ - int dir_table[9] = { 8, 1, 2, 7, 0, 3, 6, 5, 4 }; - return dir_table [check_step(x - x0, s) + 3 * check_step(y - y0, s)]; -} - -/* end: motion.c */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: motion.c,v 1.11 2002/11/05 19:03:28 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include "sarien.h" +#include "agi.h" +#include "rand.h" + + +static int check_step (int delta, int step) +{ + return (-step >= delta) ? 0 : (step <= delta) ? 2 : 1; +} + +static int check_block (int x, int y) +{ + if (x <= game.block.x1 || x >= game.block.x2) + return FALSE; + + if (y <= game.block.y1 || y >= game.block.y2) + return FALSE; + + return TRUE; +} + +static void changepos (struct vt_entry *v) +{ + int b, x, y; + int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; + int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 }; + + x = v->x_pos; + y = v->y_pos; + b = check_block (x, y); + + x += v->step_size * dx[v->direction]; + y += v->step_size * dy[v->direction]; + + if (check_block (x, y) == b) { + v->flags &= ~MOTION; + } else { + v->flags |= MOTION; + v->direction = 0; + if_is_ego_view (v) + game.vars[V_ego_dir] = 0; + } +} + +static void motion_wander (struct vt_entry *v) +{ + if (v->parm1--) { + if (~v->flags & DIDNT_MOVE) + return; + } + + v->direction = rnd (9); + + if_is_ego_view (v) { + game.vars[V_ego_dir] = v->direction; + while (v->parm1 < 6) { + v->parm1 = rnd (51); /* huh? */ + } + } +} + +static void motion_followego (struct vt_entry *v) +{ + int ego_x, ego_y; + int obj_x, obj_y; + int dir; + + ego_x = game.view_table[0].x_pos + game.view_table[0].x_size / 2; + ego_y = game.view_table[0].y_pos; + + obj_x = v->x_pos + v->x_size / 2; + obj_y = v->y_pos; + + /* Get direction to reach ego */ + dir = get_direction (obj_x, obj_y, ego_x, ego_y, v->parm1); + + /* Already at ego coordinates */ + if (dir == 0) { + v->direction = 0; + v->motion = MOTION_NORMAL; + setflag (v->parm2, TRUE); + return; + } + + if (v->parm3 == 0xff) { + v->parm3 = 0; + } else if (v->flags & DIDNT_MOVE) { + int d; + + while ((v->direction = rnd (9)) == 0) {} + + d = (abs (ego_y - obj_y) + abs (ego_x - obj_x)) / 2 + 1; + + if (d <= v->step_size) { + v->parm3 = v->step_size; + return; + } + + while ((v->parm3 = rnd (d)) < v->step_size) {} + return; + } + + if (v->parm3 != 0) { + int k; + + /* DF: this is ugly and I dont know why this works, but + * other line does not! (watcom complained about lvalue) + * + * if (((SINT8)v->parm3 -= v->step_size) < 0) + * v->parm3 = 0; + */ + k = v->parm3; + k -= v->step_size; + v->parm3 = k; + + if ((SINT8)v->parm3 < 0) + v->parm3 = 0; + } else { + v->direction = dir; + } +} + +static void motion_moveobj (struct vt_entry *v) +{ + v->direction = get_direction (v->x_pos, v->y_pos, v->parm1, + v->parm2, v->step_size); + + /* Update V6 if ego */ + if_is_ego_view (v) + game.vars[V_ego_dir] = v->direction; + + if (v->direction == 0) + in_destination (v); +} + +static void check_motion (struct vt_entry *v) +{ + switch (v->motion) { + case MOTION_WANDER: + motion_wander (v); + break; + case MOTION_FOLLOW_EGO: + motion_followego (v); + break; + case MOTION_MOVE_OBJ: + motion_moveobj (v); + break; + } + + if ((game.block.active && (~v->flags & IGNORE_BLOCKS)) && v->direction) + changepos (v); +} + + +/* + * Public functions + */ + +/** + * + */ +void check_all_motions () +{ + struct vt_entry *v; + + for_each_vt_entry (v) { + if ((v->flags & (ANIMATED|UPDATE|DRAWN)) == + (ANIMATED|UPDATE|DRAWN) && v->step_time_count == 1) + { + check_motion (v); + } + } +} + +/** + * Check if given entry is at destination point. + * This function is used to updated the flags of an object with move.obj + * type motion that * has reached its final destination coordinates. + * @param v Pointer to view table entry + */ +void in_destination (struct vt_entry *v) +{ + if (v->motion == MOTION_MOVE_OBJ) { + v->step_size = v->parm3; + setflag (v->parm4, TRUE); + } + v->motion = MOTION_NORMAL; + if_is_ego_view (v) + game.player_control = TRUE; +} + +/** + * Wrapper for static function motion_moveobj(). + * This function is used by cmd_move_object() in the first motion cycle + * after setting the motion mode to MOTION_MOVE_OBJ. + * @param v Pointer to view table entry + */ +void move_obj (struct vt_entry *v) +{ + motion_moveobj (v); +} + +/** + * Get direction from motion coordinates + * This function gets the motion direction from the current and previous + * object coordinates and the step size. + * @param x0 Original x coordinate of the object + * @param y0 Original y coordinate of the object + * @param x x coordinate of the object + * @param y y coordinate of the object + * @param s step size + */ +int get_direction (int x0, int y0, int x, int y, int s) +{ + int dir_table[9] = { 8, 1, 2, 7, 0, 3, 6, 5, 4 }; + return dir_table [check_step(x - x0, s) + 3 * check_step(y - y0, s)]; +} + +/* end: motion.c */ + diff --git a/nothing.c b/nothing.c deleted file mode 100644 index d9eb5b7..0000000 --- a/nothing.c +++ /dev/null @@ -1,8 +0,0 @@ -//GCC doesnt seem to do this correctly?! - -#ifdef NEED_NOTHING -void nothing(){} -#endif - - - diff --git a/nullvid.c b/nullvid.c index 20a6b74..3b8a59d 100644 --- a/nullvid.c +++ b/nullvid.c @@ -1,586 +1,506 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: pcvga.c,v 1.5 2002/11/16 01:20:21 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as pufblished by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#define INCL_DOS -#define INCL_WIN -#define INCL_GPI -#define INCL_WINHEAP -#define INCL_WINDIALOGS -#define INCL_GPIPRIMITIVES -#define INCL_DOSPROCESS -#define INCL_DOSQUEUES -#define INCL_DOSERRORS - -#include -#include -#include -#include -#include -////////////////////////////////////////////////////////////// -#define NUM_MASSES_X 320u -#define NUM_MASSES_Y 200u - -HAB hab; -HAB habt; -HWND hwndFrame, hwndClient; -HDC hdc, hdcMemory; -HPS hps, hpsMemory; -HMTX hmtxLock; -TID tidMain; -TID tidTimer; -TID tidBeeper; - -#define STACK 8192 /* Stack size for thread */ - -BOOL ModelSuspended = FALSE; -HBITMAP hbm; -BITMAPINFOHEADER2 bmih; -BITMAPINFOHEADER2 bmp2data; -PBITMAPINFO2 pbmi; -BYTE RGBmap[32]; -BYTE Bitmap[NUM_MASSES_X*NUM_MASSES_Y]; -POINTL aptl[3] = - { {0u, 0u}, {NUM_MASSES_X, NUM_MASSES_Y}, {0u, 0u} }; - -MRESULT EXPENTRY window_func(HWND, ULONG, MPARAM, MPARAM); -void Model(ULONG); -void PrepareGraphics(BYTE *); -void DisplayPlane(float **current); - -#define CGA_00 0x000000 -#define CGA_01 0x0000AA -#define CGA_02 0x00AA00 -#define CGA_03 0x00AAAA -#define CGA_04 0xAA0000 -#define CGA_05 0xAA00AA -#define CGA_06 0xAA5500 -#define CGA_07 0xAAAAAA -#define CGA_08 0x555555 -#define CGA_09 0x5555FF -#define CGA_10 0x55FF55 -#define CGA_11 0x55FFFF -#define CGA_12 0xFF5555 -#define CGA_13 0xFF55FF -#define CGA_14 0xFFFF55 -#define CGA_15 0xFFFFFF - -static unsigned char cga_map[16] = { - 0x00, /* 0 - black */ - 0x01, /* 1 - blue */ - 0x01, /* 2 - green */ - 0x01, /* 3 - cyan */ - 0x02, /* 4 - red */ - 0x02, /* 5 - magenta */ - 0x02, /* 6 - brown */ - 0x03, /* 7 - gray */ - 0x00, /* 8 - dark gray */ - 0x01, /* 9 - light blue */ - 0x01, /* 10 - light green */ - 0x01, /* 11 - light cyan */ - 0x02, /* 12 - light red */ - 0x02, /* 13 - light magenta */ - 0x02, /* 14 - yellow */ - 0x03 /* 15 - white */ -}; - -static unsigned int key_from; -static int pm_keypress; - -static int draw_frame; -static int draw_frame_skip; - -#define KEY_ENTER 0x0D -#define KEY_UP 0x4800 -#define KEY_DOWN 0x5000 -#define KEY_LEFT 0x4B00 -#define KEY_RIGHT 0x4D00 -#define KEY_BACKSPACE 0x08 -#define KEY_ESCAPE 0x1B -#define KEY_ENTER 0x0D - - -PSZ szQueueName = "\\QUEUES\\SARIEN.QUE"; -HQUEUE hqSpecialQue = 0; -#define QUE_CONVERT_ADDRESS 0x00000004 -////////////////////////////////////////////////////////////// - -#include "sarien.h" -#include "graphics.h" - -extern struct gfx_driver *gfx; -extern struct sarien_options opt; - -UINT8 *exec_name; -static UINT8 *screen_buffer; - -static int pc_init_vidmode (void); -static int pc_deinit_vidmode (void); -static void pc_put_block (int, int, int, int); -static void pc_put_pixels (int, int, int, UINT8 *); -static void pc_timer (void); -static int pc_get_key (void); -static int pc_keypress (void); - - -#define TICK_SECONDS 18 - -static struct gfx_driver gfx_pcvga = { - pc_init_vidmode, - pc_deinit_vidmode, - pc_put_block, - pc_put_pixels, - pc_timer, - pc_keypress, - pc_get_key -}; - -typedef struct { - int freq; - int duration; - }QueueBeep; - - -void Beeper(){ - -PID pidOwner=0; -REQUESTDATA Request = {0}; -//PSZ DataBuffer = ""; -int* DataBuffer; -BYTE ElemPrty = 0; -ULONG ulDataLen = 0; -int rc; -QueueBeep mybeep; - -rc=DosOpenQueue(&pidOwner,&hqSpecialQue,szQueueName); -if(rc!=NO_ERROR) { - printf("Error with thread openeing Queue %s\n",szQueueName); - exit(-1); - } -for(;;) { - rc=DosReadQueue(hqSpecialQue, - &Request, - &ulDataLen, - (PVOID) &DataBuffer, - 0L, - DCWW_WAIT, - &ElemPrty, - 0L); - if(rc!=ERROR_QUE_EMPTY) { - - mybeep.freq=(int)DataBuffer; - *DataBuffer++; - mybeep.duration=(int)DataBuffer; //9 100 - DosBeep(mybeep.freq/7,mybeep.duration/100); - } -// DosSleep(32L); - } -} - -void SendBeep(int freq,int duration) { -QueueBeep mybeep; -mybeep.freq=freq; -mybeep.duration=duration; - -DosWriteQueue (hqSpecialQue, - 12345L, - sizeof(freq), - freq, - 0L); -DosWriteQueue (hqSpecialQue, - 12345L, - sizeof(duration), - duration, - 0L); -} - -void Timer(){ -for(;;) { - DosSleep(20L); - clock_ticks++; - } -} - -static void pc_timer () -{ - static UINT32 cticks = 0; - - while (cticks == clock_ticks){DosSleep(5);} - cticks = clock_ticks; - //draw_frame++; -} - - -int init_machine () //(int argc, char **argv) -{ - gfx = &gfx_pcvga; - opt.cgaemu = TRUE; - return err_OK; -} - - -int deinit_machine () -{ - return err_OK; -} - - -static int pc_init_vidmode () -{ - int i; - - clock_count = 0; - clock_ticks = 0; - pm_keypress = 0; - - screen_buffer = calloc (GFX_WIDTH, GFX_HEIGHT); - - return err_OK; -} - - -static int pc_deinit_vidmode () -{ - free (screen_buffer); - - return err_OK; -} - - -/* blit a block onto the screen */ -static void pc_put_block (int x1, int y1, int x2, int y2) -{ - int x, y; - int disp_val; - - for (y = 0; y < NUM_MASSES_Y; y++) - { - for (x = 0; x < GFX_WIDTH; x++) - { - disp_val = ((int) screen_buffer[y*GFX_WIDTH+x]); //+ 16); - if (disp_val > 32) disp_val = 32; - else if (disp_val < 0) disp_val = 0; - Bitmap[((NUM_MASSES_Y-y)*(GFX_WIDTH))-(GFX_WIDTH-x)] = RGBmap[disp_val]; - } - } - // skip frame happens here - // for some reason it constantly stalls. - // have to keep hitting enter :( - // if(draw_frame>draw_frame_skip) { - - DosRequestMutexSem(hmtxLock, SEM_INDEFINITE_WAIT); - - /* This is the key to the speed. Instead of doing a GPI call to set the - color and a GPI call to set the pixel for EACH pixel, we get by - with only two GPI calls. */ - GpiSetBitmapBits(hpsMemory, 0L, (LONG) (NUM_MASSES_Y-2), &Bitmap[0], pbmi); - GpiBitBlt(hps, hpsMemory, 3L, aptl, ROP_SRCCOPY, BBO_AND); - - DosReleaseMutexSem(hmtxLock); -} - - -static void pc_put_pixels(int x, int y, int w, UINT8 *p) -{ - UINT8 *s; - for (s = &screen_buffer[y * 320 + x]; w--; *s++ = *p++); -} - - -static int pc_keypress () -{ -return (pm_keypress); -} - - -static int pc_get_key () -{ -if(pm_keypress) { - pm_keypress = 0; - return key_from; - } -else -return 0; -} - - -int OLDmain (int argc, char *argv[]); -////////////////////////////////////////////////////////////// - -int main(int argc, char *argv[]) -{ - HMQ hmq; - QMSG qmsg; - ULONG flFlags; - unsigned char class[]="MyClass"; - int rc; - - flFlags = FCF_TITLEBAR | - FCF_MINBUTTON | - FCF_TASKLIST | - FCF_SYSMENU; - - if ((hab = WinInitialize(0)) == 0) - { - printf("Error doing WinInitialize()\n"); - exit(1); - } - if ((hmq = WinCreateMsgQueue(hab, 0)) == (HMQ) NULL) - { - printf("Error doing WinCreateMsgQueue()\n"); - exit(1); - } - if (!WinRegisterClass(hab, (PSZ) class, (PFNWP) window_func, - CS_SIZEREDRAW, 0)) - { - printf("Error doing WinRegisterClass()\n"); - exit(1); - } - if ((hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &flFlags, - (PSZ) class, (PSZ) "Sarien 0.8.0-j2me", - WS_VISIBLE, 0, 0, &hwndClient)) == 0) - { - printf("Error doing WinCreateStdWindow()\n"); - exit(1); - } - WinSetWindowPos(hwndFrame, 0L, - (SHORT) (60), - (SHORT) (WinQuerySysValue(HWND_DESKTOP, - SV_CYSCREEN) - (NUM_MASSES_Y+60)), - (SHORT) GFX_WIDTH, - (SHORT) NUM_MASSES_Y + WinQuerySysValue(HWND_DESKTOP, - SV_CYTITLEBAR) - 2, SWP_SIZE | SWP_MOVE); - - /* Work out mapping from bitmap color table to our logical palette. */ - PrepareGraphics(RGBmap); - - /* Create a semaphore to control access to the memory image - presentation space. Only one thread can perform Gpi operations - on it at a time. */ - rc=DosCreateMutexSem("\\sem32\\Lock", &hmtxLock, 0, FALSE); - if(rc!=NO_ERROR) { - printf("DosCreateMutexSem \\sem32\\Lock returned error\n"); - exit (-1); - } - - DosCreateQueue(&hqSpecialQue,QUE_FIFO,szQueueName); - if(rc!=NO_ERROR) { - printf("DosCreateQueue %s returned error\n",szQueueName); - exit (-1); - } - - /* Create a thread to run the system model. */ - DosCreateThread(&tidMain,OLDmain, 0UL, 0UL, STACK); - DosCreateThread(&tidTimer,Timer, 0UL, 0UL, STACK); - DosCreateThread(&tidBeeper,Beeper, 0UL, 0UL, STACK); - -/* draw_frame=1000; - draw_frame_skip=2; - if(argc>1) - draw_frame_skip=atoi(argv[1]); */ - - while (WinGetMsg(hab, &qmsg, (HWND) NULL, 0, 0)) - { - WinDispatchMsg(hab, &qmsg); - } - WinDestroyWindow(hwndFrame); - WinDestroyMsgQueue(hmq); - WinTerminate(hab); -} -////////////////////////////////////////////////////////////// - - -MRESULT EXPENTRY -window_func(HWND handle, ULONG mess, MPARAM parm1, MPARAM parm2) -{ - int i; - LONG j; - SIZEL sizl; - LONG OS2palette[33]; - - - switch(mess) - { - case WM_CREATE: - /* Create presentation space for screen. */ - hdc = WinOpenWindowDC(handle); - sizl.cx = 0; - sizl.cy = 0; - hps = GpiCreatePS(hab, hdc, &sizl, - PU_PELS | GPIT_MICRO | GPIA_ASSOC | GPIF_DEFAULT); - - /* Create presentation space for memory image of screen. */ - hdcMemory = DevOpenDC(hab, OD_MEMORY, (PSZ) "*", 0L, 0L, 0L); - sizl.cx = 0; - sizl.cy = 0; - hpsMemory = GpiCreatePS(hab, hdcMemory, &sizl, - PU_PELS | GPIT_MICRO | GPIA_ASSOC | GPIF_DEFAULT); - - /* Create bitmap for memory image of screen. */ - memset(&bmih, 0, sizeof(bmih)); - bmih.cbFix = sizeof(bmih); - bmih.cx = NUM_MASSES_X; - bmih.cy = NUM_MASSES_Y; - bmih.cPlanes = 1; - bmih.cBitCount = 8; - hbm = GpiCreateBitmap(hpsMemory, &bmih, 0L, NULL, NULL); - GpiSetBitmap(hpsMemory, hbm); - - /* Set up gray-scale palette for screen image. */ - for (i = 0; i < 32; i++) - { - j = i << 3; - OS2palette[i] = CGA_00; //(j << 16) | (j << 8) | j; - } - OS2palette[0]=CGA_00; - OS2palette[1]=CGA_11; - OS2palette[2]=CGA_11; - OS2palette[3]=CGA_11; - OS2palette[4]=CGA_13; - OS2palette[5]=CGA_13; - OS2palette[6]=CGA_13; - OS2palette[7]=CGA_15; - OS2palette[8]=CGA_00; - OS2palette[9]=CGA_11; - OS2palette[10]=CGA_11; - OS2palette[11]=CGA_11; - OS2palette[12]=CGA_13; - OS2palette[13]=CGA_13; - OS2palette[14]=CGA_13; - OS2palette[15]=CGA_15; - - OS2palette[16]=CGA_00; - OS2palette[17]=CGA_11; - OS2palette[18]=CGA_11; - OS2palette[19]=CGA_11; - OS2palette[20]=CGA_13; - OS2palette[21]=CGA_13; - OS2palette[22]=CGA_13; - OS2palette[23]=CGA_15; - OS2palette[24]=CGA_00; - OS2palette[25]=CGA_11; - OS2palette[26]=CGA_11; - OS2palette[27]=CGA_11; - OS2palette[28]=CGA_13; - OS2palette[29]=CGA_13; - OS2palette[30]=CGA_13; - OS2palette[31]=CGA_15; - - OS2palette[32] = 0x00ffffffL; - - - GpiCreateLogColorTable(hpsMemory, (ULONG) LCOL_PURECOLOR, - (LONG) LCOLF_CONSECRGB, (LONG) 0L, (LONG) 33L, (PLONG) OS2palette); - GpiSetBackMix(hpsMemory, BM_OVERPAINT); - - /* Take the input focus. */ - WinFocusChange(HWND_DESKTOP, handle, 0L); - break; - - case WM_ERASEBACKGROUND: - case WM_PAINT: - /* Copy the memory image of the screen out to the real screen. */ - //This gets called when you move the window, or something pops up - DosRequestMutexSem(hmtxLock, SEM_INDEFINITE_WAIT); - WinBeginPaint(handle, hps, NULL); - GpiBitBlt(hps, hpsMemory, 3L, aptl, ROP_SRCCOPY, BBO_AND); - WinEndPaint(hps); - DosReleaseMutexSem(hmtxLock); - break; - - case WM_CHAR: - if (SHORT1FROMMP(parm1) & KC_KEYUP) - break; -pm_keypress=1; - - switch (SHORT2FROMMP(parm2)) - { - - case VK_LEFT: - key_from=KEY_LEFT; - break; - case VK_RIGHT: - key_from=KEY_RIGHT; - break; - case VK_UP: - key_from=KEY_UP; - break; - case VK_DOWN: - key_from=KEY_DOWN; - break; - case VK_ESC: - key_from=KEY_ESCAPE; - break; - - default: - key_from=SHORT1FROMMP(parm2); - break; - - } - break; - default: - return WinDefWindowProc(handle, mess, parm1, parm2); - } - return (MRESULT) FALSE; -} - - -void -PrepareGraphics(BYTE *RGBmap) -{ - POINTL coords; - int x, y; - - /* Give thread access to Gpi. */ - habt = WinInitialize(0); - - /* Determine mapping from logical color value to bitmap color table - index. Anybody know a more direct way??? */ - DosRequestMutexSem(hmtxLock, SEM_INDEFINITE_WAIT); - for (x = 0, y = 0; x < 33; x++) - { - GpiSetColor(hpsMemory, (LONG) x); - coords.x = x; - coords.y = y; - GpiSetPel(hpsMemory, &coords); - } - bmp2data.cbFix = 16L; - GpiQueryBitmapInfoHeader(hbm, &bmp2data); - DosAllocMem((PPVOID)&pbmi, sizeof(BITMAPINFO2) + - (sizeof(RGB2) * (1 << bmp2data.cPlanes) * - (1 << bmp2data.cBitCount)), - PAG_COMMIT | PAG_READ | PAG_WRITE); - pbmi->cbFix = bmp2data.cbFix; - pbmi->cx = bmp2data.cx; - pbmi->cy = bmp2data.cy; - pbmi->cPlanes = bmp2data.cPlanes; - pbmi->cBitCount = bmp2data.cBitCount; - pbmi->ulCompression = bmp2data.ulCompression; - pbmi->cbImage = bmp2data.cbImage; - pbmi->cxResolution = bmp2data.cxResolution; - pbmi->cyResolution = bmp2data.cyResolution; - pbmi->cclrUsed = bmp2data.cclrUsed; - pbmi->cclrImportant = bmp2data.cclrImportant; - pbmi->usUnits = bmp2data.usUnits; - pbmi->usReserved = bmp2data.usReserved; - pbmi->usRecording = bmp2data.usRecording; - pbmi->usRendering = bmp2data.usRendering; - pbmi->cSize1 = bmp2data.cSize1; - pbmi->cSize2 = bmp2data.cSize2; - pbmi->ulColorEncoding = bmp2data.ulColorEncoding; - pbmi->ulIdentifier = bmp2data.ulIdentifier; - GpiQueryBitmapBits(hpsMemory, 0L, NUM_MASSES_Y-2, &Bitmap[0], pbmi); - DosReleaseMutexSem(hmtxLock); - for (x = 0; x < 33; x++) - { - RGBmap[x] = Bitmap[x]; - } -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: pcvga.c,v 1.5 2002/11/16 01:20:21 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as pufblished by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#define INCL_DOS +#define INCL_WIN +#define INCL_GPI +#define INCL_WINHEAP +#define INCL_WINDIALOGS +#define INCL_GPIPRIMITIVES +#define INCL_DOSPROCESS + +#include +#include +#include +#include +#include +////////////////////////////////////////////////////////////// +#define NUM_MASSES_X 320u +#define NUM_MASSES_Y 200u + +HAB hab; +HAB habt; +HWND hwndFrame, hwndClient; +HDC hdc, hdcMemory; +HPS hps, hpsMemory; +HMTX hmtxLock; +TID tidMain; +TID tidTimer; + +#define STACK 8192 /* Stack size for thread */ + +BOOL ModelSuspended = FALSE; +HBITMAP hbm; +BITMAPINFOHEADER2 bmih; +BITMAPINFOHEADER2 bmp2data; +PBITMAPINFO2 pbmi; +BYTE RGBmap[32]; +BYTE Bitmap[NUM_MASSES_X*NUM_MASSES_Y]; +POINTL aptl[3] = + { {0u, 0u}, {NUM_MASSES_X, NUM_MASSES_Y}, {0u, 0u} }; + +MRESULT EXPENTRY window_func(HWND, ULONG, MPARAM, MPARAM); +void Model(ULONG); +void PrepareGraphics(BYTE *); +void DisplayPlane(float **current); + +#define CGA_00 0x000000 +#define CGA_01 0x0000AA +#define CGA_02 0x00AA00 +#define CGA_03 0x00AAAA +#define CGA_04 0xAA0000 +#define CGA_05 0xAA00AA +#define CGA_06 0xAA5500 +#define CGA_07 0xAAAAAA +#define CGA_08 0x555555 +#define CGA_09 0x5555FF +#define CGA_10 0x55FF55 +#define CGA_11 0x55FFFF +#define CGA_12 0xFF5555 +#define CGA_13 0xFF55FF +#define CGA_14 0xFFFF55 +#define CGA_15 0xFFFFFF + +static unsigned char cga_map[16] = { + 0x00, /* 0 - black */ + 0x01, /* 1 - blue */ + 0x01, /* 2 - green */ + 0x01, /* 3 - cyan */ + 0x02, /* 4 - red */ + 0x02, /* 5 - magenta */ + 0x02, /* 6 - brown */ + 0x03, /* 7 - gray */ + 0x00, /* 8 - dark gray */ + 0x01, /* 9 - light blue */ + 0x01, /* 10 - light green */ + 0x01, /* 11 - light cyan */ + 0x02, /* 12 - light red */ + 0x02, /* 13 - light magenta */ + 0x02, /* 14 - yellow */ + 0x03 /* 15 - white */ +}; + +static unsigned int key_from; +static int pm_keypress; + +static int draw_frame; +static int draw_frame_skip; + +#define KEY_ENTER 0x0D +#define KEY_UP 0x4800 +#define KEY_DOWN 0x5000 +#define KEY_LEFT 0x4B00 +#define KEY_RIGHT 0x4D00 +#define KEY_BACKSPACE 0x08 +#define KEY_ESCAPE 0x1B +#define KEY_ENTER 0x0D + + +////////////////////////////////////////////////////////////// + +#include "sarien.h" +#include "graphics.h" + +extern struct gfx_driver *gfx; +extern struct sarien_options opt; + +UINT8 *exec_name; +static UINT8 *screen_buffer; + +static int pc_init_vidmode (void); +static int pc_deinit_vidmode (void); +static void pc_put_block (int, int, int, int); +static void pc_put_pixels (int, int, int, UINT8 *); +static void pc_timer (void); +static int pc_get_key (void); +static int pc_keypress (void); + + +#define TICK_SECONDS 18 + +static struct gfx_driver gfx_pcvga = { + pc_init_vidmode, + pc_deinit_vidmode, + pc_put_block, + pc_put_pixels, + pc_timer, + pc_keypress, + pc_get_key +}; + +void Timer(){ +for(;;) { + DosSleep(20L); + clock_ticks++; + } +} + +static void pc_timer () +{ + static UINT32 cticks = 0; + + while (cticks == clock_ticks){DosSleep(5);} + cticks = clock_ticks; + draw_frame++; +} + + +int init_machine () //(int argc, char **argv) +{ + gfx = &gfx_pcvga; + opt.cgaemu = TRUE; + return err_OK; +} + + +int deinit_machine () +{ + return err_OK; +} + + +static int pc_init_vidmode () +{ + int i; + + clock_count = 0; + clock_ticks = 0; + pm_keypress = 0; + + screen_buffer = calloc (GFX_WIDTH, GFX_HEIGHT); + + return err_OK; +} + + +static int pc_deinit_vidmode () +{ + free (screen_buffer); + + return err_OK; +} + + +/* blit a block onto the screen */ +static void pc_put_block (int x1, int y1, int x2, int y2) +{ + int x, y; + int disp_val; + + for (y = 0; y < NUM_MASSES_Y; y++) + { + for (x = 0; x < GFX_WIDTH; x++) + { + disp_val = ((int) screen_buffer[y*GFX_WIDTH+x]); //+ 16); + if (disp_val > 32) disp_val = 32; + else if (disp_val < 0) disp_val = 0; + Bitmap[((NUM_MASSES_Y-y)*(GFX_WIDTH))-(GFX_WIDTH-x)] = RGBmap[disp_val]; + } + } + DosRequestMutexSem(hmtxLock, SEM_INDEFINITE_WAIT); + + /* This is the key to the speed. Instead of doing a GPI call to set the + color and a GPI call to set the pixel for EACH pixel, we get by + with only two GPI calls. */ + GpiSetBitmapBits(hpsMemory, 0L, (LONG) (NUM_MASSES_Y-2), &Bitmap[0], pbmi); + GpiBitBlt(hps, hpsMemory, 3L, aptl, ROP_SRCCOPY, BBO_AND); + + DosReleaseMutexSem(hmtxLock); +} + + +static void pc_put_pixels(int x, int y, int w, UINT8 *p) +{ + UINT8 *s; + for (s = &screen_buffer[y * 320 + x]; w--; *s++ = *p++); +} + + +static int pc_keypress () +{ +return (pm_keypress); +} + + +static int pc_get_key () +{ +if(pm_keypress) { + pm_keypress = 0; + return key_from; + } +else +return 0; +} + + +int OLDmain (int argc, char *argv[]); +////////////////////////////////////////////////////////////// + +int main(int argc, char *argv[]) +{ + HMQ hmq; + QMSG qmsg; + ULONG flFlags; + unsigned char class[]="MyClass"; + + flFlags = FCF_TITLEBAR | + FCF_MINBUTTON | + FCF_TASKLIST | + FCF_SYSMENU; + + if ((hab = WinInitialize(0)) == 0) + { + printf("Error doing WinInitialize()\n"); + exit(1); + } + if ((hmq = WinCreateMsgQueue(hab, 0)) == (HMQ) NULL) + { + printf("Error doing WinCreateMsgQueue()\n"); + exit(1); + } + if (!WinRegisterClass(hab, (PSZ) class, (PFNWP) window_func, + CS_SIZEREDRAW, 0)) + { + printf("Error doing WinRegisterClass()\n"); + exit(1); + } + if ((hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &flFlags, + (PSZ) class, (PSZ) "Sarien 0.8.0-j2me", + WS_VISIBLE, 0, 0, &hwndClient)) == 0) + { + printf("Error doing WinCreateStdWindow()\n"); + exit(1); + } + WinSetWindowPos(hwndFrame, 0L, + (SHORT) (60), + (SHORT) (WinQuerySysValue(HWND_DESKTOP, + SV_CYSCREEN) - (NUM_MASSES_Y+60)), + (SHORT) GFX_WIDTH, + (SHORT) NUM_MASSES_Y + WinQuerySysValue(HWND_DESKTOP, + SV_CYTITLEBAR) - 2, SWP_SIZE | SWP_MOVE); + + /* Work out mapping from bitmap color table to our logical palette. */ + PrepareGraphics(RGBmap); + + /* Create a semaphore to control access to the memory image + presentation space. Only one thread can perform Gpi operations + on it at a time. */ + DosCreateMutexSem("\\sem32\\Lock", &hmtxLock, 0, FALSE); + + /* Create a thread to run the system model. */ + DosCreateThread(&tidMain,OLDmain, 0UL, 0UL, STACK); + DosCreateThread(&tidTimer,Timer, 0UL, 0UL, STACK); + + draw_frame=1000; + draw_frame_skip=60; + if(argc>1) + draw_frame_skip=atoi(argv[1]); + while (WinGetMsg(hab, &qmsg, (HWND) NULL, 0, 0)) + { + WinDispatchMsg(hab, &qmsg); + } + WinDestroyWindow(hwndFrame); + WinDestroyMsgQueue(hmq); + WinTerminate(hab); +} +////////////////////////////////////////////////////////////// + + +MRESULT EXPENTRY +window_func(HWND handle, ULONG mess, MPARAM parm1, MPARAM parm2) +{ + int i; + LONG j; + SIZEL sizl; + LONG OS2palette[33]; + + + switch(mess) + { + case WM_CREATE: + /* Create presentation space for screen. */ + hdc = WinOpenWindowDC(handle); + sizl.cx = 0; + sizl.cy = 0; + hps = GpiCreatePS(hab, hdc, &sizl, + PU_PELS | GPIT_MICRO | GPIA_ASSOC | GPIF_DEFAULT); + + /* Create presentation space for memory image of screen. */ + hdcMemory = DevOpenDC(hab, OD_MEMORY, (PSZ) "*", 0L, 0L, 0L); + sizl.cx = 0; + sizl.cy = 0; + hpsMemory = GpiCreatePS(hab, hdcMemory, &sizl, + PU_PELS | GPIT_MICRO | GPIA_ASSOC | GPIF_DEFAULT); + + /* Create bitmap for memory image of screen. */ + memset(&bmih, 0, sizeof(bmih)); + bmih.cbFix = sizeof(bmih); + bmih.cx = NUM_MASSES_X; + bmih.cy = NUM_MASSES_Y; + bmih.cPlanes = 1; + bmih.cBitCount = 8; + hbm = GpiCreateBitmap(hpsMemory, &bmih, 0L, NULL, NULL); + GpiSetBitmap(hpsMemory, hbm); + + /* Set up gray-scale palette for screen image. */ + for (i = 0; i < 32; i++) + { + j = i << 3; + OS2palette[i] = CGA_00; //(j << 16) | (j << 8) | j; + } + OS2palette[0]=CGA_00; + OS2palette[1]=CGA_11; + OS2palette[2]=CGA_11; + OS2palette[3]=CGA_11; + OS2palette[4]=CGA_13; + OS2palette[5]=CGA_13; + OS2palette[6]=CGA_13; + OS2palette[7]=CGA_15; + OS2palette[8]=CGA_00; + OS2palette[9]=CGA_11; + OS2palette[10]=CGA_11; + OS2palette[11]=CGA_11; + OS2palette[12]=CGA_13; + OS2palette[13]=CGA_13; + OS2palette[14]=CGA_13; + OS2palette[15]=CGA_15; + + OS2palette[16]=CGA_00; + OS2palette[17]=CGA_11; + OS2palette[18]=CGA_11; + OS2palette[19]=CGA_11; + OS2palette[20]=CGA_13; + OS2palette[21]=CGA_13; + OS2palette[22]=CGA_13; + OS2palette[23]=CGA_15; + OS2palette[24]=CGA_00; + OS2palette[25]=CGA_11; + OS2palette[26]=CGA_11; + OS2palette[27]=CGA_11; + OS2palette[28]=CGA_13; + OS2palette[29]=CGA_13; + OS2palette[30]=CGA_13; + OS2palette[31]=CGA_15; + + OS2palette[32] = 0x00ffffffL; + + + GpiCreateLogColorTable(hpsMemory, (ULONG) LCOL_PURECOLOR, + (LONG) LCOLF_CONSECRGB, (LONG) 0L, (LONG) 33L, (PLONG) OS2palette); + GpiSetBackMix(hpsMemory, BM_OVERPAINT); + + /* Take the input focus. */ + WinFocusChange(HWND_DESKTOP, handle, 0L); + break; + + case WM_ERASEBACKGROUND: + case WM_PAINT: + /* Copy the memory image of the screen out to the real screen. */ + if(draw_frame>draw_frame_skip) { + DosRequestMutexSem(hmtxLock, SEM_INDEFINITE_WAIT); + WinBeginPaint(handle, hps, NULL); + GpiBitBlt(hps, hpsMemory, 3L, aptl, ROP_SRCCOPY, BBO_AND); + WinEndPaint(hps); + DosReleaseMutexSem(hmtxLock); + draw_frame=1; + } + break; + + case WM_CHAR: + if (SHORT1FROMMP(parm1) & KC_KEYUP) + break; +pm_keypress=1; + + switch (SHORT2FROMMP(parm2)) + { + + case VK_LEFT: + key_from=KEY_LEFT; + break; + case VK_RIGHT: + key_from=KEY_RIGHT; + break; + case VK_UP: + key_from=KEY_UP; + break; + case VK_DOWN: + key_from=KEY_DOWN; + break; + case VK_ESC: + key_from=KEY_ESCAPE; + break; + + default: + key_from=SHORT1FROMMP(parm2); + break; + + } + break; + default: + return WinDefWindowProc(handle, mess, parm1, parm2); + } + return (MRESULT) FALSE; +} + + +void +PrepareGraphics(BYTE *RGBmap) +{ + POINTL coords; + int x, y; + + /* Give thread access to Gpi. */ + habt = WinInitialize(0); + + /* Determine mapping from logical color value to bitmap color table + index. Anybody know a more direct way??? */ + DosRequestMutexSem(hmtxLock, SEM_INDEFINITE_WAIT); + for (x = 0, y = 0; x < 33; x++) + { + GpiSetColor(hpsMemory, (LONG) x); + coords.x = x; + coords.y = y; + GpiSetPel(hpsMemory, &coords); + } + bmp2data.cbFix = 16L; + GpiQueryBitmapInfoHeader(hbm, &bmp2data); + DosAllocMem((PPVOID)&pbmi, sizeof(BITMAPINFO2) + + (sizeof(RGB2) * (1 << bmp2data.cPlanes) * + (1 << bmp2data.cBitCount)), + PAG_COMMIT | PAG_READ | PAG_WRITE); + pbmi->cbFix = bmp2data.cbFix; + pbmi->cx = bmp2data.cx; + pbmi->cy = bmp2data.cy; + pbmi->cPlanes = bmp2data.cPlanes; + pbmi->cBitCount = bmp2data.cBitCount; + pbmi->ulCompression = bmp2data.ulCompression; + pbmi->cbImage = bmp2data.cbImage; + pbmi->cxResolution = bmp2data.cxResolution; + pbmi->cyResolution = bmp2data.cyResolution; + pbmi->cclrUsed = bmp2data.cclrUsed; + pbmi->cclrImportant = bmp2data.cclrImportant; + pbmi->usUnits = bmp2data.usUnits; + pbmi->usReserved = bmp2data.usReserved; + pbmi->usRecording = bmp2data.usRecording; + pbmi->usRendering = bmp2data.usRendering; + pbmi->cSize1 = bmp2data.cSize1; + pbmi->cSize2 = bmp2data.cSize2; + pbmi->ulColorEncoding = bmp2data.ulColorEncoding; + pbmi->ulIdentifier = bmp2data.ulIdentifier; + GpiQueryBitmapBits(hpsMemory, 0L, NUM_MASSES_Y-2, &Bitmap[0], pbmi); + DosReleaseMutexSem(hmtxLock); + for (x = 0; x < 33; x++) + { + RGBmap[x] = Bitmap[x]; + } +} + + \ No newline at end of file diff --git a/objects.c b/objects.c index b8d9fed..4063d64 100644 --- a/objects.c +++ b/objects.c @@ -1,178 +1,178 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: objects.c,v 1.24 2003/08/31 16:05:05 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" - -extern int decode_objects(UINT8* mem, UINT32 flen); - - -static struct agi_object *objects; /* objects in the game */ - - -int alloc_objects (int n) -{ - if ((objects = calloc (n, sizeof(struct agi_object))) == NULL) - return err_NotEnoughMemory; - - return err_OK; -} - -int decode_objects (UINT8* mem, UINT32 flen) -{ -#ifndef PALMOS - unsigned int i, so, padsize; - - padsize = game.game_flags & ID_AMIGA ? 4 : 3; - - game.num_objects = 0; - objects = NULL; - - /* check if first pointer exceeds file size - * if so, its encrypted, else it is not - */ - - if (lohi_getword (mem) > flen) { - report ("Decrypting objects... "); - decrypt (mem, flen); - report ("done.\n"); - } - - /* alloc memory for object list - * byte 3 = number of animated objects. this is ignored.. ?? - */ - if (lohi_getword(mem) / padsize >= 256) { -#ifdef AGDS_SUPPORT - /* die with no error! AGDS game needs not to die to work!! :( */ - return err_OK; -#else - /* no AGDS support, die with error */ - return err_BadResource; -#endif - } - - game.num_objects = lohi_getword(mem) / padsize; - _D ("num_objects = %d (padsize = %d)", game.num_objects, padsize); - - if (alloc_objects (game.num_objects) != err_OK) - return err_NotEnoughMemory; - - /* build the object list */ - for (i = 0, so = padsize; i < game.num_objects; i++, so += padsize) { - int offset; - - (objects + i)->location = lohi_getbyte (mem + so + 2); - offset = lohi_getword (mem + so) + padsize; - - if (offset < flen) { - (objects + i)->name = strdup (mem + offset); - } else { - printf ("ERROR: object %i name beyond object filesize! " - "(%04x > %04x)\n", i, offset, flen); - (objects + i)->name = strdup (""); - } - } - report ("Reading objects: %d objects read.\n", game.num_objects); - -#endif - return err_OK; - -} - -int load_objects (char *fname) -{ -#ifndef PALMOS - FILE *fp; - UINT32 flen; - UINT8 *mem; - char *path; - - objects=NULL; - game.num_objects = 0; - - _D ("(fname = %s)", fname); - path = fixpath (NO_GAMEDIR, fname); - report ("Loading objects: %s\n", path); - - if ((fp = fopen(path, "rb")) == NULL) - return err_BadFileOpen; - - fseek (fp, 0, SEEK_END); - flen = ftell (fp); - fseek (fp, 0, SEEK_SET); - - if ((mem = calloc (1, flen + 32)) == NULL) { - fclose (fp); - return err_NotEnoughMemory; - } - - fread (mem, 1, flen, fp); - fclose(fp); - - decode_objects(mem, flen); - free(mem); -#endif - return err_OK; -} - -void unload_objects () -{ - unsigned int i; - - if (objects != NULL) { - for (i = 0; i < game.num_objects; i++) - free (objects[i].name); - free (objects); - } -} - -#ifdef OPT_LIST_OBJECTS -int show_objects () -{ - unsigned int i; - - printf(" ID Objects\n"); - for (i = 0; i < game.num_objects; i++) - printf ("%3i) %3i - %s\n", 1+i, (objects+i)->location, (objects+i)->name); - - printf ("\n%i objects\n", game.num_objects); - - return err_OK; -} -#endif - -void object_set_location (unsigned int n, int i) -{ - if (n >= game.num_objects) { - report ("Error: Can't access object %d.", n); - return; - } - objects[n].location = i; -} - -int object_get_location (unsigned int n) -{ - if (n >= game.num_objects) { - report ("Error: Can't access object %d.", n); - return 0; - } - return objects[n].location; -} - -char *object_name (unsigned int n) -{ - if (n >= game.num_objects) { - report ("Error: Can't access object %d.", n); - return ""; - } - return objects[n].name; -} +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: objects.c,v 1.24 2003/08/31 16:05:05 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" + +extern int decode_objects(UINT8* mem, UINT32 flen); + + +static struct agi_object *objects; /* objects in the game */ + + +int alloc_objects (int n) +{ + if ((objects = calloc (n, sizeof(struct agi_object))) == NULL) + return err_NotEnoughMemory; + + return err_OK; +} + +int decode_objects (UINT8* mem, UINT32 flen) +{ +#ifndef PALMOS + unsigned int i, so, padsize; + + padsize = game.game_flags & ID_AMIGA ? 4 : 3; + + game.num_objects = 0; + objects = NULL; + + /* check if first pointer exceeds file size + * if so, its encrypted, else it is not + */ + + if (lohi_getword (mem) > flen) { + report ("Decrypting objects... "); + decrypt (mem, flen); + report ("done.\n"); + } + + /* alloc memory for object list + * byte 3 = number of animated objects. this is ignored.. ?? + */ + if (lohi_getword(mem) / padsize >= 256) { +#ifdef AGDS_SUPPORT + /* die with no error! AGDS game needs not to die to work!! :( */ + return err_OK; +#else + /* no AGDS support, die with error */ + return err_BadResource; +#endif + } + + game.num_objects = lohi_getword(mem) / padsize; + _D ("num_objects = %d (padsize = %d)", game.num_objects, padsize); + + if (alloc_objects (game.num_objects) != err_OK) + return err_NotEnoughMemory; + + /* build the object list */ + for (i = 0, so = padsize; i < game.num_objects; i++, so += padsize) { + int offset; + + (objects + i)->location = lohi_getbyte (mem + so + 2); + offset = lohi_getword (mem + so) + padsize; + + if (offset < flen) { + (objects + i)->name = strdup (mem + offset); + } else { + printf ("ERROR: object %i name beyond object filesize! " + "(%04x > %04x)\n", i, offset, flen); + (objects + i)->name = strdup (""); + } + } + report ("Reading objects: %d objects read.\n", game.num_objects); + +#endif + return err_OK; + +} + +int load_objects (char *fname) +{ +#ifndef PALMOS + FILE *fp; + UINT32 flen; + UINT8 *mem; + char *path; + + objects=NULL; + game.num_objects = 0; + + _D ("(fname = %s)", fname); + path = fixpath (NO_GAMEDIR, fname); + report ("Loading objects: %s\n", path); + + if ((fp = fopen(path, "rb")) == NULL) + return err_BadFileOpen; + + fseek (fp, 0, SEEK_END); + flen = ftell (fp); + fseek (fp, 0, SEEK_SET); + + if ((mem = calloc (1, flen + 32)) == NULL) { + fclose (fp); + return err_NotEnoughMemory; + } + + fread (mem, 1, flen, fp); + fclose(fp); + + decode_objects(mem, flen); + free(mem); +#endif + return err_OK; +} + +void unload_objects () +{ + unsigned int i; + + if (objects != NULL) { + for (i = 0; i < game.num_objects; i++) + free (objects[i].name); + free (objects); + } +} + +#ifdef OPT_LIST_OBJECTS +int show_objects () +{ + unsigned int i; + + printf(" ID Objects\n"); + for (i = 0; i < game.num_objects; i++) + printf ("%3i) %3i - %s\n", 1+i, (objects+i)->location, (objects+i)->name); + + printf ("\n%i objects\n", game.num_objects); + + return err_OK; +} +#endif + +void object_set_location (unsigned int n, int i) +{ + if (n >= game.num_objects) { + report ("Error: Can't access object %d.", n); + return; + } + objects[n].location = i; +} + +int object_get_location (unsigned int n) +{ + if (n >= game.num_objects) { + report ("Error: Can't access object %d.", n); + return 0; + } + return objects[n].location; +} + +char *object_name (unsigned int n) +{ + if (n >= game.num_objects) { + report ("Error: Can't access object %d.", n); + return ""; + } + return objects[n].name; +} diff --git a/op_cmd.c b/op_cmd.c index 717b875..dabd78f 100644 --- a/op_cmd.c +++ b/op_cmd.c @@ -1,1163 +1,1163 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: op_cmd.c,v 1.156 2003/10/16 22:15:51 bootstrap666 Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "rand.h" -#include "sprite.h" -#include "graphics.h" -#include "keyboard.h" -#include "opcodes.h" -#include "menu.h" -#include "savegame.h" -#include "text.h" - -#define p0 (p[0]) -#define p1 (p[1]) -#define p2 (p[2]) -#define p3 (p[3]) -#define p4 (p[4]) -#define p5 (p[5]) -#define p6 (p[6]) - -#define ip cur_logic->cIP -#define vt game.view_table[p0] - -static struct agi_logic *cur_logic; - -int timer_hack; /* Workaround for timer loop in MH1 */ - -#define _v game.vars -#define cmd(x) static void cmd_##x (UINT8 *p) - -cmd(increment) { if (_v[p0] != 0xff) ++_v[p0]; } -cmd(decrement) { if (_v[p0] != 0) --_v[p0]; } -cmd(assignn) { _v[p0] = p1; } -cmd(addn) { _v[p0] += p1; } -cmd(subn) { _v[p0] -= p1; } -cmd(assignv) { _v[p0] = _v[p1]; } -cmd(addv) { _v[p0] += _v[p1]; } -cmd(subv) { _v[p0] -= _v[p1]; } -cmd(mul_n) { _v[p0] *= p1; } -cmd(mul_v) { _v[p0] *= _v[p1]; } -cmd(div_n) { _v[p0] /= p1; } -cmd(div_v) { _v[p0] /= _v[p1]; } -cmd(random) { _v[p2] = rnd (1 + (p1 - p0)) + p0; } -cmd(lindirectn) { _v[_v[p0]] = p1; } -cmd(lindirectv) { _v[_v[p0]] = _v[p1]; } -cmd(rindirect) { _v[p0] = _v[_v[p1]]; } -cmd(set) { setflag (*p, TRUE); } -cmd(reset) { setflag (*p, FALSE); } -cmd(toggle) { setflag (*p, !getflag (*p)); } -cmd(set_v) { setflag (_v[p0], TRUE); } -cmd(reset_v) { setflag (_v[p0], FALSE); } -cmd(toggle_v) { setflag (_v[p0], !getflag (_v[p0])); } -cmd(new_room) { new_room (p0); } -cmd(new_room_f) { new_room (_v[p0]); } -cmd(load_view) { agi_load_resource (rVIEW, p0); } -cmd(load_logic) { agi_load_resource (rLOGIC, p0); } -cmd(load_sound) { agi_load_resource (rSOUND, p0); } -cmd(load_view_f) { agi_load_resource (rVIEW, _v[p0]); } -cmd(load_logic_f) { agi_load_resource (rLOGIC, _v[p0] ); } -cmd(discard_view) { agi_unload_resource (rVIEW, p0); } -cmd(object_on_anything) { vt.flags &= ~(ON_WATER | ON_LAND); } -cmd(object_on_land) { _D ("p0 = %d", p0); vt.flags |= ON_LAND; } -cmd(object_on_water) { _D ("p0 = %d", p0); vt.flags |= ON_WATER; } -cmd(observe_horizon) { _D ("p0 = %d", p0); vt.flags &= ~IGNORE_HORIZON; } -cmd(ignore_horizon) { _D ("p0 = %d", p0); vt.flags |= IGNORE_HORIZON; } -cmd(observe_objs) { _D ("p0 = %d", p0); vt.flags &= ~IGNORE_OBJECTS; } -cmd(ignore_objs) { _D ("p0 = %d", p0); vt.flags |= IGNORE_OBJECTS; } -cmd(observe_blocks) { _D ("p0 = %d", p0); vt.flags &= ~IGNORE_BLOCKS; } -cmd(ignore_blocks) { _D ("p0 = %d", p0); vt.flags |= IGNORE_BLOCKS; } -cmd(set_horizon) { _D ("p0 = %d", p0); game.horizon = p0; } -cmd(get_priority) { _v[p1] = vt.priority; } -cmd(set_priority) { vt.flags |= FIXED_PRIORITY; vt.priority = p1; } -cmd(set_priority_f) { vt.flags |= FIXED_PRIORITY; vt.priority = _v[p1]; } -cmd(release_priority) { vt.flags &= ~FIXED_PRIORITY; } -cmd(set_upper_left) { /* do nothing (AGI 2.917) */ } -cmd(start_update) { start_update (&vt); } -cmd(stop_update) { stop_update (&vt); } -cmd(current_view) { _v[p1] = vt.current_view; } -cmd(current_cel) { _v[p1] = vt.current_cel; _D ("v%d=%d", p1, _v[p1]); } -cmd(current_loop) { _v[p1] = vt.current_loop; } -cmd(last_cel) { _v[p1] = vt.loop_data->num_cels - 1; } -cmd(set_cel) { set_cel (&vt, p1); vt.flags &= ~DONTUPDATE; } -cmd(set_cel_f) { set_cel (&vt, _v[p1]); vt.flags &= ~DONTUPDATE; } -cmd(set_view) { _D ("o%d, %d", p0, p1); set_view (&vt, p1); } -cmd(set_view_f) { set_view (&vt, _v[p1]); } -cmd(set_loop) { set_loop (&vt, p1); } -cmd(set_loop_f) { set_loop (&vt, _v[p1]); } -cmd(number_of_loops) { _v[p1] = vt.num_loops; } -cmd(fix_loop) { vt.flags |= FIX_LOOP; } -cmd(release_loop) { vt.flags &= ~FIX_LOOP; } -cmd(step_size) { vt.step_size = _v[p1]; } -cmd(step_time) { vt.step_time = vt.step_time_count = _v[p1]; } -cmd(cycle_time) { vt.cycle_time = vt.cycle_time_count = _v[p1]; } -cmd(stop_cycling) { vt.flags &= ~CYCLING; } -cmd(start_cycling) { vt.flags |= CYCLING; } -cmd(normal_cycle) { vt.cycle = CYCLE_NORMAL; vt.flags |= CYCLING; } -cmd(reverse_cycle) { vt.cycle = CYCLE_REVERSE; vt.flags |= CYCLING; } -cmd(set_dir) { vt.direction = _v[p1]; } -cmd(get_dir) { _v[p1] = vt.direction; } -cmd(get_room_f) { _v[p1] = object_get_location (_v[p0]); } -cmd(put) { object_set_location (p0, _v[p1]); } -cmd(put_f) { object_set_location (_v[p0], _v[p1]); } -cmd(drop) { object_set_location (p0, 0); } -cmd(get) { object_set_location (p0, EGO_OWNED); } -cmd(get_f) { object_set_location (_v[p0], EGO_OWNED); } -cmd(word_to_string) { strcpy (game.strings[p0], game.ego_words[p1].word); } -cmd(open_dialogue) { _D ("p0 = %d", p0); game.has_window = TRUE; } -cmd(close_dialogue) { _D ("p0 = %d", p0); game.has_window = FALSE; } -cmd(close_window) { close_window (); } -cmd(status_line_on) { game.status_line = TRUE; write_status (); } -cmd(status_line_off) { game.status_line = FALSE; write_status (); } -cmd(show_obj) { show_obj (p0); } -cmd(show_obj_v) { show_obj (_v[p0]); } -cmd(sound) { start_sound (p0, p1); } -cmd(stop_sound) { stop_sound (); } -cmd(menu_input) { new_input_mode (INPUT_MENU); } -cmd(enable_item) { menu_set_item (p0, TRUE); } -cmd(disable_item) { menu_set_item (p0, FALSE); } -cmd(submit_menu) { menu_submit (); } -cmd(set_scan_start) { cur_logic->sIP = cur_logic->cIP; } -cmd(reset_scan_start) { cur_logic->sIP = 2; } -cmd(save_game) { game.simple_save ? - savegame_simple() : savegame_dialog(); } -cmd(load_game) { game.simple_save ? - loadgame_simple() : loadgame_dialog(); } -cmd(init_disk) { /* do nothing */ } -cmd(log) { /* do nothing */ } -cmd(trace_on) { /* do nothing */ } -cmd(trace_info) { /* do nothing */ } -cmd(show_mem) { message_box ("Enough memory"); } -cmd(init_joy) { /* do nothing */; } -cmd(script_size) { report ("script.size(%d)\n", p0); } -cmd(cancel_line) { report ("cancel.line\n"); } -cmd(obj_status_f) { report ("obj.status.f\n"); } - -/* unknown commands: - * unk_170: Force savegame name -- j5 - * unk_171: script save -- j5 - * unk_172: script restore -- j5 - * unk_173: Activate keypressed control (ego only moves while key is pressed) - * unk_174: Change priority table (used in KQ4) -- j5 - * unk_177: Disable menus completely -- j5 - * unk_181: Deactivate keypressed control (default control of ego) - */ -cmd(set_simple) { game.simple_save = TRUE; } -cmd(pop_script) { report ("pop.script\n"); } -cmd(hold_key) { report ("hold.key\n"); } -cmd(discard_sound) { report ("discard.sound\n"); } -cmd(hide_mouse) { report ("hide.mouse\n"); } -cmd(allow_menu) { report ("allow.menu\n"); } -cmd(show_mouse) { report ("show.mouse\n"); } -cmd(fence_mouse) { report ("fence.mouse\n"); } -cmd(release_key) { report ("release.key\n"); } -cmd(adj_ego_move_to_x_y){ game.view_table[0].flags |= ADJ_EGO_XY; } - - -cmd(parse) { - _v[V_word_not_found] = 0; - setflag (F_entered_cli, FALSE); - setflag (F_said_accepted_input, FALSE); - - dictionary_words (agi_sprintf(game.strings[p0])); -} - -cmd(call) { - int old_cIP; - int old_lognum; - - /* CM: we don't save sIP because set.scan.start can be - * used in a called script (fixes xmas demo) - */ - old_cIP = cur_logic->cIP; - old_lognum = game.lognum; - - run_logic (p0); - - game.lognum = old_lognum; - cur_logic = &game.logics[game.lognum]; - cur_logic->cIP = old_cIP; -} - -cmd(call_f) { - cmd_call (&_v[p0]); -} - -cmd(draw_pic) { - _D (_D_WARN "=== draw pic %d ===", _v[p0]); - erase_both (); - decode_picture (_v[p0], TRUE); - blit_both (); - game.picture_shown = 0; - _D (_D_WARN "--- end of draw pic %d ---", _v[p0]); -} - -cmd(show_pic) { - _D (_D_WARN "=== show pic ==="); - setflag (F_output_mode, FALSE); - cmd_close_window (NULL); - show_pic (); - game.picture_shown = 1; - _D (_D_WARN "--- end of show pic ---"); -} - -cmd(load_pic) { - erase_both (); - agi_load_resource (rPICTURE, _v[p0]); - blit_both (); -} - -cmd(discard_pic) { - _D (_D_WARN "--- discard pic ---"); - /* do nothing */ -} - -cmd(overlay_pic) { - _D (_D_WARN "--- overlay pic ---"); - erase_both (); - decode_picture (_v[p0], FALSE); - blit_both (); - game.picture_shown = 0; - commit_both (); -} - -cmd(show_pri_screen) { -#ifdef USE_CONSOLE - debug.priority = 1; - erase_both(); - show_pic (); - blit_both (); - wait_key (); - debug.priority = 0; - erase_both(); - show_pic (); - blit_both (); -#endif -} - -cmd(animate_obj) { - if (vt.flags & ANIMATED) - return; - - _D (_D_WARN "animate vt entry #%d", p0); - vt.flags = ANIMATED | UPDATE | CYCLING; - vt.motion = MOTION_NORMAL; - vt.cycle = CYCLE_NORMAL; - vt.direction = 0; -} - -cmd(unanimate_all) { - int i; - for (i = 0; i < MAX_VIEWTABLE; i++) - game.view_table[i].flags &= ~(ANIMATED | DRAWN); -} - -cmd(draw) { - if (vt.flags & DRAWN) - return; - - if (vt.y_size <= 0 || vt.x_size <= 0) - return; - - _D("draw entry %d", vt.entry); - - vt.flags |= UPDATE; - if (agi_get_release() >= 0x3000){ - set_loop(&vt,vt.current_loop); - set_cel(&vt,vt.current_cel); - } - fix_position (p0); - vt.x_pos2 = vt.x_pos; - vt.y_pos2 = vt.y_pos; - vt.cel_data_2 = vt.cel_data; - erase_upd_sprites (); - vt.flags |= DRAWN; - - if (agi_get_release() <= 0x2440) /* See bug #546562 */ - vt.flags |= ANIMATED; - - blit_upd_sprites (); - vt.flags &= ~DONTUPDATE; - - commit_block (vt.x_pos, vt.y_pos - vt.y_size + 1, - vt.x_pos + vt.x_size - 1, vt.y_pos); - - _D ("vt entry #%d flags = %02x", p0, vt.flags); -} - -cmd(erase) { - if (~vt.flags & DRAWN) - return; - - erase_upd_sprites (); - if (vt.flags & UPDATE) { - vt.flags &= ~DRAWN; - } else { - erase_nonupd_sprites (); - vt.flags &= ~DRAWN; - blit_nonupd_sprites (); - } - blit_upd_sprites (); - - commit_block (vt.x_pos, vt.y_pos - vt.y_size + 1, - vt.x_pos + vt.x_size - 1, vt.y_pos); -} - -cmd(position) { - vt.x_pos = vt.x_pos2 = p1; - vt.y_pos = vt.y_pos2 = p2; -} - -cmd(position_f) { - vt.x_pos = vt.x_pos2 = _v[p1]; - vt.y_pos = vt.y_pos2 = _v[p2]; -} - -cmd(get_posn) { - game.vars[p1] = (unsigned char)vt.x_pos; - game.vars[p2] = (unsigned char)vt.y_pos; -} - -cmd(reposition) { - int dx = (SINT8)_v[p1], dy = (SINT8)_v[p2]; - - _D ("dx=%d, dy=%d", dx, dy); - vt.flags |= UPDATE_POS; - - if (dx < 0 && vt.x_pos < -dx) - vt.x_pos = 0; - else - vt.x_pos += dx; - - if (dy < 0 && vt.y_pos < -dy) - vt.y_pos = 0; - else - vt.y_pos += dy; - - fix_position (p0); -} - -cmd(reposition_to) { - vt.x_pos = p1; - vt.y_pos = p2; - vt.flags |= UPDATE_POS; - fix_position (p0); -} - -cmd(reposition_to_f) { - vt.x_pos = _v[p1]; - vt.y_pos = _v[p2]; - vt.flags |= UPDATE_POS; - fix_position (p0); -} - -cmd(add_to_pic) { - add_to_pic (p0, p1, p2, p3, p4, p5, p6); -} - -cmd(add_to_pic_f) { - add_to_pic (_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]); -} - -cmd(force_update) { - erase_both (); - blit_both (); - commit_both (); -} - -cmd(reverse_loop) { - _D (_D_WARN "o%d, f%d", p0, p1); - vt.cycle = CYCLE_REV_LOOP; - vt.flags |= (DONTUPDATE|UPDATE|CYCLING); - vt.parm1 = p1; - setflag (p1, FALSE); -} - -cmd(end_of_loop) { - _D (_D_WARN "o%d, f%d", p0, p1); - vt.cycle = CYCLE_END_OF_LOOP; - vt.flags |= (DONTUPDATE|UPDATE|CYCLING); - vt.parm1 = p1; - setflag (p1, FALSE); -} - -cmd(block) { - _D (_D_WARN "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3); - game.block.active = TRUE; - game.block.x1 = p0; - game.block.y1 = p1; - game.block.x2 = p2; - game.block.y2 = p3; -} - -cmd(unblock) { - game.block.active = FALSE; -} - -cmd(normal_motion) { - vt.motion = MOTION_NORMAL; -} - -cmd(stop_motion) { - vt.direction = 0; - vt.motion = MOTION_NORMAL; - if (p0 == 0) { /* ego only */ - _v[V_ego_dir] = 0; - game.player_control = FALSE; - } -} - -cmd(start_motion) { - vt.motion = MOTION_NORMAL; - if (p0 == 0) { /* ego only */ - _v[V_ego_dir] = 0; - game.player_control = TRUE; - } -} - -cmd(player_control) { - game.player_control = TRUE; - game.view_table[0].motion = MOTION_NORMAL; -} - -cmd(program_control) { - game.player_control = FALSE; -} - -cmd(follow_ego) { - vt.motion = MOTION_FOLLOW_EGO; - vt.parm1 = p1 > vt.step_size ? p1 : vt.step_size; - vt.parm2 = p2; - vt.parm3 = 0xff; - setflag (p2, FALSE); - vt.flags |= UPDATE; -} - -cmd(move_obj) { - /* _D (_D_WARN "o=%d, x=%d, y=%d, s=%d, f=%d", p0, p1, p2, p3, p4); */ - - vt.motion = MOTION_MOVE_OBJ; - vt.parm1 = p1; - vt.parm2 = p2; - vt.parm3 = vt.step_size; - vt.parm4 = p4; - - if (p3 != 0) - vt.step_size = p3; - - setflag (p4, FALSE); - vt.flags |= UPDATE; - - if (p0 == 0) - game.player_control = FALSE; - - /* AGI 2.272 (ddp, xmas) doesn't call move_obj! */ - if (agi_get_release() > 0x2272) - move_obj (&vt); -} - -cmd(move_obj_f) { - vt.motion = MOTION_MOVE_OBJ; - vt.parm1 = _v[p1]; - vt.parm2 = _v[p2]; - vt.parm3 = vt.step_size; - vt.parm4 = p4; - - if (_v[p3] != 0) - vt.step_size = _v[p3]; - - setflag (p4, FALSE); - vt.flags |= UPDATE; - - if (p0 == 0) - game.player_control = FALSE; - - /* AGI 2.272 (ddp, xmas) doesn't call move_obj! */ - if (agi_get_release() > 0x2272) - move_obj (&vt); -} - -cmd(wander) { - if (p0 == 0) - game.player_control = FALSE; - vt.motion = MOTION_WANDER; - vt.flags |= UPDATE; -} - - -cmd(set_game_id) { - if (cur_logic->texts && (p0 - 1) <= cur_logic->num_texts) - strncpy (game.id, cur_logic->texts[p0 - 1], 8); - else - game.id[0] = 0; - - report ("Game ID: \"%s\"\n", game.id); -} - -cmd(pause) { - int tmp = game.clock_enabled; - char *b[] = { "Continue", NULL }; - - game.clock_enabled = FALSE; - selection_box (" Game is paused. \n\n\n", b); - game.clock_enabled = tmp; -} - -cmd(set_menu) { - _D ("text %02x of %02x", p0, cur_logic->num_texts); - if (cur_logic->texts != NULL && p0 < cur_logic->num_texts) - menu_add (cur_logic->texts[p0 - 1]); -} - -cmd(set_menu_item) { - _D ("text %02x of %02x", p0, cur_logic->num_texts); - if (cur_logic->texts != NULL && p0 <= cur_logic->num_texts) - menu_add_item (cur_logic->texts[p0 - 1], p1); -} - -cmd(version) { - char ver_msg[] = TITLE " v" VERSION; - char ver2_msg[] = - "\n" - " \n\n" - "Emulating Sierra AGI v%x.%03x\n"; - char ver3_msg[]= - "\n" - " \n\n" - " Emulating AGI v%x.002.%03x\n"; - /* no Sierra as it wraps textbox */ - char *r, *q; - int ver, maj, min; - char msg[256]; - - ver = agi_get_release (); - maj = (ver >> 12) & 0xf; - min = ver & 0xfff; - - q = maj == 2 ? ver2_msg : ver3_msg; - r = strchr (q+1, '\n'); - - strncpy (q+1 + ((r-q > 0 ? r - q : 1) / 4), ver_msg, strlen (ver_msg)); - sprintf (msg, q, maj, min); - message_box (msg); -} - -cmd(configure_screen) { - game.line_min_print = p0; - game.line_user_input = p1; - game.line_status = p2; -} - -cmd(text_screen) { - _D (_D_WARN "switching to text mode"); - game.gfx_mode = FALSE; - /* - * Simulates the "bright background bit" of the PC video - * controller. - */ - if (game.color_bg) - game.color_bg |= 0x08; - clear_screen (game.color_bg); -} - -cmd(graphics) { - _D (_D_WARN "switching to graphics mode"); - if (!game.gfx_mode) { - game.gfx_mode = TRUE; - clear_screen (0); - show_pic (); - write_status (); - write_prompt (); - } -} - -cmd(set_text_attribute) { - game.color_fg = p0; - game.color_bg = p1; - - if (game.gfx_mode) { - if (game.color_bg != 0) { - game.color_fg = 0; - game.color_bg = 15; - } - } -} - -cmd(status) { - inventory(); -} - -cmd(quit) { - char *buttons[] = { "Quit", "Continue", NULL }; - - stop_sound (); - if (p0) { - game.quit_prog_now = TRUE; - } else { - if (selection_box (" Quit the game, or continue? \n\n\n", - buttons) == 0) - { - game.quit_prog_now = TRUE; - } - } -} - -cmd(restart_game) { - char *buttons[] = { "Restart", "Continue", NULL }; - int sel; - - stop_sound(); - sel = getflag(F_auto_restart) ? 1 : - selection_box (" Restart game, or continue? \n\n\n", buttons); - - if (sel == 0) { - game.quit_prog_now = 0xff; - setflag (F_restart_game, TRUE); - menu_enable_all(); - } -} - -cmd(distance) { - SINT16 x1, y1, x2, y2, d; - struct vt_entry *v0 = &game.view_table[p0]; - struct vt_entry *v1 = &game.view_table[p1]; - - if (v0->flags & DRAWN && v1->flags & DRAWN) { - x1 = v0->x_pos + v0->x_size / 2; - y1 = v0->y_pos; - x2 = v1->x_pos + v1->x_size / 2; - y2 = v1->y_pos; - d = abs (x1 - x2) + abs (y1 - y2); - if (d > 0xfe) d = 0xfe; - } else { - d = 0xff; - } - _v[p2] = (unsigned char)d; -} - -cmd(accept_input) { - _D (_D_WARN "input normal"); - new_input_mode (INPUT_NORMAL); - game.input_enabled = TRUE; -} - -cmd(prevent_input) { - _D (_D_WARN "no input"); - new_input_mode (INPUT_NONE); - game.input_enabled = FALSE; -} - -cmd(get_string) { - int tex, row, col; - - _D ("%d %d %d %d %d", p0, p1, p2, p3, p4); - - tex = p1 - 1; - row = p2; - col = p3; - - /* Workaround for SQLC bug. - * See bug #792125 for details - */ - if (row > 24) row = 24; - if (col > 39) col = 39; - - new_input_mode (INPUT_GETSTRING); - - if (cur_logic->texts != NULL && cur_logic->num_texts >= tex) { - int len = strlen (cur_logic->texts[tex]); - print_text (cur_logic->texts[tex], 0, col, - row, len, game.color_fg, game.color_bg); - get_string (col + len - 1, row, p4, p0); - - /* SGEO: display input char */ - print_character ((col + len), row, game.cursor_char, - game.color_fg, game.color_bg); - } - - do { - main_cycle (); - } while (game.input_mode == INPUT_GETSTRING); -} - - -cmd(get_num) { - _D ("%d %d", p0, p1); - new_input_mode (INPUT_GETSTRING); - - if (cur_logic->texts != NULL && cur_logic->num_texts >= (p0 - 1)) { - int len = strlen (cur_logic->texts[p0 - 1]); - print_text (cur_logic->texts[p0 - 1], 0, 0, 22, len, - game.color_fg, game.color_bg); - get_string (len - 1, 22, 3, MAX_STRINGS); - - /* CM: display input char */ - print_character ((p3 + len), 22, game.cursor_char, - game.color_fg, game.color_bg); - } - - do { - main_cycle (); - } while (game.input_mode == INPUT_GETSTRING); - - _v[p1] = atoi (game.strings[MAX_STRINGS]); - _D (_D_WARN "[%s] -> %d", game.strings[MAX_STRINGS], _v[p1]); - clear_lines (22, 22, game.color_bg); - flush_lines (22, 22); -} - -cmd(set_cursor_char) { - if (cur_logic->texts != NULL && (p0 - 1) <= cur_logic->num_texts) { - game.cursor_char = *cur_logic->texts[p0 - 1]; - } else { - /* default */ - game.cursor_char = '_'; - } -} - -cmd(set_key) { - int key; - - _D ("%d %d %d", p0, p1, p2); - - if (game.ev_keyp[p2].data != 0) /* TBC sets c23 (ESC) twice! */ - return; - - key = 256 * p1 + p0; - game.ev_keyp[p2].data = key; - game.ev_keyp[p2].occured = FALSE; -} - -cmd(set_string) { - /* CM: to avoid crash in Groza (str = 150) */ - if (p0 > MAX_STRINGS) return; - strcpy (game.strings[p0], cur_logic->texts[p1 - 1]); -} - -cmd(display) { - print_text (cur_logic->texts[p2 - 1], p1, 0, p0, 40, - game.color_fg, game.color_bg); -} - -cmd(display_f) { - _D ("p0 = %d", p0); - print_text (cur_logic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, - game.color_fg, game.color_bg); -} - -cmd(clear_text_rect) { - int c, x1, y1, x2, y2; - - if ((c = p4) != 0) c = 15; - x1 = p1 * CHAR_COLS; - y1 = p0 * CHAR_LINES; - x2 = (p3 + 1) * CHAR_COLS - 1; - y2 = (p2 + 1) * CHAR_LINES - 1; - - /* Added to prevent crash with x2 = 40 in the iigs demo */ - if (x1 > GFX_WIDTH) x1 = GFX_WIDTH - 1; - if (x2 > GFX_WIDTH) x2 = GFX_WIDTH - 1; - if (y1 > GFX_HEIGHT) y1 = GFX_HEIGHT - 1; - if (y2 > GFX_HEIGHT) y2 = GFX_HEIGHT - 1; - - draw_rectangle (x1, y1, x2, y2, c); - flush_block (x1, y1, x2, y2); -} - -cmd(toggle_monitor) { - report ("toggle.monitor\n"); -#ifdef USE_HIRES - opt.hires = !opt.hires; - erase_both(); - show_pic (); - blit_both (); -#endif -} - -cmd(echo_line) { - strcpy (game.input_buffer, game.echo_buffer); - game.cursor_pos = strlen ((char*)game.input_buffer); - game.has_prompt = 0; -} - -cmd(clear_lines) { - UINT8 l; - - /* Residence 44 calls clear.lines(24,0,0), see bug #558423 */ - l = p1 ? p1 : p0; - - clear_lines (p0, l, p2); - flush_lines (p0, l); -} - -cmd(print) { - int n = p0 < 1 ? 1 : p0; - print (cur_logic->texts[n - 1], 0, 0, 0); -} - -cmd(print_f) { - int n = _v[p0] < 1 ? 1 : _v[p0]; - print (cur_logic->texts[n - 1], 0, 0, 0); -} - -cmd(print_at) { - int n = p0 < 1 ? 1 : p0; - _D ("%d %d %d %d", p0, p1, p2, p3); - print (cur_logic->texts[n - 1], p1, p2, p3); -} - -cmd(print_at_v) { - int n = _v[p0] < 1 ? 1 : _v[p0]; - print (cur_logic->texts[n - 1], p1, p2, p3); -} - -cmd(push_script) { -#ifdef USE_MOUSE - if (opt.agimouse) { - game.vars[27] = mouse.button; - game.vars[28] = mouse.x / 2; - game.vars[29] = mouse.y; - } else -#endif - report ("push.script\n"); -} - -cmd(set_pri_base) { - int i, x, pri; - - report ("Priority base set to %d\n", p0); - - /* game.alt_pri = TRUE; */ - x = (_HEIGHT - p0) * _HEIGHT / 10; - - for (i = 0; i < _HEIGHT; i++) { - pri = (i - p0) < 0 ? 4 : (i - p0) * _HEIGHT / x + 5; - if (pri > 15) - pri = 15; - game.pri_table[i] = pri; - } -} - -cmd(mouse_posn) { -#ifdef USE_MOUSE - _v[p0] = WIN_TO_PIC_X(mouse.x); - _v[p1] = WIN_TO_PIC_Y(mouse.y); -#endif -} - -cmd(shake_screen) { - int i; - -#ifdef USE_MOUSE - /* AGI Mouse 1.1 uses shake.screen values between 100 and 109 to - * set the palette. - */ - if (opt.agimouse && p0 >= 100 && p0 < 110) { - report ("not implemented: AGI Mouse palettes\n"); - return; - } - else -#endif - - shake_start (); - commit_both (); /* Fixes SQ1 demo */ - for (i = 4 * p0; i; i--) { - shake_screen (i & 1); - flush_block (0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); - main_cycle (); - } - shake_end (); -} - - -static void (*agi_command[183])(UINT8 *) = { - NULL, /* 0x00 */ - cmd_increment, - cmd_decrement, - cmd_assignn, - cmd_assignv, - cmd_addn, - cmd_addv, - cmd_subn, - cmd_subv, /* 0x08 */ - cmd_lindirectv, - cmd_rindirect, - cmd_lindirectn, - cmd_set, - cmd_reset, - cmd_toggle, - cmd_set_v, - cmd_reset_v, /* 0x10 */ - cmd_toggle_v, - cmd_new_room, - cmd_new_room_f, - cmd_load_logic, - cmd_load_logic_f, - cmd_call, - cmd_call_f, - cmd_load_pic, /* 0x18 */ - cmd_draw_pic, - cmd_show_pic, - cmd_discard_pic, - cmd_overlay_pic, - cmd_show_pri_screen, - cmd_load_view, - cmd_load_view_f, - cmd_discard_view, /* 0x20 */ - cmd_animate_obj, - cmd_unanimate_all, - cmd_draw, - cmd_erase, - cmd_position, - cmd_position_f, - cmd_get_posn, - cmd_reposition, /* 0x28 */ - cmd_set_view, - cmd_set_view_f, - cmd_set_loop, - cmd_set_loop_f, - cmd_fix_loop, - cmd_release_loop, - cmd_set_cel, - cmd_set_cel_f, /* 0x30 */ - cmd_last_cel, - cmd_current_cel, - cmd_current_loop, - cmd_current_view, - cmd_number_of_loops, - cmd_set_priority, - cmd_set_priority_f, - cmd_release_priority, /* 0x38 */ - cmd_get_priority, - cmd_stop_update, - cmd_start_update, - cmd_force_update, - cmd_ignore_horizon, - cmd_observe_horizon, - cmd_set_horizon, - cmd_object_on_water, /* 0x40 */ - cmd_object_on_land, - cmd_object_on_anything, - cmd_ignore_objs, - cmd_observe_objs, - cmd_distance, - cmd_stop_cycling, - cmd_start_cycling, - cmd_normal_cycle, /* 0x48 */ - cmd_end_of_loop, - cmd_reverse_cycle, - cmd_reverse_loop, - cmd_cycle_time, - cmd_stop_motion, - cmd_start_motion, - cmd_step_size, - cmd_step_time, /* 0x50 */ - cmd_move_obj, - cmd_move_obj_f, - cmd_follow_ego, - cmd_wander, - cmd_normal_motion, - cmd_set_dir, - cmd_get_dir, - cmd_ignore_blocks, /* 0x58 */ - cmd_observe_blocks, - cmd_block, - cmd_unblock, - cmd_get, - cmd_get_f, - cmd_drop, - cmd_put, - cmd_put_f, /* 0x60 */ - cmd_get_room_f, - cmd_load_sound, - cmd_sound, - cmd_stop_sound, - cmd_print, - cmd_print_f, - cmd_display, - cmd_display_f, /* 0x68 */ - cmd_clear_lines, - cmd_text_screen, - cmd_graphics, - cmd_set_cursor_char, - cmd_set_text_attribute, - cmd_shake_screen, - cmd_configure_screen, - cmd_status_line_on, /* 0x70 */ - cmd_status_line_off, - cmd_set_string, - cmd_get_string, - cmd_word_to_string, - cmd_parse, - cmd_get_num, - cmd_prevent_input, - cmd_accept_input, /* 0x78 */ - cmd_set_key, - cmd_add_to_pic, - cmd_add_to_pic_f, - cmd_status, - cmd_save_game, - cmd_load_game, - cmd_init_disk, - cmd_restart_game, /* 0x80 */ - cmd_show_obj, - cmd_random, - cmd_program_control, - cmd_player_control, - cmd_obj_status_f, - cmd_quit, - cmd_show_mem, - cmd_pause, /* 0x88 */ - cmd_echo_line, - cmd_cancel_line, - cmd_init_joy, - cmd_toggle_monitor, - cmd_version, - cmd_script_size, - cmd_set_game_id, - cmd_log, /* 0x90 */ - cmd_set_scan_start, - cmd_reset_scan_start, - cmd_reposition_to, - cmd_reposition_to_f, - cmd_trace_on, - cmd_trace_info, - cmd_print_at, - cmd_print_at_v, /* 0x98 */ - cmd_discard_view, - cmd_clear_text_rect, - cmd_set_upper_left, - cmd_set_menu, - cmd_set_menu_item, - cmd_submit_menu, - cmd_enable_item, - cmd_disable_item, /* 0xa0 */ - cmd_menu_input, - cmd_show_obj_v, - cmd_open_dialogue, - cmd_close_dialogue, - cmd_mul_n, - cmd_mul_v, - cmd_div_n, - cmd_div_v, /* 0xa8 */ - cmd_close_window, - cmd_set_simple, - cmd_push_script, - cmd_pop_script, - cmd_hold_key, - cmd_set_pri_base, - cmd_discard_sound, - cmd_hide_mouse, /* 0xb0 */ - cmd_allow_menu, - cmd_show_mouse, - cmd_fence_mouse, - cmd_mouse_posn, - cmd_release_key, - cmd_adj_ego_move_to_x_y -}; - - -#define CMD_BSIZE 12 - -/** - * Execute a logic script - * @param n Number of the logic resource to execute - */ -int run_logic (int n) -{ - UINT8 op = 0; - UINT8 p[CMD_BSIZE] = { 0 }; - UINT8 *code = NULL; - int num = 0; - - // printf("run_logic %d\n", n); - - /* If logic not loaded, load it */ - if (~game.dir_logic[n].flags & RES_LOADED) { - _D (_D_WARN "logic %d not loaded!", n); - agi_load_resource (rLOGIC, n); - } - - game.lognum = n; - cur_logic = &game.logics[game.lognum]; - - code = cur_logic->data; - cur_logic->cIP = cur_logic->sIP; - - timer_hack = 0; - while (ip < game.logics[n].size && !game.quit_prog_now) { -#ifdef USE_CONSOLE - if (debug.enabled) { - if (debug.steps > 0) { - if (debug.logic0 || n) { - debug_console (n, - lCOMMAND_MODE, NULL); - debug.steps--; - } - } else { - blit_both (); - console_prompt (); - do { - main_cycle (); - } while (!debug.steps && debug.enabled); - console_lock (); - erase_both (); - } - } -#endif - - switch (op = *(code + ip++)) { - case 0xff: /* if (open/close) */ - test_if_code (n); - break; - case 0xfe: /* goto */ - /* +2 covers goto size */ - // printf("op: 0x%02x @ 0x%04x -> ", *(code + ip), ip); - ip += 2 + ((SINT16)lohi_getword (code + ip)); - // printf("0x%04x\n", ip); - /* timer must keep running even in goto loops, - * but Sarien can't do that :( - */ - if (timer_hack > 20) { - poll_timer (); - update_timer (); - timer_hack = 0; - } - break; - case 0x00: /* return */ - return 1; - default: - num = logic_names_cmd[op].num_args; - memmove (p, code + ip, num); - memset (p + num, 0, CMD_BSIZE - num); - agi_command[op](p); - ip += num; - } - - if (game.exit_all_logics) - break; - } - - return 0; /* after executing new.room() */ -} - - -void execute_agi_command (UINT8 op, UINT8 *p) -{ -#ifdef USE_CONSOLE - _D (_D_WARN "%s %d %d %d", logic_names_cmd[op].name, p[0], p[1], p[2]); -#endif - agi_command[op](p); -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: op_cmd.c,v 1.156 2003/10/16 22:15:51 bootstrap666 Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "rand.h" +#include "sprite.h" +#include "graphics.h" +#include "keyboard.h" +#include "opcodes.h" +#include "menu.h" +#include "savegame.h" +#include "text.h" + +#define p0 (p[0]) +#define p1 (p[1]) +#define p2 (p[2]) +#define p3 (p[3]) +#define p4 (p[4]) +#define p5 (p[5]) +#define p6 (p[6]) + +#define ip cur_logic->cIP +#define vt game.view_table[p0] + +static struct agi_logic *cur_logic; + +int timer_hack; /* Workaround for timer loop in MH1 */ + +#define _v game.vars +#define cmd(x) static void cmd_##x (UINT8 *p) + +cmd(increment) { if (_v[p0] != 0xff) ++_v[p0]; } +cmd(decrement) { if (_v[p0] != 0) --_v[p0]; } +cmd(assignn) { _v[p0] = p1; } +cmd(addn) { _v[p0] += p1; } +cmd(subn) { _v[p0] -= p1; } +cmd(assignv) { _v[p0] = _v[p1]; } +cmd(addv) { _v[p0] += _v[p1]; } +cmd(subv) { _v[p0] -= _v[p1]; } +cmd(mul_n) { _v[p0] *= p1; } +cmd(mul_v) { _v[p0] *= _v[p1]; } +cmd(div_n) { _v[p0] /= p1; } +cmd(div_v) { _v[p0] /= _v[p1]; } +cmd(random) { _v[p2] = rnd (1 + (p1 - p0)) + p0; } +cmd(lindirectn) { _v[_v[p0]] = p1; } +cmd(lindirectv) { _v[_v[p0]] = _v[p1]; } +cmd(rindirect) { _v[p0] = _v[_v[p1]]; } +cmd(set) { setflag (*p, TRUE); } +cmd(reset) { setflag (*p, FALSE); } +cmd(toggle) { setflag (*p, !getflag (*p)); } +cmd(set_v) { setflag (_v[p0], TRUE); } +cmd(reset_v) { setflag (_v[p0], FALSE); } +cmd(toggle_v) { setflag (_v[p0], !getflag (_v[p0])); } +cmd(new_room) { new_room (p0); } +cmd(new_room_f) { new_room (_v[p0]); } +cmd(load_view) { agi_load_resource (rVIEW, p0); } +cmd(load_logic) { agi_load_resource (rLOGIC, p0); } +cmd(load_sound) { agi_load_resource (rSOUND, p0); } +cmd(load_view_f) { agi_load_resource (rVIEW, _v[p0]); } +cmd(load_logic_f) { agi_load_resource (rLOGIC, _v[p0] ); } +cmd(discard_view) { agi_unload_resource (rVIEW, p0); } +cmd(object_on_anything) { vt.flags &= ~(ON_WATER | ON_LAND); } +cmd(object_on_land) { _D ("p0 = %d", p0); vt.flags |= ON_LAND; } +cmd(object_on_water) { _D ("p0 = %d", p0); vt.flags |= ON_WATER; } +cmd(observe_horizon) { _D ("p0 = %d", p0); vt.flags &= ~IGNORE_HORIZON; } +cmd(ignore_horizon) { _D ("p0 = %d", p0); vt.flags |= IGNORE_HORIZON; } +cmd(observe_objs) { _D ("p0 = %d", p0); vt.flags &= ~IGNORE_OBJECTS; } +cmd(ignore_objs) { _D ("p0 = %d", p0); vt.flags |= IGNORE_OBJECTS; } +cmd(observe_blocks) { _D ("p0 = %d", p0); vt.flags &= ~IGNORE_BLOCKS; } +cmd(ignore_blocks) { _D ("p0 = %d", p0); vt.flags |= IGNORE_BLOCKS; } +cmd(set_horizon) { _D ("p0 = %d", p0); game.horizon = p0; } +cmd(get_priority) { _v[p1] = vt.priority; } +cmd(set_priority) { vt.flags |= FIXED_PRIORITY; vt.priority = p1; } +cmd(set_priority_f) { vt.flags |= FIXED_PRIORITY; vt.priority = _v[p1]; } +cmd(release_priority) { vt.flags &= ~FIXED_PRIORITY; } +cmd(set_upper_left) { /* do nothing (AGI 2.917) */ } +cmd(start_update) { start_update (&vt); } +cmd(stop_update) { stop_update (&vt); } +cmd(current_view) { _v[p1] = vt.current_view; } +cmd(current_cel) { _v[p1] = vt.current_cel; _D ("v%d=%d", p1, _v[p1]); } +cmd(current_loop) { _v[p1] = vt.current_loop; } +cmd(last_cel) { _v[p1] = vt.loop_data->num_cels - 1; } +cmd(set_cel) { set_cel (&vt, p1); vt.flags &= ~DONTUPDATE; } +cmd(set_cel_f) { set_cel (&vt, _v[p1]); vt.flags &= ~DONTUPDATE; } +cmd(set_view) { _D ("o%d, %d", p0, p1); set_view (&vt, p1); } +cmd(set_view_f) { set_view (&vt, _v[p1]); } +cmd(set_loop) { set_loop (&vt, p1); } +cmd(set_loop_f) { set_loop (&vt, _v[p1]); } +cmd(number_of_loops) { _v[p1] = vt.num_loops; } +cmd(fix_loop) { vt.flags |= FIX_LOOP; } +cmd(release_loop) { vt.flags &= ~FIX_LOOP; } +cmd(step_size) { vt.step_size = _v[p1]; } +cmd(step_time) { vt.step_time = vt.step_time_count = _v[p1]; } +cmd(cycle_time) { vt.cycle_time = vt.cycle_time_count = _v[p1]; } +cmd(stop_cycling) { vt.flags &= ~CYCLING; } +cmd(start_cycling) { vt.flags |= CYCLING; } +cmd(normal_cycle) { vt.cycle = CYCLE_NORMAL; vt.flags |= CYCLING; } +cmd(reverse_cycle) { vt.cycle = CYCLE_REVERSE; vt.flags |= CYCLING; } +cmd(set_dir) { vt.direction = _v[p1]; } +cmd(get_dir) { _v[p1] = vt.direction; } +cmd(get_room_f) { _v[p1] = object_get_location (_v[p0]); } +cmd(put) { object_set_location (p0, _v[p1]); } +cmd(put_f) { object_set_location (_v[p0], _v[p1]); } +cmd(drop) { object_set_location (p0, 0); } +cmd(get) { object_set_location (p0, EGO_OWNED); } +cmd(get_f) { object_set_location (_v[p0], EGO_OWNED); } +cmd(word_to_string) { strcpy (game.strings[p0], game.ego_words[p1].word); } +cmd(open_dialogue) { _D ("p0 = %d", p0); game.has_window = TRUE; } +cmd(close_dialogue) { _D ("p0 = %d", p0); game.has_window = FALSE; } +cmd(close_window) { close_window (); } +cmd(status_line_on) { game.status_line = TRUE; write_status (); } +cmd(status_line_off) { game.status_line = FALSE; write_status (); } +cmd(show_obj) { show_obj (p0); } +cmd(show_obj_v) { show_obj (_v[p0]); } +cmd(sound) { start_sound (p0, p1); } +cmd(stop_sound) { stop_sound (); } +cmd(menu_input) { new_input_mode (INPUT_MENU); } +cmd(enable_item) { menu_set_item (p0, TRUE); } +cmd(disable_item) { menu_set_item (p0, FALSE); } +cmd(submit_menu) { menu_submit (); } +cmd(set_scan_start) { cur_logic->sIP = cur_logic->cIP; } +cmd(reset_scan_start) { cur_logic->sIP = 2; } +cmd(save_game) { game.simple_save ? + savegame_simple() : savegame_dialog(); } +cmd(load_game) { game.simple_save ? + loadgame_simple() : loadgame_dialog(); } +cmd(init_disk) { /* do nothing */ } +cmd(log) { /* do nothing */ } +cmd(trace_on) { /* do nothing */ } +cmd(trace_info) { /* do nothing */ } +cmd(show_mem) { message_box ("Enough memory"); } +cmd(init_joy) { /* do nothing */; } +cmd(script_size) { report ("script.size(%d)\n", p0); } +cmd(cancel_line) { report ("cancel.line\n"); } +cmd(obj_status_f) { report ("obj.status.f\n"); } + +/* unknown commands: + * unk_170: Force savegame name -- j5 + * unk_171: script save -- j5 + * unk_172: script restore -- j5 + * unk_173: Activate keypressed control (ego only moves while key is pressed) + * unk_174: Change priority table (used in KQ4) -- j5 + * unk_177: Disable menus completely -- j5 + * unk_181: Deactivate keypressed control (default control of ego) + */ +cmd(set_simple) { game.simple_save = TRUE; } +cmd(pop_script) { report ("pop.script\n"); } +cmd(hold_key) { report ("hold.key\n"); } +cmd(discard_sound) { report ("discard.sound\n"); } +cmd(hide_mouse) { report ("hide.mouse\n"); } +cmd(allow_menu) { report ("allow.menu\n"); } +cmd(show_mouse) { report ("show.mouse\n"); } +cmd(fence_mouse) { report ("fence.mouse\n"); } +cmd(release_key) { report ("release.key\n"); } +cmd(adj_ego_move_to_x_y){ game.view_table[0].flags |= ADJ_EGO_XY; } + + +cmd(parse) { + _v[V_word_not_found] = 0; + setflag (F_entered_cli, FALSE); + setflag (F_said_accepted_input, FALSE); + + dictionary_words (agi_sprintf(game.strings[p0])); +} + +cmd(call) { + int old_cIP; + int old_lognum; + + /* CM: we don't save sIP because set.scan.start can be + * used in a called script (fixes xmas demo) + */ + old_cIP = cur_logic->cIP; + old_lognum = game.lognum; + + run_logic (p0); + + game.lognum = old_lognum; + cur_logic = &game.logics[game.lognum]; + cur_logic->cIP = old_cIP; +} + +cmd(call_f) { + cmd_call (&_v[p0]); +} + +cmd(draw_pic) { + _D (_D_WARN "=== draw pic %d ===", _v[p0]); + erase_both (); + decode_picture (_v[p0], TRUE); + blit_both (); + game.picture_shown = 0; + _D (_D_WARN "--- end of draw pic %d ---", _v[p0]); +} + +cmd(show_pic) { + _D (_D_WARN "=== show pic ==="); + setflag (F_output_mode, FALSE); + cmd_close_window (NULL); + show_pic (); + game.picture_shown = 1; + _D (_D_WARN "--- end of show pic ---"); +} + +cmd(load_pic) { + erase_both (); + agi_load_resource (rPICTURE, _v[p0]); + blit_both (); +} + +cmd(discard_pic) { + _D (_D_WARN "--- discard pic ---"); + /* do nothing */ +} + +cmd(overlay_pic) { + _D (_D_WARN "--- overlay pic ---"); + erase_both (); + decode_picture (_v[p0], FALSE); + blit_both (); + game.picture_shown = 0; + commit_both (); +} + +cmd(show_pri_screen) { +#ifdef USE_CONSOLE + debug.priority = 1; + erase_both(); + show_pic (); + blit_both (); + wait_key (); + debug.priority = 0; + erase_both(); + show_pic (); + blit_both (); +#endif +} + +cmd(animate_obj) { + if (vt.flags & ANIMATED) + return; + + _D (_D_WARN "animate vt entry #%d", p0); + vt.flags = ANIMATED | UPDATE | CYCLING; + vt.motion = MOTION_NORMAL; + vt.cycle = CYCLE_NORMAL; + vt.direction = 0; +} + +cmd(unanimate_all) { + int i; + for (i = 0; i < MAX_VIEWTABLE; i++) + game.view_table[i].flags &= ~(ANIMATED | DRAWN); +} + +cmd(draw) { + if (vt.flags & DRAWN) + return; + + if (vt.y_size <= 0 || vt.x_size <= 0) + return; + + _D("draw entry %d", vt.entry); + + vt.flags |= UPDATE; + if (agi_get_release() >= 0x3000){ + set_loop(&vt,vt.current_loop); + set_cel(&vt,vt.current_cel); + } + fix_position (p0); + vt.x_pos2 = vt.x_pos; + vt.y_pos2 = vt.y_pos; + vt.cel_data_2 = vt.cel_data; + erase_upd_sprites (); + vt.flags |= DRAWN; + + if (agi_get_release() <= 0x2440) /* See bug #546562 */ + vt.flags |= ANIMATED; + + blit_upd_sprites (); + vt.flags &= ~DONTUPDATE; + + commit_block (vt.x_pos, vt.y_pos - vt.y_size + 1, + vt.x_pos + vt.x_size - 1, vt.y_pos); + + _D ("vt entry #%d flags = %02x", p0, vt.flags); +} + +cmd(erase) { + if (~vt.flags & DRAWN) + return; + + erase_upd_sprites (); + if (vt.flags & UPDATE) { + vt.flags &= ~DRAWN; + } else { + erase_nonupd_sprites (); + vt.flags &= ~DRAWN; + blit_nonupd_sprites (); + } + blit_upd_sprites (); + + commit_block (vt.x_pos, vt.y_pos - vt.y_size + 1, + vt.x_pos + vt.x_size - 1, vt.y_pos); +} + +cmd(position) { + vt.x_pos = vt.x_pos2 = p1; + vt.y_pos = vt.y_pos2 = p2; +} + +cmd(position_f) { + vt.x_pos = vt.x_pos2 = _v[p1]; + vt.y_pos = vt.y_pos2 = _v[p2]; +} + +cmd(get_posn) { + game.vars[p1] = (unsigned char)vt.x_pos; + game.vars[p2] = (unsigned char)vt.y_pos; +} + +cmd(reposition) { + int dx = (SINT8)_v[p1], dy = (SINT8)_v[p2]; + + _D ("dx=%d, dy=%d", dx, dy); + vt.flags |= UPDATE_POS; + + if (dx < 0 && vt.x_pos < -dx) + vt.x_pos = 0; + else + vt.x_pos += dx; + + if (dy < 0 && vt.y_pos < -dy) + vt.y_pos = 0; + else + vt.y_pos += dy; + + fix_position (p0); +} + +cmd(reposition_to) { + vt.x_pos = p1; + vt.y_pos = p2; + vt.flags |= UPDATE_POS; + fix_position (p0); +} + +cmd(reposition_to_f) { + vt.x_pos = _v[p1]; + vt.y_pos = _v[p2]; + vt.flags |= UPDATE_POS; + fix_position (p0); +} + +cmd(add_to_pic) { + add_to_pic (p0, p1, p2, p3, p4, p5, p6); +} + +cmd(add_to_pic_f) { + add_to_pic (_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]); +} + +cmd(force_update) { + erase_both (); + blit_both (); + commit_both (); +} + +cmd(reverse_loop) { + _D (_D_WARN "o%d, f%d", p0, p1); + vt.cycle = CYCLE_REV_LOOP; + vt.flags |= (DONTUPDATE|UPDATE|CYCLING); + vt.parm1 = p1; + setflag (p1, FALSE); +} + +cmd(end_of_loop) { + _D (_D_WARN "o%d, f%d", p0, p1); + vt.cycle = CYCLE_END_OF_LOOP; + vt.flags |= (DONTUPDATE|UPDATE|CYCLING); + vt.parm1 = p1; + setflag (p1, FALSE); +} + +cmd(block) { + _D (_D_WARN "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3); + game.block.active = TRUE; + game.block.x1 = p0; + game.block.y1 = p1; + game.block.x2 = p2; + game.block.y2 = p3; +} + +cmd(unblock) { + game.block.active = FALSE; +} + +cmd(normal_motion) { + vt.motion = MOTION_NORMAL; +} + +cmd(stop_motion) { + vt.direction = 0; + vt.motion = MOTION_NORMAL; + if (p0 == 0) { /* ego only */ + _v[V_ego_dir] = 0; + game.player_control = FALSE; + } +} + +cmd(start_motion) { + vt.motion = MOTION_NORMAL; + if (p0 == 0) { /* ego only */ + _v[V_ego_dir] = 0; + game.player_control = TRUE; + } +} + +cmd(player_control) { + game.player_control = TRUE; + game.view_table[0].motion = MOTION_NORMAL; +} + +cmd(program_control) { + game.player_control = FALSE; +} + +cmd(follow_ego) { + vt.motion = MOTION_FOLLOW_EGO; + vt.parm1 = p1 > vt.step_size ? p1 : vt.step_size; + vt.parm2 = p2; + vt.parm3 = 0xff; + setflag (p2, FALSE); + vt.flags |= UPDATE; +} + +cmd(move_obj) { + /* _D (_D_WARN "o=%d, x=%d, y=%d, s=%d, f=%d", p0, p1, p2, p3, p4); */ + + vt.motion = MOTION_MOVE_OBJ; + vt.parm1 = p1; + vt.parm2 = p2; + vt.parm3 = vt.step_size; + vt.parm4 = p4; + + if (p3 != 0) + vt.step_size = p3; + + setflag (p4, FALSE); + vt.flags |= UPDATE; + + if (p0 == 0) + game.player_control = FALSE; + + /* AGI 2.272 (ddp, xmas) doesn't call move_obj! */ + if (agi_get_release() > 0x2272) + move_obj (&vt); +} + +cmd(move_obj_f) { + vt.motion = MOTION_MOVE_OBJ; + vt.parm1 = _v[p1]; + vt.parm2 = _v[p2]; + vt.parm3 = vt.step_size; + vt.parm4 = p4; + + if (_v[p3] != 0) + vt.step_size = _v[p3]; + + setflag (p4, FALSE); + vt.flags |= UPDATE; + + if (p0 == 0) + game.player_control = FALSE; + + /* AGI 2.272 (ddp, xmas) doesn't call move_obj! */ + if (agi_get_release() > 0x2272) + move_obj (&vt); +} + +cmd(wander) { + if (p0 == 0) + game.player_control = FALSE; + vt.motion = MOTION_WANDER; + vt.flags |= UPDATE; +} + + +cmd(set_game_id) { + if (cur_logic->texts && (p0 - 1) <= cur_logic->num_texts) + strncpy (game.id, cur_logic->texts[p0 - 1], 8); + else + game.id[0] = 0; + + report ("Game ID: \"%s\"\n", game.id); +} + +cmd(pause) { + int tmp = game.clock_enabled; + char *b[] = { "Continue", NULL }; + + game.clock_enabled = FALSE; + selection_box (" Game is paused. \n\n\n", b); + game.clock_enabled = tmp; +} + +cmd(set_menu) { + _D ("text %02x of %02x", p0, cur_logic->num_texts); + if (cur_logic->texts != NULL && p0 < cur_logic->num_texts) + menu_add (cur_logic->texts[p0 - 1]); +} + +cmd(set_menu_item) { + _D ("text %02x of %02x", p0, cur_logic->num_texts); + if (cur_logic->texts != NULL && p0 <= cur_logic->num_texts) + menu_add_item (cur_logic->texts[p0 - 1], p1); +} + +cmd(version) { + char ver_msg[] = TITLE " v" VERSION; + char ver2_msg[] = + "\n" + " \n\n" + "Emulating Sierra AGI v%x.%03x\n"; + char ver3_msg[]= + "\n" + " \n\n" + " Emulating AGI v%x.002.%03x\n"; + /* no Sierra as it wraps textbox */ + char *r, *q; + int ver, maj, min; + char msg[256]; + + ver = agi_get_release (); + maj = (ver >> 12) & 0xf; + min = ver & 0xfff; + + q = maj == 2 ? ver2_msg : ver3_msg; + r = strchr (q+1, '\n'); + + strncpy (q+1 + ((r-q > 0 ? r - q : 1) / 4), ver_msg, strlen (ver_msg)); + sprintf (msg, q, maj, min); + message_box (msg); +} + +cmd(configure_screen) { + game.line_min_print = p0; + game.line_user_input = p1; + game.line_status = p2; +} + +cmd(text_screen) { + _D (_D_WARN "switching to text mode"); + game.gfx_mode = FALSE; + /* + * Simulates the "bright background bit" of the PC video + * controller. + */ + if (game.color_bg) + game.color_bg |= 0x08; + clear_screen (game.color_bg); +} + +cmd(graphics) { + _D (_D_WARN "switching to graphics mode"); + if (!game.gfx_mode) { + game.gfx_mode = TRUE; + clear_screen (0); + show_pic (); + write_status (); + write_prompt (); + } +} + +cmd(set_text_attribute) { + game.color_fg = p0; + game.color_bg = p1; + + if (game.gfx_mode) { + if (game.color_bg != 0) { + game.color_fg = 0; + game.color_bg = 15; + } + } +} + +cmd(status) { + inventory(); +} + +cmd(quit) { + char *buttons[] = { "Quit", "Continue", NULL }; + + stop_sound (); + if (p0) { + game.quit_prog_now = TRUE; + } else { + if (selection_box (" Quit the game, or continue? \n\n\n", + buttons) == 0) + { + game.quit_prog_now = TRUE; + } + } +} + +cmd(restart_game) { + char *buttons[] = { "Restart", "Continue", NULL }; + int sel; + + stop_sound(); + sel = getflag(F_auto_restart) ? 1 : + selection_box (" Restart game, or continue? \n\n\n", buttons); + + if (sel == 0) { + game.quit_prog_now = 0xff; + setflag (F_restart_game, TRUE); + menu_enable_all(); + } +} + +cmd(distance) { + SINT16 x1, y1, x2, y2, d; + struct vt_entry *v0 = &game.view_table[p0]; + struct vt_entry *v1 = &game.view_table[p1]; + + if (v0->flags & DRAWN && v1->flags & DRAWN) { + x1 = v0->x_pos + v0->x_size / 2; + y1 = v0->y_pos; + x2 = v1->x_pos + v1->x_size / 2; + y2 = v1->y_pos; + d = abs (x1 - x2) + abs (y1 - y2); + if (d > 0xfe) d = 0xfe; + } else { + d = 0xff; + } + _v[p2] = (unsigned char)d; +} + +cmd(accept_input) { + _D (_D_WARN "input normal"); + new_input_mode (INPUT_NORMAL); + game.input_enabled = TRUE; +} + +cmd(prevent_input) { + _D (_D_WARN "no input"); + new_input_mode (INPUT_NONE); + game.input_enabled = FALSE; +} + +cmd(get_string) { + int tex, row, col; + + _D ("%d %d %d %d %d", p0, p1, p2, p3, p4); + + tex = p1 - 1; + row = p2; + col = p3; + + /* Workaround for SQLC bug. + * See bug #792125 for details + */ + if (row > 24) row = 24; + if (col > 39) col = 39; + + new_input_mode (INPUT_GETSTRING); + + if (cur_logic->texts != NULL && cur_logic->num_texts >= tex) { + int len = strlen (cur_logic->texts[tex]); + print_text (cur_logic->texts[tex], 0, col, + row, len, game.color_fg, game.color_bg); + get_string (col + len - 1, row, p4, p0); + + /* SGEO: display input char */ + print_character ((col + len), row, game.cursor_char, + game.color_fg, game.color_bg); + } + + do { + main_cycle (); + } while (game.input_mode == INPUT_GETSTRING); +} + + +cmd(get_num) { + _D ("%d %d", p0, p1); + new_input_mode (INPUT_GETSTRING); + + if (cur_logic->texts != NULL && cur_logic->num_texts >= (p0 - 1)) { + int len = strlen (cur_logic->texts[p0 - 1]); + print_text (cur_logic->texts[p0 - 1], 0, 0, 22, len, + game.color_fg, game.color_bg); + get_string (len - 1, 22, 3, MAX_STRINGS); + + /* CM: display input char */ + print_character ((p3 + len), 22, game.cursor_char, + game.color_fg, game.color_bg); + } + + do { + main_cycle (); + } while (game.input_mode == INPUT_GETSTRING); + + _v[p1] = atoi (game.strings[MAX_STRINGS]); + _D (_D_WARN "[%s] -> %d", game.strings[MAX_STRINGS], _v[p1]); + clear_lines (22, 22, game.color_bg); + flush_lines (22, 22); +} + +cmd(set_cursor_char) { + if (cur_logic->texts != NULL && (p0 - 1) <= cur_logic->num_texts) { + game.cursor_char = *cur_logic->texts[p0 - 1]; + } else { + /* default */ + game.cursor_char = '_'; + } +} + +cmd(set_key) { + int key; + + _D ("%d %d %d", p0, p1, p2); + + if (game.ev_keyp[p2].data != 0) /* TBC sets c23 (ESC) twice! */ + return; + + key = 256 * p1 + p0; + game.ev_keyp[p2].data = key; + game.ev_keyp[p2].occured = FALSE; +} + +cmd(set_string) { + /* CM: to avoid crash in Groza (str = 150) */ + if (p0 > MAX_STRINGS) return; + strcpy (game.strings[p0], cur_logic->texts[p1 - 1]); +} + +cmd(display) { + print_text (cur_logic->texts[p2 - 1], p1, 0, p0, 40, + game.color_fg, game.color_bg); +} + +cmd(display_f) { + _D ("p0 = %d", p0); + print_text (cur_logic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, + game.color_fg, game.color_bg); +} + +cmd(clear_text_rect) { + int c, x1, y1, x2, y2; + + if ((c = p4) != 0) c = 15; + x1 = p1 * CHAR_COLS; + y1 = p0 * CHAR_LINES; + x2 = (p3 + 1) * CHAR_COLS - 1; + y2 = (p2 + 1) * CHAR_LINES - 1; + + /* Added to prevent crash with x2 = 40 in the iigs demo */ + if (x1 > GFX_WIDTH) x1 = GFX_WIDTH - 1; + if (x2 > GFX_WIDTH) x2 = GFX_WIDTH - 1; + if (y1 > GFX_HEIGHT) y1 = GFX_HEIGHT - 1; + if (y2 > GFX_HEIGHT) y2 = GFX_HEIGHT - 1; + + draw_rectangle (x1, y1, x2, y2, c); + flush_block (x1, y1, x2, y2); +} + +cmd(toggle_monitor) { + report ("toggle.monitor\n"); +#ifdef USE_HIRES + opt.hires = !opt.hires; + erase_both(); + show_pic (); + blit_both (); +#endif +} + +cmd(echo_line) { + strcpy (game.input_buffer, game.echo_buffer); + game.cursor_pos = strlen ((char*)game.input_buffer); + game.has_prompt = 0; +} + +cmd(clear_lines) { + UINT8 l; + + /* Residence 44 calls clear.lines(24,0,0), see bug #558423 */ + l = p1 ? p1 : p0; + + clear_lines (p0, l, p2); + flush_lines (p0, l); +} + +cmd(print) { + int n = p0 < 1 ? 1 : p0; + print (cur_logic->texts[n - 1], 0, 0, 0); +} + +cmd(print_f) { + int n = _v[p0] < 1 ? 1 : _v[p0]; + print (cur_logic->texts[n - 1], 0, 0, 0); +} + +cmd(print_at) { + int n = p0 < 1 ? 1 : p0; + _D ("%d %d %d %d", p0, p1, p2, p3); + print (cur_logic->texts[n - 1], p1, p2, p3); +} + +cmd(print_at_v) { + int n = _v[p0] < 1 ? 1 : _v[p0]; + print (cur_logic->texts[n - 1], p1, p2, p3); +} + +cmd(push_script) { +#ifdef USE_MOUSE + if (opt.agimouse) { + game.vars[27] = mouse.button; + game.vars[28] = mouse.x / 2; + game.vars[29] = mouse.y; + } else +#endif + report ("push.script\n"); +} + +cmd(set_pri_base) { + int i, x, pri; + + report ("Priority base set to %d\n", p0); + + /* game.alt_pri = TRUE; */ + x = (_HEIGHT - p0) * _HEIGHT / 10; + + for (i = 0; i < _HEIGHT; i++) { + pri = (i - p0) < 0 ? 4 : (i - p0) * _HEIGHT / x + 5; + if (pri > 15) + pri = 15; + game.pri_table[i] = pri; + } +} + +cmd(mouse_posn) { +#ifdef USE_MOUSE + _v[p0] = WIN_TO_PIC_X(mouse.x); + _v[p1] = WIN_TO_PIC_Y(mouse.y); +#endif +} + +cmd(shake_screen) { + int i; + +#ifdef USE_MOUSE + /* AGI Mouse 1.1 uses shake.screen values between 100 and 109 to + * set the palette. + */ + if (opt.agimouse && p0 >= 100 && p0 < 110) { + report ("not implemented: AGI Mouse palettes\n"); + return; + } + else +#endif + + shake_start (); + commit_both (); /* Fixes SQ1 demo */ + for (i = 4 * p0; i; i--) { + shake_screen (i & 1); + flush_block (0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); + main_cycle (); + } + shake_end (); +} + + +static void (*agi_command[183])(UINT8 *) = { + NULL, /* 0x00 */ + cmd_increment, + cmd_decrement, + cmd_assignn, + cmd_assignv, + cmd_addn, + cmd_addv, + cmd_subn, + cmd_subv, /* 0x08 */ + cmd_lindirectv, + cmd_rindirect, + cmd_lindirectn, + cmd_set, + cmd_reset, + cmd_toggle, + cmd_set_v, + cmd_reset_v, /* 0x10 */ + cmd_toggle_v, + cmd_new_room, + cmd_new_room_f, + cmd_load_logic, + cmd_load_logic_f, + cmd_call, + cmd_call_f, + cmd_load_pic, /* 0x18 */ + cmd_draw_pic, + cmd_show_pic, + cmd_discard_pic, + cmd_overlay_pic, + cmd_show_pri_screen, + cmd_load_view, + cmd_load_view_f, + cmd_discard_view, /* 0x20 */ + cmd_animate_obj, + cmd_unanimate_all, + cmd_draw, + cmd_erase, + cmd_position, + cmd_position_f, + cmd_get_posn, + cmd_reposition, /* 0x28 */ + cmd_set_view, + cmd_set_view_f, + cmd_set_loop, + cmd_set_loop_f, + cmd_fix_loop, + cmd_release_loop, + cmd_set_cel, + cmd_set_cel_f, /* 0x30 */ + cmd_last_cel, + cmd_current_cel, + cmd_current_loop, + cmd_current_view, + cmd_number_of_loops, + cmd_set_priority, + cmd_set_priority_f, + cmd_release_priority, /* 0x38 */ + cmd_get_priority, + cmd_stop_update, + cmd_start_update, + cmd_force_update, + cmd_ignore_horizon, + cmd_observe_horizon, + cmd_set_horizon, + cmd_object_on_water, /* 0x40 */ + cmd_object_on_land, + cmd_object_on_anything, + cmd_ignore_objs, + cmd_observe_objs, + cmd_distance, + cmd_stop_cycling, + cmd_start_cycling, + cmd_normal_cycle, /* 0x48 */ + cmd_end_of_loop, + cmd_reverse_cycle, + cmd_reverse_loop, + cmd_cycle_time, + cmd_stop_motion, + cmd_start_motion, + cmd_step_size, + cmd_step_time, /* 0x50 */ + cmd_move_obj, + cmd_move_obj_f, + cmd_follow_ego, + cmd_wander, + cmd_normal_motion, + cmd_set_dir, + cmd_get_dir, + cmd_ignore_blocks, /* 0x58 */ + cmd_observe_blocks, + cmd_block, + cmd_unblock, + cmd_get, + cmd_get_f, + cmd_drop, + cmd_put, + cmd_put_f, /* 0x60 */ + cmd_get_room_f, + cmd_load_sound, + cmd_sound, + cmd_stop_sound, + cmd_print, + cmd_print_f, + cmd_display, + cmd_display_f, /* 0x68 */ + cmd_clear_lines, + cmd_text_screen, + cmd_graphics, + cmd_set_cursor_char, + cmd_set_text_attribute, + cmd_shake_screen, + cmd_configure_screen, + cmd_status_line_on, /* 0x70 */ + cmd_status_line_off, + cmd_set_string, + cmd_get_string, + cmd_word_to_string, + cmd_parse, + cmd_get_num, + cmd_prevent_input, + cmd_accept_input, /* 0x78 */ + cmd_set_key, + cmd_add_to_pic, + cmd_add_to_pic_f, + cmd_status, + cmd_save_game, + cmd_load_game, + cmd_init_disk, + cmd_restart_game, /* 0x80 */ + cmd_show_obj, + cmd_random, + cmd_program_control, + cmd_player_control, + cmd_obj_status_f, + cmd_quit, + cmd_show_mem, + cmd_pause, /* 0x88 */ + cmd_echo_line, + cmd_cancel_line, + cmd_init_joy, + cmd_toggle_monitor, + cmd_version, + cmd_script_size, + cmd_set_game_id, + cmd_log, /* 0x90 */ + cmd_set_scan_start, + cmd_reset_scan_start, + cmd_reposition_to, + cmd_reposition_to_f, + cmd_trace_on, + cmd_trace_info, + cmd_print_at, + cmd_print_at_v, /* 0x98 */ + cmd_discard_view, + cmd_clear_text_rect, + cmd_set_upper_left, + cmd_set_menu, + cmd_set_menu_item, + cmd_submit_menu, + cmd_enable_item, + cmd_disable_item, /* 0xa0 */ + cmd_menu_input, + cmd_show_obj_v, + cmd_open_dialogue, + cmd_close_dialogue, + cmd_mul_n, + cmd_mul_v, + cmd_div_n, + cmd_div_v, /* 0xa8 */ + cmd_close_window, + cmd_set_simple, + cmd_push_script, + cmd_pop_script, + cmd_hold_key, + cmd_set_pri_base, + cmd_discard_sound, + cmd_hide_mouse, /* 0xb0 */ + cmd_allow_menu, + cmd_show_mouse, + cmd_fence_mouse, + cmd_mouse_posn, + cmd_release_key, + cmd_adj_ego_move_to_x_y +}; + + +#define CMD_BSIZE 12 + +/** + * Execute a logic script + * @param n Number of the logic resource to execute + */ +int run_logic (int n) +{ + UINT8 op = 0; + UINT8 p[CMD_BSIZE] = { 0 }; + UINT8 *code = NULL; + int num = 0; + + // printf("run_logic %d\n", n); + + /* If logic not loaded, load it */ + if (~game.dir_logic[n].flags & RES_LOADED) { + _D (_D_WARN "logic %d not loaded!", n); + agi_load_resource (rLOGIC, n); + } + + game.lognum = n; + cur_logic = &game.logics[game.lognum]; + + code = cur_logic->data; + cur_logic->cIP = cur_logic->sIP; + + timer_hack = 0; + while (ip < game.logics[n].size && !game.quit_prog_now) { +#ifdef USE_CONSOLE + if (debug.enabled) { + if (debug.steps > 0) { + if (debug.logic0 || n) { + debug_console (n, + lCOMMAND_MODE, NULL); + debug.steps--; + } + } else { + blit_both (); + console_prompt (); + do { + main_cycle (); + } while (!debug.steps && debug.enabled); + console_lock (); + erase_both (); + } + } +#endif + + switch (op = *(code + ip++)) { + case 0xff: /* if (open/close) */ + test_if_code (n); + break; + case 0xfe: /* goto */ + /* +2 covers goto size */ + // printf("op: 0x%02x @ 0x%04x -> ", *(code + ip), ip); + ip += 2 + ((SINT16)lohi_getword (code + ip)); + // printf("0x%04x\n", ip); + /* timer must keep running even in goto loops, + * but Sarien can't do that :( + */ + if (timer_hack > 20) { + poll_timer (); + update_timer (); + timer_hack = 0; + } + break; + case 0x00: /* return */ + return 1; + default: + num = logic_names_cmd[op].num_args; + memmove (p, code + ip, num); + memset (p + num, 0, CMD_BSIZE - num); + agi_command[op](p); + ip += num; + } + + if (game.exit_all_logics) + break; + } + + return 0; /* after executing new.room() */ +} + + +void execute_agi_command (UINT8 op, UINT8 *p) +{ +#ifdef USE_CONSOLE + _D (_D_WARN "%s %d %d %d", logic_names_cmd[op].name, p[0], p[1], p[2]); +#endif + agi_command[op](p); +} + diff --git a/op_dbg.c b/op_dbg.c index 06710be..a248425 100644 --- a/op_dbg.c +++ b/op_dbg.c @@ -1,342 +1,342 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: op_dbg.c,v 1.11 2001/08/26 12:23:37 darkfiber Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include "sarien.h" -#include "agi.h" -#include "opcodes.h" - -#define ip (game.logics[lognum].cIP) -#define code (game.logics[lognum].data) - -#ifdef _L -#undef _L -#endif - -#ifdef USE_CONSOLE -#define _L(a,b,c) { a, b, c } -#else -#define _L(a,b,c) { b, c } -#endif - -struct agi_logicnames logic_names_test[] = { - _L("", 0, 0x00), - _L("equaln", 2, 0x80), - _L("equalv", 2, 0xC0), - _L("lessn", 2, 0x80), - _L("lessv", 2, 0xC0), - _L("greatern", 2, 0x80), - _L("greaterv", 2, 0xC0), - _L("isset", 1, 0x00), - _L("issetv", 1, 0x80), - _L("has", 1, 0x00), - _L("obj.in.room", 2, 0x40), - _L("posn", 5, 0x00), - _L("controller", 1, 0x00), - _L("have.key", 0, 0x00), - - /* Not 0 args. Has variable number. */ - _L("said", 0, 0x00), - - _L("compare.strings", 2, 0x00), - _L("obj.in.box", 5, 0x00), - _L("center.posn", 5, 0x00), - _L("right.posn", 5, 0x00) -}; - -struct agi_logicnames logic_names_if[]= { - _L("OR", 0, 0x00), - _L("NOT", 0, 0x00), - _L("ELSE", 0, 0x00), - _L("IF", 0, 0x00) -}; - -struct agi_logicnames logic_names_cmd[]= { - _L("return", 0, 0x00), /* 00 */ - _L("increment", 1, 0x80), /* 01 */ - _L("decrement", 1, 0x80), /* 02 */ - _L("assignn", 2, 0x80), /* 03 */ - _L("assignv", 2, 0xC0), /* 04 */ - _L("addn", 2, 0x80), /* 05 */ - _L("addv", 2, 0xC0), /* 06 */ - _L("subn", 2, 0x80), /* 07 */ - _L("subv", 2, 0xC0), /* 08 */ - _L("lindirectv", 2, 0xC0), /* 09 */ - _L("rindirect", 2, 0xC0), /* 0A */ - _L("lindirectn", 2, 0x80), /* 0B */ - _L("set", 1, 0x00), /* 0C */ - _L("reset", 1, 0x00), /* 0D */ - _L("toggle", 1, 0x00), /* 0E */ - _L("set.v", 1, 0x80), /* 0F */ - _L("reset.v", 1, 0x80), /* 10 */ - _L("toggle.v", 1, 0x80), /* 11 */ - _L("new.room", 1, 0x00), /* 12 */ - _L("new.room.v", 1, 0x80), /* 13 */ - _L("load.logics", 1, 0x00), /* 14 */ - _L("load.logics.v", 1, 0x80), /* 15 */ - _L("call", 1, 0x00), /* 16 */ - _L("call.v", 1, 0x80), /* 17 */ - _L("load.pic", 1, 0x80), /* 18 */ - _L("draw.pic", 1, 0x80), /* 19 */ - _L("show.pic", 0, 0x00), /* 1A */ - _L("discard.pic", 1, 0x80), /* 1B */ - _L("overlay.pic", 1, 0x80), /* 1C */ - _L("show.pri.screen", 0, 0x00), /* 1D */ - _L("load.view", 1, 0x00), /* 1E */ - _L("load.view.v", 1, 0x80), /* 1F */ - _L("discard.view", 1, 0x00), /* 20 */ - _L("animate.obj", 1, 0x00), /* 21 */ - _L("unanimate.all", 0, 0x00), /* 22 */ - _L("draw", 1, 0x00), /* 23 */ - _L("erase", 1, 0x00), /* 24 */ - _L("position", 3, 0x00), /* 25 */ - _L("position.v", 3, 0x60), /* 26 */ - _L("get.posn", 3, 0x60), /* 27 */ - _L("reposition", 3, 0x60), /* 28 */ - _L("set.view", 2, 0x00), /* 29 */ - _L("set.view.v", 2, 0x40), /* 2A */ - _L("set.loop", 2, 0x00), /* 2B */ - _L("set.loop.v", 2, 0x40), /* 2C */ - _L("fix.loop", 1, 0x00), /* 2D */ - _L("release.loop", 1, 0x00), /* 2E */ - _L("set.cel", 2, 0x00), /* 2F */ - _L("set.cel.v", 2, 0x40), /* 30 */ - _L("last.cel", 2, 0x40), /* 31 */ - _L("current.cel", 2, 0x40), /* 32 */ - _L("current.loop", 2, 0x40), /* 33 */ - _L("current.view", 2, 0x40), /* 34 */ - _L("number.of.loops", 2, 0x40), /* 35 */ - _L("set.priority", 2, 0x00), /* 36 */ - _L("set.priority.v", 2, 0x40), /* 37 */ - _L("release.priority", 1, 0x00), /* 38 */ - _L("get.priority", 2, 0x40), /* 39 */ - _L("stop.update", 1, 0x00), /* 3A */ - _L("start.update", 1, 0x00), /* 3B */ - _L("force.update", 1, 0x00), /* 3C */ - _L("ignore.horizon", 1, 0x00), /* 3D */ - _L("observe.horizon", 1, 0x00), /* 3E */ - _L("set.horizon", 1, 0x00), /* 3F */ - _L("object.on.water", 1, 0x00), /* 40 */ - _L("object.on.land", 1, 0x00), /* 41 */ - _L("object.on.anything",1, 0x00), /* 42 */ - _L("ignore.objs", 1, 0x00), /* 43 */ - _L("observe.objs", 1, 0x00), /* 44 */ - _L("distance", 3, 0x20), /* 45 */ - _L("stop.cycling", 1, 0x00), /* 46 */ - _L("start.cycling", 1, 0x00), /* 47 */ - _L("normal.cycle", 1, 0x00), /* 48 */ - _L("end.of.loop", 2, 0x00), /* 49 */ - _L("reverse.cycle", 1, 0x00), /* 4A */ - _L("reverse.loop", 2, 0x00), /* 4B */ - _L("cycle.time", 2, 0x40), /* 4C */ - _L("stop.motion", 1, 0x00), /* 4D */ - _L("start.motion", 1, 0x00), /* 4E */ - _L("step.size", 2, 0x40), /* 4F */ - _L("step.time", 2, 0x40), /* 50 */ - _L("move.obj", 5, 0x00), /* 51 */ - _L("move.obj.v", 5, 0x70), /* 52 */ - _L("follow.ego", 3, 0x00), /* 53 */ - _L("wander", 1, 0x00), /* 54 */ - _L("normal.motion", 1, 0x00), /* 55 */ - _L("set.dir", 2, 0x40), /* 56 */ - _L("get.dir", 2, 0x40), /* 57 */ - _L("ignore.blocks", 1, 0x00), /* 58 */ - _L("observe.blocks", 1, 0x00), /* 59 */ - _L("block", 4, 0x00), /* 5A */ - _L("unblock", 0, 0x00), /* 5B */ - _L("get", 1, 0x00), /* 5C */ - _L("get.v", 1, 0x80), /* 5D */ - _L("drop", 1, 0x00), /* 5E */ - _L("put", 2, 0x00), /* 5F */ - _L("put.v", 2, 0x40), /* 60 */ - _L("get.room.v", 2, 0xC0), /* 61 */ - _L("load.sound", 1, 0x00), /* 62 */ - _L("sound", 2, 0x00), /* 63 */ - _L("stop.sound", 0, 0x00), /* 64 */ - _L("print", 1, 0x00), /* 65 */ - _L("print.v", 1, 0x80), /* 66 */ - _L("display", 3, 0x00), /* 67 */ - _L("display.v", 3, 0xE0), /* 68 */ - _L("clear.lines", 3, 0x00), /* 69 */ - _L("text.screen", 0, 0x00), /* 6A */ - _L("graphics", 0, 0x00), /* 6B */ - _L("set.cursor.char", 1, 0x00), /* 6C */ - _L("set.text.attribute",2, 0x00), /* 6D */ - _L("shake.screen", 1, 0x00), /* 6E */ - _L("configure.screen", 3, 0x00), /* 6F */ - _L("status.line.on", 0, 0x00), /* 70 */ - _L("status.line.off", 0, 0x00), /* 71 */ - _L("set.string", 2, 0x00), /* 72 */ - _L("get.string", 5, 0x00), /* 73 */ - _L("word.to.string", 2, 0x00), /* 74 */ - _L("parse", 1, 0x00), /* 75 */ - _L("get.num", 2, 0x40), /* 76 */ - _L("prevent.input", 0, 0x00), /* 77 */ - _L("accept.input", 0, 0x00), /* 78 */ - _L("set.key", 3, 0x00), /* 79 */ - _L("add.to.pic", 7, 0x00), /* 7A */ - _L("add.to.pic.v", 7, 0xFE), /* 7B */ - _L("status", 0, 0x00), /* 7C */ - _L("save.game", 0, 0x00), /* 7D */ - _L("restore.game", 0, 0x00), /* 7E */ - _L("init.disk", 0, 0x00), /* 7F */ - _L("restart.game", 0, 0x00), /* 80 */ - _L("show.obj", 1, 0x00), /* 81 */ - _L("random", 3, 0x20), /* 82 */ - _L("program.control", 0, 0x00), /* 83 */ - _L("player.control", 0, 0x00), /* 84 */ - _L("obj.status.v", 1, 0x80), /* 85 */ - /* 0 args for AGI version 2.089 */ - _L("quit", 1, 0x00), /* 86 */ - - _L("show.mem", 0, 0x00), /* 87 */ - _L("pause", 0, 0x00), /* 88 */ - _L("echo.line", 0, 0x00), /* 89 */ - _L("cancel.line", 0, 0x00), /* 8A */ - _L("init.joy", 0, 0x00), /* 8B */ - _L("toggle.monitor", 0, 0x00), /* 8C */ - _L("version", 0, 0x00), /* 8D */ - _L("script.size", 1, 0x00), /* 8E */ - _L("set.game.id", 1, 0x00), /* 8F */ - _L("log", 1, 0x00), /* 90 */ - _L("set.scan.start", 0, 0x00), /* 91 */ - _L("reset.scan.start", 0, 0x00), /* 92 */ - _L("reposition.to", 3, 0x00), /* 93 */ - _L("reposition.to.v", 3, 0x60), /* 94 */ - _L("trace.on", 0, 0x00), /* 95 */ - _L("trace.info", 3, 0x00), /* 96 */ - - /* 3 args for AGI versions before 2.440 */ - _L("print.at", 4, 0x00), /* 97 */ - _L("print.at.v", 4, 0x80), /* 98 */ - - _L("discard.view.v", 1, 0x80), /* 99 */ - _L("clear.text.rect", 5, 0x00), /* 9A */ - _L("set.upper.left", 2, 0x00), /* 9B */ - _L("set.menu", 1, 0x00), /* 9C */ - _L("set.menu.item", 2, 0x00), /* 9D */ - _L("submit.menu", 0, 0x00), /* 9E */ - _L("enable.item", 1, 0x00), /* 9F */ - _L("disable.item", 1, 0x00), /* A0 */ - _L("menu.input", 0, 0x00), /* A1 */ - _L("show.obj.v", 1, 0x01), /* A2 */ - _L("open.dialogue", 0, 0x00), /* A3 */ - _L("close.dialogue", 0, 0x00), /* A4 */ - _L("mul.n", 2, 0x80), /* A5 */ - _L("mul.v", 2, 0xC0), /* A6 */ - _L("div.n", 2, 0x80), /* A7 */ - _L("div.v", 2, 0xC0), /* A8 */ - _L("close.window", 0, 0x00), /* A9 */ - - _L("set.simple", 1, 0x00), /* AA */ - _L("push.script", 0, 0x00), /* AB */ - _L("pop.script", 0, 0x00), /* AC */ - _L("hold.key", 0, 0x00), /* AD */ - _L("set.pri.base", 1, 0x00), /* AE */ - _L("discard.sound", 1, 0x00), /* AF */ - - /* 1 arg for AGI version 3.002.086 */ - _L("hide.mouse", 0, 0x00), /* B0 */ - - _L("allow.menu", 1, 0x00), /* B1 */ - _L("show.mouse", 0, 0x00), /* B2 */ - _L("fence.mouse", 4, 0x00), /* B3 */ - _L("mouse.posn", 2, 0x00), /* B4 */ - _L("release.key", 0, 0x00), /* B5 */ - _L("adj.ego.move.to.xy",0, 0x00), /* B6 */ - _L(NULL, 0, 0x00) -}; - - -#ifdef USE_CONSOLE - -void debug_console (int lognum, int mode, char *str) -{ - struct agi_logicnames *x; - UINT8 a, c, z; - - if (str) { - report (" %s\n", str); - return; - } - - report ("%03d:%04x ", lognum, ip); - - switch (*(code + ip)) - { - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - x = logic_names_if; - - if (debug.opcodes) { - report ("%02X %02X %02X %02X %02X %02X %02X %02X %02X\n" - " ", - (UINT8)*(code + (0 + ip)) & 0xFF, - (UINT8)*(code + (1 + ip)) & 0xFF, - (UINT8)*(code + (2 + ip)) & 0xFF, - (UINT8)*(code + (3 + ip)) & 0xFF, - (UINT8)*(code + (4 + ip)) & 0xFF, - (UINT8)*(code + (5 + ip)) & 0xFF, - (UINT8)*(code + (6 + ip)) & 0xFF, - (UINT8)*(code + (7 + ip)) & 0xFF, - (UINT8)*(code + (8 + ip)) & 0xFF); - } - report ("%s ", (x + *(code + ip) - 0xFC)->name); - break; - default: - x = mode == lCOMMAND_MODE ? logic_names_cmd : logic_names_test; - a = (unsigned char)(x + *(code + ip))->num_args; - c = (unsigned char)(x + *(code + ip))->arg_mask; - - if (debug.opcodes) { - report("%02X %02X %02X %02X %02X %02X %02X %02X %02X\n" - " ", - (UINT8)*(code + (0 + ip)) & 0xFF, - (UINT8)*(code + (1 + ip)) & 0xFF, - (UINT8)*(code + (2 + ip)) & 0xFF, - (UINT8)*(code + (3 + ip)) & 0xFF, - (UINT8)*(code + (4 + ip)) & 0xFF, - (UINT8)*(code + (5 + ip)) & 0xFF, - (UINT8)*(code + (6 + ip)) & 0xFF, - (UINT8)*(code + (7 + ip)) & 0xFF, - (UINT8)*(code + (8 + ip)) & 0xFF); - } - report ("%s ", (x + *(code + ip))->name); - - for (z = 1; a > 0; ) { - if (~c & 0x80) { - report ("%d", *(code+(ip+z))); - } else { - report ("v%d[%d]", *(code + (ip + z)), - getvar (*(code + (ip + z)))); - } - c <<= 1; - z++; - if (--a > 0) - report (","); - } - break; - } - - report ("\n"); -} - -#else - -void debug_console (int lognum, int mode, char *str) -{ - /* dummy */ -} - - -#endif /* USE_CONSOLE */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: op_dbg.c,v 1.11 2001/08/26 12:23:37 darkfiber Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include "sarien.h" +#include "agi.h" +#include "opcodes.h" + +#define ip (game.logics[lognum].cIP) +#define code (game.logics[lognum].data) + +#ifdef _L +#undef _L +#endif + +#ifdef USE_CONSOLE +#define _L(a,b,c) { a, b, c } +#else +#define _L(a,b,c) { b, c } +#endif + +struct agi_logicnames logic_names_test[] = { + _L("", 0, 0x00), + _L("equaln", 2, 0x80), + _L("equalv", 2, 0xC0), + _L("lessn", 2, 0x80), + _L("lessv", 2, 0xC0), + _L("greatern", 2, 0x80), + _L("greaterv", 2, 0xC0), + _L("isset", 1, 0x00), + _L("issetv", 1, 0x80), + _L("has", 1, 0x00), + _L("obj.in.room", 2, 0x40), + _L("posn", 5, 0x00), + _L("controller", 1, 0x00), + _L("have.key", 0, 0x00), + + /* Not 0 args. Has variable number. */ + _L("said", 0, 0x00), + + _L("compare.strings", 2, 0x00), + _L("obj.in.box", 5, 0x00), + _L("center.posn", 5, 0x00), + _L("right.posn", 5, 0x00) +}; + +struct agi_logicnames logic_names_if[]= { + _L("OR", 0, 0x00), + _L("NOT", 0, 0x00), + _L("ELSE", 0, 0x00), + _L("IF", 0, 0x00) +}; + +struct agi_logicnames logic_names_cmd[]= { + _L("return", 0, 0x00), /* 00 */ + _L("increment", 1, 0x80), /* 01 */ + _L("decrement", 1, 0x80), /* 02 */ + _L("assignn", 2, 0x80), /* 03 */ + _L("assignv", 2, 0xC0), /* 04 */ + _L("addn", 2, 0x80), /* 05 */ + _L("addv", 2, 0xC0), /* 06 */ + _L("subn", 2, 0x80), /* 07 */ + _L("subv", 2, 0xC0), /* 08 */ + _L("lindirectv", 2, 0xC0), /* 09 */ + _L("rindirect", 2, 0xC0), /* 0A */ + _L("lindirectn", 2, 0x80), /* 0B */ + _L("set", 1, 0x00), /* 0C */ + _L("reset", 1, 0x00), /* 0D */ + _L("toggle", 1, 0x00), /* 0E */ + _L("set.v", 1, 0x80), /* 0F */ + _L("reset.v", 1, 0x80), /* 10 */ + _L("toggle.v", 1, 0x80), /* 11 */ + _L("new.room", 1, 0x00), /* 12 */ + _L("new.room.v", 1, 0x80), /* 13 */ + _L("load.logics", 1, 0x00), /* 14 */ + _L("load.logics.v", 1, 0x80), /* 15 */ + _L("call", 1, 0x00), /* 16 */ + _L("call.v", 1, 0x80), /* 17 */ + _L("load.pic", 1, 0x80), /* 18 */ + _L("draw.pic", 1, 0x80), /* 19 */ + _L("show.pic", 0, 0x00), /* 1A */ + _L("discard.pic", 1, 0x80), /* 1B */ + _L("overlay.pic", 1, 0x80), /* 1C */ + _L("show.pri.screen", 0, 0x00), /* 1D */ + _L("load.view", 1, 0x00), /* 1E */ + _L("load.view.v", 1, 0x80), /* 1F */ + _L("discard.view", 1, 0x00), /* 20 */ + _L("animate.obj", 1, 0x00), /* 21 */ + _L("unanimate.all", 0, 0x00), /* 22 */ + _L("draw", 1, 0x00), /* 23 */ + _L("erase", 1, 0x00), /* 24 */ + _L("position", 3, 0x00), /* 25 */ + _L("position.v", 3, 0x60), /* 26 */ + _L("get.posn", 3, 0x60), /* 27 */ + _L("reposition", 3, 0x60), /* 28 */ + _L("set.view", 2, 0x00), /* 29 */ + _L("set.view.v", 2, 0x40), /* 2A */ + _L("set.loop", 2, 0x00), /* 2B */ + _L("set.loop.v", 2, 0x40), /* 2C */ + _L("fix.loop", 1, 0x00), /* 2D */ + _L("release.loop", 1, 0x00), /* 2E */ + _L("set.cel", 2, 0x00), /* 2F */ + _L("set.cel.v", 2, 0x40), /* 30 */ + _L("last.cel", 2, 0x40), /* 31 */ + _L("current.cel", 2, 0x40), /* 32 */ + _L("current.loop", 2, 0x40), /* 33 */ + _L("current.view", 2, 0x40), /* 34 */ + _L("number.of.loops", 2, 0x40), /* 35 */ + _L("set.priority", 2, 0x00), /* 36 */ + _L("set.priority.v", 2, 0x40), /* 37 */ + _L("release.priority", 1, 0x00), /* 38 */ + _L("get.priority", 2, 0x40), /* 39 */ + _L("stop.update", 1, 0x00), /* 3A */ + _L("start.update", 1, 0x00), /* 3B */ + _L("force.update", 1, 0x00), /* 3C */ + _L("ignore.horizon", 1, 0x00), /* 3D */ + _L("observe.horizon", 1, 0x00), /* 3E */ + _L("set.horizon", 1, 0x00), /* 3F */ + _L("object.on.water", 1, 0x00), /* 40 */ + _L("object.on.land", 1, 0x00), /* 41 */ + _L("object.on.anything",1, 0x00), /* 42 */ + _L("ignore.objs", 1, 0x00), /* 43 */ + _L("observe.objs", 1, 0x00), /* 44 */ + _L("distance", 3, 0x20), /* 45 */ + _L("stop.cycling", 1, 0x00), /* 46 */ + _L("start.cycling", 1, 0x00), /* 47 */ + _L("normal.cycle", 1, 0x00), /* 48 */ + _L("end.of.loop", 2, 0x00), /* 49 */ + _L("reverse.cycle", 1, 0x00), /* 4A */ + _L("reverse.loop", 2, 0x00), /* 4B */ + _L("cycle.time", 2, 0x40), /* 4C */ + _L("stop.motion", 1, 0x00), /* 4D */ + _L("start.motion", 1, 0x00), /* 4E */ + _L("step.size", 2, 0x40), /* 4F */ + _L("step.time", 2, 0x40), /* 50 */ + _L("move.obj", 5, 0x00), /* 51 */ + _L("move.obj.v", 5, 0x70), /* 52 */ + _L("follow.ego", 3, 0x00), /* 53 */ + _L("wander", 1, 0x00), /* 54 */ + _L("normal.motion", 1, 0x00), /* 55 */ + _L("set.dir", 2, 0x40), /* 56 */ + _L("get.dir", 2, 0x40), /* 57 */ + _L("ignore.blocks", 1, 0x00), /* 58 */ + _L("observe.blocks", 1, 0x00), /* 59 */ + _L("block", 4, 0x00), /* 5A */ + _L("unblock", 0, 0x00), /* 5B */ + _L("get", 1, 0x00), /* 5C */ + _L("get.v", 1, 0x80), /* 5D */ + _L("drop", 1, 0x00), /* 5E */ + _L("put", 2, 0x00), /* 5F */ + _L("put.v", 2, 0x40), /* 60 */ + _L("get.room.v", 2, 0xC0), /* 61 */ + _L("load.sound", 1, 0x00), /* 62 */ + _L("sound", 2, 0x00), /* 63 */ + _L("stop.sound", 0, 0x00), /* 64 */ + _L("print", 1, 0x00), /* 65 */ + _L("print.v", 1, 0x80), /* 66 */ + _L("display", 3, 0x00), /* 67 */ + _L("display.v", 3, 0xE0), /* 68 */ + _L("clear.lines", 3, 0x00), /* 69 */ + _L("text.screen", 0, 0x00), /* 6A */ + _L("graphics", 0, 0x00), /* 6B */ + _L("set.cursor.char", 1, 0x00), /* 6C */ + _L("set.text.attribute",2, 0x00), /* 6D */ + _L("shake.screen", 1, 0x00), /* 6E */ + _L("configure.screen", 3, 0x00), /* 6F */ + _L("status.line.on", 0, 0x00), /* 70 */ + _L("status.line.off", 0, 0x00), /* 71 */ + _L("set.string", 2, 0x00), /* 72 */ + _L("get.string", 5, 0x00), /* 73 */ + _L("word.to.string", 2, 0x00), /* 74 */ + _L("parse", 1, 0x00), /* 75 */ + _L("get.num", 2, 0x40), /* 76 */ + _L("prevent.input", 0, 0x00), /* 77 */ + _L("accept.input", 0, 0x00), /* 78 */ + _L("set.key", 3, 0x00), /* 79 */ + _L("add.to.pic", 7, 0x00), /* 7A */ + _L("add.to.pic.v", 7, 0xFE), /* 7B */ + _L("status", 0, 0x00), /* 7C */ + _L("save.game", 0, 0x00), /* 7D */ + _L("restore.game", 0, 0x00), /* 7E */ + _L("init.disk", 0, 0x00), /* 7F */ + _L("restart.game", 0, 0x00), /* 80 */ + _L("show.obj", 1, 0x00), /* 81 */ + _L("random", 3, 0x20), /* 82 */ + _L("program.control", 0, 0x00), /* 83 */ + _L("player.control", 0, 0x00), /* 84 */ + _L("obj.status.v", 1, 0x80), /* 85 */ + /* 0 args for AGI version 2.089 */ + _L("quit", 1, 0x00), /* 86 */ + + _L("show.mem", 0, 0x00), /* 87 */ + _L("pause", 0, 0x00), /* 88 */ + _L("echo.line", 0, 0x00), /* 89 */ + _L("cancel.line", 0, 0x00), /* 8A */ + _L("init.joy", 0, 0x00), /* 8B */ + _L("toggle.monitor", 0, 0x00), /* 8C */ + _L("version", 0, 0x00), /* 8D */ + _L("script.size", 1, 0x00), /* 8E */ + _L("set.game.id", 1, 0x00), /* 8F */ + _L("log", 1, 0x00), /* 90 */ + _L("set.scan.start", 0, 0x00), /* 91 */ + _L("reset.scan.start", 0, 0x00), /* 92 */ + _L("reposition.to", 3, 0x00), /* 93 */ + _L("reposition.to.v", 3, 0x60), /* 94 */ + _L("trace.on", 0, 0x00), /* 95 */ + _L("trace.info", 3, 0x00), /* 96 */ + + /* 3 args for AGI versions before 2.440 */ + _L("print.at", 4, 0x00), /* 97 */ + _L("print.at.v", 4, 0x80), /* 98 */ + + _L("discard.view.v", 1, 0x80), /* 99 */ + _L("clear.text.rect", 5, 0x00), /* 9A */ + _L("set.upper.left", 2, 0x00), /* 9B */ + _L("set.menu", 1, 0x00), /* 9C */ + _L("set.menu.item", 2, 0x00), /* 9D */ + _L("submit.menu", 0, 0x00), /* 9E */ + _L("enable.item", 1, 0x00), /* 9F */ + _L("disable.item", 1, 0x00), /* A0 */ + _L("menu.input", 0, 0x00), /* A1 */ + _L("show.obj.v", 1, 0x01), /* A2 */ + _L("open.dialogue", 0, 0x00), /* A3 */ + _L("close.dialogue", 0, 0x00), /* A4 */ + _L("mul.n", 2, 0x80), /* A5 */ + _L("mul.v", 2, 0xC0), /* A6 */ + _L("div.n", 2, 0x80), /* A7 */ + _L("div.v", 2, 0xC0), /* A8 */ + _L("close.window", 0, 0x00), /* A9 */ + + _L("set.simple", 1, 0x00), /* AA */ + _L("push.script", 0, 0x00), /* AB */ + _L("pop.script", 0, 0x00), /* AC */ + _L("hold.key", 0, 0x00), /* AD */ + _L("set.pri.base", 1, 0x00), /* AE */ + _L("discard.sound", 1, 0x00), /* AF */ + + /* 1 arg for AGI version 3.002.086 */ + _L("hide.mouse", 0, 0x00), /* B0 */ + + _L("allow.menu", 1, 0x00), /* B1 */ + _L("show.mouse", 0, 0x00), /* B2 */ + _L("fence.mouse", 4, 0x00), /* B3 */ + _L("mouse.posn", 2, 0x00), /* B4 */ + _L("release.key", 0, 0x00), /* B5 */ + _L("adj.ego.move.to.xy",0, 0x00), /* B6 */ + _L(NULL, 0, 0x00) +}; + + +#ifdef USE_CONSOLE + +void debug_console (int lognum, int mode, char *str) +{ + struct agi_logicnames *x; + UINT8 a, c, z; + + if (str) { + report (" %s\n", str); + return; + } + + report ("%03d:%04x ", lognum, ip); + + switch (*(code + ip)) + { + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + x = logic_names_if; + + if (debug.opcodes) { + report ("%02X %02X %02X %02X %02X %02X %02X %02X %02X\n" + " ", + (UINT8)*(code + (0 + ip)) & 0xFF, + (UINT8)*(code + (1 + ip)) & 0xFF, + (UINT8)*(code + (2 + ip)) & 0xFF, + (UINT8)*(code + (3 + ip)) & 0xFF, + (UINT8)*(code + (4 + ip)) & 0xFF, + (UINT8)*(code + (5 + ip)) & 0xFF, + (UINT8)*(code + (6 + ip)) & 0xFF, + (UINT8)*(code + (7 + ip)) & 0xFF, + (UINT8)*(code + (8 + ip)) & 0xFF); + } + report ("%s ", (x + *(code + ip) - 0xFC)->name); + break; + default: + x = mode == lCOMMAND_MODE ? logic_names_cmd : logic_names_test; + a = (unsigned char)(x + *(code + ip))->num_args; + c = (unsigned char)(x + *(code + ip))->arg_mask; + + if (debug.opcodes) { + report("%02X %02X %02X %02X %02X %02X %02X %02X %02X\n" + " ", + (UINT8)*(code + (0 + ip)) & 0xFF, + (UINT8)*(code + (1 + ip)) & 0xFF, + (UINT8)*(code + (2 + ip)) & 0xFF, + (UINT8)*(code + (3 + ip)) & 0xFF, + (UINT8)*(code + (4 + ip)) & 0xFF, + (UINT8)*(code + (5 + ip)) & 0xFF, + (UINT8)*(code + (6 + ip)) & 0xFF, + (UINT8)*(code + (7 + ip)) & 0xFF, + (UINT8)*(code + (8 + ip)) & 0xFF); + } + report ("%s ", (x + *(code + ip))->name); + + for (z = 1; a > 0; ) { + if (~c & 0x80) { + report ("%d", *(code+(ip+z))); + } else { + report ("v%d[%d]", *(code + (ip + z)), + getvar (*(code + (ip + z)))); + } + c <<= 1; + z++; + if (--a > 0) + report (","); + } + break; + } + + report ("\n"); +} + +#else + +void debug_console (int lognum, int mode, char *str) +{ + /* dummy */ +} + + +#endif /* USE_CONSOLE */ + diff --git a/op_test.c b/op_test.c index 8288042..0fd37ca 100644 --- a/op_test.c +++ b/op_test.c @@ -1,431 +1,431 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: op_test.c,v 1.38 2003/08/26 00:53:16 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include - -#include "sarien.h" -#include "agi.h" -#include "keyboard.h" -#include "opcodes.h" - -static UINT8 test_obj_right (UINT8, UINT8, UINT8, UINT8, UINT8); -static UINT8 test_obj_centre (UINT8, UINT8, UINT8, UINT8, UINT8); -static UINT8 test_obj_in_box (UINT8, UINT8, UINT8, UINT8, UINT8); -static UINT8 test_posn (UINT8, UINT8, UINT8, UINT8, UINT8); -static UINT8 test_said (UINT8, UINT8 *); -static UINT8 test_controller (UINT8); -static UINT8 test_keypressed (void); -static UINT8 test_compare_strings(UINT8, UINT8); - -#define ip (game.logics[lognum].cIP) -#define code (game.logics[lognum].data) - -#define test_equal(v1,v2) (getvar(v1) == (v2)) -#define test_less(v1,v2) (getvar(v1) < (v2)) -#define test_greater(v1,v2) (getvar(v1) > (v2)) -#define test_isset(flag) (getflag (flag)) -#define test_has(obj) (object_get_location (obj) == EGO_OWNED) -#define test_obj_in_room(obj,v) (object_get_location (obj) == getvar (v)) - -extern int timer_hack; /* For the timer loop in MH1 logic 153 */ - -static UINT8 test_compare_strings(UINT8 s1, UINT8 s2) -{ - char ms1[MAX_STRINGLEN]; - char ms2[MAX_STRINGLEN]; - int j, k, l; - - strcpy(ms1, game.strings[s1]); - strcpy(ms2, game.strings[s2]); - - - l=strlen(ms1); - for(k=0, j=0; kx_pos >= x1 && v->y_pos >= y1 && - v->x_pos <= x2 && v->y_pos <= y2; - - /* _D ("(%d,%d) in (%d,%d,%d,%d): %s", v->x_pos, v->y_pos, - x1, y1, x2, y2, r ? "TRUE" : "FALSE"); */ - - return r; -} - - -static UINT8 test_obj_in_box (UINT8 n, UINT8 x1, UINT8 y1, UINT8 x2, UINT8 y2) -{ - struct vt_entry *v = &game.view_table[n]; - - return v->x_pos >= x1 && - v->y_pos >= y1 && - v->x_pos + v->x_size - 1 <= x2 && - v->y_pos <= y2; -} - - -/* if n is in centre of box */ -static UINT8 test_obj_centre (UINT8 n, UINT8 x1, UINT8 y1, UINT8 x2, UINT8 y2) -{ - struct vt_entry *v = &game.view_table[n]; - - return v->x_pos + v->x_size / 2 >= x1 && - v->x_pos + v->x_size / 2 <= x2 && - v->y_pos >= y1 && - v->y_pos <= y2; -} - - -/* if nect N is in right corner */ -static UINT8 test_obj_right(UINT8 n, UINT8 x1, UINT8 y1, UINT8 x2, UINT8 y2) -{ - struct vt_entry *v = &game.view_table[n]; - - return v->x_pos + v->x_size - 1 >= x1 && - v->x_pos + v->x_size - 1 <= x2 && - v->y_pos >= y1 && - v->y_pos <= y2; -} - - -/* When player has entered something, it is parsed elsewhere */ -static UINT8 test_said (UINT8 nwords, UINT8 *cc) -{ - int c, n = game.num_ego_words; - int z = 0; - - if (getflag (F_said_accepted_input) || !getflag (F_entered_cli)) - return FALSE; - - /* FR: - * I think the reason for the code below is to add some speed.... - * - * if (nwords != num_ego_words) - * return FALSE; - * - * In the disco scene in Larry 1 when you type "examine blonde", - * inside the logic is expected ( said("examine", "blonde", "rol") ) - * where word("rol") = 9999 - * - * According to the interpreter code 9999 means that whatever the - * user typed should be correct, but it looks like code 9999 means that - * if the string is empty at this point, the entry is also correct... - * - * With the removal of this code, the behaviour of the scene was - * corrected - */ - - for (c = 0; nwords && n; c++, nwords--, n--) { - z = lohi_getword (cc); - cc += 2; - - switch (z) { - case 9999: /* rest of line (empty string counts to...) */ - nwords = 1; - break; - case 1: /* any word */ - break; - default: - if (game.ego_words[c].id != z) - return FALSE; - break; - } - } - - /* The entry string should be entirely parsed, or last word = 9999 */ - if (n && z != 9999) - return FALSE; - - /* The interpreter string shouldn't be entirely parsed, but next - * word must be 9999. - */ - if (nwords != 0 && lohi_getword(cc) != 9999) - return FALSE; - - setflag (F_said_accepted_input, TRUE); - - return TRUE; -} - - -int test_if_code (int lognum) -{ - int ec = TRUE; - int retval = TRUE; - UINT8 op = 0; - UINT8 not_test = FALSE; - UINT8 or_test = FALSE; - UINT16 last_ip = ip; - UINT8 p[16] = {0}; - - while (retval && !game.quit_prog_now) { -#ifdef USE_CONSOLE - if (debug.enabled && (debug.logic0 || lognum)) - debug_console (lognum, lTEST_MODE, NULL); -#endif - - last_ip = ip; - op = *(code + ip++); - memmove (p, (code + ip), 16); - - switch(op) { - case 0xFF: /* END IF, TEST TRUE */ - goto end_test; - case 0xFD: - not_test = !not_test; - continue; - case 0xFC: /* OR */ - /* if or_test is ON and we hit 0xFC, end of OR, then - * or is STILL false so break. - */ - if (or_test) { - ec = FALSE; - retval = FALSE; - goto end_test; - } - - or_test = TRUE; - continue; - - case 0x00: - /* return true? */ - goto end_test; - case 0x01: - ec = test_equal (p[0], p[1]); - if (p[0] == 11) timer_hack++; - break; - case 0x02: - ec = test_equal (p[0], getvar(p[1])); - if (p[0] == 11 || p[1] == 11) timer_hack++; - break; - case 0x03: - ec = test_less (p[0], p[1]); - if (p[0] == 11) timer_hack++; - break; - case 0x04: - ec = test_less(p[0], getvar(p[1])); - if (p[0] == 11 || p[1] == 11) timer_hack++; - break; - case 0x05: - ec = test_greater (p[0], p[1]); - if (p[0] == 11) timer_hack++; - break; - case 0x06: - ec = test_greater (p[0], getvar (p[1])); - if (p[0] == 11 || p[1] == 11) timer_hack++; - break; - case 0x07: - ec = test_isset (p[0]); - break; - case 0x08: - ec = test_isset (getvar(p[0])); - break; - case 0x09: - ec = test_has (p[0]); - break; - case 0x0A: - ec = test_obj_in_room (p[0], p[1]); - break; - case 0x0B: - ec = test_posn (p[0], p[1], p[2], p[3], p[4]); - break; - case 0x0C: - ec = test_controller (p[0]); - break; - case 0x0D: - ec = test_keypressed (); - break; - case 0x0E: - ec = test_said (p[0], (UINT8*)code + (ip + 1)); - ip = last_ip; - ip++; /* skip opcode */ - ip += p[0] * 2; /* skip num_words * 2 */ - ip++; /* skip num_words opcode */ - break; - case 0x0F: - _D(_D_WARN "comparing [%s], [%s]", - game.strings[p[0]], game.strings[p[1]]); - ec = test_compare_strings (p[0], p[1]); - break; - case 0x10: - ec = test_obj_in_box (p[0], p[1], p[2], p[3], p[4]); - break; - case 0x11: - ec = test_obj_centre (p[0], p[1], p[2], p[3], p[4]); - break; - case 0x12: - ec = test_obj_right (p[0], p[1], p[2], p[3], p[4]); - break; - default: - ec = FALSE; - goto end_test; - } - - if (op <= 0x12) - ip += logic_names_test[op].num_args; - - /* exchange ec value */ - if (not_test) - ec = !ec; - - /* not is only enabled for 1 test command */ - not_test = FALSE; - - if (or_test && ec) { - /* a TRUE inside an OR statement passes - * ENTIRE statement scan for end of OR - */ - - /* CM: test for opcode < 0xfc changed from 'op' to - * '*(code+ip)', to avoid problem with the 0xfd (NOT) - * opcode byte. Changed a bad ip += ... ip++ construct. - * This should fix the crash with Larry's logic.0 code: - * - * if ((isset(4) || - * !isset(2) || - * v30 == 2 || - * v30 == 1)) { - * goto Label1; - * } - * - * The bytecode is: - * ff fc 07 04 fd 07 02 01 1e 02 01 1e 01 fc ff - */ - - /* find end of OR */ - while (*(code+ip) != 0xFC) { - if (*(code + ip) == 0x0E) { /* said */ - ip++; - /* cover count + ^words */ - ip += 1 + ((*(code + ip)) * 2); - continue; - } - - if (*(code + ip) < 0xFC) - ip += logic_names_test[*(code + - ip)].num_args; - ip++; - } - ip++; - - or_test = FALSE; - retval = TRUE; - } else { - retval = or_test ? retval || ec : retval && ec; - } - } -end_test: - - /* if false, scan for end of IP? */ - if (retval) - ip += 2; - else { - ip = last_ip; - while (*(code + ip) != 0xff) { - if (*(code + ip) == 0x0e) { - ip++; - ip += (*(code + ip)) * 2 + 1; - } else if (*(code + ip) < 0xfc) { - ip += logic_names_test[*(code + ip)].num_args; - ip++; - } else { - ip++; - } - } - ip++; /* skip over 0xFF */ - ip += lohi_getword (code + ip) + 2; - } - -#ifdef USE_CONSOLE - if (debug.enabled && (debug.logic0 || lognum)) - debug_console (lognum, 0xFF, retval ? "=TRUE" : "=FALSE"); -#endif - - return retval; -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: op_test.c,v 1.38 2003/08/26 00:53:16 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include + +#include "sarien.h" +#include "agi.h" +#include "keyboard.h" +#include "opcodes.h" + +static UINT8 test_obj_right (UINT8, UINT8, UINT8, UINT8, UINT8); +static UINT8 test_obj_centre (UINT8, UINT8, UINT8, UINT8, UINT8); +static UINT8 test_obj_in_box (UINT8, UINT8, UINT8, UINT8, UINT8); +static UINT8 test_posn (UINT8, UINT8, UINT8, UINT8, UINT8); +static UINT8 test_said (UINT8, UINT8 *); +static UINT8 test_controller (UINT8); +static UINT8 test_keypressed (void); +static UINT8 test_compare_strings(UINT8, UINT8); + +#define ip (game.logics[lognum].cIP) +#define code (game.logics[lognum].data) + +#define test_equal(v1,v2) (getvar(v1) == (v2)) +#define test_less(v1,v2) (getvar(v1) < (v2)) +#define test_greater(v1,v2) (getvar(v1) > (v2)) +#define test_isset(flag) (getflag (flag)) +#define test_has(obj) (object_get_location (obj) == EGO_OWNED) +#define test_obj_in_room(obj,v) (object_get_location (obj) == getvar (v)) + +extern int timer_hack; /* For the timer loop in MH1 logic 153 */ + +static UINT8 test_compare_strings(UINT8 s1, UINT8 s2) +{ + char ms1[MAX_STRINGLEN]; + char ms2[MAX_STRINGLEN]; + int j, k, l; + + strcpy(ms1, game.strings[s1]); + strcpy(ms2, game.strings[s2]); + + + l=strlen(ms1); + for(k=0, j=0; kx_pos >= x1 && v->y_pos >= y1 && + v->x_pos <= x2 && v->y_pos <= y2; + + /* _D ("(%d,%d) in (%d,%d,%d,%d): %s", v->x_pos, v->y_pos, + x1, y1, x2, y2, r ? "TRUE" : "FALSE"); */ + + return r; +} + + +static UINT8 test_obj_in_box (UINT8 n, UINT8 x1, UINT8 y1, UINT8 x2, UINT8 y2) +{ + struct vt_entry *v = &game.view_table[n]; + + return v->x_pos >= x1 && + v->y_pos >= y1 && + v->x_pos + v->x_size - 1 <= x2 && + v->y_pos <= y2; +} + + +/* if n is in centre of box */ +static UINT8 test_obj_centre (UINT8 n, UINT8 x1, UINT8 y1, UINT8 x2, UINT8 y2) +{ + struct vt_entry *v = &game.view_table[n]; + + return v->x_pos + v->x_size / 2 >= x1 && + v->x_pos + v->x_size / 2 <= x2 && + v->y_pos >= y1 && + v->y_pos <= y2; +} + + +/* if nect N is in right corner */ +static UINT8 test_obj_right(UINT8 n, UINT8 x1, UINT8 y1, UINT8 x2, UINT8 y2) +{ + struct vt_entry *v = &game.view_table[n]; + + return v->x_pos + v->x_size - 1 >= x1 && + v->x_pos + v->x_size - 1 <= x2 && + v->y_pos >= y1 && + v->y_pos <= y2; +} + + +/* When player has entered something, it is parsed elsewhere */ +static UINT8 test_said (UINT8 nwords, UINT8 *cc) +{ + int c, n = game.num_ego_words; + int z = 0; + + if (getflag (F_said_accepted_input) || !getflag (F_entered_cli)) + return FALSE; + + /* FR: + * I think the reason for the code below is to add some speed.... + * + * if (nwords != num_ego_words) + * return FALSE; + * + * In the disco scene in Larry 1 when you type "examine blonde", + * inside the logic is expected ( said("examine", "blonde", "rol") ) + * where word("rol") = 9999 + * + * According to the interpreter code 9999 means that whatever the + * user typed should be correct, but it looks like code 9999 means that + * if the string is empty at this point, the entry is also correct... + * + * With the removal of this code, the behaviour of the scene was + * corrected + */ + + for (c = 0; nwords && n; c++, nwords--, n--) { + z = lohi_getword (cc); + cc += 2; + + switch (z) { + case 9999: /* rest of line (empty string counts to...) */ + nwords = 1; + break; + case 1: /* any word */ + break; + default: + if (game.ego_words[c].id != z) + return FALSE; + break; + } + } + + /* The entry string should be entirely parsed, or last word = 9999 */ + if (n && z != 9999) + return FALSE; + + /* The interpreter string shouldn't be entirely parsed, but next + * word must be 9999. + */ + if (nwords != 0 && lohi_getword(cc) != 9999) + return FALSE; + + setflag (F_said_accepted_input, TRUE); + + return TRUE; +} + + +int test_if_code (int lognum) +{ + int ec = TRUE; + int retval = TRUE; + UINT8 op = 0; + UINT8 not_test = FALSE; + UINT8 or_test = FALSE; + UINT16 last_ip = ip; + UINT8 p[16] = {0}; + + while (retval && !game.quit_prog_now) { +#ifdef USE_CONSOLE + if (debug.enabled && (debug.logic0 || lognum)) + debug_console (lognum, lTEST_MODE, NULL); +#endif + + last_ip = ip; + op = *(code + ip++); + memmove (p, (code + ip), 16); + + switch(op) { + case 0xFF: /* END IF, TEST TRUE */ + goto end_test; + case 0xFD: + not_test = !not_test; + continue; + case 0xFC: /* OR */ + /* if or_test is ON and we hit 0xFC, end of OR, then + * or is STILL false so break. + */ + if (or_test) { + ec = FALSE; + retval = FALSE; + goto end_test; + } + + or_test = TRUE; + continue; + + case 0x00: + /* return true? */ + goto end_test; + case 0x01: + ec = test_equal (p[0], p[1]); + if (p[0] == 11) timer_hack++; + break; + case 0x02: + ec = test_equal (p[0], getvar(p[1])); + if (p[0] == 11 || p[1] == 11) timer_hack++; + break; + case 0x03: + ec = test_less (p[0], p[1]); + if (p[0] == 11) timer_hack++; + break; + case 0x04: + ec = test_less(p[0], getvar(p[1])); + if (p[0] == 11 || p[1] == 11) timer_hack++; + break; + case 0x05: + ec = test_greater (p[0], p[1]); + if (p[0] == 11) timer_hack++; + break; + case 0x06: + ec = test_greater (p[0], getvar (p[1])); + if (p[0] == 11 || p[1] == 11) timer_hack++; + break; + case 0x07: + ec = test_isset (p[0]); + break; + case 0x08: + ec = test_isset (getvar(p[0])); + break; + case 0x09: + ec = test_has (p[0]); + break; + case 0x0A: + ec = test_obj_in_room (p[0], p[1]); + break; + case 0x0B: + ec = test_posn (p[0], p[1], p[2], p[3], p[4]); + break; + case 0x0C: + ec = test_controller (p[0]); + break; + case 0x0D: + ec = test_keypressed (); + break; + case 0x0E: + ec = test_said (p[0], (UINT8*)code + (ip + 1)); + ip = last_ip; + ip++; /* skip opcode */ + ip += p[0] * 2; /* skip num_words * 2 */ + ip++; /* skip num_words opcode */ + break; + case 0x0F: + _D(_D_WARN "comparing [%s], [%s]", + game.strings[p[0]], game.strings[p[1]]); + ec = test_compare_strings (p[0], p[1]); + break; + case 0x10: + ec = test_obj_in_box (p[0], p[1], p[2], p[3], p[4]); + break; + case 0x11: + ec = test_obj_centre (p[0], p[1], p[2], p[3], p[4]); + break; + case 0x12: + ec = test_obj_right (p[0], p[1], p[2], p[3], p[4]); + break; + default: + ec = FALSE; + goto end_test; + } + + if (op <= 0x12) + ip += logic_names_test[op].num_args; + + /* exchange ec value */ + if (not_test) + ec = !ec; + + /* not is only enabled for 1 test command */ + not_test = FALSE; + + if (or_test && ec) { + /* a TRUE inside an OR statement passes + * ENTIRE statement scan for end of OR + */ + + /* CM: test for opcode < 0xfc changed from 'op' to + * '*(code+ip)', to avoid problem with the 0xfd (NOT) + * opcode byte. Changed a bad ip += ... ip++ construct. + * This should fix the crash with Larry's logic.0 code: + * + * if ((isset(4) || + * !isset(2) || + * v30 == 2 || + * v30 == 1)) { + * goto Label1; + * } + * + * The bytecode is: + * ff fc 07 04 fd 07 02 01 1e 02 01 1e 01 fc ff + */ + + /* find end of OR */ + while (*(code+ip) != 0xFC) { + if (*(code + ip) == 0x0E) { /* said */ + ip++; + /* cover count + ^words */ + ip += 1 + ((*(code + ip)) * 2); + continue; + } + + if (*(code + ip) < 0xFC) + ip += logic_names_test[*(code + + ip)].num_args; + ip++; + } + ip++; + + or_test = FALSE; + retval = TRUE; + } else { + retval = or_test ? retval || ec : retval && ec; + } + } +end_test: + + /* if false, scan for end of IP? */ + if (retval) + ip += 2; + else { + ip = last_ip; + while (*(code + ip) != 0xff) { + if (*(code + ip) == 0x0e) { + ip++; + ip += (*(code + ip)) * 2 + 1; + } else if (*(code + ip) < 0xfc) { + ip += logic_names_test[*(code + ip)].num_args; + ip++; + } else { + ip++; + } + } + ip++; /* skip over 0xFF */ + ip += lohi_getword (code + ip) + 2; + } + +#ifdef USE_CONSOLE + if (debug.enabled && (debug.logic0 || lognum)) + debug_console (lognum, 0xFF, retval ? "=TRUE" : "=FALSE"); +#endif + + return retval; +} + diff --git a/patches.c b/patches.c index 8d486a6..0234978 100644 --- a/patches.c +++ b/patches.c @@ -1,130 +1,130 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: patches.c,v 1.7 2002/08/04 16:26:04 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "opcodes.h" - -#ifdef PATCH_LOGIC - -#define ip (game.logics[n].cIP) -#define code (game.logics[n].data) -#define size (game.logics[n].size) - -/* - * Patches - */ - -static UINT8 kq4data_find[]= { - 0x0C, 0x04, 0xFF, 0x07, 0x05, 0xFF, 0x15, 0x00, - 0x03, 0x0A, 0x00, 0x77, 0x83, 0x71, 0x0D, 0x97, - 0x03, 0x98, 0xCE, 0x18, 0x98, 0x19, 0x98, 0x1B, - 0x98, 0x0C, 0x5A, 0x1A, 0x00 -}; - -static UINT8 kq4data_fix[]= { - /* v19 = 0 - * new.room(96) - * return - */ - 0x03, 0x13, 0x0, 0x12, 0x60, 0x00 -}; - -static UINT8 grdata_find[]= { - 0x0C, 0x04, 0xFF, 0x07, 0x05, 0xFF, 0x16, 0x00, - 0x0C, 0x96, 0x03, 0x0A, 0x00, 0x77, 0x83, 0x71, - 0x0D, 0xD9, 0x03, 0xDC, 0xBF, 0x18, 0xDC, 0x19, - 0xDC, 0x1B, 0xDC, 0x0C, 0x95, 0x1A -}; - -static UINT8 grdata_fix[]= { - /* reset(227) - * v19 = 0 - * v246 = 1 - * set(15) - * new.room(73) - */ - 0x0D, 0xE3, 0x03, 0x13, 0x00, 0x03, 0xF6, 0x01, - 0x0C, 0x0F, 0x12, 0x49 -}; - -#if 0 -static UINT8 lsl1data_find[]= { - 0xFF, 0xFD, 0x07, 0x1E, 0xFC, 0x07, 0x6D, 0x01, - 0x5F, 0x03, 0xFC, 0xFF, 0x12, 0x00, 0x0C, 0x6D, - 0x78, 0x8A, 0x77, 0x69, 0x16, 0x18, 0x00, 0x0D, - 0x30, 0x0D, 0x55, 0x78, 0x65, 0x0A -}; - -static UINT8 lsl1data_fix[]= { - /* set(109) - * reset(48) - * reset(85) - * accept.input() - * new.room(11) - */ - 0x0C, 0x6D, 0x0D, 0x30, 0x0D, 0x55, 0x78, 0x12, - 0x0B -}; -#endif - -static UINT8 mh1data_find[]= { - 0xFF, 0x07, 0x05, 0xFF, 0xE6, 0x00, - 0x03, 0x0A, 0x02, 0x77, 0x83, 0x71, - 0x6F, 0x01, 0x17, 0x00, 0x03, 0x00, - 0x9F, 0x03, 0x37, 0x00, 0x03, 0x32, - 0x03, 0x03, 0x3B, 0x00, 0x6C, 0x03 -}; - -static UINT8 mh1data_fix[]= { - 0x0C, 0x05, 0x16, 0x5A, 0x12, 0x99 -}; - - -void patch_logic (int n) -{ - switch(n) { -#if 0 - /* ALT-X in the questions takes care of that */ - case 6: - /* lsl1 bypass questions */ - if (!strcmp (game.id, "LLLLL")) { - if (!memcmp (lsl1data_find, (code+ip), 30)) - memmove ((code+ip), lsl1data_fix, 9); - } - break; -#endif - case 125: - /* gold rush code break */ - if (!strcmp (game.id, "GR")) { - if (!memcmp (grdata_find, (code+ip), 30)) - memmove ((code+ip), grdata_fix, 12); - } - break; - case 140: - /* kings quest 4 code break */ - if (!strcmp (game.id, "KQ4")) { - if(memcmp (kq4data_find, (code+ip), 29)==0) - memmove ((code+ip), kq4data_fix, 6); - } - break; - case 159: - /* manhunter 1 amiga */ - if(ip + 30 < size && !memcmp (mh1data_find, (code+ip), 30)) { - memmove ((code+ip), mh1data_fix, 6); - } - break; - } -} - -#endif - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: patches.c,v 1.7 2002/08/04 16:26:04 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "opcodes.h" + +#ifdef PATCH_LOGIC + +#define ip (game.logics[n].cIP) +#define code (game.logics[n].data) +#define size (game.logics[n].size) + +/* + * Patches + */ + +static UINT8 kq4data_find[]= { + 0x0C, 0x04, 0xFF, 0x07, 0x05, 0xFF, 0x15, 0x00, + 0x03, 0x0A, 0x00, 0x77, 0x83, 0x71, 0x0D, 0x97, + 0x03, 0x98, 0xCE, 0x18, 0x98, 0x19, 0x98, 0x1B, + 0x98, 0x0C, 0x5A, 0x1A, 0x00 +}; + +static UINT8 kq4data_fix[]= { + /* v19 = 0 + * new.room(96) + * return + */ + 0x03, 0x13, 0x0, 0x12, 0x60, 0x00 +}; + +static UINT8 grdata_find[]= { + 0x0C, 0x04, 0xFF, 0x07, 0x05, 0xFF, 0x16, 0x00, + 0x0C, 0x96, 0x03, 0x0A, 0x00, 0x77, 0x83, 0x71, + 0x0D, 0xD9, 0x03, 0xDC, 0xBF, 0x18, 0xDC, 0x19, + 0xDC, 0x1B, 0xDC, 0x0C, 0x95, 0x1A +}; + +static UINT8 grdata_fix[]= { + /* reset(227) + * v19 = 0 + * v246 = 1 + * set(15) + * new.room(73) + */ + 0x0D, 0xE3, 0x03, 0x13, 0x00, 0x03, 0xF6, 0x01, + 0x0C, 0x0F, 0x12, 0x49 +}; + +#if 0 +static UINT8 lsl1data_find[]= { + 0xFF, 0xFD, 0x07, 0x1E, 0xFC, 0x07, 0x6D, 0x01, + 0x5F, 0x03, 0xFC, 0xFF, 0x12, 0x00, 0x0C, 0x6D, + 0x78, 0x8A, 0x77, 0x69, 0x16, 0x18, 0x00, 0x0D, + 0x30, 0x0D, 0x55, 0x78, 0x65, 0x0A +}; + +static UINT8 lsl1data_fix[]= { + /* set(109) + * reset(48) + * reset(85) + * accept.input() + * new.room(11) + */ + 0x0C, 0x6D, 0x0D, 0x30, 0x0D, 0x55, 0x78, 0x12, + 0x0B +}; +#endif + +static UINT8 mh1data_find[]= { + 0xFF, 0x07, 0x05, 0xFF, 0xE6, 0x00, + 0x03, 0x0A, 0x02, 0x77, 0x83, 0x71, + 0x6F, 0x01, 0x17, 0x00, 0x03, 0x00, + 0x9F, 0x03, 0x37, 0x00, 0x03, 0x32, + 0x03, 0x03, 0x3B, 0x00, 0x6C, 0x03 +}; + +static UINT8 mh1data_fix[]= { + 0x0C, 0x05, 0x16, 0x5A, 0x12, 0x99 +}; + + +void patch_logic (int n) +{ + switch(n) { +#if 0 + /* ALT-X in the questions takes care of that */ + case 6: + /* lsl1 bypass questions */ + if (!strcmp (game.id, "LLLLL")) { + if (!memcmp (lsl1data_find, (code+ip), 30)) + memmove ((code+ip), lsl1data_fix, 9); + } + break; +#endif + case 125: + /* gold rush code break */ + if (!strcmp (game.id, "GR")) { + if (!memcmp (grdata_find, (code+ip), 30)) + memmove ((code+ip), grdata_fix, 12); + } + break; + case 140: + /* kings quest 4 code break */ + if (!strcmp (game.id, "KQ4")) { + if(memcmp (kq4data_find, (code+ip), 29)==0) + memmove ((code+ip), kq4data_fix, 6); + } + break; + case 159: + /* manhunter 1 amiga */ + if(ip + 30 < size && !memcmp (mh1data_find, (code+ip), 30)) { + memmove ((code+ip), mh1data_fix, 6); + } + break; + } +} + +#endif + diff --git a/path.c b/path.c index e6a7dea..5b5d465 100644 --- a/path.c +++ b/path.c @@ -1,78 +1,78 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: path.c,v 1.4 2001/11/29 07:21:41 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include -#include "sarien.h" -#include "agi.h" - - -int get_app_dir (char *app_dir, unsigned int size) -{ -#if 0 - char *x; - - x = getenv (HOMEDIR); - _D ("HOMEDIR = %s", x); - if (x) { - strncpy (app_dir, x, size); - } else { - x = getenv ("SARIEN"); - _D ("SARIEN = %s", x); - if (x) - strncpy (app_dir, x, size); - } - - _D ("app_dir = %s", app_dir); - - return x ? 0 : -1; -#else -return -1; -#endif -} - -char* get_config_file(void) -{ - static char ini_path[MAX_PATH]; -#if 0 - char *q; - - if (getenv ("SARIEN") != NULL) { - sprintf(ini_path, "%s/%s", getenv("SARIEN"), "sarien.ini"); - } else { - strcpy (ini_path, exec_name); - q = strchr(ini_path, 0x0); - q--; - - while((*q!='\\' && *q!='/') && q>ini_path) - q--; - - if(q!=ini_path) - *q=0x0; - - strcat(ini_path, "/sarien.ini"); - } -#else - strcat(ini_path,"sarien.ini"); -#endif - - return (char*)ini_path; -} - -char *get_current_directory () -{ -#if 0 - return "."; -#else - return ""; -#endif -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: path.c,v 1.4 2001/11/29 07:21:41 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include +#include "sarien.h" +#include "agi.h" + + +int get_app_dir (char *app_dir, unsigned int size) +{ +#if 0 + char *x; + + x = getenv (HOMEDIR); + _D ("HOMEDIR = %s", x); + if (x) { + strncpy (app_dir, x, size); + } else { + x = getenv ("SARIEN"); + _D ("SARIEN = %s", x); + if (x) + strncpy (app_dir, x, size); + } + + _D ("app_dir = %s", app_dir); + + return x ? 0 : -1; +#else +return -1; +#endif +} + +char* get_config_file(void) +{ + static char ini_path[MAX_PATH]; +#if 0 + char *q; + + if (getenv ("SARIEN") != NULL) { + sprintf(ini_path, "%s/%s", getenv("SARIEN"), "sarien.ini"); + } else { + strcpy (ini_path, exec_name); + q = strchr(ini_path, 0x0); + q--; + + while((*q!='\\' && *q!='/') && q>ini_path) + q--; + + if(q!=ini_path) + *q=0x0; + + strcat(ini_path, "/sarien.ini"); + } +#else + strcat(ini_path,"sarien.ini"); +#endif + + return (char*)ini_path; +} + +char *get_current_directory () +{ +#if 0 + return "."; +#else + return ""; +#endif +} + diff --git a/pccga.c b/pccga.c index 357a656..4a4d8ac 100644 --- a/pccga.c +++ b/pccga.c @@ -1,221 +1,221 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: pccga.c,v 1.9 2002/11/16 01:20:21 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include -#include - -#include "sarien.h" -#include "graphics.h" - -#define __outp(a, b) outportb(a, b) - - -extern struct gfx_driver *gfx; -extern struct sarien_options opt; - -UINT8 *exec_name; -static UINT8 *screen_buffer; - -#ifdef _MSC_VER -static void (interrupt far * prev_08)(void); -void interrupt far tick_increment(void); -#else -void (__interrupt __far *prev_08) (void); -void __interrupt __far tick_increment (void); -#endif -static int pc_init_vidmode (void); -static int pc_deinit_vidmode (void); -static void pc_put_block (int, int, int, int); -static void pc_put_pixels (int, int, int, UINT8 *); -static void pc_timer (void); -static int pc_get_key (void); -static int pc_keypress (void); - - -#define TICK_SECONDS 18 - -static struct gfx_driver gfx_pccga = { - pc_init_vidmode, - pc_deinit_vidmode, - pc_put_block, - pc_put_pixels, - pc_timer, - pc_keypress, - pc_get_key -}; - - -static UINT8 cga_map[16] = { - 0x00, /* 0 - black */ - 0x01, /* 1 - blue */ - 0x01, /* 2 - green */ - 0x01, /* 3 - cyan */ - 0x02, /* 4 - red */ - 0x02, /* 5 - magenta */ - 0x02, /* 6 - brown */ - 0x03, /* 7 - gray */ - 0x00, /* 8 - dark gray */ - 0x01, /* 9 - light blue */ - 0x01, /* 10 - light green */ - 0x01, /* 11 - light cyan */ - 0x02, /* 12 - light red */ - 0x02, /* 13 - light magenta */ - 0x02, /* 14 - yellow */ - 0x03 /* 15 - white */ -}; - -static void pc_timer () -{ - static UINT32 cticks = 0; - - while (cticks == clock_ticks); - cticks = clock_ticks; -} - - -int init_machine (int argc, char **argv) -{ - gfx = &gfx_pccga; - return err_OK; -} - - -int deinit_machine () -{ - return err_OK; -} - - -static int pc_init_vidmode () -{ - union REGS r; - int i; - - clock_count = 0; - clock_ticks = 0; - - screen_buffer = calloc (GFX_WIDTH / 4, GFX_HEIGHT); - - prev_08 = _dos_getvect (0x08); - _dos_setvect (0x08, tick_increment); - opt.cgaemu = TRUE; - - memset (&r, 0x0, sizeof(union REGS)); - r.x.ax = 0x4; - int86 (0x10, &r, &r); - - return err_OK; -} - - -static int pc_deinit_vidmode () -{ - union REGS r; - - memset (&r, 0x0, sizeof(union REGS)); - r.x.ax = 0x03; - int86 (0x10, &r, &r); - - free (screen_buffer); - _dos_setvect (0x08, prev_08); - - return err_OK; -} - - -/* blit a block onto the screen */ -static void pc_put_block (int x1, int y1, int x2, int y2) -{ - unsigned int i, h, w, p, p2; - UINT8 far *fbuffer; - UINT8 *sbuffer; - - if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; - if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; - if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; - if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; - - y1 &= ~1; /* Always start at an even line */ - - h = y2 - y1 + 1; - w = (x2 - x1 + 1) / 4 + 1; - p = 40 * y1 + x1 / 4; /* Note: (GFX_WIDTH / 4) * (y1 / 2) */ - p2 = p + 40 * y1; - - /* Write to the interlaced CGA framebuffer */ - - fbuffer = (UINT8 far *)0xb8000000 + p; - sbuffer = screen_buffer + p2; - for (i = 0; i < h; i += 2) { - _fmemcpy (fbuffer, sbuffer, w); - fbuffer += 80; - sbuffer += 160; - } - - fbuffer = (UINT8 far *)0xb8002000 + p; - sbuffer = screen_buffer + p2 + 80; - for (i = 1; i < h; i += 2) { - _fmemcpy (fbuffer, sbuffer, w); - fbuffer += 80; - sbuffer += 160; - } -} - -static void pc_put_pixels(int x, int y, int w, UINT8 *p) -{ - UINT8 *s, mask, val, shift, c; - - for (s = &screen_buffer[80 * y + x / 4]; w; w--, x++, p++) { - shift = (x & 3) * 2; - - /* Sorry, no transparent colors */ - c = *p > 15 ? 0 : cga_map[*p]; - - mask = 0xc0 >> shift; - val = (c & 0x03) << (6 - shift); - *s = (*s & ~mask) | val; - - if ((x % 4) == 3) - s++; - } -} - - -static int pc_keypress () -{ - return !!kbhit(); -} - - -static int pc_get_key () -{ - union REGS r; - UINT16 key; - - memset (&r, 0, sizeof(union REGS)); - int86 (0x16, &r, &r); - key = r.h.al ? r.h.al : r.h.ah << 8; - - return key; -} - -#ifdef _MSC_VER -void interrupt far tick_increment(void) -#else -void __interrupt __far tick_increment (void) -#endif -{ - clock_ticks++; - _chain_intr(prev_08); -} - - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: pccga.c,v 1.9 2002/11/16 01:20:21 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include +#include + +#include "sarien.h" +#include "graphics.h" + +#define __outp(a, b) outportb(a, b) + + +extern struct gfx_driver *gfx; +extern struct sarien_options opt; + +UINT8 *exec_name; +static UINT8 *screen_buffer; + +#ifdef _MSC_VER +static void (interrupt far * prev_08)(void); +void interrupt far tick_increment(void); +#else +void (__interrupt __far *prev_08) (void); +void __interrupt __far tick_increment (void); +#endif +static int pc_init_vidmode (void); +static int pc_deinit_vidmode (void); +static void pc_put_block (int, int, int, int); +static void pc_put_pixels (int, int, int, UINT8 *); +static void pc_timer (void); +static int pc_get_key (void); +static int pc_keypress (void); + + +#define TICK_SECONDS 18 + +static struct gfx_driver gfx_pccga = { + pc_init_vidmode, + pc_deinit_vidmode, + pc_put_block, + pc_put_pixels, + pc_timer, + pc_keypress, + pc_get_key +}; + + +static UINT8 cga_map[16] = { + 0x00, /* 0 - black */ + 0x01, /* 1 - blue */ + 0x01, /* 2 - green */ + 0x01, /* 3 - cyan */ + 0x02, /* 4 - red */ + 0x02, /* 5 - magenta */ + 0x02, /* 6 - brown */ + 0x03, /* 7 - gray */ + 0x00, /* 8 - dark gray */ + 0x01, /* 9 - light blue */ + 0x01, /* 10 - light green */ + 0x01, /* 11 - light cyan */ + 0x02, /* 12 - light red */ + 0x02, /* 13 - light magenta */ + 0x02, /* 14 - yellow */ + 0x03 /* 15 - white */ +}; + +static void pc_timer () +{ + static UINT32 cticks = 0; + + while (cticks == clock_ticks); + cticks = clock_ticks; +} + + +int init_machine (int argc, char **argv) +{ + gfx = &gfx_pccga; + return err_OK; +} + + +int deinit_machine () +{ + return err_OK; +} + + +static int pc_init_vidmode () +{ + union REGS r; + int i; + + clock_count = 0; + clock_ticks = 0; + + screen_buffer = calloc (GFX_WIDTH / 4, GFX_HEIGHT); + + prev_08 = _dos_getvect (0x08); + _dos_setvect (0x08, tick_increment); + opt.cgaemu = TRUE; + + memset (&r, 0x0, sizeof(union REGS)); + r.x.ax = 0x4; + int86 (0x10, &r, &r); + + return err_OK; +} + + +static int pc_deinit_vidmode () +{ + union REGS r; + + memset (&r, 0x0, sizeof(union REGS)); + r.x.ax = 0x03; + int86 (0x10, &r, &r); + + free (screen_buffer); + _dos_setvect (0x08, prev_08); + + return err_OK; +} + + +/* blit a block onto the screen */ +static void pc_put_block (int x1, int y1, int x2, int y2) +{ + unsigned int i, h, w, p, p2; + UINT8 far *fbuffer; + UINT8 *sbuffer; + + if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; + if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; + if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; + if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; + + y1 &= ~1; /* Always start at an even line */ + + h = y2 - y1 + 1; + w = (x2 - x1 + 1) / 4 + 1; + p = 40 * y1 + x1 / 4; /* Note: (GFX_WIDTH / 4) * (y1 / 2) */ + p2 = p + 40 * y1; + + /* Write to the interlaced CGA framebuffer */ + + fbuffer = (UINT8 far *)0xb8000000 + p; + sbuffer = screen_buffer + p2; + for (i = 0; i < h; i += 2) { + _fmemcpy (fbuffer, sbuffer, w); + fbuffer += 80; + sbuffer += 160; + } + + fbuffer = (UINT8 far *)0xb8002000 + p; + sbuffer = screen_buffer + p2 + 80; + for (i = 1; i < h; i += 2) { + _fmemcpy (fbuffer, sbuffer, w); + fbuffer += 80; + sbuffer += 160; + } +} + +static void pc_put_pixels(int x, int y, int w, UINT8 *p) +{ + UINT8 *s, mask, val, shift, c; + + for (s = &screen_buffer[80 * y + x / 4]; w; w--, x++, p++) { + shift = (x & 3) * 2; + + /* Sorry, no transparent colors */ + c = *p > 15 ? 0 : cga_map[*p]; + + mask = 0xc0 >> shift; + val = (c & 0x03) << (6 - shift); + *s = (*s & ~mask) | val; + + if ((x % 4) == 3) + s++; + } +} + + +static int pc_keypress () +{ + return !!kbhit(); +} + + +static int pc_get_key () +{ + union REGS r; + UINT16 key; + + memset (&r, 0, sizeof(union REGS)); + int86 (0x16, &r, &r); + key = r.h.al ? r.h.al : r.h.ah << 8; + + return key; +} + +#ifdef _MSC_VER +void interrupt far tick_increment(void) +#else +void __interrupt __far tick_increment (void) +#endif +{ + clock_ticks++; + _chain_intr(prev_08); +} + + diff --git a/pcvga.c b/pcvga.c index 170e338..8531aa6 100644 --- a/pcvga.c +++ b/pcvga.c @@ -1,228 +1,228 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: pcvga.c,v 1.5 2002/11/16 01:20:21 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include -#include - -#ifdef _MSC_VER -#define __TURBOC__ 1 -#endif - -#ifdef __WATCOMC__ -#include -#endif - -#include "sarien.h" -#include "graphics.h" - -#ifdef __TURBOC__ -#define __outp(a, b) outportb(a, b) -#endif -#ifdef __WATCOMC__ -#define __outp(a, b) outp(a, b) -#endif -#ifdef _MSC_VER -#define __outp(a, b) outp(a, b) -#endif - -#ifdef __WATCOMC__ -void DebugBreak(void); -#pragma aux DebugBreak = "int 3" parm[]; -#endif - - -extern struct gfx_driver *gfx; -extern struct sarien_options opt; - -UINT8 *exec_name; -static UINT8 *screen_buffer; - -#ifdef _MSC_VER -static void (interrupt far * prev_08)(void); -void interrupt far tick_increment(void); -#else -void (__interrupt __far *prev_08) (void); -void __interrupt __far tick_increment (void); -#endif -static int pc_init_vidmode (void); -static int pc_deinit_vidmode (void); -static void pc_put_block (int, int, int, int); -static void pc_put_pixels (int, int, int, UINT8 *); -static void pc_timer (void); -static int pc_get_key (void); -static int pc_keypress (void); - - -#define TICK_SECONDS 18 - -static struct gfx_driver gfx_pcvga = { - pc_init_vidmode, - pc_deinit_vidmode, - pc_put_block, - pc_put_pixels, - pc_timer, - pc_keypress, - pc_get_key -}; - -static void pc_timer () -{ - static UINT32 cticks = 0; - - while (cticks == clock_ticks); - cticks = clock_ticks; -} - - -int init_machine (int argc, char **argv) -{ - gfx = &gfx_pcvga; - return err_OK; -} - - -int deinit_machine () -{ - return err_OK; -} - - -static int pc_init_vidmode () -{ - union REGS r; - int i; - - clock_count = 0; - clock_ticks = 0; - - screen_buffer = calloc (GFX_WIDTH, GFX_HEIGHT); - - prev_08 = _dos_getvect (0x08); - _dos_setvect (0x08, tick_increment); - - memset (&r, 0x0, sizeof(union REGS)); -#ifdef __WATCOMC__ - r.w.ax = 0x13; - int386 (0x10, &r, &r); -#endif - -#ifdef __TURBOC__ - r.x.ax = 0x13; - int86 (0x10, &r, &r); -#endif - - __outp (0x3c8, 0); - for (i = 0; i < 32 * 3; i++) - __outp (0x3c9, palette[i]); - - return err_OK; -} - - -static int pc_deinit_vidmode () -{ - union REGS r; - - memset (&r, 0x0, sizeof(union REGS)); - -#ifdef __WATCOMC__ - r.w.ax = 0x03; - int386 (0x10, &r, &r); -#endif - -#ifdef __TURBOC__ - r.x.ax = 0x03; - int86 (0x10, &r, &r); -#endif - - free (screen_buffer); - _dos_setvect (0x08, prev_08); - - return err_OK; -} - - -/* blit a block onto the screen */ -static void pc_put_block (int x1, int y1, int x2, int y2) -{ - unsigned int h, w, p; - - if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; - if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; - if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; - if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; - - h = y2 - y1 + 1; - w = x2 - x1 + 1; - p = GFX_WIDTH * y1 + x1; - - while (h--) { -#ifdef __WATCOMC__ - /* Watcom uses linear 0xa0000 address */ - memcpy ((UINT8 *)0xa0000 + p, screen_buffer + p, w); -#else - /* Turbo C wants 0xa0000000 in seg:ofs format */ - _fmemcpy ((UINT8 far *)0xa0000000 + p, screen_buffer + p, w); -#endif - p += 320; - } -} - - -static void pc_put_pixels(int x, int y, int w, UINT8 *p) -{ - UINT8 *s; - for (s = &screen_buffer[y * 320 + x]; w--; *s++ = *p++); -} - - -static int pc_keypress () -{ - return !!kbhit(); -} - - -static int pc_get_key () -{ - union REGS r; - UINT16 key; - - memset (&r, 0, sizeof(union REGS)); -#ifdef __WATCOMC__ - int386 (0x16, &r, &r); -#endif -#ifdef __TURBOC__ - int86 (0x16, &r, &r); -#endif - - key = r.h.al == 0 ? (r.h.ah << 8) : r.h.al; - - return key; -} - -/* WATCOM HATES timer routines... */ -/* lucky we call no other routines inside our timer */ -/* coz SS!=DS and watcom wants SS==DS but it aint inside a timer! */ -#ifdef _MSC_VER -void interrupt far tick_increment(void) -#else -void __interrupt __far tick_increment (void) -#endif -{ - clock_ticks++; -#ifdef _MSC_VER - _chain_intr(prev_08); -#else - (*prev_08)(); -#endif -} - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: pcvga.c,v 1.5 2002/11/16 01:20:21 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include +#include + +#ifdef _MSC_VER +#define __TURBOC__ 1 +#endif + +#ifdef __WATCOMC__ +#include +#endif + +#include "sarien.h" +#include "graphics.h" + +#ifdef __TURBOC__ +#define __outp(a, b) outportb(a, b) +#endif +#ifdef __WATCOMC__ +#define __outp(a, b) outp(a, b) +#endif +#ifdef _MSC_VER +#define __outp(a, b) outp(a, b) +#endif + +#ifdef __WATCOMC__ +void DebugBreak(void); +#pragma aux DebugBreak = "int 3" parm[]; +#endif + + +extern struct gfx_driver *gfx; +extern struct sarien_options opt; + +UINT8 *exec_name; +static UINT8 *screen_buffer; + +#ifdef _MSC_VER +static void (interrupt far * prev_08)(void); +void interrupt far tick_increment(void); +#else +void (__interrupt __far *prev_08) (void); +void __interrupt __far tick_increment (void); +#endif +static int pc_init_vidmode (void); +static int pc_deinit_vidmode (void); +static void pc_put_block (int, int, int, int); +static void pc_put_pixels (int, int, int, UINT8 *); +static void pc_timer (void); +static int pc_get_key (void); +static int pc_keypress (void); + + +#define TICK_SECONDS 18 + +static struct gfx_driver gfx_pcvga = { + pc_init_vidmode, + pc_deinit_vidmode, + pc_put_block, + pc_put_pixels, + pc_timer, + pc_keypress, + pc_get_key +}; + +static void pc_timer () +{ + static UINT32 cticks = 0; + + while (cticks == clock_ticks); + cticks = clock_ticks; +} + + +int init_machine (int argc, char **argv) +{ + gfx = &gfx_pcvga; + return err_OK; +} + + +int deinit_machine () +{ + return err_OK; +} + + +static int pc_init_vidmode () +{ + union REGS r; + int i; + + clock_count = 0; + clock_ticks = 0; + + screen_buffer = calloc (GFX_WIDTH, GFX_HEIGHT); + + prev_08 = _dos_getvect (0x08); + _dos_setvect (0x08, tick_increment); + + memset (&r, 0x0, sizeof(union REGS)); +#ifdef __WATCOMC__ + r.w.ax = 0x13; + int386 (0x10, &r, &r); +#endif + +#ifdef __TURBOC__ + r.x.ax = 0x13; + int86 (0x10, &r, &r); +#endif + + __outp (0x3c8, 0); + for (i = 0; i < 32 * 3; i++) + __outp (0x3c9, palette[i]); + + return err_OK; +} + + +static int pc_deinit_vidmode () +{ + union REGS r; + + memset (&r, 0x0, sizeof(union REGS)); + +#ifdef __WATCOMC__ + r.w.ax = 0x03; + int386 (0x10, &r, &r); +#endif + +#ifdef __TURBOC__ + r.x.ax = 0x03; + int86 (0x10, &r, &r); +#endif + + free (screen_buffer); + _dos_setvect (0x08, prev_08); + + return err_OK; +} + + +/* blit a block onto the screen */ +static void pc_put_block (int x1, int y1, int x2, int y2) +{ + unsigned int h, w, p; + + if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; + if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; + if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; + if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; + + h = y2 - y1 + 1; + w = x2 - x1 + 1; + p = GFX_WIDTH * y1 + x1; + + while (h--) { +#ifdef __WATCOMC__ + /* Watcom uses linear 0xa0000 address */ + memcpy ((UINT8 *)0xa0000 + p, screen_buffer + p, w); +#else + /* Turbo C wants 0xa0000000 in seg:ofs format */ + _fmemcpy ((UINT8 far *)0xa0000000 + p, screen_buffer + p, w); +#endif + p += 320; + } +} + + +static void pc_put_pixels(int x, int y, int w, UINT8 *p) +{ + UINT8 *s; + for (s = &screen_buffer[y * 320 + x]; w--; *s++ = *p++); +} + + +static int pc_keypress () +{ + return !!kbhit(); +} + + +static int pc_get_key () +{ + union REGS r; + UINT16 key; + + memset (&r, 0, sizeof(union REGS)); +#ifdef __WATCOMC__ + int386 (0x16, &r, &r); +#endif +#ifdef __TURBOC__ + int86 (0x16, &r, &r); +#endif + + key = r.h.al == 0 ? (r.h.ah << 8) : r.h.al; + + return key; +} + +/* WATCOM HATES timer routines... */ +/* lucky we call no other routines inside our timer */ +/* coz SS!=DS and watcom wants SS==DS but it aint inside a timer! */ +#ifdef _MSC_VER +void interrupt far tick_increment(void) +#else +void __interrupt __far tick_increment (void) +#endif +{ + clock_ticks++; +#ifdef _MSC_VER + _chain_intr(prev_08); +#else + (*prev_08)(); +#endif +} + diff --git a/pharcga.c b/pharcga.c index 61c2ef1..a32035e 100644 --- a/pharcga.c +++ b/pharcga.c @@ -1,264 +1,264 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: pcvga.c,v 1.5 2002/11/16 01:20:21 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include - -#include -#include - -#define INCL_DOSPROCESS -#include - -char *textptr; //pointer to the text buffer -char textbuf[4000]; - -char * gptr; //pointer to cga ram - -REALPTR old_real_timer_tick; -PIHANDLER old_prot_timer_tick; -void _interrupt _far new_prot_timer_tick(REGS16); -#define IRQ0 0x08 - - -#include "sarien.h" -#include "graphics.h" - -extern struct gfx_driver *gfx; -extern struct sarien_options opt; - -UINT8 *exec_name; -static UINT8 *screen_buffer; - -static int pc_init_vidmode (void); -static int pc_deinit_vidmode (void); -static void pc_put_block (int, int, int, int); -static void pc_put_pixels (int, int, int, UINT8 *); -static void pc_timer (void); -static int pc_get_key (void); -static int pc_keypress (void); - - -#define TICK_SECONDS 18 - -static struct gfx_driver gfx_pcvga = { - pc_init_vidmode, - pc_deinit_vidmode, - pc_put_block, - pc_put_pixels, - pc_timer, - pc_keypress, - pc_get_key -}; - -static UINT8 cga_map[16] = { - 0x00, /* 0 - black */ - 0x01, /* 1 - blue */ - 0x01, /* 2 - green */ - 0x01, /* 3 - cyan */ - 0x02, /* 4 - red */ - 0x02, /* 5 - magenta */ - 0x02, /* 6 - brown */ - 0x03, /* 7 - gray */ - 0x00, /* 8 - dark gray */ - 0x01, /* 9 - light blue */ - 0x01, /* 10 - light green */ - 0x01, /* 11 - light cyan */ - 0x02, /* 12 - light red */ - 0x02, /* 13 - light magenta */ - 0x02, /* 14 - yellow */ - 0x03 /* 15 - white */ -}; - -static void pc_timer () -{ - static UINT32 cticks = 0; -//printf("clockticks %d\n",clock_ticks); - while (cticks == clock_ticks); - cticks = clock_ticks; -} - - -int init_machine (int argc, char **argv) -{ - int rseg; -/* Get PM pointer to text screen */ - DosMapRealSeg(0xb800,4000,&rseg); - textptr=MAKEP(rseg,0); - -/* save text screen */ - memcpy(textbuf,textptr,4000); - - gfx = &gfx_pcvga; -printf("init_machine\n"); - return err_OK; -} - - -int deinit_machine () -{ - union REGS r; - - /* restore old timer tick routines */ - DosSetRealProtVec(IRQ0, old_prot_timer_tick, old_real_timer_tick,NULL, NULL); - - memset(&r,0x0,sizeof(r)); - r.h.ah = 0; - r.h.al = 3; - int86(0x10, &r, &r); - - memcpy(textptr,textbuf,4000); - -printf("deinit_machine\n"); - return err_OK; -} - - -static int pc_init_vidmode () -{ - int i; - union REGS r; - int rseg; - unsigned short _cs, _ds; - - clock_count = 0; - clock_ticks = 0; - - screen_buffer = calloc (GFX_WIDTH / 4 , GFX_HEIGHT); -printf("GFX_WIDTH %d, GFX_HEIGHT %d\n",GFX_WIDTH/4, GFX_HEIGHT); - - opt.cgaemu = TRUE; - - memset (&r, 0x0, sizeof(union REGS)); - r.x.ax = 0x4; - int86(0x10, &r, &r); - -/* Get PM pointer to VGA screen */ - DosMapRealSeg(0xb800,16384,&rseg); - gptr=MAKEP(rseg,0); - - - /* VERY IMPORTANT -- Lock down our code and data segments - because we don't want them paged out when running under - Windows 3.0. */ - - _asm mov _cs,cs - _asm mov _ds,ds - DosLockSegPages(_cs); - DosLockSegPages(_ds); - - /* install our new timer tick routine */ - DosSetPassToProtVec(IRQ0, (PIHANDLER)new_prot_timer_tick, - &old_prot_timer_tick, &old_real_timer_tick); - -printf("pc_init_vidmode\n"); - return err_OK; -} - - -static int pc_deinit_vidmode () -{ - free (screen_buffer); - - return err_OK; -} - - -/* blit a block onto the screen */ -static void pc_put_block (int x1, int y1, int x2, int y2) -{ - unsigned int i, h, w, p, p2; - UINT8 far *fbuffer; - UINT8 *sbuffer; - - if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; - if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; - if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; - if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; - - y1 &= ~1; /* Always start at an even line */ - - h = y2 - y1 + 1; - w = (x2 - x1 + 1) / 4 + 1; - p = 40 * y1 + x1 / 4; /* Note: (GFX_WIDTH / 4) * (y1 / 2) */ - p2 = p + 40 * y1; - - /* Write to the interlaced CGA framebuffer */ - - //fbuffer = (UINT8 far *)0xb8000000 + p; - fbuffer = gptr+p; - sbuffer = screen_buffer + p2; - for (i = 0; i < h; i += 2) { - _fmemcpy (fbuffer, sbuffer, w); - fbuffer += 80; - sbuffer += 160; - } -#if 1 - //fbuffer = (UINT8 far *)0xb8002000 + p; - fbuffer = gptr+p+0x2000; - sbuffer = screen_buffer + p2 + 80; - for (i = 1; i < h; i += 2) { - _fmemcpy (fbuffer, sbuffer, w); - fbuffer += 80; - sbuffer += 160; - } -#endif -} - - -static void pc_put_pixels(int x, int y, int w, UINT8 *p) -{ - UINT8 *s, mask, val, shift, c; - - for (s = &screen_buffer[80 * y + x / 4]; w; w--, x++, p++) { - shift = (x & 3) * 2; - - /* Sorry, no transparent colors */ - c = *p > 15 ? 0 : cga_map[*p]; - - mask = 0xc0 >> shift; - val = (c & 0x03) << (6 - shift); - *s = (*s & ~mask) | val; - - if ((x % 4) == 3) - s++; - } -} - - -static int pc_keypress () -{ - return !!kbhit(); -} - - -static int pc_get_key () -{ - union REGS r; - UINT16 key; - - - memset (&r, 0, sizeof(union REGS)); - int86 (0x16, &r, &r); - key = r.h.al == 0 ? (r.h.ah << 8) : r.h.al; - - return key; -} - - -void interrupt far new_prot_timer_tick(REGS16 r) -{ - clock_ticks++; - /* chain to the old interrupt */ - DosChainToRealIntr(old_real_timer_tick); - /*NOTREACHED*/ -} +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: pcvga.c,v 1.5 2002/11/16 01:20:21 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include + +#include +#include + +#define INCL_DOSPROCESS +#include + +char *textptr; //pointer to the text buffer +char textbuf[4000]; + +char * gptr; //pointer to cga ram + +REALPTR old_real_timer_tick; +PIHANDLER old_prot_timer_tick; +void _interrupt _far new_prot_timer_tick(REGS16); +#define IRQ0 0x08 + + +#include "sarien.h" +#include "graphics.h" + +extern struct gfx_driver *gfx; +extern struct sarien_options opt; + +UINT8 *exec_name; +static UINT8 *screen_buffer; + +static int pc_init_vidmode (void); +static int pc_deinit_vidmode (void); +static void pc_put_block (int, int, int, int); +static void pc_put_pixels (int, int, int, UINT8 *); +static void pc_timer (void); +static int pc_get_key (void); +static int pc_keypress (void); + + +#define TICK_SECONDS 18 + +static struct gfx_driver gfx_pcvga = { + pc_init_vidmode, + pc_deinit_vidmode, + pc_put_block, + pc_put_pixels, + pc_timer, + pc_keypress, + pc_get_key +}; + +static UINT8 cga_map[16] = { + 0x00, /* 0 - black */ + 0x01, /* 1 - blue */ + 0x01, /* 2 - green */ + 0x01, /* 3 - cyan */ + 0x02, /* 4 - red */ + 0x02, /* 5 - magenta */ + 0x02, /* 6 - brown */ + 0x03, /* 7 - gray */ + 0x00, /* 8 - dark gray */ + 0x01, /* 9 - light blue */ + 0x01, /* 10 - light green */ + 0x01, /* 11 - light cyan */ + 0x02, /* 12 - light red */ + 0x02, /* 13 - light magenta */ + 0x02, /* 14 - yellow */ + 0x03 /* 15 - white */ +}; + +static void pc_timer () +{ + static UINT32 cticks = 0; +//printf("clockticks %d\n",clock_ticks); + while (cticks == clock_ticks); + cticks = clock_ticks; +} + + +int init_machine (int argc, char **argv) +{ + int rseg; +/* Get PM pointer to text screen */ + DosMapRealSeg(0xb800,4000,&rseg); + textptr=MAKEP(rseg,0); + +/* save text screen */ + memcpy(textbuf,textptr,4000); + + gfx = &gfx_pcvga; +printf("init_machine\n"); + return err_OK; +} + + +int deinit_machine () +{ + union REGS r; + + /* restore old timer tick routines */ + DosSetRealProtVec(IRQ0, old_prot_timer_tick, old_real_timer_tick,NULL, NULL); + + memset(&r,0x0,sizeof(r)); + r.h.ah = 0; + r.h.al = 3; + int86(0x10, &r, &r); + + memcpy(textptr,textbuf,4000); + +printf("deinit_machine\n"); + return err_OK; +} + + +static int pc_init_vidmode () +{ + int i; + union REGS r; + int rseg; + unsigned short _cs, _ds; + + clock_count = 0; + clock_ticks = 0; + + screen_buffer = calloc (GFX_WIDTH / 4 , GFX_HEIGHT); +printf("GFX_WIDTH %d, GFX_HEIGHT %d\n",GFX_WIDTH/4, GFX_HEIGHT); + + opt.cgaemu = TRUE; + + memset (&r, 0x0, sizeof(union REGS)); + r.x.ax = 0x4; + int86(0x10, &r, &r); + +/* Get PM pointer to VGA screen */ + DosMapRealSeg(0xb800,16384,&rseg); + gptr=MAKEP(rseg,0); + + + /* VERY IMPORTANT -- Lock down our code and data segments + because we don't want them paged out when running under + Windows 3.0. */ + + _asm mov _cs,cs + _asm mov _ds,ds + DosLockSegPages(_cs); + DosLockSegPages(_ds); + + /* install our new timer tick routine */ + DosSetPassToProtVec(IRQ0, (PIHANDLER)new_prot_timer_tick, + &old_prot_timer_tick, &old_real_timer_tick); + +printf("pc_init_vidmode\n"); + return err_OK; +} + + +static int pc_deinit_vidmode () +{ + free (screen_buffer); + + return err_OK; +} + + +/* blit a block onto the screen */ +static void pc_put_block (int x1, int y1, int x2, int y2) +{ + unsigned int i, h, w, p, p2; + UINT8 far *fbuffer; + UINT8 *sbuffer; + + if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; + if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; + if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; + if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; + + y1 &= ~1; /* Always start at an even line */ + + h = y2 - y1 + 1; + w = (x2 - x1 + 1) / 4 + 1; + p = 40 * y1 + x1 / 4; /* Note: (GFX_WIDTH / 4) * (y1 / 2) */ + p2 = p + 40 * y1; + + /* Write to the interlaced CGA framebuffer */ + + //fbuffer = (UINT8 far *)0xb8000000 + p; + fbuffer = gptr+p; + sbuffer = screen_buffer + p2; + for (i = 0; i < h; i += 2) { + _fmemcpy (fbuffer, sbuffer, w); + fbuffer += 80; + sbuffer += 160; + } +#if 1 + //fbuffer = (UINT8 far *)0xb8002000 + p; + fbuffer = gptr+p+0x2000; + sbuffer = screen_buffer + p2 + 80; + for (i = 1; i < h; i += 2) { + _fmemcpy (fbuffer, sbuffer, w); + fbuffer += 80; + sbuffer += 160; + } +#endif +} + + +static void pc_put_pixels(int x, int y, int w, UINT8 *p) +{ + UINT8 *s, mask, val, shift, c; + + for (s = &screen_buffer[80 * y + x / 4]; w; w--, x++, p++) { + shift = (x & 3) * 2; + + /* Sorry, no transparent colors */ + c = *p > 15 ? 0 : cga_map[*p]; + + mask = 0xc0 >> shift; + val = (c & 0x03) << (6 - shift); + *s = (*s & ~mask) | val; + + if ((x % 4) == 3) + s++; + } +} + + +static int pc_keypress () +{ + return !!kbhit(); +} + + +static int pc_get_key () +{ + union REGS r; + UINT16 key; + + + memset (&r, 0, sizeof(union REGS)); + int86 (0x16, &r, &r); + key = r.h.al == 0 ? (r.h.ah << 8) : r.h.al; + + return key; +} + + +void interrupt far new_prot_timer_tick(REGS16 r) +{ + clock_ticks++; + /* chain to the old interrupt */ + DosChainToRealIntr(old_real_timer_tick); + /*NOTREACHED*/ +} \ No newline at end of file diff --git a/pharvid.c b/pharvid.c index e384854..fb18aee 100644 --- a/pharvid.c +++ b/pharvid.c @@ -1,222 +1,222 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: pcvga.c,v 1.5 2002/11/16 01:20:21 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include - -#include -#include - -#define INCL_DOSPROCESS -#include - -char *textptr; //pointer to the text buffer -char textbuf[4000]; - -char * gptr; //pointer to vga ram - -REALPTR old_real_timer_tick; -PIHANDLER old_prot_timer_tick; -void _interrupt _far new_prot_timer_tick(REGS16); -#define IRQ0 0x08 - - -#include "sarien.h" -#include "graphics.h" - -extern struct gfx_driver *gfx; -extern struct sarien_options opt; - -UINT8 *exec_name; -static UINT8 *screen_buffer; - -static int pc_init_vidmode (void); -static int pc_deinit_vidmode (void); -static void pc_put_block (int, int, int, int); -static void pc_put_pixels (int, int, int, UINT8 *); -static void pc_timer (void); -static int pc_get_key (void); -static int pc_keypress (void); - - -#define TICK_SECONDS 18 - -static struct gfx_driver gfx_pcvga = { - pc_init_vidmode, - pc_deinit_vidmode, - pc_put_block, - pc_put_pixels, - pc_timer, - pc_keypress, - pc_get_key -}; - -static void pc_timer () -{ - static UINT32 cticks = 0; -//printf("clockticks %d\n",clock_ticks); - while (cticks == clock_ticks); - cticks = clock_ticks; -} - - -int init_machine (int argc, char **argv) -{ - int rseg; -/* Get PM pointer to text screen */ - DosMapRealSeg(0xb800,4000,&rseg); - textptr=MAKEP(rseg,0); - -/* save text screen */ - memcpy(textbuf,textptr,4000); - - gfx = &gfx_pcvga; -printf("init_machine\n"); - return err_OK; -} - - -int deinit_machine () -{ - union REGS r; - - /* restore old timer tick routines */ - DosSetRealProtVec(IRQ0, old_prot_timer_tick, old_real_timer_tick,NULL, NULL); - - memset(&r,0x0,sizeof(r)); - r.h.ah = 0; - r.h.al = 3; - int86(0x10, &r, &r); - - memcpy(textptr,textbuf,4000); - -printf("deinit_machine\n"); - return err_OK; -} - - -static int pc_init_vidmode () -{ - int i; - union REGS r; - int rseg; - unsigned short _cs, _ds; - - clock_count = 0; - clock_ticks = 0; - - screen_buffer = calloc (GFX_WIDTH, GFX_HEIGHT); -printf("GFX_WIDTH %d, GFX_HEIGHT %d\n",GFX_WIDTH, GFX_HEIGHT); - - r.h.ah = 0; - r.h.al = 13; - int86(0x10, &r, &r); - -/* Get PM pointer to VGA screen */ - DosMapRealSeg(0xa000,64000,&rseg); - gptr=MAKEP(rseg,0); - - - /* VERY IMPORTANT -- Lock down our code and data segments - because we don't want them paged out when running under - Windows 3.0. */ - - _asm mov _cs,cs - _asm mov _ds,ds - DosLockSegPages(_cs); - DosLockSegPages(_ds); - - /* install our new timer tick routine */ - DosSetPassToProtVec(IRQ0, (PIHANDLER)new_prot_timer_tick, - &old_prot_timer_tick, &old_real_timer_tick); - - - /* set colors */ -// _setcolor(palette); - outp(0x3c8, 0); - for (i = 0; i < 32 * 3; i++) - outp(0x3c9, palette[i]); - - -printf("pc_init_vidmode\n"); - return err_OK; -} - - -static int pc_deinit_vidmode () -{ - free (screen_buffer); - - return err_OK; -} - - -/* blit a block onto the screen */ -static void pc_put_block (int x1, int y1, int x2, int y2) -{ - unsigned int h, w, p; -#if 0 - if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; - if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; - if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; - if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; - - h = y2 - y1 + 1; - w = x2 - x1 + 1; - p = GFX_WIDTH * y1 + x1; - - while (h--) { - /* Turbo C wants 0xa0000000 in seg:ofs format */ - _fmemcpy ((UINT8 far *)gptr + p, screen_buffer + p, w); - //memcpy(gptr+p,screen_buffer+p,w); - p += 320; - } -#else - memcpy(gptr,screen_buffer,64000); -#endif -} - - -static void pc_put_pixels(int x, int y, int w, UINT8 *p) -{ - UINT8 *s; - for (s = &screen_buffer[y * 320 + x]; w--; *s++ = *p++); -} - - -static int pc_keypress () -{ - return !!kbhit(); -} - - -static int pc_get_key () -{ - union REGS r; - UINT16 key; - - - memset (&r, 0, sizeof(union REGS)); - int86 (0x16, &r, &r); - key = r.h.al == 0 ? (r.h.ah << 8) : r.h.al; - - return key; -} - - -void interrupt far new_prot_timer_tick(REGS16 r) -{ - clock_ticks++; - /* chain to the old interrupt */ - DosChainToRealIntr(old_real_timer_tick); - /*NOTREACHED*/ -} +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: pcvga.c,v 1.5 2002/11/16 01:20:21 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include + +#include +#include + +#define INCL_DOSPROCESS +#include + +char *textptr; //pointer to the text buffer +char textbuf[4000]; + +char * gptr; //pointer to vga ram + +REALPTR old_real_timer_tick; +PIHANDLER old_prot_timer_tick; +void _interrupt _far new_prot_timer_tick(REGS16); +#define IRQ0 0x08 + + +#include "sarien.h" +#include "graphics.h" + +extern struct gfx_driver *gfx; +extern struct sarien_options opt; + +UINT8 *exec_name; +static UINT8 *screen_buffer; + +static int pc_init_vidmode (void); +static int pc_deinit_vidmode (void); +static void pc_put_block (int, int, int, int); +static void pc_put_pixels (int, int, int, UINT8 *); +static void pc_timer (void); +static int pc_get_key (void); +static int pc_keypress (void); + + +#define TICK_SECONDS 18 + +static struct gfx_driver gfx_pcvga = { + pc_init_vidmode, + pc_deinit_vidmode, + pc_put_block, + pc_put_pixels, + pc_timer, + pc_keypress, + pc_get_key +}; + +static void pc_timer () +{ + static UINT32 cticks = 0; +//printf("clockticks %d\n",clock_ticks); + while (cticks == clock_ticks); + cticks = clock_ticks; +} + + +int init_machine (int argc, char **argv) +{ + int rseg; +/* Get PM pointer to text screen */ + DosMapRealSeg(0xb800,4000,&rseg); + textptr=MAKEP(rseg,0); + +/* save text screen */ + memcpy(textbuf,textptr,4000); + + gfx = &gfx_pcvga; +printf("init_machine\n"); + return err_OK; +} + + +int deinit_machine () +{ + union REGS r; + + /* restore old timer tick routines */ + DosSetRealProtVec(IRQ0, old_prot_timer_tick, old_real_timer_tick,NULL, NULL); + + memset(&r,0x0,sizeof(r)); + r.h.ah = 0; + r.h.al = 3; + int86(0x10, &r, &r); + + memcpy(textptr,textbuf,4000); + +printf("deinit_machine\n"); + return err_OK; +} + + +static int pc_init_vidmode () +{ + int i; + union REGS r; + int rseg; + unsigned short _cs, _ds; + + clock_count = 0; + clock_ticks = 0; + + screen_buffer = calloc (GFX_WIDTH, GFX_HEIGHT); +printf("GFX_WIDTH %d, GFX_HEIGHT %d\n",GFX_WIDTH, GFX_HEIGHT); + + r.h.ah = 0; + r.h.al = 13; + int86(0x10, &r, &r); + +/* Get PM pointer to VGA screen */ + DosMapRealSeg(0xa000,64000,&rseg); + gptr=MAKEP(rseg,0); + + + /* VERY IMPORTANT -- Lock down our code and data segments + because we don't want them paged out when running under + Windows 3.0. */ + + _asm mov _cs,cs + _asm mov _ds,ds + DosLockSegPages(_cs); + DosLockSegPages(_ds); + + /* install our new timer tick routine */ + DosSetPassToProtVec(IRQ0, (PIHANDLER)new_prot_timer_tick, + &old_prot_timer_tick, &old_real_timer_tick); + + + /* set colors */ +// _setcolor(palette); + outp(0x3c8, 0); + for (i = 0; i < 32 * 3; i++) + outp(0x3c9, palette[i]); + + +printf("pc_init_vidmode\n"); + return err_OK; +} + + +static int pc_deinit_vidmode () +{ + free (screen_buffer); + + return err_OK; +} + + +/* blit a block onto the screen */ +static void pc_put_block (int x1, int y1, int x2, int y2) +{ + unsigned int h, w, p; +#if 0 + if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; + if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; + if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; + if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; + + h = y2 - y1 + 1; + w = x2 - x1 + 1; + p = GFX_WIDTH * y1 + x1; + + while (h--) { + /* Turbo C wants 0xa0000000 in seg:ofs format */ + _fmemcpy ((UINT8 far *)gptr + p, screen_buffer + p, w); + //memcpy(gptr+p,screen_buffer+p,w); + p += 320; + } +#else + memcpy(gptr,screen_buffer,64000); +#endif +} + + +static void pc_put_pixels(int x, int y, int w, UINT8 *p) +{ + UINT8 *s; + for (s = &screen_buffer[y * 320 + x]; w--; *s++ = *p++); +} + + +static int pc_keypress () +{ + return !!kbhit(); +} + + +static int pc_get_key () +{ + union REGS r; + UINT16 key; + + + memset (&r, 0, sizeof(union REGS)); + int86 (0x16, &r, &r); + key = r.h.al == 0 ? (r.h.ah << 8) : r.h.al; + + return key; +} + + +void interrupt far new_prot_timer_tick(REGS16 r) +{ + clock_ticks++; + /* chain to the old interrupt */ + DosChainToRealIntr(old_real_timer_tick); + /*NOTREACHED*/ +} \ No newline at end of file diff --git a/picture.c b/picture.c index 0b40111..add3e32 100644 --- a/picture.c +++ b/picture.c @@ -1,843 +1,843 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: picture.c,v 1.64 2003/07/05 23:29:38 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "graphics.h" -#include "rand.h" -#include "savegame.h" - -#define next_byte Pdata[foffs++] - -static UINT8 *Pdata; -static UINT32 flen; -static UINT32 foffs; - -static UINT8 pat_code; -static UINT8 pat_num; -static UINT8 pri_on; -static UINT8 scr_on; -static UINT8 scr_colour; -static UINT8 pri_colour; - -static UINT8 circles[][15] = { /* agi circle bitmaps */ - { 0x80 }, - { 0xfc }, - { 0x5f, 0xf4 }, - { 0x66, 0xff, 0xf6, 0x60 }, - { 0x23, 0xbf, 0xff, 0xff, 0xee, 0x20 }, - { 0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00 }, - { 0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff, - 0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80 }, - { 0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x7e, 0x7e, 0x7e, 0x3c, 0x18 } -}; - -static UINT8 splatter_map[32] = { /* splatter brush bitmaps */ - 0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2, - 0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14, - 0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10, - 0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04 -}; - -static UINT8 splatter_start[128] = { /* starting bit position */ - 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, - 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, - 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, - 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, - 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, - 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, - 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, - 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, - 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, - 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, - 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, - 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, - 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, - 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, - 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 -}; - -static void fix_pixel_bothsides (int x, int y); - - -static void put_virt_pixel (int x, int y, int res) -{ - UINT8 *p; - int width = _WIDTH * res; - - if (x < 0 || y < 0 || x >= width || y >= _HEIGHT) - return; - - p = -#ifdef USE_HIRES - res > 1 ? &game.hires[y * width + x] : -#endif - &game.sbuf[y * width + x]; - - if (pri_on) *p = (pri_colour << 4) | (*p & 0x0f); - if (scr_on) *p = scr_colour | (*p & 0xf0); -} - - -/* For the flood fill routines */ - -/* MH2 needs stack size > 300 */ -#define STACK_SIZE 512 -static unsigned int stack_ptr; -static UINT16 stack[STACK_SIZE]; - -static INLINE void _PUSH (UINT16 c) -{ - assert (stack_ptr < STACK_SIZE); - - stack[stack_ptr] = c; - stack_ptr++; -} - -static INLINE UINT16 _POP () -{ - if (stack_ptr == 0) - return 0xffff; - - stack_ptr--; - return stack[stack_ptr]; -} - - -/** - * Draw an AGI line. - * A line drawing routine sent by Joshua Neal, modified by Stuart George - * (fixed >>2 to >>1 and some other bugs like x1 instead of y1, etc.) - * @param x1 x coordinate of start point - * @param y1 y coordinate of start point - * @param x2 x coordinate of end point - * @param y2 y coordinate of end point - * @param res horizontal resolution multiplier - */ -static void draw_line (int x1, int y1, int x2, int y2, int res) -{ - int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta; - int width = _WIDTH * res; - - /* CM: Do clipping */ -#define clip(x, y) if((x)>=(y)) (x)=(y) - clip (x1, width - 1); - clip (x2, width - 1); - clip (y1, _HEIGHT-1); - clip (y2, _HEIGHT-1); - - /* Vertical line */ - - if (x1 == x2) { - if(y1 > y2) { - y = y1; - y1 = y2; - y2 = y; - } - - for ( ; y1 <= y2; y1++) { - put_virt_pixel (x1, y1, res); -#ifdef USE_HIRES - if (res > 1) - fix_pixel_bothsides (x1, y1); -#endif - } - - return; - } - - /* Horizontal line */ - - if (y1 == y2) { - if (x1 > x2) { - x = x1; - x1 = x2; - x2 = x; - } - -#ifdef USE_HIRES - if (res > 1) - fix_pixel_bothsides (x1, y1); -#endif - - for( ; x1 <= x2; x1++) - put_virt_pixel (x1, y1, res); - -#ifdef USE_HIRES - if (res > 1) { - put_virt_pixel (x1, y1, res); - fix_pixel_bothsides (x1, y1); - } -#endif - - return; - } - - y = y1; - x = x1; - - stepY = 1; deltaY = y2-y1; - if (deltaY < 0) { - stepY = -1; - deltaY = -deltaY; - } - - stepX = 1; deltaX = x2 - x1; - if (deltaX < 0) { - stepX = -1; - deltaX = -deltaX; - } - - if (deltaY > deltaX) { - i = deltaY; - detdelta = deltaY; - errorX = deltaY / 2; - errorY = 0; - } else { - i = deltaX; - detdelta = deltaX; - errorX = 0; - errorY = deltaX / 2; - } - - put_virt_pixel (x, y, res); -#ifdef USE_HIRES - if (res > 1) - fix_pixel_bothsides (x, y); -#endif - - do { - errorY += deltaY; - if (errorY >= detdelta) { - errorY -= detdelta; - y += stepY; - } - - errorX += deltaX; - if (errorX >= detdelta) { - errorX -= detdelta; - x += stepX; - } - - put_virt_pixel (x, y, res); -#ifdef USE_HIRES - if (res > 1) - fix_pixel_bothsides (x, y); -#endif - i--; - } while (i > 0); - -#ifdef USE_HIRES - if (res > 1) { - put_virt_pixel (x, y, res); - fix_pixel_bothsides (x, y); - } -#endif -} - -/** - * Draw a relative AGI line. - * Draws short lines relative to last position. (drawing action 0xF7) - * @param res horizontal resolution multiplier - */ -static void dynamic_draw_line (int res) -{ - int x1, y1, disp, dx, dy; - - x1 = next_byte * res; - y1 = next_byte; - - put_virt_pixel (x1, y1, res); - - while (42) { - if ((disp = next_byte) >= 0xf0) - break; - - dx= ((disp & 0xf0) >> 4) & 0x0f; - dy= (disp & 0x0f); - - if (dx & 0x08) dx = -(dx & 0x07); - if (dy & 0x08) dy = -(dy & 0x07); - - dx *= res; - - draw_line (x1, y1, x1 + dx, y1 + dy, res); - x1 += dx; - y1 += dy; - } - foffs--; -} - -/************************************************************************** -** absoluteLine -** -** Draws long lines to actual locations (cf. relative) (drawing action 0xF6) -**************************************************************************/ -static void absolute_draw_line (int res) -{ - int x1, y1, x2, y2; - - x1 = next_byte * res; - y1 = next_byte; - put_virt_pixel (x1, y1, res); - - while (42) { - if ((x2 = next_byte) >= 0xf0) - break; - - if ((y2 = next_byte) >= 0xf0) - break; - - x2 *= res; - - draw_line (x1, y1, x2, y2, res); - x1 = x2; - y1 = y2; - } - foffs--; -} - - -/************************************************************************** -** okToFill -**************************************************************************/ -static INLINE int is_ok_fill_here (int x, int y) -{ - UINT8 p; - - if (x < 0 || x >= _WIDTH || y < 0 || y >= _HEIGHT) - return FALSE; - - if (!scr_on && !pri_on) - return FALSE; - - p = game.sbuf[y * _WIDTH + x]; - - if (!pri_on && scr_on && scr_colour != 15) - return (p & 0x0f) == 15; - - if (pri_on && !scr_on && pri_colour != 4) - return (p >> 4) == 4; - - return (scr_on && (p & 0x0f) == 15 && scr_colour != 15); -} - -/************************************************************************** -** agi_fill -**************************************************************************/ -static void fill_scanline (int x, int y) -{ - unsigned int c; - int newspan_up, newspan_down; - - if (!is_ok_fill_here (x, y)) - return; - - /* Scan for left border */ - for (c = x - 1; is_ok_fill_here (c, y); c--); - - newspan_up = newspan_down = 1; - for (c++; is_ok_fill_here (c, y); c++) { - put_virt_pixel (c, y, 1); - if (is_ok_fill_here (c, y - 1)) { - if (newspan_up) { - _PUSH (c + 320 * (y - 1)); - newspan_up = 0; - } - } else { - newspan_up = 1; - } - - if (is_ok_fill_here (c, y + 1)) { - if (newspan_down) { - _PUSH (c + 320 * (y + 1)); - newspan_down = 0; - } - } else { - newspan_down = 1; - } - } -} - -static void agi_fill (unsigned int x, unsigned int y) -{ - _PUSH (x + 320 * y); - - while (42) { - UINT16 c = _POP(); - - /* Exit if stack is empty */ - if (c == 0xffff) - break; - - x = c % 320; - y = c / 320; - - fill_scanline (x, y); - } - - stack_ptr = 0; -} - -/************************************************************************** -** xCorner -** -** Draws an xCorner (drawing action 0xF5) -**************************************************************************/ -static void x_corner (int res) -{ - int x1, x2, y1, y2; - - x1 = next_byte * res; - y1 = next_byte; - put_virt_pixel (x1, y1, res); - - while (42) { - x2 = next_byte; - - if (x2 >= 0xf0) - break; - - x2 *= res; - - draw_line (x1, y1, x2, y1, res); - x1 = x2; - y2 = next_byte; - - if (y2 >= 0xf0) - break; - - draw_line (x1, y1, x1, y2, res); - y1 = y2; - } - foffs--; -} - - -/************************************************************************** -** yCorner -** -** Draws an yCorner (drawing action 0xF4) -**************************************************************************/ -static void y_corner (int res) -{ - int x1, x2, y1, y2; - - x1 = next_byte * res; - y1 = next_byte; - put_virt_pixel (x1, y1, res); - - while (42) { - y2 = next_byte; - - if (y2 >= 0xF0) - break; - - draw_line (x1, y1, x1, y2, res); - y1 = y2; - x2 = next_byte; - - if (x2 >= 0xf0) - break; - - x2 *= res; - - draw_line (x1, y1, x2, y1, res); - x1 = x2; - } - - foffs--; -} - -/************************************************************************** -** fill -** -** AGI flood fill. (drawing action 0xF8) -**************************************************************************/ -static void fill () -{ - int x1, y1; - - while ((x1 = next_byte) < 0xF0 && (y1 = next_byte) < 0xf0) - agi_fill (x1, y1); - - foffs--; -} - - -/************************************************************************** -** plotPattern -** -** Draws pixels, circles, squares, or splatter brush patterns depending -** on the pattern code. -**************************************************************************/ - -static int plot_pattern_point (int x, int y, int bitpos, int res) -{ - if (pat_code & 0x20) { - if ((splatter_map[bitpos >> 3] >> (7 - (bitpos & 7))) & 1) { -#ifdef USE_HIRES - if (res > 1) { - /* extra randomness in hi-res brush fill - */ - if (rnd(4)) put_virt_pixel(x * 2, y, 2); - if (!rnd(4)) put_virt_pixel(x * 2 + 1, y, 2); - } else -#endif - { - put_virt_pixel (x, y, 1); - } - } - bitpos++; - if (bitpos == 0xff) - bitpos=0; - } else { -#ifdef USE_HIRES - if (res > 1) { - /* double width pixels make MUMG and others - * look nicer - */ - put_virt_pixel (x * 2, y, 2); - put_virt_pixel (x * 2 + 1, y, 2); - } else -#endif - { - put_virt_pixel (x, y, 1); - } - } - - return bitpos; -} - - -static void plot_pattern (int x, int y, int res) -{ - SINT32 circlePos = 0; - UINT32 x1, y1, pensize, bitpos = splatter_start[pat_num]; - - pensize = (pat_code & 7); - - if (x < pensize) - x = pensize-1; - if (y < pensize) - y = pensize; - - for (y1 = y - pensize; y1 <= y + pensize; y1++) { - for (x1 = x - (pensize+1)/2; x1 <= x + pensize / 2; x1++) { - if (pat_code & 0x10) { /* Square */ - bitpos = plot_pattern_point - (x1, y1, bitpos, res); - } else { /* Circle */ - if ((circles[pat_code&7][circlePos>>3] >> - (7-(circlePos&7)))&1) - { - bitpos = plot_pattern_point - (x1, y1, bitpos, res); - } - circlePos++; - } - } - } -} - -/************************************************************************** -** plotBrush -** -** Plots points and various brush patterns. -**************************************************************************/ -static void plot_brush (int res) -{ - int x1, y1; - - while (42) { - if (pat_code & 0x20) { - if ((pat_num = next_byte) >= 0xF0) - break; - pat_num = (pat_num >> 1) & 0x7f; - } - - if ((x1 = next_byte) >= 0xf0) - break; - - if ((y1 = next_byte) >= 0xf0) - break; - - plot_pattern (x1, y1, res); - } - - foffs--; -} - -#ifdef USE_HIRES -#include "hirespic.c" -#endif - -static void draw_picture () -{ - UINT8 act; - int drawing; -#ifdef USE_HIRES - int save_foffs; -#endif - - pat_code = 0; - pat_num = 0; - pri_on = scr_on = FALSE; - scr_colour = 0xf; - pri_colour = 0x4; - - drawing = 1; - - _D (_D_WARN "Drawing picture"); - for (drawing = 1; drawing && foffs < flen; ) { - -#ifdef USE_HIRES - save_foffs = foffs; -#endif - - act = next_byte; - switch(act) { - case 0xf0: /* set colour on screen */ - scr_colour = next_byte; - scr_colour &= 0xF; /* for v3 drawing diff */ - scr_on = TRUE; - break; - case 0xf1: /* disable screen drawing */ - scr_on = FALSE; - break; - case 0xf2: /* set colour on priority */ - pri_colour = next_byte; - pri_colour &= 0xf; /* for v3 drawing diff */ - pri_on = TRUE; - break; - case 0xf3: /* disable priority screen */ - pri_on = FALSE; - break; - case 0xf4: /* y-corner */ - y_corner (1); - break; - case 0xf5: /* x-corner */ - x_corner (1); - break; - case 0xf6: /* absolute draw lines */ - absolute_draw_line (1); - break; - case 0xf7: /* dynamic draw lines */ - dynamic_draw_line (1); - break; - case 0xf8: /* fill */ - fill (); - break; - case 0xf9: /* set pattern */ - pat_code = next_byte; - break; - case 0xfA: /* plot brush */ - plot_brush (1); - break; - case 0xFF: /* end of pic data */ - default: - drawing = 0; - break; - } - -#ifdef USE_HIRES - foffs = save_foffs; - - act = next_byte; - switch(act) { - case 0xf0: /* set colour on screen */ - scr_colour = next_byte; - scr_colour &= 0xF; /* for v3 drawing diff */ - scr_on = TRUE; - break; - case 0xf1: /* disable screen drawing */ - scr_on = FALSE; - break; - case 0xf2: /* set colour on priority */ - pri_colour = next_byte; - pri_colour &= 0xf; /* for v3 drawing diff */ - pri_on = TRUE; - break; - case 0xf3: /* disable priority screen */ - pri_on = FALSE; - break; - case 0xf4: /* y-corner */ - y_corner (2); - break; - case 0xf5: /* x-corner */ - x_corner (2); - break; - case 0xf6: /* absolute draw lines */ - absolute_draw_line (2); - break; - case 0xf7: /* dynamic draw lines */ - dynamic_draw_line (2); - break; - case 0xf8: /* fill */ - hires_fill (); - break; - case 0xf9: /* set pattern */ - pat_code = next_byte; - break; - case 0xfA: /* plot brush */ - plot_brush (2); - break; - case 0xFF: /* end of pic data */ - default: - drawing = 0; - break; - } -#endif - } -} - -/* - * Public functions - */ - -//#if !defined(PALMOS) && !defined(FAKE_PALMOS) -/** - * - */ -UINT8* convert_v3_pic (UINT8 *data, UINT32 len) -{ - UINT8 d, old = 0, x, *in, *xdata, *out, mode = 0; - UINT32 i, ulen; - - xdata = malloc (len + len / 2); - - out = xdata; - in = Pdata; - - for (i = ulen = 0; i < len; i++, ulen++) { - d = *in++; - - *out++ = x = mode ? ((d & 0xF0) >> 4) + ((old & 0x0F) << 4) : d; - - if (x == 0xFF) { - ulen++; - break; - } - - if (x == 0xf0 || x == 0xf2) { - if (mode) { - *out++ = d & 0x0F; - ulen++; - } else { - d = *in++; - *out++ = (d & 0xF0) >> 4; - i++, ulen++; - } - - mode = !mode; - } - - old = d; - } - - free (Pdata); - xdata = realloc (xdata, ulen); - - return xdata; -} -//#endif /* !PALMOS && !FAKE_PALMOS */ - -/** - * Decode an AGI picture resource. - * This function decodes an AGI picture resource into the correct slot - * and draws it on the AGI screen, optionally cleaning the screen before - * drawing. - * @param n AGI picture resource number - * @param clear clear AGI screen before drawing - */ -int decode_picture (int n, int clear) -{ - _D (_D_WARN "(%d)", n); - - pat_code = 0; - pat_num = 0; - pri_on = scr_on = FALSE; - scr_colour = 0xF; - pri_colour = 0x4; - - Pdata = game.pictures[n].rdata; - flen = game.dir_pic[n].len; - foffs = 0; - - if (clear) { - memset (game.sbuf, 0x4f, _WIDTH * _HEIGHT); -#ifdef USE_HIRES - memset (game.hires, 0x4f, _WIDTH * 2 * _HEIGHT); -#endif - } - - draw_picture (); - -#ifdef USE_HIRES - fix_hires_picture (); -#endif - - if (clear) - clear_image_stack(); - record_image_stack_call (ADD_PIC, n, clear, 0, 0, 0, 0, 0); - - return err_OK; -} - - -/** - * Unload an AGI picture resource. - * This function unloads an AGI picture resource and deallocates - * resource data. - * @param n AGI picture resource number - */ -int unload_picture (int n) -{ - /* remove visual buffer & priority buffer if they exist */ - if (game.dir_pic[n].flags & RES_LOADED) { - free (game.pictures[n].rdata); - game.dir_pic[n].flags &= ~RES_LOADED; - } - - return err_OK; -} - -/** - * Show AGI picture. - * This function copies a ``hidden'' AGI picture to the output device. - */ -void show_pic () -{ - int i, y; - int offset; - - _D (_D_WARN "Show picture!"); -#ifdef USE_HIRES - if (opt.hires) { - show_hires_pic (); - return; - } -#endif - - i = 0; - offset = game.line_min_print * CHAR_LINES; - for (y = 0; y < _HEIGHT; y++) { - put_pixels_a (0, y + offset, _WIDTH, &game.sbuf[i]); - i += _WIDTH; - } - - flush_screen (); -} - - -/* end: picture.c */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: picture.c,v 1.64 2003/07/05 23:29:38 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "graphics.h" +#include "rand.h" +#include "savegame.h" + +#define next_byte Pdata[foffs++] + +static UINT8 *Pdata; +static UINT32 flen; +static UINT32 foffs; + +static UINT8 pat_code; +static UINT8 pat_num; +static UINT8 pri_on; +static UINT8 scr_on; +static UINT8 scr_colour; +static UINT8 pri_colour; + +static UINT8 circles[][15] = { /* agi circle bitmaps */ + { 0x80 }, + { 0xfc }, + { 0x5f, 0xf4 }, + { 0x66, 0xff, 0xf6, 0x60 }, + { 0x23, 0xbf, 0xff, 0xff, 0xee, 0x20 }, + { 0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00 }, + { 0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff, + 0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80 }, + { 0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7e, 0x7e, 0x7e, 0x3c, 0x18 } +}; + +static UINT8 splatter_map[32] = { /* splatter brush bitmaps */ + 0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2, + 0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14, + 0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10, + 0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04 +}; + +static UINT8 splatter_start[128] = { /* starting bit position */ + 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, + 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, + 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, + 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, + 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, + 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, + 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, + 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, + 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, + 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, + 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, + 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, + 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, + 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, + 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 +}; + +static void fix_pixel_bothsides (int x, int y); + + +static void put_virt_pixel (int x, int y, int res) +{ + UINT8 *p; + int width = _WIDTH * res; + + if (x < 0 || y < 0 || x >= width || y >= _HEIGHT) + return; + + p = +#ifdef USE_HIRES + res > 1 ? &game.hires[y * width + x] : +#endif + &game.sbuf[y * width + x]; + + if (pri_on) *p = (pri_colour << 4) | (*p & 0x0f); + if (scr_on) *p = scr_colour | (*p & 0xf0); +} + + +/* For the flood fill routines */ + +/* MH2 needs stack size > 300 */ +#define STACK_SIZE 512 +static unsigned int stack_ptr; +static UINT16 stack[STACK_SIZE]; + +static INLINE void _PUSH (UINT16 c) +{ + assert (stack_ptr < STACK_SIZE); + + stack[stack_ptr] = c; + stack_ptr++; +} + +static INLINE UINT16 _POP () +{ + if (stack_ptr == 0) + return 0xffff; + + stack_ptr--; + return stack[stack_ptr]; +} + + +/** + * Draw an AGI line. + * A line drawing routine sent by Joshua Neal, modified by Stuart George + * (fixed >>2 to >>1 and some other bugs like x1 instead of y1, etc.) + * @param x1 x coordinate of start point + * @param y1 y coordinate of start point + * @param x2 x coordinate of end point + * @param y2 y coordinate of end point + * @param res horizontal resolution multiplier + */ +static void draw_line (int x1, int y1, int x2, int y2, int res) +{ + int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta; + int width = _WIDTH * res; + + /* CM: Do clipping */ +#define clip(x, y) if((x)>=(y)) (x)=(y) + clip (x1, width - 1); + clip (x2, width - 1); + clip (y1, _HEIGHT-1); + clip (y2, _HEIGHT-1); + + /* Vertical line */ + + if (x1 == x2) { + if(y1 > y2) { + y = y1; + y1 = y2; + y2 = y; + } + + for ( ; y1 <= y2; y1++) { + put_virt_pixel (x1, y1, res); +#ifdef USE_HIRES + if (res > 1) + fix_pixel_bothsides (x1, y1); +#endif + } + + return; + } + + /* Horizontal line */ + + if (y1 == y2) { + if (x1 > x2) { + x = x1; + x1 = x2; + x2 = x; + } + +#ifdef USE_HIRES + if (res > 1) + fix_pixel_bothsides (x1, y1); +#endif + + for( ; x1 <= x2; x1++) + put_virt_pixel (x1, y1, res); + +#ifdef USE_HIRES + if (res > 1) { + put_virt_pixel (x1, y1, res); + fix_pixel_bothsides (x1, y1); + } +#endif + + return; + } + + y = y1; + x = x1; + + stepY = 1; deltaY = y2-y1; + if (deltaY < 0) { + stepY = -1; + deltaY = -deltaY; + } + + stepX = 1; deltaX = x2 - x1; + if (deltaX < 0) { + stepX = -1; + deltaX = -deltaX; + } + + if (deltaY > deltaX) { + i = deltaY; + detdelta = deltaY; + errorX = deltaY / 2; + errorY = 0; + } else { + i = deltaX; + detdelta = deltaX; + errorX = 0; + errorY = deltaX / 2; + } + + put_virt_pixel (x, y, res); +#ifdef USE_HIRES + if (res > 1) + fix_pixel_bothsides (x, y); +#endif + + do { + errorY += deltaY; + if (errorY >= detdelta) { + errorY -= detdelta; + y += stepY; + } + + errorX += deltaX; + if (errorX >= detdelta) { + errorX -= detdelta; + x += stepX; + } + + put_virt_pixel (x, y, res); +#ifdef USE_HIRES + if (res > 1) + fix_pixel_bothsides (x, y); +#endif + i--; + } while (i > 0); + +#ifdef USE_HIRES + if (res > 1) { + put_virt_pixel (x, y, res); + fix_pixel_bothsides (x, y); + } +#endif +} + +/** + * Draw a relative AGI line. + * Draws short lines relative to last position. (drawing action 0xF7) + * @param res horizontal resolution multiplier + */ +static void dynamic_draw_line (int res) +{ + int x1, y1, disp, dx, dy; + + x1 = next_byte * res; + y1 = next_byte; + + put_virt_pixel (x1, y1, res); + + while (42) { + if ((disp = next_byte) >= 0xf0) + break; + + dx= ((disp & 0xf0) >> 4) & 0x0f; + dy= (disp & 0x0f); + + if (dx & 0x08) dx = -(dx & 0x07); + if (dy & 0x08) dy = -(dy & 0x07); + + dx *= res; + + draw_line (x1, y1, x1 + dx, y1 + dy, res); + x1 += dx; + y1 += dy; + } + foffs--; +} + +/************************************************************************** +** absoluteLine +** +** Draws long lines to actual locations (cf. relative) (drawing action 0xF6) +**************************************************************************/ +static void absolute_draw_line (int res) +{ + int x1, y1, x2, y2; + + x1 = next_byte * res; + y1 = next_byte; + put_virt_pixel (x1, y1, res); + + while (42) { + if ((x2 = next_byte) >= 0xf0) + break; + + if ((y2 = next_byte) >= 0xf0) + break; + + x2 *= res; + + draw_line (x1, y1, x2, y2, res); + x1 = x2; + y1 = y2; + } + foffs--; +} + + +/************************************************************************** +** okToFill +**************************************************************************/ +static INLINE int is_ok_fill_here (int x, int y) +{ + UINT8 p; + + if (x < 0 || x >= _WIDTH || y < 0 || y >= _HEIGHT) + return FALSE; + + if (!scr_on && !pri_on) + return FALSE; + + p = game.sbuf[y * _WIDTH + x]; + + if (!pri_on && scr_on && scr_colour != 15) + return (p & 0x0f) == 15; + + if (pri_on && !scr_on && pri_colour != 4) + return (p >> 4) == 4; + + return (scr_on && (p & 0x0f) == 15 && scr_colour != 15); +} + +/************************************************************************** +** agi_fill +**************************************************************************/ +static void fill_scanline (int x, int y) +{ + unsigned int c; + int newspan_up, newspan_down; + + if (!is_ok_fill_here (x, y)) + return; + + /* Scan for left border */ + for (c = x - 1; is_ok_fill_here (c, y); c--); + + newspan_up = newspan_down = 1; + for (c++; is_ok_fill_here (c, y); c++) { + put_virt_pixel (c, y, 1); + if (is_ok_fill_here (c, y - 1)) { + if (newspan_up) { + _PUSH (c + 320 * (y - 1)); + newspan_up = 0; + } + } else { + newspan_up = 1; + } + + if (is_ok_fill_here (c, y + 1)) { + if (newspan_down) { + _PUSH (c + 320 * (y + 1)); + newspan_down = 0; + } + } else { + newspan_down = 1; + } + } +} + +static void agi_fill (unsigned int x, unsigned int y) +{ + _PUSH (x + 320 * y); + + while (42) { + UINT16 c = _POP(); + + /* Exit if stack is empty */ + if (c == 0xffff) + break; + + x = c % 320; + y = c / 320; + + fill_scanline (x, y); + } + + stack_ptr = 0; +} + +/************************************************************************** +** xCorner +** +** Draws an xCorner (drawing action 0xF5) +**************************************************************************/ +static void x_corner (int res) +{ + int x1, x2, y1, y2; + + x1 = next_byte * res; + y1 = next_byte; + put_virt_pixel (x1, y1, res); + + while (42) { + x2 = next_byte; + + if (x2 >= 0xf0) + break; + + x2 *= res; + + draw_line (x1, y1, x2, y1, res); + x1 = x2; + y2 = next_byte; + + if (y2 >= 0xf0) + break; + + draw_line (x1, y1, x1, y2, res); + y1 = y2; + } + foffs--; +} + + +/************************************************************************** +** yCorner +** +** Draws an yCorner (drawing action 0xF4) +**************************************************************************/ +static void y_corner (int res) +{ + int x1, x2, y1, y2; + + x1 = next_byte * res; + y1 = next_byte; + put_virt_pixel (x1, y1, res); + + while (42) { + y2 = next_byte; + + if (y2 >= 0xF0) + break; + + draw_line (x1, y1, x1, y2, res); + y1 = y2; + x2 = next_byte; + + if (x2 >= 0xf0) + break; + + x2 *= res; + + draw_line (x1, y1, x2, y1, res); + x1 = x2; + } + + foffs--; +} + +/************************************************************************** +** fill +** +** AGI flood fill. (drawing action 0xF8) +**************************************************************************/ +static void fill () +{ + int x1, y1; + + while ((x1 = next_byte) < 0xF0 && (y1 = next_byte) < 0xf0) + agi_fill (x1, y1); + + foffs--; +} + + +/************************************************************************** +** plotPattern +** +** Draws pixels, circles, squares, or splatter brush patterns depending +** on the pattern code. +**************************************************************************/ + +static int plot_pattern_point (int x, int y, int bitpos, int res) +{ + if (pat_code & 0x20) { + if ((splatter_map[bitpos >> 3] >> (7 - (bitpos & 7))) & 1) { +#ifdef USE_HIRES + if (res > 1) { + /* extra randomness in hi-res brush fill + */ + if (rnd(4)) put_virt_pixel(x * 2, y, 2); + if (!rnd(4)) put_virt_pixel(x * 2 + 1, y, 2); + } else +#endif + { + put_virt_pixel (x, y, 1); + } + } + bitpos++; + if (bitpos == 0xff) + bitpos=0; + } else { +#ifdef USE_HIRES + if (res > 1) { + /* double width pixels make MUMG and others + * look nicer + */ + put_virt_pixel (x * 2, y, 2); + put_virt_pixel (x * 2 + 1, y, 2); + } else +#endif + { + put_virt_pixel (x, y, 1); + } + } + + return bitpos; +} + + +static void plot_pattern (int x, int y, int res) +{ + SINT32 circlePos = 0; + UINT32 x1, y1, pensize, bitpos = splatter_start[pat_num]; + + pensize = (pat_code & 7); + + if (x < pensize) + x = pensize-1; + if (y < pensize) + y = pensize; + + for (y1 = y - pensize; y1 <= y + pensize; y1++) { + for (x1 = x - (pensize+1)/2; x1 <= x + pensize / 2; x1++) { + if (pat_code & 0x10) { /* Square */ + bitpos = plot_pattern_point + (x1, y1, bitpos, res); + } else { /* Circle */ + if ((circles[pat_code&7][circlePos>>3] >> + (7-(circlePos&7)))&1) + { + bitpos = plot_pattern_point + (x1, y1, bitpos, res); + } + circlePos++; + } + } + } +} + +/************************************************************************** +** plotBrush +** +** Plots points and various brush patterns. +**************************************************************************/ +static void plot_brush (int res) +{ + int x1, y1; + + while (42) { + if (pat_code & 0x20) { + if ((pat_num = next_byte) >= 0xF0) + break; + pat_num = (pat_num >> 1) & 0x7f; + } + + if ((x1 = next_byte) >= 0xf0) + break; + + if ((y1 = next_byte) >= 0xf0) + break; + + plot_pattern (x1, y1, res); + } + + foffs--; +} + +#ifdef USE_HIRES +#include "hirespic.c" +#endif + +static void draw_picture () +{ + UINT8 act; + int drawing; +#ifdef USE_HIRES + int save_foffs; +#endif + + pat_code = 0; + pat_num = 0; + pri_on = scr_on = FALSE; + scr_colour = 0xf; + pri_colour = 0x4; + + drawing = 1; + + _D (_D_WARN "Drawing picture"); + for (drawing = 1; drawing && foffs < flen; ) { + +#ifdef USE_HIRES + save_foffs = foffs; +#endif + + act = next_byte; + switch(act) { + case 0xf0: /* set colour on screen */ + scr_colour = next_byte; + scr_colour &= 0xF; /* for v3 drawing diff */ + scr_on = TRUE; + break; + case 0xf1: /* disable screen drawing */ + scr_on = FALSE; + break; + case 0xf2: /* set colour on priority */ + pri_colour = next_byte; + pri_colour &= 0xf; /* for v3 drawing diff */ + pri_on = TRUE; + break; + case 0xf3: /* disable priority screen */ + pri_on = FALSE; + break; + case 0xf4: /* y-corner */ + y_corner (1); + break; + case 0xf5: /* x-corner */ + x_corner (1); + break; + case 0xf6: /* absolute draw lines */ + absolute_draw_line (1); + break; + case 0xf7: /* dynamic draw lines */ + dynamic_draw_line (1); + break; + case 0xf8: /* fill */ + fill (); + break; + case 0xf9: /* set pattern */ + pat_code = next_byte; + break; + case 0xfA: /* plot brush */ + plot_brush (1); + break; + case 0xFF: /* end of pic data */ + default: + drawing = 0; + break; + } + +#ifdef USE_HIRES + foffs = save_foffs; + + act = next_byte; + switch(act) { + case 0xf0: /* set colour on screen */ + scr_colour = next_byte; + scr_colour &= 0xF; /* for v3 drawing diff */ + scr_on = TRUE; + break; + case 0xf1: /* disable screen drawing */ + scr_on = FALSE; + break; + case 0xf2: /* set colour on priority */ + pri_colour = next_byte; + pri_colour &= 0xf; /* for v3 drawing diff */ + pri_on = TRUE; + break; + case 0xf3: /* disable priority screen */ + pri_on = FALSE; + break; + case 0xf4: /* y-corner */ + y_corner (2); + break; + case 0xf5: /* x-corner */ + x_corner (2); + break; + case 0xf6: /* absolute draw lines */ + absolute_draw_line (2); + break; + case 0xf7: /* dynamic draw lines */ + dynamic_draw_line (2); + break; + case 0xf8: /* fill */ + hires_fill (); + break; + case 0xf9: /* set pattern */ + pat_code = next_byte; + break; + case 0xfA: /* plot brush */ + plot_brush (2); + break; + case 0xFF: /* end of pic data */ + default: + drawing = 0; + break; + } +#endif + } +} + +/* + * Public functions + */ + +//#if !defined(PALMOS) && !defined(FAKE_PALMOS) +/** + * + */ +UINT8* convert_v3_pic (UINT8 *data, UINT32 len) +{ + UINT8 d, old = 0, x, *in, *xdata, *out, mode = 0; + UINT32 i, ulen; + + xdata = malloc (len + len / 2); + + out = xdata; + in = Pdata; + + for (i = ulen = 0; i < len; i++, ulen++) { + d = *in++; + + *out++ = x = mode ? ((d & 0xF0) >> 4) + ((old & 0x0F) << 4) : d; + + if (x == 0xFF) { + ulen++; + break; + } + + if (x == 0xf0 || x == 0xf2) { + if (mode) { + *out++ = d & 0x0F; + ulen++; + } else { + d = *in++; + *out++ = (d & 0xF0) >> 4; + i++, ulen++; + } + + mode = !mode; + } + + old = d; + } + + free (Pdata); + xdata = realloc (xdata, ulen); + + return xdata; +} +//#endif /* !PALMOS && !FAKE_PALMOS */ + +/** + * Decode an AGI picture resource. + * This function decodes an AGI picture resource into the correct slot + * and draws it on the AGI screen, optionally cleaning the screen before + * drawing. + * @param n AGI picture resource number + * @param clear clear AGI screen before drawing + */ +int decode_picture (int n, int clear) +{ + _D (_D_WARN "(%d)", n); + + pat_code = 0; + pat_num = 0; + pri_on = scr_on = FALSE; + scr_colour = 0xF; + pri_colour = 0x4; + + Pdata = game.pictures[n].rdata; + flen = game.dir_pic[n].len; + foffs = 0; + + if (clear) { + memset (game.sbuf, 0x4f, _WIDTH * _HEIGHT); +#ifdef USE_HIRES + memset (game.hires, 0x4f, _WIDTH * 2 * _HEIGHT); +#endif + } + + draw_picture (); + +#ifdef USE_HIRES + fix_hires_picture (); +#endif + + if (clear) + clear_image_stack(); + record_image_stack_call (ADD_PIC, n, clear, 0, 0, 0, 0, 0); + + return err_OK; +} + + +/** + * Unload an AGI picture resource. + * This function unloads an AGI picture resource and deallocates + * resource data. + * @param n AGI picture resource number + */ +int unload_picture (int n) +{ + /* remove visual buffer & priority buffer if they exist */ + if (game.dir_pic[n].flags & RES_LOADED) { + free (game.pictures[n].rdata); + game.dir_pic[n].flags &= ~RES_LOADED; + } + + return err_OK; +} + +/** + * Show AGI picture. + * This function copies a ``hidden'' AGI picture to the output device. + */ +void show_pic () +{ + int i, y; + int offset; + + _D (_D_WARN "Show picture!"); +#ifdef USE_HIRES + if (opt.hires) { + show_hires_pic (); + return; + } +#endif + + i = 0; + offset = game.line_min_print * CHAR_LINES; + for (y = 0; y < _HEIGHT; y++) { + put_pixels_a (0, y + offset, _WIDTH, &game.sbuf[i]); + i += _WIDTH; + } + + flush_screen (); +} + + +/* end: picture.c */ diff --git a/picview.c b/picview.c index 76c0f24..c15dc63 100644 --- a/picview.c +++ b/picview.c @@ -1,170 +1,170 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: picview.c,v 1.19 2002/11/12 11:28:41 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#ifndef PALMOS -#include -#endif -#include "sarien.h" - -#ifdef OPT_PICTURE_VIEWER - -#include "agi.h" -#include "graphics.h" -#include "keyboard.h" -#include "console.h" -#include "text.h" - - -static int picviewer_get_key () -{ - int key; - - /* clear key queue */ - while (keypress ()) { get_key (); } - - _D (_D_WARN "waiting..."); - while (42) { - poll_timer (); - key = do_poll_keyboard (); - if (key) break; - } - - return key; -} - - -static void screen_dump () -{ - FILE *f; - - f = fopen ("screen.raw", "wb"); - fwrite (game.sbuf, _HEIGHT, _WIDTH, f); - fclose (f); -} - - -int view_pictures () -{ - int ec = err_OK; - char x[64]; - int i, pic = 0, dir = 1; - - game.line_min_print = 1; - - for (i = 0; ec == err_OK; i = 1) { - while (game.dir_pic[pic].offset == _EMPTY) { - pic += dir; - if (pic < 0) - pic = MAX_DIRS - 1; - - if (pic > MAX_DIRS - 1) { - pic = 0; - if (i == 0) { /* no pics? */ - ec = 1; - fprintf (stderr, "No pictures found\n"); - goto end_view; - } - } - } - - _D ("picture = %d", pic); - if ((ec = agi_load_resource (rPICTURE, pic)) != err_OK) { - _D (_D_CRIT "Whoops. bad pic %d", pic); - ec = err_OK; - pic += dir; - goto next_pic; - } - - print_text ("[drawing]", 0, 16, 0, strlen (x) + 1, 0, 15); - - /* decodes the raw data to useable form */ - decode_picture (pic, TRUE); - - show_pic (); - put_screen (); - -update_statusline: -#ifdef USE_HIRES - sprintf (x, "Picture:%3i Hi-res: %3s", - pic, opt.hires ? " on" : "off"); -#else - sprintf (x, "Picture:%3i Hi-res: N/A", pic); -#endif - print_text (x, 0, 0, 0, strlen (x) + 1, 0, 15); - sprintf (x, "H:Hi-res P:Vis/Prio +:Next -:Prev"); - print_text (x, 0, 0, 23, strlen (x) + 1, 15, 0); - sprintf (x, "R:Redraw D:Screen dump Q:Quit"); - print_text (x, 0, 0, 24, strlen (x) + 1, 15, 0); - - while (42) { - decode_picture (pic, TRUE); - switch (picviewer_get_key()) { - case 'q': - goto end_view; -#ifdef USE_HIRES -#ifdef USE_MOUSE - case BUTTON_RIGHT: -#endif - case 'h': - opt.hires = !opt.hires; - show_pic (); - put_screen (); - goto update_statusline; -#endif - case 'p': - debug.priority = !debug.priority; - show_pic (); - put_screen (); - break; - case 'd': - /*opt.showscreendraw = !opt.showscreendraw;*/ - screen_dump(); - goto update_statusline; - case 'r': - goto next_pic; -#ifdef USE_MOUSE - case BUTTON_LEFT: - if (mouse.x < GFX_WIDTH / 2) - goto previous_pic; -#endif - /* fall through */ - case '+': - _D ("next pic"); - if (pic < MAX_DIRS - 1) - pic++; - else - pic = 0; - dir = 1; - goto next_pic; - case '-': - previous_pic: - _D ("previous pic"); - if (pic > 0) - pic--; - else - pic = MAX_DIRS - 1; - i = 0; - dir = -1; - goto next_pic; - } - } -next_pic: - agi_unload_resource (rPICTURE, pic); - - } - -end_view: - return ec; -} - -#endif /* OPT_PICTURE_VIEWER */ - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: picview.c,v 1.19 2002/11/12 11:28:41 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#ifndef PALMOS +#include +#endif +#include "sarien.h" + +#ifdef OPT_PICTURE_VIEWER + +#include "agi.h" +#include "graphics.h" +#include "keyboard.h" +#include "console.h" +#include "text.h" + + +static int picviewer_get_key () +{ + int key; + + /* clear key queue */ + while (keypress ()) { get_key (); } + + _D (_D_WARN "waiting..."); + while (42) { + poll_timer (); + key = do_poll_keyboard (); + if (key) break; + } + + return key; +} + + +static void screen_dump () +{ + FILE *f; + + f = fopen ("screen.raw", "wb"); + fwrite (game.sbuf, _HEIGHT, _WIDTH, f); + fclose (f); +} + + +int view_pictures () +{ + int ec = err_OK; + char x[64]; + int i, pic = 0, dir = 1; + + game.line_min_print = 1; + + for (i = 0; ec == err_OK; i = 1) { + while (game.dir_pic[pic].offset == _EMPTY) { + pic += dir; + if (pic < 0) + pic = MAX_DIRS - 1; + + if (pic > MAX_DIRS - 1) { + pic = 0; + if (i == 0) { /* no pics? */ + ec = 1; + fprintf (stderr, "No pictures found\n"); + goto end_view; + } + } + } + + _D ("picture = %d", pic); + if ((ec = agi_load_resource (rPICTURE, pic)) != err_OK) { + _D (_D_CRIT "Whoops. bad pic %d", pic); + ec = err_OK; + pic += dir; + goto next_pic; + } + + print_text ("[drawing]", 0, 16, 0, strlen (x) + 1, 0, 15); + + /* decodes the raw data to useable form */ + decode_picture (pic, TRUE); + + show_pic (); + put_screen (); + +update_statusline: +#ifdef USE_HIRES + sprintf (x, "Picture:%3i Hi-res: %3s", + pic, opt.hires ? " on" : "off"); +#else + sprintf (x, "Picture:%3i Hi-res: N/A", pic); +#endif + print_text (x, 0, 0, 0, strlen (x) + 1, 0, 15); + sprintf (x, "H:Hi-res P:Vis/Prio +:Next -:Prev"); + print_text (x, 0, 0, 23, strlen (x) + 1, 15, 0); + sprintf (x, "R:Redraw D:Screen dump Q:Quit"); + print_text (x, 0, 0, 24, strlen (x) + 1, 15, 0); + + while (42) { + decode_picture (pic, TRUE); + switch (picviewer_get_key()) { + case 'q': + goto end_view; +#ifdef USE_HIRES +#ifdef USE_MOUSE + case BUTTON_RIGHT: +#endif + case 'h': + opt.hires = !opt.hires; + show_pic (); + put_screen (); + goto update_statusline; +#endif + case 'p': + debug.priority = !debug.priority; + show_pic (); + put_screen (); + break; + case 'd': + /*opt.showscreendraw = !opt.showscreendraw;*/ + screen_dump(); + goto update_statusline; + case 'r': + goto next_pic; +#ifdef USE_MOUSE + case BUTTON_LEFT: + if (mouse.x < GFX_WIDTH / 2) + goto previous_pic; +#endif + /* fall through */ + case '+': + _D ("next pic"); + if (pic < MAX_DIRS - 1) + pic++; + else + pic = 0; + dir = 1; + goto next_pic; + case '-': + previous_pic: + _D ("previous pic"); + if (pic > 0) + pic--; + else + pic = MAX_DIRS - 1; + i = 0; + dir = -1; + goto next_pic; + } + } +next_pic: + agi_unload_resource (rPICTURE, pic); + + } + +end_view: + return ec; +} + +#endif /* OPT_PICTURE_VIEWER */ + diff --git a/rand.c b/rand.c index f10b765..b7e969b 100644 --- a/rand.c +++ b/rand.c @@ -1,73 +1,73 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: rand.c,v 1.9 2002/03/31 18:46:24 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#ifndef PALMOS -#include -#else -#define time(x) (x) -#endif - -#include "sarien.h" -#include "rand.h" - -#define RNG_M 2147483647L -#define RNG_A 48271L -#define RNG_Q 127773L -#define RNG_R 2836L - - -SINT32 rnd_seed; - -static void set_xrnd_seed(SINT32 seedval) -{ - rnd_seed = (seedval % (RNG_M-1)) + 1; -} - -static SINT32 xrnd(void) -{ - SINT32 low, high, test; - - high = rnd_seed / RNG_Q; - low = rnd_seed % RNG_Q; - test = RNG_A * low - RNG_R * high; - - return rnd_seed = test > 0 ? test : test + RNG_M; -} - -/* - * Public functions - */ - -/** - * Set the random number generator seed. - */ -void set_rnd_seed () -{ - set_xrnd_seed(time(NULL)); -} - -/** - * Read the random number generator seed. - */ -SINT32 get_rnd_seed () -{ - return rnd_seed; -} - -/** - * Return random number. - * This function returns a random value lesser than the specified value. - */ -SINT32 rnd (SINT32 maxrnd) -{ - return maxrnd ? xrnd() % maxrnd : xrnd(); -} - -/* end: rand.c */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: rand.c,v 1.9 2002/03/31 18:46:24 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#ifndef PALMOS +#include +#else +#define time(x) (x) +#endif + +#include "sarien.h" +#include "rand.h" + +#define RNG_M 2147483647L +#define RNG_A 48271L +#define RNG_Q 127773L +#define RNG_R 2836L + + +SINT32 rnd_seed; + +static void set_xrnd_seed(SINT32 seedval) +{ + rnd_seed = (seedval % (RNG_M-1)) + 1; +} + +static SINT32 xrnd(void) +{ + SINT32 low, high, test; + + high = rnd_seed / RNG_Q; + low = rnd_seed % RNG_Q; + test = RNG_A * low - RNG_R * high; + + return rnd_seed = test > 0 ? test : test + RNG_M; +} + +/* + * Public functions + */ + +/** + * Set the random number generator seed. + */ +void set_rnd_seed () +{ + set_xrnd_seed(time(NULL)); +} + +/** + * Read the random number generator seed. + */ +SINT32 get_rnd_seed () +{ + return rnd_seed; +} + +/** + * Return random number. + * This function returns a random value lesser than the specified value. + */ +SINT32 rnd (SINT32 maxrnd) +{ + return maxrnd ? xrnd() % maxrnd : xrnd(); +} + +/* end: rand.c */ diff --git a/sarien.ini b/sarien.ini index 327d565..aa896cd 100644 --- a/sarien.ini +++ b/sarien.ini @@ -1,100 +1,100 @@ -# Sarien configuration file -# -# $Id: sarien.cfg,v 1.10 2001/11/06 09:49:58 cmatsuoka Exp $ -# -# The interpreter will look for this file in different places according -# to the operating system being used. -# -# In UNIX: -# $HOME/.sarienrc -# /etc/sarien.conf -# -# In Cygwin: -# /etc/sarien.conf -# -# In DOS/Win32: -# %SARIEN%\SARIEN.INI -# .\SARIEN.INI -# - -# CRC Int. Version [options] Game name Original int. version - -# IBM-PC versions - -0x24A18 0x2440 Black Cauldron (2.00) # 2.439 6/14/87 -0x49EDA 0x2917 Kings Quest 1 (2.0F) # 2.917 -0x633CB 0x2440 Kings Quest 2 # 2.411 -0x63338 0x2917 Kings Quest 2 (2.2) # 2.917 -0x88673 0x2272 Kings Quest 3 (1.01) # 2.272 11/08/86 -0x840D3 0x2440 Kings Quest 3 (2.00) # 2.435 5/25/87 -0x8410B 0x2936 Kings Quest 3 (2.14) # 2.936 3/15/88 -0x83695 0x2936 Kings Quest 3 (2.14) # 2.936 3/15/88 -0x6F5E1 0x2440 Leisure Suit Larry 1 (1.00) # 2.440 6/1/87 -0x5D77C 0x2917 Mixed Up Mother Goose # 2.915 -0x5D7C6 0x2917 Mixed Up Mother Goose # 2.915 -0x7F18B 0x2917 Police Quest 1 (2.0A) # 2.911 10/23/87 -0x7E0BC 0x2917 Police Quest 1 (2.0G) # 2.917 12/03/87 -0x7EF06 0x2917 Police Quest 1 (2.0G) # 2.917 12/03/87 -0x68036 0x2089 Space Quest 1 (1.0X) # 2.089 -0x67F6E 0x2272 Space Quest 1 (1.1A) # 2.272 -0x68244 0x2440 Space Quest 1 (2.2) # 2.426 -0x8DB32 0x2917 Space Quest 2 # 2.912 -0x8D825 0x2917 Space Quest 2 (2.0A) # 2.912 -0x8DA3E 0x2917 Space Quest 2 (2.0C) # 2.915 -0x8E29B 0x2936 Space Quest 2 (2.0F) # 2.936 -0x31677 0x2272 XMAS Card 1986 # 2.272 -0x8CC43 0x2917 Demo 1 # 2.915 -0x8856C 0x2917 Demo 2 # 2.915 -0x843AC 0x2917 Demo 3 # 2.917 -0x89592 0x3149 Demo 4 # 3.002.102 -0x484AA 0x2440 Demo 5 # 2.425 -0xB124B 0x3086 Kings Quest 4 (v2.0) # 3.002.086 7/27/88 -0xB291F 0x3086 Kings Quest 4 (v2.2) # 3.002.086 9/27/88 -0x23E0E 0x3149 Black Cauldron # 3.002.098 -0x22B50 0x3149 Black Cauldron # 3.002.098 -0x9CB15 0x3149 Kings Quest 4 demo # 3.002.102 -0x4C16D 0x3149 Manhunter New York (1.22) # 3.002.107 8/31/88 -0x53971 0x3149 Manhunter San Francisco (3.02) # 3.002.149 7/26/89 -0xB5A25 0x3149 Gold Rush (5.25) # 3.002.149 -0xB1C9E 0x3149 Gold Rush (3.5) # 3.002.149 -0xB1C08 0x3149 Gold Rush (Cracked) (3.5) # 3.002.149 -0xB598F 0x3149 Gold Rush (Cracked) (5.25) # 3.002.149 - -# Apple //gs versions - -0x4A9E8 0x2272 Kings Quest 1 (1.0S-88223) -0x5F4E8 0x2917 Mixed Up Mother Goose -0x7DB3F 0x2917 Police Quest 1 (2.0A) -0x93260 0x2917 Demo Disk 1.0C (Censored) # guessed interp vers -0x285FB 0x3149 Black Cauldron (1.0O) # 2.24.89 (CE) -0x4C705 0x3149 Manhunter New York # 2.0E 10/05/88 (CE) -0xAF778 0x3086 Kings Quest 4 # 1.0K 11/22/88 (CE) - -# Macintosh versions - -0x4C02C 0x2440 Kings Quest 1 (2.0C) -0x6382E 0x2440 Kings Quest 2 (2.0R) -0x78202 0x2440 Leisure Suit Larry 1 (1.05) # 6/26/87 -0x8DF84 0x2936 Space Quest 2 (2.0D) - -# Atari ST versions - -0x1A7AF 0x2272 Donald Duck's Playground (1.0C) # Aug 8 1986 - -# Amiga versions -# Use option "A" to enable padding - -0x5BCE6 0x2440 [A] Kings Quest 2 (2.0J) -0x8FEA6 0x2936 [A] Space Quest 2 (2.0F) -0x6FDDB 0x2440 [A] Leisure Suit Larry 1 (1.05) # 6/26/87 -0x4BA94 0x3149 [A] Manhunter New York (1.06) # 3/18/89 -0x6EFFB 0x3149 [A] Gold Rush! (2.05) # 2.316 3/09/89 - -# AGDS games -# Use option "a" for AGDS games - -0x5501A 0x2440 [a] Groza # AGDS sample game - -# Fan-made AGI games - -# End of sarien.conf +# Sarien configuration file +# +# $Id: sarien.cfg,v 1.10 2001/11/06 09:49:58 cmatsuoka Exp $ +# +# The interpreter will look for this file in different places according +# to the operating system being used. +# +# In UNIX: +# $HOME/.sarienrc +# /etc/sarien.conf +# +# In Cygwin: +# /etc/sarien.conf +# +# In DOS/Win32: +# %SARIEN%\SARIEN.INI +# .\SARIEN.INI +# + +# CRC Int. Version [options] Game name Original int. version + +# IBM-PC versions + +0x24A18 0x2440 Black Cauldron (2.00) # 2.439 6/14/87 +0x49EDA 0x2917 Kings Quest 1 (2.0F) # 2.917 +0x633CB 0x2440 Kings Quest 2 # 2.411 +0x63338 0x2917 Kings Quest 2 (2.2) # 2.917 +0x88673 0x2272 Kings Quest 3 (1.01) # 2.272 11/08/86 +0x840D3 0x2440 Kings Quest 3 (2.00) # 2.435 5/25/87 +0x8410B 0x2936 Kings Quest 3 (2.14) # 2.936 3/15/88 +0x83695 0x2936 Kings Quest 3 (2.14) # 2.936 3/15/88 +0x6F5E1 0x2440 Leisure Suit Larry 1 (1.00) # 2.440 6/1/87 +0x5D77C 0x2917 Mixed Up Mother Goose # 2.915 +0x5D7C6 0x2917 Mixed Up Mother Goose # 2.915 +0x7F18B 0x2917 Police Quest 1 (2.0A) # 2.911 10/23/87 +0x7E0BC 0x2917 Police Quest 1 (2.0G) # 2.917 12/03/87 +0x7EF06 0x2917 Police Quest 1 (2.0G) # 2.917 12/03/87 +0x68036 0x2089 Space Quest 1 (1.0X) # 2.089 +0x67F6E 0x2272 Space Quest 1 (1.1A) # 2.272 +0x68244 0x2440 Space Quest 1 (2.2) # 2.426 +0x8DB32 0x2917 Space Quest 2 # 2.912 +0x8D825 0x2917 Space Quest 2 (2.0A) # 2.912 +0x8DA3E 0x2917 Space Quest 2 (2.0C) # 2.915 +0x8E29B 0x2936 Space Quest 2 (2.0F) # 2.936 +0x31677 0x2272 XMAS Card 1986 # 2.272 +0x8CC43 0x2917 Demo 1 # 2.915 +0x8856C 0x2917 Demo 2 # 2.915 +0x843AC 0x2917 Demo 3 # 2.917 +0x89592 0x3149 Demo 4 # 3.002.102 +0x484AA 0x2440 Demo 5 # 2.425 +0xB124B 0x3086 Kings Quest 4 (v2.0) # 3.002.086 7/27/88 +0xB291F 0x3086 Kings Quest 4 (v2.2) # 3.002.086 9/27/88 +0x23E0E 0x3149 Black Cauldron # 3.002.098 +0x22B50 0x3149 Black Cauldron # 3.002.098 +0x9CB15 0x3149 Kings Quest 4 demo # 3.002.102 +0x4C16D 0x3149 Manhunter New York (1.22) # 3.002.107 8/31/88 +0x53971 0x3149 Manhunter San Francisco (3.02) # 3.002.149 7/26/89 +0xB5A25 0x3149 Gold Rush (5.25) # 3.002.149 +0xB1C9E 0x3149 Gold Rush (3.5) # 3.002.149 +0xB1C08 0x3149 Gold Rush (Cracked) (3.5) # 3.002.149 +0xB598F 0x3149 Gold Rush (Cracked) (5.25) # 3.002.149 + +# Apple //gs versions + +0x4A9E8 0x2272 Kings Quest 1 (1.0S-88223) +0x5F4E8 0x2917 Mixed Up Mother Goose +0x7DB3F 0x2917 Police Quest 1 (2.0A) +0x93260 0x2917 Demo Disk 1.0C (Censored) # guessed interp vers +0x285FB 0x3149 Black Cauldron (1.0O) # 2.24.89 (CE) +0x4C705 0x3149 Manhunter New York # 2.0E 10/05/88 (CE) +0xAF778 0x3086 Kings Quest 4 # 1.0K 11/22/88 (CE) + +# Macintosh versions + +0x4C02C 0x2440 Kings Quest 1 (2.0C) +0x6382E 0x2440 Kings Quest 2 (2.0R) +0x78202 0x2440 Leisure Suit Larry 1 (1.05) # 6/26/87 +0x8DF84 0x2936 Space Quest 2 (2.0D) + +# Atari ST versions + +0x1A7AF 0x2272 Donald Duck's Playground (1.0C) # Aug 8 1986 + +# Amiga versions +# Use option "A" to enable padding + +0x5BCE6 0x2440 [A] Kings Quest 2 (2.0J) +0x8FEA6 0x2936 [A] Space Quest 2 (2.0F) +0x6FDDB 0x2440 [A] Leisure Suit Larry 1 (1.05) # 6/26/87 +0x4BA94 0x3149 [A] Manhunter New York (1.06) # 3/18/89 +0x6EFFB 0x3149 [A] Gold Rush! (2.05) # 2.316 3/09/89 + +# AGDS games +# Use option "a" for AGDS games + +0x5501A 0x2440 [a] Groza # AGDS sample game + +# Fan-made AGI games + +# End of sarien.conf diff --git a/sarien.lnk b/sarien.lnk index 039fce6..b175124 100644 --- a/sarien.lnk +++ b/sarien.lnk @@ -3,9 +3,9 @@ font.obj getopt.obj getopt1.obj global.obj graphics.obj hirespic.obj id.obj inv. keyboard.obj logic.obj lzw.obj main.obj menu.obj motion.obj objects.obj fileglob.obj + op_cmd.obj op_dbg.obj op_test.obj patches.obj path.obj picture.obj picview.obj rand.obj + savegame.obj silent.obj sound.obj sprite.obj text.obj view.obj words.obj + -dummy.obj nullvid.obj nothing.obj -sarien /NOE /NOI /NOD:OLDNAMES /NOD:LIBCRT /NOD:LIBGCC /STACK:384000 +dummy.obj nullvid.obj +sarien /NOE /NOI /NOD:OLDNAMES /STACK:256000 nul.map -libc.lib + -os2386.lib +..\..\lib2\libc.lib + +..\..\lib2\os2386.lib sarien.def; \ No newline at end of file diff --git a/silent.c b/silent.c index c6910ba..de0e5ef 100644 --- a/silent.c +++ b/silent.c @@ -1,36 +1,36 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka - * - * $Id: silent.c,v 1.8 2001/08/22 20:11:57 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include "sarien.h" -#include "agi.h" - -static int dummy_init_sound (SINT16 *); -static void dummy_close_sound (void); - -struct sound_driver sound_dummy = { - "Dummy sound driver", - dummy_init_sound, - dummy_close_sound -}; - - -static int dummy_init_sound (SINT16 *buffer) -{ - report ("sound_dummy: sound output disabled\n"); - return 0; -} - - -static void dummy_close_sound () -{ -} - - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka + * + * $Id: silent.c,v 1.8 2001/08/22 20:11:57 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include "sarien.h" +#include "agi.h" + +static int dummy_init_sound (SINT16 *); +static void dummy_close_sound (void); + +struct sound_driver sound_dummy = { + "Dummy sound driver", + dummy_init_sound, + dummy_close_sound +}; + + +static int dummy_init_sound (SINT16 *buffer) +{ + report ("sound_dummy: sound output disabled\n"); + return 0; +} + + +static void dummy_close_sound () +{ +} + + diff --git a/sound.c b/sound.c index 98936e3..aaceb33 100644 --- a/sound.c +++ b/sound.c @@ -1,591 +1,804 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2001, 2007 Stuart George and Claudio Matsuoka - * - * $Id: sound.c,v 1.31 2001/09/17 02:26:42 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include - -#ifdef __TURBOC__ -#include /* For sound(), nosound() */ -#endif - -#include "sarien.h" -#include "agi.h" -#include "rand.h" - -#define USE_INTERPOLATION -#define USE_CHORUS - - -/* TODO: add support for variable sampling rate in the output device - */ - -#ifdef USE_IIGS_SOUND - -/** - * Sarien sound envelope structure. - */ -struct sound_envelope { - UINT8 bp; - UINT8 inc_hi; - UINT8 inc_lo; -}; - -struct sound_wavelist { - UINT8 top; - UINT8 addr; - UINT8 size; - UINT8 mode; - UINT8 rel_hi; - UINT8 rel_lo; -}; - -struct sound_instrument { - struct sound_envelope env[8]; - UINT8 relseg; - UINT8 priority; - UINT8 bendrange; - UINT8 vibdepth; - UINT8 vibspeed; - UINT8 spare; - UINT8 wac; - UINT8 wbc; - struct sound_wavelist wal[8]; - struct sound_wavelist wbl[8]; -}; - -struct sound_iigs_sample { - UINT8 type_lo; - UINT8 type_hi; - UINT8 srate_lo; - UINT8 srate_hi; - UINT16 unknown[2]; - UINT8 size_lo; - UINT8 size_hi; - UINT16 unknown2[13]; -}; - -#if 0 -static struct sound_instrument *instruments; -static int num_instruments; -static UINT8 *wave; -#endif - -#endif - -static int playing; -static struct channel_info chn[NUM_CHANNELS]; -static int endflag = -1; -static int playing_sound = -1; -static UINT8 *song; -static UINT8 env; - -struct sound_driver *snd; - -extern struct sound_driver sound_dummy; - -static void stop_note(int i); -static void play_note(int i, int freq, int len, int vol); -static int freq_to_note(int freq); - -static int freq_to_note_table[128] = { // index -> note; value -> freq*1000 | last 3 digits are the fractional part (8175 => 8.175 Hz) - 8175, 8661, 9177, 9722, 10300, 10913, 11562, 12249, - 12978, 13750, 14567, 15433, 16351, 17323, 18354, 19445, - 20601, 21826, 23124, 24499, 25956, 27500, 29135, 30867, - 32703, 34647, 36708, 38890, 41203, 43653, 46249, 48999, - 51913, 55000, 58270, 61735, 65406, 69295, 73416, 77781, - 82406, 87307, 92498, 97998, 103826, 110000, 116540, 123470, - 130812, 138591, 146832, 155563, 164813, 174614, 184997, 195997, - 207652, 220000, 233081, 246941, 261625, 277182, 293664, 311126, - 329627, 349228, 369994, 391995, 415304, 440000, 466163, 493883, - 523251, 554365, 587329, 622253, 659255, 698456, 739988, 783990, - 830609, 880000, 932327, 987766, 1046502, 1108730, 1174659, 1244507, - 1318510, 1396912, 1479977, 1567981, 1661218, 1760000, 1864655, 1975533, - 2093004, 2217461, 2349318, 2489015, 2637020, 2793825, 2959955, 3135963, - 3322437, 3520000, 3729310, 3951066, 4186009, 4434922, 4698636, 4978031, - 5274040, 5587651, 5919910, 6271926, 6644875, 7040000, 7458620, 7902132, - 8372018, 8869844, 9397272, 9956063, 10548081, 11175303, 11839821, 12543853 -}; - -#ifdef USE_PCM_SOUND - -SINT16 *snd_buffer; -static SINT16 *waveform; - -static SINT16 waveform_ramp[WAVEFORM_SIZE] = { - 0, 8, 16, 24, 32, 40, 48, 56, - 64, 72, 80, 88, 96, 104, 112, 120, - 128, 136, 144, 152, 160, 168, 176, 184, - 192, 200, 208, 216, 224, 232, 240, 255, - 0,-248,-240,-232,-224,-216,-208,-200, - -192,-184,-176,-168,-160,-152,-144,-136, - -128,-120,-112,-104, -96, -88, -80, -72, - -64, -56, -48, -40, -32, -24, -16, -8 /* Ramp up */ -}; - -static SINT16 waveform_square[WAVEFORM_SIZE] = { - 255, 230, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 110, - -255,-230,-220,-220,-220,-220,-220,-220, - -220,-220,-220,-220,-220,-220,-220,-220, - -220,-220,-220,-220,-220,-220,-220,-220, - -220,-220,-220,-110, 0, 0, 0, 0 /* Square */ -}; - -static SINT16 waveform_mac[WAVEFORM_SIZE] = { - 45, 110, 135, 161, 167, 173, 175, 176, - 156, 137, 123, 110, 91, 72, 35, -2, - -60,-118,-142,-165,-170,-176,-177,-179, - -177,-176,-164,-152,-117, -82, -17, 47, - 92, 137, 151, 166, 170, 173, 171, 169, - 151, 133, 116, 100, 72, 43, -7, -57, - -99,-141,-156,-170,-174,-177,-178,-179, - -175,-172,-165,-159,-137,-114, -67, -19 -}; - -#endif /* USE_PCM_SOUND */ - - - -#ifdef USE_IIGS_SOUND - -static UINT16 period[] = { - 1024, 1085, 1149, 1218, 1290, 1367, - 1448, 1534, 1625, 1722, 1825, 1933 -}; - -static struct agi_note play_sample[] = { - { 0xff, 0x7f, 0x18, 0x00, 0x7f }, - { 0xff, 0xff, 0x00, 0x00, 0x00 }, - { 0xff, 0xff, 0x00, 0x00, 0x00 }, - { 0xff, 0xff, 0x00, 0x00, 0x00 } -}; - - -static int note_to_period (int note) -{ - return 10 * (period[note % 12] >> (note / 12 - 3)); -} - -#endif /* USE_IIGS_SOUND */ - - -void unload_sound (int resnum) -{ - if (game.dir_sound[resnum].flags & RES_LOADED) { - if (game.sounds[resnum].flags & SOUND_PLAYING) - /* FIXME: Stop playing */ - ; - - /* Release RAW data for sound */ - free (game.sounds[resnum].rdata); - game.sounds[resnum].rdata = NULL; - game.dir_sound[resnum].flags &= ~RES_LOADED; - } -} - - -void decode_sound (int resnum) -{ -#ifdef USE_IIGS_SOUND - int type, size; - SINT16 *buf; - UINT8 *src; - struct sound_iigs_sample *smp; - - _D ("(%d)", resnum); - type = lohi_getword (game.sounds[resnum].rdata); - - if (type == AGI_SOUND_SAMPLE) { - /* Convert sample data to 16 bit signed format - */ - smp = (struct sound_iigs_sample *)game.sounds[resnum].rdata; - size = ((int)smp->size_hi << 8) + smp->size_lo; - src = (UINT8 *)game.sounds[resnum].rdata; - buf = calloc (1, 54 + (size << 1) + 100); /* FIXME */ - memcpy (buf, src, 54); - for (; size--; buf[size + 54] = - ((SINT16)src[size + 54] - 0x80) << 4); /* FIXME */ - game.sounds[resnum].rdata = (UINT8 *)buf; - free (src); - } -#endif /* USE_IIGS_SOUND */ -} - - -void start_sound (int resnum, int flag) -{ - int i, type; -#ifdef USE_IIGS_SOUND - struct sound_iigs_sample *smp; -#endif - - if (game.sounds[resnum].flags & SOUND_PLAYING) - return; - - stop_sound (); - - if (game.sounds[resnum].rdata == NULL) - return; - - type = lohi_getword (game.sounds[resnum].rdata); - - if (type != AGI_SOUND_SAMPLE && - type != AGI_SOUND_MIDI && - type != AGI_SOUND_4CHN) - return; - - game.sounds[resnum].flags |= SOUND_PLAYING; - game.sounds[resnum].type = type; - playing_sound = resnum; - song = (UINT8 *)game.sounds[resnum].rdata; - - switch (type) { -#ifdef USE_IIGS_SOUND - case AGI_SOUND_SAMPLE: - _D (_D_WARN "IIGS sample"); - smp = (struct sound_iigs_sample *)game.sounds[resnum].rdata; - for (i = 0; i < NUM_CHANNELS; i++) { - chn[i].type = type; - chn[i].flags = 0; - chn[i].ins = (SINT16 *)&game.sounds[resnum].rdata[54]; - chn[i].size = ((int)smp->size_hi << 8) + smp->size_lo; - chn[i].ptr = &play_sample[i]; - chn[i].timer = 0; - chn[i].vol = 0; - chn[i].end = 0; - } - break; - case AGI_SOUND_MIDI: - _D (_D_WARN "IIGS MIDI sequence"); - - for (i = 0; i < NUM_CHANNELS; i++) { - chn[i].type = type; - chn[i].flags = AGI_SOUND_LOOP | AGI_SOUND_ENVELOPE; - chn[i].ins = waveform; - chn[i].size = WAVEFORM_SIZE; - chn[i].vol = 0; - chn[i].end = 0; - } - - chn[0].timer = *(song + 2); - chn[0].ptr = (struct agi_note *)(song + 3); - break; -#endif - case AGI_SOUND_4CHN: - /* Initialize channel info */ - for (i = 0; i < NUM_CHANNELS; i++) { - chn[i].type = type; - chn[i].flags = AGI_SOUND_LOOP; - if (env) { - chn[i].flags |= AGI_SOUND_ENVELOPE; - chn[i].adsr = AGI_SOUND_ENV_ATTACK; - } -#ifdef USE_PCM_SOUND - chn[i].ins = waveform; - chn[i].size = WAVEFORM_SIZE; -#endif - chn[i].ptr = (struct agi_note *)(song + - (song[i << 1] | (song[(i << 1) + 1] << 8))); - chn[i].timer = 0; - chn[i].vol = 0; - chn[i].end = 0; - } - break; - } - -#ifdef USE_PCM_SOUND - memset (snd_buffer, 0, BUFFER_SIZE << 1); -#endif - endflag = flag; - - /* Nat Budin reports that the flag should be reset when sound starts - */ - setflag (endflag, FALSE); - - /* FIXME: should wait for sound time instead of setting the flag - * immediately - */ - if (opt.nosound) { - setflag (endflag, TRUE); - stop_sound (); - } -} - - -void stop_sound () -{ - int i; - - endflag = -1; - for (i = 0; i < NUM_CHANNELS; i++) - stop_note (i); - - if (playing_sound != -1) { - game.sounds[playing_sound].flags &= ~SOUND_PLAYING; - playing_sound = -1; - } -} - - -int init_sound () -{ - int r = -1; - -#ifdef USE_PCM_SOUND - snd_buffer = calloc (2, BUFFER_SIZE); -#endif - - __init_sound (); - - env = FALSE; - -#ifdef USE_PCM_SOUND - switch (opt.soundemu) { - case SOUND_EMU_NONE: - waveform = waveform_ramp; - env = TRUE; - break; - case SOUND_EMU_AMIGA: - case SOUND_EMU_PC: - waveform = waveform_square; - break; - case SOUND_EMU_MAC: - waveform = waveform_mac; - break; - } -#endif - - report ("Initializing sound:\n"); - - if (opt.nosound) - snd = &sound_dummy; - -#ifdef USE_PCM_SOUND - if ((r = snd->init (snd_buffer)) != 0) { - snd = &sound_dummy; - opt.nosound = TRUE; - } -#endif - - report ("sound: %s configured\n", snd->description); - - report ("sound: envelopes "); - if (env) { - report ("enabled (decay=%d, sustain=%d)\n", - ENV_DECAY, ENV_SUSTAIN); - } else { - report ("disabled\n"); - } - -#ifdef USE_IIGS_SOUND - /*load_instruments ("demo.sys");*/ -#endif - - return r; -} - - -void deinit_sound (void) -{ - _D ("()"); - snd->deinit (); -#ifdef USE_PCM_SOUND - free (snd_buffer); -#endif -} - - -static void stop_note (int i) -{ - chn[i].adsr = AGI_SOUND_ENV_RELEASE; -} - - -static void play_note (int i, int freq, int len, int vol) -{ -if(i==0) - SendBeep(freq,len); -/* - chn[i].freq = freq; - chn[i].vol = vol; - chn[i].env = 0x10000; - chn[i].adsr = AGI_SOUND_ENV_ATTACK; -*/ -} - - -int freq_to_note(int freq) -{ - int d = 0; - int ld = 99999999; - int res = -1; - int i = 0; - for (i = 0; i < 128; i++) { - d = abs(freq_to_note_table[i] - (freq * 1000)); - if (d < ld) { - ld = d; - res = i; - } - } - - if (res == -1) { - res = 0; - } - else { - res = 127 - res + 35; - if (res > 127) - res = 127; - } - - return res; -} - - -#ifdef USE_IIGS_SOUND - -void play_midi_sound () -{ - UINT8 *p; - UINT8 parm1, parm2; - static UINT8 cmd, ch; - - playing = 1; - - if (chn[0].timer > 0) { - chn[0].timer -= 2; - return; - } - - p = (UINT8*)chn[0].ptr; - - if (*p & 0x80) { - cmd = *p++; - ch = cmd & 0x0f; - cmd >>= 4; - } - - switch (cmd) { - case 0x08: - parm1 = *p++; - parm2 = *p++; - if (ch < NUM_CHANNELS) - stop_note (ch); - break; - case 0x09: - parm1 = *p++; - parm2 = *p++; - if (ch < NUM_CHANNELS) - play_note (ch, note_to_period (parm1), 127); - break; - case 0x0b: - parm1 = *p++; - parm2 = *p++; - _D (_D_WARN "controller %02x, ch %02x, val %02x", - parm1, ch, parm2); - break; - case 0x0c: - parm1 = *p++; -#if 0 - if (ch < NUM_CHANNELS) { - chn[ch].ins = (UINT16 *)&wave[waveaddr[parm1]]; - chn[ch].size = wavesize[parm1]; - } - _D (_D_WARN "set patch %02x (%d,%d), ch %02x", - parm1, waveaddr[parm1], wavesize[parm1], ch); -#endif - break; - } - - chn[0].timer = *p++; - chn[0].ptr = (struct agi_note *)p; - - if (*p >= 0xfc) { - _D (_D_WARN "end of sequence"); - playing = 0; - return; - } -} - -void play_sample_sound () -{ - play_note (0, 11025 * 10, 200); - playing = 1; -} - -#endif /* USE_IIGS_SOUND */ - - -void play_agi_sound () -{ - int i, freq; - -// for (playing = i = 0; i < (opt.soundemu == SOUND_EMU_PC ? 1 : 4); i++) { - for (playing = i = 0; i < 4; i++) { - playing |= !chn[i].end; - - if (chn[i].end) - continue; - - if ((--chn[i].timer) <= 0) { - stop_note (i); - freq = ((chn[i].ptr->frq_0 & 0x3f) << 4) - | (int)(chn[i].ptr->frq_1 & 0x0f); - - chn[i].timer = (((int)chn[i].ptr->dur_hi << 8) | chn[i].ptr->dur_lo); - - if (freq) { - UINT8 v = chn[i].ptr->vol & 0x0f; - if (chn[i].timer == 0xffff) { - play_note (i, freq * 10, 300, v == 0xf ? 0 : 0xff - (v << 1)); - } - else { - play_note (i, freq * 10, (chn[i].timer / 3) * 50, v == 0xf ? 0 : 0xff - (v << 1)); - } - } - - if (chn[i].timer == 0xffff) { - chn[i].end = 1; - chn[i].vol = 0; - chn[i].env = 0; - } - - chn[i].timer = chn[i].timer * 10 / 28; - chn[i].ptr++; - } - } -} - - -void play_sound () -{ - int i; - - if (endflag == -1) - return; - - play_agi_sound (); - - if (!playing) { - for (i = 0; i < NUM_CHANNELS; chn[i++].vol = 0); - - if (endflag != -1) - setflag (endflag, TRUE); - - if (playing_sound != -1) - game.sounds[playing_sound].flags &= ~SOUND_PLAYING; - playing_sound = -1; - endflag = -1; - } -} - - - +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2001, 2007 Stuart George and Claudio Matsuoka + * + * $Id: sound.c,v 1.31 2001/09/17 02:26:42 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include + +#ifdef __TURBOC__ +#include /* For sound(), nosound() */ +#endif + +#include "sarien.h" +#include "agi.h" +#include "rand.h" + +#define USE_INTERPOLATION +#define USE_CHORUS + + +/* TODO: add support for variable sampling rate in the output device + */ + +#ifdef USE_IIGS_SOUND + +/** + * Sarien sound envelope structure. + */ +struct sound_envelope { + UINT8 bp; + UINT8 inc_hi; + UINT8 inc_lo; +}; + +struct sound_wavelist { + UINT8 top; + UINT8 addr; + UINT8 size; + UINT8 mode; + UINT8 rel_hi; + UINT8 rel_lo; +}; + +struct sound_instrument { + struct sound_envelope env[8]; + UINT8 relseg; + UINT8 priority; + UINT8 bendrange; + UINT8 vibdepth; + UINT8 vibspeed; + UINT8 spare; + UINT8 wac; + UINT8 wbc; + struct sound_wavelist wal[8]; + struct sound_wavelist wbl[8]; +}; + +struct sound_iigs_sample { + UINT8 type_lo; + UINT8 type_hi; + UINT8 srate_lo; + UINT8 srate_hi; + UINT16 unknown[2]; + UINT8 size_lo; + UINT8 size_hi; + UINT16 unknown2[13]; +}; + +#if 0 +static struct sound_instrument *instruments; +static int num_instruments; +static UINT8 *wave; +#endif + +#endif + +static int playing; +static struct channel_info chn[NUM_CHANNELS]; +static int endflag = -1; +static int playing_sound = -1; +static UINT8 *song; +static UINT8 env; + +struct sound_driver *snd; + +extern struct sound_driver sound_dummy; + +static void stop_note(int i); +static void play_note(int i, int freq, int len, int vol); +static int freq_to_note(int freq); + +static int freq_to_note_table[128] = { // index -> note; value -> freq*1000 | last 3 digits are the fractional part (8175 => 8.175 Hz) + 8175, 8661, 9177, 9722, 10300, 10913, 11562, 12249, + 12978, 13750, 14567, 15433, 16351, 17323, 18354, 19445, + 20601, 21826, 23124, 24499, 25956, 27500, 29135, 30867, + 32703, 34647, 36708, 38890, 41203, 43653, 46249, 48999, + 51913, 55000, 58270, 61735, 65406, 69295, 73416, 77781, + 82406, 87307, 92498, 97998, 103826, 110000, 116540, 123470, + 130812, 138591, 146832, 155563, 164813, 174614, 184997, 195997, + 207652, 220000, 233081, 246941, 261625, 277182, 293664, 311126, + 329627, 349228, 369994, 391995, 415304, 440000, 466163, 493883, + 523251, 554365, 587329, 622253, 659255, 698456, 739988, 783990, + 830609, 880000, 932327, 987766, 1046502, 1108730, 1174659, 1244507, + 1318510, 1396912, 1479977, 1567981, 1661218, 1760000, 1864655, 1975533, + 2093004, 2217461, 2349318, 2489015, 2637020, 2793825, 2959955, 3135963, + 3322437, 3520000, 3729310, 3951066, 4186009, 4434922, 4698636, 4978031, + 5274040, 5587651, 5919910, 6271926, 6644875, 7040000, 7458620, 7902132, + 8372018, 8869844, 9397272, 9956063, 10548081, 11175303, 11839821, 12543853 +}; + +#ifdef USE_PCM_SOUND + +SINT16 *snd_buffer; +static SINT16 *waveform; + +static SINT16 waveform_ramp[WAVEFORM_SIZE] = { + 0, 8, 16, 24, 32, 40, 48, 56, + 64, 72, 80, 88, 96, 104, 112, 120, + 128, 136, 144, 152, 160, 168, 176, 184, + 192, 200, 208, 216, 224, 232, 240, 255, + 0,-248,-240,-232,-224,-216,-208,-200, + -192,-184,-176,-168,-160,-152,-144,-136, + -128,-120,-112,-104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, -8 /* Ramp up */ +}; + +static SINT16 waveform_square[WAVEFORM_SIZE] = { + 255, 230, 220, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 220, 220, 110, + -255,-230,-220,-220,-220,-220,-220,-220, + -220,-220,-220,-220,-220,-220,-220,-220, + -220,-220,-220,-220,-220,-220,-220,-220, + -220,-220,-220,-110, 0, 0, 0, 0 /* Square */ +}; + +static SINT16 waveform_mac[WAVEFORM_SIZE] = { + 45, 110, 135, 161, 167, 173, 175, 176, + 156, 137, 123, 110, 91, 72, 35, -2, + -60,-118,-142,-165,-170,-176,-177,-179, + -177,-176,-164,-152,-117, -82, -17, 47, + 92, 137, 151, 166, 170, 173, 171, 169, + 151, 133, 116, 100, 72, 43, -7, -57, + -99,-141,-156,-170,-174,-177,-178,-179, + -175,-172,-165,-159,-137,-114, -67, -19 +}; + +#endif /* USE_PCM_SOUND */ + + + +#ifdef USE_IIGS_SOUND + +static UINT16 period[] = { + 1024, 1085, 1149, 1218, 1290, 1367, + 1448, 1534, 1625, 1722, 1825, 1933 +}; + +static struct agi_note play_sample[] = { + { 0xff, 0x7f, 0x18, 0x00, 0x7f }, + { 0xff, 0xff, 0x00, 0x00, 0x00 }, + { 0xff, 0xff, 0x00, 0x00, 0x00 }, + { 0xff, 0xff, 0x00, 0x00, 0x00 } +}; + + +static int note_to_period (int note) +{ + return 10 * (period[note % 12] >> (note / 12 - 3)); +} + +#endif /* USE_IIGS_SOUND */ + + +void unload_sound (int resnum) +{ + if (game.dir_sound[resnum].flags & RES_LOADED) { + if (game.sounds[resnum].flags & SOUND_PLAYING) + /* FIXME: Stop playing */ + ; + + /* Release RAW data for sound */ + free (game.sounds[resnum].rdata); + game.sounds[resnum].rdata = NULL; + game.dir_sound[resnum].flags &= ~RES_LOADED; + } +} + + +void decode_sound (int resnum) +{ +#ifdef USE_IIGS_SOUND + int type, size; + SINT16 *buf; + UINT8 *src; + struct sound_iigs_sample *smp; + + _D ("(%d)", resnum); + type = lohi_getword (game.sounds[resnum].rdata); + + if (type == AGI_SOUND_SAMPLE) { + /* Convert sample data to 16 bit signed format + */ + smp = (struct sound_iigs_sample *)game.sounds[resnum].rdata; + size = ((int)smp->size_hi << 8) + smp->size_lo; + src = (UINT8 *)game.sounds[resnum].rdata; + buf = calloc (1, 54 + (size << 1) + 100); /* FIXME */ + memcpy (buf, src, 54); + for (; size--; buf[size + 54] = + ((SINT16)src[size + 54] - 0x80) << 4); /* FIXME */ + game.sounds[resnum].rdata = (UINT8 *)buf; + free (src); + } +#endif /* USE_IIGS_SOUND */ +} + + +void start_sound (int resnum, int flag) +{ + int i, type; +#ifdef USE_IIGS_SOUND + struct sound_iigs_sample *smp; +#endif + + if (game.sounds[resnum].flags & SOUND_PLAYING) + return; + + stop_sound (); + + if (game.sounds[resnum].rdata == NULL) + return; + + type = lohi_getword (game.sounds[resnum].rdata); + + if (type != AGI_SOUND_SAMPLE && + type != AGI_SOUND_MIDI && + type != AGI_SOUND_4CHN) + return; + + game.sounds[resnum].flags |= SOUND_PLAYING; + game.sounds[resnum].type = type; + playing_sound = resnum; + song = (UINT8 *)game.sounds[resnum].rdata; + + switch (type) { +#ifdef USE_IIGS_SOUND + case AGI_SOUND_SAMPLE: + _D (_D_WARN "IIGS sample"); + smp = (struct sound_iigs_sample *)game.sounds[resnum].rdata; + for (i = 0; i < NUM_CHANNELS; i++) { + chn[i].type = type; + chn[i].flags = 0; + chn[i].ins = (SINT16 *)&game.sounds[resnum].rdata[54]; + chn[i].size = ((int)smp->size_hi << 8) + smp->size_lo; + chn[i].ptr = &play_sample[i]; + chn[i].timer = 0; + chn[i].vol = 0; + chn[i].end = 0; + } + break; + case AGI_SOUND_MIDI: + _D (_D_WARN "IIGS MIDI sequence"); + + for (i = 0; i < NUM_CHANNELS; i++) { + chn[i].type = type; + chn[i].flags = AGI_SOUND_LOOP | AGI_SOUND_ENVELOPE; + chn[i].ins = waveform; + chn[i].size = WAVEFORM_SIZE; + chn[i].vol = 0; + chn[i].end = 0; + } + + chn[0].timer = *(song + 2); + chn[0].ptr = (struct agi_note *)(song + 3); + break; +#endif + case AGI_SOUND_4CHN: + /* Initialize channel info */ + for (i = 0; i < NUM_CHANNELS; i++) { + chn[i].type = type; + chn[i].flags = AGI_SOUND_LOOP; + if (env) { + chn[i].flags |= AGI_SOUND_ENVELOPE; + chn[i].adsr = AGI_SOUND_ENV_ATTACK; + } +#ifdef USE_PCM_SOUND + chn[i].ins = waveform; + chn[i].size = WAVEFORM_SIZE; +#endif + chn[i].ptr = (struct agi_note *)(song + + (song[i << 1] | (song[(i << 1) + 1] << 8))); + chn[i].timer = 0; + chn[i].vol = 0; + chn[i].end = 0; + } + break; + } + +#ifdef USE_PCM_SOUND + memset (snd_buffer, 0, BUFFER_SIZE << 1); +#endif + endflag = flag; + + /* Nat Budin reports that the flag should be reset when sound starts + */ + setflag (endflag, FALSE); + + /* FIXME: should wait for sound time instead of setting the flag + * immediately + */ + if (opt.nosound) { + setflag (endflag, TRUE); + stop_sound (); + } +} + + +void stop_sound () +{ + int i; + + endflag = -1; + for (i = 0; i < NUM_CHANNELS; i++) + stop_note (i); + + if (playing_sound != -1) { + game.sounds[playing_sound].flags &= ~SOUND_PLAYING; + playing_sound = -1; + } +} + + +int init_sound () +{ + int r = -1; + +#ifdef USE_PCM_SOUND + snd_buffer = calloc (2, BUFFER_SIZE); +#endif + + __init_sound (); + + env = FALSE; + +#ifdef USE_PCM_SOUND + switch (opt.soundemu) { + case SOUND_EMU_NONE: + waveform = waveform_ramp; + env = TRUE; + break; + case SOUND_EMU_AMIGA: + case SOUND_EMU_PC: + waveform = waveform_square; + break; + case SOUND_EMU_MAC: + waveform = waveform_mac; + break; + } +#endif + + report ("Initializing sound:\n"); + + if (opt.nosound) + snd = &sound_dummy; + +#ifdef USE_PCM_SOUND + if ((r = snd->init (snd_buffer)) != 0) { + snd = &sound_dummy; + opt.nosound = TRUE; + } +#endif + + report ("sound: %s configured\n", snd->description); + + report ("sound: envelopes "); + if (env) { + report ("enabled (decay=%d, sustain=%d)\n", + ENV_DECAY, ENV_SUSTAIN); + } else { + report ("disabled\n"); + } + +#ifdef USE_IIGS_SOUND + /*load_instruments ("demo.sys");*/ +#endif + + return r; +} + + +void deinit_sound (void) +{ + _D ("()"); + snd->deinit (); +#ifdef USE_PCM_SOUND + free (snd_buffer); +#endif +} + + +static void stop_note (int i) +{ + chn[i].adsr = AGI_SOUND_ENV_RELEASE; +} + + +static void play_note (int i, int freq, int len, int vol) +{ + if (!getflag (F_sound_on)) + vol = 0; + else if (vol && opt.soundemu == SOUND_EMU_PC) + vol = 160; + +#ifdef USE_PCM_SOUND + chn[i].phase = 0; +#endif + + chn[i].freq = freq; + chn[i].vol = vol; + chn[i].env = 0x10000; + chn[i].adsr = AGI_SOUND_ENV_ATTACK; + +#ifdef CIBYL + if (i == 0) { + int exc = 0; + int note = freq_to_note(freq); + + NOPH_try(NOPH_setter_exception_handler, (void*)&exc) { + NOPH_Manager_playTone(note, len + 1, (vol * 100) / 255); + } NOPH_catch(); + if (exc) { + printf("playTone threw an exception: note %d, len %d, vol %d\n", + note, len, (vol * 100) / 255); + } + } +#endif +} + + +int freq_to_note(int freq) +{ + int d = 0; + int ld = 99999999; + int res = -1; + int i = 0; + for (i = 0; i < 128; i++) { + d = abs(freq_to_note_table[i] - (freq * 1000)); + if (d < ld) { + ld = d; + res = i; + } + } + + if (res == -1) { + res = 0; + } + else { + res = 127 - res + 35; + if (res > 127) + res = 127; + } + + return res; +} + + +#ifdef USE_IIGS_SOUND + +void play_midi_sound () +{ + UINT8 *p; + UINT8 parm1, parm2; + static UINT8 cmd, ch; + + playing = 1; + + if (chn[0].timer > 0) { + chn[0].timer -= 2; + return; + } + + p = (UINT8*)chn[0].ptr; + + if (*p & 0x80) { + cmd = *p++; + ch = cmd & 0x0f; + cmd >>= 4; + } + + switch (cmd) { + case 0x08: + parm1 = *p++; + parm2 = *p++; + if (ch < NUM_CHANNELS) + stop_note (ch); + break; + case 0x09: + parm1 = *p++; + parm2 = *p++; + if (ch < NUM_CHANNELS) + play_note (ch, note_to_period (parm1), 127); + break; + case 0x0b: + parm1 = *p++; + parm2 = *p++; + _D (_D_WARN "controller %02x, ch %02x, val %02x", + parm1, ch, parm2); + break; + case 0x0c: + parm1 = *p++; +#if 0 + if (ch < NUM_CHANNELS) { + chn[ch].ins = (UINT16 *)&wave[waveaddr[parm1]]; + chn[ch].size = wavesize[parm1]; + } + _D (_D_WARN "set patch %02x (%d,%d), ch %02x", + parm1, waveaddr[parm1], wavesize[parm1], ch); +#endif + break; + } + + chn[0].timer = *p++; + chn[0].ptr = (struct agi_note *)p; + + if (*p >= 0xfc) { + _D (_D_WARN "end of sequence"); + playing = 0; + return; + } +} + +void play_sample_sound () +{ + play_note (0, 11025 * 10, 200); + playing = 1; +} + +#endif /* USE_IIGS_SOUND */ + + +void play_agi_sound () +{ + int i, freq; + + for (playing = i = 0; i < (opt.soundemu == SOUND_EMU_PC ? 1 : 4); i++) { + playing |= !chn[i].end; + + if (chn[i].end) + continue; + + if ((--chn[i].timer) <= 0) { + stop_note (i); + freq = ((chn[i].ptr->frq_0 & 0x3f) << 4) + | (int)(chn[i].ptr->frq_1 & 0x0f); + + chn[i].timer = (((int)chn[i].ptr->dur_hi << 8) | chn[i].ptr->dur_lo); + + if (freq) { + UINT8 v = chn[i].ptr->vol & 0x0f; + if (chn[i].timer == 0xffff) { + play_note (i, freq * 10, 300, v == 0xf ? 0 : 0xff - (v << 1)); + } + else { + play_note (i, freq * 10, (chn[i].timer / 3) * 50, v == 0xf ? 0 : 0xff - (v << 1)); + } + } + + if (chn[i].timer == 0xffff) { + chn[i].end = 1; + chn[i].vol = 0; + chn[i].env = 0; + } + + chn[i].timer = chn[i].timer * 10 / 28; + chn[i].ptr++; + } + } +} + + +void play_sound () +{ + int i; + + if (endflag == -1) + return; + +#ifdef USE_IIGS_SOUND + if (chn[0].type == AGI_SOUND_MIDI) { + /* play_midi_sound (); */ + playing = 0; + } else if (chn[0].type == AGI_SOUND_SAMPLE) { + play_sample_sound (); + } else +#endif + play_agi_sound (); + + if (!playing) { + for (i = 0; i < NUM_CHANNELS; chn[i++].vol = 0); + + if (endflag != -1) + setflag (endflag, TRUE); + + if (playing_sound != -1) + game.sounds[playing_sound].flags &= ~SOUND_PLAYING; + playing_sound = -1; + endflag = -1; + } +} + + +#ifdef USE_PCM_SOUND + +UINT32 mix_sound (void) +{ + register int i, p; + SINT16 *src; + int c, b, m; + + memset (snd_buffer, 0, BUFFER_SIZE << 1); + + for (c = 0; c < NUM_CHANNELS; c++) { + if (!chn[c].vol) + continue; + + m = chn[c].flags & AGI_SOUND_ENVELOPE ? + chn[c].vol * chn[c].env >> 16 : + chn[c].vol; + + if (chn[c].type != AGI_SOUND_4CHN || c != 3) { + src = chn[c].ins; + + p = chn[c].phase; + for (i = 0; i < BUFFER_SIZE; i++) { + b = src[p >> 8]; +#ifdef USE_INTERPOLATION + b += ((src[((p >> 8) + 1) % chn[c].size] - + src[p >> 8]) * (p & 0xff)) >> 8; +#endif + snd_buffer[i] += (b * m) >> 4; + + p += (UINT32)118600 * 4 / chn[c].freq; + + /* FIXME */ + if (chn[c].flags & AGI_SOUND_LOOP) { + p %= chn[c].size << 8; + } else { + if (p >= chn[c].size << 8) { + p = chn[c].vol = 0; + chn[c].end = 1; + break; + } + } + + } + chn[c].phase = p; + } else { + /* Add white noise */ + for (i = 0; i < BUFFER_SIZE; i++) { + b = rnd(256) - 128; + snd_buffer[i] += (b * m) >> 4; + } + } + + switch (chn[c].adsr) { + case AGI_SOUND_ENV_ATTACK: + /* not implemented */ + chn[c].adsr = AGI_SOUND_ENV_DECAY; + break; + case AGI_SOUND_ENV_DECAY: + if (chn[c].env > chn[c].vol * ENV_SUSTAIN + ENV_DECAY) { + chn[c].env -= ENV_DECAY; + } else { + chn[c].env = chn[c].vol * ENV_SUSTAIN; + chn[c].adsr = AGI_SOUND_ENV_SUSTAIN; + } + break; + case AGI_SOUND_ENV_SUSTAIN: + break; + case AGI_SOUND_ENV_RELEASE: + if (chn[c].env >= ENV_RELEASE) { + chn[c].env -= ENV_RELEASE; + } else { + chn[c].env = 0; + } + } + } + + return BUFFER_SIZE; +} + + +#ifdef USE_IIGS_SOUND + +#if 0 +int load_instruments (char *fname) +{ + FILE *fp; + int i, j, k; + struct sound_instrument ai; + int num_wav; + char *path; + + path = fixpath (NO_GAMEDIR, "sierrast"); + + if ((fp = fopen (path, "rb")) == NULL) + return err_BadFileOpen; + report ("Loading samples: %s\n", path); + + if ((wave = malloc (0x10000 * 2)) == NULL) + return err_NotEnoughMemory; + + fread (wave, 0x10000, 1, fp); + fclose (fp); + for (i = 0x10000; i--; ) { + ((SINT16 *)wave)[i] = 2 * ((SINT16)wave[i] - 128); + } + +fp = fopen ("bla", "w"); +fwrite (wave, 2, 0x10000, fp); +fclose (fp); + + fixpath (NO_GAMEDIR, fname); + report ("Loading instruments: %s\n", path); + + if ((fp = fopen (path, "rb")) == NULL) + return err_BadFileOpen; + + fseek (fp, 0x8469, SEEK_SET); + +for (num_wav = j = 0; j < 40; j++) { + fread (&ai, 1, 32, fp); + + if (ai.env[0].bp > 0x7f) + break; + +#if 0 + printf ("Instrument %d loaded ----------------\n", j); + printf ("Envelope:\n"); + for (i = 0; i < 8; i++) + printf ("[seg %d]: BP %02x Inc %04x\n", + i, ai.env[i].bp, ((int)ai.env[i].inc_hi << 8) | + ai.env[i].inc_lo); + printf ("rel seg: %d, pri inc: %d, bend range: %d, vib dep: %d, " + "vib spd: %d\n", ai.relseg, ai.priority, ai.bendrange, + ai.vibdepth, ai.vibspeed); + printf ("A wave count: %d, B wave count: %d\n", ai.wac, ai.wbc); +#endif + + for (k = 0; k < ai.wac; k++, num_wav++) { + fread (&ai.wal[k], 1, 6, fp); +#if 0 + printf ("[A %d of %d] top: %02x, wave address: %02x, " + "size: %02x, mode: %02x, relPitch: %04x\n", + k + 1, ai.wac, ai.wal[k].top, ai.wal[k].addr, + ai.wal[k].size, ai.wal[k].mode, + ((int)ai.wal[k].rel_hi << 8) | ai.wal[k].rel_lo); +#endif + } + + for (k = 0; k < ai.wbc; k++, num_wav++) { + fread (&ai.wbl[k], 1, 6, fp); +#if 0 + printf ("[B %d of %d] top: %02x, wave address: %02x, " + "size: %02x, mode: %02x, relPitch: %04x\n", + k + 1, ai.wbc, ai.wbl[k].top, ai.wbl[k].addr, + ai.wbl[k].size, ai.wbl[k].mode, + ((int)ai.wbl[k].rel_hi << 8) | ai.wbl[k].rel_lo); +#endif + } + waveaddr[j] = 256 * ai.wal[0].addr; + wavesize[j] = 256 * (1 << ((ai.wal[0].size) & 0x07)); +#if 1 + printf ("%d addr = %d\n", j, waveaddr[j]); + printf (" size = %d\n", wavesize[j]); +#endif +} + + num_instruments = j; + printf ("%d Ensoniq 5503 instruments loaded. (%d waveforms)\n", + num_instruments, num_wav); + + fclose(fp); + + return err_OK; +} + + +void unload_instruments () +{ + free (instruments); +} +#endif + +#endif /* USE_IIGS_SOUND */ + +#endif /* USE_PCM_SOUND */ + diff --git a/sprite.c b/sprite.c index 26ffbf5..cbcd7f5 100644 --- a/sprite.c +++ b/sprite.c @@ -1,907 +1,907 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: sprite.c,v 1.84 2003/10/12 17:39:36 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include /* for memcpy() */ -#include "sarien.h" -#include "list.h" -#include "agi.h" -#include "sprite.h" -#include "graphics.h" -#include "text.h" -#include "savegame.h" - -/** - * Sprite structure. - * This structure holds information on visible and priority data of - * a rectangular area of the AGI screen. Sprites are chained in two - * circular lists, one for updating and other for non-updating sprites. - */ -struct sprite { - struct list_head list; - struct vt_entry *v; /**< pointer to view table entry */ - SINT16 x_pos; /**< x coordinate of the sprite */ - SINT16 y_pos; /**< y coordinate of the sprite */ - SINT16 x_size; /**< width of the sprite */ - SINT16 y_size; /**< height of the sprite */ - UINT8 *buffer; /**< buffer to store background data */ -#ifdef USE_HIRES - UINT8 *hires; /**< buffer for hi-res background */ -#endif -}; - - -/* - * Sprite pool replaces dynamic allocation - */ -#undef ALLOC_DEBUG - -#ifdef USE_HIRES -# ifndef __TURBOC__ -# define POOL_SIZE 68000 /* Gold Rush mine room needs > 50000 */ - /* Speeder bike challenge needs > 67000 */ -# else -# define POOL_SIZE 32000 /* Can't afford that much in Turbo C! */ -# endif -#else -# define POOL_SIZE 25000 -#endif -static UINT8 *sprite_pool; -static UINT8 *pool_top; - -#ifdef ALLOC_DEBUG -#include -static int max_alloc = 0; -#endif - -static void *pool_alloc (int size) -{ - UINT8 *x; - - /* Adjust size to 32-bit boundary to prevent data misalignment - * errors. - */ - size = (size + 3) & ~3; - - x = pool_top; - pool_top += size; - -#ifdef ALLOC_DEBUG - if ((int)(pool_top - (UINT8 *)sprite_pool) > max_alloc) - max_alloc = (int)(pool_top - (UINT8 *)sprite_pool); - - printf ("pool_alloc: %d bytes @ %d (used memory: %d, max: %d)\n", - size, (x - (UINT8 *)sprite_pool), - (int)(pool_top - (UINT8 *)sprite_pool), max_alloc); -#endif - - if (pool_top >= (UINT8 *)sprite_pool + POOL_SIZE) { - _D (_D_CRIT "not enough memory"); - pool_top = x; - return NULL; - } - - return x; -} - -static void pool_release (void *s) -{ -#ifdef ALLOC_DEBUG - printf ("pool_release: %d\n", (int)(s - (void *)sprite_pool)); - if (s >= (void *)pool_top) { - printf ("s = %d\n", (int)(s - (void *)sprite_pool)); - printf ("top = %d\n", (int)(pool_top - (UINT8 *)sprite_pool)); - abort (); - } -#endif - pool_top = s; -} - - -/* - * Blitter functions - */ - -/* Blit one pixel considering the priorities */ - -static void -blit_pixel (UINT8 *p, UINT8 *end, UINT8 col, int spr, int width, int *hidden) -{ - int epr, pr; /* effective and real priorities */ - - /* CM: priority 15 overrides control lines and is ignored when - * tracking effective priority. This tweak is needed to fix - * bug #451768, and should not affect Sierra games because - * sprites shouldn't have priority 15 (like the AGI Mouse - * demo "mouse pointer") - * - * Update: this solution breaks other games, and can't be used. - */ - - if (p >= end) - return; - - /* Check if we're on a control line */ - if ((pr = *p & 0xf0) < 0x30) { - UINT8 *p1; - /* Yes, get effective priority going down */ - for (p1 = p; p1 < end && (epr = *p1 & 0xf0) < 0x30; p1 += width); - if (p1 >= end) - epr = 0x40; - } else { - epr = pr; - } - - if (spr >= epr) { - /* Keep control line information visible, but put our - * priority over water (0x30) surface - */ - *p = (pr < 0x30 ? pr : spr) | col; - *hidden = FALSE; - - /* Except if our priority is 15, which should never happen - * (fixes bug #451768) - * - * Update: breaks other games, can't be used - * - * if (spr == 0xf0) - * *p = spr | col; - */ - } -} - -#ifdef USE_HIRES - -#define X_FACT 2 /* Horizontal hires factor */ - -static int blit_hires_cel (int x, int y, int spr, struct view_cel *c) -{ - UINT8 *q = NULL; - UINT8 *h0, *h, *end; - int i, j, t, m, col; - int hidden = TRUE; - - q = c->data; - t = c->transparency; - m = c->mirror; - spr <<= 4; - h0 = &game.hires[(x + y * _WIDTH + m * (c->width - 1)) * X_FACT]; - - end = game.hires + _WIDTH * X_FACT * _HEIGHT; - - for (i = 0; i < c->height; i++) { - h = h0; - while (*q) { - col = (*q & 0xf0) >> 4; - for (j = *q & 0x0f; j; j--, h += X_FACT * (1 - 2 * m)) { - if (col != t) { - blit_pixel (h, end, col, spr, - _WIDTH * X_FACT, &hidden); - blit_pixel (h + 1, end, col, spr, - _WIDTH * X_FACT, &hidden); - } - } - q++; - } - h0 += _WIDTH * X_FACT; - q++; - } - return hidden; -} - -#endif - -static int blit_cel (int x, int y, int spr, struct view_cel *c) -{ - UINT8 *p0, *p, *q = NULL, *end; - int i, j, t, m, col; - int hidden = TRUE; - - /* Fixes bug #477841 (crash in PQ1 map C4 when y == -2) */ - if (y < 0) y = 0; - if (x < 0) x = 0; - if (y >= _HEIGHT) y = _HEIGHT - 1; - if (x >= _WIDTH) x = _WIDTH - 1; - -#ifdef USE_HIRES - if (opt.hires) - blit_hires_cel (x, y, spr, c); -#endif - - q = c->data; - t = c->transparency; - m = c->mirror; - spr <<= 4; - p0 = &game.sbuf[x + y * _WIDTH + m * (c->width - 1)]; - - end = game.sbuf + _WIDTH * _HEIGHT; - - for (i = 0; i < c->height; i++) { - p = p0; - while (*q) { - col = (*q & 0xf0) >> 4; - for (j = *q & 0x0f; j; j--, p += 1 - 2 * m) { - if (col != t) { - blit_pixel (p, end, col, spr, - _WIDTH, &hidden); - } - } - q++; - } - p0 += _WIDTH; - q++; - } - - return hidden; -} - -static void objs_savearea (struct sprite *s) -{ - int y; - SINT16 x_pos = s->x_pos, y_pos = s->y_pos; - SINT16 x_size = s->x_size, y_size = s->y_size; - UINT8 *p0, *q; -#ifdef USE_HIRES - UINT8 *h0, *k; -#endif - - if (x_pos + x_size > _WIDTH) - x_size = _WIDTH-x_pos; - - if (x_pos < 0) { - x_size += x_pos; - x_pos = 0; - } - - if (y_pos + y_size > _HEIGHT) - y_size = _HEIGHT-y_pos; - - if (y_pos < 0) { - y_size += y_pos; - y_pos = 0; - } - - if (x_size <= 0 || y_size <= 0) - return; - - p0 = &game.sbuf[x_pos + y_pos * _WIDTH]; - q = s->buffer; -#ifdef USE_HIRES - h0 = &game.hires[(x_pos + y_pos * _WIDTH) * 2]; - k = s->hires; -#endif - for (y = 0; y < y_size; y++) { - memcpy (q, p0, x_size); - q += x_size; - p0 += _WIDTH; -#ifdef USE_HIRES - memcpy (k, h0, x_size * 2); - k += x_size * 2; - h0 += _WIDTH * 2; -#endif - } -} - -static void objs_restorearea (struct sprite *s) -{ - int y, offset; - SINT16 x_pos = s->x_pos, y_pos = s->y_pos; - SINT16 x_size = s->x_size, y_size = s->y_size; - UINT8 *p0, *q; -#ifdef USE_HIRES - UINT8 *h0, *k; -#endif - - if (x_pos + x_size > _WIDTH) - x_size = _WIDTH - x_pos; - - if (x_pos < 0) { - x_size += x_pos; - x_pos = 0; - } - - if (y_pos + y_size > _HEIGHT) - y_size = _HEIGHT-y_pos; - - if (y_pos < 0) { - y_size += y_pos; - y_pos = 0; - } - - if (x_size <= 0 || y_size <= 0) - return; - - p0 = &game.sbuf[x_pos + y_pos * _WIDTH]; - q = s->buffer; -#ifdef USE_HIRES - h0 = &game.hires[(x_pos + y_pos * _WIDTH) * 2]; - k = s->hires; -#endif - offset = game.line_min_print * CHAR_LINES; - for (y = 0; y < y_size; y++) { - memcpy (p0, q, x_size); - put_pixels_a (x_pos, y_pos + y + offset, x_size, p0); - q += x_size; - p0 += _WIDTH; -#ifdef USE_HIRES - memcpy (h0, k, x_size * 2); - if (opt.hires) { - put_pixels_hires (x_pos * 2, - y_pos + y + offset, x_size * 2, h0); - } - k += x_size * 2; - h0 += _WIDTH * 2; -#endif - } -} - - -/* - * Sprite management functions - */ - -static LIST_HEAD(spr_upd_head); -static LIST_HEAD(spr_nonupd_head); - -/** - * Condition to determine whether a sprite will be in the 'updating' list. - */ -static int test_updating (struct vt_entry *v) -{ - /* Sanity check (see bug #779302) */ - if (~game.dir_view[v->current_view].flags & RES_LOADED) - return 0; - - return (v->flags & (ANIMATED|UPDATE|DRAWN)) == - (ANIMATED|UPDATE|DRAWN); -} - -/** - * Condition to determine whether a sprite will be in the 'non-updating' list. - */ -static int test_not_updating (struct vt_entry *v) -{ - /* Sanity check (see bug #779302) */ - if (~game.dir_view[v->current_view].flags & RES_LOADED) - return 0; - - return (v->flags & (ANIMATED|UPDATE|DRAWN)) == (ANIMATED|DRAWN); -} - -/** - * Convert sprite priority to y value. - */ -static INLINE int prio_to_y (int p) -{ - int i; - - if (p == 0) - return -1; - - for (i = 167; i >= 0; i--) { - if (game.pri_table[i] < p) - return i; - } - - return -1; /* (p - 5) * 12 + 48; */ -} - -/** - * Create and initialize a new sprite structure. - */ -static struct sprite *new_sprite (struct vt_entry *v) -{ - struct sprite *s; - - s = (struct sprite *)pool_alloc (sizeof (struct sprite)); - if (s == NULL) - return NULL; - - s->v = v; /* link sprite to associated view table entry */ - s->x_pos = v->x_pos; - s->y_pos = v->y_pos - v->y_size + 1; - s->x_size = v->x_size; - s->y_size = v->y_size; - s->buffer = pool_alloc (s->x_size * s->y_size); -#ifdef USE_HIRES - s->hires = pool_alloc (s->x_size * s->y_size * 2); -#endif - v->s = s; /* link view table entry to this sprite */ - - return s; -} - -/** - * Insert sprite in the specified sprite list. - */ -static void spr_addlist (struct list_head *head, struct vt_entry *v) -{ - struct sprite *s; - - s = new_sprite (v); - list_add_tail (&s->list, head); -} - -/** - * Sort sprites from lower y values to build a sprite list. - */ -static struct list_head * -build_list (struct list_head *head, int (*test)(struct vt_entry *)) -{ - int i, j, k; - struct vt_entry *v; - struct vt_entry *entry[0x100]; - int y_val[0x100]; - int min_y = 0xff, min_index = 0; - - /* fill the arrays with all sprites that satisfy the 'test' - * condition and their y values - */ - i = 0; - for_each_vt_entry(v) { - if (test (v)) { - entry[i] = v; - y_val[i] = v->flags & FIXED_PRIORITY ? - prio_to_y (v->priority) : v->y_pos; - i++; - } - } - - /* now look for the smallest y value in the array and put that - * sprite in the list - */ - for (j = 0; j < i; j++) { - min_y = 0xff; - for (k = 0; k < i; k++) { - if (y_val[k] < min_y) { - min_index = k; - min_y = y_val[k]; - } - } - - y_val[min_index] = 0xff; - spr_addlist (head, entry[min_index]); - } - - return head; -} - -/** - * Build list of updating sprites. - */ -static struct list_head *build_upd_blitlist () -{ - return build_list (&spr_upd_head, test_updating); -} - -/** - * Build list of non-updating sprites. - */ -static struct list_head *build_nonupd_blitlist () -{ - return build_list (&spr_nonupd_head, test_not_updating); -} - -/** - * Clear the given sprite list. - */ -static void free_list (struct list_head *head) -{ - struct list_head *h; - struct sprite *s; - - list_for_each (h, head, prev) { - s = list_entry (h, struct sprite, list); - list_del (h); -#ifdef USE_HIRES - pool_release (s->hires); -#endif - pool_release (s->buffer); - pool_release (s); - } -} - -/** - * Copy sprites from the pic buffer to the screen buffer, and check if - * sprites of the given list have moved. - */ -static void commit_sprites (struct list_head *head) -{ - struct list_head *h; - - list_for_each (h, head, next) { - struct sprite *s = list_entry (h, struct sprite, list); - int x1, y1, x2, y2, w, h; - - w = (s->v->cel_data->width > s->v->cel_data_2->width) ? - s->v->cel_data->width : s->v->cel_data_2->width; - - h = (s->v->cel_data->height > s->v->cel_data_2->height) ? - s->v->cel_data->height : s->v->cel_data_2->height; - - s->v->cel_data_2 = s->v->cel_data; - - if (s->v->x_pos < s->v->x_pos2) { - x1 = s->v->x_pos; - x2 = s->v->x_pos2 + w - 1; - } else { - x1 = s->v->x_pos2; - x2 = s->v->x_pos + w - 1; - } - - if (s->v->y_pos < s->v->y_pos2) { - y1 = s->v->y_pos - h + 1; - y2 = s->v->y_pos2; - } else { - y1 = s->v->y_pos2 - h + 1; - y2 = s->v->y_pos; - } - - commit_block (x1, y1, x2, y2); - - if (s->v->step_time_count != s->v->step_time) - continue; - - if (s->v->x_pos == s->v->x_pos2 && s->v->y_pos == s->v->y_pos2){ - s->v->flags |= DIDNT_MOVE; - continue; - } - - s->v->x_pos2 = s->v->x_pos; - s->v->y_pos2 = s->v->y_pos; - s->v->flags &= ~DIDNT_MOVE; - } - -#ifdef USE_CONSOLE - if (debug.statusline) - write_status (); -#endif -} - -/** - * Erase all sprites in the given list. - */ -static void erase_sprites (struct list_head *head) -{ - struct list_head *h; - - list_for_each (h, head, prev) { - struct sprite *s = list_entry (h, struct sprite, list); - objs_restorearea (s); - } - - free_list (head); -} - -/** - * Blit all sprites in the given list. - */ -static void blit_sprites (struct list_head *head) -{ - struct list_head *h = NULL; - int hidden; - - list_for_each (h, head, next) { - struct sprite *s = list_entry (h, struct sprite, list); - objs_savearea (s); - /* _D ("s->v->entry = %d (prio %d)", s->v->entry, - s->v->priority); */ - hidden = blit_cel (s->x_pos, s->y_pos, s->v->priority, - s->v->cel_data); - if (s->v->entry == 0) { /* if ego, update f1 */ - setflag (F_ego_invisible, hidden); - } - } -} - - -/* - * Public functions - */ - -void commit_upd_sprites () -{ - commit_sprites (&spr_upd_head); -} - -void commit_nonupd_sprites () -{ - commit_sprites (&spr_nonupd_head); -} - -/* check moves in both lists */ -void commit_both () -{ - commit_upd_sprites (); - commit_nonupd_sprites (); -} - -/** - * Erase updating sprites. - * This function follows the list of all updating sprites and restores - * the visible and priority data of their background buffers back to - * the AGI screen. - * - * @see erase_nonupd_sprites() - * @see erase_both() - */ -void erase_upd_sprites () -{ - erase_sprites (&spr_upd_head); -} - -/** - * Erase non-updating sprites. - * This function follows the list of all non-updating sprites and restores - * the visible and priority data of their background buffers back to - * the AGI screen. - * - * @see erase_upd_sprites() - * @see erase_both() - */ -void erase_nonupd_sprites () -{ - erase_sprites (&spr_nonupd_head); -} - -/** - * Erase all sprites. - * This function follows the lists of all updating and non-updating - * sprites and restores the visible and priority data of their background - * buffers back to the AGI screen. - * - * @see erase_upd_sprites() - * @see erase_nonupd_sprites() - */ -void erase_both () -{ - erase_upd_sprites (); - erase_nonupd_sprites (); -} - -/** - * Blit updating sprites. - * This function follows the list of all updating sprites and blits - * them on the AGI screen. - * - * @see blit_nonupd_sprites() - * @see blit_both() - */ -void blit_upd_sprites () -{ - /* _D("blit updating"); */ - blit_sprites (build_upd_blitlist ()); -} - -/** - * Blit non-updating sprites. - * This function follows the list of all non-updating sprites and blits - * them on the AGI screen. - * - * @see blit_upd_sprites() - * @see blit_both() - */ -void blit_nonupd_sprites () -{ - /* _D("blit non-updating"); */ - blit_sprites (build_nonupd_blitlist ()); -} - -/** - * Blit all sprites. - * This function follows the lists of all updating and non-updating - * sprites and blits them on the AGI screen. - * - * @see blit_upd_sprites() - * @see blit_nonupd_sprites() - */ -void blit_both () -{ - blit_nonupd_sprites (); - blit_upd_sprites (); -} - -/** - * Add view to picture. - * This function is used to implement the add.to.pic AGI command. It - * copies the specified cel from a view resource on the current picture. - * This cel is not a sprite, it can't be moved or removed. - * @param view number of view resource - * @param loop number of loop in the specified view resource - * @param cel number of cel in the specified loop - * @param x x coordinate to place the view - * @param y y coordinate to place the view - * @param pri priority to use - * @param mar if < 4, create a margin around the the base of the cel - */ -void add_to_pic (int view, int loop, int cel, int x, int y, int pri, int mar) -{ - struct view_cel *c = NULL; - int x1, y1, x2, y2, y3; - UINT8 *p1, *p2; - - _D ("v=%d, l=%d, c=%d, x=%d, y=%d, p=%d, m=%d", - view, loop, cel, x, y, pri, mar); - - record_image_stack_call(ADD_VIEW, view, loop, cel, x, y, pri, mar); - - /* - * Was hardcoded to 8, changed to pri_table[y] to fix Gold - * Rush (see bug #587558) - */ - if (pri == 0) - pri = game.pri_table[y]; - - c = &game.views[view].loop[loop].cel[cel]; - - x1 = x; - y1 = y - c->height + 1; - x2 = x + c->width - 1; - y2 = y; - - if (x1 < 0) { - x2 -= x1; - x1 = 0; - } - if (y1 < 0) { - y2 -= y1; - y1 = 0; - } - if (x2 >= _WIDTH) x2 = _WIDTH - 1; - if (y2 >= _HEIGHT) y2 = _HEIGHT - 1; - - erase_both (); - - _D (_D_WARN "blit_cel (%d, %d, %d, c)", x, y, pri); - blit_cel (x1, y1, pri, c); - - /* If margin is 0, 1, 2, or 3, the base of the cel is - * surrounded with a rectangle of the corresponding priority. - * If margin >= 4, this extra margin is not shown. - */ - if (mar < 4) { - /* add rectangle around object, don't clobber control - * info in priority data. The box extends to the end of - * its priority band! - * - * SQ1 needs +1 (see bug #810331) - */ - y3 = (y2 / 12) * 12 + 1; - - p1 = &game.sbuf[x1 + y3 * _WIDTH]; - p2 = &game.sbuf[x2 + y3 * _WIDTH]; - - for (y = y3; y <= y2; y++) { - if ((*p1 >> 4) >= 4) *p1 = (mar << 4) | (*p1 & 0x0f); - if ((*p2 >> 4) >= 4) *p2 = (mar << 4) | (*p2 & 0x0f); - p1 += _WIDTH; - p2 += _WIDTH; - } - - _D (_D_WARN "pri box: %d %d %d %d (%d)", x1, y3, x2, y2, mar); - p1 = &game.sbuf[x1 + y3 * _WIDTH]; - p2 = &game.sbuf[x1 + y2 * _WIDTH]; - for (x = x1; x <= x2; x++) { - if ((*p1 >> 4) >= 4) *p1 = (mar << 4) | (*p1 & 0x0f); - if ((*p2 >> 4) >= 4) *p2 = (mar << 4) | (*p2 & 0x0f); - p1++; - p2++; - } - } - - blit_both (); - - _D (_D_WARN "commit_block (%d, %d, %d, %d)", x1, y1, x2, y2); - commit_block (x1, y1, x2, y2); -} - -/** - * Show object and description - * This function shows an object from the player's inventory, displaying - * a message box with the object description. - * @param n Number of the object to show - */ -void show_obj (n) -{ - struct view_cel *c; - struct sprite s; - int x1, y1, x2, y2; - - agi_load_resource (rVIEW, n); - if (!(c = &game.views[n].loop[0].cel[0])) - return; - - x1 = (_WIDTH - c->width) / 2; - y1 = 112; - x2 = x1 + c->width - 1; - y2 = y1 + c->height - 1; - - s.x_pos = x1; - s.y_pos = y1; - s.x_size = c->width; - s.y_size = c->height; - s.buffer = malloc (s.x_size * s.y_size); -#ifdef USE_HIRES - s.hires = malloc (s.x_size * s.y_size * 2); -#endif - - objs_savearea (&s); - blit_cel (x1, y1, s.x_size, c); - commit_block (x1, y1, x2, y2); - message_box (game.views[n].descr); - objs_restorearea (&s); - commit_block (x1, y1, x2, y2); - - free (s.buffer); - - /* Added to fix a memory leak --Vasyl */ -#ifdef USE_HIRES - free(s.hires); -#endif -} - -void commit_block (int x1, int y1, int x2, int y2) -{ - int i, w, offset; - UINT8 *q; -#ifdef USE_HIRES - UINT8 *h; -#endif - - if (!game.picture_shown) - return; - - /* Clipping */ - if (x1 < 0) x1 = 0; - if (x2 < 0) x2 = 0; - if (y1 < 0) y1 = 0; - if (y2 < 0) y2 = 0; - if (x1 >= _WIDTH) x1 = _WIDTH - 1; - if (x2 >= _WIDTH) x2 = _WIDTH - 1; - if (y1 >= _HEIGHT) y1 = _HEIGHT - 1; - if (y2 >= _HEIGHT) y2 = _HEIGHT - 1; - - /* _D ("%d, %d, %d, %d", x1, y1, x2, y2); */ - - w = x2 - x1 + 1; - q = &game.sbuf[x1 + _WIDTH * y1]; -#ifdef USE_HIRES - h = &game.hires[(x1 + _WIDTH * y1) * 2]; -#endif - offset = game.line_min_print * CHAR_LINES; - for (i = y1; i <= y2; i++) { - put_pixels_a (x1, i + offset, w, q); - q += _WIDTH; -#ifdef USE_HIRES - if (opt.hires) { - put_pixels_hires (x1 * 2, i + offset, w * 2, h); - } - h += _WIDTH * 2; -#endif - } - - flush_block_a (x1, y1 + offset, x2, y2 + offset); -} - -int init_sprites () -{ - if ((sprite_pool = malloc (POOL_SIZE)) == NULL) - return err_NotEnoughMemory; - - pool_top = sprite_pool; - - return err_OK; -} - -void deinit_sprites () -{ - free (sprite_pool); -} - -/* end: sprite.c */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: sprite.c,v 1.84 2003/10/12 17:39:36 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include /* for memcpy() */ +#include "sarien.h" +#include "list.h" +#include "agi.h" +#include "sprite.h" +#include "graphics.h" +#include "text.h" +#include "savegame.h" + +/** + * Sprite structure. + * This structure holds information on visible and priority data of + * a rectangular area of the AGI screen. Sprites are chained in two + * circular lists, one for updating and other for non-updating sprites. + */ +struct sprite { + struct list_head list; + struct vt_entry *v; /**< pointer to view table entry */ + SINT16 x_pos; /**< x coordinate of the sprite */ + SINT16 y_pos; /**< y coordinate of the sprite */ + SINT16 x_size; /**< width of the sprite */ + SINT16 y_size; /**< height of the sprite */ + UINT8 *buffer; /**< buffer to store background data */ +#ifdef USE_HIRES + UINT8 *hires; /**< buffer for hi-res background */ +#endif +}; + + +/* + * Sprite pool replaces dynamic allocation + */ +#undef ALLOC_DEBUG + +#ifdef USE_HIRES +# ifndef __TURBOC__ +# define POOL_SIZE 68000 /* Gold Rush mine room needs > 50000 */ + /* Speeder bike challenge needs > 67000 */ +# else +# define POOL_SIZE 32000 /* Can't afford that much in Turbo C! */ +# endif +#else +# define POOL_SIZE 25000 +#endif +static UINT8 *sprite_pool; +static UINT8 *pool_top; + +#ifdef ALLOC_DEBUG +#include +static int max_alloc = 0; +#endif + +static void *pool_alloc (int size) +{ + UINT8 *x; + + /* Adjust size to 32-bit boundary to prevent data misalignment + * errors. + */ + size = (size + 3) & ~3; + + x = pool_top; + pool_top += size; + +#ifdef ALLOC_DEBUG + if ((int)(pool_top - (UINT8 *)sprite_pool) > max_alloc) + max_alloc = (int)(pool_top - (UINT8 *)sprite_pool); + + printf ("pool_alloc: %d bytes @ %d (used memory: %d, max: %d)\n", + size, (x - (UINT8 *)sprite_pool), + (int)(pool_top - (UINT8 *)sprite_pool), max_alloc); +#endif + + if (pool_top >= (UINT8 *)sprite_pool + POOL_SIZE) { + _D (_D_CRIT "not enough memory"); + pool_top = x; + return NULL; + } + + return x; +} + +static void pool_release (void *s) +{ +#ifdef ALLOC_DEBUG + printf ("pool_release: %d\n", (int)(s - (void *)sprite_pool)); + if (s >= (void *)pool_top) { + printf ("s = %d\n", (int)(s - (void *)sprite_pool)); + printf ("top = %d\n", (int)(pool_top - (UINT8 *)sprite_pool)); + abort (); + } +#endif + pool_top = s; +} + + +/* + * Blitter functions + */ + +/* Blit one pixel considering the priorities */ + +static void +blit_pixel (UINT8 *p, UINT8 *end, UINT8 col, int spr, int width, int *hidden) +{ + int epr, pr; /* effective and real priorities */ + + /* CM: priority 15 overrides control lines and is ignored when + * tracking effective priority. This tweak is needed to fix + * bug #451768, and should not affect Sierra games because + * sprites shouldn't have priority 15 (like the AGI Mouse + * demo "mouse pointer") + * + * Update: this solution breaks other games, and can't be used. + */ + + if (p >= end) + return; + + /* Check if we're on a control line */ + if ((pr = *p & 0xf0) < 0x30) { + UINT8 *p1; + /* Yes, get effective priority going down */ + for (p1 = p; p1 < end && (epr = *p1 & 0xf0) < 0x30; p1 += width); + if (p1 >= end) + epr = 0x40; + } else { + epr = pr; + } + + if (spr >= epr) { + /* Keep control line information visible, but put our + * priority over water (0x30) surface + */ + *p = (pr < 0x30 ? pr : spr) | col; + *hidden = FALSE; + + /* Except if our priority is 15, which should never happen + * (fixes bug #451768) + * + * Update: breaks other games, can't be used + * + * if (spr == 0xf0) + * *p = spr | col; + */ + } +} + +#ifdef USE_HIRES + +#define X_FACT 2 /* Horizontal hires factor */ + +static int blit_hires_cel (int x, int y, int spr, struct view_cel *c) +{ + UINT8 *q = NULL; + UINT8 *h0, *h, *end; + int i, j, t, m, col; + int hidden = TRUE; + + q = c->data; + t = c->transparency; + m = c->mirror; + spr <<= 4; + h0 = &game.hires[(x + y * _WIDTH + m * (c->width - 1)) * X_FACT]; + + end = game.hires + _WIDTH * X_FACT * _HEIGHT; + + for (i = 0; i < c->height; i++) { + h = h0; + while (*q) { + col = (*q & 0xf0) >> 4; + for (j = *q & 0x0f; j; j--, h += X_FACT * (1 - 2 * m)) { + if (col != t) { + blit_pixel (h, end, col, spr, + _WIDTH * X_FACT, &hidden); + blit_pixel (h + 1, end, col, spr, + _WIDTH * X_FACT, &hidden); + } + } + q++; + } + h0 += _WIDTH * X_FACT; + q++; + } + return hidden; +} + +#endif + +static int blit_cel (int x, int y, int spr, struct view_cel *c) +{ + UINT8 *p0, *p, *q = NULL, *end; + int i, j, t, m, col; + int hidden = TRUE; + + /* Fixes bug #477841 (crash in PQ1 map C4 when y == -2) */ + if (y < 0) y = 0; + if (x < 0) x = 0; + if (y >= _HEIGHT) y = _HEIGHT - 1; + if (x >= _WIDTH) x = _WIDTH - 1; + +#ifdef USE_HIRES + if (opt.hires) + blit_hires_cel (x, y, spr, c); +#endif + + q = c->data; + t = c->transparency; + m = c->mirror; + spr <<= 4; + p0 = &game.sbuf[x + y * _WIDTH + m * (c->width - 1)]; + + end = game.sbuf + _WIDTH * _HEIGHT; + + for (i = 0; i < c->height; i++) { + p = p0; + while (*q) { + col = (*q & 0xf0) >> 4; + for (j = *q & 0x0f; j; j--, p += 1 - 2 * m) { + if (col != t) { + blit_pixel (p, end, col, spr, + _WIDTH, &hidden); + } + } + q++; + } + p0 += _WIDTH; + q++; + } + + return hidden; +} + +static void objs_savearea (struct sprite *s) +{ + int y; + SINT16 x_pos = s->x_pos, y_pos = s->y_pos; + SINT16 x_size = s->x_size, y_size = s->y_size; + UINT8 *p0, *q; +#ifdef USE_HIRES + UINT8 *h0, *k; +#endif + + if (x_pos + x_size > _WIDTH) + x_size = _WIDTH-x_pos; + + if (x_pos < 0) { + x_size += x_pos; + x_pos = 0; + } + + if (y_pos + y_size > _HEIGHT) + y_size = _HEIGHT-y_pos; + + if (y_pos < 0) { + y_size += y_pos; + y_pos = 0; + } + + if (x_size <= 0 || y_size <= 0) + return; + + p0 = &game.sbuf[x_pos + y_pos * _WIDTH]; + q = s->buffer; +#ifdef USE_HIRES + h0 = &game.hires[(x_pos + y_pos * _WIDTH) * 2]; + k = s->hires; +#endif + for (y = 0; y < y_size; y++) { + memcpy (q, p0, x_size); + q += x_size; + p0 += _WIDTH; +#ifdef USE_HIRES + memcpy (k, h0, x_size * 2); + k += x_size * 2; + h0 += _WIDTH * 2; +#endif + } +} + +static void objs_restorearea (struct sprite *s) +{ + int y, offset; + SINT16 x_pos = s->x_pos, y_pos = s->y_pos; + SINT16 x_size = s->x_size, y_size = s->y_size; + UINT8 *p0, *q; +#ifdef USE_HIRES + UINT8 *h0, *k; +#endif + + if (x_pos + x_size > _WIDTH) + x_size = _WIDTH - x_pos; + + if (x_pos < 0) { + x_size += x_pos; + x_pos = 0; + } + + if (y_pos + y_size > _HEIGHT) + y_size = _HEIGHT-y_pos; + + if (y_pos < 0) { + y_size += y_pos; + y_pos = 0; + } + + if (x_size <= 0 || y_size <= 0) + return; + + p0 = &game.sbuf[x_pos + y_pos * _WIDTH]; + q = s->buffer; +#ifdef USE_HIRES + h0 = &game.hires[(x_pos + y_pos * _WIDTH) * 2]; + k = s->hires; +#endif + offset = game.line_min_print * CHAR_LINES; + for (y = 0; y < y_size; y++) { + memcpy (p0, q, x_size); + put_pixels_a (x_pos, y_pos + y + offset, x_size, p0); + q += x_size; + p0 += _WIDTH; +#ifdef USE_HIRES + memcpy (h0, k, x_size * 2); + if (opt.hires) { + put_pixels_hires (x_pos * 2, + y_pos + y + offset, x_size * 2, h0); + } + k += x_size * 2; + h0 += _WIDTH * 2; +#endif + } +} + + +/* + * Sprite management functions + */ + +static LIST_HEAD(spr_upd_head); +static LIST_HEAD(spr_nonupd_head); + +/** + * Condition to determine whether a sprite will be in the 'updating' list. + */ +static int test_updating (struct vt_entry *v) +{ + /* Sanity check (see bug #779302) */ + if (~game.dir_view[v->current_view].flags & RES_LOADED) + return 0; + + return (v->flags & (ANIMATED|UPDATE|DRAWN)) == + (ANIMATED|UPDATE|DRAWN); +} + +/** + * Condition to determine whether a sprite will be in the 'non-updating' list. + */ +static int test_not_updating (struct vt_entry *v) +{ + /* Sanity check (see bug #779302) */ + if (~game.dir_view[v->current_view].flags & RES_LOADED) + return 0; + + return (v->flags & (ANIMATED|UPDATE|DRAWN)) == (ANIMATED|DRAWN); +} + +/** + * Convert sprite priority to y value. + */ +static INLINE int prio_to_y (int p) +{ + int i; + + if (p == 0) + return -1; + + for (i = 167; i >= 0; i--) { + if (game.pri_table[i] < p) + return i; + } + + return -1; /* (p - 5) * 12 + 48; */ +} + +/** + * Create and initialize a new sprite structure. + */ +static struct sprite *new_sprite (struct vt_entry *v) +{ + struct sprite *s; + + s = (struct sprite *)pool_alloc (sizeof (struct sprite)); + if (s == NULL) + return NULL; + + s->v = v; /* link sprite to associated view table entry */ + s->x_pos = v->x_pos; + s->y_pos = v->y_pos - v->y_size + 1; + s->x_size = v->x_size; + s->y_size = v->y_size; + s->buffer = pool_alloc (s->x_size * s->y_size); +#ifdef USE_HIRES + s->hires = pool_alloc (s->x_size * s->y_size * 2); +#endif + v->s = s; /* link view table entry to this sprite */ + + return s; +} + +/** + * Insert sprite in the specified sprite list. + */ +static void spr_addlist (struct list_head *head, struct vt_entry *v) +{ + struct sprite *s; + + s = new_sprite (v); + list_add_tail (&s->list, head); +} + +/** + * Sort sprites from lower y values to build a sprite list. + */ +static struct list_head * +build_list (struct list_head *head, int (*test)(struct vt_entry *)) +{ + int i, j, k; + struct vt_entry *v; + struct vt_entry *entry[0x100]; + int y_val[0x100]; + int min_y = 0xff, min_index = 0; + + /* fill the arrays with all sprites that satisfy the 'test' + * condition and their y values + */ + i = 0; + for_each_vt_entry(v) { + if (test (v)) { + entry[i] = v; + y_val[i] = v->flags & FIXED_PRIORITY ? + prio_to_y (v->priority) : v->y_pos; + i++; + } + } + + /* now look for the smallest y value in the array and put that + * sprite in the list + */ + for (j = 0; j < i; j++) { + min_y = 0xff; + for (k = 0; k < i; k++) { + if (y_val[k] < min_y) { + min_index = k; + min_y = y_val[k]; + } + } + + y_val[min_index] = 0xff; + spr_addlist (head, entry[min_index]); + } + + return head; +} + +/** + * Build list of updating sprites. + */ +static struct list_head *build_upd_blitlist () +{ + return build_list (&spr_upd_head, test_updating); +} + +/** + * Build list of non-updating sprites. + */ +static struct list_head *build_nonupd_blitlist () +{ + return build_list (&spr_nonupd_head, test_not_updating); +} + +/** + * Clear the given sprite list. + */ +static void free_list (struct list_head *head) +{ + struct list_head *h; + struct sprite *s; + + list_for_each (h, head, prev) { + s = list_entry (h, struct sprite, list); + list_del (h); +#ifdef USE_HIRES + pool_release (s->hires); +#endif + pool_release (s->buffer); + pool_release (s); + } +} + +/** + * Copy sprites from the pic buffer to the screen buffer, and check if + * sprites of the given list have moved. + */ +static void commit_sprites (struct list_head *head) +{ + struct list_head *h; + + list_for_each (h, head, next) { + struct sprite *s = list_entry (h, struct sprite, list); + int x1, y1, x2, y2, w, h; + + w = (s->v->cel_data->width > s->v->cel_data_2->width) ? + s->v->cel_data->width : s->v->cel_data_2->width; + + h = (s->v->cel_data->height > s->v->cel_data_2->height) ? + s->v->cel_data->height : s->v->cel_data_2->height; + + s->v->cel_data_2 = s->v->cel_data; + + if (s->v->x_pos < s->v->x_pos2) { + x1 = s->v->x_pos; + x2 = s->v->x_pos2 + w - 1; + } else { + x1 = s->v->x_pos2; + x2 = s->v->x_pos + w - 1; + } + + if (s->v->y_pos < s->v->y_pos2) { + y1 = s->v->y_pos - h + 1; + y2 = s->v->y_pos2; + } else { + y1 = s->v->y_pos2 - h + 1; + y2 = s->v->y_pos; + } + + commit_block (x1, y1, x2, y2); + + if (s->v->step_time_count != s->v->step_time) + continue; + + if (s->v->x_pos == s->v->x_pos2 && s->v->y_pos == s->v->y_pos2){ + s->v->flags |= DIDNT_MOVE; + continue; + } + + s->v->x_pos2 = s->v->x_pos; + s->v->y_pos2 = s->v->y_pos; + s->v->flags &= ~DIDNT_MOVE; + } + +#ifdef USE_CONSOLE + if (debug.statusline) + write_status (); +#endif +} + +/** + * Erase all sprites in the given list. + */ +static void erase_sprites (struct list_head *head) +{ + struct list_head *h; + + list_for_each (h, head, prev) { + struct sprite *s = list_entry (h, struct sprite, list); + objs_restorearea (s); + } + + free_list (head); +} + +/** + * Blit all sprites in the given list. + */ +static void blit_sprites (struct list_head *head) +{ + struct list_head *h = NULL; + int hidden; + + list_for_each (h, head, next) { + struct sprite *s = list_entry (h, struct sprite, list); + objs_savearea (s); + /* _D ("s->v->entry = %d (prio %d)", s->v->entry, + s->v->priority); */ + hidden = blit_cel (s->x_pos, s->y_pos, s->v->priority, + s->v->cel_data); + if (s->v->entry == 0) { /* if ego, update f1 */ + setflag (F_ego_invisible, hidden); + } + } +} + + +/* + * Public functions + */ + +void commit_upd_sprites () +{ + commit_sprites (&spr_upd_head); +} + +void commit_nonupd_sprites () +{ + commit_sprites (&spr_nonupd_head); +} + +/* check moves in both lists */ +void commit_both () +{ + commit_upd_sprites (); + commit_nonupd_sprites (); +} + +/** + * Erase updating sprites. + * This function follows the list of all updating sprites and restores + * the visible and priority data of their background buffers back to + * the AGI screen. + * + * @see erase_nonupd_sprites() + * @see erase_both() + */ +void erase_upd_sprites () +{ + erase_sprites (&spr_upd_head); +} + +/** + * Erase non-updating sprites. + * This function follows the list of all non-updating sprites and restores + * the visible and priority data of their background buffers back to + * the AGI screen. + * + * @see erase_upd_sprites() + * @see erase_both() + */ +void erase_nonupd_sprites () +{ + erase_sprites (&spr_nonupd_head); +} + +/** + * Erase all sprites. + * This function follows the lists of all updating and non-updating + * sprites and restores the visible and priority data of their background + * buffers back to the AGI screen. + * + * @see erase_upd_sprites() + * @see erase_nonupd_sprites() + */ +void erase_both () +{ + erase_upd_sprites (); + erase_nonupd_sprites (); +} + +/** + * Blit updating sprites. + * This function follows the list of all updating sprites and blits + * them on the AGI screen. + * + * @see blit_nonupd_sprites() + * @see blit_both() + */ +void blit_upd_sprites () +{ + /* _D("blit updating"); */ + blit_sprites (build_upd_blitlist ()); +} + +/** + * Blit non-updating sprites. + * This function follows the list of all non-updating sprites and blits + * them on the AGI screen. + * + * @see blit_upd_sprites() + * @see blit_both() + */ +void blit_nonupd_sprites () +{ + /* _D("blit non-updating"); */ + blit_sprites (build_nonupd_blitlist ()); +} + +/** + * Blit all sprites. + * This function follows the lists of all updating and non-updating + * sprites and blits them on the AGI screen. + * + * @see blit_upd_sprites() + * @see blit_nonupd_sprites() + */ +void blit_both () +{ + blit_nonupd_sprites (); + blit_upd_sprites (); +} + +/** + * Add view to picture. + * This function is used to implement the add.to.pic AGI command. It + * copies the specified cel from a view resource on the current picture. + * This cel is not a sprite, it can't be moved or removed. + * @param view number of view resource + * @param loop number of loop in the specified view resource + * @param cel number of cel in the specified loop + * @param x x coordinate to place the view + * @param y y coordinate to place the view + * @param pri priority to use + * @param mar if < 4, create a margin around the the base of the cel + */ +void add_to_pic (int view, int loop, int cel, int x, int y, int pri, int mar) +{ + struct view_cel *c = NULL; + int x1, y1, x2, y2, y3; + UINT8 *p1, *p2; + + _D ("v=%d, l=%d, c=%d, x=%d, y=%d, p=%d, m=%d", + view, loop, cel, x, y, pri, mar); + + record_image_stack_call(ADD_VIEW, view, loop, cel, x, y, pri, mar); + + /* + * Was hardcoded to 8, changed to pri_table[y] to fix Gold + * Rush (see bug #587558) + */ + if (pri == 0) + pri = game.pri_table[y]; + + c = &game.views[view].loop[loop].cel[cel]; + + x1 = x; + y1 = y - c->height + 1; + x2 = x + c->width - 1; + y2 = y; + + if (x1 < 0) { + x2 -= x1; + x1 = 0; + } + if (y1 < 0) { + y2 -= y1; + y1 = 0; + } + if (x2 >= _WIDTH) x2 = _WIDTH - 1; + if (y2 >= _HEIGHT) y2 = _HEIGHT - 1; + + erase_both (); + + _D (_D_WARN "blit_cel (%d, %d, %d, c)", x, y, pri); + blit_cel (x1, y1, pri, c); + + /* If margin is 0, 1, 2, or 3, the base of the cel is + * surrounded with a rectangle of the corresponding priority. + * If margin >= 4, this extra margin is not shown. + */ + if (mar < 4) { + /* add rectangle around object, don't clobber control + * info in priority data. The box extends to the end of + * its priority band! + * + * SQ1 needs +1 (see bug #810331) + */ + y3 = (y2 / 12) * 12 + 1; + + p1 = &game.sbuf[x1 + y3 * _WIDTH]; + p2 = &game.sbuf[x2 + y3 * _WIDTH]; + + for (y = y3; y <= y2; y++) { + if ((*p1 >> 4) >= 4) *p1 = (mar << 4) | (*p1 & 0x0f); + if ((*p2 >> 4) >= 4) *p2 = (mar << 4) | (*p2 & 0x0f); + p1 += _WIDTH; + p2 += _WIDTH; + } + + _D (_D_WARN "pri box: %d %d %d %d (%d)", x1, y3, x2, y2, mar); + p1 = &game.sbuf[x1 + y3 * _WIDTH]; + p2 = &game.sbuf[x1 + y2 * _WIDTH]; + for (x = x1; x <= x2; x++) { + if ((*p1 >> 4) >= 4) *p1 = (mar << 4) | (*p1 & 0x0f); + if ((*p2 >> 4) >= 4) *p2 = (mar << 4) | (*p2 & 0x0f); + p1++; + p2++; + } + } + + blit_both (); + + _D (_D_WARN "commit_block (%d, %d, %d, %d)", x1, y1, x2, y2); + commit_block (x1, y1, x2, y2); +} + +/** + * Show object and description + * This function shows an object from the player's inventory, displaying + * a message box with the object description. + * @param n Number of the object to show + */ +void show_obj (n) +{ + struct view_cel *c; + struct sprite s; + int x1, y1, x2, y2; + + agi_load_resource (rVIEW, n); + if (!(c = &game.views[n].loop[0].cel[0])) + return; + + x1 = (_WIDTH - c->width) / 2; + y1 = 112; + x2 = x1 + c->width - 1; + y2 = y1 + c->height - 1; + + s.x_pos = x1; + s.y_pos = y1; + s.x_size = c->width; + s.y_size = c->height; + s.buffer = malloc (s.x_size * s.y_size); +#ifdef USE_HIRES + s.hires = malloc (s.x_size * s.y_size * 2); +#endif + + objs_savearea (&s); + blit_cel (x1, y1, s.x_size, c); + commit_block (x1, y1, x2, y2); + message_box (game.views[n].descr); + objs_restorearea (&s); + commit_block (x1, y1, x2, y2); + + free (s.buffer); + + /* Added to fix a memory leak --Vasyl */ +#ifdef USE_HIRES + free(s.hires); +#endif +} + +void commit_block (int x1, int y1, int x2, int y2) +{ + int i, w, offset; + UINT8 *q; +#ifdef USE_HIRES + UINT8 *h; +#endif + + if (!game.picture_shown) + return; + + /* Clipping */ + if (x1 < 0) x1 = 0; + if (x2 < 0) x2 = 0; + if (y1 < 0) y1 = 0; + if (y2 < 0) y2 = 0; + if (x1 >= _WIDTH) x1 = _WIDTH - 1; + if (x2 >= _WIDTH) x2 = _WIDTH - 1; + if (y1 >= _HEIGHT) y1 = _HEIGHT - 1; + if (y2 >= _HEIGHT) y2 = _HEIGHT - 1; + + /* _D ("%d, %d, %d, %d", x1, y1, x2, y2); */ + + w = x2 - x1 + 1; + q = &game.sbuf[x1 + _WIDTH * y1]; +#ifdef USE_HIRES + h = &game.hires[(x1 + _WIDTH * y1) * 2]; +#endif + offset = game.line_min_print * CHAR_LINES; + for (i = y1; i <= y2; i++) { + put_pixels_a (x1, i + offset, w, q); + q += _WIDTH; +#ifdef USE_HIRES + if (opt.hires) { + put_pixels_hires (x1 * 2, i + offset, w * 2, h); + } + h += _WIDTH * 2; +#endif + } + + flush_block_a (x1, y1 + offset, x2, y2 + offset); +} + +int init_sprites () +{ + if ((sprite_pool = malloc (POOL_SIZE)) == NULL) + return err_NotEnoughMemory; + + pool_top = sprite_pool; + + return err_OK; +} + +void deinit_sprites () +{ + free (sprite_pool); +} + +/* end: sprite.c */ diff --git a/text.c b/text.c index e16487d..cf5db5e 100644 --- a/text.c +++ b/text.c @@ -1,689 +1,689 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: text.c,v 1.91 2003/09/02 23:33:28 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include -#include -#include "sarien.h" -#include "agi.h" -#include "sprite.h" /* for commit_both() */ -#include "graphics.h" -#include "keyboard.h" -#include "text.h" - - -static void print_text2 (int l, char *msg, int foff, int xoff, int yoff, int len, int fg, int bg) -{ - int x1, y1; - int maxx, minx, ofoff; - int update; - /* Note: Must be unsigned to use AGDS cyrillic characters! */ - unsigned char *m; - - /* kludge! */ - update = 1; - if (l == 2) { - update = l = 0; - } - - /* FR: strings with len == 1 were not printed - */ - if (len == 1) { - put_text_character (l, xoff + foff, yoff, *msg, fg, bg); - maxx = 1; - minx = 0; - ofoff = foff; - y1 = 0; /* Check this */ - } else { - maxx = 0; - minx = GFX_WIDTH; - ofoff = foff; - - for (m = (unsigned char*)msg, x1 = y1 = 0; *m; m++) { - - if (*m >= 0x20 || *m == 1 || *m == 2 || *m == 3) { - /* FIXME */ - int ypos; - - ypos = (y1 * CHAR_LINES) + yoff; - - if((x1!=(len-1) || x1==39) && (ypos <= (GFX_HEIGHT - CHAR_LINES))) { - int xpos; - - xpos = (x1 * CHAR_COLS) + xoff + foff; - - if (xpos >= GFX_WIDTH) - continue; - - put_text_character (l, xpos, ypos, - *m, fg, bg); - - if (x1 > maxx) - maxx=x1; - if (x1 < minx) - minx=x1; - } - - x1++; - /* DF: changed the len-1 to len... */ - if(x1 == len && m[1] != '\n') - y1++, x1 = foff = 0; - } else { - y1++; - x1 = foff = 0; - } - } - } - - if (l) - return; - - if (maxx < minx) - return; - - maxx *= CHAR_COLS; - minx *= CHAR_COLS; - - if (update) { - schedule_update (foff + xoff + minx, yoff, - ofoff + xoff + maxx + CHAR_COLS - 1, - yoff + y1 * CHAR_LINES + CHAR_LINES + 1); - /* Making synchronous text updates reduces CPU load - * when updating status line and input area - */ - do_update (); - } -} - -/* len is in characters, not pixels!! - */ -static void blit_textbox (char *p, int y, int x, int len) -{ - /* if x | y = -1, then centre the box */ - int xoff, yoff, lin, h, w; - char *msg, *m; - - _D ("x=%d, y=%d, len=%d", x, y, len); - if (game.window.active) - close_window (); - - if (x == 0 && y == 0 && len == 0) - x = y = -1; - - if (len <= 0 || len >= 40) - len = 32; - - xoff = x * CHAR_COLS; - yoff = y * CHAR_LINES; - len--; - - m = msg = word_wrap_string (agi_sprintf (p), &len); - - for (lin = 1; *m; m++) { - /* Test \r for MacOS 8 */ - if (*m == '\n' || *m == '\r') - lin++; - } - - if (lin * CHAR_LINES > GFX_HEIGHT) - lin = (GFX_HEIGHT / CHAR_LINES); - - w = (len + 2) * CHAR_COLS; - h = (lin + 2) * CHAR_LINES; - - if (xoff < 0) - xoff = (GFX_WIDTH - w - CHAR_COLS) / 2; - else - xoff -= CHAR_COLS; - - if (yoff < 0) - yoff = (GFX_HEIGHT - 3 * CHAR_LINES - h) / 2; - - draw_window (xoff, yoff, xoff + w - 1, yoff + h - 1); - - print_text2 (2, msg, 0, CHAR_COLS + xoff, CHAR_LINES + yoff, len + 1, - MSG_BOX_TEXT, MSG_BOX_COLOUR); - - free (msg); - - do_update (); -} - -static void erase_textbox () -{ - if (!game.window.active) { - _D ("no window active"); - return; - } - - _D (_D_WARN "x1=%d, y1=%d, x2=%d, y2=%d", game.window.x1, - game.window.y1, game.window.x2, game.window.y2); - - restore_block (game.window.x1, game.window.y1, - game.window.x2, game.window.y2, game.window.buffer); - - free (game.window.buffer); - game.window.active = FALSE; - - do_update (); -} - - -/* - * Public functions - */ - -/** - * Print text in the Sarien screen. - */ -void print_text (char *msg, int f, int x, int y, int len, int fg, int bg) -{ - f *= CHAR_COLS; - x *= CHAR_COLS; - y *= CHAR_LINES; - - _D (_D_WARN "%s, %d, %d, %d, %d, %d, %d", msg, f, x, y, len, fg, bg); - print_text2 (0, agi_sprintf (msg), f, x, y, len, fg, bg); -} - -/** - * Print text in the Sarien console. - */ -void print_text_console (char *msg, int x, int y, int len, int fg, int bg) -{ - x *= CHAR_COLS; - y *= 10; - - print_text2 (1, msg, 0, x, y, len, fg, bg); -} - -/** - * Wrap text line to the specified width. - * @param str String to wrap. - * @param len Length of line. - */ -char* word_wrap_string (char *str, int *len) -{ - /* If the message has a long word (longer than 31 character) then - * loop in line 239 (for (; *v != ' '; v--, c--);) can wrap - * around 0 and write large number in c. This causes returned - * length to be negative (!) and eventually crashes in calling - * code. The fix is simple -- remove unsigned in maxc, c, l - * declaration. --Vasyl - */ - char *msg, *v, *e; - int maxc, c, l = *len; - - v = msg = strdup (str); - e = msg + strlen (msg); - maxc = 0; - - while (42) { - _D ("[%s], %d", msg, maxc); - if (strchr (v, ' ') == NULL && strlen (v) > l) { - _D (_D_CRIT "Word too long in message"); - l = strlen (v); - } - /* Must include \r for MacOS 8 */ - while ((c = strcspn (v, "\n\r")) <= l) { - _D ("c = %d, maxc = %d", c, maxc); - if (c > maxc) - maxc = c; - if ((v += c + 1) >= e) - goto end; - } - c = l; - if ((v += l) >= e) - break; - - /* The same line that caused that bug I mentioned - * should also do another check: - * for (; *v != ' ' && *v != '\n'; v--, c--); - * While this does not matter in most cases, in the case of - * long words it caused extra \n inserted in the line - * preceding long word. This one is definitely non-critical; - * one might argue that the function is not supposed to deal - * with long words. BTW, that condition at the beginning of - * the while loop that checks word length does not make much - * sense -- it verifies the length of the first word but for - * the rest it does something odd. Overall, even with these - * changes the function is still not completely robust. - * --Vasyl - */ - if (*v != ' ') - for (; *v != ' ' && *v != '\n' && *v != '\r'; v--, c--); - if (c > maxc) - maxc = c; - *v++ = '\n'; - } -end: - *len = maxc; - return msg; -} - -/** - * Remove existing window, if any. - */ -void close_window () -{ - _D (_D_WARN "close window"); - erase_both (); - erase_textbox (); /* remove window, if any */ - blit_both (); - commit_both (); /* redraw sprites */ - game.has_window = FALSE; -} - -/** - * Display a message box. - * This function displays the specified message in a text box - * centered in the screen and waits until a key is pressed. - * @param p The text to be displayed - */ -int message_box (char *s) -{ - int k; - - erase_both (); - blit_textbox (s, -1, -1, -1); - blit_both (); -#ifdef KEYS_WORK - k = wait_key (); - _D (_D_WARN "wait_key returned %02x", k); -#endif - close_window (); - - return k; -} - -/** - * Display a message box with buttons. - * This function displays the specified message in a text box - * centered in the screen and waits until a button is pressed. - * @param p The text to be displayed - * @param b NULL-terminated list of button labels - */ -int selection_box (char *m, char **b) -{ - int x, y, i, s; - int key, active = 0; - int rc = -1; - int bx[5], by[5]; - - erase_both (); - blit_textbox (m, -1, -1, -1); - - x = game.window.x1 + 5 * CHAR_COLS / 2; - y = game.window.y2 - 5 * CHAR_LINES / 2; - s = game.window.x2 - game.window.x1 + 1 - 5 * CHAR_COLS; - _D ("s = %d", s); - - /* Automatically position buttons */ - for (i = 0; b[i]; i++) { - s -= CHAR_COLS * strlen (b[i]); - } - - if (i > 1) { - _D ("s / %d = %d", i - 1, s / (i - 1)); - s /= (i - 1); - } else { - x += s / 2; - } - - for (i = 0; b[i]; i++) { - bx[i] = x; - by[i] = y; - x += CHAR_COLS * strlen (b[i]) + s; - } - - blit_both (); - - /* clear key queue */ - while (keypress ()) { get_key (); } - - _D (_D_WARN "waiting..."); - while (42) { - for (i = 0; b[i]; i++) - draw_button (bx[i], by[i], b[i], i == active, 0); - - poll_timer (); /* msdos driver -> does nothing */ - key = do_poll_keyboard (); - if (!console_keyhandler (key)) { - switch (key) { - case KEY_ENTER: - rc = active; - goto press; - case KEY_ESCAPE: - rc = -1; - goto getout; -#ifdef USE_MOUSE - case BUTTON_LEFT: - for (i = 0; b[i]; i++) { - if (test_button (bx[i], by[i], b[i])) { - rc = active = i; - goto press; - } - } - break; -#endif - case 0x09: /* Tab */ - _D ("Focus change"); - active++; - active %= i; - break; - } - } - console_cycle (); - } - -press: - _D (_D_WARN "Button pressed: %d", rc); - -getout: - close_window (); - _D (_D_WARN "Result = %d", rc); - - return rc; -} - -/** - * - */ -int print (char *p, int lin, int col, int len) -{ - if (p == NULL) - return 0; - - _D (_D_WARN "lin = %d, col = %d, len = %d", lin, col, len); - - if (col == 0 && lin == 0 && len == 0) - lin = col = -1; - - if (len == 0) - len = 30; - - blit_textbox (p, lin, col, len); - - if (getflag (F_output_mode)) { - /* non-blocking window */ - setflag (F_output_mode, FALSE); - return 1; - } - - /* blocking */ - - if (game.vars[V_window_reset] == 0) { - int k; - setvar (V_key, 0); - k = wait_key(); - close_window (); - return k; - } - - /* timed window */ - - _D (_D_WARN "f15==0, v21==%d => timed", getvar (21)); - game.msg_box_ticks = getvar (V_window_reset) * 10; - setvar (V_key, 0); - - do { - main_cycle (); - if (game.keypress == KEY_ENTER) { - _D (_D_WARN "KEY_ENTER"); - setvar (V_window_reset, 0); - game.keypress = 0; - break; - } - } while (game.msg_box_ticks > 0); - - setvar (V_window_reset, 0); - - close_window (); - - return 0; -} - -/** - * - */ -static void print_status (char *message, ...) -{ - char x[42]; - va_list args; - - va_start (args, message); - -#ifdef HAVE_VSNPRINTF - vsnprintf (x, 41, message, args); -#else - vsprintf (x, message, args); -#endif - - va_end (args); - - _D (_D_WARN "fg=%d, bg=%d", STATUS_FG, STATUS_BG); - print_text (x, 0, 0, game.line_status, 40, STATUS_FG, STATUS_BG); -} - - -static char *safe_strcat (char *s, const char *t) -{ - if (t != NULL) - strcat (s, t); - - return s; -} - - -/** - * Formats AGI string. - * This function turns a AGI string into a real string expanding values - * according to the AGI format specifiers. - * @param s string containing the format specifier - * @param n logic number - */ -#define MAX_LEN 768 -char *agi_sprintf (char *s) -{ - static char y[MAX_LEN]; - char x[MAX_LEN]; - char z[16], *p; - - _D ("logic %d, '%s'", game.lognum, s); - p = x; - - for (*p = 0; *s; ) { - switch (*s) { - case '\\': - s++; - goto literal; - case '%': - s++; - switch (*s++) { - int i; - case 'v': - i = strtoul (s, NULL, 10); - while (*s >= '0' && *s <= '9') - s++; - sprintf (z, "%015i", getvar(i)); - - i = 99; - if (*s == '|') { - s++; - i = strtoul (s, NULL, 10); - while (*s >= '0' && *s <= '9') - s++; - } - - if (i == 99) { - /* remove all leading 0 */ - /* don't remove the 3rd zero if 000 */ - for (i = 0; z[i] == '0' && i < 14; i++); - } else { - i = 15 - i; - } - safe_strcat(p, z + i); - break; - case '0': - i = strtoul (s, NULL, 10) - 1; - safe_strcat(p, object_name(i)); - break; - case 'g': - i = strtoul (s, NULL, 10) - 1; - safe_strcat(p, game.logics[0].texts[i]); - break; - case 'w': - i = strtoul (s, NULL, 10) - 1; - safe_strcat(p, game.ego_words[i].word); - break; - case 's': - i = strtoul (s, NULL, 10); - safe_strcat(p, game.strings[i]); - break; - case 'm': - i = strtoul (s, NULL, 10) - 1; - if (game.logics[game.lognum].num_texts > i) - safe_strcat(p, agi_sprintf(game.logics[game.lognum].texts[i])); - break; - } - - while (*s >= '0' && *s <= '9') s++; - while (*p) p++; - break; - - default: - literal: - assert (p < x + MAX_LEN); - *p++ = *s++; - *p = 0; - break; - } - } - - strcpy (y, x); - return y; -} - -/** - * Write the status line. - */ -void write_status () -{ - char x[64]; - -#ifdef USE_CONSOLE - if (debug.statusline) { -#ifdef USE_MOUSE - print_status ("%3d(%03d) %3d,%3d(%3d,%3d) ", - getvar (0), getvar (1), - game.view_table[0].x_pos, - game.view_table[0].y_pos, - WIN_TO_PIC_X(mouse.x), WIN_TO_PIC_Y(mouse.y)); -#else - print_status ("%3d(%03d) %3d,%3d ", - getvar (0), getvar (1), - game.view_table[0].x_pos, - game.view_table[0].y_pos); -#endif - return; - } -#endif /* USE_CONSOLE */ - - if (!game.status_line) { - int l = game.line_status; - clear_lines (l, l, 0); - flush_lines (l, l); - return; - } - - sprintf (x, " Score:%i of %-3i", game.vars[V_score], - game.vars[V_max_score]); - print_status ("%-17s Sound:%s ", x, - getflag (F_sound_on) ? "on " : "off"); -} - -/** - * Print user input prompt. - */ -void write_prompt () -{ - int l, fg, bg, pos; - - if (!game.input_enabled || game.input_mode != INPUT_NORMAL) - return; - - l = game.line_user_input; - fg = game.color_fg; - bg = game.color_bg; - pos = game.cursor_pos; - - _D (_D_WARN "erase line %d", l); - clear_lines (l, l, game.color_bg); - - _D (_D_WARN "prompt = '%s'", agi_sprintf (game.strings[0])); - print_text (game.strings[0], 0, 0, l, 1, fg, bg); - print_text (game.input_buffer, 0, 1, l, pos + 1, fg, bg); - print_character (pos + 1, l, game.cursor_char, fg, bg); - - flush_lines (l, l); - do_update (); -} - -/** - * Clear text lines in the screen. - * @param l1 start line - * @param l2 end line - * @param c color - */ -void clear_lines (int l1, int l2, int c) -{ - /* do we need to adjust for +8 on topline? - * inc for endline so it matches the correct num - * ie, from 22 to 24 is 3 lines, not 2 lines. - */ - - l1 *= CHAR_LINES; - l2 *= CHAR_LINES; - l2 += CHAR_LINES - 1; - - draw_rectangle (0, l1, GFX_WIDTH - 1, l2, c); -} - -/** - * - */ -void flush_lines (int l1, int l2) -{ - l1 *= CHAR_LINES; - l2 *= CHAR_LINES; - l2 += CHAR_LINES - 1; - - flush_block (0, l1, GFX_WIDTH - 1, l2); -} - -/** - * - */ -void draw_window (int x1, int y1, int x2, int y2) -{ - game.window.active = TRUE; - game.window.x1 = x1; - game.window.y1 = y1; - game.window.x2 = x2; - game.window.y2 = y2; - game.window.buffer = malloc ((x2 - x1 + 1) * (y2 - y1 + 1)); - - _D (_D_WARN "x1=%d, y1=%d, x2=%d, y2=%d", x1, y1, x2, y2); - save_block (x1, y1, x2, y2, game.window.buffer); - draw_box (x1, y1, x2, y2, MSG_BOX_COLOUR, MSG_BOX_LINE, 2); -} - -/* end: text.c */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: text.c,v 1.91 2003/09/02 23:33:28 cmatsuoka Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include +#include +#include "sarien.h" +#include "agi.h" +#include "sprite.h" /* for commit_both() */ +#include "graphics.h" +#include "keyboard.h" +#include "text.h" + + +static void print_text2 (int l, char *msg, int foff, int xoff, int yoff, int len, int fg, int bg) +{ + int x1, y1; + int maxx, minx, ofoff; + int update; + /* Note: Must be unsigned to use AGDS cyrillic characters! */ + unsigned char *m; + + /* kludge! */ + update = 1; + if (l == 2) { + update = l = 0; + } + + /* FR: strings with len == 1 were not printed + */ + if (len == 1) { + put_text_character (l, xoff + foff, yoff, *msg, fg, bg); + maxx = 1; + minx = 0; + ofoff = foff; + y1 = 0; /* Check this */ + } else { + maxx = 0; + minx = GFX_WIDTH; + ofoff = foff; + + for (m = (unsigned char*)msg, x1 = y1 = 0; *m; m++) { + + if (*m >= 0x20 || *m == 1 || *m == 2 || *m == 3) { + /* FIXME */ + int ypos; + + ypos = (y1 * CHAR_LINES) + yoff; + + if((x1!=(len-1) || x1==39) && (ypos <= (GFX_HEIGHT - CHAR_LINES))) { + int xpos; + + xpos = (x1 * CHAR_COLS) + xoff + foff; + + if (xpos >= GFX_WIDTH) + continue; + + put_text_character (l, xpos, ypos, + *m, fg, bg); + + if (x1 > maxx) + maxx=x1; + if (x1 < minx) + minx=x1; + } + + x1++; + /* DF: changed the len-1 to len... */ + if(x1 == len && m[1] != '\n') + y1++, x1 = foff = 0; + } else { + y1++; + x1 = foff = 0; + } + } + } + + if (l) + return; + + if (maxx < minx) + return; + + maxx *= CHAR_COLS; + minx *= CHAR_COLS; + + if (update) { + schedule_update (foff + xoff + minx, yoff, + ofoff + xoff + maxx + CHAR_COLS - 1, + yoff + y1 * CHAR_LINES + CHAR_LINES + 1); + /* Making synchronous text updates reduces CPU load + * when updating status line and input area + */ + do_update (); + } +} + +/* len is in characters, not pixels!! + */ +static void blit_textbox (char *p, int y, int x, int len) +{ + /* if x | y = -1, then centre the box */ + int xoff, yoff, lin, h, w; + char *msg, *m; + + _D ("x=%d, y=%d, len=%d", x, y, len); + if (game.window.active) + close_window (); + + if (x == 0 && y == 0 && len == 0) + x = y = -1; + + if (len <= 0 || len >= 40) + len = 32; + + xoff = x * CHAR_COLS; + yoff = y * CHAR_LINES; + len--; + + m = msg = word_wrap_string (agi_sprintf (p), &len); + + for (lin = 1; *m; m++) { + /* Test \r for MacOS 8 */ + if (*m == '\n' || *m == '\r') + lin++; + } + + if (lin * CHAR_LINES > GFX_HEIGHT) + lin = (GFX_HEIGHT / CHAR_LINES); + + w = (len + 2) * CHAR_COLS; + h = (lin + 2) * CHAR_LINES; + + if (xoff < 0) + xoff = (GFX_WIDTH - w - CHAR_COLS) / 2; + else + xoff -= CHAR_COLS; + + if (yoff < 0) + yoff = (GFX_HEIGHT - 3 * CHAR_LINES - h) / 2; + + draw_window (xoff, yoff, xoff + w - 1, yoff + h - 1); + + print_text2 (2, msg, 0, CHAR_COLS + xoff, CHAR_LINES + yoff, len + 1, + MSG_BOX_TEXT, MSG_BOX_COLOUR); + + free (msg); + + do_update (); +} + +static void erase_textbox () +{ + if (!game.window.active) { + _D ("no window active"); + return; + } + + _D (_D_WARN "x1=%d, y1=%d, x2=%d, y2=%d", game.window.x1, + game.window.y1, game.window.x2, game.window.y2); + + restore_block (game.window.x1, game.window.y1, + game.window.x2, game.window.y2, game.window.buffer); + + free (game.window.buffer); + game.window.active = FALSE; + + do_update (); +} + + +/* + * Public functions + */ + +/** + * Print text in the Sarien screen. + */ +void print_text (char *msg, int f, int x, int y, int len, int fg, int bg) +{ + f *= CHAR_COLS; + x *= CHAR_COLS; + y *= CHAR_LINES; + + _D (_D_WARN "%s, %d, %d, %d, %d, %d, %d", msg, f, x, y, len, fg, bg); + print_text2 (0, agi_sprintf (msg), f, x, y, len, fg, bg); +} + +/** + * Print text in the Sarien console. + */ +void print_text_console (char *msg, int x, int y, int len, int fg, int bg) +{ + x *= CHAR_COLS; + y *= 10; + + print_text2 (1, msg, 0, x, y, len, fg, bg); +} + +/** + * Wrap text line to the specified width. + * @param str String to wrap. + * @param len Length of line. + */ +char* word_wrap_string (char *str, int *len) +{ + /* If the message has a long word (longer than 31 character) then + * loop in line 239 (for (; *v != ' '; v--, c--);) can wrap + * around 0 and write large number in c. This causes returned + * length to be negative (!) and eventually crashes in calling + * code. The fix is simple -- remove unsigned in maxc, c, l + * declaration. --Vasyl + */ + char *msg, *v, *e; + int maxc, c, l = *len; + + v = msg = strdup (str); + e = msg + strlen (msg); + maxc = 0; + + while (42) { + _D ("[%s], %d", msg, maxc); + if (strchr (v, ' ') == NULL && strlen (v) > l) { + _D (_D_CRIT "Word too long in message"); + l = strlen (v); + } + /* Must include \r for MacOS 8 */ + while ((c = strcspn (v, "\n\r")) <= l) { + _D ("c = %d, maxc = %d", c, maxc); + if (c > maxc) + maxc = c; + if ((v += c + 1) >= e) + goto end; + } + c = l; + if ((v += l) >= e) + break; + + /* The same line that caused that bug I mentioned + * should also do another check: + * for (; *v != ' ' && *v != '\n'; v--, c--); + * While this does not matter in most cases, in the case of + * long words it caused extra \n inserted in the line + * preceding long word. This one is definitely non-critical; + * one might argue that the function is not supposed to deal + * with long words. BTW, that condition at the beginning of + * the while loop that checks word length does not make much + * sense -- it verifies the length of the first word but for + * the rest it does something odd. Overall, even with these + * changes the function is still not completely robust. + * --Vasyl + */ + if (*v != ' ') + for (; *v != ' ' && *v != '\n' && *v != '\r'; v--, c--); + if (c > maxc) + maxc = c; + *v++ = '\n'; + } +end: + *len = maxc; + return msg; +} + +/** + * Remove existing window, if any. + */ +void close_window () +{ + _D (_D_WARN "close window"); + erase_both (); + erase_textbox (); /* remove window, if any */ + blit_both (); + commit_both (); /* redraw sprites */ + game.has_window = FALSE; +} + +/** + * Display a message box. + * This function displays the specified message in a text box + * centered in the screen and waits until a key is pressed. + * @param p The text to be displayed + */ +int message_box (char *s) +{ + int k; + + erase_both (); + blit_textbox (s, -1, -1, -1); + blit_both (); +#ifdef KEYS_WORK + k = wait_key (); + _D (_D_WARN "wait_key returned %02x", k); +#endif + close_window (); + + return k; +} + +/** + * Display a message box with buttons. + * This function displays the specified message in a text box + * centered in the screen and waits until a button is pressed. + * @param p The text to be displayed + * @param b NULL-terminated list of button labels + */ +int selection_box (char *m, char **b) +{ + int x, y, i, s; + int key, active = 0; + int rc = -1; + int bx[5], by[5]; + + erase_both (); + blit_textbox (m, -1, -1, -1); + + x = game.window.x1 + 5 * CHAR_COLS / 2; + y = game.window.y2 - 5 * CHAR_LINES / 2; + s = game.window.x2 - game.window.x1 + 1 - 5 * CHAR_COLS; + _D ("s = %d", s); + + /* Automatically position buttons */ + for (i = 0; b[i]; i++) { + s -= CHAR_COLS * strlen (b[i]); + } + + if (i > 1) { + _D ("s / %d = %d", i - 1, s / (i - 1)); + s /= (i - 1); + } else { + x += s / 2; + } + + for (i = 0; b[i]; i++) { + bx[i] = x; + by[i] = y; + x += CHAR_COLS * strlen (b[i]) + s; + } + + blit_both (); + + /* clear key queue */ + while (keypress ()) { get_key (); } + + _D (_D_WARN "waiting..."); + while (42) { + for (i = 0; b[i]; i++) + draw_button (bx[i], by[i], b[i], i == active, 0); + + poll_timer (); /* msdos driver -> does nothing */ + key = do_poll_keyboard (); + if (!console_keyhandler (key)) { + switch (key) { + case KEY_ENTER: + rc = active; + goto press; + case KEY_ESCAPE: + rc = -1; + goto getout; +#ifdef USE_MOUSE + case BUTTON_LEFT: + for (i = 0; b[i]; i++) { + if (test_button (bx[i], by[i], b[i])) { + rc = active = i; + goto press; + } + } + break; +#endif + case 0x09: /* Tab */ + _D ("Focus change"); + active++; + active %= i; + break; + } + } + console_cycle (); + } + +press: + _D (_D_WARN "Button pressed: %d", rc); + +getout: + close_window (); + _D (_D_WARN "Result = %d", rc); + + return rc; +} + +/** + * + */ +int print (char *p, int lin, int col, int len) +{ + if (p == NULL) + return 0; + + _D (_D_WARN "lin = %d, col = %d, len = %d", lin, col, len); + + if (col == 0 && lin == 0 && len == 0) + lin = col = -1; + + if (len == 0) + len = 30; + + blit_textbox (p, lin, col, len); + + if (getflag (F_output_mode)) { + /* non-blocking window */ + setflag (F_output_mode, FALSE); + return 1; + } + + /* blocking */ + + if (game.vars[V_window_reset] == 0) { + int k; + setvar (V_key, 0); + k = wait_key(); + close_window (); + return k; + } + + /* timed window */ + + _D (_D_WARN "f15==0, v21==%d => timed", getvar (21)); + game.msg_box_ticks = getvar (V_window_reset) * 10; + setvar (V_key, 0); + + do { + main_cycle (); + if (game.keypress == KEY_ENTER) { + _D (_D_WARN "KEY_ENTER"); + setvar (V_window_reset, 0); + game.keypress = 0; + break; + } + } while (game.msg_box_ticks > 0); + + setvar (V_window_reset, 0); + + close_window (); + + return 0; +} + +/** + * + */ +static void print_status (char *message, ...) +{ + char x[42]; + va_list args; + + va_start (args, message); + +#ifdef HAVE_VSNPRINTF + vsnprintf (x, 41, message, args); +#else + vsprintf (x, message, args); +#endif + + va_end (args); + + _D (_D_WARN "fg=%d, bg=%d", STATUS_FG, STATUS_BG); + print_text (x, 0, 0, game.line_status, 40, STATUS_FG, STATUS_BG); +} + + +static char *safe_strcat (char *s, const char *t) +{ + if (t != NULL) + strcat (s, t); + + return s; +} + + +/** + * Formats AGI string. + * This function turns a AGI string into a real string expanding values + * according to the AGI format specifiers. + * @param s string containing the format specifier + * @param n logic number + */ +#define MAX_LEN 768 +char *agi_sprintf (char *s) +{ + static char y[MAX_LEN]; + char x[MAX_LEN]; + char z[16], *p; + + _D ("logic %d, '%s'", game.lognum, s); + p = x; + + for (*p = 0; *s; ) { + switch (*s) { + case '\\': + s++; + goto literal; + case '%': + s++; + switch (*s++) { + int i; + case 'v': + i = strtoul (s, NULL, 10); + while (*s >= '0' && *s <= '9') + s++; + sprintf (z, "%015i", getvar(i)); + + i = 99; + if (*s == '|') { + s++; + i = strtoul (s, NULL, 10); + while (*s >= '0' && *s <= '9') + s++; + } + + if (i == 99) { + /* remove all leading 0 */ + /* don't remove the 3rd zero if 000 */ + for (i = 0; z[i] == '0' && i < 14; i++); + } else { + i = 15 - i; + } + safe_strcat(p, z + i); + break; + case '0': + i = strtoul (s, NULL, 10) - 1; + safe_strcat(p, object_name(i)); + break; + case 'g': + i = strtoul (s, NULL, 10) - 1; + safe_strcat(p, game.logics[0].texts[i]); + break; + case 'w': + i = strtoul (s, NULL, 10) - 1; + safe_strcat(p, game.ego_words[i].word); + break; + case 's': + i = strtoul (s, NULL, 10); + safe_strcat(p, game.strings[i]); + break; + case 'm': + i = strtoul (s, NULL, 10) - 1; + if (game.logics[game.lognum].num_texts > i) + safe_strcat(p, agi_sprintf(game.logics[game.lognum].texts[i])); + break; + } + + while (*s >= '0' && *s <= '9') s++; + while (*p) p++; + break; + + default: + literal: + assert (p < x + MAX_LEN); + *p++ = *s++; + *p = 0; + break; + } + } + + strcpy (y, x); + return y; +} + +/** + * Write the status line. + */ +void write_status () +{ + char x[64]; + +#ifdef USE_CONSOLE + if (debug.statusline) { +#ifdef USE_MOUSE + print_status ("%3d(%03d) %3d,%3d(%3d,%3d) ", + getvar (0), getvar (1), + game.view_table[0].x_pos, + game.view_table[0].y_pos, + WIN_TO_PIC_X(mouse.x), WIN_TO_PIC_Y(mouse.y)); +#else + print_status ("%3d(%03d) %3d,%3d ", + getvar (0), getvar (1), + game.view_table[0].x_pos, + game.view_table[0].y_pos); +#endif + return; + } +#endif /* USE_CONSOLE */ + + if (!game.status_line) { + int l = game.line_status; + clear_lines (l, l, 0); + flush_lines (l, l); + return; + } + + sprintf (x, " Score:%i of %-3i", game.vars[V_score], + game.vars[V_max_score]); + print_status ("%-17s Sound:%s ", x, + getflag (F_sound_on) ? "on " : "off"); +} + +/** + * Print user input prompt. + */ +void write_prompt () +{ + int l, fg, bg, pos; + + if (!game.input_enabled || game.input_mode != INPUT_NORMAL) + return; + + l = game.line_user_input; + fg = game.color_fg; + bg = game.color_bg; + pos = game.cursor_pos; + + _D (_D_WARN "erase line %d", l); + clear_lines (l, l, game.color_bg); + + _D (_D_WARN "prompt = '%s'", agi_sprintf (game.strings[0])); + print_text (game.strings[0], 0, 0, l, 1, fg, bg); + print_text (game.input_buffer, 0, 1, l, pos + 1, fg, bg); + print_character (pos + 1, l, game.cursor_char, fg, bg); + + flush_lines (l, l); + do_update (); +} + +/** + * Clear text lines in the screen. + * @param l1 start line + * @param l2 end line + * @param c color + */ +void clear_lines (int l1, int l2, int c) +{ + /* do we need to adjust for +8 on topline? + * inc for endline so it matches the correct num + * ie, from 22 to 24 is 3 lines, not 2 lines. + */ + + l1 *= CHAR_LINES; + l2 *= CHAR_LINES; + l2 += CHAR_LINES - 1; + + draw_rectangle (0, l1, GFX_WIDTH - 1, l2, c); +} + +/** + * + */ +void flush_lines (int l1, int l2) +{ + l1 *= CHAR_LINES; + l2 *= CHAR_LINES; + l2 += CHAR_LINES - 1; + + flush_block (0, l1, GFX_WIDTH - 1, l2); +} + +/** + * + */ +void draw_window (int x1, int y1, int x2, int y2) +{ + game.window.active = TRUE; + game.window.x1 = x1; + game.window.y1 = y1; + game.window.x2 = x2; + game.window.y2 = y2; + game.window.buffer = malloc ((x2 - x1 + 1) * (y2 - y1 + 1)); + + _D (_D_WARN "x1=%d, y1=%d, x2=%d, y2=%d", x1, y1, x2, y2); + save_block (x1, y1, x2, y2, game.window.buffer); + draw_box (x1, y1, x2, y2, MSG_BOX_COLOUR, MSG_BOX_LINE, 2); +} + +/* end: text.c */ diff --git a/view.c b/view.c index 6b31ae2..96996d8 100644 --- a/view.c +++ b/view.c @@ -1,397 +1,397 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka - * - * $Id: view.c,v 1.52 2003/10/16 22:15:51 bootstrap666 Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "sprite.h" - - -static void _set_cel (struct vt_entry *v, int n) -{ - struct view_loop *current_vl; - struct view_cel *current_vc; - - v->current_cel = n; - current_vl = &game.views[v->current_view].loop[v->current_loop]; - - /* Added by Amit Vainsencher to prevent - * crash in KQ1 -- not in the Sierra interpreter - */ - if(current_vl->num_cels == 0) - return; - - if (!(v->flags & UPDATE)&&(agi_get_release() >= 0x3000)) - return; - - current_vc = ¤t_vl->cel[n]; - v->cel_data = current_vc; - v->x_size = current_vc->width; - v->y_size = current_vc->height; -} - -static void _set_loop (struct vt_entry *v, int n) -{ - struct view_loop *current_vl; - /* _D ("vt entry #%d, loop = %d", v->entry, n); */ - - /* Added to avoid crash when leaving the arcade machine in MH1 - * -- not in AGI 2.917 - */ - if (n >= v->num_loops) - n = 0; - - v->current_loop = n; - current_vl = &game.views[v->current_view].loop[v->current_loop]; - - v->num_cels = current_vl->num_cels; - if (v->current_cel >= v->num_cels) - v->current_cel = 0; - - if (!(v->flags & UPDATE)&&(agi_get_release() >= 0x3000)) - return; - - v->loop_data = &game.views[v->current_view].loop[n]; -} - -static void update_view (struct vt_entry *v) -{ - int cel, last_cel; - - if (v->flags & DONTUPDATE) { - v->flags &= ~DONTUPDATE; - return; - } - - cel = v->current_cel; - last_cel = v->num_cels - 1; - - switch (v->cycle) { - case CYCLE_NORMAL: - if (++cel > last_cel) - cel = 0; - break; - case CYCLE_END_OF_LOOP: - if (cel < last_cel) { - _D ("cel %d (last = %d)", cel + 1, last_cel); - if (++cel != last_cel) - break; - } - setflag (v->parm1, TRUE); - v->flags &= ~CYCLING; - v->direction = 0; - v->cycle = CYCLE_NORMAL; - break; - case CYCLE_REV_LOOP: - if (cel) { - if (--cel) - break; - } - setflag (v->parm1, TRUE); - v->flags &= ~CYCLING; - v->direction = 0; - v->cycle = CYCLE_NORMAL; - break; - case CYCLE_REVERSE: - if (cel == 0) { - cel = last_cel; - } else { - cel--; - } - break; - } - - set_cel (v, cel); -} - -/* - * Public functions - */ - -/** - * Decode an AGI view resource. - * This function decodes the raw data of the specified AGI view resource - * and fills the corresponding views array element. - * @param n number of view resource to decode - */ -int decode_view (int n) -{ - int loop, cel; - UINT8 *v, *lptr; - UINT16 lofs, cofs; - struct view_loop *vl; - struct view_cel *vc; - - _D ("(%d)", n); - v = game.views[n].rdata; - - assert (v != NULL); - - game.views[n].descr = lohi_getword (v + 3) ? - (char*)(v + lohi_getword (v + 3)) : (char*)(v+3); - - /* if no loops exist, return! */ - if ((game.views[n].num_loops = lohi_getbyte (v + 2)) == 0) - return err_NoLoopsInView; - - /* allocate memory for all views */ - game.views[n].loop = - calloc (game.views[n].num_loops, sizeof(struct view_loop)); - - if (game.views[n].loop == NULL) - return err_NotEnoughMemory; - - /* decode all of the loops in this view */ - lptr = v + 5; /* first loop address */ - - for (loop = 0; loop < game.views[n].num_loops; loop++, lptr += 2) { - lofs = lohi_getword (lptr); /* loop header offset */ - vl = &game.views[n].loop[loop]; /* the loop struct */ - - vl->num_cels = lohi_getbyte (v + lofs); - _D(_D_WARN "view %d, num_cels = %d", n, vl->num_cels); - vl->cel = calloc (vl->num_cels, sizeof (struct view_cel)); - if (vl->cel == NULL) { - free (game.views[n].loop); - game.views[n].num_loops = 0; - return err_NotEnoughMemory; - } - - /* decode the cells */ - for (cel = 0; cel < vl->num_cels; cel++) { - cofs = lofs + lohi_getword (v + lofs + 1 + (cel * 2)); - vc = &vl->cel[cel]; - - vc->width = lohi_getbyte (v + cofs); - vc->height = lohi_getbyte (v + cofs + 1); - vc->transparency = lohi_getbyte (v + cofs + 2) & 0xf; - vc->mirror_loop = (lohi_getbyte (v + cofs + 2) >>4) & 0x7; - vc->mirror = (lohi_getbyte (v + cofs + 2) >> 7) & 0x1; - - /* skip over width/height/trans|mirror data */ - cofs += 3; - - vc->data = v+cofs; - /* If mirror_loop is pointing to the current loop, - * then this is the original. - */ - if (vc->mirror_loop == loop) - vc->mirror = 0; - } /* cel */ - } /* loop */ - - return err_OK; -} - -/** - * Unloads all data in a view resource - * @param n number of view resource - */ -void unload_view (int n) -{ - int x; - - _D("discard view %d", n); - if (~game.dir_view[n].flags & RES_LOADED) - return; - - /* Rebuild sprite list, see bug #779302 */ - erase_both(); - blit_both(); - commit_both(); - - /* free all the loops */ - for (x = 0; x < game.views[n].num_loops; x++) - free (game.views[n].loop[x].cel); - - free (game.views[n].loop); - free (game.views[n].rdata); - - game.dir_view[n].flags &= ~RES_LOADED; -} - -/** - * Set a view table entry to use the specified cel of the current loop. - * @param v pointer to view table entry - * @param n number of cel - */ -void set_cel (struct vt_entry *v, int n) -{ - assert (v->view_data != NULL); - assert (v->num_cels >= n); - - _set_cel (v, n); - - /* If position isn't appropriate, update it accordingly */ - if (v->x_pos + v->x_size > _WIDTH) { - v->flags |= UPDATE_POS; - v->x_pos = _WIDTH - v->x_size; - } - if (v->y_pos - v->y_size + 1 < 0) { - v->flags |= UPDATE_POS; - v->y_pos = v->y_size - 1; - } - if (v->y_pos <= game.horizon && (~v->flags & IGNORE_HORIZON)) { - v->flags |= UPDATE_POS; - v->y_pos = game.horizon + 1; - } -} - -/** - * Set a view table entry to use the specified loop of the current view. - * @param v pointer to view table entry - * @param n number of loop - */ -void set_loop (struct vt_entry *v, int n) -{ - assert (v->view_data != NULL); - assert (v->num_loops >= n); - _set_loop (v, n); - set_cel (v, v->current_cel); -} - -/** - * Set a view table entry to use the specified view resource. - * @param v pointer to view table entry - * @param n number of AGI view resource - */ -void set_view (struct vt_entry *v, int n) -{ - v->view_data = &game.views[n]; - v->current_view = n; - v->num_loops = v->view_data->num_loops; - set_loop (v, v->current_loop >= v->num_loops ? 0 : v->current_loop); -} - -/** - * Set the view table entry as updating. - * @param v pointer to view table entry - */ -void start_update (struct vt_entry *v) -{ - if (~v->flags & UPDATE) { - erase_both (); - v->flags |= UPDATE; - blit_both (); - } -} - -/** - * Set the view table entry as non-updating. - * @param v pointer to view table entry - */ -void stop_update (struct vt_entry *v) -{ - if (v->flags & UPDATE) { - erase_both (); - v->flags &= ~UPDATE; - blit_both (); - } -} - - -/* loops to use according to direction and number of loops in - * the view resource - */ -static int loop_table_2[] = { - 0x04, 0x04, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x01 -}; - -static int loop_table_4[] = { - 0x04, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x01 -}; - -/** - * Update view table entries. - * This function is called at the end of each interpreter cycle - * to update the view table entries and blit the sprites. - */ -void update_viewtable () -{ - struct vt_entry *v; - int i, loop; - - i = 0; - for_each_vt_entry(v) { - if ((v->flags & (ANIMATED|UPDATE|DRAWN)) != - (ANIMATED|UPDATE|DRAWN)) - { - continue; - } - - i++; - - loop = 4; - if (~v->flags & FIX_LOOP) { - switch (v->num_loops) { - case 2: - case 3: - loop = loop_table_2[v->direction]; - break; - case 4: - loop = loop_table_4[v->direction]; - break; - default: - /* for KQ4 */ - if (agi_get_release () == 0x3086) - loop = loop_table_4[v->direction]; - break; - } - } - - /* AGI 2.272 (ddp, xmas) doesn't test step_time_count! */ - if (loop != 4 && loop != v->current_loop) { - if (agi_get_release() <= 0x2272 || - v->step_time_count == 1) { - set_loop (v, loop); - } - } - - if (~v->flags & CYCLING) - continue; - - if (v->cycle_time_count == 0) - continue; - - if (--v->cycle_time_count == 0) { - update_view (v); - v->cycle_time_count = v->cycle_time; - } - } - - if (i) { -#ifdef USE_CONSOLE - /* To correctly update sprites when we use the console - * we must work with all sprites. - */ - if (console.y > 0) { - erase_both (); - update_position (); - blit_both (); - commit_both (); - } else -#endif - /* If we're not using the console, updating only - * the active sprites lets us save some CPU cycles. - * This is how the original Sierra AGI works. - */ - { - erase_upd_sprites (); - update_position (); - blit_upd_sprites (); - commit_upd_sprites (); - } - - game.view_table[0].flags &= ~(ON_WATER|ON_LAND); - } -} - -/* end: view.c */ +/* Sarien - A Sierra AGI resource interpreter engine + * Copyright (C) 1999-2003 Stuart George and Claudio Matsuoka + * + * $Id: view.c,v 1.52 2003/10/16 22:15:51 bootstrap666 Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; see docs/COPYING for further details. + */ + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "sprite.h" + + +static void _set_cel (struct vt_entry *v, int n) +{ + struct view_loop *current_vl; + struct view_cel *current_vc; + + v->current_cel = n; + current_vl = &game.views[v->current_view].loop[v->current_loop]; + + /* Added by Amit Vainsencher to prevent + * crash in KQ1 -- not in the Sierra interpreter + */ + if(current_vl->num_cels == 0) + return; + + if (!(v->flags & UPDATE)&&(agi_get_release() >= 0x3000)) + return; + + current_vc = ¤t_vl->cel[n]; + v->cel_data = current_vc; + v->x_size = current_vc->width; + v->y_size = current_vc->height; +} + +static void _set_loop (struct vt_entry *v, int n) +{ + struct view_loop *current_vl; + /* _D ("vt entry #%d, loop = %d", v->entry, n); */ + + /* Added to avoid crash when leaving the arcade machine in MH1 + * -- not in AGI 2.917 + */ + if (n >= v->num_loops) + n = 0; + + v->current_loop = n; + current_vl = &game.views[v->current_view].loop[v->current_loop]; + + v->num_cels = current_vl->num_cels; + if (v->current_cel >= v->num_cels) + v->current_cel = 0; + + if (!(v->flags & UPDATE)&&(agi_get_release() >= 0x3000)) + return; + + v->loop_data = &game.views[v->current_view].loop[n]; +} + +static void update_view (struct vt_entry *v) +{ + int cel, last_cel; + + if (v->flags & DONTUPDATE) { + v->flags &= ~DONTUPDATE; + return; + } + + cel = v->current_cel; + last_cel = v->num_cels - 1; + + switch (v->cycle) { + case CYCLE_NORMAL: + if (++cel > last_cel) + cel = 0; + break; + case CYCLE_END_OF_LOOP: + if (cel < last_cel) { + _D ("cel %d (last = %d)", cel + 1, last_cel); + if (++cel != last_cel) + break; + } + setflag (v->parm1, TRUE); + v->flags &= ~CYCLING; + v->direction = 0; + v->cycle = CYCLE_NORMAL; + break; + case CYCLE_REV_LOOP: + if (cel) { + if (--cel) + break; + } + setflag (v->parm1, TRUE); + v->flags &= ~CYCLING; + v->direction = 0; + v->cycle = CYCLE_NORMAL; + break; + case CYCLE_REVERSE: + if (cel == 0) { + cel = last_cel; + } else { + cel--; + } + break; + } + + set_cel (v, cel); +} + +/* + * Public functions + */ + +/** + * Decode an AGI view resource. + * This function decodes the raw data of the specified AGI view resource + * and fills the corresponding views array element. + * @param n number of view resource to decode + */ +int decode_view (int n) +{ + int loop, cel; + UINT8 *v, *lptr; + UINT16 lofs, cofs; + struct view_loop *vl; + struct view_cel *vc; + + _D ("(%d)", n); + v = game.views[n].rdata; + + assert (v != NULL); + + game.views[n].descr = lohi_getword (v + 3) ? + (char*)(v + lohi_getword (v + 3)) : (char*)(v+3); + + /* if no loops exist, return! */ + if ((game.views[n].num_loops = lohi_getbyte (v + 2)) == 0) + return err_NoLoopsInView; + + /* allocate memory for all views */ + game.views[n].loop = + calloc (game.views[n].num_loops, sizeof(struct view_loop)); + + if (game.views[n].loop == NULL) + return err_NotEnoughMemory; + + /* decode all of the loops in this view */ + lptr = v + 5; /* first loop address */ + + for (loop = 0; loop < game.views[n].num_loops; loop++, lptr += 2) { + lofs = lohi_getword (lptr); /* loop header offset */ + vl = &game.views[n].loop[loop]; /* the loop struct */ + + vl->num_cels = lohi_getbyte (v + lofs); + _D(_D_WARN "view %d, num_cels = %d", n, vl->num_cels); + vl->cel = calloc (vl->num_cels, sizeof (struct view_cel)); + if (vl->cel == NULL) { + free (game.views[n].loop); + game.views[n].num_loops = 0; + return err_NotEnoughMemory; + } + + /* decode the cells */ + for (cel = 0; cel < vl->num_cels; cel++) { + cofs = lofs + lohi_getword (v + lofs + 1 + (cel * 2)); + vc = &vl->cel[cel]; + + vc->width = lohi_getbyte (v + cofs); + vc->height = lohi_getbyte (v + cofs + 1); + vc->transparency = lohi_getbyte (v + cofs + 2) & 0xf; + vc->mirror_loop = (lohi_getbyte (v + cofs + 2) >>4) & 0x7; + vc->mirror = (lohi_getbyte (v + cofs + 2) >> 7) & 0x1; + + /* skip over width/height/trans|mirror data */ + cofs += 3; + + vc->data = v+cofs; + /* If mirror_loop is pointing to the current loop, + * then this is the original. + */ + if (vc->mirror_loop == loop) + vc->mirror = 0; + } /* cel */ + } /* loop */ + + return err_OK; +} + +/** + * Unloads all data in a view resource + * @param n number of view resource + */ +void unload_view (int n) +{ + int x; + + _D("discard view %d", n); + if (~game.dir_view[n].flags & RES_LOADED) + return; + + /* Rebuild sprite list, see bug #779302 */ + erase_both(); + blit_both(); + commit_both(); + + /* free all the loops */ + for (x = 0; x < game.views[n].num_loops; x++) + free (game.views[n].loop[x].cel); + + free (game.views[n].loop); + free (game.views[n].rdata); + + game.dir_view[n].flags &= ~RES_LOADED; +} + +/** + * Set a view table entry to use the specified cel of the current loop. + * @param v pointer to view table entry + * @param n number of cel + */ +void set_cel (struct vt_entry *v, int n) +{ + assert (v->view_data != NULL); + assert (v->num_cels >= n); + + _set_cel (v, n); + + /* If position isn't appropriate, update it accordingly */ + if (v->x_pos + v->x_size > _WIDTH) { + v->flags |= UPDATE_POS; + v->x_pos = _WIDTH - v->x_size; + } + if (v->y_pos - v->y_size + 1 < 0) { + v->flags |= UPDATE_POS; + v->y_pos = v->y_size - 1; + } + if (v->y_pos <= game.horizon && (~v->flags & IGNORE_HORIZON)) { + v->flags |= UPDATE_POS; + v->y_pos = game.horizon + 1; + } +} + +/** + * Set a view table entry to use the specified loop of the current view. + * @param v pointer to view table entry + * @param n number of loop + */ +void set_loop (struct vt_entry *v, int n) +{ + assert (v->view_data != NULL); + assert (v->num_loops >= n); + _set_loop (v, n); + set_cel (v, v->current_cel); +} + +/** + * Set a view table entry to use the specified view resource. + * @param v pointer to view table entry + * @param n number of AGI view resource + */ +void set_view (struct vt_entry *v, int n) +{ + v->view_data = &game.views[n]; + v->current_view = n; + v->num_loops = v->view_data->num_loops; + set_loop (v, v->current_loop >= v->num_loops ? 0 : v->current_loop); +} + +/** + * Set the view table entry as updating. + * @param v pointer to view table entry + */ +void start_update (struct vt_entry *v) +{ + if (~v->flags & UPDATE) { + erase_both (); + v->flags |= UPDATE; + blit_both (); + } +} + +/** + * Set the view table entry as non-updating. + * @param v pointer to view table entry + */ +void stop_update (struct vt_entry *v) +{ + if (v->flags & UPDATE) { + erase_both (); + v->flags &= ~UPDATE; + blit_both (); + } +} + + +/* loops to use according to direction and number of loops in + * the view resource + */ +static int loop_table_2[] = { + 0x04, 0x04, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x01 +}; + +static int loop_table_4[] = { + 0x04, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x01 +}; + +/** + * Update view table entries. + * This function is called at the end of each interpreter cycle + * to update the view table entries and blit the sprites. + */ +void update_viewtable () +{ + struct vt_entry *v; + int i, loop; + + i = 0; + for_each_vt_entry(v) { + if ((v->flags & (ANIMATED|UPDATE|DRAWN)) != + (ANIMATED|UPDATE|DRAWN)) + { + continue; + } + + i++; + + loop = 4; + if (~v->flags & FIX_LOOP) { + switch (v->num_loops) { + case 2: + case 3: + loop = loop_table_2[v->direction]; + break; + case 4: + loop = loop_table_4[v->direction]; + break; + default: + /* for KQ4 */ + if (agi_get_release () == 0x3086) + loop = loop_table_4[v->direction]; + break; + } + } + + /* AGI 2.272 (ddp, xmas) doesn't test step_time_count! */ + if (loop != 4 && loop != v->current_loop) { + if (agi_get_release() <= 0x2272 || + v->step_time_count == 1) { + set_loop (v, loop); + } + } + + if (~v->flags & CYCLING) + continue; + + if (v->cycle_time_count == 0) + continue; + + if (--v->cycle_time_count == 0) { + update_view (v); + v->cycle_time_count = v->cycle_time; + } + } + + if (i) { +#ifdef USE_CONSOLE + /* To correctly update sprites when we use the console + * we must work with all sprites. + */ + if (console.y > 0) { + erase_both (); + update_position (); + blit_both (); + commit_both (); + } else +#endif + /* If we're not using the console, updating only + * the active sprites lets us save some CPU cycles. + * This is how the original Sierra AGI works. + */ + { + erase_upd_sprites (); + update_position (); + blit_upd_sprites (); + commit_upd_sprites (); + } + + game.view_table[0].flags &= ~(ON_WATER|ON_LAND); + } +} + +/* end: view.c */ diff --git a/words.c b/words.c index 2a84792..dc166f7 100644 --- a/words.c +++ b/words.c @@ -1,346 +1,346 @@ -/* Sarien - A Sierra AGI resource interpreter engine - * Copyright (C) 1999-2002 Stuart George and Claudio Matsuoka - * - * $Id: words.c,v 1.35 2003/08/26 00:53:16 cmatsuoka Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; see docs/COPYING for further details. - */ - -/* - * New find_word algorithm by Thomas Akesson - */ - -#include -#include -#include "sarien.h" -#include "agi.h" -#include "keyboard.h" /* for clean_input() */ - -static UINT8 *words; /* words in the game */ -static UINT32 words_flen; /* length of word memory */ - - -/* - * Local implementation to avoid problems with strndup() used by - * gcc 3.2 Cygwin (see #635984) - */ -static char *my_strndup (char* src, int n) -{ - char *tmp = strncpy (malloc(n + 1), src, n); - tmp[n] = 0; - return tmp; -} - - -int load_words (char *fname) -{ -#ifndef PALMOS - FILE *fp = NULL; - UINT32 flen; - UINT8 *mem = NULL; - char *path = NULL; - - words = NULL; - - path = fixpath (NO_GAMEDIR, fname); - - if ((fp = fopen(path, "rb")) == NULL) { - report ("Warning: can't open %s\n", path); - return err_OK /*err_BadFileOpen*/; - } - report ("Loading dictionary: %s\n", path); - - fseek (fp, 0, SEEK_END); - flen = ftell (fp); - fseek (fp, 0, SEEK_SET); - words_flen = flen; - - if ((mem = (UINT8*)calloc(1, flen + 32)) == NULL) { - fclose (fp); - return err_NotEnoughMemory; - } - - fread (mem, 1, flen, fp); - fclose (fp); - - words = mem; - - return err_OK; -#endif -} - - -void unload_words () -{ - if (words != NULL) { - free (words); - words = NULL; - } -} - - -/** - * Find a word in the dictionary - * Uses an algorithm hopefully like the one Sierra used. Returns the ID - * of the word and the length in flen. Returns -1 if not found. - * - * Thomas Åkesson, November 2001 - */ -int find_word (char *word, int *flen) -{ - int mchr = 0; /* matched chars */ - int len, fchr, id = -1; - UINT8* p = words; - UINT8* q = words + words_flen; - *flen = 0; - - _D ("%s", word); - if (word[0] >= 'a' && word[0] <= 'z') - fchr = word[0] - 'a'; - else - return -1; - - len = strlen (word); - - /* Get the offset to the first word beginning with the - * right character - */ - p += hilo_getword (p + 2 * fchr); - - while (p[0] >= mchr) { - if (p[0] == mchr) { - p++; - /* Loop through all matching characters */ - while ((p[0] ^ word[mchr]) == 0x7F && mchr < len) { - mchr++; - p++; - } - /* Check if this is the last character of the word - * and if it matches - */ - if ((p[0] ^ word[mchr]) == 0xFF && mchr < len) { - mchr++; - if (word[mchr] == 0 || word[mchr] == 0x20) { - id = hilo_getword (p+1); - *flen = mchr; - } - } - } - if (p >= q) - return -1; - - /* Step to the next word */ - while (p[0] < 0x80) - p++; - p += 3; - } - - return id; -} - - -void dictionary_words (char *msg) -{ - char *p = NULL; - char *q = NULL; - int wid, wlen; - - _D ("msg = \"%s\"", msg); - - clean_input (); - - for (p = msg; p && *p && getvar (V_word_not_found) == 0; ) { - if (*p == 0x20) - p++; - - if (*p == 0) - break; - - wid = find_word(p, &wlen); - _D ("find_word(p) == %d", wid); - - switch (wid) { - case -1: - _D (_D_WARN "unknown word"); - game.ego_words[game.num_ego_words].word = strdup(p); - q = game.ego_words[game.num_ego_words].word; - game.ego_words[game.num_ego_words].id = 19999; - setvar(V_word_not_found, 1 + game.num_ego_words); - game.num_ego_words++; - p += strlen (p); - break; - case 0: - /* ignore this word */ - _D (_D_WARN "ignore word"); - p += wlen; - q = NULL; - break; - default: - /* an OK word */ - /* _D (_D_WARN "ok word (%d)", wc1); */ - game.ego_words[game.num_ego_words].id = wid; - game.ego_words[game.num_ego_words].word = my_strndup(p, wlen); - game.num_ego_words++; - p += wlen; - break; - } - - if (p != NULL && *p) { - _D ("p = %s", p); - *p = 0; - p++; - } - - if (q != NULL) { - for (; (*q!=0 && *q!=0x20); q++); - if (*q) { - *q=0; - q++; - } - } - } - - _D (_D_WARN "num_ego_words = %d", game.num_ego_words); - if (game.num_ego_words > 0) { - setflag (F_entered_cli, TRUE); - setflag (F_said_accepted_input, FALSE); - } -} - -#ifdef OPT_LIST_DICT -int show_words () -{ -/* - decode *words into words! -*/ - - int sc, wc, woff, wid; - unsigned char x[128]; - unsigned char c; - int num_words; - - num_words=0; - - /* scan for first entry with words */ - for (wc = woff = 0; woff == 0 && woff < words_flen; wc += 2) - woff = hilo_getword(words+wc); - - /* AGDS cludge for bad word file :( */ - if(woff > words_flen) - return err_OK; - - /* count all the words in the list */ - for(sc=0, wc=0; woff 0x80) { - wc++; - wid = hilo_getword (words+woff); - woff += 2; - if(wid > sc && wid != 9999) - sc = wid; - } - } - num_words = wc; - - /* scan for frist words entry */ - for(wc=0, woff=0; woff==0; wc+=2) - woff=hilo_getword(words+wc); - - /* build word list */ - for(wc=0; wc -extern s9_t sarien_s9; -void add_s9_words () -{ -/* - from show_words -*/ - - int sc, wc, woff, wid; - unsigned char x[128]; - unsigned char c; - int num_words; - static char **allocated_words; - static int num_allocated_words; - - num_words=0; - - /* scan for first entry with words */ - for (wc = woff = 0; woff == 0 && woff < words_flen; wc += 2) - woff = hilo_getword(words+wc); - - /* AGDS cludge for bad word file :( */ - if(woff > words_flen) - return; - - /* count all the words in the list */ - for(sc=0, wc=0; woff 0x80) { - wc++; - wid = hilo_getword (words+woff); - woff += 2; - if(wid > sc && wid != 9999) - sc = wid; - } - } - num_words = wc; - if (allocated_words != NULL) - { - int i; - - for (i = 0; i < num_allocated_words; i++) - free( allocated_words[i] ); - free(allocated_words); - } - allocated_words = malloc(sizeof(char*) * num_words); - num_allocated_words = num_words; - - /* scan for frist words entry */ - for(wc=0, woff=0; woff==0; wc+=2) - woff=hilo_getword(words+wc); - - /* build word list */ - for(wc=0; wc + */ + +#include +#include +#include "sarien.h" +#include "agi.h" +#include "keyboard.h" /* for clean_input() */ + +static UINT8 *words; /* words in the game */ +static UINT32 words_flen; /* length of word memory */ + + +/* + * Local implementation to avoid problems with strndup() used by + * gcc 3.2 Cygwin (see #635984) + */ +static char *my_strndup (char* src, int n) +{ + char *tmp = strncpy (malloc(n + 1), src, n); + tmp[n] = 0; + return tmp; +} + + +int load_words (char *fname) +{ +#ifndef PALMOS + FILE *fp = NULL; + UINT32 flen; + UINT8 *mem = NULL; + char *path = NULL; + + words = NULL; + + path = fixpath (NO_GAMEDIR, fname); + + if ((fp = fopen(path, "rb")) == NULL) { + report ("Warning: can't open %s\n", path); + return err_OK /*err_BadFileOpen*/; + } + report ("Loading dictionary: %s\n", path); + + fseek (fp, 0, SEEK_END); + flen = ftell (fp); + fseek (fp, 0, SEEK_SET); + words_flen = flen; + + if ((mem = (UINT8*)calloc(1, flen + 32)) == NULL) { + fclose (fp); + return err_NotEnoughMemory; + } + + fread (mem, 1, flen, fp); + fclose (fp); + + words = mem; + + return err_OK; +#endif +} + + +void unload_words () +{ + if (words != NULL) { + free (words); + words = NULL; + } +} + + +/** + * Find a word in the dictionary + * Uses an algorithm hopefully like the one Sierra used. Returns the ID + * of the word and the length in flen. Returns -1 if not found. + * + * Thomas Åkesson, November 2001 + */ +int find_word (char *word, int *flen) +{ + int mchr = 0; /* matched chars */ + int len, fchr, id = -1; + UINT8* p = words; + UINT8* q = words + words_flen; + *flen = 0; + + _D ("%s", word); + if (word[0] >= 'a' && word[0] <= 'z') + fchr = word[0] - 'a'; + else + return -1; + + len = strlen (word); + + /* Get the offset to the first word beginning with the + * right character + */ + p += hilo_getword (p + 2 * fchr); + + while (p[0] >= mchr) { + if (p[0] == mchr) { + p++; + /* Loop through all matching characters */ + while ((p[0] ^ word[mchr]) == 0x7F && mchr < len) { + mchr++; + p++; + } + /* Check if this is the last character of the word + * and if it matches + */ + if ((p[0] ^ word[mchr]) == 0xFF && mchr < len) { + mchr++; + if (word[mchr] == 0 || word[mchr] == 0x20) { + id = hilo_getword (p+1); + *flen = mchr; + } + } + } + if (p >= q) + return -1; + + /* Step to the next word */ + while (p[0] < 0x80) + p++; + p += 3; + } + + return id; +} + + +void dictionary_words (char *msg) +{ + char *p = NULL; + char *q = NULL; + int wid, wlen; + + _D ("msg = \"%s\"", msg); + + clean_input (); + + for (p = msg; p && *p && getvar (V_word_not_found) == 0; ) { + if (*p == 0x20) + p++; + + if (*p == 0) + break; + + wid = find_word(p, &wlen); + _D ("find_word(p) == %d", wid); + + switch (wid) { + case -1: + _D (_D_WARN "unknown word"); + game.ego_words[game.num_ego_words].word = strdup(p); + q = game.ego_words[game.num_ego_words].word; + game.ego_words[game.num_ego_words].id = 19999; + setvar(V_word_not_found, 1 + game.num_ego_words); + game.num_ego_words++; + p += strlen (p); + break; + case 0: + /* ignore this word */ + _D (_D_WARN "ignore word"); + p += wlen; + q = NULL; + break; + default: + /* an OK word */ + /* _D (_D_WARN "ok word (%d)", wc1); */ + game.ego_words[game.num_ego_words].id = wid; + game.ego_words[game.num_ego_words].word = my_strndup(p, wlen); + game.num_ego_words++; + p += wlen; + break; + } + + if (p != NULL && *p) { + _D ("p = %s", p); + *p = 0; + p++; + } + + if (q != NULL) { + for (; (*q!=0 && *q!=0x20); q++); + if (*q) { + *q=0; + q++; + } + } + } + + _D (_D_WARN "num_ego_words = %d", game.num_ego_words); + if (game.num_ego_words > 0) { + setflag (F_entered_cli, TRUE); + setflag (F_said_accepted_input, FALSE); + } +} + +#ifdef OPT_LIST_DICT +int show_words () +{ +/* + decode *words into words! +*/ + + int sc, wc, woff, wid; + unsigned char x[128]; + unsigned char c; + int num_words; + + num_words=0; + + /* scan for first entry with words */ + for (wc = woff = 0; woff == 0 && woff < words_flen; wc += 2) + woff = hilo_getword(words+wc); + + /* AGDS cludge for bad word file :( */ + if(woff > words_flen) + return err_OK; + + /* count all the words in the list */ + for(sc=0, wc=0; woff 0x80) { + wc++; + wid = hilo_getword (words+woff); + woff += 2; + if(wid > sc && wid != 9999) + sc = wid; + } + } + num_words = wc; + + /* scan for frist words entry */ + for(wc=0, woff=0; woff==0; wc+=2) + woff=hilo_getword(words+wc); + + /* build word list */ + for(wc=0; wc +extern s9_t sarien_s9; +void add_s9_words () +{ +/* + from show_words +*/ + + int sc, wc, woff, wid; + unsigned char x[128]; + unsigned char c; + int num_words; + static char **allocated_words; + static int num_allocated_words; + + num_words=0; + + /* scan for first entry with words */ + for (wc = woff = 0; woff == 0 && woff < words_flen; wc += 2) + woff = hilo_getword(words+wc); + + /* AGDS cludge for bad word file :( */ + if(woff > words_flen) + return; + + /* count all the words in the list */ + for(sc=0, wc=0; woff 0x80) { + wc++; + wid = hilo_getword (words+woff); + woff += 2; + if(wid > sc && wid != 9999) + sc = wid; + } + } + num_words = wc; + if (allocated_words != NULL) + { + int i; + + for (i = 0; i < num_allocated_words; i++) + free( allocated_words[i] ); + free(allocated_words); + } + allocated_words = malloc(sizeof(char*) * num_words); + num_allocated_words = num_words; + + /* scan for frist words entry */ + for(wc=0, woff=0; woff==0; wc+=2) + woff=hilo_getword(words+wc); + + /* build word list */ + for(wc=0; wc