From ac9b8fd43d75aca937a32e581e06019833776248 Mon Sep 17 00:00:00 2001 From: dreammaster Date: Sun, 8 Sep 2019 22:36:19 +0100 Subject: GLK: ADRIFT: Formatting --- engines/glk/adrift/detection_tables.h | 2 +- engines/glk/adrift/os_glk.cpp | 4306 ++++----- engines/glk/adrift/scare.h | 104 +- engines/glk/adrift/scdebug.cpp | 4295 ++++----- engines/glk/adrift/scevents.cpp | 1312 ++- engines/glk/adrift/scexpr.cpp | 2557 +++-- engines/glk/adrift/scgamest.cpp | 1580 ++- engines/glk/adrift/scgamest.h | 6 +- engines/glk/adrift/scinterf.cpp | 1136 +-- engines/glk/adrift/sclibrar.cpp | 16531 +++++++++++++++----------------- engines/glk/adrift/sclocale.cpp | 546 +- engines/glk/adrift/scmemos.cpp | 737 +- engines/glk/adrift/scnpcs.cpp | 950 +- engines/glk/adrift/scobjcts.cpp | 1362 ++- engines/glk/adrift/scparser.cpp | 3170 +++--- engines/glk/adrift/scprintf.cpp | 2213 ++--- engines/glk/adrift/scprops.cpp | 1404 ++- engines/glk/adrift/scprotos.h | 1311 ++- engines/glk/adrift/scresour.cpp | 469 +- engines/glk/adrift/screstrs.cpp | 1688 ++-- engines/glk/adrift/scrunner.cpp | 3469 ++++--- engines/glk/adrift/scserial.cpp | 1277 ++- engines/glk/adrift/sctaffil.cpp | 944 +- engines/glk/adrift/sctafpar.cpp | 5840 ++++++----- engines/glk/adrift/sctasks.cpp | 2237 ++--- engines/glk/adrift/scutils.cpp | 440 +- engines/glk/adrift/scvars.cpp | 2887 +++--- engines/glk/adrift/sxfile.cpp | 236 +- engines/glk/adrift/sxglob.cpp | 409 +- engines/glk/adrift/sxmain.cpp | 225 +- engines/glk/adrift/sxprotos.h | 87 +- engines/glk/adrift/sxscript.cpp | 714 +- engines/glk/adrift/sxstubs.cpp | 484 +- engines/glk/adrift/sxtester.cpp | 84 +- engines/glk/adrift/sxutils.cpp | 182 +- 35 files changed, 31010 insertions(+), 34184 deletions(-) diff --git a/engines/glk/adrift/detection_tables.h b/engines/glk/adrift/detection_tables.h index c824905722..3f0bbdebcc 100644 --- a/engines/glk/adrift/detection_tables.h +++ b/engines/glk/adrift/detection_tables.h @@ -190,7 +190,7 @@ const PlainGameDescriptor ADRIFT_GAME_LIST[] = { { "amcthorn", "Thorn" }, { "amcneighbours", "Neighbours From Hell" }, { "amcmonsters", "Monsters" }, - { "amcdiarystrip", "Diary of a Stripper" }, + { "amcdiarystrip", "Diary of a Stripper" }, // ADRIFT One-Hour Game Competition 1 { "1hgamonkeytoomany", "" }, diff --git a/engines/glk/adrift/os_glk.cpp b/engines/glk/adrift/os_glk.cpp index 33253802a2..37ac07f941 100644 --- a/engines/glk/adrift/os_glk.cpp +++ b/engines/glk/adrift/os_glk.cpp @@ -89,9 +89,9 @@ static const sc_int GSC_CONF_SUBTLE_HINT = INT_MAX, GSC_CONF_CONTINUE_HINTS = INT_MAX - 2; /* Forward declaration of event wait functions, and a short delay. */ -static void gsc_event_wait_2 (glui32 wait_type_1, - glui32 wait_type_2, event_t *event); -static void gsc_event_wait (glui32 wait_type, event_t *event); +static void gsc_event_wait_2(glui32 wait_type_1, + glui32 wait_type_2, event_t *event); +static void gsc_event_wait(glui32 wait_type, event_t *event); static void gsc_short_delay(); @@ -106,29 +106,28 @@ static void gsc_short_delay(); * abort() or otherwise handle the error. */ static void -gsc_fatal (const char *string) -{ - /* - * If the failure happens too early for us to have a window, print - * the message to stderr. - */ - if (!gsc_main_window) { - error("\n\nINTERNAL ERROR: %s\n", string); - } +gsc_fatal(const char *string) { + /* + * If the failure happens too early for us to have a window, print + * the message to stderr. + */ + if (!gsc_main_window) { + error("\n\nINTERNAL ERROR: %s\n", string); + } - /* Cancel all possible pending window input events. */ - g_vm->glk_cancel_line_event (gsc_main_window, nullptr); - g_vm->glk_cancel_char_event (gsc_main_window); + /* Cancel all possible pending window input events. */ + g_vm->glk_cancel_line_event(gsc_main_window, nullptr); + g_vm->glk_cancel_char_event(gsc_main_window); - /* Print a message indicating the error, and exit. */ - g_vm->glk_set_window (gsc_main_window); - g_vm->glk_set_style (style_Normal); - g_vm->glk_put_string ("\n\nINTERNAL ERROR: "); - g_vm->glk_put_string ((char *) string); + /* Print a message indicating the error, and exit. */ + g_vm->glk_set_window(gsc_main_window); + g_vm->glk_set_style(style_Normal); + g_vm->glk_put_string("\n\nINTERNAL ERROR: "); + g_vm->glk_put_string((char *) string); - g_vm->glk_put_string ("\n\nPlease record the details of this error, try to" - " note down everything you did to cause it, and email" - " this information to simon_baldwin@yahoo.com.\n\n"); + g_vm->glk_put_string("\n\nPlease record the details of this error, try to" + " note down everything you did to cause it, and email" + " this information to simon_baldwin@yahoo.com.\n\n"); } @@ -138,18 +137,16 @@ gsc_fatal (const char *string) * Non-failing malloc; call gsc_fatal and exit if memory allocation fails. */ static void * -gsc_malloc (size_t size) -{ - void *pointer; +gsc_malloc(size_t size) { + void *pointer; - pointer = malloc (size > 0 ? size : 1); - if (!pointer) - { - gsc_fatal ("GLK: Out of system memory"); - g_vm->glk_exit (); - } + pointer = malloc(size > 0 ? size : 1); + if (!pointer) { + gsc_fatal("GLK: Out of system memory"); + g_vm->glk_exit(); + } - return pointer; + return pointer; } @@ -170,8 +167,8 @@ static const glui32 GSC_ISO_8859_EQUIVALENCE = 256; */ enum { GSC_TABLE_SIZE = 256 }; typedef struct { - const glui32 unicode[GSC_TABLE_SIZE]; - const sc_char *const ascii[GSC_TABLE_SIZE]; + const glui32 unicode[GSC_TABLE_SIZE]; + const sc_char *const ascii[GSC_TABLE_SIZE]; } gsc_codepages_t; /* @@ -179,9 +176,9 @@ typedef struct { * an alternate. The latter is intended for monospaced output. */ typedef struct { - const sc_char *const name; - const gsc_codepages_t main; - const gsc_codepages_t alternate; + const sc_char *const name; + const gsc_codepages_t main; + const gsc_codepages_t alternate; } gsc_locale_t; @@ -195,117 +192,127 @@ typedef struct { * character that might be recognizable as what it's trying to emulate. */ static const gsc_locale_t GSC_LATIN1_LOCALE = { - "Latin1", - /* cp1252 to unicode. */ -{ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x000a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, - 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, - 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, - 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, - 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, - 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, - 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, - 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, - 0x007e, 0x0000, 0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, - 0x2021, 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017d, 0x0000, - 0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, - 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x017e, 0x0178, 0x00a0, 0x00a1, - 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, - 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, - 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, - 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, - 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, - 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, - 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, - 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, - 0x00fc, 0x00fd, 0x00fe, 0x00ff }, - /* cp1252 to ascii. */ - { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", - "\n", nullptr, nullptr, "\n", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", - "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", - "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", - "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", - "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", - "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", - "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "{", "|", "}", "~", nullptr, "E", nullptr, ",", - "f", ",,", "...", "+", "#", "^", "%", "S", "<", "OE", nullptr, - "Z", nullptr, nullptr, "'", "'", "\"", "\"", "*", "-", "-", "~", - "[TM]","s", ">", "oe", nullptr, "z", "Y", " ", "!", "c", "GBP", - "*", "Y", "|", "S", "\"", "(C)", "a", "<<", "-", "-", "(R)", - "-", "o", "+/-", "2", "3", "'", "u", "P", "*", ",", "1", - "o", ">>", "1/4", "1/2", "3/4", "?", "A", "A", "A", "A", "A", - "A", "AE", "C", "E", "E", "E", "E", "I", "I", "I", "I", - "D", "N", "O", "O", "O", "O", "O", "x", "O", "U", "U", - "U", "U", "Y", "p", "ss", "a", "a", "a", "a", "a", "a", - "ae", "c", "e", "e", "e", "e", "i", "i", "i", "i", "d", - "n", "o", "o", "o", "o", "o", "/", "o", "u", "u", "u", - "u", "y", "P", "y" } }, - /* cp850 to unicode. */ -{ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x000a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, - 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, - 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, - 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, - 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, - 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, - 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, - 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, - 0x007e, 0x0000, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, - 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, - 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, - 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192, 0x00e1, 0x00ed, - 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00ae, 0x00ac, - 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x00c1, 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, - 0x00a2, 0x00a5, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, - 0x00e3, 0x00c3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, - 0x00a4, 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x0131, 0x00cd, 0x00ce, - 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, 0x00d3, - 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe, 0x00de, 0x00da, - 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4, 0x00ad, 0x00b1, 0x2017, - 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, - 0x00b3, 0x00b2, 0x25a0, 0x00a0 }, - /* cp850 to ascii. */ - { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", - "\n", nullptr, nullptr, "\n", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", - "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", - "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", - "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", - "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", - "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", - "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "{", "|", "}", "~", nullptr, "C", "u", "e", - "a", "a", "a", "a", "c", "e", "e", "e", "i", "i", "i", - "A", "A", "E", "ae", "AE", "o", "o", "o", "u", "u", "y", - "O", "U", "o", "GBP", "O", "x", "f", "a", "i", "o", "u", - "n", "N", "a", "o", "?", "(R)", "-", "1/2", "1/4", "i", "<<", - ">>", "#", "#", "#", "|", "+", "A", "A", "A", "(C)", "+", - "|", "+", "+", "c", "Y", "+", "+", "+", "+", "+", "-", - "+", "a", "A", "+", "+", "+", "+", "+", "=", "+", "*", - "d", "D", "E", "E", "E", "i", "I", "I", "I", "+", "+", - ".", ".", "|", "I", ".", "O", "ss", "O", "O", "o", "O", - "u", "p", "P", "U", "U", "U", "y", "Y", "-", "'", "-", - "+/-", "=", "3/4", "P", "S", "/", ",", "deg", "\"", "*", "1", - "3", "2", ".", " " } } + "Latin1", + /* cp1252 to unicode. */ + { { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x000a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, + 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, + 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, + 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, + 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, + 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, + 0x007e, 0x0000, 0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, + 0x2021, 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017d, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, + 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x017e, 0x0178, 0x00a0, 0x00a1, + 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, + 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, + 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, + 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, + 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, + 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, + 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, + 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, + 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, + 0x00fc, 0x00fd, 0x00fe, 0x00ff + }, + /* cp1252 to ascii. */ + { + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", + "\n", nullptr, nullptr, "\n", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", + "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", + "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", + "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", + "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "{", "|", "}", "~", nullptr, "E", nullptr, ",", + "f", ",,", "...", "+", "#", "^", "%", "S", "<", "OE", nullptr, + "Z", nullptr, nullptr, "'", "'", "\"", "\"", "*", "-", "-", "~", + "[TM]", "s", ">", "oe", nullptr, "z", "Y", " ", "!", "c", "GBP", + "*", "Y", "|", "S", "\"", "(C)", "a", "<<", "-", "-", "(R)", + "-", "o", "+/-", "2", "3", "'", "u", "P", "*", ",", "1", + "o", ">>", "1/4", "1/2", "3/4", "?", "A", "A", "A", "A", "A", + "A", "AE", "C", "E", "E", "E", "E", "I", "I", "I", "I", + "D", "N", "O", "O", "O", "O", "O", "x", "O", "U", "U", + "U", "U", "Y", "p", "ss", "a", "a", "a", "a", "a", "a", + "ae", "c", "e", "e", "e", "e", "i", "i", "i", "i", "d", + "n", "o", "o", "o", "o", "o", "/", "o", "u", "u", "u", + "u", "y", "P", "y" + } + }, + /* cp850 to unicode. */ + { { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x000a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, + 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, + 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, + 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, + 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, + 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, + 0x007e, 0x0000, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, + 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, + 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192, 0x00e1, 0x00ed, + 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00ae, 0x00ac, + 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, + 0x2524, 0x00c1, 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, + 0x00a2, 0x00a5, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, + 0x00e3, 0x00c3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, + 0x00a4, 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x0131, 0x00cd, 0x00ce, + 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, 0x00d3, + 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe, 0x00de, 0x00da, + 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4, 0x00ad, 0x00b1, 0x2017, + 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, + 0x00b3, 0x00b2, 0x25a0, 0x00a0 + }, + /* cp850 to ascii. */ + { + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", + "\n", nullptr, nullptr, "\n", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", + "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", + "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", + "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", + "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "{", "|", "}", "~", nullptr, "C", "u", "e", + "a", "a", "a", "a", "c", "e", "e", "e", "i", "i", "i", + "A", "A", "E", "ae", "AE", "o", "o", "o", "u", "u", "y", + "O", "U", "o", "GBP", "O", "x", "f", "a", "i", "o", "u", + "n", "N", "a", "o", "?", "(R)", "-", "1/2", "1/4", "i", "<<", + ">>", "#", "#", "#", "|", "+", "A", "A", "A", "(C)", "+", + "|", "+", "+", "c", "Y", "+", "+", "+", "+", "+", "-", + "+", "a", "A", "+", "+", "+", "+", "+", "=", "+", "*", + "d", "D", "E", "E", "E", "i", "I", "I", "I", "+", "+", + ".", ".", "|", "I", ".", "O", "ss", "O", "O", "o", "O", + "u", "p", "P", "U", "U", "U", "y", "Y", "-", "'", "-", + "+/-", "=", "3/4", "P", "S", "/", ",", "deg", "\"", "*", "1", + "3", "2", ".", " " + } + } }; @@ -321,117 +328,127 @@ static const gsc_locale_t GSC_LATIN1_LOCALE = { * the general appearance and shape of the character being emulated is used. */ static const gsc_locale_t GSC_CYRILLIC_LOCALE = { - "Cyrillic", - /* cp1251 to unicode. */ -{ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x000a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, - 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, - 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, - 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, - 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, - 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, - 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, - 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, - 0x007e, 0x0000, 0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, - 0x2021, 0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f, - 0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, - 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f, 0x00a0, 0x040e, - 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7, 0x0401, 0x00a9, 0x0404, - 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407, 0x00b0, 0x00b1, 0x0406, 0x0456, - 0x0491, 0x00b5, 0x00b6, 0x00b7, 0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, - 0x0405, 0x0455, 0x0457, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, - 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, - 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0430, - 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, - 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, - 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, - 0x044c, 0x044d, 0x044e, 0x044f }, - /* cp1251 to gost 16876-71 ascii. */ - { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", - "\n", nullptr, nullptr, "\n", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", - "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", - "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", - "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", - "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", - "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", - "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "{", "|", "}", "~", nullptr, nullptr, nullptr, ",", - nullptr, ",,", "...", "+", "#", "E", "%", nullptr, "<", nullptr, nullptr, - nullptr, nullptr, nullptr, "'", "'", "\"", "\"", "*", "-", "-", nullptr, - "[TM]",nullptr, ">", nullptr, nullptr, nullptr, nullptr, " ", nullptr, nullptr, nullptr, - "*", "G", "|", "S", "Jo", "(C)", "Je", "<<", "-", "-", "(R)", - "Ji", "o", "+/-", "I", "i", "g", "u", "P", "*", "jo", nullptr, - "je", ">>", "j", "S", "s", "ji", "A", "B", "V", "G", "D", - "E", "Zh", "Z", "I", "Jj", "K", "L", "M", "N", "O", "P", - "R", "S", "T", "U", "F", "Kh", "C", "Ch", "Sh", "Shh", "\"", - "Y", "'", "Eh", "Ju", "Ja", "a", "b", "v", "g", "d", "e", - "zh", "z", "i", "jj", "k", "l", "m", "n", "o", "p", "r", - "s", "t", "u", "f", "kh", "c", "ch", "sh", "shh", "\"", "y", - "'", "eh", "ju", "ja" } }, - /* cp866 to unicode. */ -{ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x000a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, - 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, - 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, - 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, - 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, - 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, - 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, - 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, - 0x007e, 0x0000, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, - 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, - 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, - 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0430, 0x0431, - 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, - 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, - 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, - 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, - 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x0440, - 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, - 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0401, 0x0451, 0x0404, - 0x0454, 0x0407, 0x0457, 0x040e, 0x045e, 0x00b0, 0x2022, 0x00b7, 0x221a, - 0x2116, 0x00a4, 0x25a0, 0x00a0 }, - /* cp866 to gost 16876-71 ascii. */ - { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", - "\n", nullptr, nullptr, "\n", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", - "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", - "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", - "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", - "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", - "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", - "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "{", "|", "}", "~", nullptr, "A", "B", "V", - "G", "D", "E", "Zh", "Z", "I", "Jj", "K", "L", "M", "N", - "O", "P", "R", "S", "T", "U", "F", "Kh", "C", "Ch", "Sh", - "Shh", "\"", "Y", "'", "Eh", "Ju", "Ja", "a", "b", "v", "g", - "d", "e", "zh", "z", "i", "jj", "k", "l", "m", "n", "o", - "p", "#", "#", "#", "|", "+", "+", "+", "+", "+", "+", - "|", "+", "+", "+", "+", "+", "+", "+", "+", "+", "-", - "+", "+", "+", "+", "+", "+", "+", "+", "|", "+", "+", - "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", - "+", ".", ".", ".", ".", "r", "s", "t", "u", "f", "kh", - "c", "ch", "sh", "shh", "\"", "y", "'", "eh", "ju", "ja", "Jo", - "jo", "Je", "je", "Ji", "ji", nullptr, nullptr, "deg", "*", "*", nullptr, - nullptr, "*", ".", " " } } + "Cyrillic", + /* cp1251 to unicode. */ + { { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x000a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, + 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, + 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, + 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, + 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, + 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, + 0x007e, 0x0000, 0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, + 0x2021, 0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f, + 0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, + 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f, 0x00a0, 0x040e, + 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7, 0x0401, 0x00a9, 0x0404, + 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407, 0x00b0, 0x00b1, 0x0406, 0x0456, + 0x0491, 0x00b5, 0x00b6, 0x00b7, 0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, + 0x0405, 0x0455, 0x0457, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, + 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, + 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0430, + 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, + 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, + 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, + 0x044c, 0x044d, 0x044e, 0x044f + }, + /* cp1251 to gost 16876-71 ascii. */ + { + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", + "\n", nullptr, nullptr, "\n", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", + "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", + "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", + "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", + "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "{", "|", "}", "~", nullptr, nullptr, nullptr, ",", + nullptr, ",,", "...", "+", "#", "E", "%", nullptr, "<", nullptr, nullptr, + nullptr, nullptr, nullptr, "'", "'", "\"", "\"", "*", "-", "-", nullptr, + "[TM]", nullptr, ">", nullptr, nullptr, nullptr, nullptr, " ", nullptr, nullptr, nullptr, + "*", "G", "|", "S", "Jo", "(C)", "Je", "<<", "-", "-", "(R)", + "Ji", "o", "+/-", "I", "i", "g", "u", "P", "*", "jo", nullptr, + "je", ">>", "j", "S", "s", "ji", "A", "B", "V", "G", "D", + "E", "Zh", "Z", "I", "Jj", "K", "L", "M", "N", "O", "P", + "R", "S", "T", "U", "F", "Kh", "C", "Ch", "Sh", "Shh", "\"", + "Y", "'", "Eh", "Ju", "Ja", "a", "b", "v", "g", "d", "e", + "zh", "z", "i", "jj", "k", "l", "m", "n", "o", "p", "r", + "s", "t", "u", "f", "kh", "c", "ch", "sh", "shh", "\"", "y", + "'", "eh", "ju", "ja" + } + }, + /* cp866 to unicode. */ + { { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x000a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, + 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, + 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, + 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, + 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, + 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, + 0x007e, 0x0000, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, + 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, + 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0430, 0x0431, + 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, + 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x2591, 0x2592, 0x2593, 0x2502, + 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, + 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, + 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, + 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x0440, + 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, + 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0401, 0x0451, 0x0404, + 0x0454, 0x0407, 0x0457, 0x040e, 0x045e, 0x00b0, 0x2022, 0x00b7, 0x221a, + 0x2116, 0x00a4, 0x25a0, 0x00a0 + }, + /* cp866 to gost 16876-71 ascii. */ + { + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", + "\n", nullptr, nullptr, "\n", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", + "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", + "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", + "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", + "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "{", "|", "}", "~", nullptr, "A", "B", "V", + "G", "D", "E", "Zh", "Z", "I", "Jj", "K", "L", "M", "N", + "O", "P", "R", "S", "T", "U", "F", "Kh", "C", "Ch", "Sh", + "Shh", "\"", "Y", "'", "Eh", "Ju", "Ja", "a", "b", "v", "g", + "d", "e", "zh", "z", "i", "jj", "k", "l", "m", "n", "o", + "p", "#", "#", "#", "|", "+", "+", "+", "+", "+", "+", + "|", "+", "+", "+", "+", "+", "+", "+", "+", "+", "-", + "+", "+", "+", "+", "+", "+", "+", "+", "|", "+", "+", + "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", + "+", ".", ".", ".", ".", "r", "s", "t", "u", "f", "kh", + "c", "ch", "sh", "shh", "\"", "y", "'", "eh", "ju", "ja", "Jo", + "jo", "Je", "je", "Ji", "ji", nullptr, nullptr, "deg", "*", "*", nullptr, + nullptr, "*", ".", " " + } + } }; @@ -447,24 +464,22 @@ static const sc_bool gsc_has_unicode = FALSE; /* Gestalt selector and stubs for non-unicode capable libraries. */ static const glui32 gestalt_Unicode = 15; -static void glk_put_char_uni (glui32 ch) -{ - glui32 unused; - unused = ch; - gsc_fatal ("GLK: Stub unicode function called"); +static void glk_put_char_uni(glui32 ch) { + glui32 unused; + unused = ch; + gsc_fatal("GLK: Stub unicode function called"); } -static void glk_request_line_event_uni (winid_t win, - glui32 *buf, glui32 maxlen, glui32 initlen) -{ - winid_t unused1; - glui32 *unused2; - glui32 unused3, unused4; - unused1 = win; - unused2 = buf; - unused3 = maxlen; - unused4 = initlen; - gsc_fatal ("GLK: Stub unicode function called"); +static void glk_request_line_event_uni(winid_t win, + glui32 *buf, glui32 maxlen, glui32 initlen) { + winid_t unused1; + glui32 *unused2; + glui32 unused3, unused4; + unused1 = win; + unused2 = buf; + unused3 = maxlen; + unused4 = initlen; + gsc_fatal("GLK: Stub unicode function called"); } #endif @@ -480,9 +495,9 @@ static const glui32 GSC_MIN_PRINTABLE = ' ', /* List of pointers to supported and available locales, nullptr terminated. */ static const gsc_locale_t *const GSC_AVAILABLE_LOCALES[] = { - &GSC_LATIN1_LOCALE, - &GSC_CYRILLIC_LOCALE, - nullptr + &GSC_LATIN1_LOCALE, + &GSC_CYRILLIC_LOCALE, + nullptr }; /* @@ -499,30 +514,27 @@ static const gsc_locale_t *const gsc_fallback_locale = &GSC_LATIN1_LOCALE; * Set a locale explicitly from the name passed in. */ static void -gsc_set_locale (const sc_char *name) -{ - const gsc_locale_t *matched = nullptr; - const gsc_locale_t *const *iterator; - assert (name); +gsc_set_locale(const sc_char *name) { + const gsc_locale_t *matched = nullptr; + const gsc_locale_t *const *iterator; + assert(name); - /* - * Search locales for a matching name, abbreviated if necessary. Stop on - * the first match found. - */ - for (iterator = GSC_AVAILABLE_LOCALES; *iterator; iterator++) - { - const gsc_locale_t *const locale = *iterator; + /* + * Search locales for a matching name, abbreviated if necessary. Stop on + * the first match found. + */ + for (iterator = GSC_AVAILABLE_LOCALES; *iterator; iterator++) { + const gsc_locale_t *const locale = *iterator; - if (sc_strncasecmp (name, locale->name, strlen (name)) == 0) - { - matched = locale; - break; - } - } + if (sc_strncasecmp(name, locale->name, strlen(name)) == 0) { + matched = locale; + break; + } + } - /* If matched, set the global locale. */ - if (matched) - gsc_locale = matched; + /* If matched, set the global locale. */ + if (matched) + gsc_locale = matched; } @@ -533,24 +545,22 @@ gsc_set_locale (const sc_char *name) * having to write transcripts as ascii. */ static void -gsc_put_char_uni (glui32 unicode, const char *ascii) -{ - /* If there is an transcript stream, temporarily disconnect it. */ - if (gsc_transcript_stream) - g_vm->glk_window_set_echo_stream (gsc_main_window, nullptr); +gsc_put_char_uni(glui32 unicode, const char *ascii) { + /* If there is an transcript stream, temporarily disconnect it. */ + if (gsc_transcript_stream) + g_vm->glk_window_set_echo_stream(gsc_main_window, nullptr); - g_vm->glk_put_char_uni (unicode); + g_vm->glk_put_char_uni(unicode); - /* Print ascii to the transcript, then reattach it. */ - if (gsc_transcript_stream) - { - if (ascii) - g_vm->glk_put_string_stream (gsc_transcript_stream, (char *) ascii); - else - g_vm->glk_put_char_stream (gsc_transcript_stream, '?'); + /* Print ascii to the transcript, then reattach it. */ + if (gsc_transcript_stream) { + if (ascii) + g_vm->glk_put_string_stream(gsc_transcript_stream, (char *) ascii); + else + g_vm->glk_put_char_stream(gsc_transcript_stream, '?'); - g_vm->glk_window_set_echo_stream (gsc_main_window, gsc_transcript_stream); - } + g_vm->glk_window_set_echo_stream(gsc_main_window, gsc_transcript_stream); + } } @@ -561,86 +571,79 @@ gsc_put_char_uni (glui32 unicode, const char *ascii) * main or the alternate codepage depending on the flag passed in. */ static void -gsc_put_char_locale (sc_char ch, - const gsc_locale_t *locale, sc_bool is_alternate) -{ - const gsc_codepages_t *codepage; - unsigned char character; - glui32 unicode; - const char *ascii; - - /* - * Select either the main or the alternate codepage for this locale, and - * retrieve the unicode and ascii representations of the character. - */ - codepage = is_alternate ? &locale->alternate : &locale->main; - character = (unsigned char) ch; - unicode = codepage->unicode[character]; - ascii = codepage->ascii[character]; - - /* - * If a unicode representation exists, use for either iso 8859-1 or, if - * possible, direct unicode output. - */ - if (unicode > 0) - { - /* - * If unicode is in the range 1-255, this value is directly equivalent - * to the iso 8859-1 representation; otherwise the character has no - * direct iso 8859-1 glyph. - */ - if (unicode < GSC_ISO_8859_EQUIVALENCE) - { - /* - * If the iso 8859-1 character is one that this Glk library will - * print exactly, print and return. We add a check here for the - * guaranteed printable characters, since some Glk libraries don't - * return the correct values for gestalt_CharOutput for these. - */ - if (unicode == '\n' - || (unicode >= GSC_MIN_PRINTABLE && unicode <= GSC_MAX_PRINTABLE) - || g_vm->glk_gestalt (gestalt_CharOutput, - unicode) == gestalt_CharOutput_ExactPrint) - { - g_vm->glk_put_char ((unsigned char) unicode); - return; - } - } - - /* - * If no usable iso 8859-1 representation, see if unicode is enabled and - * if the Glk library can print the character exactly. If yes, output - * the character that way. - * - * TODO Using unicode output currently disrupts transcript output. Any - * echo stream connected for a transcript here will be a text rather than - * a unicode stream, so probably won't output the character correctly. - * For now, if there's a transcript, we try to write ascii output. - */ - if (gsc_unicode_enabled) - { - if (g_vm->glk_gestalt (gestalt_CharOutput, - unicode) == gestalt_CharOutput_ExactPrint) - { - gsc_put_char_uni (unicode, ascii); - return; - } - } - } - - /* - * No success with iso 8859-1 or unicode, so try for an ascii substitute. - * Substitute strings use only 7-bit ascii, and so all are safe to print - * directly with Glk. - */ - if (ascii) - { - g_vm->glk_put_string ((char *) ascii); - return; - } - - /* No apparent way to output this character, so print a '?'. */ - g_vm->glk_put_char ('?'); +gsc_put_char_locale(sc_char ch, + const gsc_locale_t *locale, sc_bool is_alternate) { + const gsc_codepages_t *codepage; + unsigned char character; + glui32 unicode; + const char *ascii; + + /* + * Select either the main or the alternate codepage for this locale, and + * retrieve the unicode and ascii representations of the character. + */ + codepage = is_alternate ? &locale->alternate : &locale->main; + character = (unsigned char) ch; + unicode = codepage->unicode[character]; + ascii = codepage->ascii[character]; + + /* + * If a unicode representation exists, use for either iso 8859-1 or, if + * possible, direct unicode output. + */ + if (unicode > 0) { + /* + * If unicode is in the range 1-255, this value is directly equivalent + * to the iso 8859-1 representation; otherwise the character has no + * direct iso 8859-1 glyph. + */ + if (unicode < GSC_ISO_8859_EQUIVALENCE) { + /* + * If the iso 8859-1 character is one that this Glk library will + * print exactly, print and return. We add a check here for the + * guaranteed printable characters, since some Glk libraries don't + * return the correct values for gestalt_CharOutput for these. + */ + if (unicode == '\n' + || (unicode >= GSC_MIN_PRINTABLE && unicode <= GSC_MAX_PRINTABLE) + || g_vm->glk_gestalt(gestalt_CharOutput, + unicode) == gestalt_CharOutput_ExactPrint) { + g_vm->glk_put_char((unsigned char) unicode); + return; + } + } + + /* + * If no usable iso 8859-1 representation, see if unicode is enabled and + * if the Glk library can print the character exactly. If yes, output + * the character that way. + * + * TODO Using unicode output currently disrupts transcript output. Any + * echo stream connected for a transcript here will be a text rather than + * a unicode stream, so probably won't output the character correctly. + * For now, if there's a transcript, we try to write ascii output. + */ + if (gsc_unicode_enabled) { + if (g_vm->glk_gestalt(gestalt_CharOutput, + unicode) == gestalt_CharOutput_ExactPrint) { + gsc_put_char_uni(unicode, ascii); + return; + } + } + } + + /* + * No success with iso 8859-1 or unicode, so try for an ascii substitute. + * Substitute strings use only 7-bit ascii, and so all are safe to print + * directly with Glk. + */ + if (ascii) { + g_vm->glk_put_string((char *) ascii); + return; + } + + /* No apparent way to output this character, so print a '?'. */ + g_vm->glk_put_char('?'); } @@ -655,55 +658,49 @@ gsc_put_char_locale (sc_char ch, * Public functions for writing using the current or fallback locale. */ static void -gsc_put_char (const sc_char character) -{ - const gsc_locale_t *locale; +gsc_put_char(const sc_char character) { + const gsc_locale_t *locale; - locale = gsc_locale ? gsc_locale : gsc_fallback_locale; - gsc_put_char_locale (character, locale, FALSE); + locale = gsc_locale ? gsc_locale : gsc_fallback_locale; + gsc_put_char_locale(character, locale, FALSE); } static void -gsc_put_char_alternate (const sc_char character) -{ - const gsc_locale_t *locale; +gsc_put_char_alternate(const sc_char character) { + const gsc_locale_t *locale; - locale = gsc_locale ? gsc_locale : gsc_fallback_locale; - gsc_put_char_locale (character, locale, TRUE); + locale = gsc_locale ? gsc_locale : gsc_fallback_locale; + gsc_put_char_locale(character, locale, TRUE); } static void -gsc_put_buffer_using (const sc_char *buffer, - sc_int length, void (*putchar_function) (sc_char)) -{ - sc_int index_; +gsc_put_buffer_using(const sc_char *buffer, + sc_int length, void (*putchar_function)(sc_char)) { + sc_int index_; - for (index_ = 0; index_ < length; index_++) - putchar_function (buffer[index_]); + for (index_ = 0; index_ < length; index_++) + putchar_function(buffer[index_]); } static void -gsc_put_buffer (const sc_char *buffer, sc_int length) -{ - assert (buffer); +gsc_put_buffer(const sc_char *buffer, sc_int length) { + assert(buffer); - gsc_put_buffer_using (buffer, length, gsc_put_char); + gsc_put_buffer_using(buffer, length, gsc_put_char); } static void -gsc_put_string (const sc_char *string) -{ - assert (string); +gsc_put_string(const sc_char *string) { + assert(string); - gsc_put_buffer_using (string, strlen (string), gsc_put_char); + gsc_put_buffer_using(string, strlen(string), gsc_put_char); } static void -gsc_put_string_alternate (const sc_char *string) -{ - assert (string); +gsc_put_string_alternate(const sc_char *string) { + assert(string); - gsc_put_buffer_using (string, strlen (string), gsc_put_char_alternate); + gsc_put_buffer_using(string, strlen(string), gsc_put_char_alternate); } @@ -716,36 +713,33 @@ gsc_put_string_alternate (const sc_char *string) * available. */ static sc_char -gsc_unicode_to_locale (glui32 unicode, const gsc_locale_t *locale) -{ - const gsc_codepages_t *codepage; - sc_int character; +gsc_unicode_to_locale(glui32 unicode, const gsc_locale_t *locale) { + const gsc_codepages_t *codepage; + sc_int character; - /* Always use the main codepage for input. */ - codepage = &locale->main; + /* Always use the main codepage for input. */ + codepage = &locale->main; - /* - * Search the unicode table sequentially for the input character. This is - * inefficient, but because game input is usually not copious, excusable. - */ - for (character = 0; character < GSC_TABLE_SIZE; character++) - { - if (codepage->unicode[character] == unicode) - break; - } + /* + * Search the unicode table sequentially for the input character. This is + * inefficient, but because game input is usually not copious, excusable. + */ + for (character = 0; character < GSC_TABLE_SIZE; character++) { + if (codepage->unicode[character] == unicode) + break; + } - /* Return the character translation, or '?' if none. */ - return character < GSC_TABLE_SIZE ? (sc_char) character : '?'; + /* Return the character translation, or '?' if none. */ + return character < GSC_TABLE_SIZE ? (sc_char) character : '?'; } static void -gsc_unicode_buffer_to_locale (const glui32 *unicode, sc_int length, - sc_char *buffer, const gsc_locale_t *locale) -{ - sc_int index_; +gsc_unicode_buffer_to_locale(const glui32 *unicode, sc_int length, + sc_char *buffer, const gsc_locale_t *locale) { + sc_int index_; - for (index_ = 0; index_ < length; index_++) - buffer[index_] = gsc_unicode_to_locale (unicode[index_], locale); + for (index_ = 0; index_ < length; index_++) + buffer[index_] = gsc_unicode_to_locale(unicode[index_], locale); } @@ -756,41 +750,39 @@ gsc_unicode_buffer_to_locale (const glui32 *unicode, sc_int length, * of characters placed in the buffer. */ static sc_int -gsc_read_line_locale (sc_char *buffer, - sc_int length, const gsc_locale_t *locale) -{ - event_t event; +gsc_read_line_locale(sc_char *buffer, + sc_int length, const gsc_locale_t *locale) { + event_t event; - /* - * If we have unicode, we have to use it to ensure that characters not in - * the Latin1 locale are properly translated. - */ - if (gsc_unicode_enabled) - { - glui32 *unicode; + /* + * If we have unicode, we have to use it to ensure that characters not in + * the Latin1 locale are properly translated. + */ + if (gsc_unicode_enabled) { + glui32 *unicode; - /* - * Allocate a unicode buffer long enough to hold all the characters, - * then read in a unicode line. - */ - unicode = (glui32 *)gsc_malloc (length * sizeof (*unicode)); - g_vm->glk_request_line_event_uni (gsc_main_window, unicode, length, 0); - gsc_event_wait (evtype_LineInput, &event); + /* + * Allocate a unicode buffer long enough to hold all the characters, + * then read in a unicode line. + */ + unicode = (glui32 *)gsc_malloc(length * sizeof(*unicode)); + g_vm->glk_request_line_event_uni(gsc_main_window, unicode, length, 0); + gsc_event_wait(evtype_LineInput, &event); - /* Convert the unicode buffer out, then free it. */ - gsc_unicode_buffer_to_locale (unicode, event.val1, buffer, locale); - free (unicode); + /* Convert the unicode buffer out, then free it. */ + gsc_unicode_buffer_to_locale(unicode, event.val1, buffer, locale); + free(unicode); - /* Return the count of characters placed in the buffer. */ - return event.val1; - } + /* Return the count of characters placed in the buffer. */ + return event.val1; + } - /* No success with unicode, so fall back to standard line input. */ - g_vm->glk_request_line_event (gsc_main_window, buffer, length, 0); - gsc_event_wait (evtype_LineInput, &event); + /* No success with unicode, so fall back to standard line input. */ + g_vm->glk_request_line_event(gsc_main_window, buffer, length, 0); + gsc_event_wait(evtype_LineInput, &event); - /* Return the count of characters placed in the buffer. */ - return event.val1; + /* Return the count of characters placed in the buffer. */ + return event.val1; } @@ -800,12 +792,11 @@ gsc_read_line_locale (sc_char *buffer, * Public function for reading using the current or fallback locale. */ static sc_int -gsc_read_line (sc_char *buffer, sc_int length) -{ - const gsc_locale_t *locale; +gsc_read_line(sc_char *buffer, sc_int length) { + const gsc_locale_t *locale; - locale = gsc_locale ? gsc_locale : gsc_fallback_locale; - return gsc_read_line_locale (buffer, length, locale); + locale = gsc_locale ? gsc_locale : gsc_fallback_locale; + return gsc_read_line_locale(buffer, length, locale); } @@ -834,22 +825,19 @@ static const sc_char *const GSC_WHITESPACE = "\t\n\v\f\r "; * other than whitespace. */ static sc_bool -gsc_is_string_usable (const sc_char *string) -{ - /* If non-null, scan for any non-space character. */ - if (string) - { - sc_int index_; - - for (index_ = 0; string[index_] != '\0'; index_++) - { - if (!strchr (GSC_WHITESPACE, string[index_])) - return TRUE; - } - } +gsc_is_string_usable(const sc_char *string) { + /* If non-null, scan for any non-space character. */ + if (string) { + sc_int index_; + + for (index_ = 0; string[index_] != '\0'; index_++) { + if (!strchr(GSC_WHITESPACE, string[index_])) + return TRUE; + } + } - /* nullptr, or no characters other than whitespace. */ - return FALSE; + /* nullptr, or no characters other than whitespace. */ + return FALSE; } @@ -860,69 +848,62 @@ gsc_is_string_usable (const sc_char *string) * Glk libraries. */ static void -gsc_status_update() -{ - glui32 width, height; - uint index; - assert (gsc_status_window); - - g_vm->glk_window_get_size (gsc_status_window, &width, &height); - if (height > 0) - { - const sc_char *room; - - g_vm->glk_window_clear (gsc_status_window); - g_vm->glk_window_move_cursor (gsc_status_window, 0, 0); - g_vm->glk_set_window (gsc_status_window); - - g_vm->glk_set_style(style_User1); - for (index = 0; index < width; index++) - g_vm->glk_put_char (' '); - g_vm->glk_window_move_cursor (gsc_status_window, 0, 0); - - /* See if the game is indicating any current player room. */ - room = sc_get_game_room (gsc_game); - if (!gsc_is_string_usable (room)) - { - /* - * Player location is indeterminate, so print out a generic status, - * showing the game name and author. - */ - g_vm->glk_window_move_cursor (gsc_status_window, 1, 0); - gsc_put_string (sc_get_game_name (gsc_game)); - g_vm->glk_put_string (" | "); - gsc_put_string (sc_get_game_author (gsc_game)); - } - else - { - const sc_char *status; - char score[64]; - - /* Print the player location. */ - g_vm->glk_window_move_cursor (gsc_status_window, 1, 0); - gsc_put_string (room); - - /* Get the game's status line, or if none, format score. */ - status = sc_get_game_status_line (gsc_game); - if (!gsc_is_string_usable (status)) - { - sprintf (score, "Score: %ld", sc_get_game_score (gsc_game)); - status = score; - } - - /* Print the status line or score at window right, if it fits. */ - if (width > strlen (status) + GSC_STATUS_SLOP + 1) - { - glui32 position; - - position = width - strlen (status) - GSC_STATUS_SLOP; - g_vm->glk_window_move_cursor (gsc_status_window, position - 1, 0); - gsc_put_string (status); - } - } - - g_vm->glk_set_window (gsc_main_window); - } +gsc_status_update() { + glui32 width, height; + uint index; + assert(gsc_status_window); + + g_vm->glk_window_get_size(gsc_status_window, &width, &height); + if (height > 0) { + const sc_char *room; + + g_vm->glk_window_clear(gsc_status_window); + g_vm->glk_window_move_cursor(gsc_status_window, 0, 0); + g_vm->glk_set_window(gsc_status_window); + + g_vm->glk_set_style(style_User1); + for (index = 0; index < width; index++) + g_vm->glk_put_char(' '); + g_vm->glk_window_move_cursor(gsc_status_window, 0, 0); + + /* See if the game is indicating any current player room. */ + room = sc_get_game_room(gsc_game); + if (!gsc_is_string_usable(room)) { + /* + * Player location is indeterminate, so print out a generic status, + * showing the game name and author. + */ + g_vm->glk_window_move_cursor(gsc_status_window, 1, 0); + gsc_put_string(sc_get_game_name(gsc_game)); + g_vm->glk_put_string(" | "); + gsc_put_string(sc_get_game_author(gsc_game)); + } else { + const sc_char *status; + char score[64]; + + /* Print the player location. */ + g_vm->glk_window_move_cursor(gsc_status_window, 1, 0); + gsc_put_string(room); + + /* Get the game's status line, or if none, format score. */ + status = sc_get_game_status_line(gsc_game); + if (!gsc_is_string_usable(status)) { + sprintf(score, "Score: %ld", sc_get_game_score(gsc_game)); + status = score; + } + + /* Print the status line or score at window right, if it fits. */ + if (width > strlen(status) + GSC_STATUS_SLOP + 1) { + glui32 position; + + position = width - strlen(status) - GSC_STATUS_SLOP; + g_vm->glk_window_move_cursor(gsc_status_window, position - 1, 0); + gsc_put_string(status); + } + } + + g_vm->glk_set_window(gsc_main_window); + } } @@ -933,15 +914,14 @@ gsc_status_update() * available length. */ static void -gsc_status_safe_strcat (char *dest, size_t length, const char *src) -{ - size_t available, src_length; +gsc_status_safe_strcat(char *dest, size_t length, const char *src) { + size_t available, src_length; - /* Append only as many characters as will fit. */ - src_length = strlen (src); - available = length - strlen (dest) - 1; - if (available > 0) - strncat (dest, src, src_length < available ? src_length : available); + /* Append only as many characters as will fit. */ + src_length = strlen(src); + available = length - strlen(dest) - 1; + if (available > 0) + strncat(dest, src, src_length < available ? src_length : available); } @@ -953,48 +933,44 @@ gsc_status_safe_strcat (char *dest, size_t length, const char *src) * windowing Glk libraries. */ static void -gsc_status_print() -{ - static char current_status[GSC_STATUS_BUFFER_LENGTH + 1]; - - const sc_char *room; - - /* Do nothing if the game isn't indicating any current player room. */ - room = sc_get_game_room (gsc_game); - if (gsc_is_string_usable (room)) - { - char buffer[GSC_STATUS_BUFFER_LENGTH + 1]; - const sc_char *status; - char score[64]; - - /* Make an attempt at a status line, starting with player location. */ - strcpy (buffer, ""); - gsc_status_safe_strcat (buffer, sizeof (buffer), room); - - /* Get the game's status line, or if none, format score. */ - status = sc_get_game_status_line (gsc_game); - if (!gsc_is_string_usable (status)) - { - sprintf (score, "Score: %ld", sc_get_game_score (gsc_game)); - status = score; - } +gsc_status_print() { + static char current_status[GSC_STATUS_BUFFER_LENGTH + 1]; + + const sc_char *room; + + /* Do nothing if the game isn't indicating any current player room. */ + room = sc_get_game_room(gsc_game); + if (gsc_is_string_usable(room)) { + char buffer[GSC_STATUS_BUFFER_LENGTH + 1]; + const sc_char *status; + char score[64]; + + /* Make an attempt at a status line, starting with player location. */ + strcpy(buffer, ""); + gsc_status_safe_strcat(buffer, sizeof(buffer), room); + + /* Get the game's status line, or if none, format score. */ + status = sc_get_game_status_line(gsc_game); + if (!gsc_is_string_usable(status)) { + sprintf(score, "Score: %ld", sc_get_game_score(gsc_game)); + status = score; + } - /* Append the status line or score. */ - gsc_status_safe_strcat (buffer, sizeof (buffer), " | "); - gsc_status_safe_strcat (buffer, sizeof (buffer), status); + /* Append the status line or score. */ + gsc_status_safe_strcat(buffer, sizeof(buffer), " | "); + gsc_status_safe_strcat(buffer, sizeof(buffer), status); - /* If this matches the current saved status line, do nothing more. */ - if (strcmp (buffer, current_status) != 0) - { - /* Bracket, and output the status line buffer. */ - g_vm->glk_put_string ("[ "); - gsc_put_string (buffer); - g_vm->glk_put_string (" ]\n"); + /* If this matches the current saved status line, do nothing more. */ + if (strcmp(buffer, current_status) != 0) { + /* Bracket, and output the status line buffer. */ + g_vm->glk_put_string("[ "); + gsc_put_string(buffer); + g_vm->glk_put_string(" ]\n"); - /* Save the details of the printed status buffer. */ - strcpy (current_status, buffer); - } - } + /* Save the details of the printed status buffer. */ + strcpy(current_status, buffer); + } + } } @@ -1005,12 +981,11 @@ gsc_status_print() * or prints the status line to the main window. */ static void -gsc_status_notify() -{ - if (gsc_status_window) - gsc_status_update (); - else - gsc_status_print (); +gsc_status_notify() { + if (gsc_status_window) + gsc_status_update(); + else + gsc_status_print(); } @@ -1022,27 +997,25 @@ gsc_status_notify() * arrange events. */ static void -gsc_status_redraw() -{ - if (gsc_status_window) - { - winid_t parent; - - /* - * Rearrange the status window, without changing its actual arrangement - * in any way. This is a hack to work round incorrect window repainting - * in Xglk; it forces a complete repaint of affected windows on Glk - * window resize and arrange events, and works in part because Xglk - * doesn't check for actual arrangement changes in any way before - * invalidating its windows. The hack should be harmless to Glk - * libraries other than Xglk, moreover, we're careful to activate it - * only on resize and arrange events. - */ - parent = g_vm->glk_window_get_parent (gsc_status_window); - g_vm->glk_window_set_arrangement (parent, - winmethod_Above | winmethod_Fixed, 1, nullptr); - gsc_status_update (); - } +gsc_status_redraw() { + if (gsc_status_window) { + winid_t parent; + + /* + * Rearrange the status window, without changing its actual arrangement + * in any way. This is a hack to work round incorrect window repainting + * in Xglk; it forces a complete repaint of affected windows on Glk + * window resize and arrange events, and works in part because Xglk + * doesn't check for actual arrangement changes in any way before + * invalidating its windows. The hack should be harmless to Glk + * libraries other than Xglk, moreover, we're careful to activate it + * only on resize and arrange events. + */ + parent = g_vm->glk_window_get_parent(gsc_status_window); + g_vm->glk_window_set_arrangement(parent, + winmethod_Above | winmethod_Fixed, 1, nullptr); + gsc_status_update(); + } } @@ -1059,8 +1032,8 @@ static int gsc_help_requested = FALSE, /* Font descriptor type, encapsulating size and monospaced boolean. */ typedef struct { - sc_bool is_monospaced; - sc_int size; + sc_bool is_monospaced; + sc_int size; } gsc_font_size_t; /* Font stack and attributes for nesting tags. */ @@ -1098,29 +1071,25 @@ static const glui32 GSC_CANCEL_WAIT_1 = ' ', * help from the interpreter unless silenced. */ static void -gsc_output_register_help_request() -{ - gsc_help_requested = TRUE; +gsc_output_register_help_request() { + gsc_help_requested = TRUE; } static void -gsc_output_silence_help_hints() -{ - gsc_help_hints_silenced = TRUE; +gsc_output_silence_help_hints() { + gsc_help_hints_silenced = TRUE; } static void -gsc_output_provide_help_hint() -{ - if (gsc_help_requested && !gsc_help_hints_silenced) - { - g_vm->glk_set_style (style_Emphasized); - g_vm->glk_put_string ("[Try 'glk help' for help on special interpreter" - " commands]\n"); +gsc_output_provide_help_hint() { + if (gsc_help_requested && !gsc_help_hints_silenced) { + g_vm->glk_set_style(style_Emphasized); + g_vm->glk_put_string("[Try 'glk help' for help on special interpreter" + " commands]\n"); - gsc_help_requested = FALSE; - g_vm->glk_set_style (style_Normal); - } + gsc_help_requested = FALSE; + g_vm->glk_set_style(style_Normal); + } } @@ -1129,67 +1098,58 @@ gsc_output_provide_help_hint() * * Set a Glk style based on the top of the font stack and attributes. */ -static void gsc_set_glk_style() -{ - sc_bool is_monospaced; - sc_int font_size; - - /* Get the current font stack top, or default value. */ - if (gsc_font_index > 0) - { - is_monospaced = gsc_font_stack[gsc_font_index - 1].is_monospaced; - font_size = gsc_font_stack[gsc_font_index - 1].size; - } - else - { - is_monospaced = FALSE; - font_size = GSC_DEFAULT_FONT_SIZE; - } - - /* - * Map the font and current attributes into a Glk style. Because Glk styles - * aren't cumulative this has to be done by precedences. - */ - if (is_monospaced) - { - /* - * No matter the size or attributes, if monospaced use Preformatted - * style, as it's all we have. - */ - g_vm->glk_set_style (style_Preformatted); - } - else - { - /* - * For large and medium point sizes, use Header or Subheader styles - * respectively. - */ - if (font_size >= GSC_LARGE_FONT_SIZE) - g_vm->glk_set_style (style_Header); - else if (font_size >= GSC_MEDIUM_FONT_SIZE) - g_vm->glk_set_style (style_Subheader); - else - { - /* - * For bold, use Subheader; for italics, underline, or secondary - * color, use Emphasized. - */ - if (gsc_attribute_bold > 0) - g_vm->glk_set_style (style_Subheader); - else if (gsc_attribute_italic > 0 - || gsc_attribute_underline > 0 - || gsc_attribute_secondary_color > 0) - g_vm->glk_set_style (style_Emphasized); - else - { - /* - * There's nothing special about this text, so drop down to - * Normal style. - */ - g_vm->glk_set_style (style_Normal); - } - } - } +static void gsc_set_glk_style() { + sc_bool is_monospaced; + sc_int font_size; + + /* Get the current font stack top, or default value. */ + if (gsc_font_index > 0) { + is_monospaced = gsc_font_stack[gsc_font_index - 1].is_monospaced; + font_size = gsc_font_stack[gsc_font_index - 1].size; + } else { + is_monospaced = FALSE; + font_size = GSC_DEFAULT_FONT_SIZE; + } + + /* + * Map the font and current attributes into a Glk style. Because Glk styles + * aren't cumulative this has to be done by precedences. + */ + if (is_monospaced) { + /* + * No matter the size or attributes, if monospaced use Preformatted + * style, as it's all we have. + */ + g_vm->glk_set_style(style_Preformatted); + } else { + /* + * For large and medium point sizes, use Header or Subheader styles + * respectively. + */ + if (font_size >= GSC_LARGE_FONT_SIZE) + g_vm->glk_set_style(style_Header); + else if (font_size >= GSC_MEDIUM_FONT_SIZE) + g_vm->glk_set_style(style_Subheader); + else { + /* + * For bold, use Subheader; for italics, underline, or secondary + * color, use Emphasized. + */ + if (gsc_attribute_bold > 0) + g_vm->glk_set_style(style_Subheader); + else if (gsc_attribute_italic > 0 + || gsc_attribute_underline > 0 + || gsc_attribute_secondary_color > 0) + g_vm->glk_set_style(style_Emphasized); + else { + /* + * There's nothing special about this text, so drop down to + * Normal style. + */ + g_vm->glk_set_style(style_Normal); + } + } + } } @@ -1201,83 +1161,74 @@ static void gsc_set_glk_style() * font tag. Set the appropriate Glk style. */ static void -gsc_handle_font_tag (const sc_char *argument) -{ - /* Ignore the call on stack overrun. */ - if (gsc_font_index < GSC_MAX_STYLE_NESTING) - { - sc_char *lower, *face, *size; - sc_bool is_monospaced; - sc_int index_, font_size; - - /* Get the current top of stack, or default on empty stack. */ - if (gsc_font_index > 0) - { - is_monospaced = gsc_font_stack[gsc_font_index - 1].is_monospaced; - font_size = gsc_font_stack[gsc_font_index - 1].size; - } - else - { - is_monospaced = FALSE; - font_size = GSC_DEFAULT_FONT_SIZE; - } - - /* Copy and convert argument to all lowercase. */ - lower = (sc_char *)gsc_malloc (strlen (argument) + 1); - strcpy (lower, argument); - for (index_ = 0; lower[index_] != '\0'; index_++) - lower[index_] = g_vm->glk_char_to_lower (lower[index_]); - - /* Find any face= portion of the tag argument. */ - face = strstr (lower, "face="); - if (face) - { - /* - * There may be plenty of monospaced fonts, but we do only courier - * and terminal. - */ - is_monospaced = strncmp (face, "face=\"courier\"", 14) == 0 - || strncmp (face, "face=\"terminal\"", 15) == 0; - } - - /* Find the size= portion of the tag argument. */ - size = strstr (lower, "size="); - if (size) - { - sc_uint value; - - /* Deal with incremental and absolute sizes. */ - if (strncmp (size, "size=+", 6) == 0 - && sscanf (size, "size=+%lu", &value) == 1) - font_size += value; - else if (strncmp (size, "size=-", 6) == 0 - && sscanf (size, "size=-%lu", &value) == 1) - font_size -= value; - else if (sscanf (size, "size=%lu", &value) == 1) - font_size = value; - } - - /* Done with tag argument copy. */ - free (lower); - - /* - * Push the new font setting onto the font stack, and set Glk style. - */ - gsc_font_stack[gsc_font_index].is_monospaced = is_monospaced; - gsc_font_stack[gsc_font_index++].size = font_size; - gsc_set_glk_style(); - } +gsc_handle_font_tag(const sc_char *argument) { + /* Ignore the call on stack overrun. */ + if (gsc_font_index < GSC_MAX_STYLE_NESTING) { + sc_char *lower, *face, *size; + sc_bool is_monospaced; + sc_int index_, font_size; + + /* Get the current top of stack, or default on empty stack. */ + if (gsc_font_index > 0) { + is_monospaced = gsc_font_stack[gsc_font_index - 1].is_monospaced; + font_size = gsc_font_stack[gsc_font_index - 1].size; + } else { + is_monospaced = FALSE; + font_size = GSC_DEFAULT_FONT_SIZE; + } + + /* Copy and convert argument to all lowercase. */ + lower = (sc_char *)gsc_malloc(strlen(argument) + 1); + strcpy(lower, argument); + for (index_ = 0; lower[index_] != '\0'; index_++) + lower[index_] = g_vm->glk_char_to_lower(lower[index_]); + + /* Find any face= portion of the tag argument. */ + face = strstr(lower, "face="); + if (face) { + /* + * There may be plenty of monospaced fonts, but we do only courier + * and terminal. + */ + is_monospaced = strncmp(face, "face=\"courier\"", 14) == 0 + || strncmp(face, "face=\"terminal\"", 15) == 0; + } + + /* Find the size= portion of the tag argument. */ + size = strstr(lower, "size="); + if (size) { + sc_uint value; + + /* Deal with incremental and absolute sizes. */ + if (strncmp(size, "size=+", 6) == 0 + && sscanf(size, "size=+%lu", &value) == 1) + font_size += value; + else if (strncmp(size, "size=-", 6) == 0 + && sscanf(size, "size=-%lu", &value) == 1) + font_size -= value; + else if (sscanf(size, "size=%lu", &value) == 1) + font_size = value; + } + + /* Done with tag argument copy. */ + free(lower); + + /* + * Push the new font setting onto the font stack, and set Glk style. + */ + gsc_font_stack[gsc_font_index].is_monospaced = is_monospaced; + gsc_font_stack[gsc_font_index++].size = font_size; + gsc_set_glk_style(); + } } static void -gsc_handle_endfont_tag() -{ - /* Unless underrun, pop the font stack and set Glk style. */ - if (gsc_font_index > 0) - { - gsc_font_index--; - gsc_set_glk_style(); - } +gsc_handle_endfont_tag() { + /* Unless underrun, pop the font stack and set Glk style. */ + if (gsc_font_index > 0) { + gsc_font_index--; + gsc_set_glk_style(); + } } @@ -1288,60 +1239,56 @@ gsc_handle_endfont_tag() * tag. Set the appropriate Glk style. */ static void -gsc_handle_attribute_tag (sc_int tag) -{ - /* - * Increment the required attribute nesting counter, and set Glk style. - */ - switch (tag) - { - case SC_TAG_BOLD: - gsc_attribute_bold++; - break; - case SC_TAG_ITALICS: - gsc_attribute_italic++; - break; - case SC_TAG_UNDERLINE: - gsc_attribute_underline++; - break; - case SC_TAG_COLOR: - gsc_attribute_secondary_color++; - break; - default: - break; - } - gsc_set_glk_style(); +gsc_handle_attribute_tag(sc_int tag) { + /* + * Increment the required attribute nesting counter, and set Glk style. + */ + switch (tag) { + case SC_TAG_BOLD: + gsc_attribute_bold++; + break; + case SC_TAG_ITALICS: + gsc_attribute_italic++; + break; + case SC_TAG_UNDERLINE: + gsc_attribute_underline++; + break; + case SC_TAG_COLOR: + gsc_attribute_secondary_color++; + break; + default: + break; + } + gsc_set_glk_style(); } static void -gsc_handle_endattribute_tag (sc_int tag) -{ - /* - * Decrement the required attribute nesting counter, unless underrun, and - * set Glk style. - */ - switch (tag) - { - case SC_TAG_ENDBOLD: - if (gsc_attribute_bold > 0) - gsc_attribute_bold--; - break; - case SC_TAG_ENDITALICS: - if (gsc_attribute_italic > 0) - gsc_attribute_italic--; - break; - case SC_TAG_ENDUNDERLINE: - if (gsc_attribute_underline > 0) - gsc_attribute_underline--; - break; - case SC_TAG_ENDCOLOR: - if (gsc_attribute_secondary_color > 0) - gsc_attribute_secondary_color--; - break; - default: - break; - } - gsc_set_glk_style(); +gsc_handle_endattribute_tag(sc_int tag) { + /* + * Decrement the required attribute nesting counter, unless underrun, and + * set Glk style. + */ + switch (tag) { + case SC_TAG_ENDBOLD: + if (gsc_attribute_bold > 0) + gsc_attribute_bold--; + break; + case SC_TAG_ENDITALICS: + if (gsc_attribute_italic > 0) + gsc_attribute_italic--; + break; + case SC_TAG_ENDUNDERLINE: + if (gsc_attribute_underline > 0) + gsc_attribute_underline--; + break; + case SC_TAG_ENDCOLOR: + if (gsc_attribute_secondary_color > 0) + gsc_attribute_secondary_color--; + break; + default: + break; + } + gsc_set_glk_style(); } @@ -1351,62 +1298,55 @@ gsc_handle_endattribute_tag (sc_int tag) * If Glk offers timers, delay for the requested period. Otherwise, this * function does nothing. */ -static void gsc_handle_wait_tag(const sc_char *argument) -{ - double delay = 0.0; - - /* Ignore the wait tag if the Glk doesn't have timers. */ - if (!g_vm->glk_gestalt (gestalt_Timer, 0)) - return; - - /* Determine the delay time, and convert to milliseconds. */ - if (sscanf (argument, "%lf", &delay) == 1 && delay > 0.0) - { - glui32 milliseconds, timeout; - - /* - * Work with timeouts at 1/10 of the wait period, to minimize Glk - * timer jitter. Allow the timeout to be canceled by keypress, as a - * user convenience. - */ - milliseconds = (glui32) (delay * GSC_MILLISECONDS_PER_SECOND); - timeout = milliseconds / GSC_TIMEOUTS_COUNT; - if (timeout > 0) - { - glui32 delayed; - sc_bool is_completed; - - /* Request timer events, and let a keypress cancel the wait. */ - g_vm->glk_request_char_event (gsc_main_window); - g_vm->glk_request_timer_events (timeout); - - /* Loop until delay completed or canceled by a keypress. */ - is_completed = TRUE; - for (delayed = 0; delayed < milliseconds; delayed += timeout) - { - event_t event; - - gsc_event_wait_2 (evtype_CharInput, evtype_Timer, &event); - if (event.type == evtype_CharInput) - { - /* Cancel the delay, or reissue the input request. */ - if (event.val1 == GSC_CANCEL_WAIT_1 - || event.val1 == GSC_CANCEL_WAIT_2) - { - is_completed = FALSE; - break; - } - else - g_vm->glk_request_char_event (gsc_main_window); - } - } - - /* Cancel any pending character input, and stop timers. */ - if (is_completed) - g_vm->glk_cancel_char_event (gsc_main_window); - g_vm->glk_request_timer_events (0); - } - } +static void gsc_handle_wait_tag(const sc_char *argument) { + double delay = 0.0; + + /* Ignore the wait tag if the Glk doesn't have timers. */ + if (!g_vm->glk_gestalt(gestalt_Timer, 0)) + return; + + /* Determine the delay time, and convert to milliseconds. */ + if (sscanf(argument, "%lf", &delay) == 1 && delay > 0.0) { + glui32 milliseconds, timeout; + + /* + * Work with timeouts at 1/10 of the wait period, to minimize Glk + * timer jitter. Allow the timeout to be canceled by keypress, as a + * user convenience. + */ + milliseconds = (glui32)(delay * GSC_MILLISECONDS_PER_SECOND); + timeout = milliseconds / GSC_TIMEOUTS_COUNT; + if (timeout > 0) { + glui32 delayed; + sc_bool is_completed; + + /* Request timer events, and let a keypress cancel the wait. */ + g_vm->glk_request_char_event(gsc_main_window); + g_vm->glk_request_timer_events(timeout); + + /* Loop until delay completed or canceled by a keypress. */ + is_completed = TRUE; + for (delayed = 0; delayed < milliseconds; delayed += timeout) { + event_t event; + + gsc_event_wait_2(evtype_CharInput, evtype_Timer, &event); + if (event.type == evtype_CharInput) { + /* Cancel the delay, or reissue the input request. */ + if (event.val1 == GSC_CANCEL_WAIT_1 + || event.val1 == GSC_CANCEL_WAIT_2) { + is_completed = FALSE; + break; + } else + g_vm->glk_request_char_event(gsc_main_window); + } + } + + /* Cancel any pending character input, and stop timers. */ + if (is_completed) + g_vm->glk_cancel_char_event(gsc_main_window); + g_vm->glk_request_timer_events(0); + } + } } @@ -1417,15 +1357,14 @@ static void gsc_handle_wait_tag(const sc_char *argument) * style. */ static void -gsc_reset_glk_style() -{ - /* Reset the font stack and attributes, and set a normal style. */ - gsc_font_index = 0; - gsc_attribute_bold = 0; - gsc_attribute_italic = 0; - gsc_attribute_underline = 0; - gsc_attribute_secondary_color = 0; - gsc_set_glk_style(); +gsc_reset_glk_style() { + /* Reset the font stack and attributes, and set a normal style. */ + gsc_font_index = 0; + gsc_attribute_bold = 0; + gsc_attribute_italic = 0; + gsc_attribute_underline = 0; + gsc_attribute_secondary_color = 0; + gsc_set_glk_style(); } @@ -1436,88 +1375,84 @@ gsc_reset_glk_style() * here; several are ignored. */ void -os_print_tag (sc_int tag, const sc_char *argument) -{ - event_t event; - assert (argument); - - switch (tag) - { - case SC_TAG_CLS: - /* Clear the main text display window. */ - g_vm->glk_window_clear (gsc_main_window); - break; - - case SC_TAG_FONT: - /* Handle with specific tag handler function. */ - gsc_handle_font_tag (argument); - break; - - case SC_TAG_ENDFONT: - /* Handle with specific endtag handler function. */ - gsc_handle_endfont_tag (); - break; - - case SC_TAG_BOLD: - case SC_TAG_ITALICS: - case SC_TAG_UNDERLINE: - case SC_TAG_COLOR: - /* Handle with common attribute tag handler function. */ - gsc_handle_attribute_tag (tag); - break; - - case SC_TAG_ENDBOLD: - case SC_TAG_ENDITALICS: - case SC_TAG_ENDUNDERLINE: - case SC_TAG_ENDCOLOR: - /* Handle with common attribute endtag handler function. */ - gsc_handle_endattribute_tag (tag); - break; - - case SC_TAG_CENTER: - case SC_TAG_RIGHT: - case SC_TAG_ENDCENTER: - case SC_TAG_ENDRIGHT: - /* - * We don't center or justify text, but so that things look right we do - * want a newline on starting or ending such a section. - */ - g_vm->glk_put_char ('\n'); - break; - - case SC_TAG_WAIT: - /* - * Update the status line now only if it has its own window, then - * handle with a specialized handler. - */ - if (gsc_status_window) - gsc_status_notify (); - gsc_handle_wait_tag (argument); - break; - - case SC_TAG_WAITKEY: - /* - * If reading an input log, ignore; it disrupts replay. Write a newline - * to separate off any unterminated game output instead. - */ - if (!gsc_readlog_stream) - { - /* Update the status line now only if it has its own window. */ - if (gsc_status_window) - gsc_status_notify (); - - /* Request a character event, and wait for it to be filled. */ - g_vm->glk_request_char_event (gsc_main_window); - gsc_event_wait (evtype_CharInput, &event); - } - else - g_vm->glk_put_char ('\n'); - break; - - default: - /* Ignore unimplemented and unknown tags. */ - break; - } +os_print_tag(sc_int tag, const sc_char *argument) { + event_t event; + assert(argument); + + switch (tag) { + case SC_TAG_CLS: + /* Clear the main text display window. */ + g_vm->glk_window_clear(gsc_main_window); + break; + + case SC_TAG_FONT: + /* Handle with specific tag handler function. */ + gsc_handle_font_tag(argument); + break; + + case SC_TAG_ENDFONT: + /* Handle with specific endtag handler function. */ + gsc_handle_endfont_tag(); + break; + + case SC_TAG_BOLD: + case SC_TAG_ITALICS: + case SC_TAG_UNDERLINE: + case SC_TAG_COLOR: + /* Handle with common attribute tag handler function. */ + gsc_handle_attribute_tag(tag); + break; + + case SC_TAG_ENDBOLD: + case SC_TAG_ENDITALICS: + case SC_TAG_ENDUNDERLINE: + case SC_TAG_ENDCOLOR: + /* Handle with common attribute endtag handler function. */ + gsc_handle_endattribute_tag(tag); + break; + + case SC_TAG_CENTER: + case SC_TAG_RIGHT: + case SC_TAG_ENDCENTER: + case SC_TAG_ENDRIGHT: + /* + * We don't center or justify text, but so that things look right we do + * want a newline on starting or ending such a section. + */ + g_vm->glk_put_char('\n'); + break; + + case SC_TAG_WAIT: + /* + * Update the status line now only if it has its own window, then + * handle with a specialized handler. + */ + if (gsc_status_window) + gsc_status_notify(); + gsc_handle_wait_tag(argument); + break; + + case SC_TAG_WAITKEY: + /* + * If reading an input log, ignore; it disrupts replay. Write a newline + * to separate off any unterminated game output instead. + */ + if (!gsc_readlog_stream) { + /* Update the status line now only if it has its own window. */ + if (gsc_status_window) + gsc_status_notify(); + + /* Request a character event, and wait for it to be filled. */ + g_vm->glk_request_char_event(gsc_main_window); + gsc_event_wait(evtype_CharInput, &event); + } else + g_vm->glk_put_char('\n'); + break; + + default: + /* Ignore unimplemented and unknown tags. */ + break; + } } @@ -1527,30 +1462,30 @@ os_print_tag (sc_int tag, const sc_char *argument) * Print a text string to the main output window. */ void os_print_string(const sc_char *string) { - sc_bool is_monospaced; - assert (string); - assert (g_vm->glk_stream_get_current ()); - - /* - * Get the monospace font setting from the current top of stack, or - * default on empty stack. If set, we may need to use an alternative - * function to write this string. - */ - if (gsc_font_index > 0) - is_monospaced = gsc_font_stack[gsc_font_index - 1].is_monospaced; - else - is_monospaced = FALSE; - - /* - * The main window should always be the currently set window at this point, - * so we never be attempting monospaced output to the status window. - * Nevertheless, check anyway. - */ - if (is_monospaced - && g_vm->glk_stream_get_current () == g_vm->glk_window_get_stream (gsc_main_window)) - gsc_put_string_alternate (string); - else - gsc_put_string (string); + sc_bool is_monospaced; + assert(string); + assert(g_vm->glk_stream_get_current()); + + /* + * Get the monospace font setting from the current top of stack, or + * default on empty stack. If set, we may need to use an alternative + * function to write this string. + */ + if (gsc_font_index > 0) + is_monospaced = gsc_font_stack[gsc_font_index - 1].is_monospaced; + else + is_monospaced = FALSE; + + /* + * The main window should always be the currently set window at this point, + * so we never be attempting monospaced output to the status window. + * Nevertheless, check anyway. + */ + if (is_monospaced + && g_vm->glk_stream_get_current() == g_vm->glk_window_get_stream(gsc_main_window)) + gsc_put_string_alternate(string); + else + gsc_put_string(string); } @@ -1561,12 +1496,11 @@ void os_print_string(const sc_char *string) { * dedicated debugging window attempted. */ void -os_print_string_debug (const sc_char *string) -{ - assert (string); - assert (g_vm->glk_stream_get_current ()); +os_print_string_debug(const sc_char *string) { + assert(string); + assert(g_vm->glk_stream_get_current()); - gsc_put_string (string); + gsc_put_string(string); } @@ -1583,53 +1517,46 @@ os_print_string_debug (const sc_char *string) * string is one that hints that it's from the interpreter, not the game. */ static void -gsc_styled_string (glui32 style, const char *message) -{ - assert (message); +gsc_styled_string(glui32 style, const char *message) { + assert(message); - g_vm->glk_set_style (style); - g_vm->glk_put_string ((char *) message); - g_vm->glk_set_style (style_Normal); + g_vm->glk_set_style(style); + g_vm->glk_put_string((char *) message); + g_vm->glk_set_style(style_Normal); } static void -gsc_styled_char (glui32 style, char c) -{ - char buffer[2]; +gsc_styled_char(glui32 style, char c) { + char buffer[2]; - buffer[0] = c; - buffer[1] = '\0'; - gsc_styled_string (style, buffer); + buffer[0] = c; + buffer[1] = '\0'; + gsc_styled_string(style, buffer); } static void -gsc_standout_string (const char *message) -{ - gsc_styled_string (style_Emphasized, message); +gsc_standout_string(const char *message) { + gsc_styled_string(style_Emphasized, message); } static void -gsc_standout_char (char c) -{ - gsc_styled_char (style_Emphasized, c); +gsc_standout_char(char c) { + gsc_styled_char(style_Emphasized, c); } static void -gsc_normal_string (const char *message) -{ - gsc_styled_string (style_Normal, message); +gsc_normal_string(const char *message) { + gsc_styled_string(style_Normal, message); } static void -gsc_normal_char (char c) -{ - gsc_styled_char (style_Normal, c); +gsc_normal_char(char c) { + gsc_styled_char(style_Normal, c); } static void -gsc_header_string (const char *message) -{ - gsc_styled_string (style_Header, message); +gsc_header_string(const char *message) { + gsc_styled_string(style_Header, message); } @@ -1641,60 +1568,53 @@ gsc_header_string (const char *message) * it's sort of good enough for the moment. */ void -os_display_hints (sc_game game) -{ - sc_game_hint hint; - sc_int refused; - - /* For each hint, print the question, and confirm hint display. */ - refused = 0; - for (hint = sc_get_first_game_hint (game); - hint; hint = sc_get_next_game_hint (game, hint)) - { - const sc_char *hint_question, *hint_text; - - /* If enough refusals, offer a way out of the loop. */ - if (refused >= GSC_HINT_REFUSAL_LIMIT) - { - if (!os_confirm (GSC_CONF_CONTINUE_HINTS)) - break; - refused = 0; - } - - /* Pop the question. */ - hint_question = sc_get_game_hint_question (game, hint); - gsc_normal_char ('\n'); - gsc_standout_string (hint_question); - gsc_normal_char ('\n'); - - /* Print the subtle hint, or on to the next hint. */ - hint_text = sc_get_game_subtle_hint (game, hint); - if (hint_text) - { - if (!os_confirm (GSC_CONF_SUBTLE_HINT)) - { - refused++; - continue; - } - gsc_normal_char ('\n'); - gsc_standout_string (hint_text); - gsc_normal_string ("\n\n"); - } - - /* Print the less than subtle hint, or on to the next hint. */ - hint_text = sc_get_game_unsubtle_hint (game, hint); - if (hint_text) - { - if (!os_confirm (GSC_CONF_UNSUBTLE_HINT)) - { - refused++; - continue; - } - gsc_normal_char ('\n'); - gsc_standout_string (hint_text); - gsc_normal_string ("\n\n"); - } - } +os_display_hints(sc_game game) { + sc_game_hint hint; + sc_int refused; + + /* For each hint, print the question, and confirm hint display. */ + refused = 0; + for (hint = sc_get_first_game_hint(game); + hint; hint = sc_get_next_game_hint(game, hint)) { + const sc_char *hint_question, *hint_text; + + /* If enough refusals, offer a way out of the loop. */ + if (refused >= GSC_HINT_REFUSAL_LIMIT) { + if (!os_confirm(GSC_CONF_CONTINUE_HINTS)) + break; + refused = 0; + } + + /* Pop the question. */ + hint_question = sc_get_game_hint_question(game, hint); + gsc_normal_char('\n'); + gsc_standout_string(hint_question); + gsc_normal_char('\n'); + + /* Print the subtle hint, or on to the next hint. */ + hint_text = sc_get_game_subtle_hint(game, hint); + if (hint_text) { + if (!os_confirm(GSC_CONF_SUBTLE_HINT)) { + refused++; + continue; + } + gsc_normal_char('\n'); + gsc_standout_string(hint_text); + gsc_normal_string("\n\n"); + } + + /* Print the less than subtle hint, or on to the next hint. */ + hint_text = sc_get_game_unsubtle_hint(game, hint); + if (hint_text) { + if (!os_confirm(GSC_CONF_UNSUBTLE_HINT)) { + refused++; + continue; + } + gsc_normal_char('\n'); + gsc_standout_string(hint_text); + gsc_normal_string("\n\n"); + } + } } @@ -1709,21 +1629,19 @@ os_display_hints (sc_game game) * Stub functions. The unused variables defeat gcc warnings. */ void -os_play_sound (const sc_char *filepath, - sc_int offset, sc_int length, sc_bool is_looping) -{ - const sc_char *unused1; - sc_int unused2, unused3; - sc_bool unused4; - unused1 = filepath; - unused2 = offset; - unused3 = length; - unused4 = is_looping; +os_play_sound(const sc_char *filepath, + sc_int offset, sc_int length, sc_bool is_looping) { + const sc_char *unused1; + sc_int unused2, unused3; + sc_bool unused4; + unused1 = filepath; + unused2 = offset; + unused3 = length; + unused4 = is_looping; } void -os_stop_sound() -{ +os_stop_sound() { } @@ -1742,43 +1660,40 @@ os_stop_sound() static int gsclinux_graphics_enabled = TRUE; static char *gsclinux_game_file = nullptr; void -os_show_graphic (const sc_char *filepath, sc_int offset, sc_int length) -{ - const sc_char *unused1; - unused1 = filepath; - - if (length > 0 - && gsclinux_graphics_enabled && g_vm->glk_gestalt (gestalt_Graphics, 0)) - { - sc_char *buffer; - - /* - * Try to extract data with dd. Assuming that works, background xv to - * display the image, then background a job to delay ten seconds and - * then delete the temporary file containing the image. Systems lacking - * xv can usually use a small script, named xv, to invoke eog or an - * alternative image display binary. Not exactly finessed. - */ - assert (gsclinux_game_file); - buffer = gsc_malloc (strlen (gsclinux_game_file) + 128); - sprintf (buffer, "dd if=%s ibs=1c skip=%ld count=%ld obs=100k" - " of=/tmp/scare.jpg 2>/dev/null", - gsclinux_game_file, offset, length); - system (buffer); - free (buffer); - system ("xv /tmp/scare.jpg >/dev/null 2>&1 &"); - system ("( sleep 10; rm /tmp/scare.jpg ) >/dev/null 2>&1 &"); - } +os_show_graphic(const sc_char *filepath, sc_int offset, sc_int length) { + const sc_char *unused1; + unused1 = filepath; + + if (length > 0 + && gsclinux_graphics_enabled && g_vm->glk_gestalt(gestalt_Graphics, 0)) { + sc_char *buffer; + + /* + * Try to extract data with dd. Assuming that works, background xv to + * display the image, then background a job to delay ten seconds and + * then delete the temporary file containing the image. Systems lacking + * xv can usually use a small script, named xv, to invoke eog or an + * alternative image display binary. Not exactly finessed. + */ + assert(gsclinux_game_file); + buffer = gsc_malloc(strlen(gsclinux_game_file) + 128); + sprintf(buffer, "dd if=%s ibs=1c skip=%ld count=%ld obs=100k" + " of=/tmp/scare.jpg 2>/dev/null", + gsclinux_game_file, offset, length); + system(buffer); + free(buffer); + system("xv /tmp/scare.jpg >/dev/null 2>&1 &"); + system("( sleep 10; rm /tmp/scare.jpg ) >/dev/null 2>&1 &"); + } } #else void -os_show_graphic (const sc_char *filepath, sc_int offset, sc_int length) -{ - const sc_char *unused1; - sc_int unused2, unused3; - unused1 = filepath; - unused2 = offset; - unused3 = length; +os_show_graphic(const sc_char *filepath, sc_int offset, sc_int length) { + const sc_char *unused1; + sc_int unused2, unused3; + unused1 = filepath; + unused2 = offset; + unused3 = length; } #endif @@ -1793,74 +1708,65 @@ os_show_graphic (const sc_char *filepath, sc_int offset, sc_int length) * Turn game output scripting (logging) on and off. */ static void -gsc_command_script (const char *argument) -{ - assert (argument); - - if (sc_strcasecmp (argument, "on") == 0) - { - frefid_t fileref; - - if (gsc_transcript_stream) - { - gsc_normal_string ("Glk transcript is already on.\n"); - return; - } - - fileref = g_vm->glk_fileref_create_by_prompt (fileusage_Transcript - | fileusage_TextMode, - filemode_WriteAppend, 0); - if (!fileref) - { - gsc_standout_string ("Glk transcript failed.\n"); - return; - } - - gsc_transcript_stream = g_vm->glk_stream_open_file (fileref, - filemode_WriteAppend, 0); - g_vm->glk_fileref_destroy (fileref); - if (!gsc_transcript_stream) - { - gsc_standout_string ("Glk transcript failed.\n"); - return; - } - - g_vm->glk_window_set_echo_stream (gsc_main_window, gsc_transcript_stream); - - gsc_normal_string ("Glk transcript is now on.\n"); - } - - else if (sc_strcasecmp (argument, "off") == 0) - { - if (!gsc_transcript_stream) - { - gsc_normal_string ("Glk transcript is already off.\n"); - return; - } - - g_vm->glk_stream_close (gsc_transcript_stream, nullptr); - gsc_transcript_stream = nullptr; - - g_vm->glk_window_set_echo_stream (gsc_main_window, nullptr); - - gsc_normal_string ("Glk transcript is now off.\n"); - } - - else if (strlen (argument) == 0) - { - gsc_normal_string ("Glk transcript is "); - gsc_normal_string (gsc_transcript_stream ? "on" : "off"); - gsc_normal_string (".\n"); - } - - else - { - gsc_normal_string ("Glk transcript can be "); - gsc_standout_string ("on"); - gsc_normal_string (", or "); - gsc_standout_string ("off"); - gsc_normal_string (".\n"); - } +gsc_command_script(const char *argument) { + assert(argument); + + if (sc_strcasecmp(argument, "on") == 0) { + frefid_t fileref; + + if (gsc_transcript_stream) { + gsc_normal_string("Glk transcript is already on.\n"); + return; + } + + fileref = g_vm->glk_fileref_create_by_prompt(fileusage_Transcript + | fileusage_TextMode, + filemode_WriteAppend, 0); + if (!fileref) { + gsc_standout_string("Glk transcript failed.\n"); + return; + } + + gsc_transcript_stream = g_vm->glk_stream_open_file(fileref, + filemode_WriteAppend, 0); + g_vm->glk_fileref_destroy(fileref); + if (!gsc_transcript_stream) { + gsc_standout_string("Glk transcript failed.\n"); + return; + } + + g_vm->glk_window_set_echo_stream(gsc_main_window, gsc_transcript_stream); + + gsc_normal_string("Glk transcript is now on.\n"); + } + + else if (sc_strcasecmp(argument, "off") == 0) { + if (!gsc_transcript_stream) { + gsc_normal_string("Glk transcript is already off.\n"); + return; + } + + g_vm->glk_stream_close(gsc_transcript_stream, nullptr); + gsc_transcript_stream = nullptr; + + g_vm->glk_window_set_echo_stream(gsc_main_window, nullptr); + + gsc_normal_string("Glk transcript is now off.\n"); + } + + else if (strlen(argument) == 0) { + gsc_normal_string("Glk transcript is "); + gsc_normal_string(gsc_transcript_stream ? "on" : "off"); + gsc_normal_string(".\n"); + } + + else { + gsc_normal_string("Glk transcript can be "); + gsc_standout_string("on"); + gsc_normal_string(", or "); + gsc_standout_string("off"); + gsc_normal_string(".\n"); + } } @@ -1870,70 +1776,61 @@ gsc_command_script (const char *argument) * Turn game input logging on and off. */ static void -gsc_command_inputlog (const char *argument) -{ - assert (argument); - - if (sc_strcasecmp (argument, "on") == 0) - { - frefid_t fileref; - - if (gsc_inputlog_stream) - { - gsc_normal_string ("Glk input logging is already on.\n"); - return; - } - - fileref = g_vm->glk_fileref_create_by_prompt (fileusage_InputRecord - | fileusage_BinaryMode, - filemode_WriteAppend, 0); - if (!fileref) - { - gsc_standout_string ("Glk input logging failed.\n"); - return; - } - - gsc_inputlog_stream = g_vm->glk_stream_open_file (fileref, - filemode_WriteAppend, 0); - g_vm->glk_fileref_destroy (fileref); - if (!gsc_inputlog_stream) - { - gsc_standout_string ("Glk input logging failed.\n"); - return; - } - - gsc_normal_string ("Glk input logging is now on.\n"); - } - - else if (sc_strcasecmp (argument, "off") == 0) - { - if (!gsc_inputlog_stream) - { - gsc_normal_string ("Glk input logging is already off.\n"); - return; - } - - g_vm->glk_stream_close (gsc_inputlog_stream, nullptr); - gsc_inputlog_stream = nullptr; - - gsc_normal_string ("Glk input log is now off.\n"); - } - - else if (strlen (argument) == 0) - { - gsc_normal_string ("Glk input logging is "); - gsc_normal_string (gsc_inputlog_stream ? "on" : "off"); - gsc_normal_string (".\n"); - } - - else - { - gsc_normal_string ("Glk input logging can be "); - gsc_standout_string ("on"); - gsc_normal_string (", or "); - gsc_standout_string ("off"); - gsc_normal_string (".\n"); - } +gsc_command_inputlog(const char *argument) { + assert(argument); + + if (sc_strcasecmp(argument, "on") == 0) { + frefid_t fileref; + + if (gsc_inputlog_stream) { + gsc_normal_string("Glk input logging is already on.\n"); + return; + } + + fileref = g_vm->glk_fileref_create_by_prompt(fileusage_InputRecord + | fileusage_BinaryMode, + filemode_WriteAppend, 0); + if (!fileref) { + gsc_standout_string("Glk input logging failed.\n"); + return; + } + + gsc_inputlog_stream = g_vm->glk_stream_open_file(fileref, + filemode_WriteAppend, 0); + g_vm->glk_fileref_destroy(fileref); + if (!gsc_inputlog_stream) { + gsc_standout_string("Glk input logging failed.\n"); + return; + } + + gsc_normal_string("Glk input logging is now on.\n"); + } + + else if (sc_strcasecmp(argument, "off") == 0) { + if (!gsc_inputlog_stream) { + gsc_normal_string("Glk input logging is already off.\n"); + return; + } + + g_vm->glk_stream_close(gsc_inputlog_stream, nullptr); + gsc_inputlog_stream = nullptr; + + gsc_normal_string("Glk input log is now off.\n"); + } + + else if (strlen(argument) == 0) { + gsc_normal_string("Glk input logging is "); + gsc_normal_string(gsc_inputlog_stream ? "on" : "off"); + gsc_normal_string(".\n"); + } + + else { + gsc_normal_string("Glk input logging can be "); + gsc_standout_string("on"); + gsc_normal_string(", or "); + gsc_standout_string("off"); + gsc_normal_string(".\n"); + } } @@ -1943,76 +1840,66 @@ gsc_command_inputlog (const char *argument) * Set the game input log, to read input from a file. */ static void -gsc_command_readlog (const char *argument) -{ - assert (argument); - - if (sc_strcasecmp (argument, "on") == 0) - { - frefid_t fileref; - - if (gsc_readlog_stream) - { - gsc_normal_string ("Glk read log is already on.\n"); - return; - } - - fileref = g_vm->glk_fileref_create_by_prompt (fileusage_InputRecord - | fileusage_BinaryMode, - filemode_Read, 0); - if (!fileref) - { - gsc_standout_string ("Glk read log failed.\n"); - return; - } - - if (!g_vm->glk_fileref_does_file_exist (fileref)) - { - g_vm->glk_fileref_destroy (fileref); - gsc_standout_string ("Glk read log failed.\n"); - return; - } - - gsc_readlog_stream = g_vm->glk_stream_open_file (fileref, filemode_Read, 0); - g_vm->glk_fileref_destroy (fileref); - if (!gsc_readlog_stream) - { - gsc_standout_string ("Glk read log failed.\n"); - return; - } - - gsc_normal_string ("Glk read log is now on.\n"); - } - - else if (sc_strcasecmp (argument, "off") == 0) - { - if (!gsc_readlog_stream) - { - gsc_normal_string ("Glk read log is already off.\n"); - return; - } - - g_vm->glk_stream_close (gsc_readlog_stream, nullptr); - gsc_readlog_stream = nullptr; - - gsc_normal_string ("Glk read log is now off.\n"); - } - - else if (strlen (argument) == 0) - { - gsc_normal_string ("Glk read log is "); - gsc_normal_string (gsc_readlog_stream ? "on" : "off"); - gsc_normal_string (".\n"); - } - - else - { - gsc_normal_string ("Glk read log can be "); - gsc_standout_string ("on"); - gsc_normal_string (", or "); - gsc_standout_string ("off"); - gsc_normal_string (".\n"); - } +gsc_command_readlog(const char *argument) { + assert(argument); + + if (sc_strcasecmp(argument, "on") == 0) { + frefid_t fileref; + + if (gsc_readlog_stream) { + gsc_normal_string("Glk read log is already on.\n"); + return; + } + + fileref = g_vm->glk_fileref_create_by_prompt(fileusage_InputRecord + | fileusage_BinaryMode, + filemode_Read, 0); + if (!fileref) { + gsc_standout_string("Glk read log failed.\n"); + return; + } + + if (!g_vm->glk_fileref_does_file_exist(fileref)) { + g_vm->glk_fileref_destroy(fileref); + gsc_standout_string("Glk read log failed.\n"); + return; + } + + gsc_readlog_stream = g_vm->glk_stream_open_file(fileref, filemode_Read, 0); + g_vm->glk_fileref_destroy(fileref); + if (!gsc_readlog_stream) { + gsc_standout_string("Glk read log failed.\n"); + return; + } + + gsc_normal_string("Glk read log is now on.\n"); + } + + else if (sc_strcasecmp(argument, "off") == 0) { + if (!gsc_readlog_stream) { + gsc_normal_string("Glk read log is already off.\n"); + return; + } + + g_vm->glk_stream_close(gsc_readlog_stream, nullptr); + gsc_readlog_stream = nullptr; + + gsc_normal_string("Glk read log is now off.\n"); + } + + else if (strlen(argument) == 0) { + gsc_normal_string("Glk read log is "); + gsc_normal_string(gsc_readlog_stream ? "on" : "off"); + gsc_normal_string(".\n"); + } + + else { + gsc_normal_string("Glk read log can be "); + gsc_standout_string("on"); + gsc_normal_string(", or "); + gsc_standout_string("off"); + gsc_normal_string(".\n"); + } } @@ -2022,49 +1909,42 @@ gsc_command_readlog (const char *argument) * Turn abbreviation expansions on and off. */ static void -gsc_command_abbreviations (const char *argument) -{ - assert (argument); - - if (sc_strcasecmp (argument, "on") == 0) - { - if (gsc_abbreviations_enabled) - { - gsc_normal_string ("Glk abbreviation expansions are already on.\n"); - return; - } - - gsc_abbreviations_enabled = TRUE; - gsc_normal_string ("Glk abbreviation expansions are now on.\n"); - } - - else if (sc_strcasecmp (argument, "off") == 0) - { - if (!gsc_abbreviations_enabled) - { - gsc_normal_string ("Glk abbreviation expansions are already off.\n"); - return; - } - - gsc_abbreviations_enabled = FALSE; - gsc_normal_string ("Glk abbreviation expansions are now off.\n"); - } - - else if (strlen (argument) == 0) - { - gsc_normal_string ("Glk abbreviation expansions are "); - gsc_normal_string (gsc_abbreviations_enabled ? "on" : "off"); - gsc_normal_string (".\n"); - } - - else - { - gsc_normal_string ("Glk abbreviation expansions can be "); - gsc_standout_string ("on"); - gsc_normal_string (", or "); - gsc_standout_string ("off"); - gsc_normal_string (".\n"); - } +gsc_command_abbreviations(const char *argument) { + assert(argument); + + if (sc_strcasecmp(argument, "on") == 0) { + if (gsc_abbreviations_enabled) { + gsc_normal_string("Glk abbreviation expansions are already on.\n"); + return; + } + + gsc_abbreviations_enabled = TRUE; + gsc_normal_string("Glk abbreviation expansions are now on.\n"); + } + + else if (sc_strcasecmp(argument, "off") == 0) { + if (!gsc_abbreviations_enabled) { + gsc_normal_string("Glk abbreviation expansions are already off.\n"); + return; + } + + gsc_abbreviations_enabled = FALSE; + gsc_normal_string("Glk abbreviation expansions are now off.\n"); + } + + else if (strlen(argument) == 0) { + gsc_normal_string("Glk abbreviation expansions are "); + gsc_normal_string(gsc_abbreviations_enabled ? "on" : "off"); + gsc_normal_string(".\n"); + } + + else { + gsc_normal_string("Glk abbreviation expansions can be "); + gsc_standout_string("on"); + gsc_normal_string(", or "); + gsc_standout_string("off"); + gsc_normal_string(".\n"); + } } @@ -2075,31 +1955,29 @@ gsc_command_abbreviations (const char *argument) * Print out the Glk library version number. */ static void -gsc_command_print_version_number (glui32 version) -{ - char buffer[64]; +gsc_command_print_version_number(glui32 version) { + char buffer[64]; - sprintf (buffer, "%lu.%lu.%lu", - (unsigned long) version >> 16, - (unsigned long) (version >> 8) & 0xff, - (unsigned long) version & 0xff); - gsc_normal_string (buffer); + sprintf(buffer, "%lu.%lu.%lu", + (unsigned long) version >> 16, + (unsigned long)(version >> 8) & 0xff, + (unsigned long) version & 0xff); + gsc_normal_string(buffer); } static void -gsc_command_version (const char *argument) -{ - glui32 version; - assert (argument); +gsc_command_version(const char *argument) { + glui32 version; + assert(argument); - gsc_normal_string ("This is version "); - gsc_command_print_version_number (GSC_PORT_VERSION); - gsc_normal_string (" of the Glk SCARE port.\n"); + gsc_normal_string("This is version "); + gsc_command_print_version_number(GSC_PORT_VERSION); + gsc_normal_string(" of the Glk SCARE port.\n"); - version = g_vm->glk_gestalt (gestalt_Version, 0); - gsc_normal_string ("The Glk library version is "); - gsc_command_print_version_number (version); - gsc_normal_string (".\n"); + version = g_vm->glk_gestalt(gestalt_Version, 0); + gsc_normal_string("The Glk library version is "); + gsc_command_print_version_number(version); + gsc_normal_string(".\n"); } @@ -2110,36 +1988,31 @@ gsc_command_version (const char *argument) * Commands must be on already to enter this function. */ static void -gsc_command_commands (const char *argument) -{ - assert (argument); +gsc_command_commands(const char *argument) { + assert(argument); - if (sc_strcasecmp (argument, "on") == 0) - { - gsc_normal_string ("Glk commands are already on.\n"); - } + if (sc_strcasecmp(argument, "on") == 0) { + gsc_normal_string("Glk commands are already on.\n"); + } - else if (sc_strcasecmp (argument, "off") == 0) - { - gsc_commands_enabled = FALSE; - gsc_normal_string ("Glk commands are now off.\n"); - } + else if (sc_strcasecmp(argument, "off") == 0) { + gsc_commands_enabled = FALSE; + gsc_normal_string("Glk commands are now off.\n"); + } - else if (strlen (argument) == 0) - { - gsc_normal_string ("Glk commands are "); - gsc_normal_string (gsc_commands_enabled ? "on" : "off"); - gsc_normal_string (".\n"); - } + else if (strlen(argument) == 0) { + gsc_normal_string("Glk commands are "); + gsc_normal_string(gsc_commands_enabled ? "on" : "off"); + gsc_normal_string(".\n"); + } - else - { - gsc_normal_string ("Glk commands can be "); - gsc_standout_string ("on"); - gsc_normal_string (", or "); - gsc_standout_string ("off"); - gsc_normal_string (".\n"); - } + else { + gsc_normal_string("Glk commands can be "); + gsc_standout_string("on"); + gsc_normal_string(", or "); + gsc_standout_string("off"); + gsc_normal_string(".\n"); + } } @@ -2149,59 +2022,57 @@ gsc_command_commands (const char *argument) * Print licensing terms. */ static void -gsc_command_license (const char *argument) -{ - assert (argument); +gsc_command_license(const char *argument) { + assert(argument); - gsc_normal_string ("This program is free software; you can redistribute it" - " and/or modify it under the terms of version 2 of the" - " GNU General Public License as published by the Free" - " Software Foundation.\n\n"); + gsc_normal_string("This program is free software; you can redistribute it" + " and/or modify it under the terms of version 2 of the" + " GNU General Public License as published by the Free" + " Software Foundation.\n\n"); - gsc_normal_string ("This program is distributed in the hope that it will be" - " useful, but "); - gsc_standout_string ("WITHOUT ANY WARRANTY"); - gsc_normal_string ("; without even the implied warranty of "); - gsc_standout_string ("MERCHANTABILITY"); - gsc_normal_string (" or "); - gsc_standout_string ("FITNESS FOR A PARTICULAR PURPOSE"); - gsc_normal_string (". See the GNU General Public License for more" - " details.\n\n"); + gsc_normal_string("This program is distributed in the hope that it will be" + " useful, but "); + gsc_standout_string("WITHOUT ANY WARRANTY"); + gsc_normal_string("; without even the implied warranty of "); + gsc_standout_string("MERCHANTABILITY"); + gsc_normal_string(" or "); + gsc_standout_string("FITNESS FOR A PARTICULAR PURPOSE"); + gsc_normal_string(". See the GNU General Public License for more" + " details.\n\n"); - gsc_normal_string ("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., 51 Franklin" - " Street, Fifth Floor, Boston, MA 02110-1301 USA\n\n"); + gsc_normal_string("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., 51 Franklin" + " Street, Fifth Floor, Boston, MA 02110-1301 USA\n\n"); - gsc_normal_string ("Please report any bugs, omissions, or misfeatures to "); - gsc_standout_string ("simon_baldwin@yahoo.com"); - gsc_normal_string (".\n"); + gsc_normal_string("Please report any bugs, omissions, or misfeatures to "); + gsc_standout_string("simon_baldwin@yahoo.com"); + gsc_normal_string(".\n"); } /* Glk subcommands and handler functions. */ -typedef const struct -{ - const char * const command; /* Glk subcommand. */ - void (* const handler) (const char *argument); /* Subcommand handler. */ - const int takes_argument; /* Argument flag. */ +typedef const struct { + const char *const command; /* Glk subcommand. */ + void (* const handler)(const char *argument); /* Subcommand handler. */ + const int takes_argument; /* Argument flag. */ } gsc_command_t; typedef gsc_command_t *gsc_commandref_t; -static void gsc_command_summary (const char *argument); -static void gsc_command_help (const char *argument); +static void gsc_command_summary(const char *argument); +static void gsc_command_help(const char *argument); static gsc_command_t GSC_COMMAND_TABLE[] = { - {"summary", gsc_command_summary, FALSE}, - {"script", gsc_command_script, TRUE}, - {"inputlog", gsc_command_inputlog, TRUE}, - {"readlog", gsc_command_readlog, TRUE}, - {"abbreviations", gsc_command_abbreviations, TRUE}, - {"version", gsc_command_version, FALSE}, - {"commands", gsc_command_commands, TRUE}, - {"license", gsc_command_license, FALSE}, - {"help", gsc_command_help, TRUE}, - {nullptr, nullptr, FALSE} + {"summary", gsc_command_summary, FALSE}, + {"script", gsc_command_script, TRUE}, + {"inputlog", gsc_command_inputlog, TRUE}, + {"readlog", gsc_command_readlog, TRUE}, + {"abbreviations", gsc_command_abbreviations, TRUE}, + {"version", gsc_command_version, FALSE}, + {"commands", gsc_command_commands, TRUE}, + {"license", gsc_command_license, FALSE}, + {"help", gsc_command_help, TRUE}, + {nullptr, nullptr, FALSE} }; @@ -2211,24 +2082,22 @@ static gsc_command_t GSC_COMMAND_TABLE[] = { * Report all current Glk settings. */ static void -gsc_command_summary (const char *argument) -{ - gsc_commandref_t entry; - assert (argument); +gsc_command_summary(const char *argument) { + gsc_commandref_t entry; + assert(argument); - /* - * Call handlers that have status to report with an empty argument, - * prompting each to print its current setting. - */ - for (entry = GSC_COMMAND_TABLE; entry->command; entry++) - { - if (entry->handler == gsc_command_summary - || entry->handler == gsc_command_license - || entry->handler == gsc_command_help) - continue; + /* + * Call handlers that have status to report with an empty argument, + * prompting each to print its current setting. + */ + for (entry = GSC_COMMAND_TABLE; entry->command; entry++) { + if (entry->handler == gsc_command_summary + || entry->handler == gsc_command_license + || entry->handler == gsc_command_help) + continue; - entry->handler (""); - } + entry->handler(""); + } } @@ -2238,139 +2107,124 @@ gsc_command_summary (const char *argument) * Document the available Glk commands. */ static void -gsc_command_help (const char *command) -{ - gsc_commandref_t entry, matched; - assert (command); - - if (strlen (command) == 0) - { - gsc_normal_string ("Glk commands are"); - for (entry = GSC_COMMAND_TABLE; entry->command; entry++) - { - gsc_commandref_t next; - - next = entry + 1; - gsc_normal_string (next->command ? " " : " and "); - gsc_standout_string (entry->command); - gsc_normal_string (next->command ? "," : ".\n\n"); - } - - gsc_normal_string ("Glk commands may be abbreviated, as long as" - " the abbreviation is unambiguous. Use "); - gsc_standout_string ("glk help"); - gsc_normal_string (" followed by a Glk command name for help on that" - " command.\n"); - return; - } - - matched = nullptr; - for (entry = GSC_COMMAND_TABLE; entry->command; entry++) - { - if (sc_strncasecmp (command, entry->command, strlen (command)) == 0) - { - if (matched) - { - gsc_normal_string ("The Glk command "); - gsc_standout_string (command); - gsc_normal_string (" is ambiguous. Try "); - gsc_standout_string ("glk help"); - gsc_normal_string (" for more information.\n"); - return; - } - matched = entry; - } - } - if (!matched) - { - gsc_normal_string ("The Glk command "); - gsc_standout_string (command); - gsc_normal_string (" is not valid. Try "); - gsc_standout_string ("glk help"); - gsc_normal_string (" for more information.\n"); - return; - } - - if (matched->handler == gsc_command_summary) - { - gsc_normal_string ("Prints a summary of all the current Glk SCARE" - " settings.\n"); - } - - else if (matched->handler == gsc_command_script) - { - gsc_normal_string ("Logs the game's output to a file.\n\nUse "); - gsc_standout_string ("glk script on"); - gsc_normal_string (" to begin logging game output, and "); - gsc_standout_string ("glk script off"); - gsc_normal_string (" to end it. Glk SCARE will ask you for a file" - " when you turn scripts on.\n"); - } - - else if (matched->handler == gsc_command_inputlog) - { - gsc_normal_string ("Records the commands you type into a game.\n\nUse "); - gsc_standout_string ("glk inputlog on"); - gsc_normal_string (", to begin recording your commands, and "); - gsc_standout_string ("glk inputlog off"); - gsc_normal_string (" to turn off input logs. You can play back" - " recorded commands into a game with the "); - gsc_standout_string ("glk readlog"); - gsc_normal_string (" command.\n"); - } - - else if (matched->handler == gsc_command_readlog) - { - gsc_normal_string ("Plays back commands recorded with "); - gsc_standout_string ("glk inputlog on"); - gsc_normal_string (".\n\nUse "); - gsc_standout_string ("glk readlog on"); - gsc_normal_string (". Command play back stops at the end of the" - " file. You can also play back commands from a" - " text file created using any standard editor.\n"); - } - - else if (matched->handler == gsc_command_abbreviations) - { - gsc_normal_string ("Controls abbreviation expansion.\n\nGlk SCARE" - " automatically expands several standard single" - " letter abbreviations for you; for example, \"x\"" - " becomes \"examine\". Use "); - gsc_standout_string ("glk abbreviations on"); - gsc_normal_string (" to turn this feature on, and "); - gsc_standout_string ("glk abbreviations off"); - gsc_normal_string (" to turn it off. While the feature is on, you" - " can bypass abbreviation expansion for an" - " individual game command by prefixing it with a" - " single quote.\n"); - } - - else if (matched->handler == gsc_command_version) - { - gsc_normal_string ("Prints the version numbers of the Glk library" - " and the Glk SCARE port.\n"); - } - - else if (matched->handler == gsc_command_commands) - { - gsc_normal_string ("Turn off Glk commands.\n\nUse "); - gsc_standout_string ("glk commands off"); - gsc_normal_string (" to disable all Glk commands, including this one." - " Once turned off, there is no way to turn Glk" - " commands back on while inside the game.\n"); - } - - else if (matched->handler == gsc_command_license) - { - gsc_normal_string ("Prints Glk SCARE's software license.\n"); - } - - else if (matched->handler == gsc_command_help) - gsc_command_help (""); - - else - gsc_normal_string ("There is no help available on that Glk command." - " Sorry.\n"); +gsc_command_help(const char *command) { + gsc_commandref_t entry, matched; + assert(command); + + if (strlen(command) == 0) { + gsc_normal_string("Glk commands are"); + for (entry = GSC_COMMAND_TABLE; entry->command; entry++) { + gsc_commandref_t next; + + next = entry + 1; + gsc_normal_string(next->command ? " " : " and "); + gsc_standout_string(entry->command); + gsc_normal_string(next->command ? "," : ".\n\n"); + } + + gsc_normal_string("Glk commands may be abbreviated, as long as" + " the abbreviation is unambiguous. Use "); + gsc_standout_string("glk help"); + gsc_normal_string(" followed by a Glk command name for help on that" + " command.\n"); + return; + } + + matched = nullptr; + for (entry = GSC_COMMAND_TABLE; entry->command; entry++) { + if (sc_strncasecmp(command, entry->command, strlen(command)) == 0) { + if (matched) { + gsc_normal_string("The Glk command "); + gsc_standout_string(command); + gsc_normal_string(" is ambiguous. Try "); + gsc_standout_string("glk help"); + gsc_normal_string(" for more information.\n"); + return; + } + matched = entry; + } + } + if (!matched) { + gsc_normal_string("The Glk command "); + gsc_standout_string(command); + gsc_normal_string(" is not valid. Try "); + gsc_standout_string("glk help"); + gsc_normal_string(" for more information.\n"); + return; + } + + if (matched->handler == gsc_command_summary) { + gsc_normal_string("Prints a summary of all the current Glk SCARE" + " settings.\n"); + } + + else if (matched->handler == gsc_command_script) { + gsc_normal_string("Logs the game's output to a file.\n\nUse "); + gsc_standout_string("glk script on"); + gsc_normal_string(" to begin logging game output, and "); + gsc_standout_string("glk script off"); + gsc_normal_string(" to end it. Glk SCARE will ask you for a file" + " when you turn scripts on.\n"); + } + + else if (matched->handler == gsc_command_inputlog) { + gsc_normal_string("Records the commands you type into a game.\n\nUse "); + gsc_standout_string("glk inputlog on"); + gsc_normal_string(", to begin recording your commands, and "); + gsc_standout_string("glk inputlog off"); + gsc_normal_string(" to turn off input logs. You can play back" + " recorded commands into a game with the "); + gsc_standout_string("glk readlog"); + gsc_normal_string(" command.\n"); + } + + else if (matched->handler == gsc_command_readlog) { + gsc_normal_string("Plays back commands recorded with "); + gsc_standout_string("glk inputlog on"); + gsc_normal_string(".\n\nUse "); + gsc_standout_string("glk readlog on"); + gsc_normal_string(". Command play back stops at the end of the" + " file. You can also play back commands from a" + " text file created using any standard editor.\n"); + } + + else if (matched->handler == gsc_command_abbreviations) { + gsc_normal_string("Controls abbreviation expansion.\n\nGlk SCARE" + " automatically expands several standard single" + " letter abbreviations for you; for example, \"x\"" + " becomes \"examine\". Use "); + gsc_standout_string("glk abbreviations on"); + gsc_normal_string(" to turn this feature on, and "); + gsc_standout_string("glk abbreviations off"); + gsc_normal_string(" to turn it off. While the feature is on, you" + " can bypass abbreviation expansion for an" + " individual game command by prefixing it with a" + " single quote.\n"); + } + + else if (matched->handler == gsc_command_version) { + gsc_normal_string("Prints the version numbers of the Glk library" + " and the Glk SCARE port.\n"); + } + + else if (matched->handler == gsc_command_commands) { + gsc_normal_string("Turn off Glk commands.\n\nUse "); + gsc_standout_string("glk commands off"); + gsc_normal_string(" to disable all Glk commands, including this one." + " Once turned off, there is no way to turn Glk" + " commands back on while inside the game.\n"); + } + + else if (matched->handler == gsc_command_license) { + gsc_normal_string("Prints Glk SCARE's software license.\n"); + } + + else if (matched->handler == gsc_command_help) + gsc_command_help(""); + + else + gsc_normal_string("There is no help available on that Glk command." + " Sorry.\n"); } @@ -2381,103 +2235,94 @@ gsc_command_help (const char *command) * Glk port command, handle it and return TRUE, otherwise return FALSE. */ static int -gsc_command_escape (const char *string) -{ - int posn; - char *string_copy, *command, *argument; - assert (string); - - /* - * Return FALSE if the string doesn't begin with the Glk command escape - * introducer. - */ - posn = strspn (string, "\t "); - if (sc_strncasecmp (string + posn, "glk", strlen ("glk")) != 0) - return FALSE; - - /* Take a copy of the string, without any leading space or introducer. */ - string_copy = (char *)gsc_malloc (strlen (string + posn) + 1 - strlen ("glk")); - strcpy (string_copy, string + posn + strlen ("glk")); - - /* - * Find the subcommand; the first word in the string copy. Find its end, - * and ensure it terminates with a NUL. - */ - posn = strspn (string_copy, "\t "); - command = string_copy + posn; - posn += strcspn (string_copy + posn, "\t "); - if (string_copy[posn] != '\0') - string_copy[posn++] = '\0'; - - /* - * Now find any argument data for the command, ensuring it too terminates - * with a NUL. - */ - posn += strspn (string_copy + posn, "\t "); - argument = string_copy + posn; - posn += strcspn (string_copy + posn, "\t "); - string_copy[posn] = '\0'; - - /* - * Try to handle the command and argument as a Glk subcommand. If it - * doesn't run unambiguously, print command usage. Treat an empty command - * as "help". - */ - if (strlen (command) > 0) - { - gsc_commandref_t entry, matched; - int matches; - - /* - * Search for the first unambiguous table command string matching - * the command passed in. - */ - matches = 0; - matched = nullptr; - for (entry = GSC_COMMAND_TABLE; entry->command; entry++) - { - if (sc_strncasecmp (command, entry->command, strlen (command)) == 0) - { - matches++; - matched = entry; - } - } - - /* If the match was unambiguous, call the command handler. */ - if (matches == 1) - { - gsc_normal_char ('\n'); - matched->handler (argument); - - if (!matched->takes_argument && strlen (argument) > 0) - { - gsc_normal_string ("[The "); - gsc_standout_string (matched->command); - gsc_normal_string (" command ignores arguments.]\n"); - } - } - - /* No match, or the command was ambiguous. */ - else - { - gsc_normal_string ("\nThe Glk command "); - gsc_standout_string (command); - gsc_normal_string (" is "); - gsc_normal_string (matches == 0 ? "not valid" : "ambiguous"); - gsc_normal_string (". Try "); - gsc_standout_string ("glk help"); - gsc_normal_string (" for more information.\n"); - } - } - else - { - gsc_normal_char ('\n'); - gsc_command_help (""); - } - - /* The string contained a Glk command; return TRUE. */ - free (string_copy); - return TRUE; +gsc_command_escape(const char *string) { + int posn; + char *string_copy, *command, *argument; + assert(string); + + /* + * Return FALSE if the string doesn't begin with the Glk command escape + * introducer. + */ + posn = strspn(string, "\t "); + if (sc_strncasecmp(string + posn, "glk", strlen("glk")) != 0) + return FALSE; + + /* Take a copy of the string, without any leading space or introducer. */ + string_copy = (char *)gsc_malloc(strlen(string + posn) + 1 - strlen("glk")); + strcpy(string_copy, string + posn + strlen("glk")); + + /* + * Find the subcommand; the first word in the string copy. Find its end, + * and ensure it terminates with a NUL. + */ + posn = strspn(string_copy, "\t "); + command = string_copy + posn; + posn += strcspn(string_copy + posn, "\t "); + if (string_copy[posn] != '\0') + string_copy[posn++] = '\0'; + + /* + * Now find any argument data for the command, ensuring it too terminates + * with a NUL. + */ + posn += strspn(string_copy + posn, "\t "); + argument = string_copy + posn; + posn += strcspn(string_copy + posn, "\t "); + string_copy[posn] = '\0'; + + /* + * Try to handle the command and argument as a Glk subcommand. If it + * doesn't run unambiguously, print command usage. Treat an empty command + * as "help". + */ + if (strlen(command) > 0) { + gsc_commandref_t entry, matched; + int matches; + + /* + * Search for the first unambiguous table command string matching + * the command passed in. + */ + matches = 0; + matched = nullptr; + for (entry = GSC_COMMAND_TABLE; entry->command; entry++) { + if (sc_strncasecmp(command, entry->command, strlen(command)) == 0) { + matches++; + matched = entry; + } + } + + /* If the match was unambiguous, call the command handler. */ + if (matches == 1) { + gsc_normal_char('\n'); + matched->handler(argument); + + if (!matched->takes_argument && strlen(argument) > 0) { + gsc_normal_string("[The "); + gsc_standout_string(matched->command); + gsc_normal_string(" command ignores arguments.]\n"); + } + } + + /* No match, or the command was ambiguous. */ + else { + gsc_normal_string("\nThe Glk command "); + gsc_standout_string(command); + gsc_normal_string(" is "); + gsc_normal_string(matches == 0 ? "not valid" : "ambiguous"); + gsc_normal_string(". Try "); + gsc_standout_string("glk help"); + gsc_normal_string(" for more information.\n"); + } + } else { + gsc_normal_char('\n'); + gsc_command_help(""); + } + + /* The string contained a Glk command; return TRUE. */ + free(string_copy); + return TRUE; } @@ -2490,19 +2335,18 @@ static const char GSC_QUOTED_INPUT = '\''; /* Table of single-character command abbreviations. */ -typedef const struct -{ - const char abbreviation; /* Abbreviation character. */ - const char *const expansion; /* Expansion string. */ +typedef const struct { + const char abbreviation; /* Abbreviation character. */ + const char *const expansion; /* Expansion string. */ } gsc_abbreviation_t; typedef gsc_abbreviation_t *gsc_abbreviationref_t; static gsc_abbreviation_t GSC_ABBREVIATIONS[] = { - {'c', "close"}, {'g', "again"}, {'i', "inventory"}, - {'k', "attack"}, {'l', "look"}, {'p', "open"}, - {'q', "quit"}, {'r', "drop"}, {'t', "take"}, - {'x', "examine"}, {'y', "yes"}, {'z', "wait"}, - {'\0', nullptr} + {'c', "close"}, {'g', "again"}, {'i', "inventory"}, + {'k', "attack"}, {'l', "look"}, {'p', "open"}, + {'q', "quit"}, {'r', "drop"}, {'t', "take"}, + {'x', "examine"}, {'y', "yes"}, {'z', "wait"}, + {'\0', nullptr} }; @@ -2513,49 +2357,45 @@ static gsc_abbreviation_t GSC_ABBREVIATIONS[] = { * game systems. */ static void -gsc_expand_abbreviations (char *buffer, int size) -{ - char *command, abbreviation; - const char *expansion; - gsc_abbreviationref_t entry; - assert (buffer); - - /* Ignore anything that isn't a single letter command. */ - command = buffer + strspn (buffer, "\t "); - if (!(strlen (command) == 1 - || (strlen (command) > 1 && Common::isSpace(command[1])))) - return; - - /* Scan the abbreviations table for a match. */ - abbreviation = g_vm->glk_char_to_lower ((unsigned char) command[0]); - expansion = nullptr; - for (entry = GSC_ABBREVIATIONS; entry->expansion; entry++) - { - if (entry->abbreviation == abbreviation) - { - expansion = entry->expansion; - break; - } - } - - /* - * If a match found, check for a fit, then replace the character with the - * expansion string. - */ - if (expansion) - { - if (strlen (buffer) + strlen (expansion) - 1 >= (unsigned int) size) - return; - - memmove (command + strlen (expansion) - 1, command, strlen (command) + 1); - memcpy (command, expansion, strlen (expansion)); - - gsc_standout_string ("["); - gsc_standout_char (abbreviation); - gsc_standout_string (" -> "); - gsc_standout_string (expansion); - gsc_standout_string ("]\n"); - } +gsc_expand_abbreviations(char *buffer, int size) { + char *command, abbreviation; + const char *expansion; + gsc_abbreviationref_t entry; + assert(buffer); + + /* Ignore anything that isn't a single letter command. */ + command = buffer + strspn(buffer, "\t "); + if (!(strlen(command) == 1 + || (strlen(command) > 1 && Common::isSpace(command[1])))) + return; + + /* Scan the abbreviations table for a match. */ + abbreviation = g_vm->glk_char_to_lower((unsigned char) command[0]); + expansion = nullptr; + for (entry = GSC_ABBREVIATIONS; entry->expansion; entry++) { + if (entry->abbreviation == abbreviation) { + expansion = entry->expansion; + break; + } + } + + /* + * If a match found, check for a fit, then replace the character with the + * expansion string. + */ + if (expansion) { + if (strlen(buffer) + strlen(expansion) - 1 >= (unsigned int) size) + return; + + memmove(command + strlen(expansion) - 1, command, strlen(command) + 1); + memcpy(command, expansion, strlen(expansion)); + + gsc_standout_string("["); + gsc_standout_char(abbreviation); + gsc_standout_string(" -> "); + gsc_standout_string(expansion); + gsc_standout_string("]\n"); + } } @@ -2565,123 +2405,111 @@ gsc_expand_abbreviations (char *buffer, int size) * Read and return a line of player input. */ sc_bool -os_read_line (sc_char *buffer, sc_int length) -{ - sc_int characters; - assert (buffer && length > 0); - - /* If a help request is pending, provide a user hint. */ - gsc_output_provide_help_hint (); - - /* - * Ensure normal style, update the status line, and issue an input prompt. - */ - gsc_reset_glk_style (); - gsc_status_notify (); - g_vm->glk_put_string (">"); - - /* - * If we have an input log to read from, use that until it is exhausted. - * On end of file, close the stream and resume input from line requests. - */ - if (gsc_readlog_stream) - { - glui32 chars; - - /* Get the next line from the log stream. */ - chars = g_vm->glk_get_line_stream (gsc_readlog_stream, buffer, length); - if (chars > 0) - { - /* Echo the line just read in input style. */ - g_vm->glk_set_style (style_Input); - gsc_put_buffer (buffer, chars); - g_vm->glk_set_style (style_Normal); - - /* Return this line as player input. */ - return TRUE; - } - - /* - * We're at the end of the log stream. Close it, and then continue - * on to request a line from Glk. - */ - g_vm->glk_stream_close (gsc_readlog_stream, nullptr); - gsc_readlog_stream = nullptr; - } - - /* - * No input log being read, or we just hit the end of file on one. Revert - * to normal line input; start by getting a new line from Glk. - */ - characters = gsc_read_line (buffer, length - 1); - assert (characters <= length); - buffer[characters] = '\0'; - - /* - * If neither abbreviations nor local commands are enabled, use the data - * read above without further massaging. - */ - if (gsc_abbreviations_enabled || gsc_commands_enabled) - { - char *command; - - /* - * If the first non-space input character is a quote, bypass all - * abbreviation expansion and local command recognition, and use the - * unadulterated input, less introductory quote. - */ - command = buffer + strspn (buffer, "\t "); - if (command[0] == GSC_QUOTED_INPUT) - { - /* Delete the quote with memmove(). */ - memmove (command, command + 1, strlen (command)); - } - else - { - /* Check for, and expand, and abbreviated commands. */ - if (gsc_abbreviations_enabled) - gsc_expand_abbreviations (buffer, length); - - /* - * Check for standalone "help", then for Glk port special commands; - * suppress the interpreter's use of this input for Glk commands by - * returning FALSE. - */ - if (gsc_commands_enabled) - { - int posn; - - posn = strspn (buffer, "\t "); - if (sc_strncasecmp (buffer + posn, "help", strlen ("help"))== 0) - { - if (strspn (buffer + posn + strlen ("help"), "\t ") - == strlen (buffer + posn + strlen ("help"))) - { - gsc_output_register_help_request (); - } - } - - if (gsc_command_escape (buffer)) - { - gsc_output_silence_help_hints (); - return FALSE; - } - } - } - } - - /* - * If there is an input log active, log this input string to it. Note that - * by logging here we get any abbreviation expansions but we won't log glk - * special commands, nor any input read from a current open input log. - */ - if (gsc_inputlog_stream) - { - g_vm->glk_put_string_stream (gsc_inputlog_stream, buffer); - g_vm->glk_put_char_stream (gsc_inputlog_stream, '\n'); - } - - return TRUE; +os_read_line(sc_char *buffer, sc_int length) { + sc_int characters; + assert(buffer && length > 0); + + /* If a help request is pending, provide a user hint. */ + gsc_output_provide_help_hint(); + + /* + * Ensure normal style, update the status line, and issue an input prompt. + */ + gsc_reset_glk_style(); + gsc_status_notify(); + g_vm->glk_put_string(">"); + + /* + * If we have an input log to read from, use that until it is exhausted. + * On end of file, close the stream and resume input from line requests. + */ + if (gsc_readlog_stream) { + glui32 chars; + + /* Get the next line from the log stream. */ + chars = g_vm->glk_get_line_stream(gsc_readlog_stream, buffer, length); + if (chars > 0) { + /* Echo the line just read in input style. */ + g_vm->glk_set_style(style_Input); + gsc_put_buffer(buffer, chars); + g_vm->glk_set_style(style_Normal); + + /* Return this line as player input. */ + return TRUE; + } + + /* + * We're at the end of the log stream. Close it, and then continue + * on to request a line from Glk. + */ + g_vm->glk_stream_close(gsc_readlog_stream, nullptr); + gsc_readlog_stream = nullptr; + } + + /* + * No input log being read, or we just hit the end of file on one. Revert + * to normal line input; start by getting a new line from Glk. + */ + characters = gsc_read_line(buffer, length - 1); + assert(characters <= length); + buffer[characters] = '\0'; + + /* + * If neither abbreviations nor local commands are enabled, use the data + * read above without further massaging. + */ + if (gsc_abbreviations_enabled || gsc_commands_enabled) { + char *command; + + /* + * If the first non-space input character is a quote, bypass all + * abbreviation expansion and local command recognition, and use the + * unadulterated input, less introductory quote. + */ + command = buffer + strspn(buffer, "\t "); + if (command[0] == GSC_QUOTED_INPUT) { + /* Delete the quote with memmove(). */ + memmove(command, command + 1, strlen(command)); + } else { + /* Check for, and expand, and abbreviated commands. */ + if (gsc_abbreviations_enabled) + gsc_expand_abbreviations(buffer, length); + + /* + * Check for standalone "help", then for Glk port special commands; + * suppress the interpreter's use of this input for Glk commands by + * returning FALSE. + */ + if (gsc_commands_enabled) { + int posn; + + posn = strspn(buffer, "\t "); + if (sc_strncasecmp(buffer + posn, "help", strlen("help")) == 0) { + if (strspn(buffer + posn + strlen("help"), "\t ") + == strlen(buffer + posn + strlen("help"))) { + gsc_output_register_help_request(); + } + } + + if (gsc_command_escape(buffer)) { + gsc_output_silence_help_hints(); + return FALSE; + } + } + } + } + + /* + * If there is an input log active, log this input string to it. Note that + * by logging here we get any abbreviation expansions but we won't log glk + * special commands, nor any input read from a current open input log. + */ + if (gsc_inputlog_stream) { + g_vm->glk_put_string_stream(gsc_inputlog_stream, buffer); + g_vm->glk_put_char_stream(gsc_inputlog_stream, '\n'); + } + + return TRUE; } @@ -2693,12 +2521,11 @@ os_read_line (sc_char *buffer, sc_int length) * prompt. */ sc_bool -os_read_line_debug (sc_char *buffer, sc_int length) -{ - gsc_output_silence_help_hints (); - gsc_reset_glk_style (); - g_vm->glk_put_string ("[SCARE debug]"); - return os_read_line (buffer, length); +os_read_line_debug(sc_char *buffer, sc_int length) { + gsc_output_silence_help_hints(); + gsc_reset_glk_style(); + g_vm->glk_put_string("[SCARE debug]"); + return os_read_line(buffer, length); } @@ -2708,85 +2535,78 @@ os_read_line_debug (sc_char *buffer, sc_int length) * Confirm a game action with a yes/no prompt. */ sc_bool -os_confirm (sc_int type) -{ - sc_char response; - - /* - * Always allow game saves and hint display, and if we're reading from an - * input log, allow everything no matter what, on the assumption that the - * user knows what they are doing. - */ - if (gsc_readlog_stream - || type == SC_CONF_SAVE || type == SC_CONF_VIEW_HINTS) - return TRUE; - - /* Ensure back to normal style, and update status. */ - gsc_reset_glk_style (); - gsc_status_notify (); - - /* Prompt for the confirmation, based on the type. */ - if (type == GSC_CONF_SUBTLE_HINT) - g_vm->glk_put_string ("View the subtle hint for this topic"); - else if (type == GSC_CONF_UNSUBTLE_HINT) - g_vm->glk_put_string ("View the unsubtle hint for this topic"); - else if (type == GSC_CONF_CONTINUE_HINTS) - g_vm->glk_put_string ("Continue with hints"); - else - { - g_vm->glk_put_string ("Do you really want to "); - switch (type) - { - case SC_CONF_QUIT: - g_vm->glk_put_string ("quit"); - break; - case SC_CONF_RESTART: - g_vm->glk_put_string ("restart"); - break; - case SC_CONF_SAVE: - g_vm->glk_put_string ("save"); - break; - case SC_CONF_RESTORE: - g_vm->glk_put_string ("restore"); - break; - case SC_CONF_VIEW_HINTS: - g_vm->glk_put_string ("view hints"); - break; - default: - g_vm->glk_put_string ("do that"); - break; - } - } - g_vm->glk_put_string ("? "); - - /* Loop until 'yes' or 'no' returned. */ - do - { - event_t event; - - /* Wait for a standard key, ignoring Glk special keys. */ - do - { - g_vm->glk_request_char_event (gsc_main_window); - gsc_event_wait (evtype_CharInput, &event); - } - while (event.val1 > UCHAR_MAX); - response = g_vm->glk_char_to_upper (event.val1); - } - while (response != 'Y' && response != 'N'); - - /* Echo the confirmation response, and a new line. */ - g_vm->glk_set_style (style_Input); - g_vm->glk_put_string (response == 'Y' ? "Yes" : "No"); - g_vm->glk_set_style (style_Normal); - g_vm->glk_put_char ('\n'); - - /* Use a short delay on restarts, if confirmed. */ - if (type == SC_CONF_RESTART && response == 'Y') - gsc_short_delay (); - - /* Return TRUE if 'Y' was entered. */ - return (response == 'Y'); +os_confirm(sc_int type) { + sc_char response; + + /* + * Always allow game saves and hint display, and if we're reading from an + * input log, allow everything no matter what, on the assumption that the + * user knows what they are doing. + */ + if (gsc_readlog_stream + || type == SC_CONF_SAVE || type == SC_CONF_VIEW_HINTS) + return TRUE; + + /* Ensure back to normal style, and update status. */ + gsc_reset_glk_style(); + gsc_status_notify(); + + /* Prompt for the confirmation, based on the type. */ + if (type == GSC_CONF_SUBTLE_HINT) + g_vm->glk_put_string("View the subtle hint for this topic"); + else if (type == GSC_CONF_UNSUBTLE_HINT) + g_vm->glk_put_string("View the unsubtle hint for this topic"); + else if (type == GSC_CONF_CONTINUE_HINTS) + g_vm->glk_put_string("Continue with hints"); + else { + g_vm->glk_put_string("Do you really want to "); + switch (type) { + case SC_CONF_QUIT: + g_vm->glk_put_string("quit"); + break; + case SC_CONF_RESTART: + g_vm->glk_put_string("restart"); + break; + case SC_CONF_SAVE: + g_vm->glk_put_string("save"); + break; + case SC_CONF_RESTORE: + g_vm->glk_put_string("restore"); + break; + case SC_CONF_VIEW_HINTS: + g_vm->glk_put_string("view hints"); + break; + default: + g_vm->glk_put_string("do that"); + break; + } + } + g_vm->glk_put_string("? "); + + /* Loop until 'yes' or 'no' returned. */ + do { + event_t event; + + /* Wait for a standard key, ignoring Glk special keys. */ + do { + g_vm->glk_request_char_event(gsc_main_window); + gsc_event_wait(evtype_CharInput, &event); + } while (event.val1 > UCHAR_MAX); + response = g_vm->glk_char_to_upper(event.val1); + } while (response != 'Y' && response != 'N'); + + /* Echo the confirmation response, and a new line. */ + g_vm->glk_set_style(style_Input); + g_vm->glk_put_string(response == 'Y' ? "Yes" : "No"); + g_vm->glk_set_style(style_Normal); + g_vm->glk_put_char('\n'); + + /* Use a short delay on restarts, if confirmed. */ + if (type == SC_CONF_RESTART && response == 'Y') + gsc_short_delay(); + + /* Return TRUE if 'Y' was entered. */ + return (response == 'Y'); } @@ -2806,23 +2626,20 @@ static const glui32 GSC_DELAY_TIMEOUTS_COUNT = 10; * immediate, and abrupt, restart. */ static void -gsc_short_delay() -{ - /* Ignore the call if the Glk doesn't have timers. */ - if (g_vm->glk_gestalt (gestalt_Timer, 0)) - { - glui32 timeout; - - /* Timeout in small chunks to minimize Glk jitter. */ - g_vm->glk_request_timer_events (GSC_DELAY_TIMEOUT); - for (timeout = 0; timeout < GSC_DELAY_TIMEOUTS_COUNT; timeout++) - { - event_t event; +gsc_short_delay() { + /* Ignore the call if the Glk doesn't have timers. */ + if (g_vm->glk_gestalt(gestalt_Timer, 0)) { + glui32 timeout; + + /* Timeout in small chunks to minimize Glk jitter. */ + g_vm->glk_request_timer_events(GSC_DELAY_TIMEOUT); + for (timeout = 0; timeout < GSC_DELAY_TIMEOUTS_COUNT; timeout++) { + event_t event; - gsc_event_wait (evtype_Timer, &event); - } - g_vm->glk_request_timer_events (0); - } + gsc_event_wait(evtype_Timer, &event); + } + g_vm->glk_request_timer_events(0); + } } @@ -2834,36 +2651,31 @@ gsc_short_delay() * Return the event of that type. */ static void -gsc_event_wait_2 (glui32 wait_type_1, glui32 wait_type_2, event_t * event) -{ - assert (event); - - do - { - g_vm->glk_select (event); - if (g_vm->shouldQuit()) { - g_vm->glk_cancel_line_event(gsc_main_window, event); - return; - } - - switch (event->type) - { - case evtype_Arrange: - case evtype_Redraw: - /* Refresh any sensitive windows on size events. */ - gsc_status_redraw (); - break; - } - } - while (!(event->type == (EvType)wait_type_1 || event->type == (EvType)wait_type_2)); +gsc_event_wait_2(glui32 wait_type_1, glui32 wait_type_2, event_t *event) { + assert(event); + + do { + g_vm->glk_select(event); + if (g_vm->shouldQuit()) { + g_vm->glk_cancel_line_event(gsc_main_window, event); + return; + } + + switch (event->type) { + case evtype_Arrange: + case evtype_Redraw: + /* Refresh any sensitive windows on size events. */ + gsc_status_redraw(); + break; + } + } while (!(event->type == (EvType)wait_type_1 || event->type == (EvType)wait_type_2)); } static void -gsc_event_wait (glui32 wait_type, event_t * event) -{ - assert (event); +gsc_event_wait(glui32 wait_type, event_t *event) { + assert(event); - gsc_event_wait_2 (wait_type, evtype_None, event); + gsc_event_wait_2(wait_type, evtype_None, event); } @@ -2877,28 +2689,27 @@ gsc_event_wait (glui32 wait_type, event_t * event) * Open a file for save or restore, and return a Glk stream for the opened * file. */ -void *os_open_file (sc_bool is_save) { - glui32 usage, fmode; - frefid_t fileref; - strid_t stream; +void *os_open_file(sc_bool is_save) { + glui32 usage, fmode; + frefid_t fileref; + strid_t stream; - usage = fileusage_SavedGame | fileusage_BinaryMode; - fmode = is_save ? filemode_Write : filemode_Read; + usage = fileusage_SavedGame | fileusage_BinaryMode; + fmode = is_save ? filemode_Write : filemode_Read; - fileref = g_vm->glk_fileref_create_by_prompt(usage, (FileMode)fmode, 0); - if (!fileref) - return nullptr; + fileref = g_vm->glk_fileref_create_by_prompt(usage, (FileMode)fmode, 0); + if (!fileref) + return nullptr; - if (!is_save && !g_vm->glk_fileref_does_file_exist (fileref)) - { - g_vm->glk_fileref_destroy (fileref); - return nullptr; - } + if (!is_save && !g_vm->glk_fileref_does_file_exist(fileref)) { + g_vm->glk_fileref_destroy(fileref); + return nullptr; + } - stream = g_vm->glk_stream_open_file (fileref, (FileMode)fmode, 0); - g_vm->glk_fileref_destroy (fileref); + stream = g_vm->glk_stream_open_file(fileref, (FileMode)fmode, 0); + g_vm->glk_fileref_destroy(fileref); - return stream; + return stream; } @@ -2909,21 +2720,19 @@ void *os_open_file (sc_bool is_save) { * Write/read the given buffered data to/from the open Glk stream. */ void -os_write_file (void *opaque, const sc_byte *buffer, sc_int length) -{ - strid_t stream = (strid_t) opaque; - assert (opaque && buffer); +os_write_file(void *opaque, const sc_byte *buffer, sc_int length) { + strid_t stream = (strid_t) opaque; + assert(opaque && buffer); - g_vm->glk_put_buffer_stream (stream, (char *) buffer, length); + g_vm->glk_put_buffer_stream(stream, (char *) buffer, length); } sc_int -os_read_file (void *opaque, sc_byte *buffer, sc_int length) -{ - strid_t stream = (strid_t) opaque; - assert (opaque && buffer); +os_read_file(void *opaque, sc_byte *buffer, sc_int length) { + strid_t stream = (strid_t) opaque; + assert(opaque && buffer); - return g_vm->glk_get_buffer_stream (stream, (char *) buffer, length); + return g_vm->glk_get_buffer_stream(stream, (char *) buffer, length); } @@ -2933,12 +2742,11 @@ os_read_file (void *opaque, sc_byte *buffer, sc_int length) * Close the opened Glk stream. */ void -os_close_file (void *opaque) -{ - strid_t stream = (strid_t) opaque; - assert (opaque); +os_close_file(void *opaque) { + strid_t stream = (strid_t) opaque; + assert(opaque); - g_vm->glk_stream_close (stream, nullptr); + g_vm->glk_stream_close(stream, nullptr); } @@ -2981,68 +2789,63 @@ static sc_int gsc_callback(void *opaque, sc_byte *buffer, sc_int length) { * end option. Called on game completion. */ static enum gsc_end_option -gsc_get_ending_option() -{ - sc_char response; - - /* Ensure back to normal style, and update status. */ - gsc_reset_glk_style (); - gsc_status_notify (); - - /* Prompt for restart, undo, or quit. */ - g_vm->glk_put_string ("\nWould you like to RESTART, UNDO a turn, or QUIT? "); - - /* Loop until 'restart', 'undo' or 'quit'. */ - do - { - event_t event; - - do - { - g_vm->glk_request_char_event (gsc_main_window); - gsc_event_wait (evtype_CharInput, &event); - } - while (event.val1 > UCHAR_MAX); - response = g_vm->glk_char_to_upper (event.val1); - } - while (response != 'R' && response != 'U' && response != 'Q'); - - /* Echo the confirmation response, and a new line. */ - g_vm->glk_set_style (style_Input); - switch (response) - { - case 'R': - g_vm->glk_put_string ("Restart"); - break; - case 'U': - g_vm->glk_put_string ("Undo"); - break; - case 'Q': - g_vm->glk_put_string ("Quit"); - break; - default: - gsc_fatal ("GLK: Invalid response encountered"); - g_vm->glk_exit (); - } - g_vm->glk_set_style (style_Normal); - g_vm->glk_put_char ('\n'); - - /* Return the appropriate value for response. */ - switch (response) - { - case 'R': - return GAME_RESTART; - case 'U': - return GAME_UNDO; - case 'Q': - return GAME_QUIT; - default: - gsc_fatal ("GLK: Invalid response encountered"); - g_vm->glk_exit (); - } - - /* Unreachable; supplied to suppress compiler warning. */ - return GAME_QUIT; +gsc_get_ending_option() { + sc_char response; + + /* Ensure back to normal style, and update status. */ + gsc_reset_glk_style(); + gsc_status_notify(); + + /* Prompt for restart, undo, or quit. */ + g_vm->glk_put_string("\nWould you like to RESTART, UNDO a turn, or QUIT? "); + + /* Loop until 'restart', 'undo' or 'quit'. */ + do + { + event_t event; + + do + { + g_vm->glk_request_char_event(gsc_main_window); + gsc_event_wait(evtype_CharInput, &event); + } while (event.val1 > UCHAR_MAX); + response = g_vm->glk_char_to_upper(event.val1); + } while (response != 'R' && response != 'U' && response != 'Q'); + + /* Echo the confirmation response, and a new line. */ + g_vm->glk_set_style(style_Input); + switch (response) { + case 'R': + g_vm->glk_put_string("Restart"); + break; + case 'U': + g_vm->glk_put_string("Undo"); + break; + case 'Q': + g_vm->glk_put_string("Quit"); + break; + default: + gsc_fatal("GLK: Invalid response encountered"); + g_vm->glk_exit(); + } + g_vm->glk_set_style(style_Normal); + g_vm->glk_put_char('\n'); + + /* Return the appropriate value for response. */ + switch (response) { + case 'R': + return GAME_RESTART; + case 'U': + return GAME_UNDO; + case 'Q': + return GAME_QUIT; + default: + gsc_fatal("GLK: Invalid response encountered"); + g_vm->glk_exit(); + } + + /* Unreachable; supplied to suppress compiler warning. */ + return GAME_QUIT; } @@ -3057,16 +2860,14 @@ gsc_get_ending_option() */ static int gsc_startup_code(Common::SeekableReadStream *game_stream, strid_t restore_stream, - sc_uint trace_flags, sc_bool enable_debugger, - sc_bool stable_random, const sc_char *locale) -{ + sc_uint trace_flags, sc_bool enable_debugger, + sc_bool stable_random, const sc_char *locale) { winid_t window; assert(game_stream); /* Open a temporary Glk main window. */ window = g_vm->glk_window_open(0, 0, 0, wintype_TextBuffer, 0); - if (window) - { + if (window) { /* Clear and initialize the temporary window. */ g_vm->glk_window_clear(window); g_vm->glk_set_window(window); @@ -3113,42 +2914,35 @@ gsc_startup_code(Common::SeekableReadStream *game_stream, strid_t restore_stream */ sc_set_trace_flags(trace_flags); gsc_game = sc_game_from_callback(gsc_callback, game_stream); - if (!gsc_game) - { + if (!gsc_game) { gsc_game = nullptr; gsc_game_message = "Unable to load an Adrift game from the requested file."; - } - else + } else gsc_game_message = nullptr; /* * If the game was created successfully and there is a restore stream, try * to immediately restore the game from that stream. */ - if (gsc_game && restore_stream) - { - if (!sc_load_game_from_callback(gsc_game, gsc_callback, restore_stream)) - { + if (gsc_game && restore_stream) { + if (!sc_load_game_from_callback(gsc_game, gsc_callback, restore_stream)) { sc_free_game(gsc_game); gsc_game = nullptr; gsc_game_message = "Unable to restore this Adrift game from the requested file."; - } - else + } else gsc_game_message = nullptr; } if (restore_stream) g_vm->glk_stream_close(restore_stream, nullptr); /* If successful, set game debugging and synchronize to the core's locale. */ - if (gsc_game) - { + if (gsc_game) { sc_set_game_debugger_enabled(gsc_game, enable_debugger); gsc_set_locale(sc_get_locale()); } /* Set portable and predictable random number generation if requested. */ - if (stable_random) - { + if (stable_random) { sc_set_portable_random(TRUE); sc_reseed_random_sequence(1); } @@ -3167,126 +2961,112 @@ gsc_startup_code(Common::SeekableReadStream *game_stream, strid_t restore_stream } static void -gsc_main() -{ - sc_bool is_running; - - /* Ensure SCARE internal types have the right sizes. */ - if (!(sizeof (sc_byte) == 1 && sizeof (sc_char) == 1 - && sizeof (sc_uint) >= 4 && sizeof (sc_int) >= 4 - && sizeof (sc_uint) <= 8 && sizeof (sc_int) <= 8)) - { - gsc_fatal ("GLK: Types sized incorrectly, recompilation is needed"); - g_vm->glk_exit (); - } - - /* Create the Glk window, and set its stream as the current one. */ - gsc_main_window = g_vm->glk_window_open (0, 0, 0, wintype_TextBuffer, 0); - if (!gsc_main_window) - { - gsc_fatal ("GLK: Can't open main window"); - g_vm->glk_exit (); - } - g_vm->glk_window_clear (gsc_main_window); - g_vm->glk_set_window (gsc_main_window); - g_vm->glk_set_style (style_Normal); - - /* If there's a problem with the game file, complain now. */ - if (!gsc_game) - { - assert (gsc_game_message); - gsc_header_string ("Glk SCARE Error\n\n"); - gsc_normal_string (gsc_game_message); - gsc_normal_char ('\n'); - g_vm->glk_exit (); - } - - /* Try to create a one-line status window. We can live without it. */ - g_vm->glk_stylehint_set (wintype_TextGrid, style_User1, stylehint_ReverseColor, 1); - gsc_status_window = g_vm->glk_window_open (gsc_main_window, - winmethod_Above | winmethod_Fixed, - 1, wintype_TextGrid, 0); - - /* Repeat the game until no more restarts requested. */ - is_running = TRUE; - while (is_running) - { - /* Run the game until it ends, or the user quits. */ - gsc_status_notify (); - sc_interpret_game (gsc_game); - - /* - * If the game did not complete, the user quit explicitly, so leave the - * game repeat loop. - */ - if (!sc_has_game_completed (gsc_game)) - { - is_running = FALSE; - break; - } - - /* - * If reading from an input log, close it now. We need to request a - * user selection, probably modal, and after that we probably don't - * want the follow-on readlog data being used as game input. - */ - if (gsc_readlog_stream) - { - g_vm->glk_stream_close (gsc_readlog_stream, nullptr); - gsc_readlog_stream = nullptr; - } - - /* - * Get user selection of restart, undo a turn, or quit completed game. - * If undo is unavailable (this should not be possible), degrade to - * restart. - */ - switch (gsc_get_ending_option ()) - { - case GAME_RESTART: - gsc_short_delay (); - sc_restart_game (gsc_game); - break; - - case GAME_UNDO: - if (sc_is_game_undo_available (gsc_game)) - { - sc_undo_game_turn (gsc_game); - gsc_normal_string ("The previous turn has been undone.\n"); - } - else - { - gsc_normal_string ("Sorry, no undo is available.\n"); - gsc_short_delay (); - sc_restart_game (gsc_game); - } - break; - - case GAME_QUIT: - is_running = FALSE; - break; - } - } - - /* All done -- release game resources. */ - sc_free_game (gsc_game); - - /* Close any open transcript, input log, and/or read log. */ - if (gsc_transcript_stream) - { - g_vm->glk_stream_close (gsc_transcript_stream, nullptr); - gsc_transcript_stream = nullptr; - } - if (gsc_inputlog_stream) - { - g_vm->glk_stream_close (gsc_inputlog_stream, nullptr); - gsc_inputlog_stream = nullptr; - } - if (gsc_readlog_stream) - { - g_vm->glk_stream_close (gsc_readlog_stream, nullptr); - gsc_readlog_stream = nullptr; - } +gsc_main() { + sc_bool is_running; + + /* Ensure SCARE internal types have the right sizes. */ + if (!(sizeof(sc_byte) == 1 && sizeof(sc_char) == 1 + && sizeof(sc_uint) >= 4 && sizeof(sc_int) >= 4 + && sizeof(sc_uint) <= 8 && sizeof(sc_int) <= 8)) { + gsc_fatal("GLK: Types sized incorrectly, recompilation is needed"); + g_vm->glk_exit(); + } + + /* Create the Glk window, and set its stream as the current one. */ + gsc_main_window = g_vm->glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + if (!gsc_main_window) { + gsc_fatal("GLK: Can't open main window"); + g_vm->glk_exit(); + } + g_vm->glk_window_clear(gsc_main_window); + g_vm->glk_set_window(gsc_main_window); + g_vm->glk_set_style(style_Normal); + + /* If there's a problem with the game file, complain now. */ + if (!gsc_game) { + assert(gsc_game_message); + gsc_header_string("Glk SCARE Error\n\n"); + gsc_normal_string(gsc_game_message); + gsc_normal_char('\n'); + g_vm->glk_exit(); + } + + /* Try to create a one-line status window. We can live without it. */ + g_vm->glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1); + gsc_status_window = g_vm->glk_window_open(gsc_main_window, + winmethod_Above | winmethod_Fixed, + 1, wintype_TextGrid, 0); + + /* Repeat the game until no more restarts requested. */ + is_running = TRUE; + while (is_running) { + /* Run the game until it ends, or the user quits. */ + gsc_status_notify(); + sc_interpret_game(gsc_game); + + /* + * If the game did not complete, the user quit explicitly, so leave the + * game repeat loop. + */ + if (!sc_has_game_completed(gsc_game)) { + is_running = FALSE; + break; + } + + /* + * If reading from an input log, close it now. We need to request a + * user selection, probably modal, and after that we probably don't + * want the follow-on readlog data being used as game input. + */ + if (gsc_readlog_stream) { + g_vm->glk_stream_close(gsc_readlog_stream, nullptr); + gsc_readlog_stream = nullptr; + } + + /* + * Get user selection of restart, undo a turn, or quit completed game. + * If undo is unavailable (this should not be possible), degrade to + * restart. + */ + switch (gsc_get_ending_option()) { + case GAME_RESTART: + gsc_short_delay(); + sc_restart_game(gsc_game); + break; + + case GAME_UNDO: + if (sc_is_game_undo_available(gsc_game)) { + sc_undo_game_turn(gsc_game); + gsc_normal_string("The previous turn has been undone.\n"); + } else { + gsc_normal_string("Sorry, no undo is available.\n"); + gsc_short_delay(); + sc_restart_game(gsc_game); + } + break; + + case GAME_QUIT: + is_running = FALSE; + break; + } + } + + /* All done -- release game resources. */ + sc_free_game(gsc_game); + + /* Close any open transcript, input log, and/or read log. */ + if (gsc_transcript_stream) { + g_vm->glk_stream_close(gsc_transcript_stream, nullptr); + gsc_transcript_stream = nullptr; + } + if (gsc_inputlog_stream) { + g_vm->glk_stream_close(gsc_inputlog_stream, nullptr); + gsc_inputlog_stream = nullptr; + } + if (gsc_readlog_stream) { + g_vm->glk_stream_close(gsc_readlog_stream, nullptr); + gsc_readlog_stream = nullptr; + } } @@ -3325,21 +3105,33 @@ void adrift_main() { * Glk arguments for UNIX versions of the Glk interpreter. */ glkunix_argumentlist_t glkunix_arguments[] = { - {(char *) "-nc", glkunix_arg_NoValue, - (char *) "-nc No local handling for Glk special commands"}, - {(char *) "-na", glkunix_arg_NoValue, - (char *) "-na Turn off abbreviation expansions"}, - {(char *) "-nu", glkunix_arg_NoValue, - (char *) "-nu Turn off any use of Unicode output"}, + { + (char *) "-nc", glkunix_arg_NoValue, + (char *) "-nc No local handling for Glk special commands" + }, + { + (char *) "-na", glkunix_arg_NoValue, + (char *) "-na Turn off abbreviation expansions" + }, + { + (char *) "-nu", glkunix_arg_NoValue, + (char *) "-nu Turn off any use of Unicode output" + }, #ifdef LINUX_GRAPHICS - {(char *) "-ng", glkunix_arg_NoValue, - (char *) "-ng Turn off attempts at game graphics"}, + { + (char *) "-ng", glkunix_arg_NoValue, + (char *) "-ng Turn off attempts at game graphics" + }, #endif - {(char *) "-r", glkunix_arg_ValueFollows, - (char *) "-r FILE Restore from FILE on starting the game"}, - {(char *) "", glkunix_arg_ValueCanFollow, - (char *) "filename game to run"}, - {nullptr, glkunix_arg_End, nullptr} + { + (char *) "-r", glkunix_arg_ValueFollows, + (char *) "-r FILE Restore from FILE on starting the game" + }, + { + (char *) "", glkunix_arg_ValueCanFollow, + (char *) "filename game to run" + }, + {nullptr, glkunix_arg_End, nullptr} }; #endif diff --git a/engines/glk/adrift/scare.h b/engines/glk/adrift/scare.h index 43ce75af1d..d4e02314e6 100644 --- a/engines/glk/adrift/scare.h +++ b/engines/glk/adrift/scare.h @@ -50,67 +50,67 @@ typedef unsigned long sc_uint; typedef int sc_bool; /* Enumerated confirmation types, passed to os_confirm(). */ -enum -{ SC_CONF_QUIT = 0, - SC_CONF_RESTART, SC_CONF_SAVE, SC_CONF_RESTORE, SC_CONF_VIEW_HINTS +enum { + SC_CONF_QUIT = 0, + SC_CONF_RESTART, SC_CONF_SAVE, SC_CONF_RESTORE, SC_CONF_VIEW_HINTS }; /* HTML-like tag enumerated values, passed to os_print_tag(). */ -enum -{ SC_TAG_UNKNOWN = 0, SC_TAG_ITALICS, SC_TAG_ENDITALICS, SC_TAG_BOLD, - SC_TAG_ENDBOLD, SC_TAG_UNDERLINE, SC_TAG_ENDUNDERLINE, SC_TAG_COLOR, - SC_TAG_ENDCOLOR, SC_TAG_FONT, SC_TAG_ENDFONT, SC_TAG_BGCOLOR, SC_TAG_CENTER, - SC_TAG_ENDCENTER, SC_TAG_RIGHT, SC_TAG_ENDRIGHT, SC_TAG_WAIT, SC_TAG_WAITKEY, - SC_TAG_CLS, - - /* British spelling equivalents. */ - SC_TAG_COLOUR = SC_TAG_COLOR, - SC_TAG_ENDCOLOUR = SC_TAG_ENDCOLOR, - SC_TAG_BGCOLOUR = SC_TAG_BGCOLOR, - SC_TAG_CENTRE = SC_TAG_CENTER, - SC_TAG_ENDCENTRE = SC_TAG_ENDCENTER +enum { + SC_TAG_UNKNOWN = 0, SC_TAG_ITALICS, SC_TAG_ENDITALICS, SC_TAG_BOLD, + SC_TAG_ENDBOLD, SC_TAG_UNDERLINE, SC_TAG_ENDUNDERLINE, SC_TAG_COLOR, + SC_TAG_ENDCOLOR, SC_TAG_FONT, SC_TAG_ENDFONT, SC_TAG_BGCOLOR, SC_TAG_CENTER, + SC_TAG_ENDCENTER, SC_TAG_RIGHT, SC_TAG_ENDRIGHT, SC_TAG_WAIT, SC_TAG_WAITKEY, + SC_TAG_CLS, + + /* British spelling equivalents. */ + SC_TAG_COLOUR = SC_TAG_COLOR, + SC_TAG_ENDCOLOUR = SC_TAG_ENDCOLOR, + SC_TAG_BGCOLOUR = SC_TAG_BGCOLOR, + SC_TAG_CENTRE = SC_TAG_CENTER, + SC_TAG_ENDCENTRE = SC_TAG_ENDCENTER }; /* OS interface function prototypes; interpreters must define these. */ typedef void *sc_game; -extern void os_print_string (const sc_char *string); +extern void os_print_string(const sc_char *string); extern void os_print_tag(sc_int tag, const sc_char *argument); -extern void os_play_sound (const sc_char *filepath, - sc_int offset, sc_int length, sc_bool is_looping); +extern void os_play_sound(const sc_char *filepath, + sc_int offset, sc_int length, sc_bool is_looping); extern void os_stop_sound(); -extern void os_show_graphic (const sc_char *filepath, - sc_int offset, sc_int length); +extern void os_show_graphic(const sc_char *filepath, + sc_int offset, sc_int length); extern sc_bool os_read_line(sc_char *buffer, sc_int length); extern sc_bool os_confirm(sc_int type); extern void *os_open_file(sc_bool is_save); -extern void os_write_file (void *opaque, const sc_byte *buffer, sc_int length); -extern sc_int os_read_file (void *opaque, sc_byte *buffer, sc_int length); -extern void os_close_file (void *opaque); +extern void os_write_file(void *opaque, const sc_byte *buffer, sc_int length); +extern sc_int os_read_file(void *opaque, sc_byte *buffer, sc_int length); +extern void os_close_file(void *opaque); extern void os_display_hints(sc_game game); -extern void os_print_string_debug (const sc_char *string); +extern void os_print_string_debug(const sc_char *string); extern sc_bool os_read_line_debug(sc_char *buffer, sc_int length); /* Interpreter trace flag bits, passed to sc_set_trace_flags(). */ -enum -{ SC_TRACE_PARSE = 1, SC_TRACE_PROPERTIES = 2, SC_TRACE_VARIABLES = 4, - SC_TRACE_PARSER = 8, SC_TRACE_LIBRARY = 16, SC_TRACE_EVENTS = 32, - SC_TRACE_NPCS = 64, SC_TRACE_OBJECTS = 128, SC_TRACE_TASKS = 256, - SC_TRACE_PRINTFILTER = 512, - - SC_DUMP_TAF = 1024, SC_DUMP_PROPERTIES = 2048, SC_DUMP_VARIABLES = 4096, - SC_DUMP_PARSER_TREES = 8192, SC_DUMP_LOCALE_TABLES = 16384 +enum { + SC_TRACE_PARSE = 1, SC_TRACE_PROPERTIES = 2, SC_TRACE_VARIABLES = 4, + SC_TRACE_PARSER = 8, SC_TRACE_LIBRARY = 16, SC_TRACE_EVENTS = 32, + SC_TRACE_NPCS = 64, SC_TRACE_OBJECTS = 128, SC_TRACE_TASKS = 256, + SC_TRACE_PRINTFILTER = 512, + + SC_DUMP_TAF = 1024, SC_DUMP_PROPERTIES = 2048, SC_DUMP_VARIABLES = 4096, + SC_DUMP_PARSER_TREES = 8192, SC_DUMP_LOCALE_TABLES = 16384 }; /* Module-wide trace control function prototype. */ extern void sc_set_trace_flags(sc_uint trace_flags); /* Interpreter interface function prototypes. */ -extern sc_game sc_game_from_filename (const sc_char *filename); -extern sc_game sc_game_from_stream (Common::SeekableReadStream *stream); -extern sc_game sc_game_from_callback(sc_int (*callback) - (void *, sc_byte *, sc_int), - void *opaque); +extern sc_game sc_game_from_filename(const sc_char *filename); +extern sc_game sc_game_from_stream(Common::SeekableReadStream *stream); +extern sc_game sc_game_from_callback(sc_int(*callback) + (void *, sc_byte *, sc_int), + void *opaque); extern void sc_interpret_game(sc_game game); extern void sc_restart_game(sc_game game); extern sc_bool sc_save_game(sc_game game); @@ -120,16 +120,16 @@ extern void sc_quit_game(sc_game game); extern sc_bool sc_save_game_to_filename(sc_game game, const sc_char *filename); extern void sc_save_game_to_stream(sc_game game, Common::SeekableReadStream *stream); extern void sc_save_game_to_callback(sc_game game, - void (*callback) - (void *, const sc_byte *, sc_int), - void *opaque); + void (*callback) + (void *, const sc_byte *, sc_int), + void *opaque); extern sc_bool sc_load_game_from_filename(sc_game game, - const sc_char *filename); + const sc_char *filename); extern sc_bool sc_load_game_from_stream(sc_game game, Common::SeekableReadStream *stream); extern sc_bool sc_load_game_from_callback(sc_game game, - sc_int (*callback) - (void *, sc_byte *, sc_int), - void *opaque); + sc_int(*callback) + (void *, sc_byte *, sc_int), + void *opaque); extern void sc_free_game(sc_game game); extern sc_bool sc_is_game_running(sc_game game); extern const sc_char *sc_get_game_name(sc_game game); @@ -157,26 +157,26 @@ typedef void *sc_game_hint; extern sc_game_hint sc_get_first_game_hint(sc_game game); extern sc_game_hint sc_get_next_game_hint(sc_game game, sc_game_hint hint); extern const sc_char *sc_get_game_hint_question(sc_game game, - sc_game_hint hint); + sc_game_hint hint); extern const sc_char *sc_get_game_subtle_hint(sc_game game, - sc_game_hint hint); + sc_game_hint hint); extern const sc_char *sc_get_game_unsubtle_hint(sc_game game, - sc_game_hint hint); + sc_game_hint hint); extern void sc_set_game_debugger_enabled(sc_game game, sc_bool flag); extern sc_bool sc_get_game_debugger_enabled(sc_game game); extern sc_bool sc_run_game_debugger_command(sc_game game, - const sc_char *debug_command); + const sc_char *debug_command); extern void sc_set_portable_random(sc_bool flag); extern void sc_reseed_random_sequence(sc_uint new_seed); /* Locale control and query functions. */ -extern sc_bool sc_set_locale (const sc_char *name); +extern sc_bool sc_set_locale(const sc_char *name); extern const sc_char *sc_get_locale(); /* A few possibly useful utilities. */ -extern sc_int sc_strncasecmp (const sc_char *s1, const sc_char *s2, sc_int n); -extern sc_int sc_strcasecmp (const sc_char *s1, const sc_char *s2); +extern sc_int sc_strncasecmp(const sc_char *s1, const sc_char *s2, sc_int n); +extern sc_int sc_strcasecmp(const sc_char *s1, const sc_char *s2); extern const sc_char *sc_scare_version(); extern sc_int sc_scare_emulation(); diff --git a/engines/glk/adrift/scdebug.cpp b/engines/glk/adrift/scdebug.cpp index 3852d164e1..35900c37f4 100644 --- a/engines/glk/adrift/scdebug.cpp +++ b/engines/glk/adrift/scdebug.cpp @@ -32,19 +32,19 @@ static const sc_uint DEBUG_MAGIC = 0xc4584d2e; enum { DEBUG_BUFFER_SIZE = 256 }; /* Debugging command and command argument type. */ -typedef enum -{ DEBUG_NONE = 0, DEBUG_CONTINUE, DEBUG_STEP, DEBUG_BUFFER, DEBUG_RESOURCES, - DEBUG_HELP, DEBUG_GAME, - DEBUG_PLAYER, DEBUG_ROOMS, DEBUG_OBJECTS, DEBUG_NPCS, DEBUG_EVENTS, - DEBUG_TASKS, DEBUG_VARIABLES, - DEBUG_OLDPLAYER, DEBUG_OLDROOMS, DEBUG_OLDOBJECTS, DEBUG_OLDNPCS, - DEBUG_OLDEVENTS, DEBUG_OLDTASKS, DEBUG_OLDVARIABLES, - DEBUG_WATCHPLAYER, DEBUG_WATCHOBJECTS, DEBUG_WATCHNPCS, DEBUG_WATCHEVENTS, - DEBUG_WATCHTASKS, DEBUG_WATCHVARIABLES, - DEBUG_CLEARPLAYER, DEBUG_CLEAROBJECTS, DEBUG_CLEARNPCS, DEBUG_CLEAREVENTS, - DEBUG_CLEARTASKS, DEBUG_CLEARVARIABLES, - DEBUG_WATCHALL, DEBUG_CLEARALL, DEBUG_RANDOM, - DEBUG_QUIT +typedef enum { + DEBUG_NONE = 0, DEBUG_CONTINUE, DEBUG_STEP, DEBUG_BUFFER, DEBUG_RESOURCES, + DEBUG_HELP, DEBUG_GAME, + DEBUG_PLAYER, DEBUG_ROOMS, DEBUG_OBJECTS, DEBUG_NPCS, DEBUG_EVENTS, + DEBUG_TASKS, DEBUG_VARIABLES, + DEBUG_OLDPLAYER, DEBUG_OLDROOMS, DEBUG_OLDOBJECTS, DEBUG_OLDNPCS, + DEBUG_OLDEVENTS, DEBUG_OLDTASKS, DEBUG_OLDVARIABLES, + DEBUG_WATCHPLAYER, DEBUG_WATCHOBJECTS, DEBUG_WATCHNPCS, DEBUG_WATCHEVENTS, + DEBUG_WATCHTASKS, DEBUG_WATCHVARIABLES, + DEBUG_CLEARPLAYER, DEBUG_CLEAROBJECTS, DEBUG_CLEARNPCS, DEBUG_CLEAREVENTS, + DEBUG_CLEARTASKS, DEBUG_CLEARVARIABLES, + DEBUG_WATCHALL, DEBUG_CLEARALL, DEBUG_RANDOM, + DEBUG_QUIT } sc_command_t; @@ -53,30 +53,29 @@ typedef enum sc_command_type_t; /* Table connecting debugging command strings to commands. */ -typedef struct -{ - const sc_char *const command_string; - const sc_command_t command; +typedef struct { + const sc_char *const command_string; + const sc_command_t command; } sc_strings_t; static const sc_strings_t DEBUG_COMMANDS[] = { - {"continue", DEBUG_CONTINUE}, {"step", DEBUG_STEP}, {"buffer", DEBUG_BUFFER}, - {"resources", DEBUG_RESOURCES}, {"help", DEBUG_HELP}, {"game", DEBUG_GAME}, - {"player", DEBUG_PLAYER}, {"rooms", DEBUG_ROOMS}, {"objects", DEBUG_OBJECTS}, - {"npcs", DEBUG_NPCS}, {"events", DEBUG_EVENTS}, {"tasks", DEBUG_TASKS}, - {"variables", DEBUG_VARIABLES}, - {"oldplayer", DEBUG_OLDPLAYER}, {"oldrooms", DEBUG_OLDROOMS}, - {"oldobjects", DEBUG_OLDOBJECTS}, {"oldnpcs", DEBUG_OLDNPCS}, - {"oldevents", DEBUG_OLDEVENTS}, {"oldtasks", DEBUG_OLDTASKS}, - {"oldvariables", DEBUG_OLDVARIABLES}, - {"watchplayer", DEBUG_WATCHPLAYER}, {"clearplayer", DEBUG_CLEARPLAYER}, - {"watchobjects", DEBUG_WATCHOBJECTS}, {"watchnpcs", DEBUG_WATCHNPCS}, - {"watchevents", DEBUG_WATCHEVENTS}, {"watchtasks", DEBUG_WATCHTASKS}, - {"watchvariables", DEBUG_WATCHVARIABLES}, - {"clearobjects", DEBUG_CLEAROBJECTS}, {"clearnpcs", DEBUG_CLEARNPCS}, - {"clearevents", DEBUG_CLEAREVENTS}, {"cleartasks", DEBUG_CLEARTASKS}, - {"clearvariables", DEBUG_CLEARVARIABLES}, {"watchall", DEBUG_WATCHALL}, - {"clearall", DEBUG_CLEARALL}, {"random", DEBUG_RANDOM}, {"quit", DEBUG_QUIT}, - {NULL, DEBUG_NONE} + {"continue", DEBUG_CONTINUE}, {"step", DEBUG_STEP}, {"buffer", DEBUG_BUFFER}, + {"resources", DEBUG_RESOURCES}, {"help", DEBUG_HELP}, {"game", DEBUG_GAME}, + {"player", DEBUG_PLAYER}, {"rooms", DEBUG_ROOMS}, {"objects", DEBUG_OBJECTS}, + {"npcs", DEBUG_NPCS}, {"events", DEBUG_EVENTS}, {"tasks", DEBUG_TASKS}, + {"variables", DEBUG_VARIABLES}, + {"oldplayer", DEBUG_OLDPLAYER}, {"oldrooms", DEBUG_OLDROOMS}, + {"oldobjects", DEBUG_OLDOBJECTS}, {"oldnpcs", DEBUG_OLDNPCS}, + {"oldevents", DEBUG_OLDEVENTS}, {"oldtasks", DEBUG_OLDTASKS}, + {"oldvariables", DEBUG_OLDVARIABLES}, + {"watchplayer", DEBUG_WATCHPLAYER}, {"clearplayer", DEBUG_CLEARPLAYER}, + {"watchobjects", DEBUG_WATCHOBJECTS}, {"watchnpcs", DEBUG_WATCHNPCS}, + {"watchevents", DEBUG_WATCHEVENTS}, {"watchtasks", DEBUG_WATCHTASKS}, + {"watchvariables", DEBUG_WATCHVARIABLES}, + {"clearobjects", DEBUG_CLEAROBJECTS}, {"clearnpcs", DEBUG_CLEARNPCS}, + {"clearevents", DEBUG_CLEAREVENTS}, {"cleartasks", DEBUG_CLEARTASKS}, + {"clearvariables", DEBUG_CLEARVARIABLES}, {"watchall", DEBUG_WATCHALL}, + {"clearall", DEBUG_CLEARALL}, {"random", DEBUG_RANDOM}, {"quit", DEBUG_QUIT}, + {NULL, DEBUG_NONE} }; /* @@ -84,18 +83,17 @@ static const sc_strings_t DEBUG_COMMANDS[] = { * added to the game on enabling debug, and removed and destroyed on * disabling debugging. */ -typedef struct sc_debugger_s -{ - sc_uint magic; - sc_bool *watch_objects; - sc_bool *watch_npcs; - sc_bool *watch_events; - sc_bool *watch_tasks; - sc_bool *watch_variables; - sc_bool watch_player; - sc_bool single_step; - sc_bool quit_pending; - sc_uint elapsed_seconds; +typedef struct sc_debugger_s { + sc_uint magic; + sc_bool *watch_objects; + sc_bool *watch_npcs; + sc_bool *watch_events; + sc_bool *watch_tasks; + sc_bool *watch_variables; + sc_bool watch_player; + sc_bool single_step; + sc_bool quit_pending; + sc_uint elapsed_seconds; } sc_debugger_t; @@ -105,9 +103,8 @@ typedef struct sc_debugger_s * Return TRUE if pointer is a valid debugger, FALSE otherwise. */ static sc_bool -debug_is_valid (sc_debuggerref_t debug) -{ - return debug && debug->magic == DEBUG_MAGIC; +debug_is_valid(sc_debuggerref_t debug) { + return debug && debug->magic == DEBUG_MAGIC; } @@ -117,11 +114,10 @@ debug_is_valid (sc_debuggerref_t debug) * Return the debugger reference from a game, or NULL if none. */ static sc_debuggerref_t -debug_get_debugger (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); +debug_get_debugger(sc_gameref_t game) { + assert(gs_is_game_valid(game)); - return game->debugger; + return game->debugger; } @@ -131,17 +127,16 @@ debug_get_debugger (sc_gameref_t game) * Common helper to return the count of variables defined in a game. */ static sc_int -debug_variable_count (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key; - sc_int variable_count; +debug_variable_count(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key; + sc_int variable_count; - /* Find and return the variables count. */ - vt_key.string = "Variables"; - variable_count = prop_get_child_count (bundle, "I<-s", &vt_key); + /* Find and return the variables count. */ + vt_key.string = "Variables"; + variable_count = prop_get_child_count(bundle, "I<-s", &vt_key); - return variable_count; + return variable_count; } @@ -152,45 +147,44 @@ debug_variable_count (sc_gameref_t game) * game passed in. */ static void -debug_initialize (sc_gameref_t game) -{ - sc_debuggerref_t debug; - - /* Create the easy bits of the new debugging set. */ - debug = (sc_debuggerref_t)sc_malloc (sizeof (*debug)); - debug->magic = DEBUG_MAGIC; - debug->watch_player = FALSE; - debug->single_step = FALSE; - debug->quit_pending = FALSE; - debug->elapsed_seconds = 0; - - /* Allocate watchpoints for everything we can watch. */ - debug->watch_objects = (sc_bool *)sc_malloc (gs_object_count (game) - * sizeof (*debug->watch_objects)); - debug->watch_npcs = (sc_bool *)sc_malloc (gs_npc_count (game) - * sizeof (*debug->watch_npcs)); - debug->watch_events = (sc_bool *)sc_malloc (gs_event_count (game) - * sizeof (*debug->watch_events)); - debug->watch_tasks = (sc_bool *)sc_malloc (gs_task_count (game) - * sizeof (*debug->watch_tasks)); - debug->watch_variables = (sc_bool *)sc_malloc (debug_variable_count (game) - * sizeof (*debug->watch_variables)); - - /* Clear all watchpoint arrays. */ - memset (debug->watch_objects, FALSE, - gs_object_count (game) * sizeof (*debug->watch_objects)); - memset (debug->watch_npcs, FALSE, - gs_npc_count (game) * sizeof (*debug->watch_npcs)); - memset (debug->watch_events, FALSE, - gs_event_count (game) * sizeof (*debug->watch_events)); - memset (debug->watch_tasks, FALSE, - gs_task_count (game) * sizeof (*debug->watch_tasks)); - memset (debug->watch_variables, FALSE, - debug_variable_count (game) * sizeof (*debug->watch_variables)); - - /* Append the new debugger set to the game. */ - assert (!game->debugger); - game->debugger = debug; +debug_initialize(sc_gameref_t game) { + sc_debuggerref_t debug; + + /* Create the easy bits of the new debugging set. */ + debug = (sc_debuggerref_t)sc_malloc(sizeof(*debug)); + debug->magic = DEBUG_MAGIC; + debug->watch_player = FALSE; + debug->single_step = FALSE; + debug->quit_pending = FALSE; + debug->elapsed_seconds = 0; + + /* Allocate watchpoints for everything we can watch. */ + debug->watch_objects = (sc_bool *)sc_malloc(gs_object_count(game) + * sizeof(*debug->watch_objects)); + debug->watch_npcs = (sc_bool *)sc_malloc(gs_npc_count(game) + * sizeof(*debug->watch_npcs)); + debug->watch_events = (sc_bool *)sc_malloc(gs_event_count(game) + * sizeof(*debug->watch_events)); + debug->watch_tasks = (sc_bool *)sc_malloc(gs_task_count(game) + * sizeof(*debug->watch_tasks)); + debug->watch_variables = (sc_bool *)sc_malloc(debug_variable_count(game) + * sizeof(*debug->watch_variables)); + + /* Clear all watchpoint arrays. */ + memset(debug->watch_objects, FALSE, + gs_object_count(game) * sizeof(*debug->watch_objects)); + memset(debug->watch_npcs, FALSE, + gs_npc_count(game) * sizeof(*debug->watch_npcs)); + memset(debug->watch_events, FALSE, + gs_event_count(game) * sizeof(*debug->watch_events)); + memset(debug->watch_tasks, FALSE, + gs_task_count(game) * sizeof(*debug->watch_tasks)); + memset(debug->watch_variables, FALSE, + debug_variable_count(game) * sizeof(*debug->watch_variables)); + + /* Append the new debugger set to the game. */ + assert(!game->debugger); + game->debugger = debug; } @@ -201,24 +195,23 @@ debug_initialize (sc_gameref_t game) * from the game. */ static void -debug_finalize (sc_gameref_t game) -{ - sc_debuggerref_t debug = debug_get_debugger (game); - assert (debug_is_valid (debug)); - - /* Free all allocated watchpoint arrays. */ - sc_free (debug->watch_objects); - sc_free (debug->watch_npcs); - sc_free (debug->watch_events); - sc_free (debug->watch_tasks); - sc_free (debug->watch_variables); - - /* Poison and free the debugger itself. */ - memset (debug, 0xaa, sizeof (*debug)); - sc_free (debug); - - /* Remove the debug reference from the game. */ - game->debugger = NULL; +debug_finalize(sc_gameref_t game) { + sc_debuggerref_t debug = debug_get_debugger(game); + assert(debug_is_valid(debug)); + + /* Free all allocated watchpoint arrays. */ + sc_free(debug->watch_objects); + sc_free(debug->watch_npcs); + sc_free(debug->watch_events); + sc_free(debug->watch_tasks); + sc_free(debug->watch_variables); + + /* Poison and free the debugger itself. */ + memset(debug, 0xaa, sizeof(*debug)); + sc_free(debug); + + /* Remove the debug reference from the game. */ + game->debugger = NULL; } @@ -228,312 +221,309 @@ debug_finalize (sc_gameref_t game) * Print debugging help. */ static void -debug_help (sc_command_t topic) -{ - /* Is help general, or specific? */ - if (topic == DEBUG_NONE) - { - if_print_debug ( - "The following debugging commands examine game state:\n\n"); - if_print_debug ( - " game -- Print general game information," - " and class counts\n" - " player -- Show the player location and position\n" - " rooms [Range] -- Print information on game rooms\n" - " objects [Range] -- Print information on objects in the game\n" - " npcs [Range] -- Print information on game NPCs\n" - " events [Range] -- Print information on the game's events\n" - " tasks [Range] -- Print information on the game's tasks\n" - " variables [Range] -- Show variables defined by the game\n\n"); - if_print_debug ( - "Most commands take range inputs. This can be a single number, to" - " apply the command to just that item, a range such as '0 to 10' (or" - " '0 - 10', '0 .. 10', or simply '0 10') to apply to that range of" - " items, or '*' to apply the command to all items of the class. If" - " omitted, the command is applied only to the items of the class" - " 'relevant' to the current game state; see the help for specific" - " commands for more on what is 'relevant'.\n\n"); - if_print_debug ( - "The 'player', 'objects', 'npcs', 'events', 'tasks', and 'variables'" - " commands may be prefixed with 'old', in which case the values" - " printed will be those for the previous game turn, rather than the" - " current values.\n\n"); - if_print_debug ( - "These debugging commands manage watchpoints:\n\n"); - if_print_debug ( - "The 'player', 'objects', 'npcs', 'events', 'tasks', and 'variables'" - " commands may be prefixed with 'watch', to set watchpoints." - " Watchpoints automatically enter the debugger when the item changes" - " state during a game turn. For example 'watchobject 10' monitors" - " object 10 for changes, and 'watchnpc *' monitors all NPCs. A" - " 'watch' command with no range prints out all watchpoints set for" - " that class.\n\n"); - if_print_debug ( - "Prefix commands with 'clear' to clear watchpoints, for example" - " 'clearnpcs *'. Use 'watchall' to obtain a complete list of every" - " watchpoint set, and 'clearall' to clear all watchpoints in one go." - " A 'clear' command with no range behaves the same as a 'watch'" - " command with no range.\n\n"); - if_print_debug ( - "These debugging commands print details of game output and control the" - " debugger and interpreter:\n\n"); - if_print_debug ( - " buffer -- Show the current buffered game text\n" - " resources -- Show current and requested game resources\n" - " random [Seed] -- Control the random number generator\n" - " step -- Run one game turn, then re-enter the debugger\n" - " continue -- Leave the debugger and resume the game\n" - " quit -- Exit the interpreter main loop\n" - " help [Command] -- Print help specific to Command\n\n"); - if_print_debug ( - "Debugging commands may be abbreviated to their shortest unambiguous" - " form.\n\n"); - if_print_debug ( - "Use the 'debug' or '#debug' command in a game, typed at the usual" - " game prompt, to return to the debugger.\n"); - return; - } - - /* Command-specific help. */ - switch (topic) - { - case DEBUG_HELP: - if_print_debug ( - "Give the name of the command you want help on, for example 'help" - " continue'.\n"); - break; - - case DEBUG_CONTINUE: - if_print_debug ( - "Leave the debugger and resume the game. Use the 'debug' or '#debug'" - " command in a game, typed at the usual game prompt, to return to the" - " debugger.\n"); - break; - - case DEBUG_STEP: - if_print_debug ( - "Run one game turn, then re-enter the debugger. Useful for games that" - " intercept empty input lines, which otherwise catch the 'debug'" - " command before SCARE can get to it.\n"); - break; - - case DEBUG_QUIT: - if_print_debug ( - "Exit the interpreter main loop. Equivalent to a confirmed 'quit'" - " from within the game itself, this ends the interpreter session.\n"); - break; - - case DEBUG_BUFFER: - if_print_debug ( - "Print the current text that the game has buffered for output. The" - " debugger catches games before they have printed their turn output" - " -- this is the text that will be filtered and printed on exiting the" - " debugger.\n"); - break; - - case DEBUG_RESOURCES: - if_print_debug ( - "Print any resources currently active, and any requested by the game" - " on the current turn. The requested resources will become the active" - " ones on exiting the debugger.\n"); - break; - - case DEBUG_RANDOM: - if_print_debug ( - "If no seed is given, report the current random number generator" - " setting. Otherwise, seed the random number generator with the value" - " given. This is useful for persuading games with random sections to" - " behave predictably. A new seed value of zero is invalid.\n"); - break; - - case DEBUG_GAME: - if_print_debug ( - "Print general game information, including the number of rooms," - " objects, events, tasks, and variables that the game defines\n"); - break; - - case DEBUG_PLAYER: - if_print_debug ( - "Print out the current player room and position, and any parent object" - " of the player character.\n"); - break; - - case DEBUG_OLDPLAYER: - if_print_debug ( - "Print out the player room and position from the previous turn, and" - " any parent object of the player character.\n"); - break; - - case DEBUG_ROOMS: - if_print_debug ( - "Print out the name and contents of rooms in the range. If no range," - " print details of the room containing the player.\n"); - break; - - case DEBUG_OLDROOMS: - if_print_debug ( - "Print out the name and contents of rooms in the range for the" - " previous turn. If no range, print details of the room that" - " contained the player on the previous turn.\n"); - break; - - case DEBUG_OBJECTS: - if_print_debug ( - "Print out details of all objects in the range. If no range, print" - " details of objects in the room containing the player, and visible to" - " the player.\n"); - break; - - case DEBUG_OLDOBJECTS: - if_print_debug ( - "Print out details of all objects in the range for the previous turn." - " If no range, print details of objects in the room that contained" - " the player, and were visible to the player.\n"); - break; - - case DEBUG_NPCS: - if_print_debug ( - "Print out details of all NPCs in the range. If no range, print" - " details of only NPCs in the room containing the player.\n"); - break; - - case DEBUG_OLDNPCS: - if_print_debug ( - "Print out details of all NPCs in the range for the previous turn." - " If no range, print details of only NPCs in the room that contained" - " the player.\n"); - break; - - case DEBUG_EVENTS: - if_print_debug ( - "Print out details of all events in the range. If no range, print" - " details of only events currently running.\n"); - break; - - case DEBUG_OLDEVENTS: - if_print_debug ( - "Print out details of all events in the range for the previous turn." - " If no range, print details of only events running on the previous" - " turn.\n"); - break; - - case DEBUG_TASKS: - if_print_debug ( - "Print out details of all tasks in the range. If no range, print" - " details of only tasks that are runnable, for the current state of" - " the game.\n"); - break; - - case DEBUG_OLDTASKS: - if_print_debug ( - "Print out details of all tasks in the range for the previous turn." - " If no range, print details of only tasks that were runnable, for" - " the previous state of the game.\n"); - break; - - case DEBUG_VARIABLES: - if_print_debug ( - "Print out the names, types, and values of all game variables in the" - " range. If no range, print details of all variables (equivalent to" - " 'variables *').\n"); - break; - - case DEBUG_OLDVARIABLES: - if_print_debug ( - "Print out the names, types, and values at the previous turn of all" - " game variables in the range. If no range, print details of all" - " variables (equivalent to 'variables *').\n"); - break; - - case DEBUG_WATCHPLAYER: - if_print_debug ( - "If no range is given, list any watchpoint on player movement. If" - " range '0' is given, set a watchpoint on player movement. Other" - " usages of 'watchplayer' behave as if no range is given.\n"); - break; - - case DEBUG_WATCHOBJECTS: - if_print_debug ( - "Set watchpoints on all objects in the range. If no range, list out" - " object watchpoints currently set.\n"); - break; - - case DEBUG_WATCHNPCS: - if_print_debug ( - "Set watchpoints on all NPCs in the range. If no range, list out NPC" - " watchpoints currently set.\n"); - break; - - case DEBUG_WATCHEVENTS: - if_print_debug ( - "Set watchpoints on all events in the range. If no range, list out" - " event watchpoints currently set.\n"); - break; - - case DEBUG_WATCHTASKS: - if_print_debug ( - "Set watchpoints on all tasks in the range. If no range, list out" - " task watchpoints currently set.\n"); - break; - - case DEBUG_WATCHVARIABLES: - if_print_debug ( - "Set watchpoints on all game variables in the range. If no range," - " list variable watchpoints currently set.\n"); - break; - - case DEBUG_CLEARPLAYER: - if_print_debug ( - "Clear any watchpoint set on player movements.\n"); - break; - - case DEBUG_CLEAROBJECTS: - if_print_debug ( - "Clear watchpoints on all objects in the range. If no range, list" - " out object watchpoints currently set.\n"); - break; - - case DEBUG_CLEARNPCS: - if_print_debug ( - "Clear watchpoints on all NPCs in the range. If no range, list out" - " NPC watchpoints currently set.\n"); - break; - - case DEBUG_CLEAREVENTS: - if_print_debug ( - "Clear watchpoints on all events in the range. If no range, list out" - " event watchpoints currently set.\n"); - break; - - case DEBUG_CLEARTASKS: - if_print_debug ( - "Clear watchpoints on all tasks in the range. If no range, list out" - " task watchpoints currently set.\n"); - break; - - case DEBUG_CLEARVARIABLES: - if_print_debug ( - "Clear watchpoints on all game variables in the range. If no range," - " list variable watchpoints currently set.\n"); - break; - - case DEBUG_WATCHALL: - if_print_debug ( - "Print out a list of all all watchpoints set for all the classes of" - " item on which watchpoints can be used.\n"); - break; - - case DEBUG_CLEARALL: - if_print_debug ( - "Clear all watchpoints set, on all classes of item on which" - " watchpoints can be used.\n"); - break; - - default: - if_print_debug ( - "Sorry, there is no help available on that at the moment.\n"); - break; - } +debug_help(sc_command_t topic) { + /* Is help general, or specific? */ + if (topic == DEBUG_NONE) { + if_print_debug( + "The following debugging commands examine game state:\n\n"); + if_print_debug( + " game -- Print general game information," + " and class counts\n" + " player -- Show the player location and position\n" + " rooms [Range] -- Print information on game rooms\n" + " objects [Range] -- Print information on objects in the game\n" + " npcs [Range] -- Print information on game NPCs\n" + " events [Range] -- Print information on the game's events\n" + " tasks [Range] -- Print information on the game's tasks\n" + " variables [Range] -- Show variables defined by the game\n\n"); + if_print_debug( + "Most commands take range inputs. This can be a single number, to" + " apply the command to just that item, a range such as '0 to 10' (or" + " '0 - 10', '0 .. 10', or simply '0 10') to apply to that range of" + " items, or '*' to apply the command to all items of the class. If" + " omitted, the command is applied only to the items of the class" + " 'relevant' to the current game state; see the help for specific" + " commands for more on what is 'relevant'.\n\n"); + if_print_debug( + "The 'player', 'objects', 'npcs', 'events', 'tasks', and 'variables'" + " commands may be prefixed with 'old', in which case the values" + " printed will be those for the previous game turn, rather than the" + " current values.\n\n"); + if_print_debug( + "These debugging commands manage watchpoints:\n\n"); + if_print_debug( + "The 'player', 'objects', 'npcs', 'events', 'tasks', and 'variables'" + " commands may be prefixed with 'watch', to set watchpoints." + " Watchpoints automatically enter the debugger when the item changes" + " state during a game turn. For example 'watchobject 10' monitors" + " object 10 for changes, and 'watchnpc *' monitors all NPCs. A" + " 'watch' command with no range prints out all watchpoints set for" + " that class.\n\n"); + if_print_debug( + "Prefix commands with 'clear' to clear watchpoints, for example" + " 'clearnpcs *'. Use 'watchall' to obtain a complete list of every" + " watchpoint set, and 'clearall' to clear all watchpoints in one go." + " A 'clear' command with no range behaves the same as a 'watch'" + " command with no range.\n\n"); + if_print_debug( + "These debugging commands print details of game output and control the" + " debugger and interpreter:\n\n"); + if_print_debug( + " buffer -- Show the current buffered game text\n" + " resources -- Show current and requested game resources\n" + " random [Seed] -- Control the random number generator\n" + " step -- Run one game turn, then re-enter the debugger\n" + " continue -- Leave the debugger and resume the game\n" + " quit -- Exit the interpreter main loop\n" + " help [Command] -- Print help specific to Command\n\n"); + if_print_debug( + "Debugging commands may be abbreviated to their shortest unambiguous" + " form.\n\n"); + if_print_debug( + "Use the 'debug' or '#debug' command in a game, typed at the usual" + " game prompt, to return to the debugger.\n"); + return; + } + + /* Command-specific help. */ + switch (topic) { + case DEBUG_HELP: + if_print_debug( + "Give the name of the command you want help on, for example 'help" + " continue'.\n"); + break; + + case DEBUG_CONTINUE: + if_print_debug( + "Leave the debugger and resume the game. Use the 'debug' or '#debug'" + " command in a game, typed at the usual game prompt, to return to the" + " debugger.\n"); + break; + + case DEBUG_STEP: + if_print_debug( + "Run one game turn, then re-enter the debugger. Useful for games that" + " intercept empty input lines, which otherwise catch the 'debug'" + " command before SCARE can get to it.\n"); + break; + + case DEBUG_QUIT: + if_print_debug( + "Exit the interpreter main loop. Equivalent to a confirmed 'quit'" + " from within the game itself, this ends the interpreter session.\n"); + break; + + case DEBUG_BUFFER: + if_print_debug( + "Print the current text that the game has buffered for output. The" + " debugger catches games before they have printed their turn output" + " -- this is the text that will be filtered and printed on exiting the" + " debugger.\n"); + break; + + case DEBUG_RESOURCES: + if_print_debug( + "Print any resources currently active, and any requested by the game" + " on the current turn. The requested resources will become the active" + " ones on exiting the debugger.\n"); + break; + + case DEBUG_RANDOM: + if_print_debug( + "If no seed is given, report the current random number generator" + " setting. Otherwise, seed the random number generator with the value" + " given. This is useful for persuading games with random sections to" + " behave predictably. A new seed value of zero is invalid.\n"); + break; + + case DEBUG_GAME: + if_print_debug( + "Print general game information, including the number of rooms," + " objects, events, tasks, and variables that the game defines\n"); + break; + + case DEBUG_PLAYER: + if_print_debug( + "Print out the current player room and position, and any parent object" + " of the player character.\n"); + break; + + case DEBUG_OLDPLAYER: + if_print_debug( + "Print out the player room and position from the previous turn, and" + " any parent object of the player character.\n"); + break; + + case DEBUG_ROOMS: + if_print_debug( + "Print out the name and contents of rooms in the range. If no range," + " print details of the room containing the player.\n"); + break; + + case DEBUG_OLDROOMS: + if_print_debug( + "Print out the name and contents of rooms in the range for the" + " previous turn. If no range, print details of the room that" + " contained the player on the previous turn.\n"); + break; + + case DEBUG_OBJECTS: + if_print_debug( + "Print out details of all objects in the range. If no range, print" + " details of objects in the room containing the player, and visible to" + " the player.\n"); + break; + + case DEBUG_OLDOBJECTS: + if_print_debug( + "Print out details of all objects in the range for the previous turn." + " If no range, print details of objects in the room that contained" + " the player, and were visible to the player.\n"); + break; + + case DEBUG_NPCS: + if_print_debug( + "Print out details of all NPCs in the range. If no range, print" + " details of only NPCs in the room containing the player.\n"); + break; + + case DEBUG_OLDNPCS: + if_print_debug( + "Print out details of all NPCs in the range for the previous turn." + " If no range, print details of only NPCs in the room that contained" + " the player.\n"); + break; + + case DEBUG_EVENTS: + if_print_debug( + "Print out details of all events in the range. If no range, print" + " details of only events currently running.\n"); + break; + + case DEBUG_OLDEVENTS: + if_print_debug( + "Print out details of all events in the range for the previous turn." + " If no range, print details of only events running on the previous" + " turn.\n"); + break; + + case DEBUG_TASKS: + if_print_debug( + "Print out details of all tasks in the range. If no range, print" + " details of only tasks that are runnable, for the current state of" + " the game.\n"); + break; + + case DEBUG_OLDTASKS: + if_print_debug( + "Print out details of all tasks in the range for the previous turn." + " If no range, print details of only tasks that were runnable, for" + " the previous state of the game.\n"); + break; + + case DEBUG_VARIABLES: + if_print_debug( + "Print out the names, types, and values of all game variables in the" + " range. If no range, print details of all variables (equivalent to" + " 'variables *').\n"); + break; + + case DEBUG_OLDVARIABLES: + if_print_debug( + "Print out the names, types, and values at the previous turn of all" + " game variables in the range. If no range, print details of all" + " variables (equivalent to 'variables *').\n"); + break; + + case DEBUG_WATCHPLAYER: + if_print_debug( + "If no range is given, list any watchpoint on player movement. If" + " range '0' is given, set a watchpoint on player movement. Other" + " usages of 'watchplayer' behave as if no range is given.\n"); + break; + + case DEBUG_WATCHOBJECTS: + if_print_debug( + "Set watchpoints on all objects in the range. If no range, list out" + " object watchpoints currently set.\n"); + break; + + case DEBUG_WATCHNPCS: + if_print_debug( + "Set watchpoints on all NPCs in the range. If no range, list out NPC" + " watchpoints currently set.\n"); + break; + + case DEBUG_WATCHEVENTS: + if_print_debug( + "Set watchpoints on all events in the range. If no range, list out" + " event watchpoints currently set.\n"); + break; + + case DEBUG_WATCHTASKS: + if_print_debug( + "Set watchpoints on all tasks in the range. If no range, list out" + " task watchpoints currently set.\n"); + break; + + case DEBUG_WATCHVARIABLES: + if_print_debug( + "Set watchpoints on all game variables in the range. If no range," + " list variable watchpoints currently set.\n"); + break; + + case DEBUG_CLEARPLAYER: + if_print_debug( + "Clear any watchpoint set on player movements.\n"); + break; + + case DEBUG_CLEAROBJECTS: + if_print_debug( + "Clear watchpoints on all objects in the range. If no range, list" + " out object watchpoints currently set.\n"); + break; + + case DEBUG_CLEARNPCS: + if_print_debug( + "Clear watchpoints on all NPCs in the range. If no range, list out" + " NPC watchpoints currently set.\n"); + break; + + case DEBUG_CLEAREVENTS: + if_print_debug( + "Clear watchpoints on all events in the range. If no range, list out" + " event watchpoints currently set.\n"); + break; + + case DEBUG_CLEARTASKS: + if_print_debug( + "Clear watchpoints on all tasks in the range. If no range, list out" + " task watchpoints currently set.\n"); + break; + + case DEBUG_CLEARVARIABLES: + if_print_debug( + "Clear watchpoints on all game variables in the range. If no range," + " list variable watchpoints currently set.\n"); + break; + + case DEBUG_WATCHALL: + if_print_debug( + "Print out a list of all all watchpoints set for all the classes of" + " item on which watchpoints can be used.\n"); + break; + + case DEBUG_CLEARALL: + if_print_debug( + "Clear all watchpoints set, on all classes of item on which" + " watchpoints can be used.\n"); + break; + + default: + if_print_debug( + "Sorry, there is no help available on that at the moment.\n"); + break; + } } @@ -550,217 +540,200 @@ debug_help (sc_command_t topic) * Low level output helpers. */ static void -debug_print_quoted (const sc_char *string) -{ - if_print_debug_character ('"'); - if_print_debug (string); - if_print_debug_character ('"'); +debug_print_quoted(const sc_char *string) { + if_print_debug_character('"'); + if_print_debug(string); + if_print_debug_character('"'); } static void -debug_print_player (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - const sc_char *playername; - - vt_key[0].string = "Globals"; - vt_key[1].string = "PlayerName"; - playername = prop_get_string (bundle, "S<-ss", vt_key); - if_print_debug ("Player "); - debug_print_quoted (playername); +debug_print_player(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + const sc_char *playername; + + vt_key[0].string = "Globals"; + vt_key[1].string = "PlayerName"; + playername = prop_get_string(bundle, "S<-ss", vt_key); + if_print_debug("Player "); + debug_print_quoted(playername); } static void -debug_print_room (sc_gameref_t game, sc_int room) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_char buffer[32]; - const sc_char *name; - - if_print_debug ("Room "); - if (room < 0 || room >= gs_room_count (game)) - { - sprintf (buffer, "%ld ", room); - if_print_debug (buffer); - if_print_debug ("[Out of range]"); - return; - } - - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - sprintf (buffer, "%ld ", room); - if_print_debug (buffer); - debug_print_quoted (name); +debug_print_room(sc_gameref_t game, sc_int room) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_char buffer[32]; + const sc_char *name; + + if_print_debug("Room "); + if (room < 0 || room >= gs_room_count(game)) { + sprintf(buffer, "%ld ", room); + if_print_debug(buffer); + if_print_debug("[Out of range]"); + return; + } + + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + sprintf(buffer, "%ld ", room); + if_print_debug(buffer); + debug_print_quoted(name); } static void -debug_print_object (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_bool bstatic; - sc_char buffer[32]; - const sc_char *prefix, *name; - - if (object < 0 || object >= gs_object_count (game)) - { - if_print_debug ("Object "); - sprintf (buffer, "%ld ", object); - if_print_debug (buffer); - if_print_debug ("[Out of range]"); - return; - } - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Static"; - bstatic = prop_get_boolean (bundle, "B<-sis", vt_key); - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - if (bstatic) - if_print_debug ("Static "); - else - if_print_debug ("Dynamic "); - sprintf (buffer, "%ld ", object); - if_print_debug (buffer); - debug_print_quoted (prefix); - if_print_debug_character (' '); - debug_print_quoted (name); +debug_print_object(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_bool bstatic; + sc_char buffer[32]; + const sc_char *prefix, *name; + + if (object < 0 || object >= gs_object_count(game)) { + if_print_debug("Object "); + sprintf(buffer, "%ld ", object); + if_print_debug(buffer); + if_print_debug("[Out of range]"); + return; + } + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Static"; + bstatic = prop_get_boolean(bundle, "B<-sis", vt_key); + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + if (bstatic) + if_print_debug("Static "); + else + if_print_debug("Dynamic "); + sprintf(buffer, "%ld ", object); + if_print_debug(buffer); + debug_print_quoted(prefix); + if_print_debug_character(' '); + debug_print_quoted(name); } static void -debug_print_npc (sc_gameref_t game, sc_int npc) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_char buffer[32]; - const sc_char *prefix, *name; - - if_print_debug ("NPC "); - if (npc < 0 || npc >= gs_npc_count (game)) - { - sprintf (buffer, "%ld ", npc); - if_print_debug (buffer); - if_print_debug ("[Out of range]"); - return; - } - - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - sprintf (buffer, "%ld ", npc); - if_print_debug (buffer); - debug_print_quoted (prefix); - if_print_debug_character (' '); - debug_print_quoted (name); +debug_print_npc(sc_gameref_t game, sc_int npc) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_char buffer[32]; + const sc_char *prefix, *name; + + if_print_debug("NPC "); + if (npc < 0 || npc >= gs_npc_count(game)) { + sprintf(buffer, "%ld ", npc); + if_print_debug(buffer); + if_print_debug("[Out of range]"); + return; + } + + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + sprintf(buffer, "%ld ", npc); + if_print_debug(buffer); + debug_print_quoted(prefix); + if_print_debug_character(' '); + debug_print_quoted(name); } static void -debug_print_event (sc_gameref_t game, sc_int event) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_char buffer[32]; - const sc_char *name; - - if_print_debug ("Event "); - if (event < 0 || event >= gs_event_count (game)) - { - sprintf (buffer, "%ld ", event); - if_print_debug (buffer); - if_print_debug ("[Out of range]"); - return; - } - - vt_key[0].string = "Events"; - vt_key[1].integer = event; - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - sprintf (buffer, "%ld ", event); - if_print_debug (buffer); - debug_print_quoted (name); +debug_print_event(sc_gameref_t game, sc_int event) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_char buffer[32]; + const sc_char *name; + + if_print_debug("Event "); + if (event < 0 || event >= gs_event_count(game)) { + sprintf(buffer, "%ld ", event); + if_print_debug(buffer); + if_print_debug("[Out of range]"); + return; + } + + vt_key[0].string = "Events"; + vt_key[1].integer = event; + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + sprintf(buffer, "%ld ", event); + if_print_debug(buffer); + debug_print_quoted(name); } static void -debug_print_task (sc_gameref_t game, sc_int task) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_char buffer[32]; - const sc_char *command; - - if_print_debug ("Task "); - if (task < 0 || task >= gs_task_count (game)) - { - sprintf (buffer, "%ld ", task); - if_print_debug (buffer); - if_print_debug ("[Out of range]"); - return; - } - - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Command"; - vt_key[3].integer = 0; - command = prop_get_string (bundle, "S<-sisi", vt_key); - sprintf (buffer, "%ld ", task); - if_print_debug (buffer); - debug_print_quoted (command); +debug_print_task(sc_gameref_t game, sc_int task) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_char buffer[32]; + const sc_char *command; + + if_print_debug("Task "); + if (task < 0 || task >= gs_task_count(game)) { + sprintf(buffer, "%ld ", task); + if_print_debug(buffer); + if_print_debug("[Out of range]"); + return; + } + + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Command"; + vt_key[3].integer = 0; + command = prop_get_string(bundle, "S<-sisi", vt_key); + sprintf(buffer, "%ld ", task); + if_print_debug(buffer); + debug_print_quoted(command); } static void -debug_print_variable (sc_gameref_t game, sc_int variable) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[3], vt_rvalue; - sc_char buffer[32]; - sc_int var_type; - const sc_char *name; - - if (variable < 0 || variable >= debug_variable_count (game)) - { - if_print_debug ("Variable "); - sprintf (buffer, "%ld ", variable); - if_print_debug (buffer); - if_print_debug ("[Out of range]"); - return; - } - - vt_key[0].string = "Variables"; - vt_key[1].integer = variable; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - if (var_get (vars, name, &var_type, &vt_rvalue)) - { - switch (var_type) - { - case VAR_INTEGER: - if_print_debug ("Integer "); - break; - case VAR_STRING: - if_print_debug ("String "); - break; - default: - if_print_debug ("[Invalid type] "); - break; - } - } - else - if_print_debug ("[Invalid variable] "); - sprintf (buffer, "%ld ", variable); - if_print_debug (buffer); - debug_print_quoted (name); +debug_print_variable(sc_gameref_t game, sc_int variable) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[3], vt_rvalue; + sc_char buffer[32]; + sc_int var_type; + const sc_char *name; + + if (variable < 0 || variable >= debug_variable_count(game)) { + if_print_debug("Variable "); + sprintf(buffer, "%ld ", variable); + if_print_debug(buffer); + if_print_debug("[Out of range]"); + return; + } + + vt_key[0].string = "Variables"; + vt_key[1].integer = variable; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + if (var_get(vars, name, &var_type, &vt_rvalue)) { + switch (var_type) { + case VAR_INTEGER: + if_print_debug("Integer "); + break; + case VAR_STRING: + if_print_debug("String "); + break; + default: + if_print_debug("[Invalid type] "); + break; + } + } else + if_print_debug("[Invalid variable] "); + sprintf(buffer, "%ld ", variable); + if_print_debug(buffer); + debug_print_quoted(name); } @@ -770,148 +743,145 @@ debug_print_variable (sc_gameref_t game, sc_int variable) * Display overall game details. */ static void -debug_game (sc_gameref_t game, sc_command_type_t type) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_debuggerref_t debug = debug_get_debugger (game); - sc_vartype_t vt_key[2]; - const sc_char *version, *gamename, *compiledate, *gameauthor; - sc_int perspective, waitturns; - sc_bool has_sound, has_graphics, has_battle; - sc_char buffer[32]; - assert (debug_is_valid (debug)); - - if (type != COMMAND_QUERY) - { - if_print_debug ("The Game command takes no arguments.\n"); - return; - } - - if_print_debug ("Game "); - vt_key[0].string = "Globals"; - vt_key[1].string = "GameName"; - gamename = prop_get_string (bundle, "S<-ss", vt_key); - debug_print_quoted (gamename); - if_print_debug_character ('\n'); - - if_print_debug (" Compiled "); - vt_key[0].string = "CompileDate"; - compiledate = prop_get_string (bundle, "S<-s", vt_key); - debug_print_quoted (compiledate); - - if_print_debug (", Author "); - vt_key[0].string = "Globals"; - vt_key[1].string = "GameAuthor"; - gameauthor = prop_get_string (bundle, "S<-ss", vt_key); - debug_print_quoted (gameauthor); - if_print_debug_character ('\n'); - - vt_key[0].string = "VersionString"; - version = prop_get_string (bundle, "S<-s", vt_key); - if_print_debug (" Version "); - if_print_debug (version); - - vt_key[0].string = "Globals"; - vt_key[1].string = "Perspective"; - perspective = prop_get_integer (bundle, "I<-ss", vt_key); - switch (perspective) - { - case 0: - if_print_debug (", First person"); - break; - case 1: - if_print_debug (", Second person"); - break; - case 2: - if_print_debug (", Third person"); - break; - default: - if_print_debug (", [Unknown perspective]"); - break; - } - - vt_key[0].string = "Globals"; - vt_key[1].string = "WaitTurns"; - waitturns = prop_get_integer (bundle, "I<-ss", vt_key); - if_print_debug (", Waitturns "); - sprintf (buffer, "%ld", waitturns); - if_print_debug (buffer); - - vt_key[0].string = "Globals"; - vt_key[1].string = "Sound"; - has_sound = prop_get_boolean (bundle, "B<-ss", vt_key); - vt_key[1].string = "Graphics"; - has_graphics = prop_get_boolean (bundle, "B<-ss", vt_key); - if (has_sound) - if_print_debug (", Sound"); - if (has_graphics) - if_print_debug (", Graphics"); - if_print_debug_character ('\n'); - - vt_key[0].string = "Globals"; - vt_key[1].string = "BattleSystem"; - has_battle = prop_get_boolean (bundle, "B<-ss", vt_key); - if (has_battle) - if_print_debug (" Battle system\n"); - - if_print_debug (" Room count "); - sprintf (buffer, "%ld", gs_room_count (game)); - if_print_debug (buffer); - - if_print_debug (", Object count "); - sprintf (buffer, "%ld", gs_object_count (game)); - if_print_debug (buffer); - - if_print_debug (", NPC count "); - sprintf (buffer, "%ld", gs_npc_count (game)); - if_print_debug (buffer); - if_print_debug_character ('\n'); - - if_print_debug (" Event count "); - sprintf (buffer, "%ld", gs_event_count (game)); - if_print_debug (buffer); - - if_print_debug (", Task count "); - sprintf (buffer, "%ld", gs_task_count (game)); - if_print_debug (buffer); - - if_print_debug (", Variable count "); - sprintf (buffer, "%ld", debug_variable_count (game)); - if_print_debug (buffer); - if_print_debug_character ('\n'); - - if (game->is_running) - if_print_debug (" Running"); - else - if_print_debug (" Not running"); - if (game->has_completed) - if_print_debug (", Completed"); - else - if_print_debug (", Not completed"); - if (game->verbose) - if_print_debug (", Verbose"); - else - if_print_debug (", Not verbose"); - if (game->bold_room_names) - if_print_debug (", Bold"); - else - if_print_debug (", Not bold"); - if (game->undo_available) - if_print_debug (", Undo"); - else - if_print_debug (", No undo"); - if_print_debug_character ('\n'); - - if_print_debug (" Score "); - sprintf (buffer, "%ld", game->score); - if_print_debug (buffer); - if_print_debug (", Turns "); - sprintf (buffer, "%ld", game->turns); - if_print_debug (buffer); - if_print_debug (", Seconds "); - sprintf (buffer, "%lu", debug->elapsed_seconds); - if_print_debug (buffer); - if_print_debug_character ('\n'); +debug_game(sc_gameref_t game, sc_command_type_t type) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_debuggerref_t debug = debug_get_debugger(game); + sc_vartype_t vt_key[2]; + const sc_char *version, *gamename, *compiledate, *gameauthor; + sc_int perspective, waitturns; + sc_bool has_sound, has_graphics, has_battle; + sc_char buffer[32]; + assert(debug_is_valid(debug)); + + if (type != COMMAND_QUERY) { + if_print_debug("The Game command takes no arguments.\n"); + return; + } + + if_print_debug("Game "); + vt_key[0].string = "Globals"; + vt_key[1].string = "GameName"; + gamename = prop_get_string(bundle, "S<-ss", vt_key); + debug_print_quoted(gamename); + if_print_debug_character('\n'); + + if_print_debug(" Compiled "); + vt_key[0].string = "CompileDate"; + compiledate = prop_get_string(bundle, "S<-s", vt_key); + debug_print_quoted(compiledate); + + if_print_debug(", Author "); + vt_key[0].string = "Globals"; + vt_key[1].string = "GameAuthor"; + gameauthor = prop_get_string(bundle, "S<-ss", vt_key); + debug_print_quoted(gameauthor); + if_print_debug_character('\n'); + + vt_key[0].string = "VersionString"; + version = prop_get_string(bundle, "S<-s", vt_key); + if_print_debug(" Version "); + if_print_debug(version); + + vt_key[0].string = "Globals"; + vt_key[1].string = "Perspective"; + perspective = prop_get_integer(bundle, "I<-ss", vt_key); + switch (perspective) { + case 0: + if_print_debug(", First person"); + break; + case 1: + if_print_debug(", Second person"); + break; + case 2: + if_print_debug(", Third person"); + break; + default: + if_print_debug(", [Unknown perspective]"); + break; + } + + vt_key[0].string = "Globals"; + vt_key[1].string = "WaitTurns"; + waitturns = prop_get_integer(bundle, "I<-ss", vt_key); + if_print_debug(", Waitturns "); + sprintf(buffer, "%ld", waitturns); + if_print_debug(buffer); + + vt_key[0].string = "Globals"; + vt_key[1].string = "Sound"; + has_sound = prop_get_boolean(bundle, "B<-ss", vt_key); + vt_key[1].string = "Graphics"; + has_graphics = prop_get_boolean(bundle, "B<-ss", vt_key); + if (has_sound) + if_print_debug(", Sound"); + if (has_graphics) + if_print_debug(", Graphics"); + if_print_debug_character('\n'); + + vt_key[0].string = "Globals"; + vt_key[1].string = "BattleSystem"; + has_battle = prop_get_boolean(bundle, "B<-ss", vt_key); + if (has_battle) + if_print_debug(" Battle system\n"); + + if_print_debug(" Room count "); + sprintf(buffer, "%ld", gs_room_count(game)); + if_print_debug(buffer); + + if_print_debug(", Object count "); + sprintf(buffer, "%ld", gs_object_count(game)); + if_print_debug(buffer); + + if_print_debug(", NPC count "); + sprintf(buffer, "%ld", gs_npc_count(game)); + if_print_debug(buffer); + if_print_debug_character('\n'); + + if_print_debug(" Event count "); + sprintf(buffer, "%ld", gs_event_count(game)); + if_print_debug(buffer); + + if_print_debug(", Task count "); + sprintf(buffer, "%ld", gs_task_count(game)); + if_print_debug(buffer); + + if_print_debug(", Variable count "); + sprintf(buffer, "%ld", debug_variable_count(game)); + if_print_debug(buffer); + if_print_debug_character('\n'); + + if (game->is_running) + if_print_debug(" Running"); + else + if_print_debug(" Not running"); + if (game->has_completed) + if_print_debug(", Completed"); + else + if_print_debug(", Not completed"); + if (game->verbose) + if_print_debug(", Verbose"); + else + if_print_debug(", Not verbose"); + if (game->bold_room_names) + if_print_debug(", Bold"); + else + if_print_debug(", Not bold"); + if (game->undo_available) + if_print_debug(", Undo"); + else + if_print_debug(", No undo"); + if_print_debug_character('\n'); + + if_print_debug(" Score "); + sprintf(buffer, "%ld", game->score); + if_print_debug(buffer); + if_print_debug(", Turns "); + sprintf(buffer, "%ld", game->turns); + if_print_debug(buffer); + if_print_debug(", Seconds "); + sprintf(buffer, "%lu", debug->elapsed_seconds); + if_print_debug(buffer); + if_print_debug_character('\n'); } @@ -921,61 +891,54 @@ debug_game (sc_gameref_t game, sc_command_type_t type) * Print a few brief details about the player status. */ static void -debug_player (sc_gameref_t game, - sc_command_t command, sc_command_type_t type) -{ - if (type != COMMAND_QUERY) - { - if_print_debug ("The Player command takes no arguments.\n"); - return; - } - - if (command == DEBUG_OLDPLAYER) - { - if (!game->undo_available) - { - if_print_debug ("There is no previous game state to examine.\n"); - return; - } - - game = game->undo; - assert (gs_is_game_valid (game)); - } - - debug_print_player (game); - if_print_debug_character ('\n'); - - if (gs_playerroom (game) == -1) - if_print_debug (" Hidden!\n"); - else - { - if_print_debug (" In "); - debug_print_room (game, gs_playerroom (game)); - if_print_debug_character ('\n'); - } - - switch (gs_playerposition (game)) - { - case 0: - if_print_debug (" Standing\n"); - break; - case 1: - if_print_debug (" Sitting\n"); - break; - case 2: - if_print_debug (" Lying\n"); - break; - default: - if_print_debug (" [Invalid position]\n"); - break; - } - - if (gs_playerparent (game) != -1) - { - if_print_debug (" Parent is "); - debug_print_object (game, gs_playerparent (game)); - if_print_debug_character ('\n'); - } +debug_player(sc_gameref_t game, + sc_command_t command, sc_command_type_t type) { + if (type != COMMAND_QUERY) { + if_print_debug("The Player command takes no arguments.\n"); + return; + } + + if (command == DEBUG_OLDPLAYER) { + if (!game->undo_available) { + if_print_debug("There is no previous game state to examine.\n"); + return; + } + + game = game->undo; + assert(gs_is_game_valid(game)); + } + + debug_print_player(game); + if_print_debug_character('\n'); + + if (gs_playerroom(game) == -1) + if_print_debug(" Hidden!\n"); + else { + if_print_debug(" In "); + debug_print_room(game, gs_playerroom(game)); + if_print_debug_character('\n'); + } + + switch (gs_playerposition(game)) { + case 0: + if_print_debug(" Standing\n"); + break; + case 1: + if_print_debug(" Sitting\n"); + break; + case 2: + if_print_debug(" Lying\n"); + break; + default: + if_print_debug(" [Invalid position]\n"); + break; + } + + if (gs_playerparent(game) != -1) { + if_print_debug(" Parent is "); + debug_print_object(game, gs_playerparent(game)); + if_print_debug_character('\n'); + } } @@ -986,41 +949,38 @@ debug_player (sc_gameref_t game, * debug commands that take ranges. */ static sc_bool -debug_normalize_arguments (sc_command_type_t type, - sc_int *arg1, sc_int *arg2, sc_int limit) -{ - sc_int low = 0, high = 0; - - /* Set range low and high depending on the command type. */ - switch (type) - { - case COMMAND_QUERY: - case COMMAND_ALL: - low = 0; - high = limit - 1; - break; - case COMMAND_ONE: - low = *arg1; - high = *arg1; - break; - case COMMAND_RANGE: - low = *arg1; - high = *arg2; - break; - default: - sc_fatal ("debug_normalize_arguments: bad command type\n"); - } - - /* If range is valid, copy out and return TRUE. */ - if (low >= 0 && low < limit && high >= 0 && high < limit && high >= low) - { - *arg1 = low; - *arg2 = high; - return TRUE; - } - - /* Input range is invalid. */ - return FALSE; +debug_normalize_arguments(sc_command_type_t type, + sc_int *arg1, sc_int *arg2, sc_int limit) { + sc_int low = 0, high = 0; + + /* Set range low and high depending on the command type. */ + switch (type) { + case COMMAND_QUERY: + case COMMAND_ALL: + low = 0; + high = limit - 1; + break; + case COMMAND_ONE: + low = *arg1; + high = *arg1; + break; + case COMMAND_RANGE: + low = *arg1; + high = *arg2; + break; + default: + sc_fatal("debug_normalize_arguments: bad command type\n"); + } + + /* If range is valid, copy out and return TRUE. */ + if (low >= 0 && low < limit && high >= 0 && high < limit && high >= low) { + *arg1 = low; + *arg2 = high; + return TRUE; + } + + /* Input range is invalid. */ + return FALSE; } @@ -1031,50 +991,43 @@ debug_normalize_arguments (sc_command_type_t type, * Print details of rooms and their direct contents. */ static sc_bool -debug_filter_room (sc_gameref_t game, sc_int room) -{ - return room == gs_playerroom (game); +debug_filter_room(sc_gameref_t game, sc_int room) { + return room == gs_playerroom(game); } static void -debug_dump_room (sc_gameref_t game, sc_int room) -{ - sc_int object, npc; - - debug_print_room (game, room); - if_print_debug_character ('\n'); - - if (gs_room_seen (game, room)) - if_print_debug (" Visited\n"); - else - if_print_debug (" Not visited\n"); - - if (gs_playerroom (game) == room) - { - if_print_debug (" "); - debug_print_player (game); - if_print_debug_character ('\n'); - } - - for (object = 0; object < gs_object_count (game); object++) - { - if (obj_indirectly_in_room (game, object, room)) - { - if_print_debug (" "); - debug_print_object (game, object); - if_print_debug_character ('\n'); - } - } - - for (npc = 0; npc < gs_npc_count (game); npc++) - { - if (npc_in_room (game, npc, room)) - { - if_print_debug (" "); - debug_print_npc (game, npc); - if_print_debug_character ('\n'); - } - } +debug_dump_room(sc_gameref_t game, sc_int room) { + sc_int object, npc; + + debug_print_room(game, room); + if_print_debug_character('\n'); + + if (gs_room_seen(game, room)) + if_print_debug(" Visited\n"); + else + if_print_debug(" Not visited\n"); + + if (gs_playerroom(game) == room) { + if_print_debug(" "); + debug_print_player(game); + if_print_debug_character('\n'); + } + + for (object = 0; object < gs_object_count(game); object++) { + if (obj_indirectly_in_room(game, object, room)) { + if_print_debug(" "); + debug_print_object(game, object); + if_print_debug_character('\n'); + } + } + + for (npc = 0; npc < gs_npc_count(game); npc++) { + if (npc_in_room(game, npc, room)) { + if_print_debug(" "); + debug_print_npc(game, npc); + if_print_debug_character('\n'); + } + } } @@ -1085,139 +1038,130 @@ debug_dump_room (sc_gameref_t game, sc_int room) * Print the changeable details of game objects. */ static sc_bool -debug_filter_object (sc_gameref_t game, sc_int object) -{ - return obj_indirectly_in_room (game, object, gs_playerroom (game)); +debug_filter_object(sc_gameref_t game, sc_int object) { + return obj_indirectly_in_room(game, object, gs_playerroom(game)); } static void -debug_dump_object (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int openness; - sc_vartype_t vt_key[3]; - sc_bool bstatic, is_statussed; - sc_int position, parent; - - debug_print_object (game, object); - if_print_debug_character ('\n'); - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Static"; - bstatic = prop_get_boolean (bundle, "B<-sis", vt_key); - - if (gs_object_seen (game, object)) - if_print_debug (" Seen"); - else - if_print_debug (" Not seen"); - if (bstatic) - { - if (gs_object_static_unmoved (game, object)) - if_print_debug (", Not relocated"); - else - if_print_debug (", Relocated"); - } - else - { - vt_key[2].string = "OnlyWhenNotMoved"; - if (prop_get_integer (bundle, "I<-sis", vt_key) == 1) - { - if (gs_object_unmoved (game, object)) - if_print_debug (", Not moved"); - else - if_print_debug (", Moved"); - } - } - openness = gs_object_openness (game, object); - switch (openness) - { - case OBJ_OPEN: - if_print_debug (", Open"); - break; - case OBJ_CLOSED: - if_print_debug (", Closed"); - break; - case OBJ_LOCKED: - if_print_debug (", Locked"); - break; - } - if_print_debug_character ('\n'); - - position = gs_object_position (game, object); - parent = gs_object_parent (game, object); - switch (position) - { - case OBJ_HIDDEN: - if (bstatic) - if_print_debug (" Static default\n"); - else - if_print_debug (" Hidden\n"); - break; - case OBJ_HELD_PLAYER: - if_print_debug (" Held by "); - debug_print_player (game); - if_print_debug_character ('\n'); - break; - case OBJ_HELD_NPC: - if_print_debug (" Held by "); - debug_print_npc (game, parent); - if_print_debug_character ('\n'); - break; - case OBJ_WORN_PLAYER: - if_print_debug (" Worn by "); - debug_print_player (game); - if_print_debug_character ('\n'); - break; - case OBJ_WORN_NPC: - if_print_debug (" Worn by "); - debug_print_npc (game, parent); - if_print_debug_character ('\n'); - break; - case OBJ_PART_NPC: - if_print_debug (" Part of "); - if (parent == -1) - debug_print_player (game); - else - debug_print_npc (game, parent); - if_print_debug_character ('\n'); - break; - case OBJ_ON_OBJECT: - if_print_debug (" On "); - debug_print_object (game, parent); - if_print_debug_character ('\n'); - break; - case OBJ_IN_OBJECT: - if_print_debug (" Inside "); - debug_print_object (game, parent); - if_print_debug_character ('\n'); - break; - default: - if_print_debug (" In "); - debug_print_room (game, position - 1); - if_print_debug_character ('\n'); - break; - } - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "CurrentState"; - is_statussed = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - if (is_statussed) - { - sc_char buffer[32]; - const sc_char *states; - - if_print_debug (" State "); - sprintf (buffer, "%ld", gs_object_state (game, object)); - if_print_debug (buffer); - - vt_key[2].string = "States"; - states = prop_get_string (bundle, "S<-sis", vt_key); - if_print_debug (" of "); - debug_print_quoted (states); - if_print_debug_character ('\n'); - } +debug_dump_object(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int openness; + sc_vartype_t vt_key[3]; + sc_bool bstatic, is_statussed; + sc_int position, parent; + + debug_print_object(game, object); + if_print_debug_character('\n'); + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Static"; + bstatic = prop_get_boolean(bundle, "B<-sis", vt_key); + + if (gs_object_seen(game, object)) + if_print_debug(" Seen"); + else + if_print_debug(" Not seen"); + if (bstatic) { + if (gs_object_static_unmoved(game, object)) + if_print_debug(", Not relocated"); + else + if_print_debug(", Relocated"); + } else { + vt_key[2].string = "OnlyWhenNotMoved"; + if (prop_get_integer(bundle, "I<-sis", vt_key) == 1) { + if (gs_object_unmoved(game, object)) + if_print_debug(", Not moved"); + else + if_print_debug(", Moved"); + } + } + openness = gs_object_openness(game, object); + switch (openness) { + case OBJ_OPEN: + if_print_debug(", Open"); + break; + case OBJ_CLOSED: + if_print_debug(", Closed"); + break; + case OBJ_LOCKED: + if_print_debug(", Locked"); + break; + } + if_print_debug_character('\n'); + + position = gs_object_position(game, object); + parent = gs_object_parent(game, object); + switch (position) { + case OBJ_HIDDEN: + if (bstatic) + if_print_debug(" Static default\n"); + else + if_print_debug(" Hidden\n"); + break; + case OBJ_HELD_PLAYER: + if_print_debug(" Held by "); + debug_print_player(game); + if_print_debug_character('\n'); + break; + case OBJ_HELD_NPC: + if_print_debug(" Held by "); + debug_print_npc(game, parent); + if_print_debug_character('\n'); + break; + case OBJ_WORN_PLAYER: + if_print_debug(" Worn by "); + debug_print_player(game); + if_print_debug_character('\n'); + break; + case OBJ_WORN_NPC: + if_print_debug(" Worn by "); + debug_print_npc(game, parent); + if_print_debug_character('\n'); + break; + case OBJ_PART_NPC: + if_print_debug(" Part of "); + if (parent == -1) + debug_print_player(game); + else + debug_print_npc(game, parent); + if_print_debug_character('\n'); + break; + case OBJ_ON_OBJECT: + if_print_debug(" On "); + debug_print_object(game, parent); + if_print_debug_character('\n'); + break; + case OBJ_IN_OBJECT: + if_print_debug(" Inside "); + debug_print_object(game, parent); + if_print_debug_character('\n'); + break; + default: + if_print_debug(" In "); + debug_print_room(game, position - 1); + if_print_debug_character('\n'); + break; + } + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "CurrentState"; + is_statussed = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + if (is_statussed) { + sc_char buffer[32]; + const sc_char *states; + + if_print_debug(" State "); + sprintf(buffer, "%ld", gs_object_state(game, object)); + if_print_debug(buffer); + + vt_key[2].string = "States"; + states = prop_get_string(bundle, "S<-sis", vt_key); + if_print_debug(" of "); + debug_print_quoted(states); + if_print_debug_character('\n'); + } } @@ -1228,71 +1172,64 @@ debug_dump_object (sc_gameref_t game, sc_int object) * Print stuff about NPCs. */ static sc_bool -debug_filter_npc (sc_gameref_t game, sc_int npc) -{ - return npc_in_room (game, npc, gs_playerroom (game)); +debug_filter_npc(sc_gameref_t game, sc_int npc) { + return npc_in_room(game, npc, gs_playerroom(game)); } static void -debug_dump_npc (sc_gameref_t game, sc_int npc) -{ - debug_print_npc (game, npc); - if_print_debug_character ('\n'); - - if (gs_npc_seen (game, npc)) - if_print_debug (" Seen\n"); - else - if_print_debug (" Not seen\n"); - - if (gs_npc_location (game, npc) - 1 == -1) - if_print_debug (" Hidden\n"); - else - { - if_print_debug (" In "); - debug_print_room (game, gs_npc_location (game, npc) - 1); - if_print_debug_character ('\n'); - } - - switch (gs_npc_position (game, npc)) - { - case 0: - if_print_debug (" Standing\n"); - break; - case 1: - if_print_debug (" Sitting\n"); - break; - case 2: - if_print_debug (" Lying\n"); - break; - default: - if_print_debug (" [Invalid position]\n"); - break; - } - - if (gs_npc_parent (game, npc) != -1) - { - if_print_debug (" Parent is "); - debug_print_object (game, gs_npc_parent (game, npc)); - if_print_debug_character ('\n'); - } - - if (gs_npc_walkstep_count (game, npc) > 0) - { - sc_char buffer[32]; - sc_int walk; - - if_print_debug (" Walkstep count "); - sprintf (buffer, "%ld", gs_npc_walkstep_count (game, npc)); - if_print_debug (buffer); - if_print_debug (", Walks { "); - for (walk = 0; walk < gs_npc_walkstep_count (game, npc); walk++) - { - sprintf (buffer, "%ld", gs_npc_walkstep (game, npc, walk)); - if_print_debug (buffer); - if_print_debug_character (' '); - } - if_print_debug ("}.\n"); - } +debug_dump_npc(sc_gameref_t game, sc_int npc) { + debug_print_npc(game, npc); + if_print_debug_character('\n'); + + if (gs_npc_seen(game, npc)) + if_print_debug(" Seen\n"); + else + if_print_debug(" Not seen\n"); + + if (gs_npc_location(game, npc) - 1 == -1) + if_print_debug(" Hidden\n"); + else { + if_print_debug(" In "); + debug_print_room(game, gs_npc_location(game, npc) - 1); + if_print_debug_character('\n'); + } + + switch (gs_npc_position(game, npc)) { + case 0: + if_print_debug(" Standing\n"); + break; + case 1: + if_print_debug(" Sitting\n"); + break; + case 2: + if_print_debug(" Lying\n"); + break; + default: + if_print_debug(" [Invalid position]\n"); + break; + } + + if (gs_npc_parent(game, npc) != -1) { + if_print_debug(" Parent is "); + debug_print_object(game, gs_npc_parent(game, npc)); + if_print_debug_character('\n'); + } + + if (gs_npc_walkstep_count(game, npc) > 0) { + sc_char buffer[32]; + sc_int walk; + + if_print_debug(" Walkstep count "); + sprintf(buffer, "%ld", gs_npc_walkstep_count(game, npc)); + if_print_debug(buffer); + if_print_debug(", Walks { "); + for (walk = 0; walk < gs_npc_walkstep_count(game, npc); walk++) { + sprintf(buffer, "%ld", gs_npc_walkstep(game, npc, walk)); + if_print_debug(buffer); + if_print_debug_character(' '); + } + if_print_debug("}.\n"); + } } @@ -1303,44 +1240,41 @@ debug_dump_npc (sc_gameref_t game, sc_int npc) * Print stuff about events. */ static sc_bool -debug_filter_event (sc_gameref_t game, sc_int event) -{ - return gs_event_state (game, event) == ES_RUNNING; +debug_filter_event(sc_gameref_t game, sc_int event) { + return gs_event_state(game, event) == ES_RUNNING; } static void -debug_dump_event (sc_gameref_t game, sc_int event) -{ - sc_char buffer[32]; - - debug_print_event (game, event); - if_print_debug_character ('\n'); - - switch (gs_event_state (game, event)) - { - case ES_WAITING: - if_print_debug (" Waiting\n"); - break; - case ES_RUNNING: - if_print_debug (" Running\n"); - break; - case ES_AWAITING: - if_print_debug (" Awaiting\n"); - break; - case ES_FINISHED: - if_print_debug (" Finished\n"); - break; - case ES_PAUSED: - if_print_debug (" Paused\n"); - break; - default: - if_print_debug (" [Invalid state]\n"); - break; - } - - if_print_debug (" Time "); - sprintf (buffer, "%ld\n", gs_event_time (game, event)); - if_print_debug (buffer); +debug_dump_event(sc_gameref_t game, sc_int event) { + sc_char buffer[32]; + + debug_print_event(game, event); + if_print_debug_character('\n'); + + switch (gs_event_state(game, event)) { + case ES_WAITING: + if_print_debug(" Waiting\n"); + break; + case ES_RUNNING: + if_print_debug(" Running\n"); + break; + case ES_AWAITING: + if_print_debug(" Awaiting\n"); + break; + case ES_FINISHED: + if_print_debug(" Finished\n"); + break; + case ES_PAUSED: + if_print_debug(" Paused\n"); + break; + default: + if_print_debug(" [Invalid state]\n"); + break; + } + + if_print_debug(" Time "); + sprintf(buffer, "%ld\n", gs_event_time(game, event)); + if_print_debug(buffer); } @@ -1351,29 +1285,27 @@ debug_dump_event (sc_gameref_t game, sc_int event) * Print stuff about tasks. */ static sc_bool -debug_filter_task (sc_gameref_t game, sc_int task) -{ - return task_can_run_task (game, task); +debug_filter_task(sc_gameref_t game, sc_int task) { + return task_can_run_task(game, task); } static void -debug_dump_task (sc_gameref_t game, sc_int task) -{ - debug_print_task (game, task); - if_print_debug_character ('\n'); - - if (task_can_run_task (game, task)) - if_print_debug (" Runnable"); - else - if_print_debug (" Not runnable"); - if (gs_task_done (game, task)) - if_print_debug (", Done"); - else - if_print_debug (", Not done"); - if (gs_task_scored (game, task)) - if_print_debug (", Scored\n"); - else - if_print_debug (", Not scored\n"); +debug_dump_task(sc_gameref_t game, sc_int task) { + debug_print_task(game, task); + if_print_debug_character('\n'); + + if (task_can_run_task(game, task)) + if_print_debug(" Runnable"); + else + if_print_debug(" Not runnable"); + if (gs_task_done(game, task)) + if_print_debug(", Done"); + else + if_print_debug(", Not done"); + if (gs_task_scored(game, task)) + if_print_debug(", Scored\n"); + else + if_print_debug(", Not scored\n"); } @@ -1383,46 +1315,41 @@ debug_dump_task (sc_gameref_t game, sc_int task) * Print stuff about variables. */ static void -debug_dump_variable (sc_gameref_t game, sc_int variable) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[3], vt_rvalue; - const sc_char *name; - sc_int var_type; - - debug_print_variable (game, variable); - if_print_debug_character ('\n'); - - vt_key[0].string = "Variables"; - vt_key[1].integer = variable; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - if_print_debug (" Value = "); - if (var_get (vars, name, &var_type, &vt_rvalue)) - { - switch (var_type) - { - case VAR_INTEGER: - { - sc_char buffer[32]; - - sprintf (buffer, "%ld", vt_rvalue.integer); - if_print_debug (buffer); - break; - } - case VAR_STRING: - debug_print_quoted (vt_rvalue.string); - break; - default: - if_print_debug ("[Unknown]"); - break; - } - } - else - if_print_debug ("[Unknown]"); - if_print_debug_character ('\n'); +debug_dump_variable(sc_gameref_t game, sc_int variable) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[3], vt_rvalue; + const sc_char *name; + sc_int var_type; + + debug_print_variable(game, variable); + if_print_debug_character('\n'); + + vt_key[0].string = "Variables"; + vt_key[1].integer = variable; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + if_print_debug(" Value = "); + if (var_get(vars, name, &var_type, &vt_rvalue)) { + switch (var_type) { + case VAR_INTEGER: { + sc_char buffer[32]; + + sprintf(buffer, "%ld", vt_rvalue.integer); + if_print_debug(buffer); + break; + } + case VAR_STRING: + debug_print_quoted(vt_rvalue.string); + break; + default: + if_print_debug("[Unknown]"); + break; + } + } else + if_print_debug("[Unknown]"); + if_print_debug_character('\n'); } @@ -1432,142 +1359,131 @@ debug_dump_variable (sc_gameref_t game, sc_int variable) * Common handler for iterating dumps of classes. */ static void -debug_dump_common (sc_gameref_t game, sc_command_t command, - sc_command_type_t type, sc_int arg1, sc_int arg2) -{ - sc_int low = arg1, high = arg2; - sc_int limit, index_; - const sc_char *class_; - sc_bool (*filter_function) (sc_gameref_t, sc_int); - void (*dumper_function) (sc_gameref_t, sc_int); - sc_bool printed = FALSE; - - /* Initialize variables to avoid gcc warnings. */ - limit = 0; - class_ = NULL; - filter_function = NULL; - dumper_function = NULL; - - /* Switch to undo game on relevant commands. */ - switch (command) - { - case DEBUG_OLDROOMS: - case DEBUG_OLDOBJECTS: - case DEBUG_OLDNPCS: - case DEBUG_OLDEVENTS: - case DEBUG_OLDTASKS: - case DEBUG_OLDVARIABLES: - if (!game->undo_available) - { - if_print_debug ("There is no previous game state to examine.\n"); - return; - } - - game = game->undo; - assert (gs_is_game_valid (game)); - break; - - default: - break; - } - - /* Demultiplex dump command. */ - switch (command) - { - case DEBUG_ROOMS: - case DEBUG_OLDROOMS: - class_ = "Room"; - filter_function = debug_filter_room; - dumper_function = debug_dump_room; - limit = gs_room_count (game); - break; - case DEBUG_OBJECTS: - case DEBUG_OLDOBJECTS: - class_ = "Object"; - filter_function = debug_filter_object; - dumper_function = debug_dump_object; - limit = gs_object_count (game); - break; - case DEBUG_NPCS: - case DEBUG_OLDNPCS: - class_ = "NPC"; - filter_function = debug_filter_npc; - dumper_function = debug_dump_npc; - limit = gs_npc_count (game); - break; - case DEBUG_EVENTS: - case DEBUG_OLDEVENTS: - class_ = "Event"; - filter_function = debug_filter_event; - dumper_function = debug_dump_event; - limit = gs_event_count (game); - break; - case DEBUG_TASKS: - case DEBUG_OLDTASKS: - class_ = "Task"; - filter_function = debug_filter_task; - dumper_function = debug_dump_task; - limit = gs_task_count (game); - break; - case DEBUG_VARIABLES: - case DEBUG_OLDVARIABLES: - class_ = "Variable"; - filter_function = NULL; - dumper_function = debug_dump_variable; - limit = debug_variable_count (game); - break; - default: - sc_fatal ("debug_dump_common: invalid command\n"); - } - - /* Normalize to this limit. */ - if (!debug_normalize_arguments (type, &low, &high, limit)) - { - if (limit == 0) - { - if_print_debug ("There is nothing of type "); - debug_print_quoted (class_); - if_print_debug (" to print.\n"); - } - else - { - if_print_debug ("Invalid item or range for "); - debug_print_quoted (class_); - if (limit == 1) - if_print_debug ("; only 0 is valid.\n"); - else - { - sc_char buffer[32]; - - if_print_debug ("; valid values are 0 to "); - sprintf (buffer, "%ld", limit - 1); - if_print_debug (buffer); - if_print_debug (".\n"); - } - } - return; - } - - /* Print each item of the class, filtering on query commands. */ - for (index_ = low; index_ <= high; index_++) - { - if (type == COMMAND_QUERY - && filter_function && !filter_function (game, index_)) - continue; - - if (printed) - if_print_debug_character ('\n'); - dumper_function (game, index_); - printed = TRUE; - } - if (!printed) - { - if_print_debug ("Nothing of type "); - debug_print_quoted (class_); - if_print_debug (" is relevant.\nTry \""); - if_print_debug (class_); - if_print_debug (" *\" to show all items of this type.\n"); - } +debug_dump_common(sc_gameref_t game, sc_command_t command, + sc_command_type_t type, sc_int arg1, sc_int arg2) { + sc_int low = arg1, high = arg2; + sc_int limit, index_; + const sc_char *class_; + sc_bool(*filter_function)(sc_gameref_t, sc_int); + void (*dumper_function)(sc_gameref_t, sc_int); + sc_bool printed = FALSE; + + /* Initialize variables to avoid gcc warnings. */ + limit = 0; + class_ = NULL; + filter_function = NULL; + dumper_function = NULL; + + /* Switch to undo game on relevant commands. */ + switch (command) { + case DEBUG_OLDROOMS: + case DEBUG_OLDOBJECTS: + case DEBUG_OLDNPCS: + case DEBUG_OLDEVENTS: + case DEBUG_OLDTASKS: + case DEBUG_OLDVARIABLES: + if (!game->undo_available) { + if_print_debug("There is no previous game state to examine.\n"); + return; + } + + game = game->undo; + assert(gs_is_game_valid(game)); + break; + + default: + break; + } + + /* Demultiplex dump command. */ + switch (command) { + case DEBUG_ROOMS: + case DEBUG_OLDROOMS: + class_ = "Room"; + filter_function = debug_filter_room; + dumper_function = debug_dump_room; + limit = gs_room_count(game); + break; + case DEBUG_OBJECTS: + case DEBUG_OLDOBJECTS: + class_ = "Object"; + filter_function = debug_filter_object; + dumper_function = debug_dump_object; + limit = gs_object_count(game); + break; + case DEBUG_NPCS: + case DEBUG_OLDNPCS: + class_ = "NPC"; + filter_function = debug_filter_npc; + dumper_function = debug_dump_npc; + limit = gs_npc_count(game); + break; + case DEBUG_EVENTS: + case DEBUG_OLDEVENTS: + class_ = "Event"; + filter_function = debug_filter_event; + dumper_function = debug_dump_event; + limit = gs_event_count(game); + break; + case DEBUG_TASKS: + case DEBUG_OLDTASKS: + class_ = "Task"; + filter_function = debug_filter_task; + dumper_function = debug_dump_task; + limit = gs_task_count(game); + break; + case DEBUG_VARIABLES: + case DEBUG_OLDVARIABLES: + class_ = "Variable"; + filter_function = NULL; + dumper_function = debug_dump_variable; + limit = debug_variable_count(game); + break; + default: + sc_fatal("debug_dump_common: invalid command\n"); + } + + /* Normalize to this limit. */ + if (!debug_normalize_arguments(type, &low, &high, limit)) { + if (limit == 0) { + if_print_debug("There is nothing of type "); + debug_print_quoted(class_); + if_print_debug(" to print.\n"); + } else { + if_print_debug("Invalid item or range for "); + debug_print_quoted(class_); + if (limit == 1) + if_print_debug("; only 0 is valid.\n"); + else { + sc_char buffer[32]; + + if_print_debug("; valid values are 0 to "); + sprintf(buffer, "%ld", limit - 1); + if_print_debug(buffer); + if_print_debug(".\n"); + } + } + return; + } + + /* Print each item of the class, filtering on query commands. */ + for (index_ = low; index_ <= high; index_++) { + if (type == COMMAND_QUERY + && filter_function && !filter_function(game, index_)) + continue; + + if (printed) + if_print_debug_character('\n'); + dumper_function(game, index_); + printed = TRUE; + } + if (!printed) { + if_print_debug("Nothing of type "); + debug_print_quoted(class_); + if_print_debug(" is relevant.\nTry \""); + if_print_debug(class_); + if_print_debug(" *\" to show all items of this type.\n"); + } } @@ -1577,22 +1493,20 @@ debug_dump_common (sc_gameref_t game, sc_command_t command, * Print the current raw printfilter contents. */ static void -debug_buffer (sc_gameref_t game, sc_command_type_t type) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_char *buffer; - - if (type != COMMAND_QUERY) - { - if_print_debug ("The Buffer command takes no arguments.\n"); - return; - } - - buffer = pf_get_buffer (filter); - if (buffer) - if_print_debug (buffer); - else - if_print_debug ("There is no game text buffered.\n"); +debug_buffer(sc_gameref_t game, sc_command_type_t type) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_char *buffer; + + if (type != COMMAND_QUERY) { + if_print_debug("The Buffer command takes no arguments.\n"); + return; + } + + buffer = pf_get_buffer(filter); + if (buffer) + if_print_debug(buffer); + else + if_print_debug("There is no game text buffered.\n"); } @@ -1602,17 +1516,16 @@ debug_buffer (sc_gameref_t game, sc_command_type_t type) * Helper for debug_resources(). */ static void -debug_print_resource (const sc_resource_t *resource) -{ - sc_char buffer[32]; - - debug_print_quoted (resource->name); - if_print_debug (", offset "); - sprintf (buffer, "%ld", resource->offset); - if_print_debug (buffer); - if_print_debug (", length "); - sprintf (buffer, "%ld", resource->length); - if_print_debug (buffer); +debug_print_resource(const sc_resource_t *resource) { + sc_char buffer[32]; + + debug_print_quoted(resource->name); + if_print_debug(", offset "); + sprintf(buffer, "%ld", resource->offset); + if_print_debug(buffer); + if_print_debug(", length "); + sprintf(buffer, "%ld", resource->length); + if_print_debug(buffer); } @@ -1622,61 +1535,54 @@ debug_print_resource (const sc_resource_t *resource) * Print any active and requested resources. */ static void -debug_resources (sc_gameref_t game, sc_command_type_t type) -{ - sc_bool printed = FALSE; - - if (type != COMMAND_QUERY) - { - if_print_debug ("The Resources command takes no arguments.\n"); - return; - } - - if (game->stop_sound) - { - if_print_debug ("Sound stop"); - if (strlen (game->requested_sound.name) > 0) - if_print_debug (" before new sound"); - if_print_debug (" requested"); - if (game->sound_active) - if_print_debug (", sound active"); - if_print_debug (".\n"); - printed = TRUE; - } - if (!res_compare_resource (&game->requested_sound, - &game->playing_sound)) - { - if_print_debug ("Requested Sound "); - debug_print_resource (&game->requested_sound); - if_print_debug (".\n"); - printed = TRUE; - } - if (!res_compare_resource (&game->requested_graphic, - &game->displayed_graphic)) - { - if_print_debug ("Requested Graphic "); - debug_print_resource (&game->requested_graphic); - if_print_debug (".\n"); - printed = TRUE; - } - - if (strlen (game->playing_sound.name) > 0) - { - if_print_debug ("Playing Sound "); - debug_print_resource (&game->playing_sound); - if_print_debug (".\n"); - printed = TRUE; - } - if (strlen (game->displayed_graphic.name) > 0) - { - if_print_debug ("Displaying Graphic "); - debug_print_resource (&game->displayed_graphic); - if_print_debug (".\n"); - printed = TRUE; - } - - if (!printed) - if_print_debug ("There is no game resource activity.\n"); +debug_resources(sc_gameref_t game, sc_command_type_t type) { + sc_bool printed = FALSE; + + if (type != COMMAND_QUERY) { + if_print_debug("The Resources command takes no arguments.\n"); + return; + } + + if (game->stop_sound) { + if_print_debug("Sound stop"); + if (strlen(game->requested_sound.name) > 0) + if_print_debug(" before new sound"); + if_print_debug(" requested"); + if (game->sound_active) + if_print_debug(", sound active"); + if_print_debug(".\n"); + printed = TRUE; + } + if (!res_compare_resource(&game->requested_sound, + &game->playing_sound)) { + if_print_debug("Requested Sound "); + debug_print_resource(&game->requested_sound); + if_print_debug(".\n"); + printed = TRUE; + } + if (!res_compare_resource(&game->requested_graphic, + &game->displayed_graphic)) { + if_print_debug("Requested Graphic "); + debug_print_resource(&game->requested_graphic); + if_print_debug(".\n"); + printed = TRUE; + } + + if (strlen(game->playing_sound.name) > 0) { + if_print_debug("Playing Sound "); + debug_print_resource(&game->playing_sound); + if_print_debug(".\n"); + printed = TRUE; + } + if (strlen(game->displayed_graphic.name) > 0) { + if_print_debug("Displaying Graphic "); + debug_print_resource(&game->displayed_graphic); + if_print_debug(".\n"); + printed = TRUE; + } + + if (!printed) + if_print_debug("There is no game resource activity.\n"); } @@ -1687,42 +1593,38 @@ debug_resources (sc_gameref_t game, sc_command_type_t type) * given value. */ static void -debug_random (sc_command_type_t type, sc_int new_seed) -{ - const sc_char *random_type; - sc_char buffer[32]; - - if (type != COMMAND_ONE && type != COMMAND_QUERY) - { - if_print_debug ("The Random command takes either one argument or" - " no arguments.\n"); - return; - } - - random_type = sc_is_congruential_random () ? "congruential" : "platform"; - - if (type == COMMAND_QUERY) - { - if_print_debug ("The "); - if_print_debug (random_type); - if_print_debug (" random number generator is selected.\n"); - return; - } - - if (new_seed == 0) - { - if_print_debug ("The seed value may not be zero.\n"); - return; - } - - sc_seed_random (new_seed); - - if_print_debug ("Set seed "); - sprintf (buffer, "%ld", new_seed); - if_print_debug (buffer); - if_print_debug (" for the "); - if_print_debug (random_type); - if_print_debug (" random number generator.\n"); +debug_random(sc_command_type_t type, sc_int new_seed) { + const sc_char *random_type; + sc_char buffer[32]; + + if (type != COMMAND_ONE && type != COMMAND_QUERY) { + if_print_debug("The Random command takes either one argument or" + " no arguments.\n"); + return; + } + + random_type = sc_is_congruential_random() ? "congruential" : "platform"; + + if (type == COMMAND_QUERY) { + if_print_debug("The "); + if_print_debug(random_type); + if_print_debug(" random number generator is selected.\n"); + return; + } + + if (new_seed == 0) { + if_print_debug("The seed value may not be zero.\n"); + return; + } + + sc_seed_random(new_seed); + + if_print_debug("Set seed "); + sprintf(buffer, "%ld", new_seed); + if_print_debug(buffer); + if_print_debug(" for the "); + if_print_debug(random_type); + if_print_debug(" random number generator.\n"); } @@ -1732,184 +1634,165 @@ debug_random (sc_command_type_t type, sc_int new_seed) * Common handler for setting and clearing watchpoints. */ static void -debug_watchpoint_common (sc_gameref_t game, sc_command_t command, - sc_command_type_t type, sc_int arg1, sc_int arg2) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - sc_int low = arg1, high = arg2; - sc_int limit, index_; - const sc_char *class_; - sc_bool *watchpoints, action; - sc_char buffer[32]; - assert (debug_is_valid (debug)); - - /* Initialize variables to avoid gcc warnings. */ - limit = 0; - class_ = NULL; - watchpoints = NULL; - action = FALSE; - - /* Set action to TRUE or FALSE, for setting/clearing watchpoints. */ - switch (command) - { - case DEBUG_WATCHPLAYER: - case DEBUG_WATCHOBJECTS: - case DEBUG_WATCHNPCS: - case DEBUG_WATCHEVENTS: - case DEBUG_WATCHTASKS: - case DEBUG_WATCHVARIABLES: - action = TRUE; - break; - case DEBUG_CLEARPLAYER: - case DEBUG_CLEAROBJECTS: - case DEBUG_CLEARNPCS: - case DEBUG_CLEAREVENTS: - case DEBUG_CLEARTASKS: - case DEBUG_CLEARVARIABLES: - action = FALSE; - break; - default: - sc_fatal ("debug_watchpoint_common: invalid command\n"); - } - - /* Handle player watchpoint setting. */ - if (command == DEBUG_WATCHPLAYER || command == DEBUG_CLEARPLAYER) - { - if (command == DEBUG_CLEARPLAYER) - { - debug->watch_player = action; - if_print_debug ("Cleared Player watchpoint.\n"); - } - else if (type == COMMAND_ONE && arg1 == 0) - { - debug->watch_player = action; - if_print_debug ("Set Player watchpoint.\n"); - } - else - { - if (debug->watch_player) - if_print_debug ("Player watchpoint is set.\n"); - else - if_print_debug ("No Player watchpoint is set; to set one, use" - " \"Watchplayer 0\".\n"); - } - return; - } - - /* Demultiplex watchpoint command. */ - switch (command) - { - case DEBUG_WATCHOBJECTS: - case DEBUG_CLEAROBJECTS: - class_ = "Object"; - watchpoints = debug->watch_objects; - limit = gs_object_count (game); - break; - case DEBUG_WATCHNPCS: - case DEBUG_CLEARNPCS: - class_ = "NPC"; - watchpoints = debug->watch_npcs; - limit = gs_npc_count (game); - break; - case DEBUG_WATCHEVENTS: - case DEBUG_CLEAREVENTS: - class_ = "Event"; - watchpoints = debug->watch_events; - limit = gs_event_count (game); - break; - case DEBUG_WATCHTASKS: - case DEBUG_CLEARTASKS: - class_ = "Task"; - watchpoints = debug->watch_tasks; - limit = gs_task_count (game); - break; - case DEBUG_WATCHVARIABLES: - case DEBUG_CLEARVARIABLES: - class_ = "Variable"; - watchpoints = debug->watch_variables; - limit = debug_variable_count (game); - break; - default: - sc_fatal ("debug_watchpoint_common: invalid command\n"); - } - - /* Normalize to this limit. */ - if (!debug_normalize_arguments (type, &low, &high, limit)) - { - if (limit == 0) - { - if_print_debug ("There is nothing of type "); - debug_print_quoted (class_); - if_print_debug (" to watch.\n"); - } - else - { - if_print_debug ("Invalid item or range for "); - debug_print_quoted (class_); - if (limit == 1) - if_print_debug ("; only 0 is valid.\n"); - else - { - if_print_debug ("; valid values are 0 to "); - sprintf (buffer, "%ld", limit - 1); - if_print_debug (buffer); - if_print_debug (".\n"); - } - } - return; - } - - /* On query, search the array for set flags, and print out. */ - if (type == COMMAND_QUERY) - { - sc_bool printed = FALSE; - - /* Scan for set watchpoints, and list each found. */ - for (index_ = low; index_ <= high; index_++) - { - if (watchpoints[index_]) - { - if (!printed) - { - if_print_debug ("Watchpoints are set for "); - if_print_debug (class_); - if_print_debug (" { "); - } - sprintf (buffer, "%ld", index_); - if_print_debug (buffer); - if_print_debug_character (' '); - printed = TRUE; - } - } - if (printed) - if_print_debug ("}.\n"); - else - { - if_print_debug ("No "); - if_print_debug (class_); - if_print_debug (" watchpoints are set.\n"); - } - return; - } - - /* - * For non-queries, set watchpoint flags as defined in action for - * the range determined, and print confirmation. - */ - for (index_ = low; index_ <= high; index_++) - watchpoints[index_] = action; - - if (action) - if_print_debug ("Set "); - else - if_print_debug ("Cleared "); - sprintf (buffer, "%ld ", high - low + 1); - if_print_debug (buffer); - if_print_debug (class_); - if (high == low) - if_print_debug (" watchpoint.\n"); - else - if_print_debug (" watchpoints.\n"); +debug_watchpoint_common(sc_gameref_t game, sc_command_t command, + sc_command_type_t type, sc_int arg1, sc_int arg2) { + const sc_debuggerref_t debug = debug_get_debugger(game); + sc_int low = arg1, high = arg2; + sc_int limit, index_; + const sc_char *class_; + sc_bool *watchpoints, action; + sc_char buffer[32]; + assert(debug_is_valid(debug)); + + /* Initialize variables to avoid gcc warnings. */ + limit = 0; + class_ = NULL; + watchpoints = NULL; + action = FALSE; + + /* Set action to TRUE or FALSE, for setting/clearing watchpoints. */ + switch (command) { + case DEBUG_WATCHPLAYER: + case DEBUG_WATCHOBJECTS: + case DEBUG_WATCHNPCS: + case DEBUG_WATCHEVENTS: + case DEBUG_WATCHTASKS: + case DEBUG_WATCHVARIABLES: + action = TRUE; + break; + case DEBUG_CLEARPLAYER: + case DEBUG_CLEAROBJECTS: + case DEBUG_CLEARNPCS: + case DEBUG_CLEAREVENTS: + case DEBUG_CLEARTASKS: + case DEBUG_CLEARVARIABLES: + action = FALSE; + break; + default: + sc_fatal("debug_watchpoint_common: invalid command\n"); + } + + /* Handle player watchpoint setting. */ + if (command == DEBUG_WATCHPLAYER || command == DEBUG_CLEARPLAYER) { + if (command == DEBUG_CLEARPLAYER) { + debug->watch_player = action; + if_print_debug("Cleared Player watchpoint.\n"); + } else if (type == COMMAND_ONE && arg1 == 0) { + debug->watch_player = action; + if_print_debug("Set Player watchpoint.\n"); + } else { + if (debug->watch_player) + if_print_debug("Player watchpoint is set.\n"); + else + if_print_debug("No Player watchpoint is set; to set one, use" + " \"Watchplayer 0\".\n"); + } + return; + } + + /* Demultiplex watchpoint command. */ + switch (command) { + case DEBUG_WATCHOBJECTS: + case DEBUG_CLEAROBJECTS: + class_ = "Object"; + watchpoints = debug->watch_objects; + limit = gs_object_count(game); + break; + case DEBUG_WATCHNPCS: + case DEBUG_CLEARNPCS: + class_ = "NPC"; + watchpoints = debug->watch_npcs; + limit = gs_npc_count(game); + break; + case DEBUG_WATCHEVENTS: + case DEBUG_CLEAREVENTS: + class_ = "Event"; + watchpoints = debug->watch_events; + limit = gs_event_count(game); + break; + case DEBUG_WATCHTASKS: + case DEBUG_CLEARTASKS: + class_ = "Task"; + watchpoints = debug->watch_tasks; + limit = gs_task_count(game); + break; + case DEBUG_WATCHVARIABLES: + case DEBUG_CLEARVARIABLES: + class_ = "Variable"; + watchpoints = debug->watch_variables; + limit = debug_variable_count(game); + break; + default: + sc_fatal("debug_watchpoint_common: invalid command\n"); + } + + /* Normalize to this limit. */ + if (!debug_normalize_arguments(type, &low, &high, limit)) { + if (limit == 0) { + if_print_debug("There is nothing of type "); + debug_print_quoted(class_); + if_print_debug(" to watch.\n"); + } else { + if_print_debug("Invalid item or range for "); + debug_print_quoted(class_); + if (limit == 1) + if_print_debug("; only 0 is valid.\n"); + else { + if_print_debug("; valid values are 0 to "); + sprintf(buffer, "%ld", limit - 1); + if_print_debug(buffer); + if_print_debug(".\n"); + } + } + return; + } + + /* On query, search the array for set flags, and print out. */ + if (type == COMMAND_QUERY) { + sc_bool printed = FALSE; + + /* Scan for set watchpoints, and list each found. */ + for (index_ = low; index_ <= high; index_++) { + if (watchpoints[index_]) { + if (!printed) { + if_print_debug("Watchpoints are set for "); + if_print_debug(class_); + if_print_debug(" { "); + } + sprintf(buffer, "%ld", index_); + if_print_debug(buffer); + if_print_debug_character(' '); + printed = TRUE; + } + } + if (printed) + if_print_debug("}.\n"); + else { + if_print_debug("No "); + if_print_debug(class_); + if_print_debug(" watchpoints are set.\n"); + } + return; + } + + /* + * For non-queries, set watchpoint flags as defined in action for + * the range determined, and print confirmation. + */ + for (index_ = low; index_ <= high; index_++) + watchpoints[index_] = action; + + if (action) + if_print_debug("Set "); + else + if_print_debug("Cleared "); + sprintf(buffer, "%ld ", high - low + 1); + if_print_debug(buffer); + if_print_debug(class_); + if (high == low) + if_print_debug(" watchpoint.\n"); + else + if_print_debug(" watchpoints.\n"); } @@ -1919,53 +1802,50 @@ debug_watchpoint_common (sc_gameref_t game, sc_command_t command, * Common handler to list out and clear all set watchpoints at a stroke. */ static void -debug_watchall_common (sc_gameref_t game, - sc_command_t command, sc_command_type_t type) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - assert (debug_is_valid (debug)); - - if (type != COMMAND_QUERY) - { - if (command == DEBUG_WATCHALL) - if_print_debug ("The Watchall command takes no arguments.\n"); - else - if_print_debug ("The Clearall command takes no arguments.\n"); - return; - } - - /* Query all set watchpoints using common watchpoint handler... */ - if (command == DEBUG_WATCHALL) - { - debug_watchpoint_common (game, - DEBUG_WATCHPLAYER, COMMAND_QUERY, 0, 0); - debug_watchpoint_common (game, - DEBUG_WATCHOBJECTS, COMMAND_QUERY, 0, 0); - debug_watchpoint_common (game, - DEBUG_WATCHNPCS, COMMAND_QUERY, 0, 0); - debug_watchpoint_common (game, - DEBUG_WATCHEVENTS, COMMAND_QUERY, 0, 0); - debug_watchpoint_common (game, - DEBUG_WATCHTASKS, COMMAND_QUERY, 0, 0); - debug_watchpoint_common (game, - DEBUG_WATCHVARIABLES, COMMAND_QUERY, 0, 0); - return; - } - - /* ...but reset all the fast way, with memset(). */ - assert (command == DEBUG_CLEARALL); - debug->watch_player = FALSE; - memset (debug->watch_objects, FALSE, - gs_object_count (game) * sizeof (*debug->watch_objects)); - memset (debug->watch_npcs, FALSE, - gs_npc_count (game) * sizeof (*debug->watch_npcs)); - memset (debug->watch_events, FALSE, - gs_event_count (game) * sizeof (*debug->watch_events)); - memset (debug->watch_tasks, FALSE, - gs_task_count (game) * sizeof (*debug->watch_tasks)); - memset (debug->watch_variables, FALSE, - debug_variable_count (game) * sizeof (*debug->watch_variables)); - if_print_debug ("Cleared all watchpoints.\n"); +debug_watchall_common(sc_gameref_t game, + sc_command_t command, sc_command_type_t type) { + const sc_debuggerref_t debug = debug_get_debugger(game); + assert(debug_is_valid(debug)); + + if (type != COMMAND_QUERY) { + if (command == DEBUG_WATCHALL) + if_print_debug("The Watchall command takes no arguments.\n"); + else + if_print_debug("The Clearall command takes no arguments.\n"); + return; + } + + /* Query all set watchpoints using common watchpoint handler... */ + if (command == DEBUG_WATCHALL) { + debug_watchpoint_common(game, + DEBUG_WATCHPLAYER, COMMAND_QUERY, 0, 0); + debug_watchpoint_common(game, + DEBUG_WATCHOBJECTS, COMMAND_QUERY, 0, 0); + debug_watchpoint_common(game, + DEBUG_WATCHNPCS, COMMAND_QUERY, 0, 0); + debug_watchpoint_common(game, + DEBUG_WATCHEVENTS, COMMAND_QUERY, 0, 0); + debug_watchpoint_common(game, + DEBUG_WATCHTASKS, COMMAND_QUERY, 0, 0); + debug_watchpoint_common(game, + DEBUG_WATCHVARIABLES, COMMAND_QUERY, 0, 0); + return; + } + + /* ...but reset all the fast way, with memset(). */ + assert(command == DEBUG_CLEARALL); + debug->watch_player = FALSE; + memset(debug->watch_objects, FALSE, + gs_object_count(game) * sizeof(*debug->watch_objects)); + memset(debug->watch_npcs, FALSE, + gs_npc_count(game) * sizeof(*debug->watch_npcs)); + memset(debug->watch_events, FALSE, + gs_event_count(game) * sizeof(*debug->watch_events)); + memset(debug->watch_tasks, FALSE, + gs_task_count(game) * sizeof(*debug->watch_tasks)); + memset(debug->watch_variables, FALSE, + debug_variable_count(game) * sizeof(*debug->watch_variables)); + if_print_debug("Cleared all watchpoints.\n"); } @@ -1975,18 +1855,17 @@ debug_watchall_common (sc_gameref_t game, * Compare two objects, and return TRUE if the same. */ static sc_bool -debug_compare_object (sc_gameref_t from, sc_gameref_t with, sc_int object) -{ - const sc_objectstate_t *from_object = from->objects + object; - const sc_objectstate_t *with_object = with->objects + object; - - return from_object->unmoved == with_object->unmoved - && from_object->static_unmoved == with_object->static_unmoved - && from_object->position == with_object->position - && from_object->parent == with_object->parent - && from_object->openness == with_object->openness - && from_object->state == with_object->state - && from_object->seen == with_object->seen; +debug_compare_object(sc_gameref_t from, sc_gameref_t with, sc_int object) { + const sc_objectstate_t *from_object = from->objects + object; + const sc_objectstate_t *with_object = with->objects + object; + + return from_object->unmoved == with_object->unmoved + && from_object->static_unmoved == with_object->static_unmoved + && from_object->position == with_object->position + && from_object->parent == with_object->parent + && from_object->openness == with_object->openness + && from_object->state == with_object->state + && from_object->seen == with_object->seen; } @@ -1996,21 +1875,20 @@ debug_compare_object (sc_gameref_t from, sc_gameref_t with, sc_int object) * Compare two NPCs, and return TRUE if the same. */ static sc_bool -debug_compare_npc (sc_gameref_t from, sc_gameref_t with, sc_int npc) -{ - const sc_npcstate_t *from_npc = from->npcs + npc; - const sc_npcstate_t *with_npc = with->npcs + npc; - - if (from_npc->walkstep_count != with_npc->walkstep_count) - sc_fatal ("debug_compare_npc: walkstep count error\n"); - - return from_npc->location == with_npc->location - && from_npc->position == with_npc->position - && from_npc->parent == with_npc->parent - && from_npc->seen == with_npc->seen - && memcmp (from_npc->walksteps, with_npc->walksteps, - from_npc->walkstep_count - * sizeof (*from_npc->walksteps)) == 0; +debug_compare_npc(sc_gameref_t from, sc_gameref_t with, sc_int npc) { + const sc_npcstate_t *from_npc = from->npcs + npc; + const sc_npcstate_t *with_npc = with->npcs + npc; + + if (from_npc->walkstep_count != with_npc->walkstep_count) + sc_fatal("debug_compare_npc: walkstep count error\n"); + + return from_npc->location == with_npc->location + && from_npc->position == with_npc->position + && from_npc->parent == with_npc->parent + && from_npc->seen == with_npc->seen + && memcmp(from_npc->walksteps, with_npc->walksteps, + from_npc->walkstep_count + * sizeof(*from_npc->walksteps)) == 0; } @@ -2020,13 +1898,12 @@ debug_compare_npc (sc_gameref_t from, sc_gameref_t with, sc_int npc) * Compare two events, and return TRUE if the same. */ static sc_bool -debug_compare_event (sc_gameref_t from, sc_gameref_t with, sc_int event) -{ - const sc_eventstate_t *from_event = from->events + event; - const sc_eventstate_t *with_event = with->events + event; +debug_compare_event(sc_gameref_t from, sc_gameref_t with, sc_int event) { + const sc_eventstate_t *from_event = from->events + event; + const sc_eventstate_t *with_event = with->events + event; - return from_event->state == with_event->state - && from_event->time == with_event->time; + return from_event->state == with_event->state + && from_event->time == with_event->time; } @@ -2036,13 +1913,12 @@ debug_compare_event (sc_gameref_t from, sc_gameref_t with, sc_int event) * Compare two tasks, and return TRUE if the same. */ static sc_bool -debug_compare_task (sc_gameref_t from, sc_gameref_t with, sc_int task) -{ - const sc_taskstate_t *from_task = from->tasks + task; - const sc_taskstate_t *with_task = with->tasks + task; +debug_compare_task(sc_gameref_t from, sc_gameref_t with, sc_int task) { + const sc_taskstate_t *from_task = from->tasks + task; + const sc_taskstate_t *with_task = with->tasks + task; - return from_task->done == with_task->done - && from_task->scored == with_task->scored; + return from_task->done == with_task->done + && from_task->scored == with_task->scored; } @@ -2052,44 +1928,42 @@ debug_compare_task (sc_gameref_t from, sc_gameref_t with, sc_int task) * Compare two variables, and return TRUE if the same. */ static sc_bool -debug_compare_variable (sc_gameref_t from, sc_gameref_t with, sc_int variable) -{ - const sc_prop_setref_t bundle = from->bundle; - const sc_var_setref_t from_var = from->vars; - const sc_var_setref_t with_var = with->vars; - sc_vartype_t vt_key[3], vt_rvalue, vt_rvalue2; - const sc_char *name; - sc_int var_type, var_type2; - sc_bool equal = FALSE; - - if (from->bundle != with->bundle) - sc_fatal ("debug_compare_variable: property sharing malfunction\n"); - - vt_key[0].string = "Variables"; - vt_key[1].integer = variable; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - if (!var_get (from_var, name, &var_type, &vt_rvalue) - || !var_get (with_var, name, &var_type2, &vt_rvalue2)) - sc_fatal ("debug_compare_variable: can't find variable %s\n", name); - else if (var_type != var_type2) - sc_fatal ("debug_compare_variable: variable type mismatch %s\n", name); - - switch (var_type) - { - case VAR_INTEGER: - equal = (vt_rvalue.integer == vt_rvalue2.integer); - break; - case VAR_STRING: - equal = !strcmp (vt_rvalue.string, vt_rvalue2.string); - break; - default: - sc_fatal ("debug_compare_variable:" - " invalid variable type, %ld\n", var_type); - } - - return equal; +debug_compare_variable(sc_gameref_t from, sc_gameref_t with, sc_int variable) { + const sc_prop_setref_t bundle = from->bundle; + const sc_var_setref_t from_var = from->vars; + const sc_var_setref_t with_var = with->vars; + sc_vartype_t vt_key[3], vt_rvalue, vt_rvalue2; + const sc_char *name; + sc_int var_type, var_type2; + sc_bool equal = FALSE; + + if (from->bundle != with->bundle) + sc_fatal("debug_compare_variable: property sharing malfunction\n"); + + vt_key[0].string = "Variables"; + vt_key[1].integer = variable; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + if (!var_get(from_var, name, &var_type, &vt_rvalue) + || !var_get(with_var, name, &var_type2, &vt_rvalue2)) + sc_fatal("debug_compare_variable: can't find variable %s\n", name); + else if (var_type != var_type2) + sc_fatal("debug_compare_variable: variable type mismatch %s\n", name); + + switch (var_type) { + case VAR_INTEGER: + equal = (vt_rvalue.integer == vt_rvalue2.integer); + break; + case VAR_STRING: + equal = !strcmp(vt_rvalue.string, vt_rvalue2.string); + break; + default: + sc_fatal("debug_compare_variable:" + " invalid variable type, %ld\n", var_type); + } + + return equal; } @@ -2102,44 +1976,40 @@ debug_compare_variable (sc_gameref_t from, sc_gameref_t with, sc_int variable) * if any differed. */ static sc_bool -debug_check_class (sc_gameref_t from, sc_gameref_t with, - const sc_char *class_, sc_int class_count, - const sc_bool *watchpoints, - sc_bool (*const compare_function) - (sc_gameref_t, sc_gameref_t, sc_int)) -{ - sc_int index_; - sc_bool triggered = FALSE; - - /* - * Scan the watchpoints array for set watchpoints, comparing classes - * where the watchpoint flag is set. - */ - for (index_ = 0; index_ < class_count; index_++) - { - if (!watchpoints[index_]) - continue; - - if (!compare_function (from, with, index_)) - { - sc_char buffer[32]; - - if (!triggered) - { - if_print_debug ("--- "); - if_print_debug (class_); - if_print_debug (" watchpoint triggered { "); - } - sprintf (buffer, "%ld ", index_); - if_print_debug (buffer); - triggered = TRUE; - } - } - if (triggered) - if_print_debug ("}.\n"); - - /* Return TRUE if anything differed. */ - return triggered; +debug_check_class(sc_gameref_t from, sc_gameref_t with, + const sc_char *class_, sc_int class_count, + const sc_bool *watchpoints, + sc_bool(*const compare_function) + (sc_gameref_t, sc_gameref_t, sc_int)) { + sc_int index_; + sc_bool triggered = FALSE; + + /* + * Scan the watchpoints array for set watchpoints, comparing classes + * where the watchpoint flag is set. + */ + for (index_ = 0; index_ < class_count; index_++) { + if (!watchpoints[index_]) + continue; + + if (!compare_function(from, with, index_)) { + sc_char buffer[32]; + + if (!triggered) { + if_print_debug("--- "); + if_print_debug(class_); + if_print_debug(" watchpoint triggered { "); + } + sprintf(buffer, "%ld ", index_); + if_print_debug(buffer); + triggered = TRUE; + } + } + if (triggered) + if_print_debug("}.\n"); + + /* Return TRUE if anything differed. */ + return triggered; } @@ -2151,49 +2021,46 @@ debug_check_class (sc_gameref_t from, sc_gameref_t with, * in which case no check is possible). */ static sc_bool -debug_check_watchpoints (sc_gameref_t game) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - const sc_gameref_t undo = game->undo; - sc_bool triggered; - assert (debug_is_valid (debug) && gs_is_game_valid (undo)); - - /* If no undo is present, no check is possible. */ - if (!game->undo_available) - return FALSE; - - /* Check first for player watchpoint. */ - triggered = FALSE; - if (debug->watch_player) - { - if (gs_playerroom (game) != gs_playerroom (undo) - || gs_playerposition (game) != gs_playerposition (undo) - || gs_playerparent (game) != gs_playerparent (undo)) - { - if_print_debug ("--- Player watchpoint triggered.\n"); - triggered |= TRUE; - } - } - - /* Now check other classes of watchpoint. */ - triggered |= debug_check_class (game, undo, - "Object", gs_object_count (game), - debug->watch_objects, debug_compare_object); - triggered |= debug_check_class (game, undo, - "NPC", gs_npc_count (game), - debug->watch_npcs, debug_compare_npc); - triggered |= debug_check_class (game, undo, - "Event", gs_event_count (game), - debug->watch_events, debug_compare_event); - triggered |= debug_check_class (game, undo, - "Task", gs_task_count (game), - debug->watch_tasks, debug_compare_task); - triggered |= debug_check_class (game, undo, - "Variable", debug_variable_count (game), - debug->watch_variables, - debug_compare_variable); - - return triggered; +debug_check_watchpoints(sc_gameref_t game) { + const sc_debuggerref_t debug = debug_get_debugger(game); + const sc_gameref_t undo = game->undo; + sc_bool triggered; + assert(debug_is_valid(debug) && gs_is_game_valid(undo)); + + /* If no undo is present, no check is possible. */ + if (!game->undo_available) + return FALSE; + + /* Check first for player watchpoint. */ + triggered = FALSE; + if (debug->watch_player) { + if (gs_playerroom(game) != gs_playerroom(undo) + || gs_playerposition(game) != gs_playerposition(undo) + || gs_playerparent(game) != gs_playerparent(undo)) { + if_print_debug("--- Player watchpoint triggered.\n"); + triggered |= TRUE; + } + } + + /* Now check other classes of watchpoint. */ + triggered |= debug_check_class(game, undo, + "Object", gs_object_count(game), + debug->watch_objects, debug_compare_object); + triggered |= debug_check_class(game, undo, + "NPC", gs_npc_count(game), + debug->watch_npcs, debug_compare_npc); + triggered |= debug_check_class(game, undo, + "Event", gs_event_count(game), + debug->watch_events, debug_compare_event); + triggered |= debug_check_class(game, undo, + "Task", gs_task_count(game), + debug->watch_tasks, debug_compare_task); + triggered |= debug_check_class(game, undo, + "Variable", debug_variable_count(game), + debug->watch_variables, + debug_compare_variable); + + return triggered; } @@ -2205,123 +2072,112 @@ debug_check_watchpoints (sc_gameref_t game) * fails. */ static sc_command_t -debug_parse_command (const sc_char *command_string, - sc_command_type_t *type, - sc_int *arg1, sc_int *arg2, sc_command_t *help_topic) -{ - sc_command_t return_command; - sc_command_type_t return_type; - sc_int val1, val2, converted, matches; - sc_char *help, *string, junk, wildcard; - sc_bool is_help, is_parsed, is_wildcard; - const sc_strings_t *entry; - - /* Allocate temporary strings long enough to take a copy of the input. */ - string = (sc_char *)sc_malloc (strlen (command_string) + 1); - help = (sc_char *)sc_malloc (strlen (command_string) + 1); - - /* - * Parse the input line, in a very simplistic fashion. The argument count - * is one less than sscanf converts. - */ - is_parsed = is_wildcard = is_help = FALSE; - val1 = val2 = 0; - converted = sscanf (command_string, " %s %s %c", help, string, &junk); - if (converted == 2 && sc_strcasecmp (help, "help") == 0) - { - is_help = TRUE; - is_parsed = TRUE; - } - sc_free (help); - if (!is_parsed) - { - converted = sscanf (command_string, - " %s %ld to %ld %c", string, &val1, &val2, &junk); - if (converted != 3) - converted = sscanf (command_string, - " %s %ld - %ld %c", string, &val1, &val2, &junk); - if (converted != 3) - converted = sscanf (command_string, - " %s %ld .. %ld %c", string, &val1, &val2, &junk); - if (converted != 3) - converted = sscanf (command_string, - " %s %ld %ld %c", string, &val1, &val2, &junk); - is_parsed |= converted == 3; - } - if (!is_parsed) - { - converted = sscanf (command_string, - " %s %ld %c", string, &val1, &junk); - is_parsed |= converted == 2; - } - if (!is_parsed) - { - converted = sscanf (command_string, - " %s %c %c", string, &wildcard, &junk); - if (converted == 2 && wildcard == '*') - { - is_wildcard = TRUE; - is_parsed = TRUE; - } - else - is_parsed |= converted == 1; - } - if (!is_parsed) - { - if_print_debug ("Invalid debug command."); - if_print_debug (" Type 'help' for a list of valid commands.\n"); - sc_free (string); - return DEBUG_NONE; - } - - /* Decide on a command type based on the parse. */ - if (is_wildcard) - return_type = COMMAND_ALL; - else if (converted == 3) - return_type = COMMAND_RANGE; - else if (converted == 2) - return_type = COMMAND_ONE; - else - return_type = COMMAND_QUERY; - - /* - * Find the first unambiguous command matching the string. If none, - * return DEBUG_NONE. - */ - matches = 0; - return_command = DEBUG_NONE; - for (entry = DEBUG_COMMANDS; entry->command_string; entry++) - { - if (sc_strncasecmp (string, entry->command_string, strlen (string)) == 0) - { - matches++; - return_command = entry->command; - } - } - if (matches != 1) - { - if (matches > 1) - if_print_debug ("Ambiguous debug command."); - else - if_print_debug ("Unrecognized debug command."); - if_print_debug (" Type 'help' for a list of valid commands.\n"); - sc_free (string); - return DEBUG_NONE; - } - - /* Done with temporary command parse area. */ - sc_free (string); - - /* - * Return the command type, arguments, and the debugging command. For help - * , the command is help, with the command on which help requested - * in *help_topic. All clear, then? - */ - *type = return_type; - *arg1 = val1; - *arg2 = val2; - *help_topic = is_help ? return_command : DEBUG_NONE; - return is_help ? DEBUG_HELP : return_command; +debug_parse_command(const sc_char *command_string, + sc_command_type_t *type, + sc_int *arg1, sc_int *arg2, sc_command_t *help_topic) { + sc_command_t return_command; + sc_command_type_t return_type; + sc_int val1, val2, converted, matches; + sc_char *help, *string, junk, wildcard; + sc_bool is_help, is_parsed, is_wildcard; + const sc_strings_t *entry; + + /* Allocate temporary strings long enough to take a copy of the input. */ + string = (sc_char *)sc_malloc(strlen(command_string) + 1); + help = (sc_char *)sc_malloc(strlen(command_string) + 1); + + /* + * Parse the input line, in a very simplistic fashion. The argument count + * is one less than sscanf converts. + */ + is_parsed = is_wildcard = is_help = FALSE; + val1 = val2 = 0; + converted = sscanf(command_string, " %s %s %c", help, string, &junk); + if (converted == 2 && sc_strcasecmp(help, "help") == 0) { + is_help = TRUE; + is_parsed = TRUE; + } + sc_free(help); + if (!is_parsed) { + converted = sscanf(command_string, + " %s %ld to %ld %c", string, &val1, &val2, &junk); + if (converted != 3) + converted = sscanf(command_string, + " %s %ld - %ld %c", string, &val1, &val2, &junk); + if (converted != 3) + converted = sscanf(command_string, + " %s %ld .. %ld %c", string, &val1, &val2, &junk); + if (converted != 3) + converted = sscanf(command_string, + " %s %ld %ld %c", string, &val1, &val2, &junk); + is_parsed |= converted == 3; + } + if (!is_parsed) { + converted = sscanf(command_string, + " %s %ld %c", string, &val1, &junk); + is_parsed |= converted == 2; + } + if (!is_parsed) { + converted = sscanf(command_string, + " %s %c %c", string, &wildcard, &junk); + if (converted == 2 && wildcard == '*') { + is_wildcard = TRUE; + is_parsed = TRUE; + } else + is_parsed |= converted == 1; + } + if (!is_parsed) { + if_print_debug("Invalid debug command."); + if_print_debug(" Type 'help' for a list of valid commands.\n"); + sc_free(string); + return DEBUG_NONE; + } + + /* Decide on a command type based on the parse. */ + if (is_wildcard) + return_type = COMMAND_ALL; + else if (converted == 3) + return_type = COMMAND_RANGE; + else if (converted == 2) + return_type = COMMAND_ONE; + else + return_type = COMMAND_QUERY; + + /* + * Find the first unambiguous command matching the string. If none, + * return DEBUG_NONE. + */ + matches = 0; + return_command = DEBUG_NONE; + for (entry = DEBUG_COMMANDS; entry->command_string; entry++) { + if (sc_strncasecmp(string, entry->command_string, strlen(string)) == 0) { + matches++; + return_command = entry->command; + } + } + if (matches != 1) { + if (matches > 1) + if_print_debug("Ambiguous debug command."); + else + if_print_debug("Unrecognized debug command."); + if_print_debug(" Type 'help' for a list of valid commands.\n"); + sc_free(string); + return DEBUG_NONE; + } + + /* Done with temporary command parse area. */ + sc_free(string); + + /* + * Return the command type, arguments, and the debugging command. For help + * , the command is help, with the command on which help requested + * in *help_topic. All clear, then? + */ + *type = return_type; + *arg1 = val1; + *arg2 = val2; + *help_topic = is_help ? return_command : DEBUG_NONE; + return is_help ? DEBUG_HELP : return_command; } @@ -2331,69 +2187,67 @@ debug_parse_command (const sc_char *command_string, * Dispatch a debugging command to the appropriate handler. */ static void -debug_dispatch (sc_gameref_t game, - sc_command_t command, sc_command_type_t type, - sc_int arg1, sc_int arg2, sc_command_t help_topic) -{ - /* Demultiplex debugging command, and call handlers. */ - switch (command) - { - case DEBUG_HELP: - debug_help (help_topic); - break; - case DEBUG_BUFFER: - debug_buffer (game, type); - break; - case DEBUG_RESOURCES: - debug_resources (game, type); - break; - case DEBUG_RANDOM: - debug_random (type, arg1); - break; - case DEBUG_GAME: - debug_game (game, type); - break; - case DEBUG_PLAYER: - case DEBUG_OLDPLAYER: - debug_player (game, command, type); - break; - case DEBUG_ROOMS: - case DEBUG_OBJECTS: - case DEBUG_NPCS: - case DEBUG_EVENTS: - case DEBUG_TASKS: - case DEBUG_VARIABLES: - case DEBUG_OLDROOMS: - case DEBUG_OLDOBJECTS: - case DEBUG_OLDNPCS: - case DEBUG_OLDEVENTS: - case DEBUG_OLDTASKS: - case DEBUG_OLDVARIABLES: - debug_dump_common (game, command, type, arg1, arg2); - break; - case DEBUG_WATCHPLAYER: - case DEBUG_WATCHOBJECTS: - case DEBUG_WATCHNPCS: - case DEBUG_WATCHEVENTS: - case DEBUG_WATCHTASKS: - case DEBUG_WATCHVARIABLES: - case DEBUG_CLEARPLAYER: - case DEBUG_CLEAROBJECTS: - case DEBUG_CLEARNPCS: - case DEBUG_CLEAREVENTS: - case DEBUG_CLEARTASKS: - case DEBUG_CLEARVARIABLES: - debug_watchpoint_common (game, command, type, arg1, arg2); - break; - case DEBUG_WATCHALL: - case DEBUG_CLEARALL: - debug_watchall_common (game, command, type); - break; - case DEBUG_NONE: - break; - default: - sc_fatal ("debug_dispatch: invalid debug command\n"); - } +debug_dispatch(sc_gameref_t game, + sc_command_t command, sc_command_type_t type, + sc_int arg1, sc_int arg2, sc_command_t help_topic) { + /* Demultiplex debugging command, and call handlers. */ + switch (command) { + case DEBUG_HELP: + debug_help(help_topic); + break; + case DEBUG_BUFFER: + debug_buffer(game, type); + break; + case DEBUG_RESOURCES: + debug_resources(game, type); + break; + case DEBUG_RANDOM: + debug_random(type, arg1); + break; + case DEBUG_GAME: + debug_game(game, type); + break; + case DEBUG_PLAYER: + case DEBUG_OLDPLAYER: + debug_player(game, command, type); + break; + case DEBUG_ROOMS: + case DEBUG_OBJECTS: + case DEBUG_NPCS: + case DEBUG_EVENTS: + case DEBUG_TASKS: + case DEBUG_VARIABLES: + case DEBUG_OLDROOMS: + case DEBUG_OLDOBJECTS: + case DEBUG_OLDNPCS: + case DEBUG_OLDEVENTS: + case DEBUG_OLDTASKS: + case DEBUG_OLDVARIABLES: + debug_dump_common(game, command, type, arg1, arg2); + break; + case DEBUG_WATCHPLAYER: + case DEBUG_WATCHOBJECTS: + case DEBUG_WATCHNPCS: + case DEBUG_WATCHEVENTS: + case DEBUG_WATCHTASKS: + case DEBUG_WATCHVARIABLES: + case DEBUG_CLEARPLAYER: + case DEBUG_CLEAROBJECTS: + case DEBUG_CLEARNPCS: + case DEBUG_CLEAREVENTS: + case DEBUG_CLEARTASKS: + case DEBUG_CLEARVARIABLES: + debug_watchpoint_common(game, command, type, arg1, arg2); + break; + case DEBUG_WATCHALL: + case DEBUG_CLEARALL: + debug_watchall_common(game, command, type); + break; + case DEBUG_NONE: + break; + default: + sc_fatal("debug_dispatch: invalid debug command\n"); + } } @@ -2403,91 +2257,82 @@ debug_dispatch (sc_gameref_t game, * Create a small debugging dialog with the user. */ static void -debug_dialog (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_debuggerref_t debug = debug_get_debugger (game); - const sc_var_setref_t vars = gs_get_vars (game); - assert (debug_is_valid (debug)); - - /* - * Note elapsed seconds, so time stands still while debugging, and clear - * any pending game quit left over from prior dialogs (just in case). - */ - debug->elapsed_seconds = var_get_elapsed_seconds (vars); - debug->quit_pending = FALSE; - - /* Handle debug commands until debugger quit or game quit. */ - while (TRUE) - { - sc_char buffer[DEBUG_BUFFER_SIZE]; - sc_command_t command, help_topic; - sc_command_type_t type; - sc_int arg1, arg2; - - /* Get a debugging command string from the user. */ - do - { - if_read_debug (buffer, sizeof (buffer)); - - if (g_vm->shouldQuit()) - return; - } - while (sc_strempty (buffer)); - - /* Parse the command read, and handle dialog exit commands. */ - command = debug_parse_command (buffer, - &type, &arg1, &arg2, &help_topic); - if (command == DEBUG_CONTINUE || command == DEBUG_STEP) - { - if (!game->is_running) - { - if_print_debug ("The game is no longer running.\n"); - continue; - } - - debug->single_step = (command == DEBUG_STEP); - break; - } - else if (command == DEBUG_QUIT) - { - /* - * If the game is not running, we can't halt it, and we don't need - * to confirm the quit (either the player "quit" or the game - * completed), so leave the dialog loop. - */ - if (!game->is_running) - break; - - /* - * The game is still running, so confirm quit by requiring a repeat, - * or if this is the confirmation, force the game to a halt. - */ - if (!debug->quit_pending) - { - if_print_debug ("Use 'quit' again to confirm, or another" - " debugger command to cancel.\n"); - debug->quit_pending = TRUE; - continue; - } - - /* Drop printfilter contents and quit the game. */ - pf_empty (filter); - run_quit (game); - - /* Just in case... */ - if_print_debug ("Unable to quit from the game. Sorry.\n"); - continue; - } - - /* Dispatch the remaining debugging commands, and clear quit flag. */ - debug_dispatch (game, command, type, arg1, arg2, help_topic); - debug->quit_pending = FALSE; - } - - /* Restart time, and clear any pending game quit. */ - var_set_elapsed_seconds (vars, debug->elapsed_seconds); - debug->quit_pending = FALSE; +debug_dialog(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_debuggerref_t debug = debug_get_debugger(game); + const sc_var_setref_t vars = gs_get_vars(game); + assert(debug_is_valid(debug)); + + /* + * Note elapsed seconds, so time stands still while debugging, and clear + * any pending game quit left over from prior dialogs (just in case). + */ + debug->elapsed_seconds = var_get_elapsed_seconds(vars); + debug->quit_pending = FALSE; + + /* Handle debug commands until debugger quit or game quit. */ + while (TRUE) { + sc_char buffer[DEBUG_BUFFER_SIZE]; + sc_command_t command, help_topic; + sc_command_type_t type; + sc_int arg1, arg2; + + /* Get a debugging command string from the user. */ + do { + if_read_debug(buffer, sizeof(buffer)); + + if (g_vm->shouldQuit()) + return; + } while (sc_strempty(buffer)); + + /* Parse the command read, and handle dialog exit commands. */ + command = debug_parse_command(buffer, + &type, &arg1, &arg2, &help_topic); + if (command == DEBUG_CONTINUE || command == DEBUG_STEP) { + if (!game->is_running) { + if_print_debug("The game is no longer running.\n"); + continue; + } + + debug->single_step = (command == DEBUG_STEP); + break; + } else if (command == DEBUG_QUIT) { + /* + * If the game is not running, we can't halt it, and we don't need + * to confirm the quit (either the player "quit" or the game + * completed), so leave the dialog loop. + */ + if (!game->is_running) + break; + + /* + * The game is still running, so confirm quit by requiring a repeat, + * or if this is the confirmation, force the game to a halt. + */ + if (!debug->quit_pending) { + if_print_debug("Use 'quit' again to confirm, or another" + " debugger command to cancel.\n"); + debug->quit_pending = TRUE; + continue; + } + + /* Drop printfilter contents and quit the game. */ + pf_empty(filter); + run_quit(game); + + /* Just in case... */ + if_print_debug("Unable to quit from the game. Sorry.\n"); + continue; + } + + /* Dispatch the remaining debugging commands, and clear quit flag. */ + debug_dispatch(game, command, type, arg1, arg2, help_topic); + debug->quit_pending = FALSE; + } + + /* Restart time, and clear any pending game quit. */ + var_set_elapsed_seconds(vars, debug->elapsed_seconds); + debug->quit_pending = FALSE; } @@ -2498,34 +2343,32 @@ debug_dialog (sc_gameref_t game) * TRUE if valid, FALSE if invalid (parse failed, not understood). */ sc_bool -debug_run_command (sc_gameref_t game, const sc_char *debug_command) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - sc_command_t command, help_topic; - sc_command_type_t type; - sc_int arg1, arg2; - - /* If debugging disallowed (not initialized), refuse the call. */ - if (debug) - { - /* - * Parse the command string passed in, and return FALSE if the parse - * fails, or if it returns DEBUG_CONTINUE, DEBUG_STEP, or DEBUG_QUIT, - * none of which make any sense in this context. - */ - command = debug_parse_command (debug_command, - &type, &arg1, &arg2, &help_topic); - if (command == DEBUG_NONE - || command == DEBUG_CONTINUE || command == DEBUG_STEP - || command == DEBUG_QUIT) - return FALSE; - - /* Dispatch the remaining debugging commands, return successfully. */ - debug_dispatch (game, command, type, arg1, arg2, help_topic); - return TRUE; - } - - return FALSE; +debug_run_command(sc_gameref_t game, const sc_char *debug_command) { + const sc_debuggerref_t debug = debug_get_debugger(game); + sc_command_t command, help_topic; + sc_command_type_t type; + sc_int arg1, arg2; + + /* If debugging disallowed (not initialized), refuse the call. */ + if (debug) { + /* + * Parse the command string passed in, and return FALSE if the parse + * fails, or if it returns DEBUG_CONTINUE, DEBUG_STEP, or DEBUG_QUIT, + * none of which make any sense in this context. + */ + command = debug_parse_command(debug_command, + &type, &arg1, &arg2, &help_topic); + if (command == DEBUG_NONE + || command == DEBUG_CONTINUE || command == DEBUG_STEP + || command == DEBUG_QUIT) + return FALSE; + + /* Dispatch the remaining debugging commands, return successfully. */ + debug_dispatch(game, command, type, arg1, arg2, help_topic); + return TRUE; + } + + return FALSE; } @@ -2537,22 +2380,21 @@ debug_run_command (sc_gameref_t game, const sc_char *debug_command) * dialog. Uses if_print_string() as this isn't debug output. */ sc_bool -debug_cmd_debugger (sc_gameref_t game) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - - /* If debugging disallowed (not initialized), ignore the call. */ - if (debug) - debug_dialog (game); - else - if_print_string ("SCARE's game debugger is not enabled. Sorry.\n"); - - /* - * Set as administrative command, so as not to consume a game turn, and - * return successfully. - */ - game->is_admin = TRUE; - return TRUE; +debug_cmd_debugger(sc_gameref_t game) { + const sc_debuggerref_t debug = debug_get_debugger(game); + + /* If debugging disallowed (not initialized), ignore the call. */ + if (debug) + debug_dialog(game); + else + if_print_string("SCARE's game debugger is not enabled. Sorry.\n"); + + /* + * Set as administrative command, so as not to consume a game turn, and + * return successfully. + */ + game->is_admin = TRUE; + return TRUE; } @@ -2569,79 +2411,67 @@ debug_cmd_debugger (sc_gameref_t game) * watchpoints and offer the debug dialog one last time. */ void -debug_game_started (sc_gameref_t game) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - - /* If debugging disallowed (not initialized), ignore the call. */ - if (debug) - { - /* Starting a new game, or a restore or undo of an old one? */ - if (!gs_room_seen (game, gs_playerroom (game))) - { - /* - * It's a new game starting or restarting. Print a banner, and - * run the debugger dialog. - */ - if_print_debug ("\n--- SCARE " SCARE_VERSION SCARE_PATCH_LEVEL - " Game Debugger\n" - "--- Type 'help' for a list of commands.\n"); - debug_dialog (game); - } - else - { - /* - * It's a restore or undo through memos, so run the dialog only if - * single-stepping; no need to check watchpoints for this case as - * none can be set -- no undo. - */ - if (debug->single_step) - debug_dialog (game); - } - } +debug_game_started(sc_gameref_t game) { + const sc_debuggerref_t debug = debug_get_debugger(game); + + /* If debugging disallowed (not initialized), ignore the call. */ + if (debug) { + /* Starting a new game, or a restore or undo of an old one? */ + if (!gs_room_seen(game, gs_playerroom(game))) { + /* + * It's a new game starting or restarting. Print a banner, and + * run the debugger dialog. + */ + if_print_debug("\n--- SCARE " SCARE_VERSION SCARE_PATCH_LEVEL + " Game Debugger\n" + "--- Type 'help' for a list of commands.\n"); + debug_dialog(game); + } else { + /* + * It's a restore or undo through memos, so run the dialog only if + * single-stepping; no need to check watchpoints for this case as + * none can be set -- no undo. + */ + if (debug->single_step) + debug_dialog(game); + } + } } void -debug_game_ended (sc_gameref_t game) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - - /* If debugging disallowed (not initialized), ignore the call. */ - if (debug) - { - /* - * Using our carnal knowledge of the run main loop, we know here that - * if the loop exited with do_restart or do_restore, we'll get a call to - * debug_game_start() when the loop restarts. So in this case, ignore - * the call (even if single stepping). - */ - if (game->do_restart || game->do_restore) - return; - - /* - * Check for any final watchpoints, and print a message describing why - * we're here. Suppress the check for watchpoints if the user exited - * the game, as it'll only be a repeat of any found last turn update. - */ - if (!game->is_running) - { - if (game->has_completed) - { - debug_check_watchpoints (game); - if_print_debug ("\n--- The game has completed.\n"); - } - else - if_print_debug ("\n--- The game has exited.\n"); - } - else - { - debug_check_watchpoints (game); - if_print_debug ("\n--- The game is still running!\n"); - } - - /* Run a final dialog. */ - debug_dialog (game); - } +debug_game_ended(sc_gameref_t game) { + const sc_debuggerref_t debug = debug_get_debugger(game); + + /* If debugging disallowed (not initialized), ignore the call. */ + if (debug) { + /* + * Using our carnal knowledge of the run main loop, we know here that + * if the loop exited with do_restart or do_restore, we'll get a call to + * debug_game_start() when the loop restarts. So in this case, ignore + * the call (even if single stepping). + */ + if (game->do_restart || game->do_restore) + return; + + /* + * Check for any final watchpoints, and print a message describing why + * we're here. Suppress the check for watchpoints if the user exited + * the game, as it'll only be a repeat of any found last turn update. + */ + if (!game->is_running) { + if (game->has_completed) { + debug_check_watchpoints(game); + if_print_debug("\n--- The game has completed.\n"); + } else + if_print_debug("\n--- The game has exited.\n"); + } else { + debug_check_watchpoints(game); + if_print_debug("\n--- The game is still running!\n"); + } + + /* Run a final dialog. */ + debug_dialog(game); + } } @@ -2652,29 +2482,27 @@ debug_game_ended (sc_gameref_t game) * watchpoints, and triggers a debug dialog when any fire. */ void -debug_turn_update (sc_gameref_t game) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - - /* If debugging disallowed (not initialized), ignore the call. */ - if (debug) - { - /* - * Again using carnal knowledge of the run main loop, if we're in - * mid-wait, ignore the call. Also, ignore the call if the game is - * no longer running, as we'll see a debug_game_ended() call come - * along to handle that. - */ - if (game->waitcounter > 0 || !game->is_running) - return; - - /* - * Run debugger dialog if any watchpoints triggered, or if single - * stepping (even if none triggered). - */ - if (debug_check_watchpoints (game) || debug->single_step) - debug_dialog (game); - } +debug_turn_update(sc_gameref_t game) { + const sc_debuggerref_t debug = debug_get_debugger(game); + + /* If debugging disallowed (not initialized), ignore the call. */ + if (debug) { + /* + * Again using carnal knowledge of the run main loop, if we're in + * mid-wait, ignore the call. Also, ignore the call if the game is + * no longer running, as we'll see a debug_game_ended() call come + * along to handle that. + */ + if (game->waitcounter > 0 || !game->is_running) + return; + + /* + * Run debugger dialog if any watchpoints triggered, or if single + * stepping (even if none triggered). + */ + if (debug_check_watchpoints(game) || debug->single_step) + debug_dialog(game); + } } @@ -2690,30 +2518,27 @@ debug_turn_update (sc_gameref_t game) * disabling. */ void -debug_set_enabled (sc_gameref_t game, sc_bool enable) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); - - /* - * If enabling and not already enabled, or disabling and not already - * disabled, either initialize or finalize.. - */ - if ((enable && !debug) || (!enable && debug)) - { - /* Initialize or finalize debugging, as appropriate. */ - if (enable) - debug_initialize (game); - else - debug_finalize (game); - } +debug_set_enabled(sc_gameref_t game, sc_bool enable) { + const sc_debuggerref_t debug = debug_get_debugger(game); + + /* + * If enabling and not already enabled, or disabling and not already + * disabled, either initialize or finalize.. + */ + if ((enable && !debug) || (!enable && debug)) { + /* Initialize or finalize debugging, as appropriate. */ + if (enable) + debug_initialize(game); + else + debug_finalize(game); + } } sc_bool -debug_get_enabled (sc_gameref_t game) -{ - const sc_debuggerref_t debug = debug_get_debugger (game); +debug_get_enabled(sc_gameref_t game) { + const sc_debuggerref_t debug = debug_get_debugger(game); - return debug != NULL; + return debug != NULL; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scevents.cpp b/engines/glk/adrift/scevents.cpp index 18d95b19ec..0048cd6dd9 100644 --- a/engines/glk/adrift/scevents.cpp +++ b/engines/glk/adrift/scevents.cpp @@ -43,19 +43,17 @@ static sc_bool evt_trace = FALSE; * Return TRUE if any task at all matches the given completion state. */ static sc_bool -evt_any_task_in_state (sc_gameref_t game, sc_bool state) -{ - sc_int task; - - /* Scan tasks for any whose completion matches input. */ - for (task = 0; task < gs_task_count (game); task++) - { - if (gs_task_done (game, task) == state) - return TRUE; - } - - /* No tasks matched. */ - return FALSE; +evt_any_task_in_state(sc_gameref_t game, sc_bool state) { + sc_int task; + + /* Scan tasks for any whose completion matches input. */ + for (task = 0; task < gs_task_count(game); task++) { + if (gs_task_done(game, task) == state) + return TRUE; + } + + /* No tasks matched. */ + return FALSE; } @@ -65,39 +63,37 @@ evt_any_task_in_state (sc_gameref_t game, sc_bool state) * Return TRUE if player is in the right room for event text. */ sc_bool -evt_can_see_event (sc_gameref_t game, sc_int event) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int type; - - /* Check room list for the event and return it. */ - vt_key[0].string = "Events"; - vt_key[1].integer = event; - vt_key[2].string = "Where"; - vt_key[3].string = "Type"; - type = prop_get_integer (bundle, "I<-siss", vt_key); - switch (type) - { - case ROOMLIST_NO_ROOMS: - return FALSE; - case ROOMLIST_ALL_ROOMS: - return TRUE; - - case ROOMLIST_ONE_ROOM: - vt_key[3].string = "Room"; - return prop_get_integer (bundle, "I<-siss", vt_key) - == gs_playerroom (game); - - case ROOMLIST_SOME_ROOMS: - vt_key[3].string = "Rooms"; - vt_key[4].integer = gs_playerroom (game); - return prop_get_boolean (bundle, "B<-sissi", vt_key); - - default: - sc_fatal ("evt_can_see_event: invalid type, %ld\n", type); - return FALSE; - } +evt_can_see_event(sc_gameref_t game, sc_int event) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int type; + + /* Check room list for the event and return it. */ + vt_key[0].string = "Events"; + vt_key[1].integer = event; + vt_key[2].string = "Where"; + vt_key[3].string = "Type"; + type = prop_get_integer(bundle, "I<-siss", vt_key); + switch (type) { + case ROOMLIST_NO_ROOMS: + return FALSE; + case ROOMLIST_ALL_ROOMS: + return TRUE; + + case ROOMLIST_ONE_ROOM: + vt_key[3].string = "Room"; + return prop_get_integer(bundle, "I<-siss", vt_key) + == gs_playerroom(game); + + case ROOMLIST_SOME_ROOMS: + vt_key[3].string = "Rooms"; + vt_key[4].integer = gs_playerroom(game); + return prop_get_boolean(bundle, "B<-sissi", vt_key); + + default: + sc_fatal("evt_can_see_event: invalid type, %ld\n", type); + return FALSE; + } } @@ -107,55 +103,50 @@ evt_can_see_event (sc_gameref_t game, sc_int event) * Move an object from within an event. */ static void -evt_move_object (sc_gameref_t game, sc_int object, sc_int destination) -{ - /* Ignore negative values of object. */ - if (object >= 0) - { - if (evt_trace) - { - sc_trace ("Event: moving object %ld to room %ld\n", - object, destination); - } - - /* Move object depending on destination. */ - switch (destination) - { - case -1: /* Hidden. */ - gs_object_make_hidden (game, object); - break; - - case 0: /* Held by player. */ - gs_object_player_get (game, object); - break; - - case 1: /* Same room as player. */ - gs_object_to_room (game, object, gs_playerroom (game)); - break; - - default: - if (destination < gs_room_count (game) + 2) - gs_object_to_room (game, object, destination - 2); - else - { - sc_int roomgroup, room; - - roomgroup = destination - gs_room_count (game) - 2; - room = lib_random_roomgroup_member (game, roomgroup); - gs_object_to_room (game, object, room); - } - break; - } - - /* - * If static, mark as no longer unmoved. - * - * TODO Is this the only place static objects can be moved? And just - * how static is a static object if it's moveable, anyway? - */ - if (obj_is_static (game, object)) - gs_set_object_static_unmoved (game, object, FALSE); - } +evt_move_object(sc_gameref_t game, sc_int object, sc_int destination) { + /* Ignore negative values of object. */ + if (object >= 0) { + if (evt_trace) { + sc_trace("Event: moving object %ld to room %ld\n", + object, destination); + } + + /* Move object depending on destination. */ + switch (destination) { + case -1: /* Hidden. */ + gs_object_make_hidden(game, object); + break; + + case 0: /* Held by player. */ + gs_object_player_get(game, object); + break; + + case 1: /* Same room as player. */ + gs_object_to_room(game, object, gs_playerroom(game)); + break; + + default: + if (destination < gs_room_count(game) + 2) + gs_object_to_room(game, object, destination - 2); + else { + sc_int roomgroup, room; + + roomgroup = destination - gs_room_count(game) - 2; + room = lib_random_roomgroup_member(game, roomgroup); + gs_object_to_room(game, object, room); + } + break; + } + + /* + * If static, mark as no longer unmoved. + * + * TODO Is this the only place static objects can be moved? And just + * how static is a static object if it's moveable, anyway? + */ + if (obj_is_static(game, object)) + gs_set_object_static_unmoved(game, object, FALSE); + } } @@ -168,36 +159,34 @@ evt_move_object (sc_gameref_t game, sc_int object, sc_int destination) * can do the same thing here, though it's ugly. */ static sc_bool -evt_fixup_v390_v380_immediate_restart (sc_gameref_t game, sc_int event) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int version; - - vt_key[0].string = "Version"; - version = prop_get_integer (bundle, "I<-s", vt_key); - if (version < TAF_VERSION_400) - { - sc_int time1, time2; - - if (evt_trace) - sc_trace ("Event: applying 3.9/3.8 restart fixup\n"); - - /* Set to running state. */ - gs_set_event_state (game, event, ES_RUNNING); - - /* Set up event time to be one less than a proper start. */ - vt_key[0].string = "Events"; - vt_key[1].integer = event; - vt_key[2].string = "Time1"; - time1 = prop_get_integer (bundle, "I<-sis", vt_key); - vt_key[2].string = "Time2"; - time2 = prop_get_integer (bundle, "I<-sis", vt_key); - gs_set_event_time (game, event, sc_randomint (time1, time2) - 1); - } - - /* Return TRUE if we applied the fixup. */ - return version < TAF_VERSION_400; +evt_fixup_v390_v380_immediate_restart(sc_gameref_t game, sc_int event) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int version; + + vt_key[0].string = "Version"; + version = prop_get_integer(bundle, "I<-s", vt_key); + if (version < TAF_VERSION_400) { + sc_int time1, time2; + + if (evt_trace) + sc_trace("Event: applying 3.9/3.8 restart fixup\n"); + + /* Set to running state. */ + gs_set_event_state(game, event, ES_RUNNING); + + /* Set up event time to be one less than a proper start. */ + vt_key[0].string = "Events"; + vt_key[1].integer = event; + vt_key[2].string = "Time1"; + time1 = prop_get_integer(bundle, "I<-sis", vt_key); + vt_key[2].string = "Time2"; + time2 = prop_get_integer(bundle, "I<-sis", vt_key); + gs_set_event_time(game, event, sc_randomint(time1, time2) - 1); + } + + /* Return TRUE if we applied the fixup. */ + return version < TAF_VERSION_400; } @@ -207,58 +196,55 @@ evt_fixup_v390_v380_immediate_restart (sc_gameref_t game, sc_int event) * Change an event from WAITING to RUNNING. */ static void -evt_start_event (sc_gameref_t game, sc_int event) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int time1, time2, obj1, obj1dest; - - if (evt_trace) - sc_trace ("Event: starting event %ld\n", event); - - /* If event is visible, print its start text. */ - if (evt_can_see_event (game, event)) - { - const sc_char *starttext; - - /* Get and print start text. */ - vt_key[0].string = "Events"; - vt_key[1].integer = event; - vt_key[2].string = "StartText"; - starttext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (starttext)) - { - pf_buffer_string (filter, starttext); - pf_buffer_character (filter, '\n'); - } - - /* Handle any associated resource. */ - vt_key[2].string = "Res"; - vt_key[3].integer = 0; - res_handle_resource (game, "sisi", vt_key); - } - - /* Move event object to destination. */ - vt_key[0].string = "Events"; - vt_key[1].integer = event; - vt_key[2].string = "Obj1"; - obj1 = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - vt_key[2].string = "Obj1Dest"; - obj1dest = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - evt_move_object (game, obj1, obj1dest); - - /* Set the event's state and time. */ - gs_set_event_state (game, event, ES_RUNNING); - - vt_key[2].string = "Time1"; - time1 = prop_get_integer (bundle, "I<-sis", vt_key); - vt_key[2].string = "Time2"; - time2 = prop_get_integer (bundle, "I<-sis", vt_key); - gs_set_event_time (game, event, sc_randomint (time1, time2)); - - if (evt_trace) - sc_trace ("Event: start event handling done, %ld\n", event); +evt_start_event(sc_gameref_t game, sc_int event) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int time1, time2, obj1, obj1dest; + + if (evt_trace) + sc_trace("Event: starting event %ld\n", event); + + /* If event is visible, print its start text. */ + if (evt_can_see_event(game, event)) { + const sc_char *starttext; + + /* Get and print start text. */ + vt_key[0].string = "Events"; + vt_key[1].integer = event; + vt_key[2].string = "StartText"; + starttext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(starttext)) { + pf_buffer_string(filter, starttext); + pf_buffer_character(filter, '\n'); + } + + /* Handle any associated resource. */ + vt_key[2].string = "Res"; + vt_key[3].integer = 0; + res_handle_resource(game, "sisi", vt_key); + } + + /* Move event object to destination. */ + vt_key[0].string = "Events"; + vt_key[1].integer = event; + vt_key[2].string = "Obj1"; + obj1 = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + vt_key[2].string = "Obj1Dest"; + obj1dest = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + evt_move_object(game, obj1, obj1dest); + + /* Set the event's state and time. */ + gs_set_event_state(game, event, ES_RUNNING); + + vt_key[2].string = "Time1"; + time1 = prop_get_integer(bundle, "I<-sis", vt_key); + vt_key[2].string = "Time2"; + time2 = prop_get_integer(bundle, "I<-sis", vt_key); + gs_set_event_time(game, event, sc_randomint(time1, time2)); + + if (evt_trace) + sc_trace("Event: start event handling done, %ld\n", event); } @@ -268,18 +254,17 @@ evt_start_event (sc_gameref_t game, sc_int event) * Return the starter type for an event. */ static sc_int -evt_get_starter_type (sc_gameref_t game, sc_int event) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int startertype; - - vt_key[0].string = "Events"; - vt_key[1].integer = event; - vt_key[2].string = "StarterType"; - startertype = prop_get_integer (bundle, "I<-sis", vt_key); - - return startertype; +evt_get_starter_type(sc_gameref_t game, sc_int event) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int startertype; + + vt_key[0].string = "Events"; + vt_key[1].integer = event; + vt_key[2].string = "StarterType"; + startertype = prop_get_integer(bundle, "I<-sis", vt_key); + + return startertype; } @@ -289,148 +274,136 @@ evt_get_starter_type (sc_gameref_t game, sc_int event) * Move an event to FINISHED, or restart it. */ static void -evt_finish_event (sc_gameref_t game, sc_int event) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int obj2, obj2dest, obj3, obj3dest; - sc_int task, startertype, restarttype; - sc_bool taskdir; - - if (evt_trace) - sc_trace ("Event: finishing event %ld\n", event); - - /* Set up invariant parts of the key. */ - vt_key[0].string = "Events"; - vt_key[1].integer = event; - - /* If event is visible, print its finish text. */ - if (evt_can_see_event (game, event)) - { - const sc_char *finishtext; - - /* Get and print finish text. */ - vt_key[2].string = "FinishText"; - finishtext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (finishtext)) - { - pf_buffer_string (filter, finishtext); - pf_buffer_character (filter, '\n'); - } - - /* Handle any associated resource. */ - vt_key[2].string = "Res"; - vt_key[3].integer = 4; - res_handle_resource (game, "sisi", vt_key); - } - - /* Move event objects to destination. */ - vt_key[2].string = "Obj2"; - obj2 = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - vt_key[2].string = "Obj2Dest"; - obj2dest = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - evt_move_object (game, obj2, obj2dest); - - vt_key[2].string = "Obj3"; - obj3 = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - vt_key[2].string = "Obj3Dest"; - obj3dest = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - evt_move_object (game, obj3, obj3dest); - - /* See if there is an affected task. */ - vt_key[2].string = "TaskAffected"; - task = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - if (task >= 0) - { - vt_key[2].string = "TaskFinished"; - taskdir = !prop_get_boolean (bundle, "B<-sis", vt_key); - if (task_can_run_task_directional (game, task, taskdir)) - { - if (evt_trace) - { - sc_trace ("Event: event running task %ld, %s\n", - task, taskdir ? "forwards" : "backwards"); - } - - task_run_task (game, task, taskdir); - } - else - { - if (evt_trace) - sc_trace ("Event: event can't run task %ld\n", task); - } - } - - /* Handle possible restart. */ - vt_key[2].string = "RestartType"; - restarttype = prop_get_integer (bundle, "I<-sis", vt_key); - switch (restarttype) - { - case 0: /* Don't restart. */ - startertype = evt_get_starter_type (game, event); - switch (startertype) - { - case 1: /* Immediate. */ - case 2: /* Random delay. */ - case 3: /* After task. */ - gs_set_event_state (game, event, ES_FINISHED); - gs_set_event_time (game, event, 0); - break; - - default: - sc_fatal ("evt_finish_event:" - " unknown value for starter type, %ld\n", startertype); - } - break; - - case 1: /* Restart immediately. */ - if (evt_fixup_v390_v380_immediate_restart (game, event)) - break; - else - evt_start_event (game, event); - break; - - case 2: /* Restart after delay. */ - startertype = evt_get_starter_type (game, event); - switch (startertype) - { - case 1: /* Immediate. */ - if (evt_fixup_v390_v380_immediate_restart (game, event)) - break; - else - evt_start_event (game, event); - break; - - case 2: /* Random delay. */ - { - sc_int start, end; - - gs_set_event_state (game, event, ES_WAITING); - vt_key[2].string = "StartTime"; - start = prop_get_integer (bundle, "I<-sis", vt_key); - vt_key[2].string = "EndTime"; - end = prop_get_integer (bundle, "I<-sis", vt_key); - gs_set_event_time (game, event, sc_randomint (start, end)); - break; - } - - case 3: /* After task. */ - gs_set_event_state (game, event, ES_AWAITING); - gs_set_event_time (game, event, 0); - break; - - default: - sc_fatal ("evt_finish_event: unknown StarterType\n"); - } - break; - - default: - sc_fatal ("evt_finish_event: unknown RestartType\n"); - } - - if (evt_trace) - sc_trace ("Event: finish event handling done, %ld\n", event); +evt_finish_event(sc_gameref_t game, sc_int event) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int obj2, obj2dest, obj3, obj3dest; + sc_int task, startertype, restarttype; + sc_bool taskdir; + + if (evt_trace) + sc_trace("Event: finishing event %ld\n", event); + + /* Set up invariant parts of the key. */ + vt_key[0].string = "Events"; + vt_key[1].integer = event; + + /* If event is visible, print its finish text. */ + if (evt_can_see_event(game, event)) { + const sc_char *finishtext; + + /* Get and print finish text. */ + vt_key[2].string = "FinishText"; + finishtext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(finishtext)) { + pf_buffer_string(filter, finishtext); + pf_buffer_character(filter, '\n'); + } + + /* Handle any associated resource. */ + vt_key[2].string = "Res"; + vt_key[3].integer = 4; + res_handle_resource(game, "sisi", vt_key); + } + + /* Move event objects to destination. */ + vt_key[2].string = "Obj2"; + obj2 = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + vt_key[2].string = "Obj2Dest"; + obj2dest = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + evt_move_object(game, obj2, obj2dest); + + vt_key[2].string = "Obj3"; + obj3 = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + vt_key[2].string = "Obj3Dest"; + obj3dest = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + evt_move_object(game, obj3, obj3dest); + + /* See if there is an affected task. */ + vt_key[2].string = "TaskAffected"; + task = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + if (task >= 0) { + vt_key[2].string = "TaskFinished"; + taskdir = !prop_get_boolean(bundle, "B<-sis", vt_key); + if (task_can_run_task_directional(game, task, taskdir)) { + if (evt_trace) { + sc_trace("Event: event running task %ld, %s\n", + task, taskdir ? "forwards" : "backwards"); + } + + task_run_task(game, task, taskdir); + } else { + if (evt_trace) + sc_trace("Event: event can't run task %ld\n", task); + } + } + + /* Handle possible restart. */ + vt_key[2].string = "RestartType"; + restarttype = prop_get_integer(bundle, "I<-sis", vt_key); + switch (restarttype) { + case 0: /* Don't restart. */ + startertype = evt_get_starter_type(game, event); + switch (startertype) { + case 1: /* Immediate. */ + case 2: /* Random delay. */ + case 3: /* After task. */ + gs_set_event_state(game, event, ES_FINISHED); + gs_set_event_time(game, event, 0); + break; + + default: + sc_fatal("evt_finish_event:" + " unknown value for starter type, %ld\n", startertype); + } + break; + + case 1: /* Restart immediately. */ + if (evt_fixup_v390_v380_immediate_restart(game, event)) + break; + else + evt_start_event(game, event); + break; + + case 2: /* Restart after delay. */ + startertype = evt_get_starter_type(game, event); + switch (startertype) { + case 1: /* Immediate. */ + if (evt_fixup_v390_v380_immediate_restart(game, event)) + break; + else + evt_start_event(game, event); + break; + + case 2: { /* Random delay. */ + sc_int start, end; + + gs_set_event_state(game, event, ES_WAITING); + vt_key[2].string = "StartTime"; + start = prop_get_integer(bundle, "I<-sis", vt_key); + vt_key[2].string = "EndTime"; + end = prop_get_integer(bundle, "I<-sis", vt_key); + gs_set_event_time(game, event, sc_randomint(start, end)); + break; + } + + case 3: /* After task. */ + gs_set_event_state(game, event, ES_AWAITING); + gs_set_event_time(game, event, 0); + break; + + default: + sc_fatal("evt_finish_event: unknown StarterType\n"); + } + break; + + default: + sc_fatal("evt_finish_event: unknown RestartType\n"); + } + + if (evt_trace) + sc_trace("Event: finish event handling done, %ld\n", event); } @@ -443,102 +416,89 @@ evt_finish_event (sc_gameref_t game, sc_int event) * Return the status of start, pause and resume states of an event. */ static sc_bool -evt_has_starter_task (sc_gameref_t game, sc_int event) -{ - sc_int startertype; +evt_has_starter_task(sc_gameref_t game, sc_int event) { + sc_int startertype; - startertype = evt_get_starter_type (game, event); - return startertype == 3; + startertype = evt_get_starter_type(game, event); + return startertype == 3; } static sc_bool -evt_starter_task_is_complete (sc_gameref_t game, sc_int event) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int task; - sc_bool start; - - vt_key[0].string = "Events"; - vt_key[1].integer = event; - vt_key[2].string = "TaskNum"; - task = prop_get_integer (bundle, "I<-sis", vt_key); - - start = FALSE; - if (task == 0) - { - if (evt_any_task_in_state (game, TRUE)) - start = TRUE; - } - else if (task > 0) - { - if (gs_task_done (game, task - 1)) - start = TRUE; - } - - return start; +evt_starter_task_is_complete(sc_gameref_t game, sc_int event) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int task; + sc_bool start; + + vt_key[0].string = "Events"; + vt_key[1].integer = event; + vt_key[2].string = "TaskNum"; + task = prop_get_integer(bundle, "I<-sis", vt_key); + + start = FALSE; + if (task == 0) { + if (evt_any_task_in_state(game, TRUE)) + start = TRUE; + } else if (task > 0) { + if (gs_task_done(game, task - 1)) + start = TRUE; + } + + return start; } static sc_bool -evt_pauser_task_is_complete (sc_gameref_t game, sc_int event) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int pausetask; - sc_bool completed, pause; - - vt_key[0].string = "Events"; - vt_key[1].integer = event; - - vt_key[2].string = "PauseTask"; - pausetask = prop_get_integer (bundle, "I<-sis", vt_key); - vt_key[2].string = "PauserCompleted"; - completed = !prop_get_boolean (bundle, "B<-sis", vt_key); - - pause = FALSE; - if (pausetask == 1) - { - if (evt_any_task_in_state (game, completed)) - pause = TRUE; - } - else if (pausetask > 1) - { - if (completed == gs_task_done (game, pausetask - 2)) - pause = TRUE; - } - - return pause; +evt_pauser_task_is_complete(sc_gameref_t game, sc_int event) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int pausetask; + sc_bool completed, pause; + + vt_key[0].string = "Events"; + vt_key[1].integer = event; + + vt_key[2].string = "PauseTask"; + pausetask = prop_get_integer(bundle, "I<-sis", vt_key); + vt_key[2].string = "PauserCompleted"; + completed = !prop_get_boolean(bundle, "B<-sis", vt_key); + + pause = FALSE; + if (pausetask == 1) { + if (evt_any_task_in_state(game, completed)) + pause = TRUE; + } else if (pausetask > 1) { + if (completed == gs_task_done(game, pausetask - 2)) + pause = TRUE; + } + + return pause; } static sc_bool -evt_resumer_task_is_complete (sc_gameref_t game, sc_int event) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int resumetask; - sc_bool completed, resume; - - vt_key[0].string = "Events"; - vt_key[1].integer = event; - - vt_key[2].string = "ResumeTask"; - resumetask = prop_get_integer (bundle, "I<-sis", vt_key); - vt_key[2].string = "ResumerCompleted"; - completed = !prop_get_boolean (bundle, "B<-sis", vt_key); - - resume = FALSE; - if (resumetask == 1) - { - if (evt_any_task_in_state (game, completed)) - resume = TRUE; - } - else if (resumetask > 1) - { - if (completed == gs_task_done (game, resumetask - 2)) - resume = TRUE; - } - - return resume; +evt_resumer_task_is_complete(sc_gameref_t game, sc_int event) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int resumetask; + sc_bool completed, resume; + + vt_key[0].string = "Events"; + vt_key[1].integer = event; + + vt_key[2].string = "ResumeTask"; + resumetask = prop_get_integer(bundle, "I<-sis", vt_key); + vt_key[2].string = "ResumerCompleted"; + completed = !prop_get_boolean(bundle, "B<-sis", vt_key); + + resume = FALSE; + if (resumetask == 1) { + if (evt_any_task_in_state(game, completed)) + resume = TRUE; + } else if (resumetask > 1) { + if (completed == gs_task_done(game, resumetask - 2)) + resume = TRUE; + } + + return resume; } @@ -549,50 +509,45 @@ evt_resumer_task_is_complete (sc_gameref_t game, sc_int event) * and getting close to some number of turns from its end. */ static void -evt_handle_preftime_notifications (sc_gameref_t game, sc_int event) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int preftime1, preftime2; - const sc_char *preftext; - - vt_key[0].string = "Events"; - vt_key[1].integer = event; - - vt_key[2].string = "PrefTime1"; - preftime1 = prop_get_integer (bundle, "I<-sis", vt_key); - if (preftime1 == gs_event_time (game, event)) - { - vt_key[2].string = "PrefText1"; - preftext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (preftext)) - { - pf_buffer_string (filter, preftext); - pf_buffer_character (filter, '\n'); - } - - vt_key[2].string = "Res"; - vt_key[3].integer = 2; - res_handle_resource (game, "sisi", vt_key); - } - - vt_key[2].string = "PrefTime2"; - preftime2 = prop_get_integer (bundle, "I<-sis", vt_key); - if (preftime2 == gs_event_time (game, event)) - { - vt_key[2].string = "PrefText2"; - preftext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (preftext)) - { - pf_buffer_string (filter, preftext); - pf_buffer_character (filter, '\n'); - } - - vt_key[2].string = "Res"; - vt_key[3].integer = 3; - res_handle_resource (game, "sisi", vt_key); - } +evt_handle_preftime_notifications(sc_gameref_t game, sc_int event) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int preftime1, preftime2; + const sc_char *preftext; + + vt_key[0].string = "Events"; + vt_key[1].integer = event; + + vt_key[2].string = "PrefTime1"; + preftime1 = prop_get_integer(bundle, "I<-sis", vt_key); + if (preftime1 == gs_event_time(game, event)) { + vt_key[2].string = "PrefText1"; + preftext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(preftext)) { + pf_buffer_string(filter, preftext); + pf_buffer_character(filter, '\n'); + } + + vt_key[2].string = "Res"; + vt_key[3].integer = 2; + res_handle_resource(game, "sisi", vt_key); + } + + vt_key[2].string = "PrefTime2"; + preftime2 = prop_get_integer(bundle, "I<-sis", vt_key); + if (preftime2 == gs_event_time(game, event)) { + vt_key[2].string = "PrefText2"; + preftext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(preftext)) { + pf_buffer_string(filter, preftext); + pf_buffer_character(filter, '\n'); + } + + vt_key[2].string = "Res"; + vt_key[3].integer = 3; + res_handle_resource(game, "sisi", vt_key); + } } @@ -602,203 +557,183 @@ evt_handle_preftime_notifications (sc_gameref_t game, sc_int event) * Attempt to advance an event by one turn. */ static void -evt_tick_event (sc_gameref_t game, sc_int event) -{ - if (evt_trace) - { - sc_trace ("Event: ticking event %ld: state %ld, time %ld\n", event, - gs_event_state (game, event), gs_event_time (game, event)); - } - - /* Handle call based on current event state. */ - switch (gs_event_state (game, event)) - { - case ES_WAITING: - { - if (evt_trace) - sc_trace ("Event: ticking waiting event %ld\n", event); - - /* - * Because we also tick an event that goes from waiting to running, - * events started here will tick through RUNNING too, and have their - * time decremented. To get around this, so that the timer for one- - * shot events doesn't look one lower than it should after this - * transition, we need to set the initial time for events that start - * as soon as the game starts to one greater than that set by - * evt_start_time(). Here's the hack to do that; if the event starts - * immediately, its time will already be zero, even before decrement, - * which is how we tell which events to apply this hack to. - * - * TODO This seems to work, but also seems very dodgy. - */ - if (gs_event_time (game, event) == 0) - { - evt_start_event (game, event); - - /* If the event time was set to zero, finish immediately. */ - if (gs_event_time (game, event) <= 0) - evt_finish_event (game, event); - else - gs_set_event_time (game, event, gs_event_time (game, event) + 1); - break; - } - - /* - * Decrement the event's time, and if it goes to zero, start running - * the event. - */ - gs_decrement_event_time (game, event); - - if (gs_event_time (game, event) <= 0) - { - evt_start_event (game, event); - - /* If the event time was set to zero, finish immediately. */ - if (gs_event_time (game, event) <= 0) - evt_finish_event (game, event); - } - } - break; - - case ES_RUNNING: - { - if (evt_trace) - sc_trace ("Event: ticking running event %ld\n", event); - - /* - * Re-check the starter task; if it's no longer completed, we need - * to set the event back to waiting on task. - */ - if (evt_has_starter_task (game, event)) - { - if (!evt_starter_task_is_complete (game, event)) - { - if (evt_trace) - sc_trace ("Event: starter task not complete\n"); - - gs_set_event_state (game, event, ES_AWAITING); - gs_set_event_time (game, event, 0); - break; - } - } - - /* If the pauser has completed, but resumer not, pause this event. */ - if (evt_pauser_task_is_complete (game, event) - && !evt_resumer_task_is_complete (game, event)) - { - if (evt_trace) - sc_trace ("Event: pause complete\n"); - - gs_set_event_state (game, event, ES_PAUSED); - break; - } - - /* - * Decrement the event's time, and print any notifications for a set - * number of turns from the event end. - */ - gs_decrement_event_time (game, event); - - if (evt_can_see_event (game, event)) - evt_handle_preftime_notifications (game, event); - - /* If the time goes to zero, finish running the event. */ - if (gs_event_time (game, event) <= 0) - evt_finish_event (game, event); - } - break; - - case ES_AWAITING: - { - if (evt_trace) - sc_trace ("Event: ticking awaiting event %ld\n", event); - - /* - * Check the starter task. If it's completed, start running the - * event. - */ - if (evt_starter_task_is_complete (game, event)) - { - evt_start_event (game, event); - - /* If the event time was set to zero, finish immediately. */ - if (gs_event_time (game, event) <= 0) - evt_finish_event (game, event); - else - { - /* - * If the pauser has completed, but resumer not, immediately - * also pause this event. - */ - if (evt_pauser_task_is_complete (game, event) - && !evt_resumer_task_is_complete (game, event)) - { - if (evt_trace) - sc_trace ("Event: pause complete, immediate pause\n"); - - gs_set_event_state (game, event, ES_PAUSED); - } - } - } - } - break; - - case ES_FINISHED: - { - if (evt_trace) - sc_trace ("Event: ticking finished event %ld\n", event); - - /* - * Check the starter task; if it's not completed, we need to set the - * event back to waiting on task. - * - * A completed event needs to go back to waiting on its task, but we - * don't want to set it there as soon as the event finishes. We need - * to wait for the starter task to first become undone, otherwise the - * event just cycles endlessly, and they don't in Adrift itself. Here - * is where we wait for starter tasks to become undone. - */ - if (evt_has_starter_task (game, event)) - { - if (!evt_starter_task_is_complete (game, event)) - { - if (evt_trace) - sc_trace ("Event: starter task not complete\n"); - - gs_set_event_state (game, event, ES_AWAITING); - gs_set_event_time (game, event, 0); - break; - } - } - } - break; - - case ES_PAUSED: - { - if (evt_trace) - sc_trace ("Event: ticking paused event %ld\n", event); - - /* If the resumer has completed, resume this event. */ - if (evt_resumer_task_is_complete (game, event)) - { - if (evt_trace) - sc_trace ("Event: resume complete\n"); - - gs_set_event_state (game, event, ES_RUNNING); - break; - } - } - break; - - default: - sc_fatal ("evt_tick: invalid event state\n"); - } - - if (evt_trace) - { - sc_trace ("Event: after ticking event %ld: state %ld, time %ld\n", event, - gs_event_state (game, event), gs_event_time (game, event)); - } +evt_tick_event(sc_gameref_t game, sc_int event) { + if (evt_trace) { + sc_trace("Event: ticking event %ld: state %ld, time %ld\n", event, + gs_event_state(game, event), gs_event_time(game, event)); + } + + /* Handle call based on current event state. */ + switch (gs_event_state(game, event)) { + case ES_WAITING: { + if (evt_trace) + sc_trace("Event: ticking waiting event %ld\n", event); + + /* + * Because we also tick an event that goes from waiting to running, + * events started here will tick through RUNNING too, and have their + * time decremented. To get around this, so that the timer for one- + * shot events doesn't look one lower than it should after this + * transition, we need to set the initial time for events that start + * as soon as the game starts to one greater than that set by + * evt_start_time(). Here's the hack to do that; if the event starts + * immediately, its time will already be zero, even before decrement, + * which is how we tell which events to apply this hack to. + * + * TODO This seems to work, but also seems very dodgy. + */ + if (gs_event_time(game, event) == 0) { + evt_start_event(game, event); + + /* If the event time was set to zero, finish immediately. */ + if (gs_event_time(game, event) <= 0) + evt_finish_event(game, event); + else + gs_set_event_time(game, event, gs_event_time(game, event) + 1); + break; + } + + /* + * Decrement the event's time, and if it goes to zero, start running + * the event. + */ + gs_decrement_event_time(game, event); + + if (gs_event_time(game, event) <= 0) { + evt_start_event(game, event); + + /* If the event time was set to zero, finish immediately. */ + if (gs_event_time(game, event) <= 0) + evt_finish_event(game, event); + } + } + break; + + case ES_RUNNING: { + if (evt_trace) + sc_trace("Event: ticking running event %ld\n", event); + + /* + * Re-check the starter task; if it's no longer completed, we need + * to set the event back to waiting on task. + */ + if (evt_has_starter_task(game, event)) { + if (!evt_starter_task_is_complete(game, event)) { + if (evt_trace) + sc_trace("Event: starter task not complete\n"); + + gs_set_event_state(game, event, ES_AWAITING); + gs_set_event_time(game, event, 0); + break; + } + } + + /* If the pauser has completed, but resumer not, pause this event. */ + if (evt_pauser_task_is_complete(game, event) + && !evt_resumer_task_is_complete(game, event)) { + if (evt_trace) + sc_trace("Event: pause complete\n"); + + gs_set_event_state(game, event, ES_PAUSED); + break; + } + + /* + * Decrement the event's time, and print any notifications for a set + * number of turns from the event end. + */ + gs_decrement_event_time(game, event); + + if (evt_can_see_event(game, event)) + evt_handle_preftime_notifications(game, event); + + /* If the time goes to zero, finish running the event. */ + if (gs_event_time(game, event) <= 0) + evt_finish_event(game, event); + } + break; + + case ES_AWAITING: { + if (evt_trace) + sc_trace("Event: ticking awaiting event %ld\n", event); + + /* + * Check the starter task. If it's completed, start running the + * event. + */ + if (evt_starter_task_is_complete(game, event)) { + evt_start_event(game, event); + + /* If the event time was set to zero, finish immediately. */ + if (gs_event_time(game, event) <= 0) + evt_finish_event(game, event); + else { + /* + * If the pauser has completed, but resumer not, immediately + * also pause this event. + */ + if (evt_pauser_task_is_complete(game, event) + && !evt_resumer_task_is_complete(game, event)) { + if (evt_trace) + sc_trace("Event: pause complete, immediate pause\n"); + + gs_set_event_state(game, event, ES_PAUSED); + } + } + } + } + break; + + case ES_FINISHED: { + if (evt_trace) + sc_trace("Event: ticking finished event %ld\n", event); + + /* + * Check the starter task; if it's not completed, we need to set the + * event back to waiting on task. + * + * A completed event needs to go back to waiting on its task, but we + * don't want to set it there as soon as the event finishes. We need + * to wait for the starter task to first become undone, otherwise the + * event just cycles endlessly, and they don't in Adrift itself. Here + * is where we wait for starter tasks to become undone. + */ + if (evt_has_starter_task(game, event)) { + if (!evt_starter_task_is_complete(game, event)) { + if (evt_trace) + sc_trace("Event: starter task not complete\n"); + + gs_set_event_state(game, event, ES_AWAITING); + gs_set_event_time(game, event, 0); + break; + } + } + } + break; + + case ES_PAUSED: { + if (evt_trace) + sc_trace("Event: ticking paused event %ld\n", event); + + /* If the resumer has completed, resume this event. */ + if (evt_resumer_task_is_complete(game, event)) { + if (evt_trace) + sc_trace("Event: resume complete\n"); + + gs_set_event_state(game, event, ES_RUNNING); + break; + } + } + break; + + default: + sc_fatal("evt_tick: invalid event state\n"); + } + + if (evt_trace) { + sc_trace("Event: after ticking event %ld: state %ld, time %ld\n", event, + gs_event_state(game, event), gs_event_time(game, event)); + } } @@ -808,35 +743,33 @@ evt_tick_event (sc_gameref_t game, sc_int event) * Attempt to advance each event by one turn. */ void -evt_tick_events (sc_gameref_t game) -{ - sc_int event; - - /* - * Tick all events. If an event transitions into a running state from a - * paused or waiting state, tick that event again. - */ - for (event = 0; event < gs_event_count (game); event++) - { - sc_int prior_state, state; - - /* Note current state, and tick event forwards. */ - prior_state = gs_event_state (game, event); - evt_tick_event (game, event); - - /* - * If the event went from paused or waiting to running, tick again. - * This looks dodgy, and probably is, but it does keep timers correct - * by only re-ticking events that have transitioned from non-running - * states to a running one, and not already-running events. This is - * in effect just adding a bit of turn processing to a tick that would - * otherwise change state alone; a bit of laziness, in other words. - */ - state = gs_event_state (game, event); - if (state == ES_RUNNING - && (prior_state == ES_PAUSED || prior_state == ES_WAITING)) - evt_tick_event (game, event); - } +evt_tick_events(sc_gameref_t game) { + sc_int event; + + /* + * Tick all events. If an event transitions into a running state from a + * paused or waiting state, tick that event again. + */ + for (event = 0; event < gs_event_count(game); event++) { + sc_int prior_state, state; + + /* Note current state, and tick event forwards. */ + prior_state = gs_event_state(game, event); + evt_tick_event(game, event); + + /* + * If the event went from paused or waiting to running, tick again. + * This looks dodgy, and probably is, but it does keep timers correct + * by only re-ticking events that have transitioned from non-running + * states to a running one, and not already-running events. This is + * in effect just adding a bit of turn processing to a tick that would + * otherwise change state alone; a bit of laziness, in other words. + */ + state = gs_event_state(game, event); + if (state == ES_RUNNING + && (prior_state == ES_PAUSED || prior_state == ES_WAITING)) + evt_tick_event(game, event); + } } @@ -846,9 +779,8 @@ evt_tick_events (sc_gameref_t game) * Set event tracing on/off. */ void -evt_debug_trace (sc_bool flag) -{ - evt_trace = flag; +evt_debug_trace(sc_bool flag) { + evt_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scexpr.cpp b/engines/glk/adrift/scexpr.cpp index ed3386020f..a316b7cdec 100644 --- a/engines/glk/adrift/scexpr.cpp +++ b/engines/glk/adrift/scexpr.cpp @@ -51,50 +51,49 @@ static const sc_char DOUBLE_QUOTE = '"'; * serves to indicate string concatenation -- it's never returned by the * tokenizer. */ -enum -{ TOK_NONE = -1, - TOK_ADD = '+', TOK_SUBTRACT = '-', TOK_MULTIPLY = '*', TOK_DIVIDE = '/', - TOK_AND = '&', TOK_OR = '|', - TOK_LPAREN = '(', TOK_RPAREN = ')', TOK_COMMA = ',', TOK_POWER = '^', - TOK_EQUAL = '=', TOK_GREATER = '>', TOK_LESS = '<', - - TOK_IDENT = 256, - TOK_INTEGER, TOK_STRING, TOK_VARIABLE, TOK_UMINUS, TOK_UPLUS, - TOK_MOD, TOK_NOT_EQUAL, TOK_GREATER_EQ, TOK_LESS_EQ, TOK_IF, - TOK_MIN, TOK_MAX, TOK_EITHER, TOK_RANDOM, TOK_INSTR, TOK_LEN, TOK_VAL, - TOK_ABS, TOK_UPPER, TOK_LOWER, TOK_PROPER, TOK_RIGHT, TOK_LEFT, TOK_MID, - TOK_STR, TOK_CONCATENATE, - TOK_EOS +enum { + TOK_NONE = -1, + TOK_ADD = '+', TOK_SUBTRACT = '-', TOK_MULTIPLY = '*', TOK_DIVIDE = '/', + TOK_AND = '&', TOK_OR = '|', + TOK_LPAREN = '(', TOK_RPAREN = ')', TOK_COMMA = ',', TOK_POWER = '^', + TOK_EQUAL = '=', TOK_GREATER = '>', TOK_LESS = '<', + + TOK_IDENT = 256, + TOK_INTEGER, TOK_STRING, TOK_VARIABLE, TOK_UMINUS, TOK_UPLUS, + TOK_MOD, TOK_NOT_EQUAL, TOK_GREATER_EQ, TOK_LESS_EQ, TOK_IF, + TOK_MIN, TOK_MAX, TOK_EITHER, TOK_RANDOM, TOK_INSTR, TOK_LEN, TOK_VAL, + TOK_ABS, TOK_UPPER, TOK_LOWER, TOK_PROPER, TOK_RIGHT, TOK_LEFT, TOK_MID, + TOK_STR, TOK_CONCATENATE, + TOK_EOS }; /* * Small tables tying multicharacter tokens strings to tokens. At present, * the string lengths for names are not used. */ -typedef struct -{ - const sc_char *const name; - const sc_int length; - const sc_int token; +typedef struct { + const sc_char *const name; + const sc_int length; + const sc_int token; } sc_expr_multichar_t; static const sc_expr_multichar_t FUNCTION_TOKENS[] = { - {"either", 6, TOK_EITHER}, - {"proper", 6, TOK_PROPER}, {"pcase", 5, TOK_PROPER}, {"instr", 5, TOK_INSTR}, - {"upper", 5, TOK_UPPER}, {"ucase", 5, TOK_UPPER}, - {"lower", 5, TOK_LOWER}, {"lcase", 5, TOK_LOWER}, - {"right", 5, TOK_RIGHT}, {"left", 4, TOK_LEFT}, - {"rand", 4, TOK_RANDOM}, {"max", 3, TOK_MAX}, {"min", 3, TOK_MIN}, - {"mod", 3, TOK_MOD}, {"abs", 3, TOK_ABS}, {"len", 3, TOK_LEN}, - {"val", 3, TOK_VAL}, {"and", 3, TOK_AND}, {"mid", 3, TOK_MID}, - {"str", 3, TOK_STR}, {"or", 2, TOK_OR}, {"if", 2, TOK_IF}, - {NULL, 0, TOK_NONE} + {"either", 6, TOK_EITHER}, + {"proper", 6, TOK_PROPER}, {"pcase", 5, TOK_PROPER}, {"instr", 5, TOK_INSTR}, + {"upper", 5, TOK_UPPER}, {"ucase", 5, TOK_UPPER}, + {"lower", 5, TOK_LOWER}, {"lcase", 5, TOK_LOWER}, + {"right", 5, TOK_RIGHT}, {"left", 4, TOK_LEFT}, + {"rand", 4, TOK_RANDOM}, {"max", 3, TOK_MAX}, {"min", 3, TOK_MIN}, + {"mod", 3, TOK_MOD}, {"abs", 3, TOK_ABS}, {"len", 3, TOK_LEN}, + {"val", 3, TOK_VAL}, {"and", 3, TOK_AND}, {"mid", 3, TOK_MID}, + {"str", 3, TOK_STR}, {"or", 2, TOK_OR}, {"if", 2, TOK_IF}, + {NULL, 0, TOK_NONE} }; static const sc_expr_multichar_t OPERATOR_TOKENS[] = { - {"&&", 2, TOK_AND}, {"||", 2, TOK_OR}, - {"==", 2, TOK_EQUAL}, {"!=", 2, TOK_NOT_EQUAL}, - {"<>", 2, TOK_NOT_EQUAL}, {">=", 2, TOK_GREATER_EQ}, {"<=", 2, TOK_LESS_EQ}, - {NULL, 0, TOK_NONE} + {"&&", 2, TOK_AND}, {"||", 2, TOK_OR}, + {"==", 2, TOK_EQUAL}, {"!=", 2, TOK_NOT_EQUAL}, + {"<>", 2, TOK_NOT_EQUAL}, {">=", 2, TOK_GREATER_EQ}, {"<=", 2, TOK_LESS_EQ}, + {NULL, 0, TOK_NONE} }; @@ -105,19 +104,17 @@ static const sc_expr_multichar_t OPERATOR_TOKENS[] = { * TOK_NONE if no match. */ static sc_int -expr_multichar_search (const sc_char *name, const sc_expr_multichar_t *table) -{ - const sc_expr_multichar_t *entry; - - /* Scan the table for a case-independent full string match. */ - for (entry = table; entry->name; entry++) - { - if (sc_strcasecmp (name, entry->name) == 0) - break; - } - - /* Return the token matched, or TOK_NONE. */ - return entry->name ? entry->token : TOK_NONE; +expr_multichar_search(const sc_char *name, const sc_expr_multichar_t *table) { + const sc_expr_multichar_t *entry; + + /* Scan the table for a case-independent full string match. */ + for (entry = table; entry->name; entry++) { + if (sc_strcasecmp(name, entry->name) == 0) + break; + } + + /* Return the token matched, or TOK_NONE. */ + return entry->name ? entry->token : TOK_NONE; } @@ -135,60 +132,53 @@ static sc_int expr_current_token = TOK_NONE; * Start and wrap up expression string tokenization. */ static void -expr_tokenize_start (const sc_char *expression) -{ - static sc_bool initialized = FALSE; - - /* On first call only, verify the string lengths in the tables. */ - if (!initialized) - { - const sc_expr_multichar_t *entry; - - /* Compare table lengths with string lengths. */ - for (entry = FUNCTION_TOKENS; entry->name; entry++) - { - if (entry->length != (sc_int) strlen (entry->name)) - { - sc_fatal ("expr_tokenize_start:" - " token string length is wrong for \"%s\"\n", - entry->name); - } - } - - for (entry = OPERATOR_TOKENS; entry->name; entry++) - { - if (entry->length != (sc_int) strlen (entry->name)) - { - sc_fatal ("expr_tokenize_start:" - " operator string length is wrong for \"%s\"\n", - entry->name); - } - } - - initialized = TRUE; - } - - /* Save expression, and restart index. */ - expr_expression = expression; - expr_index = 0; - - /* Allocate a temporary token value/literals string. */ - assert (!expr_temporary); - expr_temporary = (sc_char *)sc_malloc (strlen (expression) + 1); - - /* Reset last token to none. */ - expr_current_token = TOK_NONE; +expr_tokenize_start(const sc_char *expression) { + static sc_bool initialized = FALSE; + + /* On first call only, verify the string lengths in the tables. */ + if (!initialized) { + const sc_expr_multichar_t *entry; + + /* Compare table lengths with string lengths. */ + for (entry = FUNCTION_TOKENS; entry->name; entry++) { + if (entry->length != (sc_int) strlen(entry->name)) { + sc_fatal("expr_tokenize_start:" + " token string length is wrong for \"%s\"\n", + entry->name); + } + } + + for (entry = OPERATOR_TOKENS; entry->name; entry++) { + if (entry->length != (sc_int) strlen(entry->name)) { + sc_fatal("expr_tokenize_start:" + " operator string length is wrong for \"%s\"\n", + entry->name); + } + } + + initialized = TRUE; + } + + /* Save expression, and restart index. */ + expr_expression = expression; + expr_index = 0; + + /* Allocate a temporary token value/literals string. */ + assert(!expr_temporary); + expr_temporary = (sc_char *)sc_malloc(strlen(expression) + 1); + + /* Reset last token to none. */ + expr_current_token = TOK_NONE; } static void -expr_tokenize_end (void) -{ - /* Deallocate temporary strings, clear expression. */ - sc_free (expr_temporary); - expr_temporary = NULL; - expr_expression = NULL; - expr_index = 0; - expr_current_token = TOK_NONE; +expr_tokenize_end(void) { + /* Deallocate temporary strings, clear expression. */ + sc_free(expr_temporary); + expr_temporary = NULL; + expr_expression = NULL; + expr_index = 0; + expr_current_token = TOK_NONE; } @@ -200,219 +190,198 @@ expr_tokenize_end (void) * be adjusted into a unary +/- depending on the value of the previous token. */ static sc_int -expr_next_token_unadjusted (sc_vartype_t *token_value) -{ - sc_int c; - assert (expr_expression); - - /* Skip any and all leading whitespace. */ - do - { - c = expr_expression[expr_index++]; - } - while (sc_isspace (c) && c != NUL); - - /* Return EOS if at expression end. */ - if (c == NUL) - { - expr_index--; - return TOK_EOS; - } - - /* - * Identify and return numerics. We deal only with unsigned numbers here; - * the unary +/- tokens take care of any integer sign issues. - */ - else if (sc_isdigit (c)) - { - sc_int value; - - sscanf (expr_expression + expr_index - 1, "%ld", &value); - - while (sc_isdigit (c) && c != NUL) - c = expr_expression[expr_index++]; - expr_index--; - - token_value->integer = value; - return TOK_INTEGER; - } - - /* Identify and return variable references. */ - else if (c == PERCENT) - { - sc_int index_; - - /* Copy variable name. */ - c = expr_expression[expr_index++]; - for (index_ = 0; c != PERCENT && c != NUL;) - { - expr_temporary[index_++] = c; - c = expr_expression[expr_index++]; - } - expr_temporary[index_++] = NUL; - - if (c == NUL) - { - sc_error ("expr_next_token_unadjusted:" - " warning: unterminated variable name\n"); - expr_index--; - } - - /* Return a variable name. */ - token_value->string = expr_temporary; - return TOK_VARIABLE; - } - - /* Identify and return string literals. */ - else if (c == DOUBLE_QUOTE || c == SINGLE_QUOTE) - { - sc_int index_; - sc_char quote; - - /* Copy maximal string literal. */ - quote = c; - c = expr_expression[expr_index++]; - for (index_ = 0; c != quote && c != NUL;) - { - expr_temporary[index_++] = c; - c = expr_expression[expr_index++]; - } - expr_temporary[index_++] = NUL; - - if (c == NUL) - { - sc_error ("expr_next_token_unadjusted:" - " warning: unterminated string literal\n"); - expr_index--; - } - - /* Return string literal. */ - token_value->string = expr_temporary; - return TOK_STRING; - } - - /* Identify ids and other multicharacter tokens. */ - else if (sc_isalpha (c)) - { - sc_int index_, token; - - /* - * Copy maximal alphabetical string. While an ident would normally - * be alpha followed by zero or more alnum, for Adrift purposes we - * use only alpha -- all idents should really be "functions", and - * in particular we want to see "mod7" as "mod" and 7 separately. - */ - for (index_ = 0; sc_isalpha (c) && c != NUL;) - { - expr_temporary[index_++] = c; - c = expr_expression[expr_index++]; - } - expr_index--; - expr_temporary[index_++] = NUL; - - /* - * Check for a function name, and if known, return that, otherwise - * return a bare id. - */ - token = expr_multichar_search (expr_temporary, FUNCTION_TOKENS); - if (token == TOK_NONE) - { - token_value->string = expr_temporary; - return TOK_IDENT; - } - else - return token; - } - - /* - * Last chance check for two-character (multichar) operators, and if none - * then return a single-character token. - */ - else - { - sc_char operator_[3]; - sc_int token; - - /* - * Build a two-character string. If we happen to be at the last - * expression character, we'll pick up the expression NUL into - * operator_[1], so no need to special case end of expression here. - */ - operator_[0] = c; - operator_[1] = expr_expression[expr_index]; - operator_[2] = NUL; - - /* Search for this two-character operator. */ - if (operator_[0] != NUL && operator_[1] != NUL) - { - token = expr_multichar_search (operator_, OPERATOR_TOKENS); - if (token != TOK_NONE) - { - /* Matched, so advance expression index and return this token. */ - expr_index++; - return token; - } - } - - /* - * No match, or at last expression character; return a single character - * token. - */ - return c; - } +expr_next_token_unadjusted(sc_vartype_t *token_value) { + sc_int c; + assert(expr_expression); + + /* Skip any and all leading whitespace. */ + do { + c = expr_expression[expr_index++]; + } while (sc_isspace(c) && c != NUL); + + /* Return EOS if at expression end. */ + if (c == NUL) { + expr_index--; + return TOK_EOS; + } + + /* + * Identify and return numerics. We deal only with unsigned numbers here; + * the unary +/- tokens take care of any integer sign issues. + */ + else if (sc_isdigit(c)) { + sc_int value; + + sscanf(expr_expression + expr_index - 1, "%ld", &value); + + while (sc_isdigit(c) && c != NUL) + c = expr_expression[expr_index++]; + expr_index--; + + token_value->integer = value; + return TOK_INTEGER; + } + + /* Identify and return variable references. */ + else if (c == PERCENT) { + sc_int index_; + + /* Copy variable name. */ + c = expr_expression[expr_index++]; + for (index_ = 0; c != PERCENT && c != NUL;) { + expr_temporary[index_++] = c; + c = expr_expression[expr_index++]; + } + expr_temporary[index_++] = NUL; + + if (c == NUL) { + sc_error("expr_next_token_unadjusted:" + " warning: unterminated variable name\n"); + expr_index--; + } + + /* Return a variable name. */ + token_value->string = expr_temporary; + return TOK_VARIABLE; + } + + /* Identify and return string literals. */ + else if (c == DOUBLE_QUOTE || c == SINGLE_QUOTE) { + sc_int index_; + sc_char quote; + + /* Copy maximal string literal. */ + quote = c; + c = expr_expression[expr_index++]; + for (index_ = 0; c != quote && c != NUL;) { + expr_temporary[index_++] = c; + c = expr_expression[expr_index++]; + } + expr_temporary[index_++] = NUL; + + if (c == NUL) { + sc_error("expr_next_token_unadjusted:" + " warning: unterminated string literal\n"); + expr_index--; + } + + /* Return string literal. */ + token_value->string = expr_temporary; + return TOK_STRING; + } + + /* Identify ids and other multicharacter tokens. */ + else if (sc_isalpha(c)) { + sc_int index_, token; + + /* + * Copy maximal alphabetical string. While an ident would normally + * be alpha followed by zero or more alnum, for Adrift purposes we + * use only alpha -- all idents should really be "functions", and + * in particular we want to see "mod7" as "mod" and 7 separately. + */ + for (index_ = 0; sc_isalpha(c) && c != NUL;) { + expr_temporary[index_++] = c; + c = expr_expression[expr_index++]; + } + expr_index--; + expr_temporary[index_++] = NUL; + + /* + * Check for a function name, and if known, return that, otherwise + * return a bare id. + */ + token = expr_multichar_search(expr_temporary, FUNCTION_TOKENS); + if (token == TOK_NONE) { + token_value->string = expr_temporary; + return TOK_IDENT; + } else + return token; + } + + /* + * Last chance check for two-character (multichar) operators, and if none + * then return a single-character token. + */ + else { + sc_char operator_[3]; + sc_int token; + + /* + * Build a two-character string. If we happen to be at the last + * expression character, we'll pick up the expression NUL into + * operator_[1], so no need to special case end of expression here. + */ + operator_[0] = c; + operator_[1] = expr_expression[expr_index]; + operator_[2] = NUL; + + /* Search for this two-character operator. */ + if (operator_[0] != NUL && operator_[1] != NUL) { + token = expr_multichar_search(operator_, OPERATOR_TOKENS); + if (token != TOK_NONE) { + /* Matched, so advance expression index and return this token. */ + expr_index++; + return token; + } + } + + /* + * No match, or at last expression character; return a single character + * token. + */ + return c; + } } static sc_int -expr_next_token (void) -{ - sc_int token; - sc_vartype_t token_value; - - /* - * Get the basic next token. We may adjust it later for unary minus/plus - * depending on what it is, and the prior token. - */ - token_value.voidp = NULL; - token = expr_next_token_unadjusted (&token_value); - - /* Special handling for unary minus/plus signs. */ - if (token == TOK_SUBTRACT || token == TOK_ADD) - { - /* - * Unary minus/plus if prior token was an operator or a comparison, left - * parenthesis, or comma, or if there was no prior token. - */ - switch (expr_current_token) - { - case TOK_MOD: - case TOK_POWER: - case TOK_ADD: - case TOK_SUBTRACT: - case TOK_MULTIPLY: - case TOK_DIVIDE: - case TOK_AND: - case TOK_OR: - case TOK_EQUAL: - case TOK_GREATER: - case TOK_LESS: - case TOK_NOT_EQUAL: - case TOK_GREATER_EQ: - case TOK_LESS_EQ: - case TOK_LPAREN: - case TOK_COMMA: - case TOK_NONE: - token = (token == TOK_SUBTRACT) ? TOK_UMINUS : TOK_UPLUS; - break; - - default: - break; - } - } - - /* Set current token to the one just found, and return it. */ - expr_current_token = token; - expr_token_value = token_value; - return token; +expr_next_token(void) { + sc_int token; + sc_vartype_t token_value; + + /* + * Get the basic next token. We may adjust it later for unary minus/plus + * depending on what it is, and the prior token. + */ + token_value.voidp = NULL; + token = expr_next_token_unadjusted(&token_value); + + /* Special handling for unary minus/plus signs. */ + if (token == TOK_SUBTRACT || token == TOK_ADD) { + /* + * Unary minus/plus if prior token was an operator or a comparison, left + * parenthesis, or comma, or if there was no prior token. + */ + switch (expr_current_token) { + case TOK_MOD: + case TOK_POWER: + case TOK_ADD: + case TOK_SUBTRACT: + case TOK_MULTIPLY: + case TOK_DIVIDE: + case TOK_AND: + case TOK_OR: + case TOK_EQUAL: + case TOK_GREATER: + case TOK_LESS: + case TOK_NOT_EQUAL: + case TOK_GREATER_EQ: + case TOK_LESS_EQ: + case TOK_LPAREN: + case TOK_COMMA: + case TOK_NONE: + token = (token == TOK_SUBTRACT) ? TOK_UMINUS : TOK_UPLUS; + break; + + default: + break; + } + } + + /* Set current token to the one just found, and return it. */ + expr_current_token = token; + expr_token_value = token_value; + return token; } @@ -423,24 +392,22 @@ expr_next_token (void) * token is not numeric, an id, or a variable. */ static void -expr_current_token_value (sc_vartype_t *value) -{ - /* Quick check that the value is a valid one. */ - switch (expr_current_token) - { - case TOK_INTEGER: - case TOK_STRING: - case TOK_VARIABLE: - case TOK_IDENT: - break; - - default: - sc_fatal ("expr_current_token_value:" - " taking undefined token value, %ld\n", expr_current_token); - } - - /* Return value. */ - *value = expr_token_value; +expr_current_token_value(sc_vartype_t *value) { + /* Quick check that the value is a valid one. */ + switch (expr_current_token) { + case TOK_INTEGER: + case TOK_STRING: + case TOK_VARIABLE: + case TOK_IDENT: + break; + + default: + sc_fatal("expr_current_token_value:" + " taking undefined token value, %ld\n", expr_current_token); + } + + /* Return value. */ + *value = expr_token_value; } @@ -449,10 +416,9 @@ expr_current_token_value (sc_vartype_t *value) * integers and strings, and flags strings for possible garbage collection * on parse errors. */ -typedef struct -{ - sc_bool is_collectible; - sc_vartype_t value; +typedef struct { + sc_bool is_collectible; + sc_vartype_t value; } sc_stack_t; static sc_stack_t expr_eval_stack[MAX_NESTING_DEPTH]; static sc_int expr_eval_stack_index = 0; @@ -467,10 +433,9 @@ static sc_var_setref_t expr_varset = NULL; * set to use when referencing %...% variables. */ static void -expr_eval_start (sc_var_setref_t vars) -{ - expr_eval_stack_index = 0; - expr_varset = vars; +expr_eval_start(sc_var_setref_t vars) { + expr_eval_stack_index = 0; + expr_varset = vars; } @@ -481,22 +446,20 @@ expr_eval_start (sc_var_setref_t vars) * strings left in the evaluation array. */ static void -expr_eval_garbage_collect (void) -{ - sc_int index_; - - /* - * Find and free all collectible strings still in the stack. We have to - * free through mutable string rather than const string. - */ - for (index_ = 0; index_ < expr_eval_stack_index; index_++) - { - if (expr_eval_stack[index_].is_collectible) - sc_free (expr_eval_stack[index_].value.mutable_string); - } - - /* Reset the stack index, for clarity and neatness. */ - expr_eval_stack_index = 0; +expr_eval_garbage_collect(void) { + sc_int index_; + + /* + * Find and free all collectible strings still in the stack. We have to + * free through mutable string rather than const string. + */ + for (index_ = 0; index_ < expr_eval_stack_index; index_++) { + if (expr_eval_stack[index_].is_collectible) + sc_free(expr_eval_stack[index_].value.mutable_string); + } + + /* Reset the stack index, for clarity and neatness. */ + expr_eval_stack_index = 0; } @@ -511,38 +474,35 @@ expr_eval_garbage_collect (void) * the caller should not subsequently free the string. */ static void -expr_eval_push_integer (sc_int value) -{ - if (expr_eval_stack_index >= MAX_NESTING_DEPTH) - sc_fatal ("expr_eval_push_integer: stack overflow\n"); +expr_eval_push_integer(sc_int value) { + if (expr_eval_stack_index >= MAX_NESTING_DEPTH) + sc_fatal("expr_eval_push_integer: stack overflow\n"); - expr_eval_stack[expr_eval_stack_index].is_collectible = FALSE; - expr_eval_stack[expr_eval_stack_index++].value.integer = value; + expr_eval_stack[expr_eval_stack_index].is_collectible = FALSE; + expr_eval_stack[expr_eval_stack_index++].value.integer = value; } static void -expr_eval_push_string (const sc_char *value) -{ - sc_char *value_copy; - - if (expr_eval_stack_index >= MAX_NESTING_DEPTH) - sc_fatal ("expr_eval_push_string: stack overflow\n"); - - /* Push a copy of value. */ - value_copy = (sc_char *)sc_malloc (strlen (value) + 1); - strcpy (value_copy, value); - expr_eval_stack[expr_eval_stack_index].is_collectible = TRUE; - expr_eval_stack[expr_eval_stack_index++].value.mutable_string = value_copy; +expr_eval_push_string(const sc_char *value) { + sc_char *value_copy; + + if (expr_eval_stack_index >= MAX_NESTING_DEPTH) + sc_fatal("expr_eval_push_string: stack overflow\n"); + + /* Push a copy of value. */ + value_copy = (sc_char *)sc_malloc(strlen(value) + 1); + strcpy(value_copy, value); + expr_eval_stack[expr_eval_stack_index].is_collectible = TRUE; + expr_eval_stack[expr_eval_stack_index++].value.mutable_string = value_copy; } static void -expr_eval_push_alloced_string (sc_char *value) -{ - if (expr_eval_stack_index >= MAX_NESTING_DEPTH) - sc_fatal ("expr_eval_push_alloced_string: stack overflow\n"); +expr_eval_push_alloced_string(sc_char *value) { + if (expr_eval_stack_index >= MAX_NESTING_DEPTH) + sc_fatal("expr_eval_push_alloced_string: stack overflow\n"); - expr_eval_stack[expr_eval_stack_index].is_collectible = TRUE; - expr_eval_stack[expr_eval_stack_index++].value.mutable_string = value; + expr_eval_stack[expr_eval_stack_index].is_collectible = TRUE; + expr_eval_stack[expr_eval_stack_index++].value.mutable_string = value; } @@ -554,24 +514,22 @@ expr_eval_push_alloced_string (sc_char *value) * and the caller is responsible for freeing them. */ static sc_int -expr_eval_pop_integer (void) -{ - if (expr_eval_stack_index == 0) - sc_fatal ("expr_eval_pop_integer: stack underflow\n"); +expr_eval_pop_integer(void) { + if (expr_eval_stack_index == 0) + sc_fatal("expr_eval_pop_integer: stack underflow\n"); - assert (!expr_eval_stack[expr_eval_stack_index - 1].is_collectible); - return expr_eval_stack[--expr_eval_stack_index].value.integer; + assert(!expr_eval_stack[expr_eval_stack_index - 1].is_collectible); + return expr_eval_stack[--expr_eval_stack_index].value.integer; } static sc_char * -expr_eval_pop_string (void) -{ - if (expr_eval_stack_index == 0) - sc_fatal ("expr_eval_pop_string: stack underflow\n"); - - /* Returns mutable string rather than const string. */ - assert (expr_eval_stack[expr_eval_stack_index - 1].is_collectible); - return expr_eval_stack[--expr_eval_stack_index].value.mutable_string; +expr_eval_pop_string(void) { + if (expr_eval_stack_index == 0) + sc_fatal("expr_eval_pop_string: stack underflow\n"); + + /* Returns mutable string rather than const string. */ + assert(expr_eval_stack[expr_eval_stack_index - 1].is_collectible); + return expr_eval_stack[--expr_eval_stack_index].value.mutable_string; } @@ -581,14 +539,13 @@ expr_eval_pop_string (void) * Return the top of the values stack as the expression result. */ static void -expr_eval_result (sc_vartype_t *vt_rvalue) -{ - if (expr_eval_stack_index != 1) - sc_fatal ("expr_eval_result: values stack not completed\n"); - - /* Clear down stack and return the top value. */ - expr_eval_stack_index = 0; - *vt_rvalue = expr_eval_stack[0].value; +expr_eval_result(sc_vartype_t *vt_rvalue) { + if (expr_eval_stack_index != 1) + sc_fatal("expr_eval_result: values stack not completed\n"); + + /* Clear down stack and return the top value. */ + expr_eval_stack_index = 0; + *vt_rvalue = expr_eval_stack[0].value; } @@ -599,9 +556,8 @@ expr_eval_result (sc_vartype_t *vt_rvalue) * avoids tying sc_int to long types too closely. */ static sc_int -expr_eval_abs (sc_int value) -{ - return value < 0 ? -value : value; +expr_eval_abs(sc_int value) { + return value < 0 ? -value : value; } @@ -614,525 +570,489 @@ static jmp_buf expr_parse_error; * Evaluate the effect of a token into the values stack. */ static void -expr_eval_action (sc_int token) -{ - sc_vartype_t token_value; - - switch (token) - { - /* Handle tokens representing stack pushes. */ - case TOK_INTEGER: - expr_current_token_value (&token_value); - expr_eval_push_integer (token_value.integer); - break; - - case TOK_STRING: - expr_current_token_value (&token_value); - expr_eval_push_string (token_value.string); - break; - - case TOK_VARIABLE: - { - sc_vartype_t vt_rvalue; - sc_int type; - - expr_current_token_value (&token_value); - if (!var_get (expr_varset, token_value.string, &type, &vt_rvalue)) - { - sc_error ("expr_eval_action:" - " undefined variable, %s\n", token_value.string); - longjmp (expr_parse_error, 1); - } - switch (type) - { - case VAR_INTEGER: - expr_eval_push_integer (vt_rvalue.integer); - break; - - case VAR_STRING: - expr_eval_push_string (vt_rvalue.string); - break; - - default: - sc_fatal ("expr_eval_action: bad variable type\n"); - } - break; - } - - /* Handle tokens representing functions returning numeric. */ - case TOK_IF: - { - sc_int test, val1, val2; - - /* Pop the test and alternatives, and push back result. */ - val2 = expr_eval_pop_integer (); - val1 = expr_eval_pop_integer (); - test = expr_eval_pop_integer (); - expr_eval_push_integer (test ? val1 : val2); - break; - } - - case TOK_MAX: - case TOK_MIN: - { - sc_int argument_count, index_, result; - - /* Get argument count off the top of the stack. */ - argument_count = expr_eval_pop_integer (); - assert (argument_count > 0); - - /* Find the max or min of these stacked values. */ - result = expr_eval_pop_integer (); - for (index_ = 1; index_ < argument_count; index_++) - { - sc_int next; - - next = expr_eval_pop_integer (); - switch (token) - { - case TOK_MAX: - result = (next > result) ? next : result; - break; - - case TOK_MIN: - result = (next < result) ? next : result; - break; - - default: - sc_fatal ("expr_eval_action: bad token, %ld\n", token); - } - } - - /* Push back the result. */ - expr_eval_push_integer (result); - break; - } - - case TOK_EITHER: - { - sc_int argument_count, pick, index_; - sc_int result = 0; - - /* Get argument count off the top of the stack. */ - argument_count = expr_eval_pop_integer (); - assert (argument_count > 0); - - /* - * Pick one of the top N items at random, then unstack all N and - * push back the value of the one picked. - */ - pick = sc_rand () % argument_count; - for (index_ = 0; index_ < argument_count; index_++) - { - sc_int val; - - val = expr_eval_pop_integer (); - if (index_ == pick) - result = val; - } - - /* Push back the result. */ - expr_eval_push_integer (result); - break; - } - - case TOK_INSTR: - { - sc_char *val1, *val2, *search; - sc_int result; - - /* Extract the two values to work on. */ - val2 = expr_eval_pop_string (); - val1 = expr_eval_pop_string (); - - /* - * Search for the second in the first. The result is the character - * position, starting at 1, or 0 if not found. Then free the popped - * strings, and push back the result. - */ - search = (val1[0] != NUL) ? strstr (val1, val2) : NULL; - result = (!search) ? 0 : search - val1 + 1; - sc_free (val1); - sc_free (val2); - expr_eval_push_integer (result); - break; - } - - case TOK_LEN: - { - sc_char *val; - sc_int result; - - /* Pop the top string, and push back its length. */ - val = expr_eval_pop_string (); - result = strlen (val); - sc_free (val); - expr_eval_push_integer (result); - break; - } - - case TOK_VAL: - { - sc_char *val; - sc_int result = 0; - - /* - * Extract the string at stack top, and try to convert, returning - * zero if conversion fails. Free the popped string, and push back - * the result. - */ - val = expr_eval_pop_string (); - sscanf (val, "%ld", &result); - sc_free (val); - expr_eval_push_integer (result); - break; - } - - /* Handle tokens representing unary numeric operations. */ - case TOK_UMINUS: - expr_eval_push_integer (-(expr_eval_pop_integer ())); - break; - - case TOK_UPLUS: - break; - - case TOK_ABS: - expr_eval_push_integer (expr_eval_abs (expr_eval_pop_integer ())); - break; - - /* Handle tokens representing most binary numeric operations. */ - case TOK_ADD: - case TOK_SUBTRACT: - case TOK_MULTIPLY: - case TOK_AND: - case TOK_OR: - case TOK_EQUAL: - case TOK_GREATER: - case TOK_LESS: - case TOK_NOT_EQUAL: - case TOK_GREATER_EQ: - case TOK_LESS_EQ: - case TOK_RANDOM: - { - sc_int val1, val2, result = 0; - - /* Extract the two values to work on. */ - val2 = expr_eval_pop_integer (); - val1 = expr_eval_pop_integer (); - - /* Generate the result value. */ - switch (token) - { - case TOK_ADD: - result = val1 + val2; - break; - case TOK_SUBTRACT: - result = val1 - val2; - break; - case TOK_MULTIPLY: - result = val1 * val2; - break; - case TOK_AND: - result = val1 && val2; - break; - case TOK_OR: - result = val1 || val2; - break; - case TOK_EQUAL: - result = val1 == val2; - break; - case TOK_GREATER: - result = val1 > val2; - break; - case TOK_LESS: - result = val1 < val2; - break; - case TOK_NOT_EQUAL: - result = val1 != val2; - break; - case TOK_GREATER_EQ: - result = val1 >= val2; - break; - case TOK_LESS_EQ: - result = val1 <= val2; - break; - case TOK_RANDOM: - result = sc_randomint (val1, val2); - break; - default: - sc_fatal ("expr_eval_action: bad token, %ld\n", token); - } - - /* Put result back at top of stack. */ - expr_eval_push_integer (result); - break; - } - - /* Handle division and modulus separately; they're "eccentric". */ - case TOK_DIVIDE: - case TOK_MOD: - { - sc_int val1, val2, x, y, result = 0; - - /* Extract the two values to work on, complain about division by 0. */ - val2 = expr_eval_pop_integer (); - val1 = expr_eval_pop_integer (); - if (val2 == 0) - { - sc_error ("expr_eval_action: attempt to divide by zero\n"); - expr_eval_push_integer (result); - break; - } - - /* - * ANSI/ISO C only defines integer division for positive values. - * Negative values usually work consistently across platforms, but are - * not guaranteed. For maximum portability, then, here we'll work - * carefully with positive integers only. - */ - x = expr_eval_abs (val1); - y = expr_eval_abs (val2); - - /* Generate the result value. */ - switch (token) - { - case TOK_DIVIDE: - /* - * Adrift's division apparently works by dividing using floating - * point, then applying (asymmetrical) rounding, so we have to do - * the same here. - */ - result = ((val1 < 0) == (val2 < 0)) - ? ((x / y) + (((x % y) * 2 >= y) ? 1 : 0)) - : -((x / y) + (((x % y) * 2 > y) ? 1 : 0)); - break; - - case TOK_MOD: - /* - * Adrift also breaks numerical consistency by defining mod in a - * conventional (non-rounded), way, so that A=(AdivB)*B+AmodB - * does not hold. - */ - result = (val1 < 0) ? -(x % y) : (x % y); - break; - - default: - sc_fatal ("expr_eval_action: bad token, %ld\n", token); - } - - /* Put result back at top of stack. */ - expr_eval_push_integer (result); - break; - } - - /* Handle power individually, to avoid needing a maths library. */ - case TOK_POWER: - { - sc_int val1, val2, result; - - /* Extract the two values to work on. */ - val2 = expr_eval_pop_integer (); - val1 = expr_eval_pop_integer (); - - /* Handle negative and zero power values first, as special cases. */ - if (val2 == 0) - result = 1; - else if (val2 < 0) - { - if (val1 == 0) - { - sc_error ("expr_eval_action: attempt to divide by zero\n"); - result = 0; - } - else if (val1 == 1) - result = val1; - else if (val1 == -1) - result = (-val2 & 1) ? val1 : -val1; - else - result = 0; - } - else - { - /* Raise to positive powers using the Russian Peasant algorithm. */ - while ((val2 & 1) == 0) - { - val1 = val1 * val1; - val2 >>= 1; - } - - result = val1; - val2 >>= 1; - while (val2 > 0) - { - val1 = val1 * val1; - if (val2 & 1) - result = result * val1; - val2 >>= 1; - } - } - - /* Put result back at top of stack. */ - expr_eval_push_integer (result); - break; - } - - /* Handle tokens representing functions returning string. */ - case TOK_LEFT: - case TOK_RIGHT: - { - sc_char *text; - sc_int length; - - /* - * Extract the text and length. If length is longer than text, or - * negative, do nothing. - */ - length = expr_eval_pop_integer (); - text = expr_eval_pop_string (); - if (length < 0 || length >= (sc_int) strlen (text)) - { - expr_eval_push_alloced_string (text); - break; - } - - /* - * Take the left or right segment -- for left, the operation is a - * simple truncation; for right, it's a memmove. - */ - switch (token) - { - case TOK_LEFT: - text[length] = NUL; - break; - - case TOK_RIGHT: - memmove (text, text + strlen (text) - length, length + 1); - break; - - default: - sc_fatal ("expr_eval_action: bad token, %ld\n", token); - } - - /* Put result back at top of stack. */ - expr_eval_push_alloced_string (text); - break; - } - - case TOK_MID: - { - sc_char *text; - sc_int length, start, limit; - - /* - * Extract the text, start, and length, re-basing start from 1 to 0, - * and calculate the limit on characters available for the move. - */ - length = expr_eval_pop_integer (); - start = expr_eval_pop_integer () - 1; - text = expr_eval_pop_string (); - limit = strlen (text); - - /* - * Clamp ranges that roam outside the available text -- start less - * than 0 to 0, and greater than len(text) to len(text), and length - * less than 0 to 0, and off string end to string end. - */ - if (start < 0) - start = 0; - else if (start > limit) - start = limit; - if (length < 0) - length = 0; - else if (length > limit - start) - length = limit - start; - - /* Move substring, terminate, and put back at top of stack. */ - memmove (text, text + start, length + 1); - text[length] = NUL; - expr_eval_push_alloced_string (text); - break; - } - - case TOK_STR: - { - sc_int val; - sc_char buffer[32]; - - /* - * Extract the value, convert it, and push back the resulting string. - * The leading space on positive values matches the Runner. - */ - val = expr_eval_pop_integer (); - sprintf (buffer, "% ld", val); - expr_eval_push_string (buffer); - break; - } - - - /* Handle tokens representing unary string operations. */ - case TOK_UPPER: - case TOK_LOWER: - case TOK_PROPER: - { - sc_char *text; - sc_int index_; - - /* Extract the value to work on. */ - text = expr_eval_pop_string (); - - /* Convert the entire string in place -- it's malloc'ed. */ - for (index_ = 0; text[index_] != NUL; index_++) - { - switch (token) - { - case TOK_UPPER: - text[index_] = sc_toupper (text[index_]); - break; - - case TOK_LOWER: - text[index_] = sc_tolower (text[index_]); - break; - - case TOK_PROPER: - if (index_ == 0 || sc_isspace (text[index_ - 1])) - text[index_] = sc_toupper (text[index_]); - else - text[index_] = sc_tolower (text[index_]); - break; - - default: - sc_fatal ("expr_eval_action: bad token, %ld\n", token); - } - } - - /* Put result back at top of stack. */ - expr_eval_push_alloced_string (text); - break; - } - - /* Handle token representing binary string operation. */ - case TOK_CONCATENATE: - { - sc_char *text1, *text2; - - /* Extract the two texts to work on. */ - text2 = expr_eval_pop_string (); - text1 = expr_eval_pop_string (); - - /* - * Resize text1 to be long enough for both, and concatenate, then - * free text2, and push back the concatenation. - */ - text1 = (sc_char *)sc_realloc (text1, strlen (text1) + strlen (text2) + 1); - strcat (text1, text2); - sc_free (text2); - expr_eval_push_alloced_string (text1); - break; - } - - default: - sc_fatal ("expr_eval_action: bad token, %ld\n", token); - } +expr_eval_action(sc_int token) { + sc_vartype_t token_value; + + switch (token) { + /* Handle tokens representing stack pushes. */ + case TOK_INTEGER: + expr_current_token_value(&token_value); + expr_eval_push_integer(token_value.integer); + break; + + case TOK_STRING: + expr_current_token_value(&token_value); + expr_eval_push_string(token_value.string); + break; + + case TOK_VARIABLE: { + sc_vartype_t vt_rvalue; + sc_int type; + + expr_current_token_value(&token_value); + if (!var_get(expr_varset, token_value.string, &type, &vt_rvalue)) { + sc_error("expr_eval_action:" + " undefined variable, %s\n", token_value.string); + longjmp(expr_parse_error, 1); + } + switch (type) { + case VAR_INTEGER: + expr_eval_push_integer(vt_rvalue.integer); + break; + + case VAR_STRING: + expr_eval_push_string(vt_rvalue.string); + break; + + default: + sc_fatal("expr_eval_action: bad variable type\n"); + } + break; + } + + /* Handle tokens representing functions returning numeric. */ + case TOK_IF: { + sc_int test, val1, val2; + + /* Pop the test and alternatives, and push back result. */ + val2 = expr_eval_pop_integer(); + val1 = expr_eval_pop_integer(); + test = expr_eval_pop_integer(); + expr_eval_push_integer(test ? val1 : val2); + break; + } + + case TOK_MAX: + case TOK_MIN: { + sc_int argument_count, index_, result; + + /* Get argument count off the top of the stack. */ + argument_count = expr_eval_pop_integer(); + assert(argument_count > 0); + + /* Find the max or min of these stacked values. */ + result = expr_eval_pop_integer(); + for (index_ = 1; index_ < argument_count; index_++) { + sc_int next; + + next = expr_eval_pop_integer(); + switch (token) { + case TOK_MAX: + result = (next > result) ? next : result; + break; + + case TOK_MIN: + result = (next < result) ? next : result; + break; + + default: + sc_fatal("expr_eval_action: bad token, %ld\n", token); + } + } + + /* Push back the result. */ + expr_eval_push_integer(result); + break; + } + + case TOK_EITHER: { + sc_int argument_count, pick, index_; + sc_int result = 0; + + /* Get argument count off the top of the stack. */ + argument_count = expr_eval_pop_integer(); + assert(argument_count > 0); + + /* + * Pick one of the top N items at random, then unstack all N and + * push back the value of the one picked. + */ + pick = sc_rand() % argument_count; + for (index_ = 0; index_ < argument_count; index_++) { + sc_int val; + + val = expr_eval_pop_integer(); + if (index_ == pick) + result = val; + } + + /* Push back the result. */ + expr_eval_push_integer(result); + break; + } + + case TOK_INSTR: { + sc_char *val1, *val2, *search; + sc_int result; + + /* Extract the two values to work on. */ + val2 = expr_eval_pop_string(); + val1 = expr_eval_pop_string(); + + /* + * Search for the second in the first. The result is the character + * position, starting at 1, or 0 if not found. Then free the popped + * strings, and push back the result. + */ + search = (val1[0] != NUL) ? strstr(val1, val2) : NULL; + result = (!search) ? 0 : search - val1 + 1; + sc_free(val1); + sc_free(val2); + expr_eval_push_integer(result); + break; + } + + case TOK_LEN: { + sc_char *val; + sc_int result; + + /* Pop the top string, and push back its length. */ + val = expr_eval_pop_string(); + result = strlen(val); + sc_free(val); + expr_eval_push_integer(result); + break; + } + + case TOK_VAL: { + sc_char *val; + sc_int result = 0; + + /* + * Extract the string at stack top, and try to convert, returning + * zero if conversion fails. Free the popped string, and push back + * the result. + */ + val = expr_eval_pop_string(); + sscanf(val, "%ld", &result); + sc_free(val); + expr_eval_push_integer(result); + break; + } + + /* Handle tokens representing unary numeric operations. */ + case TOK_UMINUS: + expr_eval_push_integer(-(expr_eval_pop_integer())); + break; + + case TOK_UPLUS: + break; + + case TOK_ABS: + expr_eval_push_integer(expr_eval_abs(expr_eval_pop_integer())); + break; + + /* Handle tokens representing most binary numeric operations. */ + case TOK_ADD: + case TOK_SUBTRACT: + case TOK_MULTIPLY: + case TOK_AND: + case TOK_OR: + case TOK_EQUAL: + case TOK_GREATER: + case TOK_LESS: + case TOK_NOT_EQUAL: + case TOK_GREATER_EQ: + case TOK_LESS_EQ: + case TOK_RANDOM: { + sc_int val1, val2, result = 0; + + /* Extract the two values to work on. */ + val2 = expr_eval_pop_integer(); + val1 = expr_eval_pop_integer(); + + /* Generate the result value. */ + switch (token) { + case TOK_ADD: + result = val1 + val2; + break; + case TOK_SUBTRACT: + result = val1 - val2; + break; + case TOK_MULTIPLY: + result = val1 * val2; + break; + case TOK_AND: + result = val1 && val2; + break; + case TOK_OR: + result = val1 || val2; + break; + case TOK_EQUAL: + result = val1 == val2; + break; + case TOK_GREATER: + result = val1 > val2; + break; + case TOK_LESS: + result = val1 < val2; + break; + case TOK_NOT_EQUAL: + result = val1 != val2; + break; + case TOK_GREATER_EQ: + result = val1 >= val2; + break; + case TOK_LESS_EQ: + result = val1 <= val2; + break; + case TOK_RANDOM: + result = sc_randomint(val1, val2); + break; + default: + sc_fatal("expr_eval_action: bad token, %ld\n", token); + } + + /* Put result back at top of stack. */ + expr_eval_push_integer(result); + break; + } + + /* Handle division and modulus separately; they're "eccentric". */ + case TOK_DIVIDE: + case TOK_MOD: { + sc_int val1, val2, x, y, result = 0; + + /* Extract the two values to work on, complain about division by 0. */ + val2 = expr_eval_pop_integer(); + val1 = expr_eval_pop_integer(); + if (val2 == 0) { + sc_error("expr_eval_action: attempt to divide by zero\n"); + expr_eval_push_integer(result); + break; + } + + /* + * ANSI/ISO C only defines integer division for positive values. + * Negative values usually work consistently across platforms, but are + * not guaranteed. For maximum portability, then, here we'll work + * carefully with positive integers only. + */ + x = expr_eval_abs(val1); + y = expr_eval_abs(val2); + + /* Generate the result value. */ + switch (token) { + case TOK_DIVIDE: + /* + * Adrift's division apparently works by dividing using floating + * point, then applying (asymmetrical) rounding, so we have to do + * the same here. + */ + result = ((val1 < 0) == (val2 < 0)) + ? ((x / y) + (((x % y) * 2 >= y) ? 1 : 0)) + : -((x / y) + (((x % y) * 2 > y) ? 1 : 0)); + break; + + case TOK_MOD: + /* + * Adrift also breaks numerical consistency by defining mod in a + * conventional (non-rounded), way, so that A=(AdivB)*B+AmodB + * does not hold. + */ + result = (val1 < 0) ? -(x % y) : (x % y); + break; + + default: + sc_fatal("expr_eval_action: bad token, %ld\n", token); + } + + /* Put result back at top of stack. */ + expr_eval_push_integer(result); + break; + } + + /* Handle power individually, to avoid needing a maths library. */ + case TOK_POWER: { + sc_int val1, val2, result; + + /* Extract the two values to work on. */ + val2 = expr_eval_pop_integer(); + val1 = expr_eval_pop_integer(); + + /* Handle negative and zero power values first, as special cases. */ + if (val2 == 0) + result = 1; + else if (val2 < 0) { + if (val1 == 0) { + sc_error("expr_eval_action: attempt to divide by zero\n"); + result = 0; + } else if (val1 == 1) + result = val1; + else if (val1 == -1) + result = (-val2 & 1) ? val1 : -val1; + else + result = 0; + } else { + /* Raise to positive powers using the Russian Peasant algorithm. */ + while ((val2 & 1) == 0) { + val1 = val1 * val1; + val2 >>= 1; + } + + result = val1; + val2 >>= 1; + while (val2 > 0) { + val1 = val1 * val1; + if (val2 & 1) + result = result * val1; + val2 >>= 1; + } + } + + /* Put result back at top of stack. */ + expr_eval_push_integer(result); + break; + } + + /* Handle tokens representing functions returning string. */ + case TOK_LEFT: + case TOK_RIGHT: { + sc_char *text; + sc_int length; + + /* + * Extract the text and length. If length is longer than text, or + * negative, do nothing. + */ + length = expr_eval_pop_integer(); + text = expr_eval_pop_string(); + if (length < 0 || length >= (sc_int) strlen(text)) { + expr_eval_push_alloced_string(text); + break; + } + + /* + * Take the left or right segment -- for left, the operation is a + * simple truncation; for right, it's a memmove. + */ + switch (token) { + case TOK_LEFT: + text[length] = NUL; + break; + + case TOK_RIGHT: + memmove(text, text + strlen(text) - length, length + 1); + break; + + default: + sc_fatal("expr_eval_action: bad token, %ld\n", token); + } + + /* Put result back at top of stack. */ + expr_eval_push_alloced_string(text); + break; + } + + case TOK_MID: { + sc_char *text; + sc_int length, start, limit; + + /* + * Extract the text, start, and length, re-basing start from 1 to 0, + * and calculate the limit on characters available for the move. + */ + length = expr_eval_pop_integer(); + start = expr_eval_pop_integer() - 1; + text = expr_eval_pop_string(); + limit = strlen(text); + + /* + * Clamp ranges that roam outside the available text -- start less + * than 0 to 0, and greater than len(text) to len(text), and length + * less than 0 to 0, and off string end to string end. + */ + if (start < 0) + start = 0; + else if (start > limit) + start = limit; + if (length < 0) + length = 0; + else if (length > limit - start) + length = limit - start; + + /* Move substring, terminate, and put back at top of stack. */ + memmove(text, text + start, length + 1); + text[length] = NUL; + expr_eval_push_alloced_string(text); + break; + } + + case TOK_STR: { + sc_int val; + sc_char buffer[32]; + + /* + * Extract the value, convert it, and push back the resulting string. + * The leading space on positive values matches the Runner. + */ + val = expr_eval_pop_integer(); + sprintf(buffer, "% ld", val); + expr_eval_push_string(buffer); + break; + } + + + /* Handle tokens representing unary string operations. */ + case TOK_UPPER: + case TOK_LOWER: + case TOK_PROPER: { + sc_char *text; + sc_int index_; + + /* Extract the value to work on. */ + text = expr_eval_pop_string(); + + /* Convert the entire string in place -- it's malloc'ed. */ + for (index_ = 0; text[index_] != NUL; index_++) { + switch (token) { + case TOK_UPPER: + text[index_] = sc_toupper(text[index_]); + break; + + case TOK_LOWER: + text[index_] = sc_tolower(text[index_]); + break; + + case TOK_PROPER: + if (index_ == 0 || sc_isspace(text[index_ - 1])) + text[index_] = sc_toupper(text[index_]); + else + text[index_] = sc_tolower(text[index_]); + break; + + default: + sc_fatal("expr_eval_action: bad token, %ld\n", token); + } + } + + /* Put result back at top of stack. */ + expr_eval_push_alloced_string(text); + break; + } + + /* Handle token representing binary string operation. */ + case TOK_CONCATENATE: { + sc_char *text1, *text2; + + /* Extract the two texts to work on. */ + text2 = expr_eval_pop_string(); + text1 = expr_eval_pop_string(); + + /* + * Resize text1 to be long enough for both, and concatenate, then + * free text2, and push back the concatenation. + */ + text1 = (sc_char *)sc_realloc(text1, strlen(text1) + strlen(text2) + 1); + strcat(text1, text2); + sc_free(text2); + expr_eval_push_alloced_string(text1); + break; + } + + default: + sc_fatal("expr_eval_action: bad token, %ld\n", token); + } } @@ -1140,9 +1060,9 @@ expr_eval_action (sc_int token) static sc_int expr_parse_lookahead = TOK_NONE; /* Forward declaration of factor parsers and string expression parser. */ -static void expr_parse_numeric_factor (void); -static void expr_parse_string_factor (void); -static void expr_parse_string_expr (void); +static void expr_parse_numeric_factor(void); +static void expr_parse_string_factor(void); +static void expr_parse_string_expr(void); /* * expr_parse_match() @@ -1150,17 +1070,15 @@ static void expr_parse_string_expr (void); * Match a token to the lookahead, then advance lookahead. */ static void -expr_parse_match (sc_int token) -{ - if (expr_parse_lookahead == token) - expr_parse_lookahead = expr_next_token (); - else - { - /* Syntax error. */ - sc_error ("expr_parse_match: syntax error," - " expected %ld, got %ld\n", expr_parse_lookahead, token); - longjmp (expr_parse_error, 1); - } +expr_parse_match(sc_int token) { + if (expr_parse_lookahead == token) + expr_parse_lookahead = expr_next_token(); + else { + /* Syntax error. */ + sc_error("expr_parse_match: syntax error," + " expected %ld, got %ld\n", expr_parse_lookahead, token); + longjmp(expr_parse_error, 1); + } } @@ -1171,10 +1089,9 @@ expr_parse_match (sc_int token) * a list with no operators (although in practice we need to put a TOK_NONE * in here since some C compilers won't accept { } as an empty initializer). */ -typedef struct -{ - const sc_int token_count; - const sc_int tokens[6]; +typedef struct { + const sc_int token_count; + const sc_int tokens[6]; } sc_precedence_entry_t; #if 0 /* @@ -1183,14 +1100,14 @@ typedef struct * comparisons, and boolean combiners. */ static const sc_precedence_entry_t PRECEDENCE_TABLE[] = { - {1, {TOK_OR}}, - {1, {TOK_AND}}, - {2, {TOK_EQUAL, TOK_NOT_EQUAL}}, - {4, {TOK_GREATER, TOK_LESS, TOK_GREATER_EQ, TOK_LESS_EQ}}, - {2, {TOK_ADD, TOK_SUBTRACT}}, - {3, {TOK_MULTIPLY, TOK_DIVIDE, TOK_MOD}}, - {1, {TOK_POWER}}, - {0, {TOK_NONE}} + {1, {TOK_OR}}, + {1, {TOK_AND}}, + {2, {TOK_EQUAL, TOK_NOT_EQUAL}}, + {4, {TOK_GREATER, TOK_LESS, TOK_GREATER_EQ, TOK_LESS_EQ}}, + {2, {TOK_ADD, TOK_SUBTRACT}}, + {3, {TOK_MULTIPLY, TOK_DIVIDE, TOK_MOD}}, + {1, {TOK_POWER}}, + {0, {TOK_NONE}} }; #else /* @@ -1199,12 +1116,16 @@ static const sc_precedence_entry_t PRECEDENCE_TABLE[] = { * subtraction, and boolean 'and' and 'or' have equal precedence. */ static const sc_precedence_entry_t PRECEDENCE_TABLE[] = { - {2, {TOK_OR, TOK_AND}}, - {6, {TOK_EQUAL, TOK_NOT_EQUAL, - TOK_GREATER, TOK_LESS, TOK_GREATER_EQ, TOK_LESS_EQ}}, - {4, {TOK_ADD, TOK_SUBTRACT, TOK_POWER, TOK_MOD}}, - {2, {TOK_MULTIPLY, TOK_DIVIDE}}, - {0, {TOK_NONE}} + {2, {TOK_OR, TOK_AND}}, + { + 6, { + TOK_EQUAL, TOK_NOT_EQUAL, + TOK_GREATER, TOK_LESS, TOK_GREATER_EQ, TOK_LESS_EQ + } + }, + {4, {TOK_ADD, TOK_SUBTRACT, TOK_POWER, TOK_MOD}}, + {2, {TOK_MULTIPLY, TOK_DIVIDE}}, + {0, {TOK_NONE}} }; #endif @@ -1216,23 +1137,20 @@ static const sc_precedence_entry_t PRECEDENCE_TABLE[] = { * entry passed in, and return TRUE if it contains the given token. */ static int -expr_parse_contains_token (const sc_precedence_entry_t *entry, sc_int token) -{ - sc_bool is_matched; - sc_int index_; - - /* Search the entry's token list for the token passed in. */ - is_matched = FALSE; - for (index_ = 0; index_ < entry->token_count; index_++) - { - if (entry->tokens[index_] == token) - { - is_matched = TRUE; - break; - } - } - - return is_matched; +expr_parse_contains_token(const sc_precedence_entry_t *entry, sc_int token) { + sc_bool is_matched; + sc_int index_; + + /* Search the entry's token list for the token passed in. */ + is_matched = FALSE; + for (index_ = 0; index_ < entry->token_count; index_++) { + if (entry->tokens[index_] == token) { + is_matched = TRUE; + break; + } + } + + return is_matched; } @@ -1244,34 +1162,31 @@ expr_parse_contains_token (const sc_precedence_entry_t *entry, sc_int token) * whether to parse a highest-precedence factor. */ static void -expr_parse_numeric_element (sc_int precedence) -{ - const sc_precedence_entry_t *entry; - - /* See if the level passed in has listed tokens. */ - entry = PRECEDENCE_TABLE + precedence; - if (entry->token_count == 0) - { - /* Precedence levels that hit the table end are factors. */ - expr_parse_numeric_factor (); - return; - } - - /* - * Parse initial higher-precedence factor, then others that associate - * with the given level. - */ - expr_parse_numeric_element (precedence + 1); - while (expr_parse_contains_token (entry, expr_parse_lookahead)) - { - sc_int token; - - /* Note token and match, parse next level, then action this token. */ - token = expr_parse_lookahead; - expr_parse_match (token); - expr_parse_numeric_element (precedence + 1); - expr_eval_action (token); - } +expr_parse_numeric_element(sc_int precedence) { + const sc_precedence_entry_t *entry; + + /* See if the level passed in has listed tokens. */ + entry = PRECEDENCE_TABLE + precedence; + if (entry->token_count == 0) { + /* Precedence levels that hit the table end are factors. */ + expr_parse_numeric_factor(); + return; + } + + /* + * Parse initial higher-precedence factor, then others that associate + * with the given level. + */ + expr_parse_numeric_element(precedence + 1); + while (expr_parse_contains_token(entry, expr_parse_lookahead)) { + sc_int token; + + /* Note token and match, parse next level, then action this token. */ + token = expr_parse_lookahead; + expr_parse_match(token); + expr_parse_numeric_element(precedence + 1); + expr_eval_action(token); + } } @@ -1281,10 +1196,9 @@ expr_parse_numeric_element (sc_int precedence) * Parse a complete numeric (sub-)expression. */ static void -expr_parse_numeric_expr (void) -{ - /* Call the parser of the lowest precedence operators. */ - expr_parse_numeric_element (0); +expr_parse_numeric_expr(void) { + /* Call the parser of the lowest precedence operators. */ + expr_parse_numeric_element(0); } @@ -1294,161 +1208,155 @@ expr_parse_numeric_expr (void) * Parse a numeric expression factor. */ static void -expr_parse_numeric_factor (void) -{ - /* Handle factors based on lookahead token. */ - switch (expr_parse_lookahead) - { - /* Handle straightforward factors first. */ - case TOK_LPAREN: - expr_parse_match (TOK_LPAREN); - expr_parse_numeric_expr (); - expr_parse_match (TOK_RPAREN); - break; - - case TOK_UMINUS: - expr_parse_match (TOK_UMINUS); - expr_parse_numeric_factor (); - expr_eval_action (TOK_UMINUS); - break; - - case TOK_UPLUS: - expr_parse_match (TOK_UPLUS); - expr_parse_numeric_factor (); - break; - - case TOK_INTEGER: - expr_eval_action (TOK_INTEGER); - expr_parse_match (TOK_INTEGER); - break; - - case TOK_VARIABLE: - { - sc_vartype_t token_value, vt_rvalue; - sc_int type; - - expr_current_token_value (&token_value); - if (!var_get (expr_varset, token_value.string, &type, &vt_rvalue)) - { - sc_error ("expr_parse_numeric_factor:" - " undefined variable, %s\n", token_value.string); - longjmp (expr_parse_error, 1); - } - if (type != VAR_INTEGER) - { - sc_error ("expr_parse_numeric_factor:" - " string variable in numeric context, %s\n", - token_value.string); - longjmp (expr_parse_error, 1); - } - expr_eval_action (TOK_VARIABLE); - expr_parse_match (TOK_VARIABLE); - break; - } - - /* Handle functions as factors. */ - case TOK_ABS: - /* Parse as "abs (val)". */ - expr_parse_match (TOK_ABS); - expr_parse_match (TOK_LPAREN); - expr_parse_numeric_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (TOK_ABS); - break; - - case TOK_IF: - /* Parse as "if (boolean, val1, val2)". */ - expr_parse_match (TOK_IF); - expr_parse_match (TOK_LPAREN); - expr_parse_numeric_expr (); - expr_parse_match (TOK_COMMA); - expr_parse_numeric_expr (); - expr_parse_match (TOK_COMMA); - expr_parse_numeric_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (TOK_IF); - break; - - case TOK_RANDOM: - /* Parse as "random (low, high)". */ - expr_parse_match (TOK_RANDOM); - expr_parse_match (TOK_LPAREN); - expr_parse_numeric_expr (); - expr_parse_match (TOK_COMMA); - expr_parse_numeric_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (TOK_RANDOM); - break; - - case TOK_MAX: - case TOK_MIN: - case TOK_EITHER: - /* Parse as " (val1[,val2[,val3...]]])". */ - { - sc_int token, argument_count; - - /* Match up the function name and opening parenthesis. */ - token = expr_parse_lookahead; - expr_parse_match (token); - expr_parse_match (TOK_LPAREN); - - /* Count variable number of arguments as they are stacked. */ - expr_parse_numeric_expr (); - argument_count = 1; - while (expr_parse_lookahead == TOK_COMMA) - { - expr_parse_match (TOK_COMMA); - expr_parse_numeric_expr (); - argument_count++; - } - expr_parse_match (TOK_RPAREN); - - /* Push additional value -- the count of arguments. */ - expr_eval_push_integer (argument_count); - expr_eval_action (token); - break; - } - - case TOK_INSTR: - /* Parse as "instr (val1, val2)". */ - expr_parse_match (TOK_INSTR); - expr_parse_match (TOK_LPAREN); - expr_parse_string_expr (); - expr_parse_match (TOK_COMMA); - expr_parse_string_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (TOK_INSTR); - break; - - case TOK_LEN: - /* Parse as "len (val)". */ - expr_parse_match (TOK_LEN); - expr_parse_match (TOK_LPAREN); - expr_parse_string_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (TOK_LEN); - break; - - case TOK_VAL: - /* Parse as "val (val)". */ - expr_parse_match (TOK_VAL); - expr_parse_match (TOK_LPAREN); - expr_parse_string_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (TOK_VAL); - break; - - case TOK_IDENT: - /* Unrecognized function-type token. */ - sc_error ("expr_parse_numeric_factor: syntax error, unknown ident\n"); - longjmp (expr_parse_error, 1); - - default: - /* Syntax error. */ - sc_error ("expr_parse_numeric_factor:" - " syntax error, unexpected token, %ld\n", expr_parse_lookahead); - longjmp (expr_parse_error, 1); - } +expr_parse_numeric_factor(void) { + /* Handle factors based on lookahead token. */ + switch (expr_parse_lookahead) { + /* Handle straightforward factors first. */ + case TOK_LPAREN: + expr_parse_match(TOK_LPAREN); + expr_parse_numeric_expr(); + expr_parse_match(TOK_RPAREN); + break; + + case TOK_UMINUS: + expr_parse_match(TOK_UMINUS); + expr_parse_numeric_factor(); + expr_eval_action(TOK_UMINUS); + break; + + case TOK_UPLUS: + expr_parse_match(TOK_UPLUS); + expr_parse_numeric_factor(); + break; + + case TOK_INTEGER: + expr_eval_action(TOK_INTEGER); + expr_parse_match(TOK_INTEGER); + break; + + case TOK_VARIABLE: { + sc_vartype_t token_value, vt_rvalue; + sc_int type; + + expr_current_token_value(&token_value); + if (!var_get(expr_varset, token_value.string, &type, &vt_rvalue)) { + sc_error("expr_parse_numeric_factor:" + " undefined variable, %s\n", token_value.string); + longjmp(expr_parse_error, 1); + } + if (type != VAR_INTEGER) { + sc_error("expr_parse_numeric_factor:" + " string variable in numeric context, %s\n", + token_value.string); + longjmp(expr_parse_error, 1); + } + expr_eval_action(TOK_VARIABLE); + expr_parse_match(TOK_VARIABLE); + break; + } + + /* Handle functions as factors. */ + case TOK_ABS: + /* Parse as "abs (val)". */ + expr_parse_match(TOK_ABS); + expr_parse_match(TOK_LPAREN); + expr_parse_numeric_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(TOK_ABS); + break; + + case TOK_IF: + /* Parse as "if (boolean, val1, val2)". */ + expr_parse_match(TOK_IF); + expr_parse_match(TOK_LPAREN); + expr_parse_numeric_expr(); + expr_parse_match(TOK_COMMA); + expr_parse_numeric_expr(); + expr_parse_match(TOK_COMMA); + expr_parse_numeric_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(TOK_IF); + break; + + case TOK_RANDOM: + /* Parse as "random (low, high)". */ + expr_parse_match(TOK_RANDOM); + expr_parse_match(TOK_LPAREN); + expr_parse_numeric_expr(); + expr_parse_match(TOK_COMMA); + expr_parse_numeric_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(TOK_RANDOM); + break; + + case TOK_MAX: + case TOK_MIN: + case TOK_EITHER: + /* Parse as " (val1[,val2[,val3...]]])". */ + { + sc_int token, argument_count; + + /* Match up the function name and opening parenthesis. */ + token = expr_parse_lookahead; + expr_parse_match(token); + expr_parse_match(TOK_LPAREN); + + /* Count variable number of arguments as they are stacked. */ + expr_parse_numeric_expr(); + argument_count = 1; + while (expr_parse_lookahead == TOK_COMMA) { + expr_parse_match(TOK_COMMA); + expr_parse_numeric_expr(); + argument_count++; + } + expr_parse_match(TOK_RPAREN); + + /* Push additional value -- the count of arguments. */ + expr_eval_push_integer(argument_count); + expr_eval_action(token); + break; + } + + case TOK_INSTR: + /* Parse as "instr (val1, val2)". */ + expr_parse_match(TOK_INSTR); + expr_parse_match(TOK_LPAREN); + expr_parse_string_expr(); + expr_parse_match(TOK_COMMA); + expr_parse_string_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(TOK_INSTR); + break; + + case TOK_LEN: + /* Parse as "len (val)". */ + expr_parse_match(TOK_LEN); + expr_parse_match(TOK_LPAREN); + expr_parse_string_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(TOK_LEN); + break; + + case TOK_VAL: + /* Parse as "val (val)". */ + expr_parse_match(TOK_VAL); + expr_parse_match(TOK_LPAREN); + expr_parse_string_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(TOK_VAL); + break; + + case TOK_IDENT: + /* Unrecognized function-type token. */ + sc_error("expr_parse_numeric_factor: syntax error, unknown ident\n"); + longjmp(expr_parse_error, 1); + + default: + /* Syntax error. */ + sc_error("expr_parse_numeric_factor:" + " syntax error, unexpected token, %ld\n", expr_parse_lookahead); + longjmp(expr_parse_error, 1); + } } @@ -1458,20 +1366,18 @@ expr_parse_numeric_factor (void) * Parse a complete string (sub-)expression. */ static void -expr_parse_string_expr (void) -{ - /* - * Parse a string factor, then all repeated concatenations. Because the '+' - * and '&' are context sensitive, we have to invent/translate them into the - * otherwise unused TOK_CONCATENATE for evaluation. - */ - expr_parse_string_factor (); - while (expr_parse_lookahead == TOK_AND || expr_parse_lookahead == TOK_ADD) - { - expr_parse_match (expr_parse_lookahead); - expr_parse_string_factor (); - expr_eval_action (TOK_CONCATENATE); - } +expr_parse_string_expr(void) { + /* + * Parse a string factor, then all repeated concatenations. Because the '+' + * and '&' are context sensitive, we have to invent/translate them into the + * otherwise unused TOK_CONCATENATE for evaluation. + */ + expr_parse_string_factor(); + while (expr_parse_lookahead == TOK_AND || expr_parse_lookahead == TOK_ADD) { + expr_parse_match(expr_parse_lookahead); + expr_parse_string_factor(); + expr_eval_action(TOK_CONCATENATE); + } } @@ -1481,114 +1387,109 @@ expr_parse_string_expr (void) * Parse a string expression factor. */ static void -expr_parse_string_factor (void) -{ - /* Handle factors based on lookahead token. */ - switch (expr_parse_lookahead) - { - /* Handle straightforward factors first. */ - case TOK_LPAREN: - expr_parse_match (TOK_LPAREN); - expr_parse_string_expr (); - expr_parse_match (TOK_RPAREN); - break; - - case TOK_STRING: - expr_eval_action (TOK_STRING); - expr_parse_match (TOK_STRING); - break; - - case TOK_VARIABLE: - { - sc_vartype_t token_value, vt_rvalue; - sc_int type; - - expr_current_token_value (&token_value); - if (!var_get (expr_varset, token_value.string, &type, &vt_rvalue)) - { - sc_error ("expr_parse_string_factor:" - " undefined variable, %s\n", token_value.string); - longjmp (expr_parse_error, 1); - } - if (type != VAR_STRING) - { - sc_error ("expr_parse_string_factor:" - " numeric variable in string context, %s\n", - token_value.string); - longjmp (expr_parse_error, 1); - } - expr_eval_action (TOK_VARIABLE); - expr_parse_match (TOK_VARIABLE); - break; - } - - /* Handle functions as factors. */ - case TOK_UPPER: - case TOK_LOWER: - case TOK_PROPER: - /* Parse as " (text)". */ - { - sc_int token; - - token = expr_parse_lookahead; - expr_parse_match (token); - expr_parse_match (TOK_LPAREN); - expr_parse_string_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (token); - break; - } - - case TOK_LEFT: - case TOK_RIGHT: - /* Parse as " (text,length)". */ - { - sc_int token; - - token = expr_parse_lookahead; - expr_parse_match (token); - expr_parse_match (TOK_LPAREN); - expr_parse_string_expr (); - expr_parse_match (TOK_COMMA); - expr_parse_numeric_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (token); - break; - } - - case TOK_MID: - /* Parse as "mid (text,start,length)". */ - expr_parse_match (TOK_MID); - expr_parse_match (TOK_LPAREN); - expr_parse_string_expr (); - expr_parse_match (TOK_COMMA); - expr_parse_numeric_expr (); - expr_parse_match (TOK_COMMA); - expr_parse_numeric_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (TOK_MID); - break; - - case TOK_STR: - /* Parse as "str (val)". */ - expr_parse_match (TOK_STR); - expr_parse_match (TOK_LPAREN); - expr_parse_numeric_expr (); - expr_parse_match (TOK_RPAREN); - expr_eval_action (TOK_STR); - break; - - case TOK_IDENT: - /* Unrecognized function-type token. */ - sc_error ("expr_parse_string_factor: syntax error, unknown ident\n"); - longjmp (expr_parse_error, 1); - - default: - /* Syntax error. */ - sc_error ("expr_parse_string_factor:" - " syntax error, unexpected token, %ld\n", expr_parse_lookahead); - longjmp (expr_parse_error, 1); - } +expr_parse_string_factor(void) { + /* Handle factors based on lookahead token. */ + switch (expr_parse_lookahead) { + /* Handle straightforward factors first. */ + case TOK_LPAREN: + expr_parse_match(TOK_LPAREN); + expr_parse_string_expr(); + expr_parse_match(TOK_RPAREN); + break; + + case TOK_STRING: + expr_eval_action(TOK_STRING); + expr_parse_match(TOK_STRING); + break; + + case TOK_VARIABLE: { + sc_vartype_t token_value, vt_rvalue; + sc_int type; + + expr_current_token_value(&token_value); + if (!var_get(expr_varset, token_value.string, &type, &vt_rvalue)) { + sc_error("expr_parse_string_factor:" + " undefined variable, %s\n", token_value.string); + longjmp(expr_parse_error, 1); + } + if (type != VAR_STRING) { + sc_error("expr_parse_string_factor:" + " numeric variable in string context, %s\n", + token_value.string); + longjmp(expr_parse_error, 1); + } + expr_eval_action(TOK_VARIABLE); + expr_parse_match(TOK_VARIABLE); + break; + } + + /* Handle functions as factors. */ + case TOK_UPPER: + case TOK_LOWER: + case TOK_PROPER: + /* Parse as " (text)". */ + { + sc_int token; + + token = expr_parse_lookahead; + expr_parse_match(token); + expr_parse_match(TOK_LPAREN); + expr_parse_string_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(token); + break; + } + + case TOK_LEFT: + case TOK_RIGHT: + /* Parse as " (text,length)". */ + { + sc_int token; + + token = expr_parse_lookahead; + expr_parse_match(token); + expr_parse_match(TOK_LPAREN); + expr_parse_string_expr(); + expr_parse_match(TOK_COMMA); + expr_parse_numeric_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(token); + break; + } + + case TOK_MID: + /* Parse as "mid (text,start,length)". */ + expr_parse_match(TOK_MID); + expr_parse_match(TOK_LPAREN); + expr_parse_string_expr(); + expr_parse_match(TOK_COMMA); + expr_parse_numeric_expr(); + expr_parse_match(TOK_COMMA); + expr_parse_numeric_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(TOK_MID); + break; + + case TOK_STR: + /* Parse as "str (val)". */ + expr_parse_match(TOK_STR); + expr_parse_match(TOK_LPAREN); + expr_parse_numeric_expr(); + expr_parse_match(TOK_RPAREN); + expr_eval_action(TOK_STR); + break; + + case TOK_IDENT: + /* Unrecognized function-type token. */ + sc_error("expr_parse_string_factor: syntax error, unknown ident\n"); + longjmp(expr_parse_error, 1); + + default: + /* Syntax error. */ + sc_error("expr_parse_string_factor:" + " syntax error, unexpected token, %ld\n", expr_parse_lookahead); + longjmp(expr_parse_error, 1); + } } @@ -1599,38 +1500,34 @@ expr_parse_string_factor (void) * value of the expression. */ static sc_bool -expr_evaluate_expression (const sc_char *expression, sc_var_setref_t vars, - sc_int assign_type, sc_vartype_t *vt_rvalue) -{ - assert (assign_type == VAR_INTEGER || assign_type == VAR_STRING); - - /* Reset values stack and start tokenizer. */ - expr_eval_start (vars); - expr_tokenize_start (expression); - - /* Try parsing an expression, and catch errors. */ - if (setjmp (expr_parse_error) == 0) - { - /* Parse an expression, and ensure it ends at string end. */ - expr_parse_lookahead = expr_next_token (); - if (assign_type == VAR_STRING) - expr_parse_string_expr (); - else - expr_parse_numeric_expr (); - expr_parse_match (TOK_EOS); - } - else - { - /* Parse error -- clean up tokenizer, collect garbage, and fail. */ - expr_tokenize_end (); - expr_eval_garbage_collect (); - return FALSE; - } - - /* Clean up tokenizer and return successfully with result. */ - expr_tokenize_end (); - expr_eval_result (vt_rvalue); - return TRUE; +expr_evaluate_expression(const sc_char *expression, sc_var_setref_t vars, + sc_int assign_type, sc_vartype_t *vt_rvalue) { + assert(assign_type == VAR_INTEGER || assign_type == VAR_STRING); + + /* Reset values stack and start tokenizer. */ + expr_eval_start(vars); + expr_tokenize_start(expression); + + /* Try parsing an expression, and catch errors. */ + if (setjmp(expr_parse_error) == 0) { + /* Parse an expression, and ensure it ends at string end. */ + expr_parse_lookahead = expr_next_token(); + if (assign_type == VAR_STRING) + expr_parse_string_expr(); + else + expr_parse_numeric_expr(); + expr_parse_match(TOK_EOS); + } else { + /* Parse error -- clean up tokenizer, collect garbage, and fail. */ + expr_tokenize_end(); + expr_eval_garbage_collect(); + return FALSE; + } + + /* Clean up tokenizer and return successfully with result. */ + expr_tokenize_end(); + expr_eval_result(vt_rvalue); + return TRUE; } @@ -1644,33 +1541,31 @@ expr_evaluate_expression (const sc_char *expression, sc_var_setref_t vars, * it. */ sc_bool -expr_eval_numeric_expression (const sc_char *expression, - sc_var_setref_t vars, sc_int *rvalue) -{ - sc_vartype_t vt_rvalue; - sc_bool status; - assert (expression && vars && rvalue); - - /* Evaluate numeric expression, and return value if valid. */ - status = expr_evaluate_expression (expression, vars, VAR_INTEGER, &vt_rvalue); - if (status) - *rvalue = vt_rvalue.integer; - return status; +expr_eval_numeric_expression(const sc_char *expression, + sc_var_setref_t vars, sc_int *rvalue) { + sc_vartype_t vt_rvalue; + sc_bool status; + assert(expression && vars && rvalue); + + /* Evaluate numeric expression, and return value if valid. */ + status = expr_evaluate_expression(expression, vars, VAR_INTEGER, &vt_rvalue); + if (status) + *rvalue = vt_rvalue.integer; + return status; } sc_bool -expr_eval_string_expression (const sc_char *expression, - sc_var_setref_t vars, sc_char **rvalue) -{ - sc_vartype_t vt_rvalue; - sc_bool status; - assert (expression && vars && rvalue); - - /* Evaluate string expression, and return value if valid. */ - status = expr_evaluate_expression (expression, vars, VAR_STRING, &vt_rvalue); - if (status) - *rvalue = vt_rvalue.mutable_string; - return status; +expr_eval_string_expression(const sc_char *expression, + sc_var_setref_t vars, sc_char **rvalue) { + sc_vartype_t vt_rvalue; + sc_bool status; + assert(expression && vars && rvalue); + + /* Evaluate string expression, and return value if valid. */ + status = expr_evaluate_expression(expression, vars, VAR_STRING, &vt_rvalue); + if (status) + *rvalue = vt_rvalue.mutable_string; + return status; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scgamest.cpp b/engines/glk/adrift/scgamest.cpp index 2d9d78fbb3..f2af6b85d6 100644 --- a/engines/glk/adrift/scgamest.cpp +++ b/engines/glk/adrift/scgamest.cpp @@ -37,30 +37,26 @@ static const sc_uint GAME_MAGIC = 0x35aed26e; * Move the player to a given room, and check presence in a given room. */ void -gs_move_player_to_room (sc_gameref_t game, sc_int room) -{ - assert(gs_is_game_valid (game)); +gs_move_player_to_room(sc_gameref_t game, sc_int room) { + assert(gs_is_game_valid(game)); - if (room < 0) - { - sc_fatal ("gs_move_player_to_room: invalid room, %ld\n", room); - return; - } - else if (room < game->room_count) - game->playerroom = room; - else - game->playerroom = lib_random_roomgroup_member (game, - room - game->room_count); + if (room < 0) { + sc_fatal("gs_move_player_to_room: invalid room, %ld\n", room); + return; + } else if (room < game->room_count) + game->playerroom = room; + else + game->playerroom = lib_random_roomgroup_member(game, + room - game->room_count); - game->playerparent = -1; - game->playerposition = 0; + game->playerparent = -1; + game->playerposition = 0; } sc_bool -gs_player_in_room (sc_gameref_t game, sc_int room) -{ - assert(gs_is_game_valid (game)); - return game->playerroom == room; +gs_player_in_room(sc_gameref_t game, sc_int room) { + assert(gs_is_game_valid(game)); + return game->playerroom == room; } @@ -70,9 +66,8 @@ gs_player_in_room (sc_gameref_t game, sc_int room) * Helper for event, room, object, and npc range assertions. */ static sc_bool -gs_in_range (sc_int value, sc_int limit) -{ - return value >= 0 && value < limit; +gs_in_range(sc_int value, sc_int limit) { + return value >= 0 && value < limit; } @@ -82,31 +77,27 @@ gs_in_range (sc_int value, sc_int limit) * Game accessors and mutators. */ sc_var_setref_t -gs_get_vars (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->vars; +gs_get_vars(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->vars; } sc_prop_setref_t -gs_get_bundle (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->bundle; +gs_get_bundle(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->bundle; } sc_filterref_t -gs_get_filter (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->filter; +gs_get_filter(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->filter; } sc_memo_setref_t -gs_get_memento (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->memento; +gs_get_memento(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->memento; } @@ -114,45 +105,39 @@ gs_get_memento (sc_gameref_t gs) * Game accessors and mutators for the player. */ void -gs_set_playerroom (sc_gameref_t gs, sc_int room) -{ - assert(gs_is_game_valid (gs)); - gs->playerroom = room; +gs_set_playerroom(sc_gameref_t gs, sc_int room) { + assert(gs_is_game_valid(gs)); + gs->playerroom = room; } void -gs_set_playerposition (sc_gameref_t gs, sc_int position) -{ - assert(gs_is_game_valid (gs)); - gs->playerposition = position; +gs_set_playerposition(sc_gameref_t gs, sc_int position) { + assert(gs_is_game_valid(gs)); + gs->playerposition = position; } void -gs_set_playerparent (sc_gameref_t gs, sc_int parent) -{ - assert(gs_is_game_valid (gs)); - gs->playerparent = parent; +gs_set_playerparent(sc_gameref_t gs, sc_int parent) { + assert(gs_is_game_valid(gs)); + gs->playerparent = parent; } sc_int -gs_playerroom (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->playerroom; +gs_playerroom(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->playerroom; } sc_int -gs_playerposition (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->playerposition; +gs_playerposition(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->playerposition; } sc_int -gs_playerparent (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->playerparent; +gs_playerparent(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->playerparent; } @@ -160,45 +145,39 @@ gs_playerparent (sc_gameref_t gs) * Game accessors and mutators for events. */ sc_int -gs_event_count (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->event_count; +gs_event_count(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->event_count; } void -gs_set_event_state (sc_gameref_t gs, sc_int event, sc_int state) -{ - assert(gs_is_game_valid (gs) && gs_in_range (event, gs->event_count)); - gs->events[event].state = state; +gs_set_event_state(sc_gameref_t gs, sc_int event, sc_int state) { + assert(gs_is_game_valid(gs) && gs_in_range(event, gs->event_count)); + gs->events[event].state = state; } void -gs_set_event_time (sc_gameref_t gs, sc_int event, sc_int etime) -{ - assert(gs_is_game_valid (gs) && gs_in_range (event, gs->event_count)); - gs->events[event].time = etime; +gs_set_event_time(sc_gameref_t gs, sc_int event, sc_int etime) { + assert(gs_is_game_valid(gs) && gs_in_range(event, gs->event_count)); + gs->events[event].time = etime; } sc_int -gs_event_state (sc_gameref_t gs, sc_int event) -{ - assert(gs_is_game_valid (gs) && gs_in_range (event, gs->event_count)); - return gs->events[event].state; +gs_event_state(sc_gameref_t gs, sc_int event) { + assert(gs_is_game_valid(gs) && gs_in_range(event, gs->event_count)); + return gs->events[event].state; } sc_int -gs_event_time (sc_gameref_t gs, sc_int event) -{ - assert(gs_is_game_valid (gs) && gs_in_range (event, gs->event_count)); - return gs->events[event].time; +gs_event_time(sc_gameref_t gs, sc_int event) { + assert(gs_is_game_valid(gs) && gs_in_range(event, gs->event_count)); + return gs->events[event].time; } void -gs_decrement_event_time (sc_gameref_t gs, sc_int event) -{ - assert(gs_is_game_valid (gs) && gs_in_range (event, gs->event_count)); - gs->events[event].time--; +gs_decrement_event_time(sc_gameref_t gs, sc_int event) { + assert(gs_is_game_valid(gs) && gs_in_range(event, gs->event_count)); + gs->events[event].time--; } @@ -206,24 +185,21 @@ gs_decrement_event_time (sc_gameref_t gs, sc_int event) * Game accessors and mutators for rooms. */ sc_int -gs_room_count (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->room_count; +gs_room_count(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->room_count; } void -gs_set_room_seen (sc_gameref_t gs, sc_int room, sc_bool seen) -{ - assert(gs_is_game_valid (gs) && gs_in_range (room, gs->room_count)); - gs->rooms[room].visited = seen; +gs_set_room_seen(sc_gameref_t gs, sc_int room, sc_bool seen) { + assert(gs_is_game_valid(gs) && gs_in_range(room, gs->room_count)); + gs->rooms[room].visited = seen; } sc_bool -gs_room_seen (sc_gameref_t gs, sc_int room) -{ - assert(gs_is_game_valid (gs) && gs_in_range (room, gs->room_count)); - return gs->rooms[room].visited; +gs_room_seen(sc_gameref_t gs, sc_int room) { + assert(gs_is_game_valid(gs) && gs_in_range(room, gs->room_count)); + return gs->rooms[room].visited; } @@ -231,38 +207,33 @@ gs_room_seen (sc_gameref_t gs, sc_int room) * Game accessors and mutators for tasks. */ sc_int -gs_task_count (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->task_count; +gs_task_count(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->task_count; } void -gs_set_task_done (sc_gameref_t gs, sc_int task, sc_bool done) -{ - assert(gs_is_game_valid (gs) && gs_in_range (task, gs->task_count)); - gs->tasks[task].done = done; +gs_set_task_done(sc_gameref_t gs, sc_int task, sc_bool done) { + assert(gs_is_game_valid(gs) && gs_in_range(task, gs->task_count)); + gs->tasks[task].done = done; } void -gs_set_task_scored (sc_gameref_t gs, sc_int task, sc_bool scored) -{ - assert(gs_is_game_valid (gs) && gs_in_range (task, gs->task_count)); - gs->tasks[task].scored = scored; +gs_set_task_scored(sc_gameref_t gs, sc_int task, sc_bool scored) { + assert(gs_is_game_valid(gs) && gs_in_range(task, gs->task_count)); + gs->tasks[task].scored = scored; } sc_bool -gs_task_done (sc_gameref_t gs, sc_int task) -{ - assert(gs_is_game_valid (gs) && gs_in_range (task, gs->task_count)); - return gs->tasks[task].done; +gs_task_done(sc_gameref_t gs, sc_int task) { + assert(gs_is_game_valid(gs) && gs_in_range(task, gs->task_count)); + return gs->tasks[task].done; } sc_bool -gs_task_scored (sc_gameref_t gs, sc_int task) -{ - assert(gs_is_game_valid (gs) && gs_in_range (task, gs->task_count)); - return gs->tasks[task].scored; +gs_task_scored(sc_gameref_t gs, sc_int task) { + assert(gs_is_game_valid(gs) && gs_in_range(task, gs->task_count)); + return gs->tasks[task].scored; } @@ -270,250 +241,213 @@ gs_task_scored (sc_gameref_t gs, sc_int task) * Game accessors and mutators for objects. */ sc_int -gs_object_count (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->object_count; +gs_object_count(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->object_count; } void -gs_set_object_openness (sc_gameref_t gs, sc_int object, sc_int openness) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].openness = openness; +gs_set_object_openness(sc_gameref_t gs, sc_int object, sc_int openness) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].openness = openness; } void -gs_set_object_state (sc_gameref_t gs, sc_int object, sc_int state) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].state = state; +gs_set_object_state(sc_gameref_t gs, sc_int object, sc_int state) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].state = state; } void -gs_set_object_seen (sc_gameref_t gs, sc_int object, sc_bool seen) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].seen = seen; +gs_set_object_seen(sc_gameref_t gs, sc_int object, sc_bool seen) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].seen = seen; } void -gs_set_object_unmoved (sc_gameref_t gs, sc_int object, sc_bool unmoved) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].unmoved = unmoved; +gs_set_object_unmoved(sc_gameref_t gs, sc_int object, sc_bool unmoved) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].unmoved = unmoved; } void -gs_set_object_static_unmoved (sc_gameref_t gs, sc_int object, sc_bool unmoved) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].static_unmoved = unmoved; +gs_set_object_static_unmoved(sc_gameref_t gs, sc_int object, sc_bool unmoved) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].static_unmoved = unmoved; } sc_int -gs_object_openness (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - return gs->objects[object].openness; +gs_object_openness(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + return gs->objects[object].openness; } sc_int -gs_object_state (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - return gs->objects[object].state; +gs_object_state(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + return gs->objects[object].state; } sc_bool -gs_object_seen (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - return gs->objects[object].seen; +gs_object_seen(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + return gs->objects[object].seen; } sc_bool -gs_object_unmoved (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - return gs->objects[object].unmoved; +gs_object_unmoved(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + return gs->objects[object].unmoved; } sc_bool -gs_object_static_unmoved (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - return gs->objects[object].static_unmoved; +gs_object_static_unmoved(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + return gs->objects[object].static_unmoved; } sc_int -gs_object_position (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - return gs->objects[object].position; +gs_object_position(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + return gs->objects[object].position; } sc_int -gs_object_parent (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - return gs->objects[object].parent; +gs_object_parent(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + return gs->objects[object].parent; } static void -gs_object_move_onto_unchecked (sc_gameref_t gs, sc_int object, sc_int onto) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].position = OBJ_ON_OBJECT; - gs->objects[object].parent = onto; +gs_object_move_onto_unchecked(sc_gameref_t gs, sc_int object, sc_int onto) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].position = OBJ_ON_OBJECT; + gs->objects[object].parent = onto; } static void -gs_object_move_into_unchecked (sc_gameref_t gs, sc_int object, sc_int into) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].position = OBJ_IN_OBJECT; - gs->objects[object].parent = into; +gs_object_move_into_unchecked(sc_gameref_t gs, sc_int object, sc_int into) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].position = OBJ_IN_OBJECT; + gs->objects[object].parent = into; } static void -gs_object_make_hidden_unchecked (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].position = OBJ_HIDDEN; - gs->objects[object].parent = -1; +gs_object_make_hidden_unchecked(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].position = OBJ_HIDDEN; + gs->objects[object].parent = -1; } static void -gs_object_player_get_unchecked (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].position = OBJ_HELD_PLAYER; - gs->objects[object].parent = -1; +gs_object_player_get_unchecked(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].position = OBJ_HELD_PLAYER; + gs->objects[object].parent = -1; } static void -gs_object_npc_get_unchecked (sc_gameref_t gs, sc_int object, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].position = OBJ_HELD_NPC; - gs->objects[object].parent = npc; +gs_object_npc_get_unchecked(sc_gameref_t gs, sc_int object, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].position = OBJ_HELD_NPC; + gs->objects[object].parent = npc; } static void -gs_object_player_wear_unchecked (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].position = OBJ_WORN_PLAYER; - gs->objects[object].parent = 0; +gs_object_player_wear_unchecked(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].position = OBJ_WORN_PLAYER; + gs->objects[object].parent = 0; } static void -gs_object_npc_wear_unchecked (sc_gameref_t gs, sc_int object, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].position = OBJ_WORN_NPC; - gs->objects[object].parent = npc; +gs_object_npc_wear_unchecked(sc_gameref_t gs, sc_int object, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].position = OBJ_WORN_NPC; + gs->objects[object].parent = npc; } static void -gs_object_to_room_unchecked (sc_gameref_t gs, sc_int object, sc_int room) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - gs->objects[object].position = room + 1; - gs->objects[object].parent = -1; +gs_object_to_room_unchecked(sc_gameref_t gs, sc_int object, sc_int room) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + gs->objects[object].position = room + 1; + gs->objects[object].parent = -1; } void -gs_object_move_onto (sc_gameref_t gs, sc_int object, sc_int onto) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - if (gs->objects[object].position != OBJ_ON_OBJECT - || gs->objects[object].parent != onto) - { - gs_object_move_onto_unchecked (gs, object, onto); - gs->objects[object].unmoved = FALSE; - } +gs_object_move_onto(sc_gameref_t gs, sc_int object, sc_int onto) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + if (gs->objects[object].position != OBJ_ON_OBJECT + || gs->objects[object].parent != onto) { + gs_object_move_onto_unchecked(gs, object, onto); + gs->objects[object].unmoved = FALSE; + } } void -gs_object_move_into (sc_gameref_t gs, sc_int object, sc_int into) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - if (gs->objects[object].position != OBJ_IN_OBJECT - || gs->objects[object].parent != into) - { - gs_object_move_into_unchecked (gs, object, into); - gs->objects[object].unmoved = FALSE; - } +gs_object_move_into(sc_gameref_t gs, sc_int object, sc_int into) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + if (gs->objects[object].position != OBJ_IN_OBJECT + || gs->objects[object].parent != into) { + gs_object_move_into_unchecked(gs, object, into); + gs->objects[object].unmoved = FALSE; + } } void -gs_object_make_hidden (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - if (gs->objects[object].position != OBJ_HIDDEN) - { - gs_object_make_hidden_unchecked (gs, object); - gs->objects[object].unmoved = FALSE; - } +gs_object_make_hidden(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + if (gs->objects[object].position != OBJ_HIDDEN) { + gs_object_make_hidden_unchecked(gs, object); + gs->objects[object].unmoved = FALSE; + } } void -gs_object_player_get (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - if (gs->objects[object].position != OBJ_HELD_PLAYER) - { - gs_object_player_get_unchecked (gs, object); - gs->objects[object].unmoved = FALSE; - } +gs_object_player_get(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + if (gs->objects[object].position != OBJ_HELD_PLAYER) { + gs_object_player_get_unchecked(gs, object); + gs->objects[object].unmoved = FALSE; + } } void -gs_object_npc_get (sc_gameref_t gs, sc_int object, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - if (gs->objects[object].position != OBJ_HELD_NPC - || gs->objects[object].parent != npc) - { - gs_object_npc_get_unchecked (gs, object, npc); - gs->objects[object].unmoved = FALSE; - } +gs_object_npc_get(sc_gameref_t gs, sc_int object, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + if (gs->objects[object].position != OBJ_HELD_NPC + || gs->objects[object].parent != npc) { + gs_object_npc_get_unchecked(gs, object, npc); + gs->objects[object].unmoved = FALSE; + } } void -gs_object_player_wear (sc_gameref_t gs, sc_int object) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - if (gs->objects[object].position != OBJ_WORN_PLAYER) - { - gs_object_player_wear_unchecked (gs, object); - gs->objects[object].unmoved = FALSE; - } +gs_object_player_wear(sc_gameref_t gs, sc_int object) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + if (gs->objects[object].position != OBJ_WORN_PLAYER) { + gs_object_player_wear_unchecked(gs, object); + gs->objects[object].unmoved = FALSE; + } } void -gs_object_npc_wear (sc_gameref_t gs, sc_int object, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - if (gs->objects[object].position != OBJ_WORN_NPC - || gs->objects[object].parent != npc) - { - gs_object_npc_wear_unchecked (gs, object, npc); - gs->objects[object].unmoved = FALSE; - } +gs_object_npc_wear(sc_gameref_t gs, sc_int object, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + if (gs->objects[object].position != OBJ_WORN_NPC + || gs->objects[object].parent != npc) { + gs_object_npc_wear_unchecked(gs, object, npc); + gs->objects[object].unmoved = FALSE; + } } void -gs_object_to_room (sc_gameref_t gs, sc_int object, sc_int room) -{ - assert(gs_is_game_valid (gs) && gs_in_range (object, gs->object_count)); - if (gs->objects[object].position != room + 1) - { - gs_object_to_room_unchecked (gs, object, room); - gs->objects[object].unmoved = FALSE; - } +gs_object_to_room(sc_gameref_t gs, sc_int object, sc_int room) { + assert(gs_is_game_valid(gs) && gs_in_range(object, gs->object_count)); + if (gs->objects[object].position != room + 1) { + gs_object_to_room_unchecked(gs, object, room); + gs->objects[object].unmoved = FALSE; + } } @@ -521,98 +455,85 @@ gs_object_to_room (sc_gameref_t gs, sc_int object, sc_int room) * Game accessors and mutators for NPCs. */ sc_int -gs_npc_count (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - return gs->npc_count; +gs_npc_count(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + return gs->npc_count; } void -gs_set_npc_location (sc_gameref_t gs, sc_int npc, sc_int location) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - gs->npcs[npc].location = location; +gs_set_npc_location(sc_gameref_t gs, sc_int npc, sc_int location) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + gs->npcs[npc].location = location; } sc_int -gs_npc_location (sc_gameref_t gs, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - return gs->npcs[npc].location; +gs_npc_location(sc_gameref_t gs, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + return gs->npcs[npc].location; } void -gs_set_npc_position (sc_gameref_t gs, sc_int npc, sc_int position) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - gs->npcs[npc].position = position; +gs_set_npc_position(sc_gameref_t gs, sc_int npc, sc_int position) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + gs->npcs[npc].position = position; } sc_int -gs_npc_position (sc_gameref_t gs, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - return gs->npcs[npc].position; +gs_npc_position(sc_gameref_t gs, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + return gs->npcs[npc].position; } void -gs_set_npc_parent (sc_gameref_t gs, sc_int npc, sc_int parent) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - gs->npcs[npc].parent = parent; +gs_set_npc_parent(sc_gameref_t gs, sc_int npc, sc_int parent) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + gs->npcs[npc].parent = parent; } sc_int -gs_npc_parent (sc_gameref_t gs, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - return gs->npcs[npc].parent; +gs_npc_parent(sc_gameref_t gs, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + return gs->npcs[npc].parent; } void -gs_set_npc_seen (sc_gameref_t gs, sc_int npc, sc_bool seen) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - gs->npcs[npc].seen = seen; +gs_set_npc_seen(sc_gameref_t gs, sc_int npc, sc_bool seen) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + gs->npcs[npc].seen = seen; } sc_bool -gs_npc_seen (sc_gameref_t gs, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - return gs->npcs[npc].seen; +gs_npc_seen(sc_gameref_t gs, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + return gs->npcs[npc].seen; } sc_int -gs_npc_walkstep_count (sc_gameref_t gs, sc_int npc) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count)); - return gs->npcs[npc].walkstep_count; +gs_npc_walkstep_count(sc_gameref_t gs, sc_int npc) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count)); + return gs->npcs[npc].walkstep_count; } void -gs_set_npc_walkstep (sc_gameref_t gs, - sc_int npc, sc_int walk, sc_int walkstep) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count) - && gs_in_range (walk, gs->npcs[npc].walkstep_count)); - gs->npcs[npc].walksteps[walk] = walkstep; +gs_set_npc_walkstep(sc_gameref_t gs, + sc_int npc, sc_int walk, sc_int walkstep) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count) + && gs_in_range(walk, gs->npcs[npc].walkstep_count)); + gs->npcs[npc].walksteps[walk] = walkstep; } sc_int -gs_npc_walkstep (sc_gameref_t gs, sc_int npc, sc_int walk) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count) - && gs_in_range (walk, gs->npcs[npc].walkstep_count)); - return gs->npcs[npc].walksteps[walk]; +gs_npc_walkstep(sc_gameref_t gs, sc_int npc, sc_int walk) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count) + && gs_in_range(walk, gs->npcs[npc].walkstep_count)); + return gs->npcs[npc].walksteps[walk]; } void -gs_decrement_npc_walkstep (sc_gameref_t gs, sc_int npc, sc_int walk) -{ - assert(gs_is_game_valid (gs) && gs_in_range (npc, gs->npc_count) - && gs_in_range (walk, gs->npcs[npc].walkstep_count)); - gs->npcs[npc].walksteps[walk]--; +gs_decrement_npc_walkstep(sc_gameref_t gs, sc_int npc, sc_int walk) { + assert(gs_is_game_valid(gs) && gs_in_range(npc, gs->npc_count) + && gs_in_range(walk, gs->npcs[npc].walkstep_count)); + gs->npcs[npc].walksteps[walk]--; } @@ -620,35 +541,31 @@ gs_decrement_npc_walkstep (sc_gameref_t gs, sc_int npc, sc_int walk) * Convenience functions for bulk clearance of references. */ void -gs_clear_npc_references (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - memset (gs->npc_references, - FALSE, gs->npc_count * sizeof (*gs->npc_references)); +gs_clear_npc_references(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + memset(gs->npc_references, + FALSE, gs->npc_count * sizeof(*gs->npc_references)); } void -gs_clear_object_references (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - memset (gs->object_references, - FALSE, gs->object_count * sizeof (*gs->object_references)); +gs_clear_object_references(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + memset(gs->object_references, + FALSE, gs->object_count * sizeof(*gs->object_references)); } void -gs_set_multiple_references (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - memset (gs->multiple_references, - TRUE, gs->object_count * sizeof (*gs->multiple_references)); +gs_set_multiple_references(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + memset(gs->multiple_references, + TRUE, gs->object_count * sizeof(*gs->multiple_references)); } void -gs_clear_multiple_references (sc_gameref_t gs) -{ - assert(gs_is_game_valid (gs)); - memset (gs->multiple_references, - FALSE, gs->object_count * sizeof (*gs->multiple_references)); +gs_clear_multiple_references(sc_gameref_t gs) { + assert(gs_is_game_valid(gs)); + memset(gs->multiple_references, + FALSE, gs->object_count * sizeof(*gs->multiple_references)); } @@ -658,314 +575,294 @@ gs_clear_multiple_references (sc_gameref_t gs) * Create and initialize a game state. */ sc_gameref_t -gs_create (sc_var_setref_t vars, - sc_prop_setref_t bundle, sc_filterref_t filter) -{ - sc_gameref_t game; - sc_vartype_t vt_key[4]; - sc_int index_, bytes; - assert(vars && bundle && filter); - - /* Create the initial state structure. */ - game = (sc_gameref_t)sc_malloc (sizeof (*game)); - game->magic = GAME_MAGIC; - - /* Store the variables, properties bundle, and filter references. */ - game->vars = vars; - game->bundle = bundle; - game->filter = filter; - - /* Set memento to NULL for now; it's added later. */ - game->memento = NULL; - - /* Initialize for no debugger. */ - game->debugger = NULL; - - /* Initialize the undo buffers to NULL for now. */ - game->temporary = NULL; - game->undo = NULL; - game->undo_available = FALSE; - - /* Create rooms state array. */ - vt_key[0].string = "Rooms"; - game->room_count = prop_get_child_count (bundle, "I<-s", vt_key); - game->rooms = (sc_roomstate_t *)sc_malloc (game->room_count * sizeof (*game->rooms)); - - /* Set up initial rooms states. */ - for (index_ = 0; index_ < game->room_count; index_++) - gs_set_room_seen (game, index_, FALSE); - - /* Create objects state array. */ - vt_key[0].string = "Objects"; - game->object_count = prop_get_child_count (bundle, "I<-s", vt_key); - game->objects = (sc_objectstate_t *)sc_malloc (game->object_count * sizeof (*game->objects)); - - /* Set up initial object states. */ - for (index_ = 0; index_ < game->object_count; index_++) - { - const sc_char *inroomdesc; - sc_bool is_static, unmoved; - - vt_key[1].integer = index_; - - vt_key[2].string = "Static"; - is_static = prop_get_boolean (bundle, "B<-sis", vt_key); - if (is_static) - { - sc_int type; - - vt_key[2].string = "Where"; - vt_key[3].string = "Type"; - type = prop_get_integer (bundle, "I<-siss", vt_key); - if (type == ROOMLIST_NPC_PART) - { - sc_int parent; - - game->objects[index_].position = OBJ_PART_NPC; - - vt_key[2].string = "Parent"; - parent = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - game->objects[index_].parent = parent; - } - else - gs_object_make_hidden_unchecked (game, index_); - } - else - { - sc_int initialparent, initialposition; - - vt_key[2].string = "Parent"; - initialparent = prop_get_integer (bundle, "I<-sis", vt_key); - vt_key[2].string = "InitialPosition"; - initialposition = prop_get_integer (bundle, "I<-sis", vt_key); - switch (initialposition) - { - case 0: /* Hidden. */ - gs_object_make_hidden_unchecked (game, index_); - break; - - case 1: /* Held. */ - if (initialparent == 0) /* By player. */ - gs_object_player_get_unchecked (game, index_); - else /* By NPC. */ - gs_object_npc_get_unchecked (game, index_, initialparent - 1); - break; - - case 2: /* In container. */ - gs_object_move_into_unchecked (game, index_, - obj_container_object (game, initialparent)); - break; - - case 3: /* On surface. */ - gs_object_move_onto_unchecked (game, index_, - obj_surface_object (game, initialparent)); - break; - - default: /* In room, or worn by player/NPC. */ - if (initialposition >= 4 - && initialposition < 4 + game->room_count) - { - gs_object_to_room_unchecked (game, - index_, initialposition - 4); - } - else if (initialposition == 4 + game->room_count) - { - if (initialparent == 0) - gs_object_player_wear_unchecked (game, index_); - else - gs_object_npc_wear_unchecked (game, - index_, initialparent - 1); - } - else - { - sc_error ("gs_create: object in out of bounds room, %ld\n", - initialposition - 4 - game->room_count); - gs_object_to_room_unchecked (game, index_, -2); - } - } - } - - vt_key[2].string = "CurrentState"; - gs_set_object_state (game, index_, - prop_get_integer (bundle, "I<-sis", vt_key)); - - vt_key[2].string = "Openable"; - gs_set_object_openness (game, index_, - prop_get_integer (bundle, "I<-sis", vt_key)); - - gs_set_object_seen (game, index_, FALSE); - - vt_key[2].string = "InRoomDesc"; - inroomdesc = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (inroomdesc)) - { - vt_key[2].string = "OnlyWhenNotMoved"; - if (prop_get_integer (bundle, "I<-sis", vt_key) == 1) - unmoved = TRUE; - else - unmoved = FALSE; - } - else - unmoved = FALSE; - gs_set_object_unmoved (game, index_, unmoved); - gs_set_object_static_unmoved (game, index_, TRUE); - } - - /* Create tasks state array. */ - vt_key[0].string = "Tasks"; - game->task_count = prop_get_child_count (bundle, "I<-s", vt_key); - game->tasks = (sc_taskstate_t *)sc_malloc (game->task_count * sizeof (*game->tasks)); - - /* Set up initial tasks states. */ - for (index_ = 0; index_ < game->task_count; index_++) - { - gs_set_task_done (game, index_, FALSE); - gs_set_task_scored (game, index_, FALSE); - } - - /* Create events state array. */ - vt_key[0].string = "Events"; - game->event_count = prop_get_child_count (bundle, "I<-s", vt_key); - game->events = (sc_eventstate_t *)sc_malloc (game->event_count * sizeof (*game->events)); - - /* Set up initial events states. */ - for (index_ = 0; index_ < game->event_count; index_++) - { - sc_int startertype; - - vt_key[1].integer = index_; - vt_key[2].string = "StarterType"; - startertype = prop_get_integer (bundle, "I<-sis", vt_key); - - switch (startertype) - { - case 1: - gs_set_event_state (game, index_, ES_WAITING); - gs_set_event_time (game, index_, 0); - break; - - case 2: - { - sc_int start, end; - - gs_set_event_state (game, index_, ES_WAITING); - vt_key[2].string = "StartTime"; - start = prop_get_integer (bundle, "I<-sis", vt_key); - vt_key[2].string = "EndTime"; - end = prop_get_integer (bundle, "I<-sis", vt_key); - gs_set_event_time (game, index_, sc_randomint (start, end)); - break; - } - - case 3: - gs_set_event_state (game, index_, ES_AWAITING); - gs_set_event_time (game, index_, 0); - break; - } - } - - /* Create NPCs state array. */ - vt_key[0].string = "NPCs"; - game->npc_count = prop_get_child_count (bundle, "I<-s", vt_key); - game->npcs = (sc_npcstate_t *)sc_malloc (game->npc_count * sizeof (*game->npcs)); - - /* Set up initial NPCs states. */ - for (index_ = 0; index_ < game->npc_count; index_++) - { - sc_int walk, walkstep_count; - - gs_set_npc_position (game, index_, 0); - gs_set_npc_parent (game, index_, -1); - gs_set_npc_seen (game, index_, FALSE); - - vt_key[1].integer = index_; - - vt_key[2].string = "StartRoom"; - gs_set_npc_location (game, index_, - prop_get_integer (bundle, "I<-sis", vt_key)); - - vt_key[2].string = "Walks"; - walkstep_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - game->npcs[index_].walkstep_count = walkstep_count; - game->npcs[index_].walksteps = (sc_int *)sc_malloc (walkstep_count - * sizeof (*game->npcs[0].walksteps)); - - for (walk = 0; walk < walkstep_count; walk++) - gs_set_npc_walkstep (game, index_, walk, 0); - } - - /* Set up the player portions of the game state. */ - vt_key[0].string = "Header"; - vt_key[1].string = "StartRoom"; - game->playerroom = prop_get_integer (bundle, "I<-ss", vt_key); - vt_key[0].string = "Globals"; - vt_key[1].string = "ParentObject"; - game->playerparent = prop_get_integer (bundle, "I<-ss", vt_key) - 1; - vt_key[1].string = "Position"; - game->playerposition = prop_get_integer (bundle, "I<-ss", vt_key); - - /* Initialize score notifications from game properties. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "NoScoreNotify"; - game->notify_score_change = !prop_get_boolean (bundle, "B<-ss", vt_key); - - /* Miscellaneous state defaults. */ - game->turns = 0; - game->score = 0; - game->bold_room_names = TRUE; - game->verbose = FALSE; - game->current_room_name = NULL; - game->status_line = NULL; - game->title = NULL; - game->author = NULL; - game->hint_text = NULL; - - /* Resource controls. */ - res_clear_resource (&game->requested_sound); - res_clear_resource (&game->requested_graphic); - res_clear_resource (&game->playing_sound); - res_clear_resource (&game->displayed_graphic); - game->stop_sound = FALSE; - game->sound_active = FALSE; - - /* Initialize wait turns from game properties. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "WaitTurns"; - game->waitturns = prop_get_integer (bundle, "I<-ss", vt_key); - - /* Non-game conveniences. */ - game->is_running = FALSE; - game->has_notified = FALSE; - game->is_admin = FALSE; - game->has_completed = FALSE; - game->waitcounter = 0; - game->do_again = FALSE; - game->redo_sequence = 0; - game->do_restart = FALSE; - game->do_restore = FALSE; - - bytes = game->object_count * sizeof (*game->object_references); - game->object_references = (sc_bool *)sc_malloc (bytes); - memset (game->object_references, FALSE, bytes); - bytes = game->object_count * sizeof (*game->multiple_references); - game->multiple_references = (sc_bool *)sc_malloc (bytes); - memset (game->multiple_references, FALSE, bytes); - - bytes = game->npc_count * sizeof (*game->npc_references); - game->npc_references = (sc_bool *)sc_malloc (bytes); - memset (game->npc_references, FALSE, bytes); - - game->it_object = -1; - game->him_npc = -1; - game->her_npc = -1; - game->it_npc = -1; - - /* Clear the quit jump buffer for tidiness. */ - memset (&game->quitter, 0, sizeof (game->quitter)); - - /* Return the constructed game state. */ - return game; +gs_create(sc_var_setref_t vars, + sc_prop_setref_t bundle, sc_filterref_t filter) { + sc_gameref_t game; + sc_vartype_t vt_key[4]; + sc_int index_, bytes; + assert(vars && bundle && filter); + + /* Create the initial state structure. */ + game = (sc_gameref_t)sc_malloc(sizeof(*game)); + game->magic = GAME_MAGIC; + + /* Store the variables, properties bundle, and filter references. */ + game->vars = vars; + game->bundle = bundle; + game->filter = filter; + + /* Set memento to NULL for now; it's added later. */ + game->memento = NULL; + + /* Initialize for no debugger. */ + game->debugger = NULL; + + /* Initialize the undo buffers to NULL for now. */ + game->temporary = NULL; + game->undo = NULL; + game->undo_available = FALSE; + + /* Create rooms state array. */ + vt_key[0].string = "Rooms"; + game->room_count = prop_get_child_count(bundle, "I<-s", vt_key); + game->rooms = (sc_roomstate_t *)sc_malloc(game->room_count * sizeof(*game->rooms)); + + /* Set up initial rooms states. */ + for (index_ = 0; index_ < game->room_count; index_++) + gs_set_room_seen(game, index_, FALSE); + + /* Create objects state array. */ + vt_key[0].string = "Objects"; + game->object_count = prop_get_child_count(bundle, "I<-s", vt_key); + game->objects = (sc_objectstate_t *)sc_malloc(game->object_count * sizeof(*game->objects)); + + /* Set up initial object states. */ + for (index_ = 0; index_ < game->object_count; index_++) { + const sc_char *inroomdesc; + sc_bool is_static, unmoved; + + vt_key[1].integer = index_; + + vt_key[2].string = "Static"; + is_static = prop_get_boolean(bundle, "B<-sis", vt_key); + if (is_static) { + sc_int type; + + vt_key[2].string = "Where"; + vt_key[3].string = "Type"; + type = prop_get_integer(bundle, "I<-siss", vt_key); + if (type == ROOMLIST_NPC_PART) { + sc_int parent; + + game->objects[index_].position = OBJ_PART_NPC; + + vt_key[2].string = "Parent"; + parent = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + game->objects[index_].parent = parent; + } else + gs_object_make_hidden_unchecked(game, index_); + } else { + sc_int initialparent, initialposition; + + vt_key[2].string = "Parent"; + initialparent = prop_get_integer(bundle, "I<-sis", vt_key); + vt_key[2].string = "InitialPosition"; + initialposition = prop_get_integer(bundle, "I<-sis", vt_key); + switch (initialposition) { + case 0: /* Hidden. */ + gs_object_make_hidden_unchecked(game, index_); + break; + + case 1: /* Held. */ + if (initialparent == 0) /* By player. */ + gs_object_player_get_unchecked(game, index_); + else /* By NPC. */ + gs_object_npc_get_unchecked(game, index_, initialparent - 1); + break; + + case 2: /* In container. */ + gs_object_move_into_unchecked(game, index_, + obj_container_object(game, initialparent)); + break; + + case 3: /* On surface. */ + gs_object_move_onto_unchecked(game, index_, + obj_surface_object(game, initialparent)); + break; + + default: /* In room, or worn by player/NPC. */ + if (initialposition >= 4 + && initialposition < 4 + game->room_count) { + gs_object_to_room_unchecked(game, + index_, initialposition - 4); + } else if (initialposition == 4 + game->room_count) { + if (initialparent == 0) + gs_object_player_wear_unchecked(game, index_); + else + gs_object_npc_wear_unchecked(game, + index_, initialparent - 1); + } else { + sc_error("gs_create: object in out of bounds room, %ld\n", + initialposition - 4 - game->room_count); + gs_object_to_room_unchecked(game, index_, -2); + } + } + } + + vt_key[2].string = "CurrentState"; + gs_set_object_state(game, index_, + prop_get_integer(bundle, "I<-sis", vt_key)); + + vt_key[2].string = "Openable"; + gs_set_object_openness(game, index_, + prop_get_integer(bundle, "I<-sis", vt_key)); + + gs_set_object_seen(game, index_, FALSE); + + vt_key[2].string = "InRoomDesc"; + inroomdesc = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(inroomdesc)) { + vt_key[2].string = "OnlyWhenNotMoved"; + if (prop_get_integer(bundle, "I<-sis", vt_key) == 1) + unmoved = TRUE; + else + unmoved = FALSE; + } else + unmoved = FALSE; + gs_set_object_unmoved(game, index_, unmoved); + gs_set_object_static_unmoved(game, index_, TRUE); + } + + /* Create tasks state array. */ + vt_key[0].string = "Tasks"; + game->task_count = prop_get_child_count(bundle, "I<-s", vt_key); + game->tasks = (sc_taskstate_t *)sc_malloc(game->task_count * sizeof(*game->tasks)); + + /* Set up initial tasks states. */ + for (index_ = 0; index_ < game->task_count; index_++) { + gs_set_task_done(game, index_, FALSE); + gs_set_task_scored(game, index_, FALSE); + } + + /* Create events state array. */ + vt_key[0].string = "Events"; + game->event_count = prop_get_child_count(bundle, "I<-s", vt_key); + game->events = (sc_eventstate_t *)sc_malloc(game->event_count * sizeof(*game->events)); + + /* Set up initial events states. */ + for (index_ = 0; index_ < game->event_count; index_++) { + sc_int startertype; + + vt_key[1].integer = index_; + vt_key[2].string = "StarterType"; + startertype = prop_get_integer(bundle, "I<-sis", vt_key); + + switch (startertype) { + case 1: + gs_set_event_state(game, index_, ES_WAITING); + gs_set_event_time(game, index_, 0); + break; + + case 2: { + sc_int start, end; + + gs_set_event_state(game, index_, ES_WAITING); + vt_key[2].string = "StartTime"; + start = prop_get_integer(bundle, "I<-sis", vt_key); + vt_key[2].string = "EndTime"; + end = prop_get_integer(bundle, "I<-sis", vt_key); + gs_set_event_time(game, index_, sc_randomint(start, end)); + break; + } + + case 3: + gs_set_event_state(game, index_, ES_AWAITING); + gs_set_event_time(game, index_, 0); + break; + } + } + + /* Create NPCs state array. */ + vt_key[0].string = "NPCs"; + game->npc_count = prop_get_child_count(bundle, "I<-s", vt_key); + game->npcs = (sc_npcstate_t *)sc_malloc(game->npc_count * sizeof(*game->npcs)); + + /* Set up initial NPCs states. */ + for (index_ = 0; index_ < game->npc_count; index_++) { + sc_int walk, walkstep_count; + + gs_set_npc_position(game, index_, 0); + gs_set_npc_parent(game, index_, -1); + gs_set_npc_seen(game, index_, FALSE); + + vt_key[1].integer = index_; + + vt_key[2].string = "StartRoom"; + gs_set_npc_location(game, index_, + prop_get_integer(bundle, "I<-sis", vt_key)); + + vt_key[2].string = "Walks"; + walkstep_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + game->npcs[index_].walkstep_count = walkstep_count; + game->npcs[index_].walksteps = (sc_int *)sc_malloc(walkstep_count + * sizeof(*game->npcs[0].walksteps)); + + for (walk = 0; walk < walkstep_count; walk++) + gs_set_npc_walkstep(game, index_, walk, 0); + } + + /* Set up the player portions of the game state. */ + vt_key[0].string = "Header"; + vt_key[1].string = "StartRoom"; + game->playerroom = prop_get_integer(bundle, "I<-ss", vt_key); + vt_key[0].string = "Globals"; + vt_key[1].string = "ParentObject"; + game->playerparent = prop_get_integer(bundle, "I<-ss", vt_key) - 1; + vt_key[1].string = "Position"; + game->playerposition = prop_get_integer(bundle, "I<-ss", vt_key); + + /* Initialize score notifications from game properties. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "NoScoreNotify"; + game->notify_score_change = !prop_get_boolean(bundle, "B<-ss", vt_key); + + /* Miscellaneous state defaults. */ + game->turns = 0; + game->score = 0; + game->bold_room_names = TRUE; + game->verbose = FALSE; + game->current_room_name = NULL; + game->status_line = NULL; + game->title = NULL; + game->author = NULL; + game->hint_text = NULL; + + /* Resource controls. */ + res_clear_resource(&game->requested_sound); + res_clear_resource(&game->requested_graphic); + res_clear_resource(&game->playing_sound); + res_clear_resource(&game->displayed_graphic); + game->stop_sound = FALSE; + game->sound_active = FALSE; + + /* Initialize wait turns from game properties. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "WaitTurns"; + game->waitturns = prop_get_integer(bundle, "I<-ss", vt_key); + + /* Non-game conveniences. */ + game->is_running = FALSE; + game->has_notified = FALSE; + game->is_admin = FALSE; + game->has_completed = FALSE; + game->waitcounter = 0; + game->do_again = FALSE; + game->redo_sequence = 0; + game->do_restart = FALSE; + game->do_restore = FALSE; + + bytes = game->object_count * sizeof(*game->object_references); + game->object_references = (sc_bool *)sc_malloc(bytes); + memset(game->object_references, FALSE, bytes); + bytes = game->object_count * sizeof(*game->multiple_references); + game->multiple_references = (sc_bool *)sc_malloc(bytes); + memset(game->multiple_references, FALSE, bytes); + + bytes = game->npc_count * sizeof(*game->npc_references); + game->npc_references = (sc_bool *)sc_malloc(bytes); + memset(game->npc_references, FALSE, bytes); + + game->it_object = -1; + game->him_npc = -1; + game->her_npc = -1; + game->it_npc = -1; + + /* Clear the quit jump buffer for tidiness. */ + memset(&game->quitter, 0, sizeof(game->quitter)); + + /* Return the constructed game state. */ + return game; } @@ -975,9 +872,8 @@ gs_create (sc_var_setref_t vars, * Return TRUE if pointer is a valid game, FALSE otherwise. */ sc_bool -gs_is_game_valid (sc_gameref_t game) -{ - return game && game->magic == GAME_MAGIC; +gs_is_game_valid(sc_gameref_t game) { + return game && game->magic == GAME_MAGIC; } @@ -988,19 +884,16 @@ gs_is_game_valid (sc_gameref_t game) * if from is NULL, taking care not to leak memory. */ static void -gs_string_copy (sc_char **to_string, const sc_char *from_string) -{ - /* Free any current contents of to_string. */ - sc_free (*to_string); +gs_string_copy(sc_char **to_string, const sc_char *from_string) { + /* Free any current contents of to_string. */ + sc_free(*to_string); - /* Copy from_string if set, otherwise set to_string to NULL. */ - if (from_string) - { - *to_string = (sc_char *)sc_malloc (strlen (from_string) + 1); - strcpy (*to_string, from_string); - } - else - *to_string = NULL; + /* Copy from_string if set, otherwise set to_string to NULL. */ + if (from_string) { + *to_string = (sc_char *)sc_malloc(strlen(from_string) + 1); + strcpy(*to_string, from_string); + } else + *to_string = NULL; } @@ -1011,146 +904,142 @@ gs_string_copy (sc_char **to_string, const sc_char *from_string) * game structure. */ void -gs_copy (sc_gameref_t to, sc_gameref_t from) -{ - const sc_prop_setref_t bundle = from->bundle; - sc_vartype_t vt_key[3]; - sc_int var_count, var, npc; - assert(gs_is_game_valid (to) && gs_is_game_valid (from)); - - /* - * Copy over references to the properties bundle and filter. The debugger - * is specifically excluded, as it's considered to be tied to the game. - */ - to->bundle = from->bundle; - to->filter = from->filter; - - /* Copy over references to the undo buffers. */ - to->temporary = from->temporary; - to->undo = from->undo; - to->undo_available = from->undo_available; - - /* Copy over all variables values. */ - vt_key[0].string = "Variables"; - var_count = prop_get_child_count (bundle, "I<-s", vt_key); - - for (var = 0; var < var_count; var++) - { - const sc_char *name; - sc_int var_type; - - vt_key[1].integer = var; - - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Type"; - var_type = prop_get_integer (bundle, "I<-sis", vt_key); - - switch (var_type) - { - case TAFVAR_NUMERIC: - var_put_integer (to->vars, name, var_get_integer (from->vars, name)); - break; - - case TAFVAR_STRING: - var_put_string (to->vars, name, var_get_string (from->vars, name)); - break; - - default: - sc_fatal ("gs_copy: unknown variable type, %ld\n", var_type); - } - } - - /* Copy over the variable timestamp. */ - var_set_elapsed_seconds (to->vars, var_get_elapsed_seconds (from->vars)); - - /* Copy over room states. */ - assert(to->room_count == from->room_count); - memcpy (to->rooms, from->rooms, from->room_count * sizeof (*from->rooms)); - - /* Copy over object states. */ - assert(to->object_count == from->object_count); - memcpy (to->objects, from->objects, - from->object_count * sizeof (*from->objects)); - - /* Copy over task states. */ - assert(to->task_count == from->task_count); - memcpy (to->tasks, from->tasks, from->task_count * sizeof (*from->tasks)); - - /* Copy over event states. */ - assert(to->event_count == from->event_count); - memcpy (to->events, from->events, from->event_count * sizeof (*from->events)); - - /* Copy over NPC states individually, to avoid walks problems. */ - for (npc = 0; npc < from->npc_count; npc++) - { - to->npcs[npc].location = from->npcs[npc].location; - to->npcs[npc].position = from->npcs[npc].position; - to->npcs[npc].parent = from->npcs[npc].parent; - to->npcs[npc].seen = from->npcs[npc].seen; - to->npcs[npc].walkstep_count = from->npcs[npc].walkstep_count; - - /* Copy over NPC walks information. */ - assert(to->npcs[npc].walkstep_count == from->npcs[npc].walkstep_count); - memcpy (to->npcs[npc].walksteps, from->npcs[npc].walksteps, - from->npcs[npc].walkstep_count - * sizeof (*from->npcs[npc].walksteps)); - } - - /* Copy over player information. */ - to->playerroom = from->playerroom; - to->playerposition = from->playerposition; - to->playerparent = from->playerparent; - - /* - * Copy over miscellaneous other details. Specifically exclude bold rooms, - * verbose, and score notification, so that they are invariant across copies, - * particularly undo/restore. - */ - to->turns = from->turns; - to->score = from->score; - - gs_string_copy (&to->current_room_name, from->current_room_name); - gs_string_copy (&to->status_line, from->status_line); - gs_string_copy (&to->title, from->title); - gs_string_copy (&to->author, from->author); - gs_string_copy (&to->hint_text, from->hint_text); - - /* - * Specifically exclude playing sound and displayed graphic from the copy - * so that they remain invariant across game copies. - */ - to->requested_sound = from->requested_sound; - to->requested_graphic = from->requested_graphic; - to->stop_sound = from->stop_sound; - - to->is_running = from->is_running; - to->has_notified = from->has_notified; - to->is_admin = from->is_admin; - to->has_completed = from->has_completed; - - to->waitturns = from->waitturns; - - to->waitcounter = from->waitcounter; - to->do_again = from->do_again; - to->redo_sequence = from->redo_sequence; - to->do_restart = from->do_restart; - to->do_restore = from->do_restore; - - memcpy (to->object_references, from->object_references, - from->object_count * sizeof (*from->object_references)); - memcpy (to->multiple_references, from->multiple_references, - from->object_count * sizeof (*from->multiple_references)); - memcpy (to->npc_references, from->npc_references, - from->npc_count * sizeof (*from->npc_references)); - - to->it_object = from->it_object; - to->him_npc = from->him_npc; - to->her_npc = from->her_npc; - to->it_npc = from->it_npc; - - /* Copy over the quit jump buffer. */ - memcpy (&to->quitter, &from->quitter, sizeof (from->quitter)); +gs_copy(sc_gameref_t to, sc_gameref_t from) { + const sc_prop_setref_t bundle = from->bundle; + sc_vartype_t vt_key[3]; + sc_int var_count, var, npc; + assert(gs_is_game_valid(to) && gs_is_game_valid(from)); + + /* + * Copy over references to the properties bundle and filter. The debugger + * is specifically excluded, as it's considered to be tied to the game. + */ + to->bundle = from->bundle; + to->filter = from->filter; + + /* Copy over references to the undo buffers. */ + to->temporary = from->temporary; + to->undo = from->undo; + to->undo_available = from->undo_available; + + /* Copy over all variables values. */ + vt_key[0].string = "Variables"; + var_count = prop_get_child_count(bundle, "I<-s", vt_key); + + for (var = 0; var < var_count; var++) { + const sc_char *name; + sc_int var_type; + + vt_key[1].integer = var; + + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Type"; + var_type = prop_get_integer(bundle, "I<-sis", vt_key); + + switch (var_type) { + case TAFVAR_NUMERIC: + var_put_integer(to->vars, name, var_get_integer(from->vars, name)); + break; + + case TAFVAR_STRING: + var_put_string(to->vars, name, var_get_string(from->vars, name)); + break; + + default: + sc_fatal("gs_copy: unknown variable type, %ld\n", var_type); + } + } + + /* Copy over the variable timestamp. */ + var_set_elapsed_seconds(to->vars, var_get_elapsed_seconds(from->vars)); + + /* Copy over room states. */ + assert(to->room_count == from->room_count); + memcpy(to->rooms, from->rooms, from->room_count * sizeof(*from->rooms)); + + /* Copy over object states. */ + assert(to->object_count == from->object_count); + memcpy(to->objects, from->objects, + from->object_count * sizeof(*from->objects)); + + /* Copy over task states. */ + assert(to->task_count == from->task_count); + memcpy(to->tasks, from->tasks, from->task_count * sizeof(*from->tasks)); + + /* Copy over event states. */ + assert(to->event_count == from->event_count); + memcpy(to->events, from->events, from->event_count * sizeof(*from->events)); + + /* Copy over NPC states individually, to avoid walks problems. */ + for (npc = 0; npc < from->npc_count; npc++) { + to->npcs[npc].location = from->npcs[npc].location; + to->npcs[npc].position = from->npcs[npc].position; + to->npcs[npc].parent = from->npcs[npc].parent; + to->npcs[npc].seen = from->npcs[npc].seen; + to->npcs[npc].walkstep_count = from->npcs[npc].walkstep_count; + + /* Copy over NPC walks information. */ + assert(to->npcs[npc].walkstep_count == from->npcs[npc].walkstep_count); + memcpy(to->npcs[npc].walksteps, from->npcs[npc].walksteps, + from->npcs[npc].walkstep_count + * sizeof(*from->npcs[npc].walksteps)); + } + + /* Copy over player information. */ + to->playerroom = from->playerroom; + to->playerposition = from->playerposition; + to->playerparent = from->playerparent; + + /* + * Copy over miscellaneous other details. Specifically exclude bold rooms, + * verbose, and score notification, so that they are invariant across copies, + * particularly undo/restore. + */ + to->turns = from->turns; + to->score = from->score; + + gs_string_copy(&to->current_room_name, from->current_room_name); + gs_string_copy(&to->status_line, from->status_line); + gs_string_copy(&to->title, from->title); + gs_string_copy(&to->author, from->author); + gs_string_copy(&to->hint_text, from->hint_text); + + /* + * Specifically exclude playing sound and displayed graphic from the copy + * so that they remain invariant across game copies. + */ + to->requested_sound = from->requested_sound; + to->requested_graphic = from->requested_graphic; + to->stop_sound = from->stop_sound; + + to->is_running = from->is_running; + to->has_notified = from->has_notified; + to->is_admin = from->is_admin; + to->has_completed = from->has_completed; + + to->waitturns = from->waitturns; + + to->waitcounter = from->waitcounter; + to->do_again = from->do_again; + to->redo_sequence = from->redo_sequence; + to->do_restart = from->do_restart; + to->do_restore = from->do_restore; + + memcpy(to->object_references, from->object_references, + from->object_count * sizeof(*from->object_references)); + memcpy(to->multiple_references, from->multiple_references, + from->object_count * sizeof(*from->multiple_references)); + memcpy(to->npc_references, from->npc_references, + from->npc_count * sizeof(*from->npc_references)); + + to->it_object = from->it_object; + to->him_npc = from->him_npc; + to->her_npc = from->her_npc; + to->it_npc = from->it_npc; + + /* Copy over the quit jump buffer. */ + memcpy(&to->quitter, &from->quitter, sizeof(from->quitter)); } @@ -1160,35 +1049,34 @@ gs_copy (sc_gameref_t to, sc_gameref_t from) * Free all the memory associated with a game state. */ void -gs_destroy (sc_gameref_t game) -{ - sc_int npc; - assert(gs_is_game_valid (game)); - - /* Free the malloc'ed state arrays. */ - sc_free (game->rooms); - sc_free (game->objects); - sc_free (game->tasks); - sc_free (game->events); - for (npc = 0; npc < game->npc_count; npc++) - sc_free (game->npcs[npc].walksteps); - sc_free (game->npcs); - - /* Free the malloc'ed object and NPC references. */ - sc_free (game->object_references); - sc_free (game->multiple_references); - sc_free (game->npc_references); - - /* Free malloc'ed game strings. */ - sc_free (game->current_room_name); - sc_free (game->status_line); - sc_free (game->title); - sc_free (game->author); - sc_free (game->hint_text); - - /* Poison and free the game state itself. */ - memset (game, 0xaa, sizeof (*game)); - sc_free (game); +gs_destroy(sc_gameref_t game) { + sc_int npc; + assert(gs_is_game_valid(game)); + + /* Free the malloc'ed state arrays. */ + sc_free(game->rooms); + sc_free(game->objects); + sc_free(game->tasks); + sc_free(game->events); + for (npc = 0; npc < game->npc_count; npc++) + sc_free(game->npcs[npc].walksteps); + sc_free(game->npcs); + + /* Free the malloc'ed object and NPC references. */ + sc_free(game->object_references); + sc_free(game->multiple_references); + sc_free(game->npc_references); + + /* Free malloc'ed game strings. */ + sc_free(game->current_room_name); + sc_free(game->status_line); + sc_free(game->title); + sc_free(game->author); + sc_free(game->hint_text); + + /* Poison and free the game state itself. */ + memset(game, 0xaa, sizeof(*game)); + sc_free(game); } } // End of namespace Adrift diff --git a/engines/glk/adrift/scgamest.h b/engines/glk/adrift/scgamest.h index 4287551bfd..a246d05164 100644 --- a/engines/glk/adrift/scgamest.h +++ b/engines/glk/adrift/scgamest.h @@ -67,9 +67,9 @@ struct sc_taskstate_s { typedef sc_taskstate_s sc_taskstate_t; /* Event state structure, holds event state, and timing information. */ -enum -{ ES_WAITING = 1, - ES_RUNNING = 2, ES_AWAITING = 3, ES_FINISHED = 4, ES_PAUSED = 5 +enum { + ES_WAITING = 1, + ES_RUNNING = 2, ES_AWAITING = 3, ES_FINISHED = 4, ES_PAUSED = 5 }; struct sc_eventstate_s { sc_int state; diff --git a/engines/glk/adrift/scinterf.cpp b/engines/glk/adrift/scinterf.cpp index cc8e1235d7..c5e53e959d 100644 --- a/engines/glk/adrift/scinterf.cpp +++ b/engines/glk/adrift/scinterf.cpp @@ -46,37 +46,28 @@ static sc_uint if_trace_flags = 0; * tries to ensure correct compile options. */ static void -if_initialize (void) -{ - static sc_bool initialized = FALSE; - - /* Only do checks on the first call. */ - if (!initialized) - { - /* Make a few quick checks on types and type sizes. */ - if (sizeof (sc_byte) != 1 || sizeof (sc_char) != 1) - { - sc_error ("if_initialize: sizeof sc_byte or sc_char" - " is not 1, check compile options\n"); - } - else if (sizeof (sc_uint) < 4 || sizeof (sc_int) < 4) - { - sc_error ("if_initialize: sizeof sc_uint or sc_int" - " is not at least 4, check compile options\n"); - } - else if (sizeof (sc_uint) > 8 || sizeof (sc_int) > 8) - { - sc_error ("if_initialize: sizeof sc_uint or sc_int" - " is more than 8, check compile options\n"); - } - else if (!((sc_uint) -1 > 0)) - { - sc_error ("if_initialize: sc_uint appears not to be unsigned," - " check compile options\n"); - } - - initialized = TRUE; - } +if_initialize(void) { + static sc_bool initialized = FALSE; + + /* Only do checks on the first call. */ + if (!initialized) { + /* Make a few quick checks on types and type sizes. */ + if (sizeof(sc_byte) != 1 || sizeof(sc_char) != 1) { + sc_error("if_initialize: sizeof sc_byte or sc_char" + " is not 1, check compile options\n"); + } else if (sizeof(sc_uint) < 4 || sizeof(sc_int) < 4) { + sc_error("if_initialize: sizeof sc_uint or sc_int" + " is not at least 4, check compile options\n"); + } else if (sizeof(sc_uint) > 8 || sizeof(sc_int) > 8) { + sc_error("if_initialize: sizeof sc_uint or sc_int" + " is more than 8, check compile options\n"); + } else if (!((sc_uint) - 1 > 0)) { + sc_error("if_initialize: sc_uint appears not to be unsigned," + " check compile options\n"); + } + + initialized = TRUE; + } } @@ -89,37 +80,34 @@ if_initialize (void) * tracing setting to all modules that support it. */ static sc_bool -if_bool (sc_uint flag) -{ - return flag ? TRUE : FALSE; +if_bool(sc_uint flag) { + return flag ? TRUE : FALSE; } void -sc_set_trace_flags (sc_uint trace_flags) -{ - if_initialize (); - - /* Save the value for queries. */ - if_trace_flags = trace_flags; - - /* Propagate tracing to modules that support it. */ - parse_debug_trace (if_bool (trace_flags & SC_TRACE_PARSE)); - prop_debug_trace (if_bool (trace_flags & SC_TRACE_PROPERTIES)); - var_debug_trace (if_bool (trace_flags & SC_TRACE_VARIABLES)); - uip_debug_trace (if_bool (trace_flags & SC_TRACE_PARSER)); - lib_debug_trace (if_bool (trace_flags & SC_TRACE_LIBRARY)); - evt_debug_trace (if_bool (trace_flags & SC_TRACE_EVENTS)); - npc_debug_trace (if_bool (trace_flags & SC_TRACE_NPCS)); - obj_debug_trace (if_bool (trace_flags & SC_TRACE_OBJECTS)); - task_debug_trace (if_bool (trace_flags & SC_TRACE_TASKS)); - restr_debug_trace (if_bool (trace_flags & SC_TRACE_TASKS)); - pf_debug_trace (if_bool (trace_flags & SC_TRACE_PRINTFILTER)); +sc_set_trace_flags(sc_uint trace_flags) { + if_initialize(); + + /* Save the value for queries. */ + if_trace_flags = trace_flags; + + /* Propagate tracing to modules that support it. */ + parse_debug_trace(if_bool(trace_flags & SC_TRACE_PARSE)); + prop_debug_trace(if_bool(trace_flags & SC_TRACE_PROPERTIES)); + var_debug_trace(if_bool(trace_flags & SC_TRACE_VARIABLES)); + uip_debug_trace(if_bool(trace_flags & SC_TRACE_PARSER)); + lib_debug_trace(if_bool(trace_flags & SC_TRACE_LIBRARY)); + evt_debug_trace(if_bool(trace_flags & SC_TRACE_EVENTS)); + npc_debug_trace(if_bool(trace_flags & SC_TRACE_NPCS)); + obj_debug_trace(if_bool(trace_flags & SC_TRACE_OBJECTS)); + task_debug_trace(if_bool(trace_flags & SC_TRACE_TASKS)); + restr_debug_trace(if_bool(trace_flags & SC_TRACE_TASKS)); + pf_debug_trace(if_bool(trace_flags & SC_TRACE_PRINTFILTER)); } sc_bool -if_get_trace_flag (sc_uint bitmask) -{ - return if_bool (if_trace_flags & bitmask); +if_get_trace_flag(sc_uint bitmask) { + return if_bool(if_trace_flags & bitmask); } @@ -135,59 +123,51 @@ if_get_trace_flag (sc_uint bitmask) * Call OS-specific print function for the given arguments. */ static void -if_print_string_common (const sc_char *string, - void (*print_string_function) (const sc_char *)) -{ - assert (string); +if_print_string_common(const sc_char *string, + void (*print_string_function)(const sc_char *)) { + assert(string); - if (string[0] != NUL) - print_string_function (string); + if (string[0] != NUL) + print_string_function(string); } void -if_print_string (const sc_char *string) -{ - if_print_string_common (string, os_print_string); +if_print_string(const sc_char *string) { + if_print_string_common(string, os_print_string); } void -if_print_debug (const sc_char *string) -{ - if_print_string_common (string, os_print_string_debug); +if_print_debug(const sc_char *string) { + if_print_string_common(string, os_print_string_debug); } static void -if_print_character_common (sc_char character, - void (*print_string_function) (const sc_char *)) -{ - if (character != NUL) - { - sc_char buffer[2]; +if_print_character_common(sc_char character, + void (*print_string_function)(const sc_char *)) { + if (character != NUL) { + sc_char buffer[2]; - buffer[0] = character; - buffer[1] = NUL; - print_string_function (buffer); - } + buffer[0] = character; + buffer[1] = NUL; + print_string_function(buffer); + } } void -if_print_character (sc_char character) -{ - if_print_character_common (character, os_print_string); +if_print_character(sc_char character) { + if_print_character_common(character, os_print_string); } void -if_print_debug_character (sc_char character) -{ - if_print_character_common (character, os_print_string_debug); +if_print_debug_character(sc_char character) { + if_print_character_common(character, os_print_string_debug); } void -if_print_tag (sc_int tag, const sc_char *arg) -{ - assert (arg); +if_print_tag(sc_int tag, const sc_char *arg) { + assert(arg); - os_print_tag (tag, arg); + os_print_tag(tag, arg); } @@ -200,43 +180,38 @@ if_print_tag (sc_int tag, const sc_char *arg) * before returning it to the caller. */ static void -if_read_line_common (sc_char *buffer, sc_int length, - sc_bool (*read_line_function) (sc_char *, sc_int)) -{ - sc_bool is_line_available; - sc_int last; - assert (buffer && length > 0); - - /* Loop until valid player input is available. */ - do - { - /* Space first with a blank line, and clear the buffer. */ - if_print_character ('\n'); - memset (buffer, NUL, length); - - is_line_available = read_line_function (buffer, length); - if (g_vm->shouldQuit()) - return; - } - while (!is_line_available); - - /* Drop any trailing newline/return. */ - last = strlen (buffer) - 1; - while (last >= 0 - && (buffer[last] == CARRIAGE_RETURN || buffer[last] == NEWLINE)) - buffer[last--] = NUL; +if_read_line_common(sc_char *buffer, sc_int length, + sc_bool(*read_line_function)(sc_char *, sc_int)) { + sc_bool is_line_available; + sc_int last; + assert(buffer && length > 0); + + /* Loop until valid player input is available. */ + do { + /* Space first with a blank line, and clear the buffer. */ + if_print_character('\n'); + memset(buffer, NUL, length); + + is_line_available = read_line_function(buffer, length); + if (g_vm->shouldQuit()) + return; + } while (!is_line_available); + + /* Drop any trailing newline/return. */ + last = strlen(buffer) - 1; + while (last >= 0 + && (buffer[last] == CARRIAGE_RETURN || buffer[last] == NEWLINE)) + buffer[last--] = NUL; } void -if_read_line (sc_char *buffer, sc_int length) -{ - if_read_line_common (buffer, length, os_read_line); +if_read_line(sc_char *buffer, sc_int length) { + if_read_line_common(buffer, length, os_read_line); } void -if_read_debug (sc_char *buffer, sc_int length) -{ - if_read_line_common (buffer, length, os_read_line_debug); +if_read_debug(sc_char *buffer, sc_int length) { + if_read_line_common(buffer, length, os_read_line_debug); } @@ -246,9 +221,8 @@ if_read_debug (sc_char *buffer, sc_int length) * Call OS-specific confirm function. */ sc_bool -if_confirm (sc_int type) -{ - return os_confirm (type); +if_confirm(sc_int type) { + return os_confirm(type); } @@ -261,31 +235,27 @@ if_confirm (sc_int type) * Call OS-specific functions for saving and restoring games. */ void * -if_open_saved_game (sc_bool is_save) -{ - return os_open_file (is_save); +if_open_saved_game(sc_bool is_save) { + return os_open_file(is_save); } void -if_write_saved_game (void *opaque, const sc_byte *buffer, sc_int length) -{ - assert (buffer); +if_write_saved_game(void *opaque, const sc_byte *buffer, sc_int length) { + assert(buffer); - os_write_file (opaque, buffer, length); + os_write_file(opaque, buffer, length); } sc_int -if_read_saved_game (void *opaque, sc_byte *buffer, sc_int length) -{ - assert (buffer); +if_read_saved_game(void *opaque, sc_byte *buffer, sc_int length) { + assert(buffer); - return os_read_file (opaque, buffer, length); + return os_read_file(opaque, buffer, length); } void -if_close_saved_game (void *opaque) -{ - os_close_file (opaque); +if_close_saved_game(void *opaque) { + os_close_file(opaque); } @@ -295,11 +265,10 @@ if_close_saved_game (void *opaque) * Call OS-specific hint display function. */ void -if_display_hints (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); +if_display_hints(sc_gameref_t game) { + assert(gs_is_game_valid(game)); - os_display_hints ((sc_game) game); + os_display_hints((sc_game) game); } @@ -310,21 +279,19 @@ if_display_hints (sc_gameref_t game) * Call OS-specific sound and graphic handler functions. */ void -if_update_sound (const sc_char *filename, - sc_int sound_offset, sc_int sound_length, - sc_bool is_looping) -{ - if (strlen (filename) > 0) - os_play_sound (filename, sound_offset, sound_length, is_looping); - else - os_stop_sound (); +if_update_sound(const sc_char *filename, + sc_int sound_offset, sc_int sound_length, + sc_bool is_looping) { + if (strlen(filename) > 0) + os_play_sound(filename, sound_offset, sound_length, is_looping); + else + os_stop_sound(); } void -if_update_graphic (const sc_char *filename, - sc_int graphic_offset, sc_int graphic_length) -{ - os_show_graphic (filename, graphic_offset, graphic_length); +if_update_graphic(const sc_char *filename, + sc_int graphic_offset, sc_int graphic_length) { + os_show_graphic(filename, graphic_offset, graphic_length); } @@ -335,17 +302,15 @@ if_update_graphic (const sc_char *filename, * Return a version string and Adrift emulation level. */ const sc_char * -sc_scare_version (void) -{ - if_initialize (); - return "SCARE " SCARE_VERSION SCARE_PATCH_LEVEL; +sc_scare_version(void) { + if_initialize(); + return "SCARE " SCARE_VERSION SCARE_PATCH_LEVEL; } sc_int -sc_scare_emulation (void) -{ - if_initialize (); - return SCARE_EMULATION; +sc_scare_emulation(void) { + if_initialize(); + return SCARE_EMULATION; } @@ -357,24 +322,23 @@ sc_scare_emulation (void) * calls from filename and stream variants. */ static sc_int -if_file_read_callback (void *opaque, sc_byte *buffer, sc_int length) { - Common::SeekableReadStream *stream = (Common::SeekableReadStream *)opaque; - sc_int bytes; +if_file_read_callback(void *opaque, sc_byte *buffer, sc_int length) { + Common::SeekableReadStream *stream = (Common::SeekableReadStream *)opaque; + sc_int bytes; - bytes = stream->read(buffer, length); - if (stream->err()) - sc_error ("if_file_read_callback: warning: read error\n"); + bytes = stream->read(buffer, length); + if (stream->err()) + sc_error("if_file_read_callback: warning: read error\n"); - return bytes; + return bytes; } -static void if_file_write_callback (void *opaque, const sc_byte *buffer, sc_int length) -{ - Common::WriteStream *stream = (Common::WriteStream *) opaque; +static void if_file_write_callback(void *opaque, const sc_byte *buffer, sc_int length) { + Common::WriteStream *stream = (Common::WriteStream *) opaque; - stream->write(buffer, length); - if (stream->err()) - sc_error ("if_file_write_callback: warning: write error\n"); + stream->write(buffer, length); + if (stream->err()) + sc_error("if_file_write_callback: warning: write error\n"); } @@ -387,53 +351,49 @@ static void if_file_write_callback (void *opaque, const sc_byte *buffer, sc_int * and _stream() variants are adapters for run_create(). */ sc_game -sc_game_from_filename (const sc_char *filename) { - Common::File *stream; - sc_game game; +sc_game_from_filename(const sc_char *filename) { + Common::File *stream; + sc_game game; - if_initialize (); - if (!filename) - { - sc_error ("sc_game_from_filename: nullptr filename\n"); - return nullptr; - } + if_initialize(); + if (!filename) { + sc_error("sc_game_from_filename: nullptr filename\n"); + return nullptr; + } - stream = new Common::File(); - if (!stream->open(filename)) { - delete stream; - sc_error ("sc_game_from_filename: fopen error\n"); - return nullptr; - } + stream = new Common::File(); + if (!stream->open(filename)) { + delete stream; + sc_error("sc_game_from_filename: fopen error\n"); + return nullptr; + } - game = run_create (if_file_read_callback, stream); - delete stream; + game = run_create(if_file_read_callback, stream); + delete stream; - return game; + return game; } -sc_game sc_game_from_stream (Common::SeekableReadStream *stream) { - if_initialize (); - if (!stream) - { - sc_error ("sc_game_from_stream: nullptr stream\n"); - return nullptr; - } +sc_game sc_game_from_stream(Common::SeekableReadStream *stream) { + if_initialize(); + if (!stream) { + sc_error("sc_game_from_stream: nullptr stream\n"); + return nullptr; + } - return run_create (if_file_read_callback, stream); + return run_create(if_file_read_callback, stream); } sc_game -sc_game_from_callback (sc_int (*callback) (void *, sc_byte *, sc_int), - void *opaque) -{ - if_initialize (); - if (!callback) - { - sc_error ("sc_game_from_callback: nullptr callback\n"); - return nullptr; - } +sc_game_from_callback(sc_int(*callback)(void *, sc_byte *, sc_int), + void *opaque) { + if_initialize(); + if (!callback) { + sc_error("sc_game_from_callback: nullptr callback\n"); + return nullptr; + } - return run_create (callback, opaque); + return run_create(callback, opaque); } @@ -444,20 +404,18 @@ sc_game_from_callback (sc_int (*callback) (void *, sc_byte *, sc_int), * is a valid game. Returns TRUE on game error, FALSE if okay. */ static sc_bool -if_game_error (sc_gameref_t game, const sc_char *function_name) -{ - /* Check for invalid game -- null pointer or bad magic. */ - if (!gs_is_game_valid (game)) - { - if (game) - sc_error ("%s: invalid game\n", function_name); - else - sc_error ("%s: nullptr game\n", function_name); - return TRUE; - } +if_game_error(sc_gameref_t game, const sc_char *function_name) { + /* Check for invalid game -- null pointer or bad magic. */ + if (!gs_is_game_valid(game)) { + if (game) + sc_error("%s: invalid game\n", function_name); + else + sc_error("%s: nullptr game\n", function_name); + return TRUE; + } - /* No game error. */ - return FALSE; + /* No game error. */ + return FALSE; } @@ -478,69 +436,63 @@ if_game_error (sc_gameref_t game, const sc_char *function_name) * be restored. sc_undo_game_turn() behaves like sc_load_game(). */ void -sc_interpret_game (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_interpret_game(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_interpret_game")) - return; + if (if_game_error(game_, "sc_interpret_game")) + return; - run_interpret (game_); + run_interpret(game_); } void -sc_restart_game (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_restart_game(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_restart_game")) - return; + if (if_game_error(game_, "sc_restart_game")) + return; - run_restart (game_); + run_restart(game_); } sc_bool -sc_save_game (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_save_game(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_save_game")) - return FALSE; + if (if_game_error(game_, "sc_save_game")) + return FALSE; - return run_save_prompted (game_); + return run_save_prompted(game_); } sc_bool -sc_load_game (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_load_game(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_load_game")) - return FALSE; + if (if_game_error(game_, "sc_load_game")) + return FALSE; - return run_restore_prompted (game_); + return run_restore_prompted(game_); } sc_bool -sc_undo_game_turn (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_undo_game_turn(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_undo_game_turn")) - return FALSE; + if (if_game_error(game_, "sc_undo_game_turn")) + return FALSE; - return run_undo (game_); + return run_undo(game_); } void -sc_quit_game (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_quit_game(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_quit_game")) - return; + if (if_game_error(game_, "sc_quit_game")) + return; - run_quit (game_); + run_quit(game_); } @@ -559,132 +511,119 @@ sc_quit_game (sc_game game) * streams. */ sc_bool -sc_save_game_to_filename (sc_game game, const sc_char *filename) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - Common::OutSaveFile *sf; +sc_save_game_to_filename(sc_game game, const sc_char *filename) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + Common::OutSaveFile *sf; - if (if_game_error (game_, "sc_save_game_to_filename")) - return FALSE; + if (if_game_error(game_, "sc_save_game_to_filename")) + return FALSE; - if (!filename) - { - sc_error ("sc_save_game_to_filename: nullptr filename\n"); - return FALSE; - } + if (!filename) { + sc_error("sc_save_game_to_filename: nullptr filename\n"); + return FALSE; + } - sf = g_system->getSavefileManager()->openForSaving(filename); - if (!sf) { - sc_error ("sc_save_game_to_filename: fopen error\n"); - return FALSE; - } + sf = g_system->getSavefileManager()->openForSaving(filename); + if (!sf) { + sc_error("sc_save_game_to_filename: fopen error\n"); + return FALSE; + } - run_save(game_, if_file_write_callback, sf); - sf->finalize(); - delete sf; + run_save(game_, if_file_write_callback, sf); + sf->finalize(); + delete sf; - return TRUE; + return TRUE; } void -sc_save_game_to_stream (sc_game game, Common::SeekableReadStream *stream) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_save_game_to_stream(sc_game game, Common::SeekableReadStream *stream) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_save_game_to_stream")) - return; + if (if_game_error(game_, "sc_save_game_to_stream")) + return; - if (!stream) - { - sc_error ("sc_save_game_to_stream: nullptr stream\n"); - return; - } + if (!stream) { + sc_error("sc_save_game_to_stream: nullptr stream\n"); + return; + } - run_save (game_, if_file_write_callback, stream); + run_save(game_, if_file_write_callback, stream); } void -sc_save_game_to_callback (sc_game game, - void (*callback) (void *, const sc_byte *, sc_int), - void *opaque) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_save_game_to_callback(sc_game game, + void (*callback)(void *, const sc_byte *, sc_int), + void *opaque) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_save_game_to_callback")) - return; + if (if_game_error(game_, "sc_save_game_to_callback")) + return; - if (!callback) - { - sc_error ("sc_save_game_to_callback: nullptr callback\n"); - return; - } + if (!callback) { + sc_error("sc_save_game_to_callback: nullptr callback\n"); + return; + } - run_save (game_, callback, opaque); + run_save(game_, callback, opaque); } sc_bool -sc_load_game_from_filename (sc_game game, const sc_char *filename) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - Common::InSaveFile *sf; - sc_bool status; +sc_load_game_from_filename(sc_game game, const sc_char *filename) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + Common::InSaveFile *sf; + sc_bool status; - if (if_game_error (game_, "sc_load_game_from_filename")) - return FALSE; + if (if_game_error(game_, "sc_load_game_from_filename")) + return FALSE; - if (!filename) - { - sc_error ("sc_load_game_from_filename: nullptr filename\n"); - return FALSE; - } + if (!filename) { + sc_error("sc_load_game_from_filename: nullptr filename\n"); + return FALSE; + } - sf = g_system->getSavefileManager()->openForLoading(filename); - if (!sf) - { - sc_error ("sc_load_game_from_filename: fopen error\n"); - return FALSE; - } + sf = g_system->getSavefileManager()->openForLoading(filename); + if (!sf) { + sc_error("sc_load_game_from_filename: fopen error\n"); + return FALSE; + } - status = run_restore (game_, if_file_read_callback, sf); - delete sf; + status = run_restore(game_, if_file_read_callback, sf); + delete sf; - return status; + return status; } sc_bool -sc_load_game_from_stream (sc_game game, Common::SeekableReadStream *stream) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_load_game_from_stream(sc_game game, Common::SeekableReadStream *stream) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_load_game_from_stream")) - return FALSE; + if (if_game_error(game_, "sc_load_game_from_stream")) + return FALSE; - if (!stream) - { - sc_error ("sc_load_game_from_stream: nullptr stream\n"); - return FALSE; - } + if (!stream) { + sc_error("sc_load_game_from_stream: nullptr stream\n"); + return FALSE; + } - return run_restore (game_, if_file_read_callback, stream); + return run_restore(game_, if_file_read_callback, stream); } sc_bool -sc_load_game_from_callback (sc_game game, - sc_int (*callback) (void *, sc_byte *, sc_int), - void *opaque) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_load_game_from_callback(sc_game game, + sc_int(*callback)(void *, sc_byte *, sc_int), + void *opaque) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_load_game_from_callback")) - return FALSE; + if (if_game_error(game_, "sc_load_game_from_callback")) + return FALSE; - if (!callback) - { - sc_error ("sc_load_game_from_callback: nullptr callback\n"); - return FALSE; - } + if (!callback) { + sc_error("sc_load_game_from_callback: nullptr callback\n"); + return FALSE; + } - return run_restore (game_, callback, opaque); + return run_restore(game_, callback, opaque); } @@ -694,14 +633,13 @@ sc_load_game_from_callback (sc_game game, * Called by the OS-specific layer to free run context memory. */ void -sc_free_game (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_free_game(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_free_game")) - return; + if (if_game_error(game_, "sc_free_game")) + return; - run_destroy (game_); + run_destroy(game_); } @@ -725,206 +663,191 @@ sc_free_game (sc_game game) * Return a few attributes of a game. */ sc_bool -sc_is_game_running (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_is_game_running(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_is_game_running")) - return FALSE; + if (if_game_error(game_, "sc_is_game_running")) + return FALSE; - return run_is_running (game_); + return run_is_running(game_); } const sc_char * -sc_get_game_name (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_char *retval; +sc_get_game_name(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_char *retval; - if (if_game_error (game_, "sc_get_game_name")) - return "[invalid game]"; + if (if_game_error(game_, "sc_get_game_name")) + return "[invalid game]"; - run_get_attributes (game_, &retval, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr); - return retval; + run_get_attributes(game_, &retval, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr); + return retval; } const sc_char * -sc_get_game_author (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_char *retval; +sc_get_game_author(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_char *retval; - if (if_game_error (game_, "sc_get_game_author")) - return "[invalid game]"; + if (if_game_error(game_, "sc_get_game_author")) + return "[invalid game]"; - run_get_attributes (game_, nullptr, &retval, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr); - return retval; + run_get_attributes(game_, nullptr, &retval, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr); + return retval; } const sc_char * -sc_get_game_compile_date (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_char *retval; +sc_get_game_compile_date(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_char *retval; - if (if_game_error (game_, "sc_get_game_compile_date")) - return "[invalid game]"; + if (if_game_error(game_, "sc_get_game_compile_date")) + return "[invalid game]"; - run_get_attributes (game_, nullptr, nullptr, &retval, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, &retval, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + return retval; } sc_int -sc_get_game_turns (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_int retval; +sc_get_game_turns(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_int retval; - if (if_game_error (game_, "sc_get_game_turns")) - return 0; + if (if_game_error(game_, "sc_get_game_turns")) + return 0; - run_get_attributes (game_, nullptr, nullptr, nullptr, &retval, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, &retval, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + return retval; } sc_int -sc_get_game_score (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_int retval; +sc_get_game_score(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_int retval; - if (if_game_error (game_, "sc_get_game_score")) - return 0; + if (if_game_error(game_, "sc_get_game_score")) + return 0; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, &retval, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, &retval, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + return retval; } sc_int -sc_get_game_max_score (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_int retval; +sc_get_game_max_score(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_int retval; - if (if_game_error (game_, "sc_get_game_max_score")) - return 0; + if (if_game_error(game_, "sc_get_game_max_score")) + return 0; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, &retval, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, &retval, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + return retval; } const sc_char * -sc_get_game_room (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_char *retval; +sc_get_game_room(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_char *retval; - if (if_game_error (game_, "sc_get_game_room")) - return "[invalid game]"; + if (if_game_error(game_, "sc_get_game_room")) + return "[invalid game]"; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &retval, - nullptr, nullptr, nullptr, nullptr, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &retval, + nullptr, nullptr, nullptr, nullptr, nullptr); + return retval; } const sc_char * -sc_get_game_status_line (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_char *retval; +sc_get_game_status_line(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_char *retval; - if (if_game_error (game_, "sc_get_game_status_line")) - return "[invalid game]"; + if (if_game_error(game_, "sc_get_game_status_line")) + return "[invalid game]"; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - &retval, nullptr, nullptr, nullptr, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + &retval, nullptr, nullptr, nullptr, nullptr); + return retval; } const sc_char * -sc_get_game_preferred_font (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_char *retval; +sc_get_game_preferred_font(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_char *retval; - if (if_game_error (game_, "sc_get_game_preferred_font")) - return "[invalid game]"; + if (if_game_error(game_, "sc_get_game_preferred_font")) + return "[invalid game]"; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, &retval, nullptr, nullptr, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &retval, nullptr, nullptr, nullptr); + return retval; } sc_bool -sc_get_game_bold_room_names (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_bool retval; +sc_get_game_bold_room_names(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_bool retval; - if (if_game_error (game_, "sc_get_game_bold_room_names")) - return FALSE; + if (if_game_error(game_, "sc_get_game_bold_room_names")) + return FALSE; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, &retval, nullptr, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, &retval, nullptr, nullptr); + return retval; } sc_bool -sc_get_game_verbose (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_bool retval; +sc_get_game_verbose(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_bool retval; - if (if_game_error (game_, "sc_get_game_verbose")) - return FALSE; + if (if_game_error(game_, "sc_get_game_verbose")) + return FALSE; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, &retval, nullptr); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, &retval, nullptr); + return retval; } sc_bool -sc_get_game_notify_score_change (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_bool retval; +sc_get_game_notify_score_change(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_bool retval; - if (if_game_error (game_, "sc_get_game_notify_score_change")) - return FALSE; + if (if_game_error(game_, "sc_get_game_notify_score_change")) + return FALSE; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, &retval); - return retval; + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, &retval); + return retval; } sc_bool -sc_has_game_completed (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_has_game_completed(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_has_game_completed")) - return FALSE; + if (if_game_error(game_, "sc_has_game_completed")) + return FALSE; - return run_has_completed (game_); + return run_has_completed(game_); } sc_bool -sc_is_game_undo_available (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_is_game_undo_available(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_is_game_undo_available")) - return FALSE; + if (if_game_error(game_, "sc_is_game_undo_available")) + return FALSE; - return run_is_undo_available (game_); + return run_is_undo_available(game_); } @@ -936,45 +859,42 @@ sc_is_game_undo_available (sc_game game) * Set a few attributes of a game. */ void -sc_set_game_bold_room_names (sc_game game, sc_bool flag) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_bool bold, verbose, notify; +sc_set_game_bold_room_names(sc_game game, sc_bool flag) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_bool bold, verbose, notify; - if (if_game_error (game_, "sc_set_game_bold_room_names")) - return; + if (if_game_error(game_, "sc_set_game_bold_room_names")) + return; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, &bold, &verbose, ¬ify); - run_set_attributes (game_, flag, verbose, notify); + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, &bold, &verbose, ¬ify); + run_set_attributes(game_, flag, verbose, notify); } void -sc_set_game_verbose (sc_game game, sc_bool flag) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_bool bold, verbose, notify; +sc_set_game_verbose(sc_game game, sc_bool flag) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_bool bold, verbose, notify; - if (if_game_error (game_, "sc_set_game_verbose")) - return; + if (if_game_error(game_, "sc_set_game_verbose")) + return; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, &bold, &verbose, ¬ify); - run_set_attributes (game_, bold, flag, notify); + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, &bold, &verbose, ¬ify); + run_set_attributes(game_, bold, flag, notify); } void -sc_set_game_notify_score_change (sc_game game, sc_bool flag) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - sc_bool bold, verbose, notify; +sc_set_game_notify_score_change(sc_game game, sc_bool flag) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + sc_bool bold, verbose, notify; - if (if_game_error (game_, "sc_set_game_notify_score_change")) - return; + if (if_game_error(game_, "sc_set_game_notify_score_change")) + return; - run_get_attributes (game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, &bold, &verbose, ¬ify); - run_set_attributes (game_, bold, verbose, flag); + run_get_attributes(game_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, &bold, &verbose, ¬ify); + run_set_attributes(game_, bold, verbose, flag); } @@ -985,25 +905,23 @@ sc_set_game_notify_score_change (sc_game game, sc_bool flag) * Indicate the game's use of resources. */ sc_bool -sc_does_game_use_sounds (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_does_game_use_sounds(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_does_game_use_sounds")) - return FALSE; + if (if_game_error(game_, "sc_does_game_use_sounds")) + return FALSE; - return res_has_sound (game_); + return res_has_sound(game_); } sc_bool -sc_does_game_use_graphics (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_does_game_use_graphics(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_does_game_use_graphics")) - return FALSE; + if (if_game_error(game_, "sc_does_game_use_graphics")) + return FALSE; - return res_has_graphics (game_); + return res_has_graphics(game_); } @@ -1017,82 +935,73 @@ sc_does_game_use_graphics (sc_game game) * Iterate currently available hints, and return strings for a hint. */ sc_game_hint -sc_get_first_game_hint (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_get_first_game_hint(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_get_first_game_hint")) - return nullptr; + if (if_game_error(game_, "sc_get_first_game_hint")) + return nullptr; - return run_hint_iterate (game_, nullptr); + return run_hint_iterate(game_, nullptr); } sc_game_hint -sc_get_next_game_hint (sc_game game, sc_game_hint hint) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_hintref_t hint_ = (const sc_hintref_t)hint; +sc_get_next_game_hint(sc_game game, sc_game_hint hint) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_hintref_t hint_ = (const sc_hintref_t)hint; - if (if_game_error (game_, "sc_get_next_game_hint")) - return nullptr; - if (!hint_) - { - sc_error ("sc_get_next_game_hint: nullptr hint\n"); - return nullptr; - } + if (if_game_error(game_, "sc_get_next_game_hint")) + return nullptr; + if (!hint_) { + sc_error("sc_get_next_game_hint: nullptr hint\n"); + return nullptr; + } - return run_hint_iterate (game_, hint_); + return run_hint_iterate(game_, hint_); } const sc_char * -sc_get_game_hint_question (sc_game game, sc_game_hint hint) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_hintref_t hint_ = (const sc_hintref_t)hint; +sc_get_game_hint_question(sc_game game, sc_game_hint hint) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_hintref_t hint_ = (const sc_hintref_t)hint; - if (if_game_error (game_, "sc_get_game_hint_question")) - return nullptr; - if (!hint_) - { - sc_error ("sc_get_game_hint_question: nullptr hint\n"); - return nullptr; - } + if (if_game_error(game_, "sc_get_game_hint_question")) + return nullptr; + if (!hint_) { + sc_error("sc_get_game_hint_question: nullptr hint\n"); + return nullptr; + } - return run_get_hint_question (game_, hint_); + return run_get_hint_question(game_, hint_); } const sc_char * -sc_get_game_subtle_hint (sc_game game, sc_game_hint hint) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_hintref_t hint_ = (const sc_hintref_t)hint; +sc_get_game_subtle_hint(sc_game game, sc_game_hint hint) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_hintref_t hint_ = (const sc_hintref_t)hint; - if (if_game_error (game_, "sc_get_game_subtle_hint")) - return nullptr; - if (!hint_) - { - sc_error ("sc_get_game_subtle_hint: nullptr hint\n"); - return nullptr; - } + if (if_game_error(game_, "sc_get_game_subtle_hint")) + return nullptr; + if (!hint_) { + sc_error("sc_get_game_subtle_hint: nullptr hint\n"); + return nullptr; + } - return run_get_subtle_hint (game_, hint_); + return run_get_subtle_hint(game_, hint_); } const sc_char * -sc_get_game_unsubtle_hint (sc_game game, sc_game_hint hint) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; - const sc_hintref_t hint_ = (const sc_hintref_t)hint; +sc_get_game_unsubtle_hint(sc_game game, sc_game_hint hint) { + const sc_gameref_t game_ = (const sc_gameref_t)game; + const sc_hintref_t hint_ = (const sc_hintref_t)hint; - if (if_game_error (game_, "sc_get_game_unsubtle_hint")) - return nullptr; - if (!hint_) - { - sc_error ("sc_get_game_unsubtle_hint: nullptr hint\n"); - return nullptr; - } + if (if_game_error(game_, "sc_get_game_unsubtle_hint")) + return nullptr; + if (!hint_) { + sc_error("sc_get_game_unsubtle_hint: nullptr hint\n"); + return nullptr; + } - return run_get_unsubtle_hint (game_, hint_); + return run_get_unsubtle_hint(game_, hint_); } @@ -1104,36 +1013,33 @@ sc_get_game_unsubtle_hint (sc_game game, sc_game_hint hint) * Enable, disable, and query game debugging, and run a single debug command. */ void -sc_set_game_debugger_enabled (sc_game game, sc_bool flag) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_set_game_debugger_enabled(sc_game game, sc_bool flag) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_set_game_debugger_enabled")) - return; + if (if_game_error(game_, "sc_set_game_debugger_enabled")) + return; - debug_set_enabled (game_, flag); + debug_set_enabled(game_, flag); } sc_bool -sc_get_game_debugger_enabled (sc_game game) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_get_game_debugger_enabled(sc_game game) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_get_game_debugger_enabled")) - return FALSE; + if (if_game_error(game_, "sc_get_game_debugger_enabled")) + return FALSE; - return debug_get_enabled (game_); + return debug_get_enabled(game_); } sc_bool -sc_run_game_debugger_command (sc_game game, const sc_char *debug_command) -{ - const sc_gameref_t game_ = (const sc_gameref_t)game; +sc_run_game_debugger_command(sc_game game, const sc_char *debug_command) { + const sc_gameref_t game_ = (const sc_gameref_t)game; - if (if_game_error (game_, "sc_run_game_debugger_command")) - return FALSE; + if (if_game_error(game_, "sc_run_game_debugger_command")) + return FALSE; - return debug_run_command (game_, debug_command); + return debug_run_command(game_, debug_command); } @@ -1144,21 +1050,18 @@ sc_run_game_debugger_command (sc_game game, const sc_char *debug_command) * Set the interpreter locale, and get the currently set locale. */ sc_bool -sc_set_locale (const sc_char *name) -{ - if (!name) - { - sc_error ("sc_set_locale: nullptr name\n"); - return FALSE; - } +sc_set_locale(const sc_char *name) { + if (!name) { + sc_error("sc_set_locale: nullptr name\n"); + return FALSE; + } - return loc_set_locale (name); + return loc_set_locale(name); } const sc_char * -sc_get_locale (void) -{ - return loc_get_locale (); +sc_get_locale(void) { + return loc_get_locale(); } @@ -1170,24 +1073,21 @@ sc_get_locale (void) * for random number generators. */ void -sc_set_portable_random (sc_bool flag) -{ - if (flag) - sc_set_congruential_random (); - else - sc_set_platform_random (); +sc_set_portable_random(sc_bool flag) { + if (flag) + sc_set_congruential_random(); + else + sc_set_platform_random(); } void -sc_reseed_random_sequence (sc_uint new_seed) -{ - if (new_seed == 0) - { - sc_error ("sc_reseed_random_sequence: new_seed may not be 0\n"); - return; - } - - sc_seed_random (new_seed); +sc_reseed_random_sequence(sc_uint new_seed) { + if (new_seed == 0) { + sc_error("sc_reseed_random_sequence: new_seed may not be 0\n"); + return; + } + + sc_seed_random(new_seed); } } // End of namespace Adrift diff --git a/engines/glk/adrift/sclibrar.cpp b/engines/glk/adrift/sclibrar.cpp index 8f97a7c05a..bfa1711aea 100644 --- a/engines/glk/adrift/sclibrar.cpp +++ b/engines/glk/adrift/sclibrar.cpp @@ -40,10 +40,10 @@ namespace Adrift { /* Assorted definitions and constants. */ static const sc_char NUL = '\0'; static const sc_char COMMA = ','; -enum -{ SECS_PER_MINUTE = 60, - MINS_PER_HOUR = 60, - SECS_PER_HOUR = 3600 +enum { + SECS_PER_MINUTE = 60, + MINS_PER_HOUR = 60, + SECS_PER_HOUR = 3600 }; enum { LIB_ALLOCATION_AVOIDANCE_SIZE = 128 }; @@ -59,25 +59,24 @@ static sc_bool lib_trace = FALSE; * with ALRs. */ void -lib_warn_battle_system (void) -{ - if_print_tag (SC_TAG_FONT, "size=16"); - if_print_string ("SCARE WARNING"); - if_print_tag (SC_TAG_ENDFONT, ""); +lib_warn_battle_system(void) { + if_print_tag(SC_TAG_FONT, "size=16"); + if_print_string("SCARE WARNING"); + if_print_tag(SC_TAG_ENDFONT, ""); - if_print_string ( - "\n\nThe game uses Adrift's Battle System, something not fully supported" - " by this release of SCARE.\n\n"); + if_print_string( + "\n\nThe game uses Adrift's Battle System, something not fully supported" + " by this release of SCARE.\n\n"); - if_print_string ( - "SCARE will still run the game, but it will not create character" - " battles where they would normally occur. For some games, this may" - " be perfectly okay, as the Battle System is sometimes turned on" - " by accident in a game, but never actually used. For others, though," - " the omission of this feature may be more serious.\n\n"); + if_print_string( + "SCARE will still run the game, but it will not create character" + " battles where they would normally occur. For some games, this may" + " be perfectly okay, as the Battle System is sometimes turned on" + " by accident in a game, but never actually used. For others, though," + " the omission of this feature may be more serious.\n\n"); - if_print_string ("Please press a key to continue...\n\n"); - if_print_tag (SC_TAG_WAITKEY, ""); + if_print_string("Please press a key to continue...\n\n"); + if_print_tag(SC_TAG_WAITKEY, ""); } @@ -87,34 +86,31 @@ lib_warn_battle_system (void) * Return a random member of a roomgroup. */ sc_int -lib_random_roomgroup_member (sc_gameref_t game, sc_int roomgroup) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int count, room; +lib_random_roomgroup_member(sc_gameref_t game, sc_int roomgroup) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int count, room; - /* Get the count of rooms in the group. */ - vt_key[0].string = "RoomGroups"; - vt_key[1].integer = roomgroup; - vt_key[2].string = "List2"; - count = prop_get_child_count (bundle, "I<-sis", vt_key); - if (count == 0) - { - sc_fatal ("lib_random_roomgroup_member:" - " no rooms in group %ld\n", roomgroup); - } + /* Get the count of rooms in the group. */ + vt_key[0].string = "RoomGroups"; + vt_key[1].integer = roomgroup; + vt_key[2].string = "List2"; + count = prop_get_child_count(bundle, "I<-sis", vt_key); + if (count == 0) { + sc_fatal("lib_random_roomgroup_member:" + " no rooms in group %ld\n", roomgroup); + } - /* Pick a room at random and return it. */ - vt_key[3].integer = sc_randomint (0, count - 1); - room = prop_get_integer (bundle, "I<-sisi", vt_key); + /* Pick a room at random and return it. */ + vt_key[3].integer = sc_randomint(0, count - 1); + room = prop_get_integer(bundle, "I<-sisi", vt_key); - if (lib_trace) - { - sc_trace ("Library: random room for group %ld is %ld\n", - roomgroup, room); - } + if (lib_trace) { + sc_trace("Library: random room for group %ld is %ld\n", + roomgroup, room); + } - return room; + return room; } @@ -124,129 +120,123 @@ lib_random_roomgroup_member (sc_gameref_t game, sc_int roomgroup) * Return TRUE if a particular alternate room description should be used. */ static sc_bool -lib_use_room_alt (sc_gameref_t game, sc_int room, sc_int alt) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int type; - sc_bool retval; - - /* Get alternate type. */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Alts"; - vt_key[3].integer = alt; - vt_key[4].string = "Type"; - type = prop_get_integer (bundle, "I<-sisis", vt_key); - - /* Select based on type. */ - retval = FALSE; - switch (type) - { - case 0: /* Task. */ - { - sc_int var2, var3; - - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - if (var2 == 0) /* No task. */ - retval = TRUE; - else - { - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - - retval = gs_task_done (game, var2 - 1) == !(var3 != 0); - } - break; - } - - case 1: /* Stateful object. */ - { - sc_int var2, var3, object; - - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - if (var2 == 0) /* No object. */ - retval = TRUE; - else - { - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - - object = obj_stateful_index (game, var2 - 1); - retval = restr_pass_task_object_state (game, object + 1, var3 - 1); - } - break; - } - - case 2: /* Player condition. */ - { - sc_int var2, var3, object; - - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - - if (var3 == 0) - { - switch (var2) - { - case 0: case 2: case 5: - retval = TRUE; - break; - case 1: case 3: case 4: - retval = FALSE; - break; - default: - sc_fatal ("lib_use_room_alt:" - " invalid player condition, %ld\n", var2); - } - break; - } - - if (var2 == 2 || var2 == 3) - object = obj_wearable_object (game, var3 - 1); - else - object = obj_dynamic_object (game, var3 - 1); - - switch (var2) - { - case 0: /* Isn't holding (or wearing). */ - retval = gs_object_position (game, object) != OBJ_HELD_PLAYER - && gs_object_position (game, object) != OBJ_WORN_PLAYER; - break; - case 1: /* Is holding (or wearing). */ - retval = gs_object_position (game, object) == OBJ_HELD_PLAYER - || gs_object_position (game, object) == OBJ_WORN_PLAYER; - break; - case 2: /* Isn't wearing. */ - retval = gs_object_position (game, object) != OBJ_WORN_PLAYER; - break; - case 3: /* Is wearing. */ - retval = gs_object_position (game, object) == OBJ_WORN_PLAYER; - break; - case 4: /* Isn't in the same room as. */ - retval = !obj_indirectly_in_room (game, - object, gs_playerroom (game)); - break; - case 5: /* Is in the same room as. */ - retval = obj_indirectly_in_room (game, - object, gs_playerroom (game)); - break; - default: - sc_fatal ("lib_use_room_alt:" - " invalid player condition, %ld\n", var2); - } - break; - } - - default: - sc_fatal ("lib_use_room_alt: invalid type, %ld\n", type); - } - - return retval; +lib_use_room_alt(sc_gameref_t game, sc_int room, sc_int alt) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int type; + sc_bool retval; + + /* Get alternate type. */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Alts"; + vt_key[3].integer = alt; + vt_key[4].string = "Type"; + type = prop_get_integer(bundle, "I<-sisis", vt_key); + + /* Select based on type. */ + retval = FALSE; + switch (type) { + case 0: { /* Task. */ + sc_int var2, var3; + + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + if (var2 == 0) /* No task. */ + retval = TRUE; + else { + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + + retval = gs_task_done(game, var2 - 1) == !(var3 != 0); + } + break; + } + + case 1: { /* Stateful object. */ + sc_int var2, var3, object; + + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + if (var2 == 0) /* No object. */ + retval = TRUE; + else { + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + + object = obj_stateful_index(game, var2 - 1); + retval = restr_pass_task_object_state(game, object + 1, var3 - 1); + } + break; + } + + case 2: { /* Player condition. */ + sc_int var2, var3, object; + + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + + if (var3 == 0) { + switch (var2) { + case 0: + case 2: + case 5: + retval = TRUE; + break; + case 1: + case 3: + case 4: + retval = FALSE; + break; + default: + sc_fatal("lib_use_room_alt:" + " invalid player condition, %ld\n", var2); + } + break; + } + + if (var2 == 2 || var2 == 3) + object = obj_wearable_object(game, var3 - 1); + else + object = obj_dynamic_object(game, var3 - 1); + + switch (var2) { + case 0: /* Isn't holding (or wearing). */ + retval = gs_object_position(game, object) != OBJ_HELD_PLAYER + && gs_object_position(game, object) != OBJ_WORN_PLAYER; + break; + case 1: /* Is holding (or wearing). */ + retval = gs_object_position(game, object) == OBJ_HELD_PLAYER + || gs_object_position(game, object) == OBJ_WORN_PLAYER; + break; + case 2: /* Isn't wearing. */ + retval = gs_object_position(game, object) != OBJ_WORN_PLAYER; + break; + case 3: /* Is wearing. */ + retval = gs_object_position(game, object) == OBJ_WORN_PLAYER; + break; + case 4: /* Isn't in the same room as. */ + retval = !obj_indirectly_in_room(game, + object, gs_playerroom(game)); + break; + case 5: /* Is in the same room as. */ + retval = obj_indirectly_in_room(game, + object, gs_playerroom(game)); + break; + default: + sc_fatal("lib_use_room_alt:" + " invalid player condition, %ld\n", var2); + } + break; + } + + default: + sc_fatal("lib_use_room_alt: invalid type, %ld\n", type); + } + + return retval; } @@ -258,61 +248,54 @@ lib_use_room_alt (sc_gameref_t game, sc_int room, sc_int alt) * no alt overrides the default room long description. */ static sc_int -lib_find_starting_alt (sc_gameref_t game, sc_int room) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int alt_count, alt, retval; - - /* Get count of room alternates. */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Alts"; - alt_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - /* Search backwards for a method-0 or method-1 overriding description. */ - retval = -1; - for (alt = alt_count - 1; alt >= 0; alt--) - { - sc_int method; - - vt_key[3].integer = alt; - vt_key[4].string = "DisplayRoom"; - method = prop_get_integer (bundle, "I<-sisis", vt_key); - - if (!(method == 0 || method == 1)) - continue; - - if (lib_use_room_alt (game, room, alt)) - { - const sc_char *m1; - - vt_key[3].integer = alt; - vt_key[4].string = "M1"; - m1 = prop_get_string (bundle, "S<-sisis", vt_key); - if (!sc_strempty (m1)) - { - retval = alt; - break; - } - } - else - { - const sc_char *m2; - - vt_key[3].integer = alt; - vt_key[4].string = "M2"; - m2 = prop_get_string (bundle, "S<-sisis", vt_key); - if (!sc_strempty (m2)) - { - retval = alt; - break; - } - } - } - - /* Return the index of the base alt, or -1 if none found. */ - return retval; +lib_find_starting_alt(sc_gameref_t game, sc_int room) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int alt_count, alt, retval; + + /* Get count of room alternates. */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Alts"; + alt_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + /* Search backwards for a method-0 or method-1 overriding description. */ + retval = -1; + for (alt = alt_count - 1; alt >= 0; alt--) { + sc_int method; + + vt_key[3].integer = alt; + vt_key[4].string = "DisplayRoom"; + method = prop_get_integer(bundle, "I<-sisis", vt_key); + + if (!(method == 0 || method == 1)) + continue; + + if (lib_use_room_alt(game, room, alt)) { + const sc_char *m1; + + vt_key[3].integer = alt; + vt_key[4].string = "M1"; + m1 = prop_get_string(bundle, "S<-sisis", vt_key); + if (!sc_strempty(m1)) { + retval = alt; + break; + } + } else { + const sc_char *m2; + + vt_key[3].integer = alt; + vt_key[4].string = "M2"; + m2 = prop_get_string(bundle, "S<-sisis", vt_key); + if (!sc_strempty(m2)) { + retval = alt; + break; + } + } + } + + /* Return the index of the base alt, or -1 if none found. */ + return retval; } @@ -323,78 +306,71 @@ lib_find_starting_alt (sc_gameref_t game, sc_int room) * Get/print out the name for a given room. */ const sc_char * -lib_get_room_name (sc_gameref_t game, sc_int room) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int alt_count, alt, start; - const sc_char *name; - - /* Get the basic room name, and the count of room alternates. */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - vt_key[2].string = "Alts"; - alt_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - /* Get our starting point in the alts list. */ - start = lib_find_starting_alt (game, room); - - /* - * Run forwards through all alts lower than our starting point, or all alts - * if no starting point found. - */ - for (alt = (start != -1) ? start : 0; alt < alt_count; alt++) - { - /* Ignore all non-method-2 alts except for the starter. */ - if (alt != start) - { - sc_int method; - - vt_key[3].integer = alt; - vt_key[4].string = "DisplayRoom"; - method = prop_get_integer (bundle, "I<-sisis", vt_key); - - if (method != 2) - continue; - } - - /* If this alt offers a name change, note it and continue. */ - if (lib_use_room_alt (game, room, alt)) - { - const sc_char *changed; - - vt_key[3].integer = alt; - vt_key[4].string = "Changed"; - changed = prop_get_string (bundle, "S<-sisis", vt_key); - if (!sc_strempty (changed)) - name = changed; - } - } - - /* Return the final selected name. */ - return name; +lib_get_room_name(sc_gameref_t game, sc_int room) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int alt_count, alt, start; + const sc_char *name; + + /* Get the basic room name, and the count of room alternates. */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + vt_key[2].string = "Alts"; + alt_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + /* Get our starting point in the alts list. */ + start = lib_find_starting_alt(game, room); + + /* + * Run forwards through all alts lower than our starting point, or all alts + * if no starting point found. + */ + for (alt = (start != -1) ? start : 0; alt < alt_count; alt++) { + /* Ignore all non-method-2 alts except for the starter. */ + if (alt != start) { + sc_int method; + + vt_key[3].integer = alt; + vt_key[4].string = "DisplayRoom"; + method = prop_get_integer(bundle, "I<-sisis", vt_key); + + if (method != 2) + continue; + } + + /* If this alt offers a name change, note it and continue. */ + if (lib_use_room_alt(game, room, alt)) { + const sc_char *changed; + + vt_key[3].integer = alt; + vt_key[4].string = "Changed"; + changed = prop_get_string(bundle, "S<-sisis", vt_key); + if (!sc_strempty(changed)) + name = changed; + } + } + + /* Return the final selected name. */ + return name; } void -lib_print_room_name (sc_gameref_t game, sc_int room) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_char *name; +lib_print_room_name(sc_gameref_t game, sc_int room) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_char *name; - /* Print the room name, possibly in bold. */ - name = lib_get_room_name (game, room); - if (game->bold_room_names) - { - pf_buffer_tag (filter, SC_TAG_BOLD); - pf_buffer_string (filter, name); - pf_buffer_tag (filter, SC_TAG_ENDBOLD); - } - else - pf_buffer_string (filter, name); - pf_buffer_character (filter, '\n'); + /* Print the room name, possibly in bold. */ + name = lib_get_room_name(game, room); + if (game->bold_room_names) { + pf_buffer_tag(filter, SC_TAG_BOLD); + pf_buffer_string(filter, name); + pf_buffer_tag(filter, SC_TAG_ENDBOLD); + } else + pf_buffer_string(filter, name); + pf_buffer_character(filter, '\n'); } @@ -407,110 +383,96 @@ lib_print_room_name (sc_gameref_t game, sc_int room) * prefix. */ static void -lib_print_object_np (sc_gameref_t game, sc_int object) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *prefix, *normalized, *name; - - /* Get the object's prefix. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - - /* - * Normalize by skipping any leading "a"/"an"/"some", replacing it instead - * with "the", and skipping any odd "the" already present. If no prefix at - * all, add a "the " anyway. - * - * TODO This is empirical, based on observed Adrift Runner behavior, and - * what it's _really_ supposed to do is a mystery. This routine has been a - * real PITA. - */ - normalized = prefix; - if (sc_compare_word (prefix, "a", 1)) - { - normalized = prefix + 1; - pf_buffer_string (filter, "the"); - } - else if (sc_compare_word (prefix, "an", 2)) - { - normalized = prefix + 2; - pf_buffer_string (filter, "the"); - } - else if (sc_compare_word (prefix, "the", 3)) - { - normalized = prefix + 3; - pf_buffer_string (filter, "the"); - } - else if (sc_compare_word (prefix, "some", 4)) - { - normalized = prefix + 4; - pf_buffer_string (filter, "the"); - } - else if (sc_strempty (prefix)) - pf_buffer_string (filter, "the "); - - /* - * If the remaining normalized prefix isn't empty, print it, and a space. - * If it is, then consider adding a space to any "the" printed above, except - * for the one done for empty prefixes, that is. - */ - if (!sc_strempty (normalized)) - { - pf_buffer_string (filter, normalized); - pf_buffer_character (filter, ' '); - } - else if (normalized > prefix) - pf_buffer_character (filter, ' '); - - /* - * Print the object's name; here we also look for a leading article and - * strip if found -- some games may avoid prefix and do this instead. - */ - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - if (sc_compare_word (name, "a", 1)) - name += 1; - else if (sc_compare_word (name, "an", 2)) - name += 2; - else if (sc_compare_word (name, "the", 3)) - name += 3; - else if (sc_compare_word (name, "some", 4)) - name += 4; - pf_buffer_string (filter, name); +lib_print_object_np(sc_gameref_t game, sc_int object) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *prefix, *normalized, *name; + + /* Get the object's prefix. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + + /* + * Normalize by skipping any leading "a"/"an"/"some", replacing it instead + * with "the", and skipping any odd "the" already present. If no prefix at + * all, add a "the " anyway. + * + * TODO This is empirical, based on observed Adrift Runner behavior, and + * what it's _really_ supposed to do is a mystery. This routine has been a + * real PITA. + */ + normalized = prefix; + if (sc_compare_word(prefix, "a", 1)) { + normalized = prefix + 1; + pf_buffer_string(filter, "the"); + } else if (sc_compare_word(prefix, "an", 2)) { + normalized = prefix + 2; + pf_buffer_string(filter, "the"); + } else if (sc_compare_word(prefix, "the", 3)) { + normalized = prefix + 3; + pf_buffer_string(filter, "the"); + } else if (sc_compare_word(prefix, "some", 4)) { + normalized = prefix + 4; + pf_buffer_string(filter, "the"); + } else if (sc_strempty(prefix)) + pf_buffer_string(filter, "the "); + + /* + * If the remaining normalized prefix isn't empty, print it, and a space. + * If it is, then consider adding a space to any "the" printed above, except + * for the one done for empty prefixes, that is. + */ + if (!sc_strempty(normalized)) { + pf_buffer_string(filter, normalized); + pf_buffer_character(filter, ' '); + } else if (normalized > prefix) + pf_buffer_character(filter, ' '); + + /* + * Print the object's name; here we also look for a leading article and + * strip if found -- some games may avoid prefix and do this instead. + */ + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + if (sc_compare_word(name, "a", 1)) + name += 1; + else if (sc_compare_word(name, "an", 2)) + name += 2; + else if (sc_compare_word(name, "the", 3)) + name += 3; + else if (sc_compare_word(name, "some", 4)) + name += 4; + pf_buffer_string(filter, name); } static void -lib_print_object (sc_gameref_t game, sc_int object) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *prefix, *name; - - /* - * Get the object's prefix, and print if not empty, otherwise default to an - * "a " prefix, as that's what Adrift seems to do. - */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (prefix)) - { - pf_buffer_string (filter, prefix); - pf_buffer_character (filter, ' '); - } - else - pf_buffer_string (filter, "a "); - - /* Print object name. */ - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - pf_buffer_string (filter, name); +lib_print_object(sc_gameref_t game, sc_int object) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *prefix, *name; + + /* + * Get the object's prefix, and print if not empty, otherwise default to an + * "a " prefix, as that's what Adrift seems to do. + */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(prefix)) { + pf_buffer_string(filter, prefix); + pf_buffer_character(filter, ' '); + } else + pf_buffer_string(filter, "a "); + + /* Print object name. */ + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + pf_buffer_string(filter, name); } @@ -522,44 +484,41 @@ lib_print_object (sc_gameref_t game, sc_int object) * any prefix. */ static void -lib_print_npc_np (sc_gameref_t game, sc_int npc) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *name; +lib_print_npc_np(sc_gameref_t game, sc_int npc) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *name; - /* Get the NPC's short description, and print it. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); + /* Get the NPC's short description, and print it. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); - pf_buffer_string (filter, name); + pf_buffer_string(filter, name); } #if 0 static void -lib_print_npc (sc_gameref_t game, sc_int npc) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *prefix; - - /* Get the NPC's prefix. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - - /* If the prefix isn't empty, print it, then print NPC name. */ - if (!sc_strempty (prefix)) - { - pf_buffer_string (filter, prefix); - pf_buffer_character (filter, ' '); - } - lib_print_npc_np (game, npc); +lib_print_npc(sc_gameref_t game, sc_int npc) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *prefix; + + /* Get the NPC's prefix. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + + /* If the prefix isn't empty, print it, then print NPC name. */ + if (!sc_strempty(prefix)) { + pf_buffer_string(filter, prefix); + pf_buffer_character(filter, ' '); + } + lib_print_npc_np(game, npc); } #endif @@ -572,46 +531,43 @@ lib_print_npc (sc_gameref_t game, sc_int npc) * response string for a game, based on perspective or object plurality. */ static const sc_char * -lib_select_response (sc_gameref_t game, - const sc_char *second_person, - const sc_char *first_person, - const sc_char *third_person) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_int perspective; - const sc_char *response; - - /* Return the response appropriate for Perspective. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "Perspective"; - perspective = prop_get_integer (bundle, "I<-ss", vt_key); - switch (perspective) - { - case LIB_FIRST_PERSON: - response = first_person; - break; - case LIB_SECOND_PERSON: - response = second_person; - break; - case LIB_THIRD_PERSON: - response = third_person; - break; - default: - sc_error ("lib_select_response:" - " unknown perspective, %ld\n", perspective); - response = second_person; - break; - } - - return response; +lib_select_response(sc_gameref_t game, + const sc_char *second_person, + const sc_char *first_person, + const sc_char *third_person) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_int perspective; + const sc_char *response; + + /* Return the response appropriate for Perspective. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "Perspective"; + perspective = prop_get_integer(bundle, "I<-ss", vt_key); + switch (perspective) { + case LIB_FIRST_PERSON: + response = first_person; + break; + case LIB_SECOND_PERSON: + response = second_person; + break; + case LIB_THIRD_PERSON: + response = third_person; + break; + default: + sc_error("lib_select_response:" + " unknown perspective, %ld\n", perspective); + response = second_person; + break; + } + + return response; } static const sc_char * -lib_select_plurality (sc_gameref_t game, sc_int object, - const sc_char *singular, const sc_char *plural) -{ - return obj_appears_plural (game, object) ? plural : singular; +lib_select_plurality(sc_gameref_t game, sc_int object, + const sc_char *singular, const sc_char *plural) { + return obj_appears_plural(game, object) ? plural : singular; } @@ -623,39 +579,36 @@ lib_select_plurality (sc_gameref_t game, sc_int object, * return the standard inroom text. */ static const sc_char * -lib_get_npc_inroom_text (sc_gameref_t game, sc_int npc) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int walk_count, walk; - const sc_char *inroomtext; - - /* Get the count of NPC walks. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Walks"; - walk_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - /* Check for any active walk with a description, return if found. */ - for (walk = walk_count - 1; walk >= 0; walk--) - { - if (gs_npc_walkstep (game, npc, walk) > 0) - { - const sc_char *changeddesc; - - /* Get and check any walk active description. */ - vt_key[3].integer = walk; - vt_key[4].string = "ChangedDesc"; - changeddesc = prop_get_string (bundle, "S<-sisis", vt_key); - if (!sc_strempty (changeddesc)) - return changeddesc; - } - } - - /* Return the standard inroom text. */ - vt_key[2].string = "InRoomText"; - inroomtext = prop_get_string (bundle, "S<-sis", vt_key); - return inroomtext; +lib_get_npc_inroom_text(sc_gameref_t game, sc_int npc) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int walk_count, walk; + const sc_char *inroomtext; + + /* Get the count of NPC walks. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Walks"; + walk_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + /* Check for any active walk with a description, return if found. */ + for (walk = walk_count - 1; walk >= 0; walk--) { + if (gs_npc_walkstep(game, npc, walk) > 0) { + const sc_char *changeddesc; + + /* Get and check any walk active description. */ + vt_key[3].integer = walk; + vt_key[4].string = "ChangedDesc"; + changeddesc = prop_get_string(bundle, "S<-sisis", vt_key); + if (!sc_strempty(changeddesc)) + return changeddesc; + } + } + + /* Return the standard inroom text. */ + vt_key[2].string = "InRoomText"; + inroomtext = prop_get_string(bundle, "S<-sis", vt_key); + return inroomtext; } @@ -665,177 +618,155 @@ lib_get_npc_inroom_text (sc_gameref_t game, sc_int npc) * Print a list of the contents of a room. */ static void -lib_print_room_contents (sc_gameref_t game, sc_int room) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int object, npc, count, trail; - - /* List all objects that show their initial description. */ - count = 0; - for (object = 0; object < gs_object_count (game); object++) - { - if (obj_directly_in_room (game, object, room) - && obj_shows_initial_description (game, object)) - { - const sc_char *inroomdesc; - - /* Find and print in room description. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "InRoomDesc"; - inroomdesc = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (inroomdesc)) - { - if (count == 0) - pf_buffer_character (filter, '\n'); - else - pf_buffer_string (filter, " "); - pf_buffer_string (filter, inroomdesc); - count++; - } - } - } - if (count > 0) - pf_buffer_character (filter, '\n'); - - /* - * List dynamic objects directly located in the room, and not already listed - * above since they lack, or suppress, an in room description. - * - * If an object sets ListFlag, then if dynamic it's suppressed from the list - * where it would normally be included, but if static it's included where it - * would normally be excluded. - */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - if (obj_directly_in_room (game, object, room)) - { - const sc_char *inroomdesc; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "InRoomDesc"; - inroomdesc = prop_get_string (bundle, "S<-sis", vt_key); - - if (!obj_shows_initial_description (game, object) - || sc_strempty (inroomdesc)) - { - sc_bool listflag; - - vt_key[2].string = "ListFlag"; - listflag = prop_get_boolean (bundle, "B<-sis", vt_key); - - if (listflag == obj_is_static (game, object)) - { - if (count > 0) - { - if (count == 1) - pf_buffer_string (filter, - lib_select_plurality (game, trail, - "\nAlso here is ", - "\nAlso here are ")); - else - pf_buffer_string (filter, ", "); - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - } - } - if (count >= 1) - { - if (count == 1) - pf_buffer_string (filter, - lib_select_plurality (game, trail, - "\nAlso here is ", - "\nAlso here are ")); - else - pf_buffer_string (filter, " and "); - lib_print_object (game, trail); - pf_buffer_string (filter, ".\n"); - } - - /* List NPCs directly in the room that have an in room description. */ - count = 0; - for (npc = 0; npc < gs_npc_count (game); npc++) - { - if (npc_in_room (game, npc, room)) - { - const sc_char *description; - - /* Print any non='#' in-room description. */ - description = lib_get_npc_inroom_text (game, npc); - if (!sc_strempty (description) && sc_strcasecmp (description, "#")) - { - if (count == 0) - pf_buffer_character (filter, '\n'); - else - pf_buffer_string (filter, " "); - pf_buffer_string (filter, description); - count++; - } - } - } - if (count > 0) - pf_buffer_character (filter, '\n'); - - /* - * List NPCs in the room that don't have an in room description and that - * request a default "...is here" with "#". - * - * TODO Is this right? - */ - count = 0; - trail = -1; - for (npc = 0; npc < gs_npc_count (game); npc++) - { - if (npc_in_room (game, npc, room)) - { - const sc_char *description; - - /* Print name for descriptions marked '#'. */ - description = lib_get_npc_inroom_text (game, npc); - if (!sc_strempty (description) && !sc_strcasecmp (description, "#")) - { - if (count > 0) - { - if (count > 1) - pf_buffer_string (filter, ", "); - else - { - pf_buffer_character (filter, '\n'); - pf_new_sentence (filter); - } - lib_print_npc_np (game, trail); - } - trail = npc; - count++; - } - } - } - if (count >= 1) - { - if (count == 1) - { - pf_buffer_character (filter, '\n'); - pf_new_sentence (filter); - lib_print_npc_np (game, trail); - pf_buffer_string (filter, " is here"); - } - else - { - pf_buffer_string (filter, " and "); - lib_print_npc_np (game, trail); - pf_buffer_string (filter, " are here"); - } - pf_buffer_string (filter, ".\n"); - } +lib_print_room_contents(sc_gameref_t game, sc_int room) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int object, npc, count, trail; + + /* List all objects that show their initial description. */ + count = 0; + for (object = 0; object < gs_object_count(game); object++) { + if (obj_directly_in_room(game, object, room) + && obj_shows_initial_description(game, object)) { + const sc_char *inroomdesc; + + /* Find and print in room description. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "InRoomDesc"; + inroomdesc = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(inroomdesc)) { + if (count == 0) + pf_buffer_character(filter, '\n'); + else + pf_buffer_string(filter, " "); + pf_buffer_string(filter, inroomdesc); + count++; + } + } + } + if (count > 0) + pf_buffer_character(filter, '\n'); + + /* + * List dynamic objects directly located in the room, and not already listed + * above since they lack, or suppress, an in room description. + * + * If an object sets ListFlag, then if dynamic it's suppressed from the list + * where it would normally be included, but if static it's included where it + * would normally be excluded. + */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + if (obj_directly_in_room(game, object, room)) { + const sc_char *inroomdesc; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "InRoomDesc"; + inroomdesc = prop_get_string(bundle, "S<-sis", vt_key); + + if (!obj_shows_initial_description(game, object) + || sc_strempty(inroomdesc)) { + sc_bool listflag; + + vt_key[2].string = "ListFlag"; + listflag = prop_get_boolean(bundle, "B<-sis", vt_key); + + if (listflag == obj_is_static(game, object)) { + if (count > 0) { + if (count == 1) + pf_buffer_string(filter, + lib_select_plurality(game, trail, + "\nAlso here is ", + "\nAlso here are ")); + else + pf_buffer_string(filter, ", "); + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + } + } + if (count >= 1) { + if (count == 1) + pf_buffer_string(filter, + lib_select_plurality(game, trail, + "\nAlso here is ", + "\nAlso here are ")); + else + pf_buffer_string(filter, " and "); + lib_print_object(game, trail); + pf_buffer_string(filter, ".\n"); + } + + /* List NPCs directly in the room that have an in room description. */ + count = 0; + for (npc = 0; npc < gs_npc_count(game); npc++) { + if (npc_in_room(game, npc, room)) { + const sc_char *description; + + /* Print any non='#' in-room description. */ + description = lib_get_npc_inroom_text(game, npc); + if (!sc_strempty(description) && sc_strcasecmp(description, "#")) { + if (count == 0) + pf_buffer_character(filter, '\n'); + else + pf_buffer_string(filter, " "); + pf_buffer_string(filter, description); + count++; + } + } + } + if (count > 0) + pf_buffer_character(filter, '\n'); + + /* + * List NPCs in the room that don't have an in room description and that + * request a default "...is here" with "#". + * + * TODO Is this right? + */ + count = 0; + trail = -1; + for (npc = 0; npc < gs_npc_count(game); npc++) { + if (npc_in_room(game, npc, room)) { + const sc_char *description; + + /* Print name for descriptions marked '#'. */ + description = lib_get_npc_inroom_text(game, npc); + if (!sc_strempty(description) && !sc_strcasecmp(description, "#")) { + if (count > 0) { + if (count > 1) + pf_buffer_string(filter, ", "); + else { + pf_buffer_character(filter, '\n'); + pf_new_sentence(filter); + } + lib_print_npc_np(game, trail); + } + trail = npc; + count++; + } + } + } + if (count >= 1) { + if (count == 1) { + pf_buffer_character(filter, '\n'); + pf_new_sentence(filter); + lib_print_npc_np(game, trail); + pf_buffer_string(filter, " is here"); + } else { + pf_buffer_string(filter, " and "); + lib_print_npc_np(game, trail); + pf_buffer_string(filter, " are here"); + } + pf_buffer_string(filter, ".\n"); + } } @@ -845,152 +776,139 @@ lib_print_room_contents (sc_gameref_t game, sc_int room) * Print out the long description for a given room. */ void -lib_print_room_description (sc_gameref_t game, sc_int room) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_bool showobjects, is_described, is_suppressed; - sc_int alt_count, alt, start, event; - - /* Get count of room alternates. */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Alts"; - alt_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - /* Start with no description, and get our starting point in the alts list. */ - is_described = FALSE; - start = lib_find_starting_alt (game, room); - - /* Print the standard description unless a start alt indicates not. */ - if (start == -1) - is_suppressed = FALSE; - else - { - sc_int method; - - vt_key[3].integer = start; - vt_key[4].string = "DisplayRoom"; - method = prop_get_integer (bundle, "I<-sisis", vt_key); - - is_suppressed = (method == 0); - } - if (!is_suppressed) - { - const sc_char *description; - - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Long"; - description = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (description)) - { - pf_buffer_string (filter, description); - is_described = TRUE; - } - - vt_key[2].string = "Res"; - res_handle_resource (game, "sis", vt_key); - } - - /* Ensure that we're back to handling room alts. */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Alts"; - - /* - * Run forwards through all alts lower than our starting point, or all alts - * if no starting point overrider found. - */ - showobjects = TRUE; - for (alt = (start != -1) ? start : 0; alt < alt_count; alt++) - { - /* Ignore all non-method-2 alts except for the starter. */ - if (alt != start) - { - sc_int method; - - vt_key[3].integer = alt; - vt_key[4].string = "DisplayRoom"; - method = prop_get_integer (bundle, "I<-sisis", vt_key); - - if (method != 2) - continue; - } - - if (lib_use_room_alt (game, room, alt)) - { - const sc_char *m1; - sc_int hideobjects; - - vt_key[3].integer = alt; - vt_key[4].string = "M1"; - m1 = prop_get_string (bundle, "S<-sisis", vt_key); - if (!sc_strempty (m1)) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, m1); - is_described = TRUE; - } - - vt_key[4].string = "Res1"; - res_handle_resource (game, "sisis", vt_key); - - vt_key[4].string = "HideObjects"; - hideobjects = prop_get_integer (bundle, "I<-sisis", vt_key); - if (hideobjects == 1) - showobjects = FALSE; - } - else - { - const sc_char *m2; - - vt_key[3].integer = alt; - vt_key[4].string = "M2"; - m2 = prop_get_string (bundle, "S<-sisis", vt_key); - if (!sc_strempty (m2)) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, m2); - is_described = TRUE; - } - - vt_key[4].string = "Res2"; - res_handle_resource (game, "sisis", vt_key); - } - } - - /* Print out any relevant event look text. */ - for (event = 0; event < gs_event_count (game); event++) - { - if (gs_event_state (game, event) == ES_RUNNING - && evt_can_see_event (game, event)) - { - const sc_char *looktext; - - vt_key[0].string = "Events"; - vt_key[1].integer = event; - vt_key[2].string = "LookText"; - looktext = prop_get_string (bundle, "S<-sis", vt_key); - if (is_described) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, looktext); - is_described = TRUE; - - vt_key[2].string = "Res"; - vt_key[3].integer = 1; - res_handle_resource (game, "sisi", vt_key); - } - } - if (is_described) - pf_buffer_character (filter, '\n'); - - /* Finally, print room contents. */ - if (showobjects) - lib_print_room_contents (game, room); +lib_print_room_description(sc_gameref_t game, sc_int room) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_bool showobjects, is_described, is_suppressed; + sc_int alt_count, alt, start, event; + + /* Get count of room alternates. */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Alts"; + alt_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + /* Start with no description, and get our starting point in the alts list. */ + is_described = FALSE; + start = lib_find_starting_alt(game, room); + + /* Print the standard description unless a start alt indicates not. */ + if (start == -1) + is_suppressed = FALSE; + else { + sc_int method; + + vt_key[3].integer = start; + vt_key[4].string = "DisplayRoom"; + method = prop_get_integer(bundle, "I<-sisis", vt_key); + + is_suppressed = (method == 0); + } + if (!is_suppressed) { + const sc_char *description; + + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Long"; + description = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(description)) { + pf_buffer_string(filter, description); + is_described = TRUE; + } + + vt_key[2].string = "Res"; + res_handle_resource(game, "sis", vt_key); + } + + /* Ensure that we're back to handling room alts. */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Alts"; + + /* + * Run forwards through all alts lower than our starting point, or all alts + * if no starting point overrider found. + */ + showobjects = TRUE; + for (alt = (start != -1) ? start : 0; alt < alt_count; alt++) { + /* Ignore all non-method-2 alts except for the starter. */ + if (alt != start) { + sc_int method; + + vt_key[3].integer = alt; + vt_key[4].string = "DisplayRoom"; + method = prop_get_integer(bundle, "I<-sisis", vt_key); + + if (method != 2) + continue; + } + + if (lib_use_room_alt(game, room, alt)) { + const sc_char *m1; + sc_int hideobjects; + + vt_key[3].integer = alt; + vt_key[4].string = "M1"; + m1 = prop_get_string(bundle, "S<-sisis", vt_key); + if (!sc_strempty(m1)) { + if (is_described) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, m1); + is_described = TRUE; + } + + vt_key[4].string = "Res1"; + res_handle_resource(game, "sisis", vt_key); + + vt_key[4].string = "HideObjects"; + hideobjects = prop_get_integer(bundle, "I<-sisis", vt_key); + if (hideobjects == 1) + showobjects = FALSE; + } else { + const sc_char *m2; + + vt_key[3].integer = alt; + vt_key[4].string = "M2"; + m2 = prop_get_string(bundle, "S<-sisis", vt_key); + if (!sc_strempty(m2)) { + if (is_described) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, m2); + is_described = TRUE; + } + + vt_key[4].string = "Res2"; + res_handle_resource(game, "sisis", vt_key); + } + } + + /* Print out any relevant event look text. */ + for (event = 0; event < gs_event_count(game); event++) { + if (gs_event_state(game, event) == ES_RUNNING + && evt_can_see_event(game, event)) { + const sc_char *looktext; + + vt_key[0].string = "Events"; + vt_key[1].integer = event; + vt_key[2].string = "LookText"; + looktext = prop_get_string(bundle, "S<-sis", vt_key); + if (is_described) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, looktext); + is_described = TRUE; + + vt_key[2].string = "Res"; + vt_key[3].integer = 1; + res_handle_resource(game, "sisi", vt_key); + } + } + if (is_described) + pf_buffer_character(filter, '\n'); + + /* Finally, print room contents. */ + if (showobjects) + lib_print_room_contents(game, room); } @@ -1000,134 +918,116 @@ lib_print_room_description (sc_gameref_t game, sc_int room) * Return TRUE if the player can move in the given direction. */ static sc_bool -lib_can_go (sc_gameref_t game, sc_int room, sc_int direction) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int restriction; - sc_bool is_restricted = FALSE; - - /* Set up invariant parts of key. */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Exits"; - vt_key[3].integer = direction; - - /* Check for any movement restrictions. */ - vt_key[4].string = "Var1"; - restriction = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if (restriction >= 0) - { - sc_int type; - - if (lib_trace) - sc_trace ("Library: hit move restriction\n"); - - /* Get restriction type. */ - vt_key[4].string = "Var3"; - type = prop_get_integer (bundle, "I<-sisis", vt_key); - switch (type) - { - case 0: /* Task type restriction */ - { - sc_int check; - - /* Get the expected completion state. */ - vt_key[4].string = "Var2"; - check = prop_get_integer (bundle, "I<-sisis", vt_key); - - if (lib_trace) - { - sc_trace ("Library: task %ld, check %ld\n", - restriction, check); - } - - /* Restrict if task isn't done/not done as expected. */ - if ((check != 0) == gs_task_done (game, restriction)) - is_restricted = TRUE; - break; - } - - case 1: /* Object state restriction */ - { - sc_int object, check, openable; - - /* Get the target object. */ - object = obj_stateful_object (game, restriction); - - /* Get the expected object state. */ - vt_key[4].string = "Var2"; - check = prop_get_integer (bundle, "I<-sisis", vt_key); - - if (lib_trace) - sc_trace ("Library: object %ld, check %ld\n", object, check); - - /* Check openable and lockable objects. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Openable"; - openable = prop_get_integer (bundle, "I<-sis", vt_key); - if (openable > 0) - { - sc_int lockable; - - /* See if lockable. */ - vt_key[2].string = "Key"; - lockable = prop_get_integer (bundle, "I<-sis", vt_key); - if (lockable >= 0) - { - /* Lockable. */ - if (check <= 2) - { - if (gs_object_openness (game, object) != check + 5) - is_restricted = TRUE; - } - else - { - if (gs_object_state (game, object) != check - 2) - is_restricted = TRUE; - } - } - else - { - /* Not lockable, though openable. */ - if (check <= 1) - { - if (gs_object_openness (game, object) != check + 5) - is_restricted = TRUE; - } - else - { - if (gs_object_state (game, object) != check - 1) - is_restricted = TRUE; - } - } - } - else - { - /* Not openable. */ - if (gs_object_state (game, object) != check + 1) - is_restricted = TRUE; - } - break; - } - } - } - - /* Return TRUE if not restricted. */ - return !is_restricted; +lib_can_go(sc_gameref_t game, sc_int room, sc_int direction) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int restriction; + sc_bool is_restricted = FALSE; + + /* Set up invariant parts of key. */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Exits"; + vt_key[3].integer = direction; + + /* Check for any movement restrictions. */ + vt_key[4].string = "Var1"; + restriction = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if (restriction >= 0) { + sc_int type; + + if (lib_trace) + sc_trace("Library: hit move restriction\n"); + + /* Get restriction type. */ + vt_key[4].string = "Var3"; + type = prop_get_integer(bundle, "I<-sisis", vt_key); + switch (type) { + case 0: { /* Task type restriction */ + sc_int check; + + /* Get the expected completion state. */ + vt_key[4].string = "Var2"; + check = prop_get_integer(bundle, "I<-sisis", vt_key); + + if (lib_trace) { + sc_trace("Library: task %ld, check %ld\n", + restriction, check); + } + + /* Restrict if task isn't done/not done as expected. */ + if ((check != 0) == gs_task_done(game, restriction)) + is_restricted = TRUE; + break; + } + + case 1: { /* Object state restriction */ + sc_int object, check, openable; + + /* Get the target object. */ + object = obj_stateful_object(game, restriction); + + /* Get the expected object state. */ + vt_key[4].string = "Var2"; + check = prop_get_integer(bundle, "I<-sisis", vt_key); + + if (lib_trace) + sc_trace("Library: object %ld, check %ld\n", object, check); + + /* Check openable and lockable objects. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Openable"; + openable = prop_get_integer(bundle, "I<-sis", vt_key); + if (openable > 0) { + sc_int lockable; + + /* See if lockable. */ + vt_key[2].string = "Key"; + lockable = prop_get_integer(bundle, "I<-sis", vt_key); + if (lockable >= 0) { + /* Lockable. */ + if (check <= 2) { + if (gs_object_openness(game, object) != check + 5) + is_restricted = TRUE; + } else { + if (gs_object_state(game, object) != check - 2) + is_restricted = TRUE; + } + } else { + /* Not lockable, though openable. */ + if (check <= 1) { + if (gs_object_openness(game, object) != check + 5) + is_restricted = TRUE; + } else { + if (gs_object_state(game, object) != check - 1) + is_restricted = TRUE; + } + } + } else { + /* Not openable. */ + if (gs_object_state(game, object) != check + 1) + is_restricted = TRUE; + } + break; + } + } + } + + /* Return TRUE if not restricted. */ + return !is_restricted; } /* List of direction names, for printing and counting exits. */ static const sc_char *const DIRNAMES_4[] = { - "north", "east", "south", "west", "up", "down", "in", "out", - NULL + "north", "east", "south", "west", "up", "down", "in", "out", + NULL }; static const sc_char *const DIRNAMES_8[] = { - "north", "east", "south", "west", "up", "down", "in", "out", - "northeast", "southeast", "southwest", "northwest", - NULL + "north", "east", "south", "west", "up", "down", "in", "out", + "northeast", "southeast", "southwest", "northwest", + NULL }; @@ -1137,86 +1037,75 @@ static const sc_char *const DIRNAMES_8[] = { * Print a list of exits from the player room. */ sc_bool -lib_cmd_print_room_exits (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_bool eightpointcompass; - const sc_char *const *dirnames; - sc_int count, index_, trail; - - /* Decide on four or eight point compass names list. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "EightPointCompass"; - eightpointcompass = prop_get_boolean (bundle, "B<-ss", vt_key); - dirnames = eightpointcompass ? DIRNAMES_8 : DIRNAMES_4; - - /* Poll for an exit for each valid direction name. */ - count = 0; - trail = -1; - for (index_ = 0; dirnames[index_]; index_++) - { - sc_vartype_t vt_rvalue; - - vt_key[0].string = "Rooms"; - vt_key[1].integer = gs_playerroom (game); - vt_key[2].string = "Exits"; - vt_key[3].integer = index_; - if (prop_get (bundle, "I<-sisi", &vt_rvalue, vt_key) - && lib_can_go (game, gs_playerroom (game), index_)) - { - if (count > 0) - { - if (count == 1) - { - /* Vary text slightly for DispFirstRoom. */ - if (game->turns == 0) - pf_buffer_string (filter, "There are exits "); - else - pf_buffer_string (filter, - lib_select_response (game, - "You can move ", - "I can move ", - "%player% can move ")); - } - else - pf_buffer_string (filter, ", "); - pf_buffer_string (filter, dirnames[trail]); - } - trail = index_; - count++; - } - } - if (count >= 1) - { - if (count == 1) - { - /* Vary text slightly for DispFirstRoom. */ - if (game->turns == 0) - pf_buffer_string (filter, "There is an exit "); - else - pf_buffer_string (filter, - lib_select_response (game, - "You can only move ", - "I can only move ", - "%player% can only move ")); - } - else - pf_buffer_string (filter, " and "); - pf_buffer_string (filter, dirnames[trail]); - pf_buffer_string (filter, ".\n"); - } - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't go in any direction!\n", - "I can't go in any direction!\n", - "%player% can't go in any direction!\n")); - } - - return TRUE; +lib_cmd_print_room_exits(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_bool eightpointcompass; + const sc_char *const *dirnames; + sc_int count, index_, trail; + + /* Decide on four or eight point compass names list. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "EightPointCompass"; + eightpointcompass = prop_get_boolean(bundle, "B<-ss", vt_key); + dirnames = eightpointcompass ? DIRNAMES_8 : DIRNAMES_4; + + /* Poll for an exit for each valid direction name. */ + count = 0; + trail = -1; + for (index_ = 0; dirnames[index_]; index_++) { + sc_vartype_t vt_rvalue; + + vt_key[0].string = "Rooms"; + vt_key[1].integer = gs_playerroom(game); + vt_key[2].string = "Exits"; + vt_key[3].integer = index_; + if (prop_get(bundle, "I<-sisi", &vt_rvalue, vt_key) + && lib_can_go(game, gs_playerroom(game), index_)) { + if (count > 0) { + if (count == 1) { + /* Vary text slightly for DispFirstRoom. */ + if (game->turns == 0) + pf_buffer_string(filter, "There are exits "); + else + pf_buffer_string(filter, + lib_select_response(game, + "You can move ", + "I can move ", + "%player% can move ")); + } else + pf_buffer_string(filter, ", "); + pf_buffer_string(filter, dirnames[trail]); + } + trail = index_; + count++; + } + } + if (count >= 1) { + if (count == 1) { + /* Vary text slightly for DispFirstRoom. */ + if (game->turns == 0) + pf_buffer_string(filter, "There is an exit "); + else + pf_buffer_string(filter, + lib_select_response(game, + "You can only move ", + "I can only move ", + "%player% can only move ")); + } else + pf_buffer_string(filter, " and "); + pf_buffer_string(filter, dirnames[trail]); + pf_buffer_string(filter, ".\n"); + } else { + pf_buffer_string(filter, + lib_select_response(game, + "You can't go in any direction!\n", + "I can't go in any direction!\n", + "%player% can't go in any direction!\n")); + } + + return TRUE; } @@ -1227,34 +1116,31 @@ lib_cmd_print_room_exits (sc_gameref_t game) * room has already been visited. */ static void -lib_describe_player_room (sc_gameref_t game, sc_bool force_verbose) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; +lib_describe_player_room(sc_gameref_t game, sc_bool force_verbose) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; - /* Print the room name. */ - lib_print_room_name (game, gs_playerroom (game)); + /* Print the room name. */ + lib_print_room_name(game, gs_playerroom(game)); - /* Print other room details if applicable. */ - if (force_verbose - || game->verbose || !gs_room_seen (game, gs_playerroom (game))) - { - sc_bool showexits; + /* Print other room details if applicable. */ + if (force_verbose + || game->verbose || !gs_room_seen(game, gs_playerroom(game))) { + sc_bool showexits; - /* Print room description, and objects and NPCs. */ - lib_print_room_description (game, gs_playerroom (game)); + /* Print room description, and objects and NPCs. */ + lib_print_room_description(game, gs_playerroom(game)); - /* Print exits if the ShowExits global requests it. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "ShowExits"; - showexits = prop_get_boolean (bundle, "B<-ss", vt_key); - if (showexits) - { - pf_buffer_character (filter, '\n'); - lib_cmd_print_room_exits (game); - } - } + /* Print exits if the ShowExits global requests it. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "ShowExits"; + showexits = prop_get_boolean(bundle, "B<-ss", vt_key); + if (showexits) { + pf_buffer_character(filter, '\n'); + lib_cmd_print_room_exits(game); + } + } } @@ -1264,13 +1150,12 @@ lib_describe_player_room (sc_gameref_t game, sc_bool force_verbose) * Command handler for "look" command. */ sc_bool -lib_cmd_look (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_look(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_character (filter, '\n'); - lib_describe_player_room (game, TRUE); - return TRUE; + pf_buffer_character(filter, '\n'); + lib_describe_player_room(game, TRUE); + return TRUE; } @@ -1280,13 +1165,12 @@ lib_cmd_look (sc_gameref_t game) * Called on "quit". Exits from the game main loop. */ sc_bool -lib_cmd_quit (sc_gameref_t game) -{ - if (if_confirm (SC_CONF_QUIT)) - game->is_running = FALSE; +lib_cmd_quit(sc_gameref_t game) { + if (if_confirm(SC_CONF_QUIT)) + game->is_running = FALSE; - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -1297,16 +1181,14 @@ lib_cmd_quit (sc_gameref_t game) * request set. */ sc_bool -lib_cmd_restart (sc_gameref_t game) -{ - if (if_confirm (SC_CONF_RESTART)) - { - game->is_running = FALSE; - game->do_restart = TRUE; - } +lib_cmd_restart(sc_gameref_t game) { + if (if_confirm(SC_CONF_RESTART)) { + game->is_running = FALSE; + game->do_restart = TRUE; + } - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -1316,46 +1198,43 @@ lib_cmd_restart (sc_gameref_t game) * Called on "undo". Restores any undo game or memo to the main game. */ sc_bool -lib_cmd_undo (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_memo_setref_t memento = gs_get_memento (game); +lib_cmd_undo(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_memo_setref_t memento = gs_get_memento(game); - /* If an undo buffer is available, restore it. */ - if (game->undo_available) - { - gs_copy (game, game->undo); - game->undo_available = FALSE; + /* If an undo buffer is available, restore it. */ + if (game->undo_available) { + gs_copy(game, game->undo); + game->undo_available = FALSE; - lib_print_room_name (game, gs_playerroom (game)); - pf_buffer_string (filter, "[The previous turn has been undone.]\n"); + lib_print_room_name(game, gs_playerroom(game)); + pf_buffer_string(filter, "[The previous turn has been undone.]\n"); - /* Undo can't properly unravel layered sounds... */ - game->stop_sound = TRUE; - } + /* Undo can't properly unravel layered sounds... */ + game->stop_sound = TRUE; + } - /* - * If there is no undo buffer, try to restore one saved previously in a - * memo. If that works, treat as for restore from file, since that's - * effectively what it is. - */ - else if (memo_load_game (memento, game)) - { - lib_print_room_name (game, gs_playerroom (game)); - pf_buffer_string (filter, "[The previous turn has been undone.]\n"); + /* + * If there is no undo buffer, try to restore one saved previously in a + * memo. If that works, treat as for restore from file, since that's + * effectively what it is. + */ + else if (memo_load_game(memento, game)) { + lib_print_room_name(game, gs_playerroom(game)); + pf_buffer_string(filter, "[The previous turn has been undone.]\n"); - game->is_running = FALSE; - game->do_restore = TRUE; - } + game->is_running = FALSE; + game->do_restore = TRUE; + } - /* If no undo buffer and memo restore failed, there's no undo available. */ - else if (game->turns == 0) - pf_buffer_string (filter, "You can't undo what hasn't been done.\n"); - else - pf_buffer_string (filter, "Sorry, no more undo is available.\n"); + /* If no undo buffer and memo restore failed, there's no undo available. */ + else if (game->turns == 0) + pf_buffer_string(filter, "You can't undo what hasn't been done.\n"); + else + pf_buffer_string(filter, "Sorry, no more undo is available.\n"); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -1368,106 +1247,98 @@ lib_cmd_undo (sc_gameref_t game) * than using the printfilter to avoid possible clashes with ALRs. */ static sc_bool -lib_cmd_history_common (sc_gameref_t game, sc_int limit) -{ - const sc_var_setref_t vars = gs_get_vars (game); - const sc_memo_setref_t memento = gs_get_memento (game); - sc_int first, count, timestamp; - - /* - * The runner main loop will add an entry for the "history" command that - * got us here, but it hasn't done so yet. To keep the history list - * accurate for recalling commands, we add a surrogate "history" command - * to the history here, and remove it when we've done listing. This matches - * the c-shell, which always shows 'history' listed last. - */ - timestamp = var_get_elapsed_seconds (vars); - memo_save_command (memento, "[history]", timestamp, game->turns); - - /* Decide on the first history to display; all if limit is 0 or less. */ - if (limit > 0) - { - /* - * Get a count of the history length recorded. Because of the surrogate - * "history" above, this is always at least one. From this, choose a - * start point for the display; all if not enough history. - */ - count = memo_get_command_count (memento); - first = (count > limit) ? count - limit : 0; - } - else - first = 0; - - if_print_string ("These are your most recent game commands:\n\n"); - - /* Display history starting at the first entry determined above. */ - memo_first_command (memento); - for (count = 0; memo_more_commands (memento); count++) - { - const sc_char *command; - sc_int sequence, turns; - - /* Obtain the history entry, and write if included. */ - memo_next_command (memento, &command, &sequence, ×tamp, &turns); - if (count >= first) - { - sc_int hr, min, sec; - sc_char buffer[64]; - - /* Write the history entry sequence. */ - sprintf (buffer, "%4ld -- Time ", sequence); - if_print_string (buffer); - - /* Separate the timestamp out into components. */ - hr = timestamp / SECS_PER_HOUR; - min = (timestamp % SECS_PER_HOUR) / MINS_PER_HOUR; - sec = timestamp % SECS_PER_MINUTE; - - /* Print playing time as "[HHh ][M]Mm SSs". */ - if (hr > 0) - sprintf (buffer, "%ldh %02ldm %02lds", hr, min, sec); - else - sprintf (buffer, "%ldm %02lds", min, sec); - if_print_string (buffer); - - /* Follow up with the turns count, and the command string itself. */ - sprintf (buffer, ", turn %ld : ", turns); - if_print_string (buffer); - if_print_string (command); - if_print_character ('\n'); - } - } - - /* Remove the surrogate "history"; the main loop will add the real one. */ - memo_unsave_command (memento); - - game->is_admin = TRUE; - return TRUE; -} - -sc_bool -lib_cmd_history_number (sc_gameref_t game) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int limit; - - /* Get requested length of history list, and complain if not valid. */ - limit = var_get_ref_number (vars); - if (limit < 1) - { - if_print_string ("That's not a valid history length.\n"); - - game->is_admin = TRUE; - return TRUE; - } - - return lib_cmd_history_common (game, limit); -} - -sc_bool -lib_cmd_history (sc_gameref_t game) -{ - return lib_cmd_history_common (game, 0); +lib_cmd_history_common(sc_gameref_t game, sc_int limit) { + const sc_var_setref_t vars = gs_get_vars(game); + const sc_memo_setref_t memento = gs_get_memento(game); + sc_int first, count, timestamp; + + /* + * The runner main loop will add an entry for the "history" command that + * got us here, but it hasn't done so yet. To keep the history list + * accurate for recalling commands, we add a surrogate "history" command + * to the history here, and remove it when we've done listing. This matches + * the c-shell, which always shows 'history' listed last. + */ + timestamp = var_get_elapsed_seconds(vars); + memo_save_command(memento, "[history]", timestamp, game->turns); + + /* Decide on the first history to display; all if limit is 0 or less. */ + if (limit > 0) { + /* + * Get a count of the history length recorded. Because of the surrogate + * "history" above, this is always at least one. From this, choose a + * start point for the display; all if not enough history. + */ + count = memo_get_command_count(memento); + first = (count > limit) ? count - limit : 0; + } else + first = 0; + + if_print_string("These are your most recent game commands:\n\n"); + + /* Display history starting at the first entry determined above. */ + memo_first_command(memento); + for (count = 0; memo_more_commands(memento); count++) { + const sc_char *command; + sc_int sequence, turns; + + /* Obtain the history entry, and write if included. */ + memo_next_command(memento, &command, &sequence, ×tamp, &turns); + if (count >= first) { + sc_int hr, min, sec; + sc_char buffer[64]; + + /* Write the history entry sequence. */ + sprintf(buffer, "%4ld -- Time ", sequence); + if_print_string(buffer); + + /* Separate the timestamp out into components. */ + hr = timestamp / SECS_PER_HOUR; + min = (timestamp % SECS_PER_HOUR) / MINS_PER_HOUR; + sec = timestamp % SECS_PER_MINUTE; + + /* Print playing time as "[HHh ][M]Mm SSs". */ + if (hr > 0) + sprintf(buffer, "%ldh %02ldm %02lds", hr, min, sec); + else + sprintf(buffer, "%ldm %02lds", min, sec); + if_print_string(buffer); + + /* Follow up with the turns count, and the command string itself. */ + sprintf(buffer, ", turn %ld : ", turns); + if_print_string(buffer); + if_print_string(command); + if_print_character('\n'); + } + } + + /* Remove the surrogate "history"; the main loop will add the real one. */ + memo_unsave_command(memento); + + game->is_admin = TRUE; + return TRUE; +} + +sc_bool +lib_cmd_history_number(sc_gameref_t game) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int limit; + + /* Get requested length of history list, and complain if not valid. */ + limit = var_get_ref_number(vars); + if (limit < 1) { + if_print_string("That's not a valid history length.\n"); + + game->is_admin = TRUE; + return TRUE; + } + + return lib_cmd_history_common(game, limit); +} + +sc_bool +lib_cmd_history(sc_gameref_t game) { + return lib_cmd_history_common(game, 0); } @@ -1483,167 +1354,150 @@ lib_cmd_history (sc_gameref_t game) * to re-run. */ sc_bool -lib_cmd_again (sc_gameref_t game) -{ - game->do_again = TRUE; - game->redo_sequence = 0; - - game->is_admin = TRUE; - return TRUE; -} - -sc_bool -lib_cmd_redo_number (sc_gameref_t game) -{ - const sc_var_setref_t vars = gs_get_vars (game); - const sc_memo_setref_t memento = gs_get_memento (game); - sc_int sequence; - - /* - * Get the history sequence entry requested and validate it. The sequence - * may be positive (absolute) or negative (relative to history end), but - * not zero. - */ - sequence = var_get_ref_number (vars); - if (sequence != 0 && memo_find_command (memento, sequence)) - { - game->do_again = TRUE; - game->redo_sequence = sequence; - } - else - { - if_print_string ("No matching entry found in the command history.\n"); - - /* - * This is a failed redo, but returning FALSE will cause the game's - * unknown command message to come up. However, returning TRUE will - * cause the runner main loop to add this to its history, and at some - * point a "redo 7" could cause problems (say, when it's at sequence 7, - * where it'll cause an infinite loop). To work round this, here we'll - * return a redo_sequence _without_ do_again, and have the runner catch - * that as an indication not to save the command in its history. Sorry - * for the ugliness. - */ - game->do_again = FALSE; - game->redo_sequence = INT_MAX; - } - - game->is_admin = TRUE; - return TRUE; +lib_cmd_again(sc_gameref_t game) { + game->do_again = TRUE; + game->redo_sequence = 0; + + game->is_admin = TRUE; + return TRUE; +} + +sc_bool +lib_cmd_redo_number(sc_gameref_t game) { + const sc_var_setref_t vars = gs_get_vars(game); + const sc_memo_setref_t memento = gs_get_memento(game); + sc_int sequence; + + /* + * Get the history sequence entry requested and validate it. The sequence + * may be positive (absolute) or negative (relative to history end), but + * not zero. + */ + sequence = var_get_ref_number(vars); + if (sequence != 0 && memo_find_command(memento, sequence)) { + game->do_again = TRUE; + game->redo_sequence = sequence; + } else { + if_print_string("No matching entry found in the command history.\n"); + + /* + * This is a failed redo, but returning FALSE will cause the game's + * unknown command message to come up. However, returning TRUE will + * cause the runner main loop to add this to its history, and at some + * point a "redo 7" could cause problems (say, when it's at sequence 7, + * where it'll cause an infinite loop). To work round this, here we'll + * return a redo_sequence _without_ do_again, and have the runner catch + * that as an indication not to save the command in its history. Sorry + * for the ugliness. + */ + game->do_again = FALSE; + game->redo_sequence = INT_MAX; + } + + game->is_admin = TRUE; + return TRUE; } static sc_bool -lib_cmd_redo_text_last_common (sc_gameref_t game, const sc_char *target) -{ - const sc_memo_setref_t memento = gs_get_memento (game); - sc_bool is_do_last, is_contains; - sc_int length, matched_sequence; - - /* Make a special case of "!!", rerun the final command in the history. */ - is_do_last = (strcmp (target, "!") == 0); - - /* - * Differentiate starts-with and contains searches, setting is_contains and - * advancing by one if the target begins '?' (word search). Note target - * string length. - */ - is_contains = (target[0] == '?'); - target += is_contains ? 1 : 0; - length = strlen (target); - - /* If there's no text left to search for, reject this call now. */ - if (length == 0) - { - if_print_string ("No matching entry found in the command history.\n"); - - /* As with failed numeric redo above, special-case this return. */ - game->do_again = FALSE; - game->redo_sequence = INT_MAX; - - game->is_admin = TRUE; - return TRUE; - } - - /* - * Search saved commands for one that matches the target string in the - * required way. We want to return the most recently saved match, so ideally - * we'd search backwards, but the iterator is only forwards, so we do it the - * hard way. - */ - matched_sequence = 0; - memo_first_command (memento); - while (memo_more_commands (memento)) - { - const sc_char *command; - sc_int sequence, timestamp, turns; - sc_bool is_matched; - - /* Get the command; only command and sequence are relevant. */ - memo_next_command (memento, &command, &sequence, ×tamp, &turns); - - /* - * If this is the "!!" special case, match everything. Otherwise, - * either search the command for the target, or match if the command - * begins with the target. - */ - if (is_do_last) - is_matched = TRUE; - else if (is_contains) - { - sc_int index_; - - /* Search this command for an occurrence of target anywhere. */ - is_matched = FALSE; - for (index_ = strlen (command) - length; index_ >= 0; index_--) - { - if (sc_strncasecmp (command + index_, target, length) == 0) - { - is_matched = TRUE; - break; - } - } - } - else - is_matched = (sc_strncasecmp (command, target, length) == 0); - - /* If the command matched the target criteria, note it and continue. */ - if (is_matched) - matched_sequence = sequence; - } - - /* If we found a match, set the redo values accordingly. */ - if (matched_sequence > 0) - { - game->do_again = TRUE; - game->redo_sequence = matched_sequence; - } - else - { - if_print_string ("No matching entry found in the command history.\n"); - - /* As with failed numeric redo above, special-case this return. */ - game->do_again = FALSE; - game->redo_sequence = INT_MAX; - } - - game->is_admin = TRUE; - return TRUE; -} - -sc_bool -lib_cmd_redo_text (sc_gameref_t game) -{ - const sc_var_setref_t vars = gs_get_vars (game); - - /* Call the common redo with the referenced text from %text%. */ - return lib_cmd_redo_text_last_common (game, var_get_ref_text (vars)); -} - -sc_bool -lib_cmd_redo_last (sc_gameref_t game) -{ - /* Call the common redo with, literally, "!", forming "!!" . */ - return lib_cmd_redo_text_last_common (game, "!"); +lib_cmd_redo_text_last_common(sc_gameref_t game, const sc_char *target) { + const sc_memo_setref_t memento = gs_get_memento(game); + sc_bool is_do_last, is_contains; + sc_int length, matched_sequence; + + /* Make a special case of "!!", rerun the final command in the history. */ + is_do_last = (strcmp(target, "!") == 0); + + /* + * Differentiate starts-with and contains searches, setting is_contains and + * advancing by one if the target begins '?' (word search). Note target + * string length. + */ + is_contains = (target[0] == '?'); + target += is_contains ? 1 : 0; + length = strlen(target); + + /* If there's no text left to search for, reject this call now. */ + if (length == 0) { + if_print_string("No matching entry found in the command history.\n"); + + /* As with failed numeric redo above, special-case this return. */ + game->do_again = FALSE; + game->redo_sequence = INT_MAX; + + game->is_admin = TRUE; + return TRUE; + } + + /* + * Search saved commands for one that matches the target string in the + * required way. We want to return the most recently saved match, so ideally + * we'd search backwards, but the iterator is only forwards, so we do it the + * hard way. + */ + matched_sequence = 0; + memo_first_command(memento); + while (memo_more_commands(memento)) { + const sc_char *command; + sc_int sequence, timestamp, turns; + sc_bool is_matched; + + /* Get the command; only command and sequence are relevant. */ + memo_next_command(memento, &command, &sequence, ×tamp, &turns); + + /* + * If this is the "!!" special case, match everything. Otherwise, + * either search the command for the target, or match if the command + * begins with the target. + */ + if (is_do_last) + is_matched = TRUE; + else if (is_contains) { + sc_int index_; + + /* Search this command for an occurrence of target anywhere. */ + is_matched = FALSE; + for (index_ = strlen(command) - length; index_ >= 0; index_--) { + if (sc_strncasecmp(command + index_, target, length) == 0) { + is_matched = TRUE; + break; + } + } + } else + is_matched = (sc_strncasecmp(command, target, length) == 0); + + /* If the command matched the target criteria, note it and continue. */ + if (is_matched) + matched_sequence = sequence; + } + + /* If we found a match, set the redo values accordingly. */ + if (matched_sequence > 0) { + game->do_again = TRUE; + game->redo_sequence = matched_sequence; + } else { + if_print_string("No matching entry found in the command history.\n"); + + /* As with failed numeric redo above, special-case this return. */ + game->do_again = FALSE; + game->redo_sequence = INT_MAX; + } + + game->is_admin = TRUE; + return TRUE; +} + +sc_bool +lib_cmd_redo_text(sc_gameref_t game) { + const sc_var_setref_t vars = gs_get_vars(game); + + /* Call the common redo with the referenced text from %text%. */ + return lib_cmd_redo_text_last_common(game, var_get_ref_text(vars)); +} + +sc_bool +lib_cmd_redo_last(sc_gameref_t game) { + /* Call the common redo with, literally, "!", forming "!!" . */ + return lib_cmd_redo_text_last_common(game, "!"); } @@ -1653,48 +1507,40 @@ lib_cmd_redo_last (sc_gameref_t game) * Called on "hints". Requests the interface to display any available hints. */ sc_bool -lib_cmd_hints (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int task; - sc_bool game_has_hints; - - /* - * Check for the presence of any game hints at all, no matter whether the - * task is runnable or not. - */ - game_has_hints = FALSE; - for (task = 0; task < gs_task_count (game); task++) - { - if (task_has_hints (game, task)) - { - game_has_hints = TRUE; - break; - } - } - - /* If the game has hints, display any relevant ones. */ - if (game_has_hints) - { - if (run_hint_iterate (game, NULL)) - { - if (if_confirm (SC_CONF_VIEW_HINTS)) - if_display_hints (game); - } - else - pf_buffer_string (filter, "There are currently no hints available.\n"); - } - else - { - pf_buffer_string (filter, - "There are no hints available for this adventure.\n"); - pf_buffer_string (filter, - "You're just going to have to work it out for" - " yourself...\n"); - } - - game->is_admin = TRUE; - return TRUE; +lib_cmd_hints(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int task; + sc_bool game_has_hints; + + /* + * Check for the presence of any game hints at all, no matter whether the + * task is runnable or not. + */ + game_has_hints = FALSE; + for (task = 0; task < gs_task_count(game); task++) { + if (task_has_hints(game, task)) { + game_has_hints = TRUE; + break; + } + } + + /* If the game has hints, display any relevant ones. */ + if (game_has_hints) { + if (run_hint_iterate(game, NULL)) { + if (if_confirm(SC_CONF_VIEW_HINTS)) + if_display_hints(game); + } else + pf_buffer_string(filter, "There are currently no hints available.\n"); + } else { + pf_buffer_string(filter, + "There are no hints available for this adventure.\n"); + pf_buffer_string(filter, + "You're just going to have to work it out for" + " yourself...\n"); + } + + game->is_admin = TRUE; + return TRUE; } @@ -1705,19 +1551,17 @@ lib_cmd_hints (sc_gameref_t game) * Convenience helpers for printing licensing and game information. */ static void -lib_print_string_bold (const sc_char *string) -{ - if_print_tag (SC_TAG_BOLD, ""); - if_print_string (string); - if_print_tag (SC_TAG_ENDBOLD, ""); +lib_print_string_bold(const sc_char *string) { + if_print_tag(SC_TAG_BOLD, ""); + if_print_string(string); + if_print_tag(SC_TAG_ENDBOLD, ""); } static void -lib_print_string_italics (const sc_char *string) -{ - if_print_tag (SC_TAG_ITALICS, ""); - if_print_string (string); - if_print_tag (SC_TAG_ENDITALICS, ""); +lib_print_string_italics(const sc_char *string) { + if_print_tag(SC_TAG_ITALICS, ""); + if_print_string(string); + if_print_tag(SC_TAG_ENDITALICS, ""); } @@ -1730,95 +1574,93 @@ lib_print_string_italics (const sc_char *string) * to avoid possible clashes with ALRs. */ sc_bool -lib_cmd_help (sc_gameref_t game) -{ - if_print_string ( - "These are some of the typical commands used in this adventure:\n\n"); - - if_print_string ( - " [N]orth, [E]ast, [S]outh, [W]est, [U]p, [D]own, [In], [O]ut," - " [L]ook, [Exits]\n E[x]amine , [Get ]," - " [Drop ], [...it], [...all]\n [Where is ]\n" - " [Give to ], [Open...], [Close...]," - " [Ask about ]\n" - " [Wear ], [Remove ], [I]nventory\n" - " [Put into ], [Put onto ]\n"); - - if_print_string ("\nUse the "); - lib_print_string_italics ("Save"); - if_print_string (", "); - lib_print_string_italics ("Restore"); - if_print_string (", "); - lib_print_string_italics ("Undo"); - if_print_string (", and "); - lib_print_string_italics ("Quit"); - if_print_string ( - " commands to save and restore games, undo a move, and leave the " - " game. Use "); - lib_print_string_italics ("History"); - if_print_string (" and "); - lib_print_string_italics ("Redo"); - if_print_string ( - " to view and repeat recent game commands.\n"); - - if_print_string ("\nThe "); - lib_print_string_italics ("Hint"); - if_print_string (" command displays any game hints, "); - lib_print_string_italics ("Notify"); - if_print_string (" provides score change notification, and "); - lib_print_string_italics ("Verbose"); - if_print_string (" and "); - lib_print_string_italics ("Brief"); - if_print_string (" control room descriptions.\n"); - - if_print_string ("\nUse "); - lib_print_string_italics ("License"); - if_print_string ( - " to view SCARE's licensing terms and conditions, and "); - lib_print_string_italics ("Version"); - if_print_string ( - " to print both SCARE's and the game's version number.\n"); - - game->is_admin = TRUE; - return TRUE; -} - -sc_bool -lib_cmd_license (sc_gameref_t game) -{ - lib_print_string_bold ("SCARE"); - if_print_string (" is "); - lib_print_string_italics ( - "Copyright (C) 2003-2008 Simon Baldwin and Mark J. Tilford"); - if_print_string (".\n\n"); - - if_print_string ( - "This program is free software; you can redistribute it and/or modify" - " it under the terms of version 2 of the GNU General Public License" - " as published by the Free Software Foundation.\n\n"); - - if_print_string ( - "This program is distributed in the hope that it will be useful, but "); - lib_print_string_bold ("WITHOUT ANY WARRANTY"); - if_print_string ("; without even the implied warranty of "); - lib_print_string_bold ("MERCHANTABILITY"); - if_print_string (" or "); - lib_print_string_bold ("FITNESS FOR A PARTICULAR PURPOSE"); - if_print_string ( - ". See the GNU General Public License for more details.\n\n"); - - if_print_string ( - "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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301" - " USA\n\n"); - - if_print_string ("Please report any bugs, omissions, or misfeatures to "); - lib_print_string_italics ("simon_baldwin@yahoo.com"); - if_print_string (".\n"); - - game->is_admin = TRUE; - return TRUE; +lib_cmd_help(sc_gameref_t game) { + if_print_string( + "These are some of the typical commands used in this adventure:\n\n"); + + if_print_string( + " [N]orth, [E]ast, [S]outh, [W]est, [U]p, [D]own, [In], [O]ut," + " [L]ook, [Exits]\n E[x]amine , [Get ]," + " [Drop ], [...it], [...all]\n [Where is ]\n" + " [Give to ], [Open...], [Close...]," + " [Ask about ]\n" + " [Wear ], [Remove ], [I]nventory\n" + " [Put into ], [Put onto ]\n"); + + if_print_string("\nUse the "); + lib_print_string_italics("Save"); + if_print_string(", "); + lib_print_string_italics("Restore"); + if_print_string(", "); + lib_print_string_italics("Undo"); + if_print_string(", and "); + lib_print_string_italics("Quit"); + if_print_string( + " commands to save and restore games, undo a move, and leave the " + " game. Use "); + lib_print_string_italics("History"); + if_print_string(" and "); + lib_print_string_italics("Redo"); + if_print_string( + " to view and repeat recent game commands.\n"); + + if_print_string("\nThe "); + lib_print_string_italics("Hint"); + if_print_string(" command displays any game hints, "); + lib_print_string_italics("Notify"); + if_print_string(" provides score change notification, and "); + lib_print_string_italics("Verbose"); + if_print_string(" and "); + lib_print_string_italics("Brief"); + if_print_string(" control room descriptions.\n"); + + if_print_string("\nUse "); + lib_print_string_italics("License"); + if_print_string( + " to view SCARE's licensing terms and conditions, and "); + lib_print_string_italics("Version"); + if_print_string( + " to print both SCARE's and the game's version number.\n"); + + game->is_admin = TRUE; + return TRUE; +} + +sc_bool +lib_cmd_license(sc_gameref_t game) { + lib_print_string_bold("SCARE"); + if_print_string(" is "); + lib_print_string_italics( + "Copyright (C) 2003-2008 Simon Baldwin and Mark J. Tilford"); + if_print_string(".\n\n"); + + if_print_string( + "This program is free software; you can redistribute it and/or modify" + " it under the terms of version 2 of the GNU General Public License" + " as published by the Free Software Foundation.\n\n"); + + if_print_string( + "This program is distributed in the hope that it will be useful, but "); + lib_print_string_bold("WITHOUT ANY WARRANTY"); + if_print_string("; without even the implied warranty of "); + lib_print_string_bold("MERCHANTABILITY"); + if_print_string(" or "); + lib_print_string_bold("FITNESS FOR A PARTICULAR PURPOSE"); + if_print_string( + ". See the GNU General Public License for more details.\n\n"); + + if_print_string( + "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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301" + " USA\n\n"); + + if_print_string("Please report any bugs, omissions, or misfeatures to "); + lib_print_string_italics("simon_baldwin@yahoo.com"); + if_print_string(".\n"); + + game->is_admin = TRUE; + return TRUE; } @@ -1830,46 +1672,44 @@ lib_cmd_license (sc_gameref_t game) * avoid possible clashes with ALRs. */ sc_bool -lib_cmd_information (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[2]; - const sc_char *gamename, *compile_date, *gameauthor; - sc_char *filtered; +lib_cmd_information(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[2]; + const sc_char *gamename, *compile_date, *gameauthor; + sc_char *filtered; - vt_key[0].string = "Globals"; - vt_key[1].string = "GameName"; - gamename = prop_get_string (bundle, "S<-ss", vt_key); - filtered = pf_filter_for_info (gamename, vars); - pf_strip_tags (filtered); + vt_key[0].string = "Globals"; + vt_key[1].string = "GameName"; + gamename = prop_get_string(bundle, "S<-ss", vt_key); + filtered = pf_filter_for_info(gamename, vars); + pf_strip_tags(filtered); - if_print_string ("\""); - if_print_string (!sc_strempty (filtered) ? filtered : "Untitled"); - if_print_string ("\""); - sc_free (filtered); + if_print_string("\""); + if_print_string(!sc_strempty(filtered) ? filtered : "Untitled"); + if_print_string("\""); + sc_free(filtered); - vt_key[0].string = "CompileDate"; - compile_date = prop_get_string (bundle, "S<-s", vt_key); - if (!sc_strempty (compile_date)) - { - if_print_string (", "); - if_print_string (compile_date); - } + vt_key[0].string = "CompileDate"; + compile_date = prop_get_string(bundle, "S<-s", vt_key); + if (!sc_strempty(compile_date)) { + if_print_string(", "); + if_print_string(compile_date); + } - vt_key[0].string = "Globals"; - vt_key[1].string = "GameAuthor"; - gameauthor = prop_get_string (bundle, "S<-ss", vt_key); - filtered = pf_filter_for_info (gameauthor, vars); - pf_strip_tags (filtered); + vt_key[0].string = "Globals"; + vt_key[1].string = "GameAuthor"; + gameauthor = prop_get_string(bundle, "S<-ss", vt_key); + filtered = pf_filter_for_info(gameauthor, vars); + pf_strip_tags(filtered); - if_print_string (", "); - if_print_string (!sc_strempty (filtered) ? filtered : "Anonymous"); - if_print_string (".\n"); - sc_free (filtered); + if_print_string(", "); + if_print_string(!sc_strempty(filtered) ? filtered : "Anonymous"); + if_print_string(".\n"); + sc_free(filtered); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -1879,14 +1719,13 @@ lib_cmd_information (sc_gameref_t game) * Clear the main game window (almost). */ sc_bool -lib_cmd_clear (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_clear(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_tag (filter, SC_TAG_CLS); - pf_buffer_string (filter, "Screen cleared.\n"); - game->is_admin = TRUE; - return TRUE; + pf_buffer_tag(filter, SC_TAG_CLS); + pf_buffer_string(filter, "Screen cleared.\n"); + game->is_admin = TRUE; + return TRUE; } @@ -1898,47 +1737,42 @@ lib_cmd_clear (sc_gameref_t game) * rather than using the printfilter to avoid possible clashes with ALRs. */ sc_bool -lib_cmd_statusline (sc_gameref_t game) -{ - const sc_char *name, *author, *room, *status; - sc_int score; +lib_cmd_statusline(sc_gameref_t game) { + const sc_char *name, *author, *room, *status; + sc_int score; - /* - * Retrieve the game's name and author, the description of the current - * game room, and any formatted game status line. - */ - run_get_attributes (game, &name, &author, NULL, NULL, - &score, NULL, &room, &status, NULL, NULL, NULL, NULL); + /* + * Retrieve the game's name and author, the description of the current + * game room, and any formatted game status line. + */ + run_get_attributes(game, &name, &author, NULL, NULL, + &score, NULL, &room, &status, NULL, NULL, NULL, NULL); - /* If nothing is yet determined, print the game name and author. */ - if (!room || sc_strempty (room)) - { - if_print_string (name); - if_print_string (" | "); - if_print_string (author); - } - else - { - /* Print the player location, and a separator. */ - if_print_string (room); - if_print_string (" | "); + /* If nothing is yet determined, print the game name and author. */ + if (!room || sc_strempty(room)) { + if_print_string(name); + if_print_string(" | "); + if_print_string(author); + } else { + /* Print the player location, and a separator. */ + if_print_string(room); + if_print_string(" | "); - /* If the game offers a status line, print it, otherwise the score. */ - if (status && !sc_strempty (status)) - if_print_string (status); - else - { - sc_char buffer[32]; + /* If the game offers a status line, print it, otherwise the score. */ + if (status && !sc_strempty(status)) + if_print_string(status); + else { + sc_char buffer[32]; - if_print_string ("Score: "); - sprintf (buffer, "%ld", score); - if_print_string (buffer); - } - } - if_print_character ('\n'); + if_print_string("Score: "); + sprintf(buffer, "%ld", score); + if_print_string(buffer); + } + } + if_print_character('\n'); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -1949,32 +1783,31 @@ lib_cmd_statusline (sc_gameref_t game) * printfilter to avoid possible clashes with ALRs. */ sc_bool -lib_cmd_version (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key; - sc_char buffer[64]; - sc_int major, minor, point; - const sc_char *version; +lib_cmd_version(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key; + sc_char buffer[64]; + sc_int major, minor, point; + const sc_char *version; - if_print_string ("SCARE version "); - if_print_string (SCARE_VERSION SCARE_PATCH_LEVEL); - if_print_string (" [Adrift "); - major = SCARE_EMULATION / 1000; - minor = (SCARE_EMULATION % 1000) / 100; - point = SCARE_EMULATION % 100; - sprintf (buffer, "%ld.%02ld.%02ld", major, minor, point); - if_print_string (buffer); - if_print_string (" compatible], "); + if_print_string("SCARE version "); + if_print_string(SCARE_VERSION SCARE_PATCH_LEVEL); + if_print_string(" [Adrift "); + major = SCARE_EMULATION / 1000; + minor = (SCARE_EMULATION % 1000) / 100; + point = SCARE_EMULATION % 100; + sprintf(buffer, "%ld.%02ld.%02ld", major, minor, point); + if_print_string(buffer); + if_print_string(" compatible], "); - vt_key.string = "VersionString"; - version = prop_get_string (bundle, "S<-s", &vt_key); - if_print_string ("Generator version "); - if_print_string (version); - if_print_string (".\n"); + vt_key.string = "VersionString"; + version = prop_get_string(bundle, "S<-s", &vt_key); + if_print_string("Generator version "); + if_print_string(version); + if_print_string(".\n"); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -1990,62 +1823,58 @@ lib_cmd_version (sc_gameref_t game) * printfilter to avoid possible clashes with ALRs. */ sc_bool -lib_cmd_wait (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_int waitturns; +lib_cmd_wait(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_int waitturns; - /* Note if wait turns is different from the game's setting. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "WaitTurns"; - waitturns = prop_get_integer (bundle, "I<-ss", vt_key); - if (waitturns != game->waitturns) - { - sc_char buffer[32]; + /* Note if wait turns is different from the game's setting. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "WaitTurns"; + waitturns = prop_get_integer(bundle, "I<-ss", vt_key); + if (waitturns != game->waitturns) { + sc_char buffer[32]; - pf_buffer_string (filter, "("); - sprintf (buffer, "%ld", game->waitturns); - pf_buffer_string (filter, buffer); - pf_buffer_string (filter, - game->waitturns == 1 ? " turn)\n" : " turns)\n"); - } + pf_buffer_string(filter, "("); + sprintf(buffer, "%ld", game->waitturns); + pf_buffer_string(filter, buffer); + pf_buffer_string(filter, + game->waitturns == 1 ? " turn)\n" : " turns)\n"); + } - /* Reset the wait counter to the current waitturns setting. */ - game->waitcounter = game->waitturns; + /* Reset the wait counter to the current waitturns setting. */ + game->waitcounter = game->waitturns; - pf_buffer_string (filter, "Time passes...\n"); - return TRUE; + pf_buffer_string(filter, "Time passes...\n"); + return TRUE; } sc_bool -lib_cmd_wait_number (sc_gameref_t game) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int waitturns; - sc_char buffer[32]; +lib_cmd_wait_number(sc_gameref_t game) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int waitturns; + sc_char buffer[32]; - /* Get and validate the waitturns setting. */ - waitturns = var_get_ref_number (vars); - if (waitturns < 1 || waitturns > 20) - { - if_print_string ("You can only wait between 1 and 20 turns.\n"); - game->is_admin = TRUE; - return TRUE; - } + /* Get and validate the waitturns setting. */ + waitturns = var_get_ref_number(vars); + if (waitturns < 1 || waitturns > 20) { + if_print_string("You can only wait between 1 and 20 turns.\n"); + game->is_admin = TRUE; + return TRUE; + } - /* Update the game setting, and confirm for the player. */ - game->waitturns = waitturns; + /* Update the game setting, and confirm for the player. */ + game->waitturns = waitturns; - if_print_string ("The game will now wait "); - sprintf (buffer, "%ld", waitturns); - if_print_string (buffer); - if_print_string (waitturns == 1 ? " turn" : " turns"); - if_print_string (" for each 'wait' command you enter.\n"); + if_print_string("The game will now wait "); + sprintf(buffer, "%ld", waitturns); + if_print_string(buffer); + if_print_string(waitturns == 1 ? " turn" : " turns"); + if_print_string(" for each 'wait' command you enter.\n"); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -2057,35 +1886,33 @@ lib_cmd_wait_number (sc_gameref_t game) * printfilter to avoid possible clashes with ALRs. */ sc_bool -lib_cmd_verbose (sc_gameref_t game) -{ - /* Set game verbose flag and return. */ - game->verbose = TRUE; - if_print_string ("The game is now in its "); - if_print_tag (SC_TAG_ITALICS, ""); - if_print_string ("verbose"); - if_print_tag (SC_TAG_ENDITALICS, ""); - if_print_string (" mode, which always gives long descriptions of locations" - " (even if you've been there before).\n"); +lib_cmd_verbose(sc_gameref_t game) { + /* Set game verbose flag and return. */ + game->verbose = TRUE; + if_print_string("The game is now in its "); + if_print_tag(SC_TAG_ITALICS, ""); + if_print_string("verbose"); + if_print_tag(SC_TAG_ENDITALICS, ""); + if_print_string(" mode, which always gives long descriptions of locations" + " (even if you've been there before).\n"); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } sc_bool -lib_cmd_brief (sc_gameref_t game) -{ - /* Clear game verbose flag and return. */ - game->verbose = FALSE; - if_print_string ("The game is now in its "); - if_print_tag (SC_TAG_ITALICS, ""); - if_print_string ("brief"); - if_print_tag (SC_TAG_ENDITALICS, ""); - if_print_string (" mode, which gives long descriptions of places never" - " before visited and short descriptions otherwise.\n"); +lib_cmd_brief(sc_gameref_t game) { + /* Clear game verbose flag and return. */ + game->verbose = FALSE; + if_print_string("The game is now in its "); + if_print_tag(SC_TAG_ITALICS, ""); + if_print_string("brief"); + if_print_tag(SC_TAG_ENDITALICS, ""); + if_print_string(" mode, which gives long descriptions of places never" + " before visited and short descriptions otherwise.\n"); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -2097,67 +1924,57 @@ lib_cmd_brief (sc_gameref_t game) * rather than using the printfilter to avoid possible clashes with ALRs. */ sc_bool -lib_cmd_notify_on_off (sc_gameref_t game) -{ - const sc_var_setref_t vars = gs_get_vars (game); - const sc_char *control; - - /* Get the text following the notify command, and check for "on"/"off". */ - control = var_get_ref_text (vars); - if (sc_strcasecmp (control, "on") == 0) - { - /* Set score change notification. */ - game->notify_score_change = TRUE; - if_print_string ("Game score change notification is now "); - if_print_tag (SC_TAG_ITALICS, ""); - if_print_string ("on"); - if_print_tag (SC_TAG_ENDITALICS, ""); - if_print_string (", and the game will tell you of any changes in the" - " score.\n"); - } - else if (sc_strcasecmp (control, "off") == 0) - { - /* Clear score change notification. */ - game->notify_score_change = FALSE; - if_print_string ("Game score change notification is now "); - if_print_tag (SC_TAG_ITALICS, ""); - if_print_string ("off"); - if_print_tag (SC_TAG_ENDITALICS, ""); - if_print_string (", and the game will be silent on changes in the" - " score.\n"); - } - else - { - if_print_string ("Use 'notify on' or 'notify off' to control game" - " score notification.\n"); - } - - game->is_admin = TRUE; - return TRUE; -} - -sc_bool -lib_cmd_notify (sc_gameref_t game) -{ - /* Report the current state of notification. */ - if_print_string ("Game score change notification is "); - if_print_tag (SC_TAG_ITALICS, ""); - if_print_string (game->notify_score_change ? "on" : "off"); - if_print_tag (SC_TAG_ENDITALICS, ""); - - if (game->notify_score_change) - { - if_print_string (", and the game will tell you of any changes in the" - " score.\n"); - } - else - { - if_print_string (", and the game will be silent on changes in the" - " score.\n"); - } - - game->is_admin = TRUE; - return TRUE; +lib_cmd_notify_on_off(sc_gameref_t game) { + const sc_var_setref_t vars = gs_get_vars(game); + const sc_char *control; + + /* Get the text following the notify command, and check for "on"/"off". */ + control = var_get_ref_text(vars); + if (sc_strcasecmp(control, "on") == 0) { + /* Set score change notification. */ + game->notify_score_change = TRUE; + if_print_string("Game score change notification is now "); + if_print_tag(SC_TAG_ITALICS, ""); + if_print_string("on"); + if_print_tag(SC_TAG_ENDITALICS, ""); + if_print_string(", and the game will tell you of any changes in the" + " score.\n"); + } else if (sc_strcasecmp(control, "off") == 0) { + /* Clear score change notification. */ + game->notify_score_change = FALSE; + if_print_string("Game score change notification is now "); + if_print_tag(SC_TAG_ITALICS, ""); + if_print_string("off"); + if_print_tag(SC_TAG_ENDITALICS, ""); + if_print_string(", and the game will be silent on changes in the" + " score.\n"); + } else { + if_print_string("Use 'notify on' or 'notify off' to control game" + " score notification.\n"); + } + + game->is_admin = TRUE; + return TRUE; +} + +sc_bool +lib_cmd_notify(sc_gameref_t game) { + /* Report the current state of notification. */ + if_print_string("Game score change notification is "); + if_print_tag(SC_TAG_ITALICS, ""); + if_print_string(game->notify_score_change ? "on" : "off"); + if_print_tag(SC_TAG_ENDITALICS, ""); + + if (game->notify_score_change) { + if_print_string(", and the game will tell you of any changes in the" + " score.\n"); + } else { + if_print_string(", and the game will be silent on changes in the" + " score.\n"); + } + + game->is_admin = TRUE; + return TRUE; } @@ -2170,39 +1987,37 @@ lib_cmd_notify (sc_gameref_t game) * different. */ sc_bool -lib_cmd_time (sc_gameref_t game) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_uint timestamp; - sc_int hr, min, sec; - sc_char buffer[64]; +lib_cmd_time(sc_gameref_t game) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_uint timestamp; + sc_int hr, min, sec; + sc_char buffer[64]; - /* Get elapsed game time and convert to hour, minutes, and seconds. */ - timestamp = var_get_elapsed_seconds (vars); - hr = timestamp / SECS_PER_HOUR; - min = (timestamp % SECS_PER_HOUR) / MINS_PER_HOUR; - sec = timestamp % SECS_PER_MINUTE; - if (hr > 0) - sprintf (buffer, "%ldh %02ldm %02lds", hr, min, sec); - else - sprintf (buffer, "%ldm %02lds", min, sec); + /* Get elapsed game time and convert to hour, minutes, and seconds. */ + timestamp = var_get_elapsed_seconds(vars); + hr = timestamp / SECS_PER_HOUR; + min = (timestamp % SECS_PER_HOUR) / MINS_PER_HOUR; + sec = timestamp % SECS_PER_MINUTE; + if (hr > 0) + sprintf(buffer, "%ldh %02ldm %02lds", hr, min, sec); + else + sprintf(buffer, "%ldm %02lds", min, sec); - /* Print the game's elapsed time. */ - if_print_string ("You have been running the game for "); - if_print_string (buffer); - if_print_string (".\n"); + /* Print the game's elapsed time. */ + if_print_string("You have been running the game for "); + if_print_string(buffer); + if_print_string(".\n"); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } sc_bool -lib_cmd_date (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_date(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "Maybe we should just be good friends.\n"); - return TRUE; + pf_buffer_string(filter, "Maybe we should just be good friends.\n"); + return TRUE; } @@ -2211,10 +2026,10 @@ lib_cmd_date (sc_gameref_t game) * into a single function. The values are explicit to ensure they match * enumerations in the game data. */ -enum -{ DIR_NORTH = 0, DIR_EAST = 1, DIR_SOUTH = 2, DIR_WEST = 3, - DIR_UP = 4, DIR_DOWN = 5, DIR_IN = 6, DIR_OUT = 7, - DIR_NORTHEAST = 8, DIR_SOUTHEAST = 9, DIR_SOUTHWEST = 10, DIR_NORTHWEST = 11 +enum { + DIR_NORTH = 0, DIR_EAST = 1, DIR_SOUTH = 2, DIR_WEST = 3, + DIR_UP = 4, DIR_DOWN = 5, DIR_IN = 6, DIR_OUT = 7, + DIR_NORTHEAST = 8, DIR_SOUTHEAST = 9, DIR_SOUTHWEST = 10, DIR_NORTHWEST = 11 }; @@ -2224,137 +2039,123 @@ enum * Central movement command, called by all movement handlers. */ static sc_bool -lib_go (sc_gameref_t game, sc_int direction) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5], vt_rvalue; - sc_bool eightpointcompass, is_trapped, is_exitable[12]; - sc_int destination, index_; - const sc_char *const *dirnames; - - /* Decide on four or eight point compass names list. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "EightPointCompass"; - eightpointcompass = prop_get_boolean (bundle, "B<-ss", vt_key); - dirnames = eightpointcompass ? DIRNAMES_8 : DIRNAMES_4; - - /* Start by seeing if there are any exits at all available. */ - is_trapped = TRUE; - for (index_ = 0; dirnames[index_]; index_++) - { - vt_key[0].string = "Rooms"; - vt_key[1].integer = gs_playerroom (game); - vt_key[2].string = "Exits"; - vt_key[3].integer = index_; - if (prop_get (bundle, "I<-sisi", &vt_rvalue, vt_key) - && lib_can_go (game, gs_playerroom (game), index_)) - { - is_exitable[index_] = TRUE; - is_trapped = FALSE; - } - else - is_exitable[index_] = FALSE; - } - if (is_trapped) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't go in any direction!\n", - "I can't go in any direction!\n", - "%player% can't go in any direction!\n")); - return TRUE; - } - - /* - * Check for the exit, and if it doesn't exist, refuse, and list the possible - * options. - */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = gs_playerroom (game); - vt_key[2].string = "Exits"; - vt_key[3].integer = direction; - vt_key[4].string = "Dest"; - if (prop_get (bundle, "I<-sisis", &vt_rvalue, vt_key)) - destination = vt_rvalue.integer - 1; - else - { - sc_int count, trail; - - pf_buffer_string (filter, - lib_select_response (game, - "You can't go in that direction, but you can move ", - "I can't go in that direction, but I can move ", - "%player% can't go in that direction, but can move ")); - - /* List available exits, found in exit test loop earlier. */ - count = 0; - trail = -1; - for (index_ = 0; dirnames[index_]; index_++) - { - if (is_exitable[index_]) - { - if (count > 0) - { - if (count > 1) - pf_buffer_string (filter, ", "); - pf_buffer_string (filter, dirnames[trail]); - } - trail = index_; - count++; - } - } - if (count >= 1) - { - if (count > 1) - pf_buffer_string (filter, " and "); - pf_buffer_string (filter, dirnames[trail]); - } - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - /* Check for any movement restrictions. */ - if (!lib_can_go (game, gs_playerroom (game), direction)) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't go in that direction (at present).\n", - "I can't go in that direction (at present).\n", - "%player% can't go in that direction (at present).\n")); - return TRUE; - } - - if (lib_trace) - { - sc_trace ("Library: moving player from %ld to %ld\n", - gs_playerroom (game), destination); - } - - /* Indicate if getting off something or standing up first. */ - if (gs_playerparent (game) != -1) - { - pf_buffer_string (filter, "(Getting off "); - lib_print_object_np (game, gs_playerparent (game)); - pf_buffer_string (filter, " first)\n"); - } - else if (gs_playerposition (game) != 0) - pf_buffer_string (filter, "(Standing up first)\n"); - - /* Confirm and then make move. */ - pf_buffer_string (filter, - lib_select_response (game, - "You move ", - "I move ", - "%player% moves ")); - pf_buffer_string (filter, dirnames[direction]); - pf_buffer_string (filter, ".\n"); - - gs_move_player_to_room (game, destination); - - /* Describe the new room and return. */ - lib_describe_player_room (game, FALSE); - return TRUE; +lib_go(sc_gameref_t game, sc_int direction) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5], vt_rvalue; + sc_bool eightpointcompass, is_trapped, is_exitable[12]; + sc_int destination, index_; + const sc_char *const *dirnames; + + /* Decide on four or eight point compass names list. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "EightPointCompass"; + eightpointcompass = prop_get_boolean(bundle, "B<-ss", vt_key); + dirnames = eightpointcompass ? DIRNAMES_8 : DIRNAMES_4; + + /* Start by seeing if there are any exits at all available. */ + is_trapped = TRUE; + for (index_ = 0; dirnames[index_]; index_++) { + vt_key[0].string = "Rooms"; + vt_key[1].integer = gs_playerroom(game); + vt_key[2].string = "Exits"; + vt_key[3].integer = index_; + if (prop_get(bundle, "I<-sisi", &vt_rvalue, vt_key) + && lib_can_go(game, gs_playerroom(game), index_)) { + is_exitable[index_] = TRUE; + is_trapped = FALSE; + } else + is_exitable[index_] = FALSE; + } + if (is_trapped) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't go in any direction!\n", + "I can't go in any direction!\n", + "%player% can't go in any direction!\n")); + return TRUE; + } + + /* + * Check for the exit, and if it doesn't exist, refuse, and list the possible + * options. + */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = gs_playerroom(game); + vt_key[2].string = "Exits"; + vt_key[3].integer = direction; + vt_key[4].string = "Dest"; + if (prop_get(bundle, "I<-sisis", &vt_rvalue, vt_key)) + destination = vt_rvalue.integer - 1; + else { + sc_int count, trail; + + pf_buffer_string(filter, + lib_select_response(game, + "You can't go in that direction, but you can move ", + "I can't go in that direction, but I can move ", + "%player% can't go in that direction, but can move ")); + + /* List available exits, found in exit test loop earlier. */ + count = 0; + trail = -1; + for (index_ = 0; dirnames[index_]; index_++) { + if (is_exitable[index_]) { + if (count > 0) { + if (count > 1) + pf_buffer_string(filter, ", "); + pf_buffer_string(filter, dirnames[trail]); + } + trail = index_; + count++; + } + } + if (count >= 1) { + if (count > 1) + pf_buffer_string(filter, " and "); + pf_buffer_string(filter, dirnames[trail]); + } + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + /* Check for any movement restrictions. */ + if (!lib_can_go(game, gs_playerroom(game), direction)) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't go in that direction (at present).\n", + "I can't go in that direction (at present).\n", + "%player% can't go in that direction (at present).\n")); + return TRUE; + } + + if (lib_trace) { + sc_trace("Library: moving player from %ld to %ld\n", + gs_playerroom(game), destination); + } + + /* Indicate if getting off something or standing up first. */ + if (gs_playerparent(game) != -1) { + pf_buffer_string(filter, "(Getting off "); + lib_print_object_np(game, gs_playerparent(game)); + pf_buffer_string(filter, " first)\n"); + } else if (gs_playerposition(game) != 0) + pf_buffer_string(filter, "(Standing up first)\n"); + + /* Confirm and then make move. */ + pf_buffer_string(filter, + lib_select_response(game, + "You move ", + "I move ", + "%player% moves ")); + pf_buffer_string(filter, dirnames[direction]); + pf_buffer_string(filter, ".\n"); + + gs_move_player_to_room(game, destination); + + /* Describe the new room and return. */ + lib_describe_player_room(game, FALSE); + return TRUE; } @@ -2364,75 +2165,63 @@ lib_go (sc_gameref_t game, sc_int direction) * Direction-specific movement commands. */ sc_bool -lib_cmd_go_north (sc_gameref_t game) -{ - return lib_go (game, DIR_NORTH); +lib_cmd_go_north(sc_gameref_t game) { + return lib_go(game, DIR_NORTH); } sc_bool -lib_cmd_go_east (sc_gameref_t game) -{ - return lib_go (game, DIR_EAST); +lib_cmd_go_east(sc_gameref_t game) { + return lib_go(game, DIR_EAST); } sc_bool -lib_cmd_go_south (sc_gameref_t game) -{ - return lib_go (game, DIR_SOUTH); +lib_cmd_go_south(sc_gameref_t game) { + return lib_go(game, DIR_SOUTH); } sc_bool -lib_cmd_go_west (sc_gameref_t game) -{ - return lib_go (game, DIR_WEST); +lib_cmd_go_west(sc_gameref_t game) { + return lib_go(game, DIR_WEST); } sc_bool -lib_cmd_go_up (sc_gameref_t game) -{ - return lib_go (game, DIR_UP); +lib_cmd_go_up(sc_gameref_t game) { + return lib_go(game, DIR_UP); } sc_bool -lib_cmd_go_down (sc_gameref_t game) -{ - return lib_go (game, DIR_DOWN); +lib_cmd_go_down(sc_gameref_t game) { + return lib_go(game, DIR_DOWN); } sc_bool -lib_cmd_go_in (sc_gameref_t game) -{ - return lib_go (game, DIR_IN); +lib_cmd_go_in(sc_gameref_t game) { + return lib_go(game, DIR_IN); } sc_bool -lib_cmd_go_out (sc_gameref_t game) -{ - return lib_go (game, DIR_OUT); +lib_cmd_go_out(sc_gameref_t game) { + return lib_go(game, DIR_OUT); } sc_bool -lib_cmd_go_northeast (sc_gameref_t game) -{ - return lib_go (game, DIR_NORTHEAST); +lib_cmd_go_northeast(sc_gameref_t game) { + return lib_go(game, DIR_NORTHEAST); } sc_bool -lib_cmd_go_southeast (sc_gameref_t game) -{ - return lib_go (game, DIR_SOUTHEAST); +lib_cmd_go_southeast(sc_gameref_t game) { + return lib_go(game, DIR_SOUTHEAST); } sc_bool -lib_cmd_go_northwest (sc_gameref_t game) -{ - return lib_go (game, DIR_NORTHWEST); +lib_cmd_go_northwest(sc_gameref_t game) { + return lib_go(game, DIR_NORTHWEST); } sc_bool -lib_cmd_go_southwest (sc_gameref_t game) -{ - return lib_go (game, DIR_SOUTHWEST); +lib_cmd_go_southwest(sc_gameref_t game) { + return lib_go(game, DIR_SOUTHWEST); } @@ -2444,34 +2233,33 @@ lib_cmd_go_southwest (sc_gameref_t game) * requires that string is filtered, stripped, trimmed and normalized. */ static sc_bool -lib_compare_rooms (sc_gameref_t game, sc_int room, const sc_char *string) -{ - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_char *name, *compare_name; - sc_bool status; +lib_compare_rooms(sc_gameref_t game, sc_int room, const sc_char *string) { + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_char *name, *compare_name; + sc_bool status; - /* Get the name of the room, and filter it down to a plain string. */ - name = pf_filter (lib_get_room_name (game, room), vars, bundle); - pf_strip_tags (name); - sc_normalize_string (sc_trim_string (name)); + /* Get the name of the room, and filter it down to a plain string. */ + name = pf_filter(lib_get_room_name(game, room), vars, bundle); + pf_strip_tags(name); + sc_normalize_string(sc_trim_string(name)); - /* Bypass any prefix on the room name. */ - if (sc_compare_word (name, "a", 1)) - compare_name = name + 1; - else if (sc_compare_word (name, "an", 2)) - compare_name = name + 2; - else if (sc_compare_word (name, "the", 3)) - compare_name = name + 3; - else - compare_name = name; - sc_trim_string (compare_name); + /* Bypass any prefix on the room name. */ + if (sc_compare_word(name, "a", 1)) + compare_name = name + 1; + else if (sc_compare_word(name, "an", 2)) + compare_name = name + 2; + else if (sc_compare_word(name, "the", 3)) + compare_name = name + 3; + else + compare_name = name; + sc_trim_string(compare_name); - /* Compare strings, then free the allocated name. */ - status = sc_strcasecmp (compare_name, string) == 0; - sc_free (name); + /* Compare strings, then free the allocated name. */ + status = sc_strcasecmp(compare_name, string) == 0; + sc_free(name); - return status; + return status; } @@ -2488,118 +2276,108 @@ lib_compare_rooms (sc_gameref_t game, sc_int room, const sc_char *string) * differentiated within the game with trailing "" components. */ sc_bool -lib_cmd_go_room (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5], vt_rvalue; - sc_bool eightpointcompass, is_trapped, is_ambiguous; - sc_int direction, destination, index_; - const sc_char *const *dirnames; - sc_char *name, *compare_name; - - /* Determine the requested room, and filter it down to a plain string. */ - name = pf_filter (var_get_ref_text (vars), vars, bundle); - pf_strip_tags (name); - sc_normalize_string (sc_trim_string (name)); - - /* Bypass any prefix on the request room name. */ - if (sc_compare_word (name, "a", 1)) - compare_name = name + 1; - else if (sc_compare_word (name, "an", 2)) - compare_name = name + 2; - else if (sc_compare_word (name, "the", 3)) - compare_name = name + 3; - else - compare_name = name; - sc_trim_string (compare_name); - - /* See if the named room is the current player room. */ - if (lib_compare_rooms (game, gs_playerroom (game), compare_name)) - { - pf_buffer_string (filter, "You are already there!\n"); - sc_free (name); - return TRUE; - } - - /* Decide on four or eight point compass names list. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "EightPointCompass"; - eightpointcompass = prop_get_boolean (bundle, "B<-ss", vt_key); - dirnames = eightpointcompass ? DIRNAMES_8 : DIRNAMES_4; - - /* Search adjacent and available rooms for a name match. */ - is_trapped = TRUE; - is_ambiguous = FALSE; - direction = -1; - destination = -1; - for (index_ = 0; dirnames[index_]; index_++) - { - vt_key[0].string = "Rooms"; - vt_key[1].integer = gs_playerroom (game); - vt_key[2].string = "Exits"; - vt_key[3].integer = index_; - if (prop_get (bundle, "I<-sisi", &vt_rvalue, vt_key) - && lib_can_go (game, gs_playerroom (game), index_)) - { - is_trapped = FALSE; - - /* - * Room is available. Compare its name with that requested provided - * that it's a location we've not already accepted (that is, some - * rooms are reachable by multiple directions, such as both "south" - * and "out"). - */ - vt_key[4].string = "Dest"; - if (prop_get (bundle, "I<-sisis", &vt_rvalue, vt_key)) - { - sc_int location; - - location = vt_rvalue.integer - 1; - if (location != destination - && lib_compare_rooms (game, location, compare_name)) - { - if (direction != -1) - is_ambiguous = TRUE; - direction = index_; - destination = location; - } - } - } - } - sc_free (name); - - /* If trapped or it's unclear where to go, handle these cases. */ - if (is_trapped) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't go in any direction!\n", - "I can't go in any direction!\n", - "%player% can't go in any direction!\n")); - return TRUE; - } - else if (is_ambiguous) - { - pf_buffer_string (filter, - "I'm not clear about where you want to go." - " Please try using just a direction.\n"); - pf_buffer_character (filter, '\n'); - lib_cmd_print_room_exits (game); - return TRUE; - } - - /* If no match, note it, otherwise handle as standard directional move. */ - if (direction == -1) - { - pf_buffer_string (filter, "I don't know how to get there from here.\n"); - pf_buffer_character (filter, '\n'); - lib_cmd_print_room_exits (game); - return TRUE; - } - - return lib_go (game, direction); +lib_cmd_go_room(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5], vt_rvalue; + sc_bool eightpointcompass, is_trapped, is_ambiguous; + sc_int direction, destination, index_; + const sc_char *const *dirnames; + sc_char *name, *compare_name; + + /* Determine the requested room, and filter it down to a plain string. */ + name = pf_filter(var_get_ref_text(vars), vars, bundle); + pf_strip_tags(name); + sc_normalize_string(sc_trim_string(name)); + + /* Bypass any prefix on the request room name. */ + if (sc_compare_word(name, "a", 1)) + compare_name = name + 1; + else if (sc_compare_word(name, "an", 2)) + compare_name = name + 2; + else if (sc_compare_word(name, "the", 3)) + compare_name = name + 3; + else + compare_name = name; + sc_trim_string(compare_name); + + /* See if the named room is the current player room. */ + if (lib_compare_rooms(game, gs_playerroom(game), compare_name)) { + pf_buffer_string(filter, "You are already there!\n"); + sc_free(name); + return TRUE; + } + + /* Decide on four or eight point compass names list. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "EightPointCompass"; + eightpointcompass = prop_get_boolean(bundle, "B<-ss", vt_key); + dirnames = eightpointcompass ? DIRNAMES_8 : DIRNAMES_4; + + /* Search adjacent and available rooms for a name match. */ + is_trapped = TRUE; + is_ambiguous = FALSE; + direction = -1; + destination = -1; + for (index_ = 0; dirnames[index_]; index_++) { + vt_key[0].string = "Rooms"; + vt_key[1].integer = gs_playerroom(game); + vt_key[2].string = "Exits"; + vt_key[3].integer = index_; + if (prop_get(bundle, "I<-sisi", &vt_rvalue, vt_key) + && lib_can_go(game, gs_playerroom(game), index_)) { + is_trapped = FALSE; + + /* + * Room is available. Compare its name with that requested provided + * that it's a location we've not already accepted (that is, some + * rooms are reachable by multiple directions, such as both "south" + * and "out"). + */ + vt_key[4].string = "Dest"; + if (prop_get(bundle, "I<-sisis", &vt_rvalue, vt_key)) { + sc_int location; + + location = vt_rvalue.integer - 1; + if (location != destination + && lib_compare_rooms(game, location, compare_name)) { + if (direction != -1) + is_ambiguous = TRUE; + direction = index_; + destination = location; + } + } + } + } + sc_free(name); + + /* If trapped or it's unclear where to go, handle these cases. */ + if (is_trapped) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't go in any direction!\n", + "I can't go in any direction!\n", + "%player% can't go in any direction!\n")); + return TRUE; + } else if (is_ambiguous) { + pf_buffer_string(filter, + "I'm not clear about where you want to go." + " Please try using just a direction.\n"); + pf_buffer_character(filter, '\n'); + lib_cmd_print_room_exits(game); + return TRUE; + } + + /* If no match, note it, otherwise handle as standard directional move. */ + if (direction == -1) { + pf_buffer_string(filter, "I don't know how to get there from here.\n"); + pf_buffer_character(filter, '\n'); + lib_cmd_print_room_exits(game); + return TRUE; + } + + return lib_go(game, direction); } @@ -2609,121 +2387,108 @@ lib_cmd_go_room (sc_gameref_t game) * Show the long description of a player. */ sc_bool -lib_cmd_examine_self (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_int task, object, count, trail; - const sc_char *description, *position = NULL; - - /* Get selection task. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "Task"; - task = prop_get_integer (bundle, "I<-ss", vt_key) - 1; - - /* Select either the main or the alternate description. */ - if (task >= 0 && gs_task_done (game, task)) - vt_key[1].string = "AltDesc"; - else - vt_key[1].string = "PlayerDesc"; - - /* Print the description, or default response. */ - description = prop_get_string (bundle, "S<-ss", vt_key); - if (!sc_strempty (description)) - pf_buffer_string (filter, description); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are as well as can be expected," - " considering the circumstances.", - "I am as well as can be expected," - " considering the circumstances.", - "%player% is as well as can be expected," - " considering the circumstances.")); - } - - /* If not just standing on the floor, say more. */ - switch (gs_playerposition (game)) - { - case 0: - position = lib_select_response (game, - "You are standing", - "I am standing", - "%player% is standing"); - break; - case 1: - position = lib_select_response (game, - "You are sitting down", - "I am sitting down", - "%player% is sitting down"); - break; - case 2: - position = lib_select_response (game, - "You are lying down", - "I am lying down", - "%player% is lying down"); - break; - } - - if (position - && !(gs_playerposition (game) == 0 && gs_playerparent (game) == -1)) - { - pf_buffer_string (filter, " "); - pf_buffer_string (filter, position); - if (gs_playerparent (game) != -1) - { - pf_buffer_string (filter, " on "); - lib_print_object_np (game, gs_playerparent (game)); - } - pf_buffer_character (filter, '.'); - } - - /* Find and list each object worn by the player. */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_WORN_PLAYER) - { - if (count > 0) - { - if (count == 1) - { - pf_buffer_string (filter, - lib_select_response (game, - " You are wearing ", - " I am wearing ", - " %player% is wearing ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - pf_buffer_string (filter, - lib_select_response (game, - " You are wearing ", - " I am wearing ", - " %player% is wearing ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object (game, trail); - pf_buffer_character (filter, '.'); - } - - pf_buffer_character (filter, '\n'); - return TRUE; +lib_cmd_examine_self(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_int task, object, count, trail; + const sc_char *description, *position = NULL; + + /* Get selection task. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "Task"; + task = prop_get_integer(bundle, "I<-ss", vt_key) - 1; + + /* Select either the main or the alternate description. */ + if (task >= 0 && gs_task_done(game, task)) + vt_key[1].string = "AltDesc"; + else + vt_key[1].string = "PlayerDesc"; + + /* Print the description, or default response. */ + description = prop_get_string(bundle, "S<-ss", vt_key); + if (!sc_strempty(description)) + pf_buffer_string(filter, description); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are as well as can be expected," + " considering the circumstances.", + "I am as well as can be expected," + " considering the circumstances.", + "%player% is as well as can be expected," + " considering the circumstances.")); + } + + /* If not just standing on the floor, say more. */ + switch (gs_playerposition(game)) { + case 0: + position = lib_select_response(game, + "You are standing", + "I am standing", + "%player% is standing"); + break; + case 1: + position = lib_select_response(game, + "You are sitting down", + "I am sitting down", + "%player% is sitting down"); + break; + case 2: + position = lib_select_response(game, + "You are lying down", + "I am lying down", + "%player% is lying down"); + break; + } + + if (position + && !(gs_playerposition(game) == 0 && gs_playerparent(game) == -1)) { + pf_buffer_string(filter, " "); + pf_buffer_string(filter, position); + if (gs_playerparent(game) != -1) { + pf_buffer_string(filter, " on "); + lib_print_object_np(game, gs_playerparent(game)); + } + pf_buffer_character(filter, '.'); + } + + /* Find and list each object worn by the player. */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_WORN_PLAYER) { + if (count > 0) { + if (count == 1) { + pf_buffer_string(filter, + lib_select_response(game, + " You are wearing ", + " I am wearing ", + " %player% is wearing ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + pf_buffer_string(filter, + lib_select_response(game, + " You are wearing ", + " I am wearing ", + " %player% is wearing ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object(game, trail); + pf_buffer_character(filter, '.'); + } + + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -2737,83 +2502,74 @@ lib_cmd_examine_self (sc_gameref_t game) * return -1. */ static sc_int -lib_disambiguate_npc (sc_gameref_t game, - const sc_char *verb, sc_bool *is_ambiguous) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int count, index_, npc, listed; - - /* - * Filter out all referenced NPCs not actually visible or seen. Count the - * number of NPCs remaining as referenced by the last command, and note the - * last referenced NPC, for where count is 1. - */ - count = 0; - npc = -1; - for (index_ = 0; index_ < gs_npc_count (game); index_++) - { - if (game->npc_references[index_] - && gs_npc_seen (game, index_) - && npc_in_room (game, index_, gs_playerroom (game))) - { - count++; - npc = index_; - } - else - game->npc_references[index_] = FALSE; - } - - /* If the reference is unambiguous, set in variables and return it. */ - if (count == 1) - { - /* Set this NPC as the referenced character. */ - var_set_ref_character (vars, npc); - - /* Return, setting no ambiguity. */ - if (is_ambiguous) - *is_ambiguous = FALSE; - return npc; - } - - /* If nothing referenced, return no NPC. */ - if (count == 0) - { - if (is_ambiguous) - *is_ambiguous = FALSE; - else - { - pf_buffer_string (filter, - "Please be more clear, who do you want to "); - pf_buffer_string (filter, verb); - pf_buffer_string (filter, "?\n"); - } - return -1; - } - - /* The NPC reference is ambiguous, so list the choices. */ - pf_buffer_string (filter, "Please be more clear, who do you want to "); - pf_buffer_string (filter, verb); - pf_buffer_string (filter, "? "); - - pf_new_sentence (filter); - listed = 0; - for (index_ = 0; index_ < gs_npc_count (game); index_++) - { - if (game->npc_references[index_]) - { - lib_print_npc_np (game, index_); - listed++; - if (listed < count) - pf_buffer_string (filter, (listed < count - 1) ? ", " : " or "); - } - } - pf_buffer_string (filter, "?\n"); - - /* Return no NPC for an ambiguous reference. */ - if (is_ambiguous) - *is_ambiguous = TRUE; - return -1; +lib_disambiguate_npc(sc_gameref_t game, + const sc_char *verb, sc_bool *is_ambiguous) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int count, index_, npc, listed; + + /* + * Filter out all referenced NPCs not actually visible or seen. Count the + * number of NPCs remaining as referenced by the last command, and note the + * last referenced NPC, for where count is 1. + */ + count = 0; + npc = -1; + for (index_ = 0; index_ < gs_npc_count(game); index_++) { + if (game->npc_references[index_] + && gs_npc_seen(game, index_) + && npc_in_room(game, index_, gs_playerroom(game))) { + count++; + npc = index_; + } else + game->npc_references[index_] = FALSE; + } + + /* If the reference is unambiguous, set in variables and return it. */ + if (count == 1) { + /* Set this NPC as the referenced character. */ + var_set_ref_character(vars, npc); + + /* Return, setting no ambiguity. */ + if (is_ambiguous) + *is_ambiguous = FALSE; + return npc; + } + + /* If nothing referenced, return no NPC. */ + if (count == 0) { + if (is_ambiguous) + *is_ambiguous = FALSE; + else { + pf_buffer_string(filter, + "Please be more clear, who do you want to "); + pf_buffer_string(filter, verb); + pf_buffer_string(filter, "?\n"); + } + return -1; + } + + /* The NPC reference is ambiguous, so list the choices. */ + pf_buffer_string(filter, "Please be more clear, who do you want to "); + pf_buffer_string(filter, verb); + pf_buffer_string(filter, "? "); + + pf_new_sentence(filter); + listed = 0; + for (index_ = 0; index_ < gs_npc_count(game); index_++) { + if (game->npc_references[index_]) { + lib_print_npc_np(game, index_); + listed++; + if (listed < count) + pf_buffer_string(filter, (listed < count - 1) ? ", " : " or "); + } + } + pf_buffer_string(filter, "?\n"); + + /* Return no NPC for an ambiguous reference. */ + if (is_ambiguous) + *is_ambiguous = TRUE; + return -1; } @@ -2835,158 +2591,141 @@ lib_disambiguate_npc (sc_gameref_t game, * function used to filter objects for multiple references. */ static sc_int -lib_disambiguate_object_common (sc_gameref_t game, const sc_char *verb, - sc_bool (*resolver) - (sc_gameref_t, sc_int, sc_int), +lib_disambiguate_object_common(sc_gameref_t game, const sc_char *verb, + sc_bool(*resolver) + (sc_gameref_t, sc_int, sc_int), sc_int resolver_arg, - sc_bool *is_ambiguous) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int count, index_, object, listed; - - /* - * Filter out all referenced objects not actually visible or seen. Count - * the number of objects remaining as referenced by the last command, and - * note the last referenced object, for where count is 1. - */ - count = 0; - object = -1; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (game->object_references[index_] - && gs_object_seen (game, index_) - && obj_indirectly_in_room (game, index_, gs_playerroom (game))) - { - count++; - object = index_; - } - else - game->object_references[index_] = FALSE; - } - - /* - * If this reference is ambiguous and a resolver was supplied, try to - * resolve it unambiguously by calling the resolver filter on the remaining - * set references. - */ - if (resolver && count > 1) - { - sc_int retry_count; - - /* - * Search for objects accepted by the resolver filter, but don't filter - * references just yet. Again, note the last referenced. - */ - retry_count = 0; - object = -1; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (game->object_references[index_] - && resolver (game, index_, resolver_arg)) - { - retry_count++; - object = index_; - } - } - - /* See if we narrowed the field without eliminating every object. */ - if (retry_count > 0 && retry_count < count) - { - /* - * If we got down to a single object, the ambiguity is resolved. - * In this case, set count to 1 so that 'object' is returned. - */ - if (retry_count == 1) - count = retry_count; - else - { - /* - * We got down to fewer objects; reduce references so that the - * disambiguation message is clearer. Note that here we still - * leave with count greater than 1. - */ - count = 0; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (game->object_references[index_] - && resolver (game, index_, resolver_arg)) - count++; - else - game->object_references[index_] = FALSE; - } - } - } - } - - /* If the reference is unambiguous, set in variables and return it. */ - if (count == 1) - { - /* Set this object as referenced. */ - var_set_ref_object (vars, object); - - /* Return, setting no ambiguity. */ - if (is_ambiguous) - *is_ambiguous = FALSE; - return object; - } - - /* If nothing referenced, return no object. */ - if (count == 0) - { - if (is_ambiguous) - *is_ambiguous = FALSE; - else - { - pf_buffer_string (filter, - "Please be more clear, what do you want to "); - pf_buffer_string (filter, verb); - pf_buffer_string (filter, "?\n"); - } - return -1; - } - - /* The object reference is ambiguous, so list the choices. */ - pf_buffer_string (filter, "Please be more clear, what do you want to "); - pf_buffer_string (filter, verb); - pf_buffer_string (filter, "? "); - - pf_new_sentence (filter); - listed = 0; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (game->object_references[index_]) - { - lib_print_object_np (game, index_); - listed++; - if (listed < count) - pf_buffer_string (filter, (listed < count - 1) ? ", " : " or "); - } - } - pf_buffer_string (filter, "?\n"); - - /* Return no object for an ambiguous reference. */ - if (is_ambiguous) - *is_ambiguous = TRUE; - return -1; + sc_bool *is_ambiguous) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int count, index_, object, listed; + + /* + * Filter out all referenced objects not actually visible or seen. Count + * the number of objects remaining as referenced by the last command, and + * note the last referenced object, for where count is 1. + */ + count = 0; + object = -1; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (game->object_references[index_] + && gs_object_seen(game, index_) + && obj_indirectly_in_room(game, index_, gs_playerroom(game))) { + count++; + object = index_; + } else + game->object_references[index_] = FALSE; + } + + /* + * If this reference is ambiguous and a resolver was supplied, try to + * resolve it unambiguously by calling the resolver filter on the remaining + * set references. + */ + if (resolver && count > 1) { + sc_int retry_count; + + /* + * Search for objects accepted by the resolver filter, but don't filter + * references just yet. Again, note the last referenced. + */ + retry_count = 0; + object = -1; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (game->object_references[index_] + && resolver(game, index_, resolver_arg)) { + retry_count++; + object = index_; + } + } + + /* See if we narrowed the field without eliminating every object. */ + if (retry_count > 0 && retry_count < count) { + /* + * If we got down to a single object, the ambiguity is resolved. + * In this case, set count to 1 so that 'object' is returned. + */ + if (retry_count == 1) + count = retry_count; + else { + /* + * We got down to fewer objects; reduce references so that the + * disambiguation message is clearer. Note that here we still + * leave with count greater than 1. + */ + count = 0; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (game->object_references[index_] + && resolver(game, index_, resolver_arg)) + count++; + else + game->object_references[index_] = FALSE; + } + } + } + } + + /* If the reference is unambiguous, set in variables and return it. */ + if (count == 1) { + /* Set this object as referenced. */ + var_set_ref_object(vars, object); + + /* Return, setting no ambiguity. */ + if (is_ambiguous) + *is_ambiguous = FALSE; + return object; + } + + /* If nothing referenced, return no object. */ + if (count == 0) { + if (is_ambiguous) + *is_ambiguous = FALSE; + else { + pf_buffer_string(filter, + "Please be more clear, what do you want to "); + pf_buffer_string(filter, verb); + pf_buffer_string(filter, "?\n"); + } + return -1; + } + + /* The object reference is ambiguous, so list the choices. */ + pf_buffer_string(filter, "Please be more clear, what do you want to "); + pf_buffer_string(filter, verb); + pf_buffer_string(filter, "? "); + + pf_new_sentence(filter); + listed = 0; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (game->object_references[index_]) { + lib_print_object_np(game, index_); + listed++; + if (listed < count) + pf_buffer_string(filter, (listed < count - 1) ? ", " : " or "); + } + } + pf_buffer_string(filter, "?\n"); + + /* Return no object for an ambiguous reference. */ + if (is_ambiguous) + *is_ambiguous = TRUE; + return -1; } static sc_int -lib_disambiguate_object (sc_gameref_t game, - const sc_char *verb, sc_bool *is_ambiguous) -{ - return lib_disambiguate_object_common (game, verb, NULL, -1, is_ambiguous); +lib_disambiguate_object(sc_gameref_t game, + const sc_char *verb, sc_bool *is_ambiguous) { + return lib_disambiguate_object_common(game, verb, NULL, -1, is_ambiguous); } static sc_int -lib_disambiguate_object_extended (sc_gameref_t game, const sc_char *verb, - sc_bool (*resolver) - (sc_gameref_t, sc_int, sc_int), - sc_int resolver_arg, - sc_bool *is_ambiguous) -{ - return lib_disambiguate_object_common (game, verb, - resolver, resolver_arg, is_ambiguous); +lib_disambiguate_object_extended(sc_gameref_t game, const sc_char *verb, + sc_bool(*resolver) + (sc_gameref_t, sc_int, sc_int), + sc_int resolver_arg, + sc_bool *is_ambiguous) { + return lib_disambiguate_object_common(game, verb, + resolver, resolver_arg, is_ambiguous); } @@ -2996,116 +2735,93 @@ lib_disambiguate_object_extended (sc_gameref_t game, const sc_char *verb, * List objects carried and worn by an NPC. */ static sc_bool -lib_list_npc_inventory (sc_gameref_t game, sc_int npc, sc_bool is_described) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object, count, trail; - sc_bool wearing; - - /* Find and list each object worn by the NPC. */ - count = 0; - trail = -1; - wearing = FALSE; - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_WORN_NPC - && gs_object_parent (game, object) == npc) - { - if (count > 0) - { - if (count == 1) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " is wearing "); - } - else - pf_buffer_string (filter, ", "); - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " is wearing "); - } - else - pf_buffer_string (filter, " and "); - lib_print_object (game, trail); - wearing = TRUE; - } - - /* Find and list each object owned by the NPC. */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_HELD_NPC - && gs_object_parent (game, object) == npc) - { - if (count > 0) - { - if (count == 1) - { - if (!wearing) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_npc_np (game, npc); - } - else - pf_buffer_string (filter, ", and"); - pf_buffer_string (filter, " is carrying "); - } - else - pf_buffer_string (filter, ", "); - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - if (!wearing) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_npc_np (game, npc); - } - else - pf_buffer_string (filter, ", and"); - pf_buffer_string (filter, " is carrying "); - } - else - pf_buffer_string (filter, " and "); - lib_print_object (game, trail); - pf_buffer_character (filter, '.'); - } - else - { - if (wearing) - pf_buffer_character (filter, '.'); - } - - /* Return TRUE if anything worn or carried. */ - return wearing || count > 0; +lib_list_npc_inventory(sc_gameref_t game, sc_int npc, sc_bool is_described) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object, count, trail; + sc_bool wearing; + + /* Find and list each object worn by the NPC. */ + count = 0; + trail = -1; + wearing = FALSE; + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_WORN_NPC + && gs_object_parent(game, object) == npc) { + if (count > 0) { + if (count == 1) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " is wearing "); + } else + pf_buffer_string(filter, ", "); + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " is wearing "); + } else + pf_buffer_string(filter, " and "); + lib_print_object(game, trail); + wearing = TRUE; + } + + /* Find and list each object owned by the NPC. */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_HELD_NPC + && gs_object_parent(game, object) == npc) { + if (count > 0) { + if (count == 1) { + if (!wearing) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_npc_np(game, npc); + } else + pf_buffer_string(filter, ", and"); + pf_buffer_string(filter, " is carrying "); + } else + pf_buffer_string(filter, ", "); + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + if (!wearing) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_npc_np(game, npc); + } else + pf_buffer_string(filter, ", and"); + pf_buffer_string(filter, " is carrying "); + } else + pf_buffer_string(filter, " and "); + lib_print_object(game, trail); + pf_buffer_character(filter, '.'); + } else { + if (wearing) + pf_buffer_character(filter, '.'); + } + + /* Return TRUE if anything worn or carried. */ + return wearing || count > 0; } @@ -3116,59 +2832,54 @@ lib_list_npc_inventory (sc_gameref_t game, sc_int npc, sc_bool is_described) * list of what they're wearing and carrying. */ sc_bool -lib_cmd_examine_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int npc, task, resource; - sc_bool is_ambiguous; - const sc_char *description; - - /* Get the referenced npc, and if none, consider complete. */ - npc = lib_disambiguate_npc (game, "examine", &is_ambiguous); - if (npc == -1) - return is_ambiguous; - - /* Get selection task. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Task"; - task = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - - /* Select either the main or the alternate description. */ - if (task >= 0 && gs_task_done (game, task)) - { - vt_key[2].string = "AltText"; - resource = 1; - } - else - { - vt_key[2].string = "Descr"; - resource = 0; - } - - /* Print the description, or a default message if none. */ - description = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (description)) - pf_buffer_string (filter, description); - else - { - pf_buffer_string (filter, "There's nothing special about "); - lib_print_npc_np (game, npc); - pf_buffer_character (filter, '.'); - } - - /* Handle any associated resource. */ - vt_key[2].string = "Res"; - vt_key[3].integer = resource; - res_handle_resource (game, "sisi", vt_key); - - /* Print what the NPC is wearing and carrying. */ - lib_list_npc_inventory (game, npc, TRUE); - - pf_buffer_character (filter, '\n'); - return TRUE; +lib_cmd_examine_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int npc, task, resource; + sc_bool is_ambiguous; + const sc_char *description; + + /* Get the referenced npc, and if none, consider complete. */ + npc = lib_disambiguate_npc(game, "examine", &is_ambiguous); + if (npc == -1) + return is_ambiguous; + + /* Get selection task. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Task"; + task = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + + /* Select either the main or the alternate description. */ + if (task >= 0 && gs_task_done(game, task)) { + vt_key[2].string = "AltText"; + resource = 1; + } else { + vt_key[2].string = "Descr"; + resource = 0; + } + + /* Print the description, or a default message if none. */ + description = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(description)) + pf_buffer_string(filter, description); + else { + pf_buffer_string(filter, "There's nothing special about "); + lib_print_npc_np(game, npc); + pf_buffer_character(filter, '.'); + } + + /* Handle any associated resource. */ + vt_key[2].string = "Res"; + vt_key[3].integer = resource; + res_handle_resource(game, "sisi", vt_key); + + /* Print what the NPC is wearing and carrying. */ + lib_list_npc_inventory(game, npc, TRUE); + + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -3178,66 +2889,57 @@ lib_cmd_examine_npc (sc_gameref_t game) * List the objects in a given container object, normal format listing. */ static sc_bool -lib_list_in_object_normal (sc_gameref_t game, - sc_int container, sc_bool is_described) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object, count, trail; - - /* List out the containers contained in this container. */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - /* Contained? */ - if (gs_object_position (game, object) == OBJ_IN_OBJECT - && gs_object_parent (game, object) == container) - { - if (count > 0) - { - if (count == 1) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, "Inside "); - lib_print_object_np (game, container); - pf_buffer_string (filter, - lib_select_plurality (game, trail, - " is ", " are ")); - } - else - pf_buffer_string (filter, ", "); - - /* Print out the current list object. */ - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, "Inside "); - lib_print_object_np (game, container); - pf_buffer_string (filter, - lib_select_plurality (game, trail, - " is ", " are ")); - } - else - pf_buffer_string (filter, " and "); - - /* Print out the final object. */ - lib_print_object (game, trail); - pf_buffer_character (filter, '.'); - } - - /* Return TRUE if anything listed. */ - return count > 0; +lib_list_in_object_normal(sc_gameref_t game, + sc_int container, sc_bool is_described) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object, count, trail; + + /* List out the containers contained in this container. */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + /* Contained? */ + if (gs_object_position(game, object) == OBJ_IN_OBJECT + && gs_object_parent(game, object) == container) { + if (count > 0) { + if (count == 1) { + if (is_described) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, "Inside "); + lib_print_object_np(game, container); + pf_buffer_string(filter, + lib_select_plurality(game, trail, + " is ", " are ")); + } else + pf_buffer_string(filter, ", "); + + /* Print out the current list object. */ + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + if (is_described) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, "Inside "); + lib_print_object_np(game, container); + pf_buffer_string(filter, + lib_select_plurality(game, trail, + " is ", " are ")); + } else + pf_buffer_string(filter, " and "); + + /* Print out the final object. */ + lib_print_object(game, trail); + pf_buffer_character(filter, '.'); + } + + /* Return TRUE if anything listed. */ + return count > 0; } @@ -3247,67 +2949,57 @@ lib_list_in_object_normal (sc_gameref_t game, * List the objects in a given container object, alternate format listing. */ static sc_bool -lib_list_in_object_alternate (sc_gameref_t game, - sc_int container, sc_bool is_described) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object, count, trail; - - /* List out the objects contained in this object. */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - /* Contained? */ - if (gs_object_position (game, object) == OBJ_IN_OBJECT - && gs_object_parent (game, object) == container) - { - if (count > 0) - { - if (count == 1) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - } - else - pf_buffer_string (filter, ", "); - - /* Print out the current list object. */ - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object (game, trail); - pf_buffer_string (filter, - lib_select_plurality (game, trail, - " is inside ", - " are inside ")); - } - else - { - pf_buffer_string (filter, " and "); - lib_print_object (game, trail); - pf_buffer_string (filter, " are inside "); - } - - /* Print out the container. */ - lib_print_object_np (game, container); - pf_buffer_character (filter, '.'); - } - - /* Return TRUE if anything listed. */ - return count > 0; +lib_list_in_object_alternate(sc_gameref_t game, + sc_int container, sc_bool is_described) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object, count, trail; + + /* List out the objects contained in this object. */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + /* Contained? */ + if (gs_object_position(game, object) == OBJ_IN_OBJECT + && gs_object_parent(game, object) == container) { + if (count > 0) { + if (count == 1) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + } else + pf_buffer_string(filter, ", "); + + /* Print out the current list object. */ + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object(game, trail); + pf_buffer_string(filter, + lib_select_plurality(game, trail, + " is inside ", + " are inside ")); + } else { + pf_buffer_string(filter, " and "); + lib_print_object(game, trail); + pf_buffer_string(filter, " are inside "); + } + + /* Print out the container. */ + lib_print_object_np(game, container); + pf_buffer_character(filter, '.'); + } + + /* Return TRUE if anything listed. */ + return count > 0; } @@ -3323,45 +3015,40 @@ lib_list_in_object_alternate (sc_gameref_t game, * but it's almost certainly wrong. Or, at minimum, incomplete. */ static sc_bool -lib_list_in_object (sc_gameref_t game, sc_int container, sc_bool is_described) -{ - sc_bool use_alternate_format = FALSE; +lib_list_in_object(sc_gameref_t game, sc_int container, sc_bool is_described) { + sc_bool use_alternate_format = FALSE; - /* - * Switch if the object is static and part of an NPC or the player, or if - * the count of contained objects in a dynamic container is exactly one. - */ - if (obj_is_static (game, container)) - { - sc_int object_position; + /* + * Switch if the object is static and part of an NPC or the player, or if + * the count of contained objects in a dynamic container is exactly one. + */ + if (obj_is_static(game, container)) { + sc_int object_position; - object_position = gs_object_position (game, container); + object_position = gs_object_position(game, container); - if (object_position == OBJ_PART_NPC || object_position == OBJ_PART_PLAYER) - use_alternate_format = TRUE; - } - else - { - sc_int object, count; + if (object_position == OBJ_PART_NPC || object_position == OBJ_PART_PLAYER) + use_alternate_format = TRUE; + } else { + sc_int object, count; - count = 0; - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_IN_OBJECT - && gs_object_parent (game, object) == container) - count++; - if (count > 1) - break; - } + count = 0; + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_IN_OBJECT + && gs_object_parent(game, object) == container) + count++; + if (count > 1) + break; + } - if (count == 1) - use_alternate_format = TRUE; - } + if (count == 1) + use_alternate_format = TRUE; + } - /* List contained objects using the selected handler. */ - return use_alternate_format - ? lib_list_in_object_alternate (game, container, is_described) - : lib_list_in_object_normal (game, container, is_described); + /* List contained objects using the selected handler. */ + return use_alternate_format + ? lib_list_in_object_alternate(game, container, is_described) + : lib_list_in_object_normal(game, container, is_described); } @@ -3371,66 +3058,56 @@ lib_list_in_object (sc_gameref_t game, sc_int container, sc_bool is_described) * List the objects on a given surface object. */ static sc_bool -lib_list_on_object (sc_gameref_t game, sc_int supporter, sc_bool is_described) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object, count, trail; - - /* List out the objects standing on this object. */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - /* Standing on? */ - if (gs_object_position (game, object) == OBJ_ON_OBJECT - && gs_object_parent (game, object) == supporter) - { - if (count > 0) - { - if (count == 1) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - } - else - pf_buffer_string (filter, ", "); - - /* Print out the current list object. */ - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object (game, trail); - pf_buffer_string (filter, - lib_select_plurality (game, trail, - " is on ", - " are on ")); - } - else - { - pf_buffer_string (filter, " and "); - lib_print_object (game, trail); - pf_buffer_string (filter, " are on "); - } - - /* Print out the surface. */ - lib_print_object_np (game, supporter); - pf_buffer_character (filter, '.'); - } - - /* Return TRUE if anything listed. */ - return count > 0; +lib_list_on_object(sc_gameref_t game, sc_int supporter, sc_bool is_described) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object, count, trail; + + /* List out the objects standing on this object. */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + /* Standing on? */ + if (gs_object_position(game, object) == OBJ_ON_OBJECT + && gs_object_parent(game, object) == supporter) { + if (count > 0) { + if (count == 1) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + } else + pf_buffer_string(filter, ", "); + + /* Print out the current list object. */ + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object(game, trail); + pf_buffer_string(filter, + lib_select_plurality(game, trail, + " is on ", + " are on ")); + } else { + pf_buffer_string(filter, " and "); + lib_print_object(game, trail); + pf_buffer_string(filter, " are on "); + } + + /* Print out the surface. */ + lib_print_object_np(game, supporter); + pf_buffer_character(filter, '.'); + } + + /* Return TRUE if anything listed. */ + return count > 0; } @@ -3440,47 +3117,42 @@ lib_list_on_object (sc_gameref_t game, sc_int supporter, sc_bool is_described) * Describe the state of a stateful object. */ static sc_bool -lib_list_object_state (sc_gameref_t game, sc_int object, sc_bool is_described) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_bool is_statussed; - sc_char *state; - - /* Get object statefulness. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "CurrentState"; - is_statussed = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - - /* Ensure this is a stateful object. */ - if (is_statussed) - { - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, " is ", " are ")); - - /* Add object state string. */ - state = obj_state_name (game, object); - if (state) - { - pf_buffer_string (filter, state); - sc_free (state); - pf_buffer_string (filter, "."); - } - else - { - sc_error ("lib_list_object_state: invalid object state\n"); - pf_buffer_string (filter, "[invalid state]."); - } - } - - /* Return TRUE if a state was printed. */ - return is_statussed; +lib_list_object_state(sc_gameref_t game, sc_int object, sc_bool is_described) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_bool is_statussed; + sc_char *state; + + /* Get object statefulness. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "CurrentState"; + is_statussed = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + + /* Ensure this is a stateful object. */ + if (is_statussed) { + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, " is ", " are ")); + + /* Add object state string. */ + state = obj_state_name(game, object); + if (state) { + pf_buffer_string(filter, state); + sc_free(state); + pf_buffer_string(filter, "."); + } else { + sc_error("lib_list_object_state: invalid object state\n"); + pf_buffer_string(filter, "[invalid state]."); + } + } + + /* Return TRUE if a state was printed. */ + return is_statussed; } @@ -3490,133 +3162,125 @@ lib_list_object_state (sc_gameref_t game, sc_int object, sc_bool is_described) * Show the long description of the most recently referenced object. */ sc_bool -lib_cmd_examine_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int object, task, openness; - sc_bool is_described, is_statussed, is_mentioned, is_ambiguous, should_be; - const sc_char *description, *resource; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "examine", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Begin assuming no description printed. */ - is_described = FALSE; - - /* - * Get selection task and expected state; for the expected task state, FALSE - * indicates task completed, TRUE not completed. - */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Task"; - task = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - vt_key[2].string = "TaskNotDone"; - should_be = !prop_get_boolean (bundle, "B<-sis", vt_key); - - /* Select either the main or the alternate description. */ - if (task >= 0 && gs_task_done (game, task) == should_be) - { - vt_key[2].string = "AltDesc"; - resource = "Res2"; - } - else - { - vt_key[2].string = "Description"; - resource = "Res1"; - } - - /* Print the description, or a default response. */ - description = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (description)) - { - pf_buffer_string (filter, description); - is_described |= TRUE; - } - - /* Handle any associated resource. */ - vt_key[2].string = resource; - res_handle_resource (game, "sis", vt_key); - - /* If the object is openable, print its openness state. */ - openness = gs_object_openness (game, object); - switch (openness) - { - case OBJ_OPEN: - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is open.", " are open.")); - is_described |= TRUE; - break; - - case OBJ_CLOSED: - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is closed.", " are closed.")); - is_described |= TRUE; - break; - - case OBJ_LOCKED: - if (is_described) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is locked.", " are locked.")); - is_described |= TRUE; - break; - - default: - break; - } - - /* Add any extra details for stateful objects. */ - vt_key[1].integer = object; - vt_key[2].string = "CurrentState"; - is_statussed = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - if (is_statussed) - { - vt_key[2].string = "StateListed"; - is_mentioned = prop_get_boolean (bundle, "B<-sis", vt_key); - if (is_mentioned) - is_described |= lib_list_object_state (game, object, is_described); - } - - /* For open container objects, list out what's in them. */ - if (obj_is_container (game, object) && openness <= OBJ_OPEN) - is_described |= lib_list_in_object (game, object, is_described); - - /* For surface objects, list out what's on them. */ - if (obj_is_surface (game, object)) - is_described |= lib_list_on_object (game, object, is_described); - - /* If nothing yet said, print a default response. */ - if (!is_described) - { - pf_buffer_string (filter, - lib_select_response (game, - "You see nothing special about ", - "I see nothing special about ", - "%player% sees nothing special about ")); - lib_print_object_np (game, object); - pf_buffer_character (filter, '.'); - } - - pf_buffer_character (filter, '\n'); - return TRUE; +lib_cmd_examine_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int object, task, openness; + sc_bool is_described, is_statussed, is_mentioned, is_ambiguous, should_be; + const sc_char *description, *resource; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "examine", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Begin assuming no description printed. */ + is_described = FALSE; + + /* + * Get selection task and expected state; for the expected task state, FALSE + * indicates task completed, TRUE not completed. + */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Task"; + task = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + vt_key[2].string = "TaskNotDone"; + should_be = !prop_get_boolean(bundle, "B<-sis", vt_key); + + /* Select either the main or the alternate description. */ + if (task >= 0 && gs_task_done(game, task) == should_be) { + vt_key[2].string = "AltDesc"; + resource = "Res2"; + } else { + vt_key[2].string = "Description"; + resource = "Res1"; + } + + /* Print the description, or a default response. */ + description = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(description)) { + pf_buffer_string(filter, description); + is_described |= TRUE; + } + + /* Handle any associated resource. */ + vt_key[2].string = resource; + res_handle_resource(game, "sis", vt_key); + + /* If the object is openable, print its openness state. */ + openness = gs_object_openness(game, object); + switch (openness) { + case OBJ_OPEN: + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is open.", " are open.")); + is_described |= TRUE; + break; + + case OBJ_CLOSED: + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is closed.", " are closed.")); + is_described |= TRUE; + break; + + case OBJ_LOCKED: + if (is_described) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is locked.", " are locked.")); + is_described |= TRUE; + break; + + default: + break; + } + + /* Add any extra details for stateful objects. */ + vt_key[1].integer = object; + vt_key[2].string = "CurrentState"; + is_statussed = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + if (is_statussed) { + vt_key[2].string = "StateListed"; + is_mentioned = prop_get_boolean(bundle, "B<-sis", vt_key); + if (is_mentioned) + is_described |= lib_list_object_state(game, object, is_described); + } + + /* For open container objects, list out what's in them. */ + if (obj_is_container(game, object) && openness <= OBJ_OPEN) + is_described |= lib_list_in_object(game, object, is_described); + + /* For surface objects, list out what's on them. */ + if (obj_is_surface(game, object)) + is_described |= lib_list_on_object(game, object, is_described); + + /* If nothing yet said, print a default response. */ + if (!is_described) { + pf_buffer_string(filter, + lib_select_response(game, + "You see nothing special about ", + "I see nothing special about ", + "%player% sees nothing special about ")); + lib_print_object_np(game, object); + pf_buffer_character(filter, '.'); + } + + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -3631,32 +3295,30 @@ lib_cmd_examine_object (sc_gameref_t game) * its own buffer; testing the return value shows which happened. */ static sc_bool * -lib_save_object_references (sc_gameref_t game, sc_bool buffer[], sc_int length) -{ - sc_int required, available; - sc_bool *references; +lib_save_object_references(sc_gameref_t game, sc_bool buffer[], sc_int length) { + sc_int required, available; + sc_bool *references; - /* - * Calculate the required bytes for references, and then either allocate or - * use the buffer supplied. - */ - required = gs_object_count (game) * sizeof (*references); - available = length * sizeof (buffer[0]); - references = required > available ? (sc_bool *)sc_malloc (required) : buffer; + /* + * Calculate the required bytes for references, and then either allocate or + * use the buffer supplied. + */ + required = gs_object_count(game) * sizeof(*references); + available = length * sizeof(buffer[0]); + references = required > available ? (sc_bool *)sc_malloc(required) : buffer; - /* Copy over references from the game, and return the saved copy. */ - memcpy (references, game->object_references, required); - return references; + /* Copy over references from the game, and return the saved copy. */ + memcpy(references, game->object_references, required); + return references; } static void -lib_restore_object_references (sc_gameref_t game, const sc_bool references[]) -{ - sc_int bytes; +lib_restore_object_references(sc_gameref_t game, const sc_bool references[]) { + sc_int bytes; - /* Calculate the bytes in the references array, and copy back to the game. */ - bytes = gs_object_count (game) * sizeof (references[0]); - memcpy (game->object_references, references, bytes); + /* Calculate the bytes in the references array, and copy back to the game. */ + bytes = gs_object_count(game) * sizeof(references[0]); + memcpy(game->object_references, references, bytes); } @@ -3671,148 +3333,134 @@ lib_restore_object_references (sc_gameref_t game, const sc_bool references[]) * makes "take/pick up/put down" work with a game's overridden get/drop. */ static sc_bool -lib_try_game_command_common (sc_gameref_t game, - const sc_char *verb, sc_int object, - const sc_char *preposition, - sc_int associate, - sc_bool is_associate_object, - sc_bool is_associate_npc) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_char buffer[LIB_ALLOCATION_AVOIDANCE_SIZE]; - sc_bool references_buffer[LIB_ALLOCATION_AVOIDANCE_SIZE]; - const sc_char *prefix, *name; - sc_char *command; - sc_bool *references, status; - assert (!is_associate_object || !is_associate_npc); - - /* Save the game's references, for restore later on. */ - references = lib_save_object_references (game, references_buffer, - LIB_ALLOCATION_AVOIDANCE_SIZE); - - /* Get the addressed object's prefix and main name. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - /* Construct and try for game commands with a standard verb. */ - if (is_associate_object || is_associate_npc) - { - const sc_char *associate_prefix, *associate_name; - sc_int required; - - /* Get the associate's prefix and main name. */ - if (is_associate_object) - { - vt_key[0].string = "Objects"; - vt_key[1].integer = associate; - vt_key[2].string = "Prefix"; - associate_prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Short"; - associate_name = prop_get_string (bundle, "S<-sis", vt_key); - } - else - { - assert (is_associate_npc); - vt_key[0].string = "NPCs"; - vt_key[1].integer = associate; - vt_key[2].string = "Prefix"; - associate_prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Name"; - associate_name = prop_get_string (bundle, "S<-sis", vt_key); - } - - assert (preposition); - required = strlen (verb) + strlen (prefix) + strlen (name) - + strlen (preposition) + strlen (associate_prefix) - + strlen (associate_name) + 6; - command = required > (sc_int) sizeof (buffer) - ? (sc_char *)sc_malloc (required) : buffer; - - /* - * Try the command with and without prefixes on both the target object - * and the associate. - */ - sprintf (command, "%s %s %s %s %s %s", verb, - prefix, name, preposition, associate_prefix, associate_name); - status = run_game_task_commands (game, command); - if (!status) - { - sprintf (command, "%s %s %s %s %s", - verb, prefix, name, preposition, associate_name); - status = run_game_task_commands (game, command); - } - if (!status) - { - sprintf (command, "%s %s %s %s %s", - verb, name, preposition, associate_prefix, associate_name); - status = run_game_task_commands (game, command); - } - if (!status) - { - sprintf (command, "%s %s %s %s", - verb, name, preposition, associate_name); - status = run_game_task_commands (game, command); - } - } - else - { - sc_int required; - - required = strlen (verb) + strlen (prefix) + strlen (name) + 3; - command = required > (sc_int) sizeof (buffer) - ? (sc_char *)sc_malloc (required) : buffer; - - /* Try the command with and without prefixes on the addressed object. */ - sprintf (command, "%s %s %s", verb, prefix, name); - status = run_game_task_commands (game, command); - if (!status) - { - sprintf (command, "%s %s", verb, name); - status = run_game_task_commands (game, command); - } - } - - /* Restore the game object references back to their state on entry. */ - lib_restore_object_references (game, references); - - /* Free any allocations, and return the game command status. */ - if (command != buffer) - sc_free (command); - if (references != references_buffer) - sc_free (references); - return status; +lib_try_game_command_common(sc_gameref_t game, + const sc_char *verb, sc_int object, + const sc_char *preposition, + sc_int associate, + sc_bool is_associate_object, + sc_bool is_associate_npc) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_char buffer[LIB_ALLOCATION_AVOIDANCE_SIZE]; + sc_bool references_buffer[LIB_ALLOCATION_AVOIDANCE_SIZE]; + const sc_char *prefix, *name; + sc_char *command; + sc_bool *references, status; + assert(!is_associate_object || !is_associate_npc); + + /* Save the game's references, for restore later on. */ + references = lib_save_object_references(game, references_buffer, + LIB_ALLOCATION_AVOIDANCE_SIZE); + + /* Get the addressed object's prefix and main name. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + /* Construct and try for game commands with a standard verb. */ + if (is_associate_object || is_associate_npc) { + const sc_char *associate_prefix, *associate_name; + sc_int required; + + /* Get the associate's prefix and main name. */ + if (is_associate_object) { + vt_key[0].string = "Objects"; + vt_key[1].integer = associate; + vt_key[2].string = "Prefix"; + associate_prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Short"; + associate_name = prop_get_string(bundle, "S<-sis", vt_key); + } else { + assert(is_associate_npc); + vt_key[0].string = "NPCs"; + vt_key[1].integer = associate; + vt_key[2].string = "Prefix"; + associate_prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Name"; + associate_name = prop_get_string(bundle, "S<-sis", vt_key); + } + + assert(preposition); + required = strlen(verb) + strlen(prefix) + strlen(name) + + strlen(preposition) + strlen(associate_prefix) + + strlen(associate_name) + 6; + command = required > (sc_int) sizeof(buffer) + ? (sc_char *)sc_malloc(required) : buffer; + + /* + * Try the command with and without prefixes on both the target object + * and the associate. + */ + sprintf(command, "%s %s %s %s %s %s", verb, + prefix, name, preposition, associate_prefix, associate_name); + status = run_game_task_commands(game, command); + if (!status) { + sprintf(command, "%s %s %s %s %s", + verb, prefix, name, preposition, associate_name); + status = run_game_task_commands(game, command); + } + if (!status) { + sprintf(command, "%s %s %s %s %s", + verb, name, preposition, associate_prefix, associate_name); + status = run_game_task_commands(game, command); + } + if (!status) { + sprintf(command, "%s %s %s %s", + verb, name, preposition, associate_name); + status = run_game_task_commands(game, command); + } + } else { + sc_int required; + + required = strlen(verb) + strlen(prefix) + strlen(name) + 3; + command = required > (sc_int) sizeof(buffer) + ? (sc_char *)sc_malloc(required) : buffer; + + /* Try the command with and without prefixes on the addressed object. */ + sprintf(command, "%s %s %s", verb, prefix, name); + status = run_game_task_commands(game, command); + if (!status) { + sprintf(command, "%s %s", verb, name); + status = run_game_task_commands(game, command); + } + } + + /* Restore the game object references back to their state on entry. */ + lib_restore_object_references(game, references); + + /* Free any allocations, and return the game command status. */ + if (command != buffer) + sc_free(command); + if (references != references_buffer) + sc_free(references); + return status; } static sc_bool -lib_try_game_command_short (sc_gameref_t game, - const sc_char *verb, sc_int object) -{ - return lib_try_game_command_common (game, verb, object, - NULL, -1, FALSE, FALSE); +lib_try_game_command_short(sc_gameref_t game, + const sc_char *verb, sc_int object) { + return lib_try_game_command_common(game, verb, object, + NULL, -1, FALSE, FALSE); } static sc_bool -lib_try_game_command_with_object (sc_gameref_t game, - const sc_char *verb, sc_int object, - const sc_char *preposition, - sc_int other_object) -{ - return lib_try_game_command_common (game, verb, object, - preposition, other_object, TRUE, FALSE); +lib_try_game_command_with_object(sc_gameref_t game, + const sc_char *verb, sc_int object, + const sc_char *preposition, + sc_int other_object) { + return lib_try_game_command_common(game, verb, object, + preposition, other_object, TRUE, FALSE); } static sc_bool -lib_try_game_command_with_npc (sc_gameref_t game, - const sc_char *verb, sc_int object, - const sc_char *preposition, sc_int npc) -{ - return lib_try_game_command_common (game, verb, object, - preposition, npc, FALSE, TRUE); +lib_try_game_command_with_npc(sc_gameref_t game, + const sc_char *verb, sc_int object, + const sc_char *preposition, sc_int npc) { + return lib_try_game_command_common(game, verb, object, + preposition, npc, FALSE, TRUE); } @@ -3825,41 +3473,36 @@ lib_try_game_command_with_npc (sc_gameref_t game, * but there appear to be more following it. */ static sc_bool -lib_parse_next_object (sc_gameref_t game, const sc_char *verb, - sc_bool (*resolver) (sc_gameref_t, sc_int, sc_int), - sc_int resolver_arg, - sc_int *object, - sc_bool *are_more_objects, sc_bool *is_ambiguous) -{ - const sc_var_setref_t vars = gs_get_vars (game); - const sc_char *list; - sc_bool is_matched; - - /* Look for "object" or "object and ...", and set match and more flags. */ - list = var_get_ref_text (vars); - if (uip_match ("%object%", list, game)) - { - *are_more_objects = FALSE; - is_matched = TRUE; - } - else if (uip_match ("%object% and %text%", list, game)) - { - *are_more_objects = TRUE; - is_matched = TRUE; - } - else - is_matched = FALSE; - - /* If we extracted an object from referenced text, disambiguate. */ - if (is_matched) - *object = lib_disambiguate_object_extended (game, verb, - resolver, resolver_arg, - is_ambiguous); - else - *is_ambiguous = FALSE; - - /* Return TRUE if we matched anything. */ - return is_matched; +lib_parse_next_object(sc_gameref_t game, const sc_char *verb, + sc_bool(*resolver)(sc_gameref_t, sc_int, sc_int), + sc_int resolver_arg, + sc_int *object, + sc_bool *are_more_objects, sc_bool *is_ambiguous) { + const sc_var_setref_t vars = gs_get_vars(game); + const sc_char *list; + sc_bool is_matched; + + /* Look for "object" or "object and ...", and set match and more flags. */ + list = var_get_ref_text(vars); + if (uip_match("%object%", list, game)) { + *are_more_objects = FALSE; + is_matched = TRUE; + } else if (uip_match("%object% and %text%", list, game)) { + *are_more_objects = TRUE; + is_matched = TRUE; + } else + is_matched = FALSE; + + /* If we extracted an object from referenced text, disambiguate. */ + if (is_matched) + *object = lib_disambiguate_object_extended(game, verb, + resolver, resolver_arg, + is_ambiguous); + else + *is_ambiguous = FALSE; + + /* Return TRUE if we matched anything. */ + return is_matched; } @@ -3871,101 +3514,93 @@ lib_parse_next_object (sc_gameref_t game, const sc_char *verb, * the multiple objects in the game's multiple_references. */ static sc_bool -lib_parse_multiple_objects (sc_gameref_t game, const sc_char *verb, - sc_bool (*resolver) (sc_gameref_t, sc_int, sc_int), - sc_int resolver_arg, - sc_int *count) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int count_, object; - sc_bool are_more_objects, is_ambiguous; - - /* Initialize variables to avoid gcc warnings. */ - object = -1; - are_more_objects = FALSE; - - /* Clear all current multiple object references, and the count. */ - gs_clear_multiple_references (game); - count_ = 0; - - /* - * Parse the first object from the list. If we get nothing here, return - * FALSE if it didn't look like a multiple object list, TRUE if ambiguous. - * Beyond here, we always return TRUE, since after this point _something_ - * looked believable... - */ - if (!lib_parse_next_object (game, verb, - resolver, resolver_arg, - &object, &are_more_objects, &is_ambiguous)) - return FALSE; - else if (object == -1) - { - if (is_ambiguous) - { - /* - * Return TRUE, with zero count, to cause caller to return. We get - * here if the first parsed object was ambiguous. In this case, - * the disambiguation has printed a message, so we want our caller - * to simply return TRUE to indicate that the command was handled, - * albeit not fully successfully. - */ - *count = count_; - return TRUE; - } - else - { - /* - * No object matched after disambiguation, so return FALSE to have - * our caller ignore the command. - */ - return FALSE; - } - } - - /* Mark this first object as referenced in the return array. */ - game->multiple_references[object] = TRUE; - count_++; - - /* Now parse each additional object from the list. */ - while (are_more_objects) - { - sc_int last_object; - - /* - * If no next object, leave the loop. If no disambiguation message - * then it was probably garble, so print a message for that case. We - * also catch repeated objects here. - */ - last_object = object; - if (!lib_parse_next_object (game, verb, - resolver, resolver_arg, - &object, &are_more_objects, &is_ambiguous) - || object == -1 - || game->multiple_references[object]) - { - if (!is_ambiguous) - { - pf_buffer_string (filter, - "I only understood you as far as wanting to "); - pf_buffer_string (filter, verb); - pf_buffer_character (filter, ' '); - lib_print_object_np (game, last_object); - pf_buffer_string (filter, ".\n"); - } - - /* Zero count to indicate an error somewhere in the list. */ - count_ = 0; - break; - } - - /* Mark the object as referenced in the return array. */ - game->multiple_references[object] = TRUE; - count_++; - } - - /* We found at least enough of an object list to say we matched. */ - *count = count_; - return TRUE; +lib_parse_multiple_objects(sc_gameref_t game, const sc_char *verb, + sc_bool(*resolver)(sc_gameref_t, sc_int, sc_int), + sc_int resolver_arg, + sc_int *count) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int count_, object; + sc_bool are_more_objects, is_ambiguous; + + /* Initialize variables to avoid gcc warnings. */ + object = -1; + are_more_objects = FALSE; + + /* Clear all current multiple object references, and the count. */ + gs_clear_multiple_references(game); + count_ = 0; + + /* + * Parse the first object from the list. If we get nothing here, return + * FALSE if it didn't look like a multiple object list, TRUE if ambiguous. + * Beyond here, we always return TRUE, since after this point _something_ + * looked believable... + */ + if (!lib_parse_next_object(game, verb, + resolver, resolver_arg, + &object, &are_more_objects, &is_ambiguous)) + return FALSE; + else if (object == -1) { + if (is_ambiguous) { + /* + * Return TRUE, with zero count, to cause caller to return. We get + * here if the first parsed object was ambiguous. In this case, + * the disambiguation has printed a message, so we want our caller + * to simply return TRUE to indicate that the command was handled, + * albeit not fully successfully. + */ + *count = count_; + return TRUE; + } else { + /* + * No object matched after disambiguation, so return FALSE to have + * our caller ignore the command. + */ + return FALSE; + } + } + + /* Mark this first object as referenced in the return array. */ + game->multiple_references[object] = TRUE; + count_++; + + /* Now parse each additional object from the list. */ + while (are_more_objects) { + sc_int last_object; + + /* + * If no next object, leave the loop. If no disambiguation message + * then it was probably garble, so print a message for that case. We + * also catch repeated objects here. + */ + last_object = object; + if (!lib_parse_next_object(game, verb, + resolver, resolver_arg, + &object, &are_more_objects, &is_ambiguous) + || object == -1 + || game->multiple_references[object]) { + if (!is_ambiguous) { + pf_buffer_string(filter, + "I only understood you as far as wanting to "); + pf_buffer_string(filter, verb); + pf_buffer_character(filter, ' '); + lib_print_object_np(game, last_object); + pf_buffer_string(filter, ".\n"); + } + + /* Zero count to indicate an error somewhere in the list. */ + count_ = 0; + break; + } + + /* Mark the object as referenced in the return array. */ + game->multiple_references[object] = TRUE; + count_++; + } + + /* We found at least enough of an object list to say we matched. */ + *count = count_; + return TRUE; } @@ -3978,80 +3613,70 @@ lib_parse_multiple_objects (sc_gameref_t game, const sc_char *verb, * The first is inclusive, the second exclusive. */ static sc_int -lib_apply_multiple_filter (sc_gameref_t game, - sc_bool (*filter) (sc_gameref_t, sc_int, sc_int), - sc_int filter_arg, sc_int *references) -{ - sc_int count, object, references_; - - /* Clear all object references initially. */ - gs_clear_object_references (game); - - /* - * Find objects included by the filter, and transfer the reference of each - * from the multiple references into standard references. - */ - count = 0; - references_ = references ? *references : 0; - for (object = 0; object < gs_object_count (game); object++) - { - if (filter (game, object, filter_arg)) - { - /* Transfer the reference. */ - if (game->multiple_references[object]) - { - game->object_references[object] = TRUE; - count++; - game->multiple_references[object] = FALSE; - references_--; - } - } - } - - /* Copy back the updated reference count, return count. */ - if (references) - *references = references_; - return count; +lib_apply_multiple_filter(sc_gameref_t game, + sc_bool(*filter)(sc_gameref_t, sc_int, sc_int), + sc_int filter_arg, sc_int *references) { + sc_int count, object, references_; + + /* Clear all object references initially. */ + gs_clear_object_references(game); + + /* + * Find objects included by the filter, and transfer the reference of each + * from the multiple references into standard references. + */ + count = 0; + references_ = references ? *references : 0; + for (object = 0; object < gs_object_count(game); object++) { + if (filter(game, object, filter_arg)) { + /* Transfer the reference. */ + if (game->multiple_references[object]) { + game->object_references[object] = TRUE; + count++; + game->multiple_references[object] = FALSE; + references_--; + } + } + } + + /* Copy back the updated reference count, return count. */ + if (references) + *references = references_; + return count; } static sc_int -lib_apply_except_filter (sc_gameref_t game, - sc_bool (*filter) (sc_gameref_t, sc_int, sc_int), - sc_int filter_arg, sc_int *references) -{ - sc_int count, object, references_; - - /* Clear all object references initially. */ - gs_clear_object_references (game); - - /* - * Find objects included by the filter, and transfer the reference of each - * from the multiple references into standard references. - */ - count = 0; - references_ = references ? *references : 0; - for (object = 0; object < gs_object_count (game); object++) - { - if (filter (game, object, filter_arg)) - { - /* If excepted, remove from exceptions, else add to references. */ - if (game->multiple_references[object]) - { - game->multiple_references[object] = FALSE; - references_--; - } - else - { - game->object_references[object] = TRUE; - count++; - } - } - } - - /* Copy back the updated reference count, return count. */ - if (references) - *references = references_; - return count; +lib_apply_except_filter(sc_gameref_t game, + sc_bool(*filter)(sc_gameref_t, sc_int, sc_int), + sc_int filter_arg, sc_int *references) { + sc_int count, object, references_; + + /* Clear all object references initially. */ + gs_clear_object_references(game); + + /* + * Find objects included by the filter, and transfer the reference of each + * from the multiple references into standard references. + */ + count = 0; + references_ = references ? *references : 0; + for (object = 0; object < gs_object_count(game); object++) { + if (filter(game, object, filter_arg)) { + /* If excepted, remove from exceptions, else add to references. */ + if (game->multiple_references[object]) { + game->multiple_references[object] = FALSE; + references_--; + } else { + game->object_references[object] = TRUE; + count++; + } + } + } + + /* Copy back the updated reference count, return count. */ + if (references) + *references = references_; + return count; } @@ -4061,49 +3686,46 @@ lib_apply_except_filter (sc_gameref_t game, * Display player weight and size limits and amounts currently carried. */ sc_bool -lib_cmd_count (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int index_, size, weight; - sc_char buffer[32]; - - /* Sum sizes for objects currently held or worn by player. */ - size = 0; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (gs_object_position (game, index_) == OBJ_HELD_PLAYER - || gs_object_position (game, index_) == OBJ_WORN_PLAYER) - size += obj_get_size (game, index_); - } - - /* Sum weights for objects currently held or worn by player. */ - weight = 0; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (gs_object_position (game, index_) == OBJ_HELD_PLAYER - || gs_object_position (game, index_) == OBJ_WORN_PLAYER) - weight += obj_get_weight (game, index_); - } - - /* Print the player limits and amounts used. */ - pf_buffer_string (filter, "Size: You have "); - sprintf (buffer, "%ld", size); - pf_buffer_string (filter, buffer); - pf_buffer_string (filter, ". The most you can hold is "); - sprintf (buffer, "%ld", obj_get_player_size_limit (game)); - pf_buffer_string (filter, buffer); - pf_buffer_string (filter, ".\n"); - - pf_buffer_string (filter, "Weight: You have "); - sprintf (buffer, "%ld", weight); - pf_buffer_string (filter, buffer); - pf_buffer_string (filter, ". The most you can hold is "); - sprintf (buffer, "%ld", obj_get_player_weight_limit (game)); - pf_buffer_string (filter, buffer); - pf_buffer_string (filter, ".\n"); - - game->is_admin = TRUE; - return TRUE; +lib_cmd_count(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int index_, size, weight; + sc_char buffer[32]; + + /* Sum sizes for objects currently held or worn by player. */ + size = 0; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (gs_object_position(game, index_) == OBJ_HELD_PLAYER + || gs_object_position(game, index_) == OBJ_WORN_PLAYER) + size += obj_get_size(game, index_); + } + + /* Sum weights for objects currently held or worn by player. */ + weight = 0; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (gs_object_position(game, index_) == OBJ_HELD_PLAYER + || gs_object_position(game, index_) == OBJ_WORN_PLAYER) + weight += obj_get_weight(game, index_); + } + + /* Print the player limits and amounts used. */ + pf_buffer_string(filter, "Size: You have "); + sprintf(buffer, "%ld", size); + pf_buffer_string(filter, buffer); + pf_buffer_string(filter, ". The most you can hold is "); + sprintf(buffer, "%ld", obj_get_player_size_limit(game)); + pf_buffer_string(filter, buffer); + pf_buffer_string(filter, ".\n"); + + pf_buffer_string(filter, "Weight: You have "); + sprintf(buffer, "%ld", weight); + pf_buffer_string(filter, buffer); + pf_buffer_string(filter, ". The most you can hold is "); + sprintf(buffer, "%ld", obj_get_player_weight_limit(game)); + pf_buffer_string(filter, buffer); + pf_buffer_string(filter, ".\n"); + + game->is_admin = TRUE; + return TRUE; } @@ -4113,29 +3735,27 @@ lib_cmd_count (sc_gameref_t game) * Return TRUE if the given object is too heavy for the player to carry. */ static sc_bool -lib_object_too_heavy (sc_gameref_t game, sc_int object, sc_bool *is_portable) -{ - sc_int player_limit, index_, weight, object_weight; +lib_object_too_heavy(sc_gameref_t game, sc_int object, sc_bool *is_portable) { + sc_int player_limit, index_, weight, object_weight; - /* Get the player limit and the given object weight. */ - player_limit = obj_get_player_weight_limit (game); - object_weight = obj_get_weight (game, object); + /* Get the player limit and the given object weight. */ + player_limit = obj_get_player_weight_limit(game); + object_weight = obj_get_weight(game, object); - /* Sum weights for objects currently held or worn by player. */ - weight = 0; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (gs_object_position (game, index_) == OBJ_HELD_PLAYER - || gs_object_position (game, index_) == OBJ_WORN_PLAYER) - weight += obj_get_weight (game, index_); - } + /* Sum weights for objects currently held or worn by player. */ + weight = 0; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (gs_object_position(game, index_) == OBJ_HELD_PLAYER + || gs_object_position(game, index_) == OBJ_WORN_PLAYER) + weight += obj_get_weight(game, index_); + } - /* If requested, return object portability. */ - if (is_portable) - *is_portable = !(object_weight > player_limit); + /* If requested, return object portability. */ + if (is_portable) + *is_portable = !(object_weight > player_limit); - /* Return TRUE if the new object exceeds limit. */ - return weight + object_weight > player_limit; + /* Return TRUE if the new object exceeds limit. */ + return weight + object_weight > player_limit; } @@ -4145,29 +3765,27 @@ lib_object_too_heavy (sc_gameref_t game, sc_int object, sc_bool *is_portable) * Return TRUE if the given object is too large for the player to carry. */ static sc_bool -lib_object_too_large (sc_gameref_t game, sc_int object, sc_bool *is_portable) -{ - sc_int player_limit, index_, size, object_size; +lib_object_too_large(sc_gameref_t game, sc_int object, sc_bool *is_portable) { + sc_int player_limit, index_, size, object_size; - /* Get the player limit and the given object size. */ - player_limit = obj_get_player_size_limit (game); - object_size = obj_get_size (game, object); + /* Get the player limit and the given object size. */ + player_limit = obj_get_player_size_limit(game); + object_size = obj_get_size(game, object); - /* Sum sizes for objects currently held or worn by player. */ - size = 0; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (gs_object_position (game, index_) == OBJ_HELD_PLAYER - || gs_object_position (game, index_) == OBJ_WORN_PLAYER) - size += obj_get_size (game, index_); - } + /* Sum sizes for objects currently held or worn by player. */ + size = 0; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (gs_object_position(game, index_) == OBJ_HELD_PLAYER + || gs_object_position(game, index_) == OBJ_WORN_PLAYER) + size += obj_get_size(game, index_); + } - /* If requested, return object portability. */ - if (is_portable) - *is_portable = !(object_size > player_limit); + /* If requested, return object portability. */ + if (is_portable) + *is_portable = !(object_size > player_limit); - /* Return TRUE if the new object exceeds limit. */ - return size + object_size > player_limit; + /* Return TRUE if the new object exceeds limit. */ + return size + object_size > player_limit; } @@ -4177,22 +3795,21 @@ lib_object_too_large (sc_gameref_t game, sc_int object, sc_bool *is_portable) * Reject attempts to take an npc. */ sc_bool -lib_cmd_take_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int npc; - sc_bool is_ambiguous; +lib_cmd_take_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int npc; + sc_bool is_ambiguous; - /* Get the referenced npc, and if none, consider complete. */ - npc = lib_disambiguate_npc (game, "take", &is_ambiguous); - if (npc == -1) - return is_ambiguous; + /* Get the referenced npc, and if none, consider complete. */ + npc = lib_disambiguate_npc(game, "take", &is_ambiguous); + if (npc == -1) + return is_ambiguous; - /* Reject this attempt. */ - pf_buffer_string (filter, "I don't think "); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " would appreciate being handled.\n"); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, "I don't think "); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " would appreciate being handled.\n"); + return TRUE; } @@ -4207,624 +3824,545 @@ lib_cmd_take_npc (sc_gameref_t game) * deemed not actionable are flagged in multiple_references. */ static void -lib_take_backend_common (sc_gameref_t game, sc_int associate, - sc_bool is_associate_object, sc_bool is_associate_npc) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object_count, object, count, trail, total, npc; - sc_int too_heavy, too_large; - sc_bool too_heavy_portable, too_large_portable, has_printed; - assert (!is_associate_object || !is_associate_npc); - - /* Initialize our notions of anything exceeding player capacity. */ - too_heavy_portable = too_large_portable = FALSE; - too_large = too_heavy = -1; - - /* - * Try game commands for all referenced objects first. If any succeed, - * remove that reference from the list. At the same time, filter out and - * flag any object that takes us over the player's capacity. We report - * only the first. - */ - has_printed = FALSE; - object_count = gs_object_count (game); - for (object = 0; object < object_count; object++) - { - sc_bool status; - - if (!game->object_references[object]) - continue; - - /* - * If the object is inside or on something already held by the player, - * capacity checks are meaningless. - */ - if (!((gs_object_position (game, object) == OBJ_IN_OBJECT - || gs_object_position (game, object) == OBJ_ON_OBJECT) - && obj_indirectly_held_by_player (game, - gs_object_parent (game, object)))) - { - sc_bool is_portable; - - /* - * See if the object takes us beyond capacity. If it does and it's - * the first of its kind, note it and continue. - */ - if (lib_object_too_heavy (game, object, &is_portable)) - { - if (too_heavy == -1) - { - too_heavy = object; - too_heavy_portable = is_portable; - } - game->object_references[object] = FALSE; - continue; - } - if (lib_object_too_large (game, object, &is_portable)) - { - if (too_large == -1) - { - too_large = object; - too_large_portable = is_portable; - } - game->object_references[object] = FALSE; - continue; - } - } - - /* Now try for a game command, using the associate if supplied. */ - if (is_associate_object) - status = lib_try_game_command_with_object (game, "get", - object, "from", associate); - else if (is_associate_npc) - status = lib_try_game_command_with_npc (game, "get", - object, "from", associate); - else - status = lib_try_game_command_short (game, "get", object); - if (status) - { - game->object_references[object] = FALSE; - has_printed = TRUE; - } - } - - /* - * We attempt acquisition of get-able objects here only for cases where - * there is either no associate, or where the associate is an object. If - * the associate is an NPC, we're going to refuse all acquisitions later - * on, by forcing object references. - */ - total = 0; - if (!is_associate_npc) - { - sc_int parent, start, limit; - - /* - * Attempt to acquire each remaining get-able object in turn, looping - * on each possible parent object in turn, with an initial parent of - * -1 for objects not contained or supported. - * - * If we're dealing with only objects from a known container or - * supporter, eliminate all but one iteration of the parent search. - */ - start = is_associate_object ? associate : -1; - limit = is_associate_object ? associate : object_count - 1; - - for (parent = start; parent <= limit; parent++) - { - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - sc_bool is_portable; - - if (!game->object_references[object]) - continue; - - /* - * If parent is -1, ignore contained objects, otherwise ignore - * objects not contained, or if contained, not contained by the - * current parent. - */ - if (parent == -1) - { - if (gs_object_position (game, object) == OBJ_IN_OBJECT - || gs_object_position (game, object) == OBJ_ON_OBJECT) - continue; - } - else - { - if (!(gs_object_position (game, object) == OBJ_IN_OBJECT - || gs_object_position (game, object) == OBJ_ON_OBJECT)) - continue; - if (gs_object_parent (game, object) != parent) - continue; - } - - /* - * Here we have to repeat capacity checks. As objects are - * acquired more and more of the player's capacity gets used up. - * This means a check directly before each acquisition. - */ - if (parent == -1 - || !obj_indirectly_held_by_player (game, parent)) - { - if (lib_object_too_heavy (game, object, &is_portable)) - { - if (too_heavy == -1) - { - too_heavy = object; - too_heavy_portable = is_portable; - } - continue; - } - if (lib_object_too_large (game, object, &is_portable)) - { - if (too_large == -1) - { - too_large = object; - too_large_portable = is_portable; - } - continue; - } - } - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, total == 0 ? "\n" : " "); - if (parent == -1) - pf_buffer_string (filter, - lib_select_response (game, - "You pick up ", - "I pick up ", - "%player% picks up ")); - else - pf_buffer_string (filter, - lib_select_response (game, - "You take ", - "I take ", - "%player% takes ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - gs_object_player_get (game, object); - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, total == 0 ? "\n" : " "); - if (parent == -1) - pf_buffer_string (filter, - lib_select_response (game, - "You pick up ", - "I pick up ", - "%player% picks up ")); - else - pf_buffer_string (filter, - lib_select_response (game, - "You take ", - "I take ", - "%player% takes ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - if (parent != -1) - { - pf_buffer_string (filter, " from "); - lib_print_object_np (game, parent); - } - pf_buffer_character (filter, '.'); - } - total += count; - has_printed |= count > 0; - } - } - - /* - * If we ran out of capacity, either in weight or in size, print the - * details. Note that we currently only report the first object of any - * type to go over capacity. - */ - if (too_heavy != -1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, too_heavy); - pf_buffer_string (filter, - lib_select_plurality (game, too_heavy, " is", " are")); - pf_buffer_string (filter, - lib_select_response (game, - " too heavy for you to carry", - " too heavy for me to carry", - " too heavy for %player% to carry")); - if (too_heavy_portable) - pf_buffer_string (filter, " at the moment"); - pf_buffer_character (filter, '.'); - has_printed |= TRUE; - } - else if (too_large != -1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "Your hands are full", - "My hands are full", - "%player%'s hands are full")); - if (too_large_portable) - pf_buffer_string (filter, " at the moment"); - pf_buffer_character (filter, '.'); - has_printed |= TRUE; - } - - /* - * Note any remaining multiple references left out of the take operation. - * This is some workload... - * - * First, deal with the case where we have an associated object. - */ - if (is_associate_object) - { - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (gs_object_position (game, object) == OBJ_HELD_PLAYER - || gs_object_position (game, object) == OBJ_WORN_PLAYER) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, trail); - } - else - pf_buffer_string (filter, ", "); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, trail); - pf_buffer_string (filter, - lib_select_plurality (game, trail, - " is not ", - " are not ")); - } - else - { - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_string (filter, " are not "); - } - if (obj_is_container (game, associate)) - { - pf_buffer_string (filter, "in "); - if (obj_is_surface (game, associate)) - pf_buffer_string (filter, "or on "); - } - else - pf_buffer_string (filter, "on "); - lib_print_object_np (game, associate); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - } - - /* - * Now, deal with the case where we have an associated NPC. Once this - * case is handled, we can force the object references so that the code - * that follows on from here will report errors taking all objects. - * - * Note that this means that we can never successfully take an object - * from an NPC; that'll have to happen via a game's own commands. - */ - if (is_associate_npc) - { - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (gs_object_position (game, object) == OBJ_PART_NPC) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_npc_np (game, associate); - pf_buffer_string (filter, " is not carrying "); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_npc_np (game, associate); - pf_buffer_string (filter, " is not carrying "); - lib_print_object_np (game, trail); - } - else - { - pf_buffer_string (filter, " or "); - lib_print_object_np (game, trail); - } - pf_buffer_character (filter, '!'); - } - has_printed |= count > 0; - - /* - * Merge any remaining object references into multiple references, - * so that succeeding code complains about the inability to acquire - * these objects. - */ - for (object = 0; object < object_count; object++) - { - game->multiple_references[object] |= game->object_references[object]; - game->object_references[object] = FALSE; - } - } - - /* - * The remainder of this routine is common error reporting for both object - * and NPC associates (and also for no associates). - */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (gs_object_position (game, object) != OBJ_HELD_PLAYER) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You've already got ", - "I've already got ", - "%player% already has ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You've already got ", - "I've already got ", - "%player% already has ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '!'); - } - has_printed |= count > 0; - - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (gs_object_position (game, object) != OBJ_WORN_PLAYER) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You're already wearing ", - "I'm already wearing ", - "%player% is already wearing ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You're already wearing ", - "I'm already wearing ", - "%player% is already wearing ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '!'); - } - has_printed |= count > 0; - - for (npc = 0; npc < gs_npc_count (game); npc++) - { - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (gs_object_position (game, object) != OBJ_HELD_NPC - && gs_object_position (game, object) != OBJ_WORN_NPC) - continue; - if (gs_object_parent (game, object) != npc) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_npc_np (game, gs_object_parent (game, trail)); - pf_buffer_string (filter, - lib_select_response (game, - " refuses to give you ", - " refuses to give me ", - " refuses to give %player% ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_npc_np (game, gs_object_parent (game, trail)); - pf_buffer_string (filter, - lib_select_response (game, - " refuses to give you ", - " refuses to give me ", - " refuses to give %player% ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '!'); - } - has_printed |= count > 0; - } - - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You can't take ", - "I can't take ", - "%player% can't take ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You can't take ", - "I can't take ", - "%player% can't take ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '!'); - } +lib_take_backend_common(sc_gameref_t game, sc_int associate, + sc_bool is_associate_object, sc_bool is_associate_npc) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object_count, object, count, trail, total, npc; + sc_int too_heavy, too_large; + sc_bool too_heavy_portable, too_large_portable, has_printed; + assert(!is_associate_object || !is_associate_npc); + + /* Initialize our notions of anything exceeding player capacity. */ + too_heavy_portable = too_large_portable = FALSE; + too_large = too_heavy = -1; + + /* + * Try game commands for all referenced objects first. If any succeed, + * remove that reference from the list. At the same time, filter out and + * flag any object that takes us over the player's capacity. We report + * only the first. + */ + has_printed = FALSE; + object_count = gs_object_count(game); + for (object = 0; object < object_count; object++) { + sc_bool status; + + if (!game->object_references[object]) + continue; + + /* + * If the object is inside or on something already held by the player, + * capacity checks are meaningless. + */ + if (!((gs_object_position(game, object) == OBJ_IN_OBJECT + || gs_object_position(game, object) == OBJ_ON_OBJECT) + && obj_indirectly_held_by_player(game, + gs_object_parent(game, object)))) { + sc_bool is_portable; + + /* + * See if the object takes us beyond capacity. If it does and it's + * the first of its kind, note it and continue. + */ + if (lib_object_too_heavy(game, object, &is_portable)) { + if (too_heavy == -1) { + too_heavy = object; + too_heavy_portable = is_portable; + } + game->object_references[object] = FALSE; + continue; + } + if (lib_object_too_large(game, object, &is_portable)) { + if (too_large == -1) { + too_large = object; + too_large_portable = is_portable; + } + game->object_references[object] = FALSE; + continue; + } + } + + /* Now try for a game command, using the associate if supplied. */ + if (is_associate_object) + status = lib_try_game_command_with_object(game, "get", + object, "from", associate); + else if (is_associate_npc) + status = lib_try_game_command_with_npc(game, "get", + object, "from", associate); + else + status = lib_try_game_command_short(game, "get", object); + if (status) { + game->object_references[object] = FALSE; + has_printed = TRUE; + } + } + + /* + * We attempt acquisition of get-able objects here only for cases where + * there is either no associate, or where the associate is an object. If + * the associate is an NPC, we're going to refuse all acquisitions later + * on, by forcing object references. + */ + total = 0; + if (!is_associate_npc) { + sc_int parent, start, limit; + + /* + * Attempt to acquire each remaining get-able object in turn, looping + * on each possible parent object in turn, with an initial parent of + * -1 for objects not contained or supported. + * + * If we're dealing with only objects from a known container or + * supporter, eliminate all but one iteration of the parent search. + */ + start = is_associate_object ? associate : -1; + limit = is_associate_object ? associate : object_count - 1; + + for (parent = start; parent <= limit; parent++) { + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + sc_bool is_portable; + + if (!game->object_references[object]) + continue; + + /* + * If parent is -1, ignore contained objects, otherwise ignore + * objects not contained, or if contained, not contained by the + * current parent. + */ + if (parent == -1) { + if (gs_object_position(game, object) == OBJ_IN_OBJECT + || gs_object_position(game, object) == OBJ_ON_OBJECT) + continue; + } else { + if (!(gs_object_position(game, object) == OBJ_IN_OBJECT + || gs_object_position(game, object) == OBJ_ON_OBJECT)) + continue; + if (gs_object_parent(game, object) != parent) + continue; + } + + /* + * Here we have to repeat capacity checks. As objects are + * acquired more and more of the player's capacity gets used up. + * This means a check directly before each acquisition. + */ + if (parent == -1 + || !obj_indirectly_held_by_player(game, parent)) { + if (lib_object_too_heavy(game, object, &is_portable)) { + if (too_heavy == -1) { + too_heavy = object; + too_heavy_portable = is_portable; + } + continue; + } + if (lib_object_too_large(game, object, &is_portable)) { + if (too_large == -1) { + too_large = object; + too_large_portable = is_portable; + } + continue; + } + } + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, total == 0 ? "\n" : " "); + if (parent == -1) + pf_buffer_string(filter, + lib_select_response(game, + "You pick up ", + "I pick up ", + "%player% picks up ")); + else + pf_buffer_string(filter, + lib_select_response(game, + "You take ", + "I take ", + "%player% takes ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + gs_object_player_get(game, object); + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, total == 0 ? "\n" : " "); + if (parent == -1) + pf_buffer_string(filter, + lib_select_response(game, + "You pick up ", + "I pick up ", + "%player% picks up ")); + else + pf_buffer_string(filter, + lib_select_response(game, + "You take ", + "I take ", + "%player% takes ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + if (parent != -1) { + pf_buffer_string(filter, " from "); + lib_print_object_np(game, parent); + } + pf_buffer_character(filter, '.'); + } + total += count; + has_printed |= count > 0; + } + } + + /* + * If we ran out of capacity, either in weight or in size, print the + * details. Note that we currently only report the first object of any + * type to go over capacity. + */ + if (too_heavy != -1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, too_heavy); + pf_buffer_string(filter, + lib_select_plurality(game, too_heavy, " is", " are")); + pf_buffer_string(filter, + lib_select_response(game, + " too heavy for you to carry", + " too heavy for me to carry", + " too heavy for %player% to carry")); + if (too_heavy_portable) + pf_buffer_string(filter, " at the moment"); + pf_buffer_character(filter, '.'); + has_printed |= TRUE; + } else if (too_large != -1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "Your hands are full", + "My hands are full", + "%player%'s hands are full")); + if (too_large_portable) + pf_buffer_string(filter, " at the moment"); + pf_buffer_character(filter, '.'); + has_printed |= TRUE; + } + + /* + * Note any remaining multiple references left out of the take operation. + * This is some workload... + * + * First, deal with the case where we have an associated object. + */ + if (is_associate_object) { + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (gs_object_position(game, object) == OBJ_HELD_PLAYER + || gs_object_position(game, object) == OBJ_WORN_PLAYER) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, trail); + } else + pf_buffer_string(filter, ", "); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, trail); + pf_buffer_string(filter, + lib_select_plurality(game, trail, + " is not ", + " are not ")); + } else { + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_string(filter, " are not "); + } + if (obj_is_container(game, associate)) { + pf_buffer_string(filter, "in "); + if (obj_is_surface(game, associate)) + pf_buffer_string(filter, "or on "); + } else + pf_buffer_string(filter, "on "); + lib_print_object_np(game, associate); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + } + + /* + * Now, deal with the case where we have an associated NPC. Once this + * case is handled, we can force the object references so that the code + * that follows on from here will report errors taking all objects. + * + * Note that this means that we can never successfully take an object + * from an NPC; that'll have to happen via a game's own commands. + */ + if (is_associate_npc) { + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (gs_object_position(game, object) == OBJ_PART_NPC) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_npc_np(game, associate); + pf_buffer_string(filter, " is not carrying "); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_npc_np(game, associate); + pf_buffer_string(filter, " is not carrying "); + lib_print_object_np(game, trail); + } else { + pf_buffer_string(filter, " or "); + lib_print_object_np(game, trail); + } + pf_buffer_character(filter, '!'); + } + has_printed |= count > 0; + + /* + * Merge any remaining object references into multiple references, + * so that succeeding code complains about the inability to acquire + * these objects. + */ + for (object = 0; object < object_count; object++) { + game->multiple_references[object] |= game->object_references[object]; + game->object_references[object] = FALSE; + } + } + + /* + * The remainder of this routine is common error reporting for both object + * and NPC associates (and also for no associates). + */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (gs_object_position(game, object) != OBJ_HELD_PLAYER) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You've already got ", + "I've already got ", + "%player% already has ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You've already got ", + "I've already got ", + "%player% already has ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '!'); + } + has_printed |= count > 0; + + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (gs_object_position(game, object) != OBJ_WORN_PLAYER) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You're already wearing ", + "I'm already wearing ", + "%player% is already wearing ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You're already wearing ", + "I'm already wearing ", + "%player% is already wearing ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '!'); + } + has_printed |= count > 0; + + for (npc = 0; npc < gs_npc_count(game); npc++) { + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (gs_object_position(game, object) != OBJ_HELD_NPC + && gs_object_position(game, object) != OBJ_WORN_NPC) + continue; + if (gs_object_parent(game, object) != npc) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_npc_np(game, gs_object_parent(game, trail)); + pf_buffer_string(filter, + lib_select_response(game, + " refuses to give you ", + " refuses to give me ", + " refuses to give %player% ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_npc_np(game, gs_object_parent(game, trail)); + pf_buffer_string(filter, + lib_select_response(game, + " refuses to give you ", + " refuses to give me ", + " refuses to give %player% ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '!'); + } + has_printed |= count > 0; + } + + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You can't take ", + "I can't take ", + "%player% can't take ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You can't take ", + "I can't take ", + "%player% can't take ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '!'); + } } @@ -4837,21 +4375,18 @@ lib_take_backend_common (sc_gameref_t game, sc_int associate, * the plain "take" handlers, or the "take from " handlers. */ static void -lib_take_backend (sc_gameref_t game) -{ - lib_take_backend_common (game, -1, FALSE, FALSE); +lib_take_backend(sc_gameref_t game) { + lib_take_backend_common(game, -1, FALSE, FALSE); } static void -lib_take_from_object_backend (sc_gameref_t game, sc_int associate) -{ - lib_take_backend_common (game, associate, TRUE, FALSE); +lib_take_from_object_backend(sc_gameref_t game, sc_int associate) { + lib_take_backend_common(game, associate, TRUE, FALSE); } static void -lib_take_from_npc_backend (sc_gameref_t game, sc_int associate) -{ - lib_take_backend_common (game, associate, FALSE, TRUE); +lib_take_from_npc_backend(sc_gameref_t game, sc_int associate) { + lib_take_backend_common(game, associate, FALSE, TRUE); } @@ -4863,32 +4398,30 @@ lib_take_from_npc_backend (sc_gameref_t game, sc_int associate) * Returns TRUE if an object may be acquired, FALSE otherwise. */ static sc_bool -lib_take_filter (sc_gameref_t game, sc_int object, sc_int unused) -{ - assert (unused == -1); - - /* - * To be take-able, an object must be visible in the room, not static, - * and not already held or worn by the player or an NPC. - */ - return obj_indirectly_in_room (game, object, gs_playerroom (game)) - && !obj_is_static (game, object) - && !(gs_object_position (game, object) == OBJ_HELD_PLAYER - || gs_object_position (game, object) == OBJ_WORN_PLAYER) - && !(gs_object_position (game, object) == OBJ_HELD_NPC - || gs_object_position (game, object) == OBJ_WORN_NPC); +lib_take_filter(sc_gameref_t game, sc_int object, sc_int unused) { + assert(unused == -1); + + /* + * To be take-able, an object must be visible in the room, not static, + * and not already held or worn by the player or an NPC. + */ + return obj_indirectly_in_room(game, object, gs_playerroom(game)) + && !obj_is_static(game, object) + && !(gs_object_position(game, object) == OBJ_HELD_PLAYER + || gs_object_position(game, object) == OBJ_WORN_PLAYER) + && !(gs_object_position(game, object) == OBJ_HELD_NPC + || gs_object_position(game, object) == OBJ_WORN_NPC); } static sc_bool -lib_take_not_associated_filter (sc_gameref_t game, - sc_int object, sc_int unused) -{ - assert (unused == -1); +lib_take_not_associated_filter(sc_gameref_t game, + sc_int object, sc_int unused) { + assert(unused == -1); - /* In addition to other checks, the object may not be in or on an object. */ - return lib_take_filter (game, object, -1) - && !(gs_object_position (game, object) == OBJ_ON_OBJECT - || gs_object_position (game, object) == OBJ_IN_OBJECT); + /* In addition to other checks, the object may not be in or on an object. */ + return lib_take_filter(game, object, -1) + && !(gs_object_position(game, object) == OBJ_ON_OBJECT + || gs_object_position(game, object) == OBJ_IN_OBJECT); } @@ -4898,24 +4431,23 @@ lib_take_not_associated_filter (sc_gameref_t game, * Attempt to take all objects currently visible to the player. */ sc_bool -lib_cmd_take_all (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects; +lib_cmd_take_all(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects; - /* Filter objects into references, then handle with the backend. */ - gs_set_multiple_references (game); - objects = lib_apply_multiple_filter (game, - lib_take_not_associated_filter, -1, - NULL); - gs_clear_multiple_references (game); - if (objects > 0) - lib_take_backend (game); - else - pf_buffer_string (filter, "There is nothing to pick up here."); + /* Filter objects into references, then handle with the backend. */ + gs_set_multiple_references(game); + objects = lib_apply_multiple_filter(game, + lib_take_not_associated_filter, -1, + NULL); + gs_clear_multiple_references(game); + if (objects > 0) + lib_take_backend(game); + else + pf_buffer_string(filter, "There is nothing to pick up here."); - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -4926,35 +4458,33 @@ lib_cmd_take_all (sc_gameref_t game) * in %text%. */ sc_bool -lib_cmd_take_except_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects, references; +lib_cmd_take_except_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects, references; - /* Parse the multiple objects list to find leave target objects. */ - if (!lib_parse_multiple_objects (game, "leave", - lib_take_not_associated_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find leave target objects. */ + if (!lib_parse_multiple_objects(game, "leave", + lib_take_not_associated_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_except_filter (game, - lib_take_not_associated_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_take_backend (game); - else - { - if (objects == 0) - pf_buffer_string (filter, "There is nothing else to pick up here."); - else - pf_buffer_string (filter, "There is nothing to pick up here."); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_except_filter(game, + lib_take_not_associated_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_take_backend(game); + else { + if (objects == 0) + pf_buffer_string(filter, "There is nothing else to pick up here."); + else + pf_buffer_string(filter, "There is nothing to pick up here."); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -4964,30 +4494,29 @@ lib_cmd_take_except_multiple (sc_gameref_t game) * Take all objects currently available to the player and listed in %text%. */ sc_bool -lib_cmd_take_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects, references; +lib_cmd_take_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects, references; - /* Parse the multiple objects list to find take target objects. */ - if (!lib_parse_multiple_objects (game, "take", - lib_take_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find take target objects. */ + if (!lib_parse_multiple_objects(game, "take", + lib_take_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_multiple_filter (game, - lib_take_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_take_backend (game); - else - pf_buffer_string (filter, "There is nothing to pick up here."); + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_multiple_filter(game, + lib_take_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_take_backend(game); + else + pf_buffer_string(filter, "There is nothing to pick up here."); - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -4998,16 +4527,15 @@ lib_cmd_take_multiple (sc_gameref_t game) * Returns TRUE if an object may be acquired, FALSE otherwise. */ static sc_bool -lib_take_from_filter (sc_gameref_t game, sc_int object, sc_int associate) -{ - /* - * To be take-able, an object must be either inside or on the specified - * object. - */ - return (gs_object_position (game, object) == OBJ_IN_OBJECT - || gs_object_position (game, object) == OBJ_ON_OBJECT) - && !obj_is_static (game, object) - && gs_object_parent (game, object) == associate; +lib_take_from_filter(sc_gameref_t game, sc_int object, sc_int associate) { + /* + * To be take-able, an object must be either inside or on the specified + * object. + */ + return (gs_object_position(game, object) == OBJ_IN_OBJECT + || gs_object_position(game, object) == OBJ_ON_OBJECT) + && !obj_is_static(game, object) + && gs_object_parent(game, object) == associate; } @@ -5018,70 +4546,57 @@ lib_take_from_filter (sc_gameref_t game, sc_int object, sc_int associate) * supporter object. */ static void -lib_take_from_empty (sc_gameref_t game, sc_int associate, sc_bool is_except) -{ - const sc_filterref_t filter = gs_get_filter (game); - - if (obj_is_container (game, associate) && obj_is_surface (game, associate)) - { - if (gs_object_openness (game, associate) <= OBJ_OPEN) - { - if (is_except) - pf_buffer_string (filter, "There is nothing else in or on "); - else - pf_buffer_string (filter, "There is nothing in or on "); - lib_print_object_np (game, associate); - pf_buffer_character (filter, '.'); - } - else - { - if (is_except) - pf_buffer_string (filter, "There is nothing else on "); - else - pf_buffer_string (filter, "There is nothing on "); - lib_print_object_np (game, associate); - if (gs_object_openness (game, associate) == OBJ_LOCKED) - pf_buffer_string (filter, " and it is locked."); - else - pf_buffer_string (filter, " and it is closed."); - } - } - else - { - if (obj_is_container (game, associate)) - { - if (gs_object_openness (game, associate) <= OBJ_OPEN) - { - if (is_except) - pf_buffer_string (filter, "There is nothing else inside "); - else - pf_buffer_string (filter, "There is nothing inside "); - lib_print_object_np (game, associate); - pf_buffer_character (filter, '.'); - } - else - { - pf_new_sentence (filter); - lib_print_object_np (game, associate); - pf_buffer_string (filter, - lib_select_plurality (game, associate, - " is ", " are ")); - if (gs_object_openness (game, associate) == OBJ_LOCKED) - pf_buffer_string (filter, "locked."); - else - pf_buffer_string (filter, "closed."); - } - } - else - { - if (is_except) - pf_buffer_string (filter, "There is nothing else on "); - else - pf_buffer_string (filter, "There is nothing on "); - lib_print_object_np (game, associate); - pf_buffer_character (filter, '.'); - } - } +lib_take_from_empty(sc_gameref_t game, sc_int associate, sc_bool is_except) { + const sc_filterref_t filter = gs_get_filter(game); + + if (obj_is_container(game, associate) && obj_is_surface(game, associate)) { + if (gs_object_openness(game, associate) <= OBJ_OPEN) { + if (is_except) + pf_buffer_string(filter, "There is nothing else in or on "); + else + pf_buffer_string(filter, "There is nothing in or on "); + lib_print_object_np(game, associate); + pf_buffer_character(filter, '.'); + } else { + if (is_except) + pf_buffer_string(filter, "There is nothing else on "); + else + pf_buffer_string(filter, "There is nothing on "); + lib_print_object_np(game, associate); + if (gs_object_openness(game, associate) == OBJ_LOCKED) + pf_buffer_string(filter, " and it is locked."); + else + pf_buffer_string(filter, " and it is closed."); + } + } else { + if (obj_is_container(game, associate)) { + if (gs_object_openness(game, associate) <= OBJ_OPEN) { + if (is_except) + pf_buffer_string(filter, "There is nothing else inside "); + else + pf_buffer_string(filter, "There is nothing inside "); + lib_print_object_np(game, associate); + pf_buffer_character(filter, '.'); + } else { + pf_new_sentence(filter); + lib_print_object_np(game, associate); + pf_buffer_string(filter, + lib_select_plurality(game, associate, + " is ", " are ")); + if (gs_object_openness(game, associate) == OBJ_LOCKED) + pf_buffer_string(filter, "locked."); + else + pf_buffer_string(filter, "closed."); + } + } else { + if (is_except) + pf_buffer_string(filter, "There is nothing else on "); + else + pf_buffer_string(filter, "There is nothing on "); + lib_print_object_np(game, associate); + pf_buffer_character(filter, '.'); + } + } } @@ -5091,39 +4606,36 @@ lib_take_from_empty (sc_gameref_t game, sc_int associate, sc_bool is_except) * Validate the supporter requested in "take from" commands. */ static sc_bool -lib_take_from_is_valid (sc_gameref_t game, sc_int associate) -{ - const sc_filterref_t filter = gs_get_filter (game); - - /* Disallow emptying non-container/non-surface objects. */ - if (!(obj_is_container (game, associate) - || obj_is_surface (game, associate))) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't take anything from ", - "I can't take anything from ", - "%player% can't take anything from ")); - lib_print_object_np (game, associate); - pf_buffer_string (filter, ".\n"); - return FALSE; - } - - /* If object is a container, and is closed, reject now. */ - if (obj_is_container (game, associate) - && gs_object_openness (game, associate) > OBJ_OPEN) - { - pf_new_sentence (filter); - lib_print_object_np (game, associate); - pf_buffer_string (filter, - lib_select_plurality (game, associate, - " is closed.\n", - " are closed.\n")); - return FALSE; - } - - /* Associate is a valid target for "take from". */ - return TRUE; +lib_take_from_is_valid(sc_gameref_t game, sc_int associate) { + const sc_filterref_t filter = gs_get_filter(game); + + /* Disallow emptying non-container/non-surface objects. */ + if (!(obj_is_container(game, associate) + || obj_is_surface(game, associate))) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't take anything from ", + "I can't take anything from ", + "%player% can't take anything from ")); + lib_print_object_np(game, associate); + pf_buffer_string(filter, ".\n"); + return FALSE; + } + + /* If object is a container, and is closed, reject now. */ + if (obj_is_container(game, associate) + && gs_object_openness(game, associate) > OBJ_OPEN) { + pf_new_sentence(filter); + lib_print_object_np(game, associate); + pf_buffer_string(filter, + lib_select_plurality(game, associate, + " is closed.\n", + " are closed.\n")); + return FALSE; + } + + /* Associate is a valid target for "take from". */ + return TRUE; } @@ -5133,34 +4645,33 @@ lib_take_from_is_valid (sc_gameref_t game, sc_int associate) * Attempt to take all objects contained in or supported by a given object. */ sc_bool -lib_cmd_take_all_from (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int associate, objects; - sc_bool is_ambiguous; +lib_cmd_take_all_from(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int associate, objects; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - associate = lib_disambiguate_object (game, "take from", &is_ambiguous); - if (associate == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + associate = lib_disambiguate_object(game, "take from", &is_ambiguous); + if (associate == -1) + return is_ambiguous; - /* Validate the associate object to take from. */ - if (!lib_take_from_is_valid (game, associate)) - return TRUE; + /* Validate the associate object to take from. */ + if (!lib_take_from_is_valid(game, associate)) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - gs_set_multiple_references (game); - objects = lib_apply_multiple_filter (game, - lib_take_from_filter, associate, - NULL); - gs_clear_multiple_references (game); - if (objects > 0) - lib_take_from_object_backend (game, associate); - else - lib_take_from_empty (game, associate, FALSE); + /* Filter objects into references, then handle with the backend. */ + gs_set_multiple_references(game); + objects = lib_apply_multiple_filter(game, + lib_take_from_filter, associate, + NULL); + gs_clear_multiple_references(game); + if (objects > 0) + lib_take_from_object_backend(game, associate); + else + lib_take_from_empty(game, associate, FALSE); - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5171,50 +4682,48 @@ lib_cmd_take_all_from (sc_gameref_t game) * those listed in %text%. */ sc_bool -lib_cmd_take_from_except_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int associate, objects, references; - sc_bool is_ambiguous; +lib_cmd_take_from_except_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int associate, objects, references; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - associate = lib_disambiguate_object (game, "take from", &is_ambiguous); - if (associate == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + associate = lib_disambiguate_object(game, "take from", &is_ambiguous); + if (associate == -1) + return is_ambiguous; - /* Parse the multiple objects list to find leave target objects. */ - if (!lib_parse_multiple_objects (game, "leave", - lib_take_from_filter, associate, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find leave target objects. */ + if (!lib_parse_multiple_objects(game, "leave", + lib_take_from_filter, associate, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Validate the associate object to take from. */ - if (!lib_take_from_is_valid (game, associate)) - return TRUE; + /* Validate the associate object to take from. */ + if (!lib_take_from_is_valid(game, associate)) + return TRUE; - /* As a special case, complain about requests to retain the associate. */ - if (game->multiple_references[associate]) - { - pf_buffer_string (filter, - "I only understood you as far as wanting to leave "); - lib_print_object_np (game, associate); - pf_buffer_string (filter, ".\n"); - return TRUE; - } + /* As a special case, complain about requests to retain the associate. */ + if (game->multiple_references[associate]) { + pf_buffer_string(filter, + "I only understood you as far as wanting to leave "); + lib_print_object_np(game, associate); + pf_buffer_string(filter, ".\n"); + return TRUE; + } - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_except_filter (game, - lib_take_from_filter, associate, - &references); - if (objects > 0 || references > 0) - lib_take_from_object_backend (game, associate); - else - lib_take_from_empty (game, associate, TRUE); + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_except_filter(game, + lib_take_from_filter, associate, + &references); + if (objects > 0 || references > 0) + lib_take_from_object_backend(game, associate); + else + lib_take_from_empty(game, associate, TRUE); - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5226,40 +4735,39 @@ lib_cmd_take_from_except_multiple (sc_gameref_t game) * ers and surfaces, but it's a standard in Adrift so here it is. */ sc_bool -lib_cmd_take_from_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int associate, objects, references; - sc_bool is_ambiguous; +lib_cmd_take_from_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int associate, objects, references; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - associate = lib_disambiguate_object (game, "take from", &is_ambiguous); - if (associate == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + associate = lib_disambiguate_object(game, "take from", &is_ambiguous); + if (associate == -1) + return is_ambiguous; - /* Parse the multiple objects list to find take target objects. */ - if (!lib_parse_multiple_objects (game, "take", - lib_take_from_filter, associate, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find take target objects. */ + if (!lib_parse_multiple_objects(game, "take", + lib_take_from_filter, associate, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Validate the associate object to take from. */ - if (!lib_take_from_is_valid (game, associate)) - return TRUE; + /* Validate the associate object to take from. */ + if (!lib_take_from_is_valid(game, associate)) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_multiple_filter (game, - lib_take_from_filter, associate, - &references); - if (objects > 0 || references > 0) - lib_take_from_object_backend (game, associate); - else - lib_take_from_empty (game, associate, FALSE); + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_multiple_filter(game, + lib_take_from_filter, associate, + &references); + if (objects > 0 || references > 0) + lib_take_from_object_backend(game, associate); + else + lib_take_from_empty(game, associate, FALSE); - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5270,16 +4778,15 @@ lib_cmd_take_from_multiple (sc_gameref_t game) * Returns TRUE if an object may be acquired, FALSE otherwise. */ static sc_bool -lib_take_from_npc_filter (sc_gameref_t game, sc_int object, sc_int associate) -{ - /* - * To be take-able, an object must be either held or worn by the specified - * NPC. - */ - return (gs_object_position (game, object) == OBJ_HELD_NPC - || gs_object_position (game, object) == OBJ_WORN_NPC) - && !obj_is_static (game, object) - && gs_object_parent (game, object) == associate; +lib_take_from_npc_filter(sc_gameref_t game, sc_int object, sc_int associate) { + /* + * To be take-able, an object must be either held or worn by the specified + * NPC. + */ + return (gs_object_position(game, object) == OBJ_HELD_NPC + || gs_object_position(game, object) == OBJ_WORN_NPC) + && !obj_is_static(game, object) + && gs_object_parent(game, object) == associate; } @@ -5289,34 +4796,32 @@ lib_take_from_npc_filter (sc_gameref_t game, sc_int object, sc_int associate) * Attempt to take all objects held or worn by a given NPC. */ sc_bool -lib_cmd_take_all_from_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int associate, objects; - sc_bool is_ambiguous; +lib_cmd_take_all_from_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int associate, objects; + sc_bool is_ambiguous; - /* Get the referenced NPC, and if none, consider complete. */ - associate = lib_disambiguate_npc (game, "take from", &is_ambiguous); - if (associate == -1) - return is_ambiguous; + /* Get the referenced NPC, and if none, consider complete. */ + associate = lib_disambiguate_npc(game, "take from", &is_ambiguous); + if (associate == -1) + return is_ambiguous; - /* Filter objects into references, then handle with the backend. */ - gs_set_multiple_references (game); - objects = lib_apply_multiple_filter (game, - lib_take_from_npc_filter, associate, - NULL); - gs_clear_multiple_references (game); - if (objects > 0) - lib_take_from_npc_backend (game, associate); - else - { - pf_new_sentence (filter); - lib_print_npc_np (game, associate); - pf_buffer_string (filter, " is not carrying anything!"); - } + /* Filter objects into references, then handle with the backend. */ + gs_set_multiple_references(game); + objects = lib_apply_multiple_filter(game, + lib_take_from_npc_filter, associate, + NULL); + gs_clear_multiple_references(game); + if (objects > 0) + lib_take_from_npc_backend(game, associate); + else { + pf_new_sentence(filter); + lib_print_npc_np(game, associate); + pf_buffer_string(filter, " is not carrying anything!"); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5327,40 +4832,38 @@ lib_cmd_take_all_from_npc (sc_gameref_t game) * listed in %text%. */ sc_bool -lib_cmd_take_from_npc_except_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int associate, objects, references; - sc_bool is_ambiguous; +lib_cmd_take_from_npc_except_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int associate, objects, references; + sc_bool is_ambiguous; - /* Get the referenced NPC, and if none, consider complete. */ - associate = lib_disambiguate_npc (game, "take from", &is_ambiguous); - if (associate == -1) - return is_ambiguous; + /* Get the referenced NPC, and if none, consider complete. */ + associate = lib_disambiguate_npc(game, "take from", &is_ambiguous); + if (associate == -1) + return is_ambiguous; - /* Parse the multiple objects list to find leave target objects. */ - if (!lib_parse_multiple_objects (game, "leave", - lib_take_from_npc_filter, associate, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find leave target objects. */ + if (!lib_parse_multiple_objects(game, "leave", + lib_take_from_npc_filter, associate, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_except_filter (game, - lib_take_from_npc_filter, associate, - &references); - if (objects > 0 || references > 0) - lib_take_from_npc_backend (game, associate); - else - { - pf_new_sentence (filter); - lib_print_npc_np (game, associate); - pf_buffer_string (filter, " is not carrying anything else!"); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_except_filter(game, + lib_take_from_npc_filter, associate, + &references); + if (objects > 0 || references > 0) + lib_take_from_npc_backend(game, associate); + else { + pf_new_sentence(filter); + lib_print_npc_np(game, associate); + pf_buffer_string(filter, " is not carrying anything else!"); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5371,40 +4874,38 @@ lib_cmd_take_from_npc_except_multiple (sc_gameref_t game) * in %text%. */ sc_bool -lib_cmd_take_from_npc_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int associate, objects, references; - sc_bool is_ambiguous; +lib_cmd_take_from_npc_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int associate, objects, references; + sc_bool is_ambiguous; - /* Get the referenced NPC, and if none, consider complete. */ - associate = lib_disambiguate_npc (game, "take from", &is_ambiguous); - if (associate == -1) - return is_ambiguous; + /* Get the referenced NPC, and if none, consider complete. */ + associate = lib_disambiguate_npc(game, "take from", &is_ambiguous); + if (associate == -1) + return is_ambiguous; - /* Parse the multiple objects list to find take target objects. */ - if (!lib_parse_multiple_objects (game, "take", - lib_take_from_npc_filter, associate, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find take target objects. */ + if (!lib_parse_multiple_objects(game, "take", + lib_take_from_npc_filter, associate, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_multiple_filter (game, - lib_take_from_npc_filter, associate, - &references); - if (objects > 0 || references > 0) - lib_take_from_npc_backend (game, associate); - else - { - pf_new_sentence (filter); - lib_print_npc_np (game, associate); - pf_buffer_string (filter, " is not carrying anything!"); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_multiple_filter(game, + lib_take_from_npc_filter, associate, + &references); + if (objects > 0 || references > 0) + lib_take_from_npc_backend(game, associate); + else { + pf_new_sentence(filter); + lib_print_npc_np(game, associate); + pf_buffer_string(filter, " is not carrying anything!"); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5419,126 +4920,109 @@ lib_cmd_take_from_npc_multiple (sc_gameref_t game) * deemed not actionable are flagged in multiple_references. */ static void -lib_drop_backend (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object_count, object, count, trail; - sc_bool has_printed; - - /* - * Try game commands for all referenced objects first. If any succeed, - * remove that reference from the list. - */ - has_printed = FALSE; - object_count = gs_object_count (game); - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (lib_try_game_command_short (game, "drop", object)) - { - game->object_references[object] = FALSE; - has_printed = TRUE; - } - } - - /* Drop every object that remains referenced. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You drop ", - "I drop ", - "%player% drops ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - gs_object_to_room (game, object, gs_playerroom (game)); - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You drop ", - "I drop ", - "%player% drops ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - - /* Note any remaining multiple references left out of the drop operation. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - } - else - pf_buffer_string (filter, " or "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } +lib_drop_backend(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object_count, object, count, trail; + sc_bool has_printed; + + /* + * Try game commands for all referenced objects first. If any succeed, + * remove that reference from the list. + */ + has_printed = FALSE; + object_count = gs_object_count(game); + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (lib_try_game_command_short(game, "drop", object)) { + game->object_references[object] = FALSE; + has_printed = TRUE; + } + } + + /* Drop every object that remains referenced. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You drop ", + "I drop ", + "%player% drops ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + gs_object_to_room(game, object, gs_playerroom(game)); + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You drop ", + "I drop ", + "%player% drops ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + + /* Note any remaining multiple references left out of the drop operation. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + } else + pf_buffer_string(filter, " or "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } } @@ -5549,12 +5033,11 @@ lib_drop_backend (sc_gameref_t game) * Returns TRUE if an object may be dropped, FALSE otherwise. */ static sc_bool -lib_drop_filter (sc_gameref_t game, sc_int object, sc_int unused) -{ - assert (unused == -1); +lib_drop_filter(sc_gameref_t game, sc_int object, sc_int unused) { + assert(unused == -1); - return !obj_is_static (game, object) - && gs_object_position (game, object) == OBJ_HELD_PLAYER; + return !obj_is_static(game, object) + && gs_object_position(game, object) == OBJ_HELD_PLAYER; } @@ -5564,30 +5047,28 @@ lib_drop_filter (sc_gameref_t game, sc_int object, sc_int unused) * Drop all objects currently held by the player. */ sc_bool -lib_cmd_drop_all (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects; +lib_cmd_drop_all(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects; - /* Filter objects into references, then handle with the backend. */ - gs_set_multiple_references (game); - objects = lib_apply_multiple_filter (game, - lib_drop_filter, -1, - NULL); - gs_clear_multiple_references (game); - if (objects > 0) - lib_drop_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You're not carrying anything.", - "I'm not carrying anything.", - "%player%'s not carrying anything.")); - } + /* Filter objects into references, then handle with the backend. */ + gs_set_multiple_references(game); + objects = lib_apply_multiple_filter(game, + lib_drop_filter, -1, + NULL); + gs_clear_multiple_references(game); + if (objects > 0) + lib_drop_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You're not carrying anything.", + "I'm not carrying anything.", + "%player%'s not carrying anything.")); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5598,39 +5079,37 @@ lib_cmd_drop_all (sc_gameref_t game) * %text%. */ sc_bool -lib_cmd_drop_except_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects, references; +lib_cmd_drop_except_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects, references; - /* Parse the multiple objects list to find retain target objects. */ - if (!lib_parse_multiple_objects (game, "retain", - lib_drop_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find retain target objects. */ + if (!lib_parse_multiple_objects(game, "retain", + lib_drop_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_except_filter (game, - lib_drop_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_drop_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything", - "I am not holding anything", - "%player% is not holding anything")); - if (objects == 0) - pf_buffer_string (filter, " else"); - pf_buffer_character (filter, '.'); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_except_filter(game, + lib_drop_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_drop_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything", + "I am not holding anything", + "%player% is not holding anything")); + if (objects == 0) + pf_buffer_string(filter, " else"); + pf_buffer_character(filter, '.'); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5640,36 +5119,34 @@ lib_cmd_drop_except_multiple (sc_gameref_t game) * Drop all objects currently held by the player and listed in %text%. */ sc_bool -lib_cmd_drop_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects, references; +lib_cmd_drop_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects, references; - /* Parse the multiple objects list to find drop target objects. */ - if (!lib_parse_multiple_objects (game, "drop", - lib_drop_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find drop target objects. */ + if (!lib_parse_multiple_objects(game, "drop", + lib_drop_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_multiple_filter (game, - lib_drop_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_drop_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything.", - "I am not holding anything.", - "%player% is not holding anything.")); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_multiple_filter(game, + lib_drop_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_drop_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything.", + "I am not holding anything.", + "%player% is not holding anything.")); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -5680,74 +5157,70 @@ lib_cmd_drop_multiple (sc_gameref_t game) * Attempt to give an object to an NPC. */ sc_bool -lib_cmd_give_object_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object, npc; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "give", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Get the referenced npc, and if none, consider complete. */ - npc = lib_disambiguate_npc (game, "give to", NULL); - if (npc == -1) - return TRUE; - - /* Reject if not holding the object offered. */ - if (gs_object_position (game, object) != OBJ_HELD_PLAYER) - { - pf_buffer_string (filter, - lib_select_response (game, - "You don't have ", - "I don't have ", - "%player% doesn't have ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, "!\n"); - return TRUE; - } - - /* After all that, the npc is disinterested. */ - pf_new_sentence (filter); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " doesn't seem interested in "); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; -} - -sc_bool -lib_cmd_give_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "give", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Reject if not holding the object offered. */ - if (gs_object_position (game, object) != OBJ_HELD_PLAYER) - { - pf_buffer_string (filter, - lib_select_response (game, - "You don't have ", - "I don't have ", - "%player% doesn't have ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, "!\n"); - return TRUE; - } - - /* After all that, we have to ask (and shouldn't this be "to whom?"). */ - pf_buffer_string (filter, "Give "); - lib_print_object_np (game, object); - pf_buffer_string (filter, " to who?\n"); - return TRUE; +lib_cmd_give_object_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object, npc; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "give", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Get the referenced npc, and if none, consider complete. */ + npc = lib_disambiguate_npc(game, "give to", NULL); + if (npc == -1) + return TRUE; + + /* Reject if not holding the object offered. */ + if (gs_object_position(game, object) != OBJ_HELD_PLAYER) { + pf_buffer_string(filter, + lib_select_response(game, + "You don't have ", + "I don't have ", + "%player% doesn't have ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, "!\n"); + return TRUE; + } + + /* After all that, the npc is disinterested. */ + pf_new_sentence(filter); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " doesn't seem interested in "); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; +} + +sc_bool +lib_cmd_give_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "give", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Reject if not holding the object offered. */ + if (gs_object_position(game, object) != OBJ_HELD_PLAYER) { + pf_buffer_string(filter, + lib_select_response(game, + "You don't have ", + "I don't have ", + "%player% doesn't have ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, "!\n"); + return TRUE; + } + + /* After all that, we have to ask (and shouldn't this be "to whom?"). */ + pf_buffer_string(filter, "Give "); + lib_print_object_np(game, object); + pf_buffer_string(filter, " to who?\n"); + return TRUE; } @@ -5761,228 +5234,197 @@ lib_cmd_give_object (sc_gameref_t game) * deemed not actionable are flagged in multiple_references. */ static void -lib_wear_backend (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object_count, object, count, trail; - sc_bool has_printed; - - /* - * Try game commands for all referenced objects first. If any succeed, - * remove that reference from the list. - */ - has_printed = FALSE; - object_count = gs_object_count (game); - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (lib_try_game_command_short (game, "wear", object)) - { - game->object_references[object] = FALSE; - has_printed = TRUE; - } - } - - /* Wear every object referenced. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You put on ", - "I put on ", - "%player% puts on ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - gs_object_player_wear (game, object); - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You put on ", - "I put on ", - "%player% puts on ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - - /* Note any remaining multiple references left out of the wear operation. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (gs_object_position (game, object) != OBJ_WORN_PLAYER) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are already wearing ", - "I am already wearing ", - "%player% is already wearing ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are already wearing ", - "I am already wearing ", - "%player% is already wearing ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (gs_object_position (game, object) == OBJ_HELD_PLAYER) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - } - else - pf_buffer_string (filter, " or "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You can't wear ", - "I can't wear ", - "%player% can't wear ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You can't wear ", - "I can't wear ", - "%player% can't wear ")); - } - else - pf_buffer_string (filter, " or "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } +lib_wear_backend(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object_count, object, count, trail; + sc_bool has_printed; + + /* + * Try game commands for all referenced objects first. If any succeed, + * remove that reference from the list. + */ + has_printed = FALSE; + object_count = gs_object_count(game); + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (lib_try_game_command_short(game, "wear", object)) { + game->object_references[object] = FALSE; + has_printed = TRUE; + } + } + + /* Wear every object referenced. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You put on ", + "I put on ", + "%player% puts on ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + gs_object_player_wear(game, object); + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You put on ", + "I put on ", + "%player% puts on ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + + /* Note any remaining multiple references left out of the wear operation. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (gs_object_position(game, object) != OBJ_WORN_PLAYER) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are already wearing ", + "I am already wearing ", + "%player% is already wearing ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are already wearing ", + "I am already wearing ", + "%player% is already wearing ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (gs_object_position(game, object) == OBJ_HELD_PLAYER) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + } else + pf_buffer_string(filter, " or "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You can't wear ", + "I can't wear ", + "%player% can't wear ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You can't wear ", + "I can't wear ", + "%player% can't wear ")); + } else + pf_buffer_string(filter, " or "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } } @@ -5993,29 +5435,27 @@ lib_wear_backend (sc_gameref_t game) * Returns TRUE if an object may be worn, FALSE otherwise. */ static sc_bool -lib_wear_filter (sc_gameref_t game, sc_int object, sc_int unused) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - assert (unused == -1); +lib_wear_filter(sc_gameref_t game, sc_int object, sc_int unused) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + assert(unused == -1); - /* - * The object is wearable if the player is holding it, and it's not static - * (static moved to player inventory by event), and if it's marked wearable - * in properties. - */ - if (gs_object_position (game, object) == OBJ_HELD_PLAYER - && !obj_is_static (game, object)) - { - sc_vartype_t vt_key[3]; + /* + * The object is wearable if the player is holding it, and it's not static + * (static moved to player inventory by event), and if it's marked wearable + * in properties. + */ + if (gs_object_position(game, object) == OBJ_HELD_PLAYER + && !obj_is_static(game, object)) { + sc_vartype_t vt_key[3]; - /* Return wearability from the object properties. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Wearable"; - return prop_get_boolean (bundle, "B<-sis", vt_key); - } + /* Return wearability from the object properties. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Wearable"; + return prop_get_boolean(bundle, "B<-sis", vt_key); + } - return FALSE; + return FALSE; } @@ -6025,31 +5465,29 @@ lib_wear_filter (sc_gameref_t game, sc_int object, sc_int unused) * Wear all wearable objects currently held by the player. */ sc_bool -lib_cmd_wear_all (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects; +lib_cmd_wear_all(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects; - /* Filter objects into references, then handle with the backend. */ - gs_set_multiple_references (game); - objects = lib_apply_multiple_filter (game, - lib_wear_filter, -1, - NULL); - gs_clear_multiple_references (game); - if (objects > 0) - lib_wear_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You're not carrying anything", - "I'm not carrying anything", - "%player%'s not carrying anything")); - pf_buffer_string (filter, " that can be worn."); - } + /* Filter objects into references, then handle with the backend. */ + gs_set_multiple_references(game); + objects = lib_apply_multiple_filter(game, + lib_wear_filter, -1, + NULL); + gs_clear_multiple_references(game); + if (objects > 0) + lib_wear_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You're not carrying anything", + "I'm not carrying anything", + "%player%'s not carrying anything")); + pf_buffer_string(filter, " that can be worn."); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -6060,39 +5498,37 @@ lib_cmd_wear_all (sc_gameref_t game) * listed in %text%. */ sc_bool -lib_cmd_wear_except_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects, references; +lib_cmd_wear_except_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects, references; - /* Parse the multiple objects list to find retain target objects. */ - if (!lib_parse_multiple_objects (game, "retain", - lib_wear_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find retain target objects. */ + if (!lib_parse_multiple_objects(game, "retain", + lib_wear_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_except_filter (game, - lib_wear_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_wear_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything", - "I am not holding anything", - "%player% is not holding anything")); - if (objects == 0) - pf_buffer_string (filter, " else"); - pf_buffer_string (filter, " that can be worn."); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_except_filter(game, + lib_wear_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_wear_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything", + "I am not holding anything", + "%player% is not holding anything")); + if (objects == 0) + pf_buffer_string(filter, " else"); + pf_buffer_string(filter, " that can be worn."); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -6103,37 +5539,35 @@ lib_cmd_wear_except_multiple (sc_gameref_t game) * in %text%. */ sc_bool -lib_cmd_wear_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects, references; +lib_cmd_wear_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects, references; - /* Parse the multiple objects list to find wear target objects. */ - if (!lib_parse_multiple_objects (game, "wear", - lib_wear_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find wear target objects. */ + if (!lib_parse_multiple_objects(game, "wear", + lib_wear_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_multiple_filter (game, - lib_wear_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_wear_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything", - "I am not holding anything", - "%player% is not holding anything")); - pf_buffer_string (filter, " that can be worn."); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_multiple_filter(game, + lib_wear_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_wear_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything", + "I am not holding anything", + "%player% is not holding anything")); + pf_buffer_string(filter, " that can be worn."); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -6147,126 +5581,109 @@ lib_cmd_wear_multiple (sc_gameref_t game) * deemed not actionable are flagged in multiple_references. */ static void -lib_remove_backend (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object_count, object, count, trail; - sc_bool has_printed; - - /* - * Try game commands for all referenced objects first. If any succeed, - * remove that reference from the list. - */ - has_printed = FALSE; - object_count = gs_object_count (game); - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (lib_try_game_command_short (game, "remove", object)) - { - game->object_references[object] = FALSE; - has_printed = TRUE; - } - } - - /* Remove every object referenced. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You remove ", - "I remove ", - "%player% removes ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - gs_object_player_get (game, object); - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You remove ", - "I remove ", - "%player% removes ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - - /* Note any remaining multiple references left out of the remove operation. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not wearing ", - "I am not wearing ", - "%player% is not wearing ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not wearing ", - "I am not wearing ", - "%player% is not wearing ")); - } - else - pf_buffer_string (filter, " or "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '!'); - } +lib_remove_backend(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object_count, object, count, trail; + sc_bool has_printed; + + /* + * Try game commands for all referenced objects first. If any succeed, + * remove that reference from the list. + */ + has_printed = FALSE; + object_count = gs_object_count(game); + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (lib_try_game_command_short(game, "remove", object)) { + game->object_references[object] = FALSE; + has_printed = TRUE; + } + } + + /* Remove every object referenced. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You remove ", + "I remove ", + "%player% removes ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + gs_object_player_get(game, object); + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You remove ", + "I remove ", + "%player% removes ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + + /* Note any remaining multiple references left out of the remove operation. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not wearing ", + "I am not wearing ", + "%player% is not wearing ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not wearing ", + "I am not wearing ", + "%player% is not wearing ")); + } else + pf_buffer_string(filter, " or "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '!'); + } } @@ -6277,12 +5694,11 @@ lib_remove_backend (sc_gameref_t game) * Returns TRUE if an object is currently being worn, FALSE otherwise. */ static sc_bool -lib_remove_filter (sc_gameref_t game, sc_int object, sc_int unused) -{ - assert (unused == -1); +lib_remove_filter(sc_gameref_t game, sc_int object, sc_int unused) { + assert(unused == -1); - return !obj_is_static (game, object) - && gs_object_position (game, object) == OBJ_WORN_PLAYER; + return !obj_is_static(game, object) + && gs_object_position(game, object) == OBJ_WORN_PLAYER; } @@ -6292,31 +5708,29 @@ lib_remove_filter (sc_gameref_t game, sc_int object, sc_int unused) * Remove all objects currently held by the player. */ sc_bool -lib_cmd_remove_all (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects; +lib_cmd_remove_all(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects; - /* Filter objects into references, then handle with the backend. */ - gs_set_multiple_references (game); - objects = lib_apply_multiple_filter (game, - lib_remove_filter, -1, - NULL); - gs_clear_multiple_references (game); - if (objects > 0) - lib_remove_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You're not wearing anything", - "I'm not wearing anything", - "%player%'s not wearing anything")); - pf_buffer_string (filter, " that can be removed."); - } + /* Filter objects into references, then handle with the backend. */ + gs_set_multiple_references(game); + objects = lib_apply_multiple_filter(game, + lib_remove_filter, -1, + NULL); + gs_clear_multiple_references(game); + if (objects > 0) + lib_remove_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You're not wearing anything", + "I'm not wearing anything", + "%player%'s not wearing anything")); + pf_buffer_string(filter, " that can be removed."); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -6327,39 +5741,37 @@ lib_cmd_remove_all (sc_gameref_t game) * in %text%. */ sc_bool -lib_cmd_remove_except_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects, references; +lib_cmd_remove_except_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects, references; - /* Parse the multiple objects list to find retain target objects. */ - if (!lib_parse_multiple_objects (game, "retain", - lib_remove_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find retain target objects. */ + if (!lib_parse_multiple_objects(game, "retain", + lib_remove_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_except_filter (game, - lib_remove_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_remove_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not wearing anything", - "I am not wearing anything", - "%player% is not wearing anything")); - if (objects == 0) - pf_buffer_string (filter, " else"); - pf_buffer_string (filter, " that can be removed."); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_except_filter(game, + lib_remove_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_remove_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not wearing anything", + "I am not wearing anything", + "%player% is not wearing anything")); + if (objects == 0) + pf_buffer_string(filter, " else"); + pf_buffer_string(filter, " that can be removed."); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -6369,37 +5781,35 @@ lib_cmd_remove_except_multiple (sc_gameref_t game) * Remove all objects currently worn by the player, and listed in %text%. */ sc_bool -lib_cmd_remove_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int objects, references; +lib_cmd_remove_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int objects, references; - /* Parse the multiple objects list to find remove target objects. */ - if (!lib_parse_multiple_objects (game, "remove", - lib_remove_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find remove target objects. */ + if (!lib_parse_multiple_objects(game, "remove", + lib_remove_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_multiple_filter (game, - lib_remove_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_remove_backend (game); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything", - "I am not holding anything", - "%player% is not holding anything")); - pf_buffer_string (filter, " that can be removed."); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_multiple_filter(game, + lib_remove_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_remove_backend(game); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything", + "I am not holding anything", + "%player% is not holding anything")); + pf_buffer_string(filter, " that can be removed."); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -6409,155 +5819,125 @@ lib_cmd_remove_multiple (sc_gameref_t game) * List objects carried and worn by the player. */ sc_bool -lib_cmd_inventory (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object, count, trail; - sc_bool wearing; - - /* Find and list each object worn by the player. */ - count = 0; - trail = -1; - wearing = FALSE; - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_WORN_PLAYER) - { - if (count > 0) - { - if (count == 1) - { - pf_buffer_string (filter, - lib_select_response (game, - "You are wearing ", - "I am wearing ", - "%player% is wearing ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - pf_buffer_string (filter, - lib_select_response (game, - "You are wearing ", - "I am wearing ", - "%player% is wearing ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object (game, trail); - wearing = TRUE; - } - - /* Find and list each object owned by the player. */ - count = 0; - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_HELD_PLAYER) - { - if (count > 0) - { - if (count == 1) - { - if (wearing) - { - pf_buffer_string (filter, - lib_select_response (game, - ", and you are carrying ", - ", and I am carrying ", - ", and %player% is carrying ")); - } - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are carrying ", - "I am carrying ", - "%player% is carrying ")); - } - } - else - pf_buffer_string (filter, ", "); - lib_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - if (wearing) - { - pf_buffer_string (filter, - lib_select_response (game, - ", and you are carrying ", - ", and I am carrying ", - ", and %player% is carrying ")); - } - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are carrying ", - "I am carrying ", - "%player% is carrying ")); - } - } - else - pf_buffer_string (filter, " and "); - lib_print_object (game, trail); - pf_buffer_character (filter, '.'); - - /* Print contents of every container and surface carried. */ - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_HELD_PLAYER) - { - if (obj_is_container (game, object) - && gs_object_openness (game, object) <= OBJ_OPEN) - lib_list_in_object (game, object, TRUE); - - if (obj_is_surface (game, object)) - lib_list_on_object (game, object, TRUE); - } - } - pf_buffer_character (filter, '\n'); - } - else - { - if (wearing) - { - pf_buffer_string (filter, ", and "); - pf_buffer_string (filter, - lib_select_response (game, - "you are carrying nothing.\n", - "I am carrying nothing.\n", - "%player% is carrying nothing.\n")); - } - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are carrying nothing.\n", - "I am carrying nothing.\n", - "%player% is carrying nothing.\n")); - } - } - - /* Successful command. */ - return TRUE; +lib_cmd_inventory(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object, count, trail; + sc_bool wearing; + + /* Find and list each object worn by the player. */ + count = 0; + trail = -1; + wearing = FALSE; + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_WORN_PLAYER) { + if (count > 0) { + if (count == 1) { + pf_buffer_string(filter, + lib_select_response(game, + "You are wearing ", + "I am wearing ", + "%player% is wearing ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + pf_buffer_string(filter, + lib_select_response(game, + "You are wearing ", + "I am wearing ", + "%player% is wearing ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object(game, trail); + wearing = TRUE; + } + + /* Find and list each object owned by the player. */ + count = 0; + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_HELD_PLAYER) { + if (count > 0) { + if (count == 1) { + if (wearing) { + pf_buffer_string(filter, + lib_select_response(game, + ", and you are carrying ", + ", and I am carrying ", + ", and %player% is carrying ")); + } else { + pf_buffer_string(filter, + lib_select_response(game, + "You are carrying ", + "I am carrying ", + "%player% is carrying ")); + } + } else + pf_buffer_string(filter, ", "); + lib_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + if (wearing) { + pf_buffer_string(filter, + lib_select_response(game, + ", and you are carrying ", + ", and I am carrying ", + ", and %player% is carrying ")); + } else { + pf_buffer_string(filter, + lib_select_response(game, + "You are carrying ", + "I am carrying ", + "%player% is carrying ")); + } + } else + pf_buffer_string(filter, " and "); + lib_print_object(game, trail); + pf_buffer_character(filter, '.'); + + /* Print contents of every container and surface carried. */ + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_HELD_PLAYER) { + if (obj_is_container(game, object) + && gs_object_openness(game, object) <= OBJ_OPEN) + lib_list_in_object(game, object, TRUE); + + if (obj_is_surface(game, object)) + lib_list_on_object(game, object, TRUE); + } + } + pf_buffer_character(filter, '\n'); + } else { + if (wearing) { + pf_buffer_string(filter, ", and "); + pf_buffer_string(filter, + lib_select_response(game, + "you are carrying nothing.\n", + "I am carrying nothing.\n", + "%player% is carrying nothing.\n")); + } else { + pf_buffer_string(filter, + lib_select_response(game, + "You are carrying nothing.\n", + "I am carrying nothing.\n", + "%player% is carrying nothing.\n")); + } + } + + /* Successful command. */ + return TRUE; } @@ -6567,70 +5947,68 @@ lib_cmd_inventory (sc_gameref_t game) * Attempt to open the referenced object. */ sc_bool -lib_cmd_open_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object, openness; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "open", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Get the current object openness. */ - openness = gs_object_openness (game, object); - - /* React to the request based on openness state. */ - switch (openness) - { - case OBJ_OPEN: - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is already open!\n", - " are already open!\n")); - return TRUE; - - case OBJ_CLOSED: - pf_buffer_string (filter, - lib_select_response (game, - "You open ", - "I open ", - "%player% opens ")); - lib_print_object_np (game, object); - pf_buffer_character (filter, '.'); - - /* Set open state, and list contents. */ - gs_set_object_openness (game, object, OBJ_OPEN); - lib_list_in_object (game, object, TRUE); - pf_buffer_character (filter, '\n'); - return TRUE; - - case OBJ_LOCKED: - pf_buffer_string (filter, - lib_select_response (game, - "You can't open ", - "I can't open ", - "%player% can't open ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " as it is locked!\n"); - return TRUE; - - default: - break; - } - - /* The object isn't openable. */ - pf_buffer_string (filter, - lib_select_response (game, - "You can't open ", - "I can't open ", - "%player% can't open ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, "!\n"); - return TRUE; +lib_cmd_open_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object, openness; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "open", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Get the current object openness. */ + openness = gs_object_openness(game, object); + + /* React to the request based on openness state. */ + switch (openness) { + case OBJ_OPEN: + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is already open!\n", + " are already open!\n")); + return TRUE; + + case OBJ_CLOSED: + pf_buffer_string(filter, + lib_select_response(game, + "You open ", + "I open ", + "%player% opens ")); + lib_print_object_np(game, object); + pf_buffer_character(filter, '.'); + + /* Set open state, and list contents. */ + gs_set_object_openness(game, object, OBJ_OPEN); + lib_list_in_object(game, object, TRUE); + pf_buffer_character(filter, '\n'); + return TRUE; + + case OBJ_LOCKED: + pf_buffer_string(filter, + lib_select_response(game, + "You can't open ", + "I can't open ", + "%player% can't open ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " as it is locked!\n"); + return TRUE; + + default: + break; + } + + /* The object isn't openable. */ + pf_buffer_string(filter, + lib_select_response(game, + "You can't open ", + "I can't open ", + "%player% can't open ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, "!\n"); + return TRUE; } @@ -6640,59 +6018,57 @@ lib_cmd_open_object (sc_gameref_t game) * Attempt to close the referenced object. */ sc_bool -lib_cmd_close_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object, openness; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "close", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Get the current object openness. */ - openness = gs_object_openness (game, object); - - /* React to the request based on openness state. */ - switch (openness) - { - case OBJ_OPEN: - pf_buffer_string (filter, - lib_select_response (game, - "You close ", - "I close ", - "%player% closes ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - - /* Set closed state. */ - gs_set_object_openness (game, object, OBJ_CLOSED); - return TRUE; - - case OBJ_CLOSED: - case OBJ_LOCKED: - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is already closed!\n", - " are already closed!\n")); - return TRUE; - - default: - break; - } - - /* The object isn't closeable. */ - pf_buffer_string (filter, - lib_select_response (game, - "You can't close ", - "I can't close ", - "%player% can't close ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, "!\n"); - return TRUE; +lib_cmd_close_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object, openness; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "close", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Get the current object openness. */ + openness = gs_object_openness(game, object); + + /* React to the request based on openness state. */ + switch (openness) { + case OBJ_OPEN: + pf_buffer_string(filter, + lib_select_response(game, + "You close ", + "I close ", + "%player% closes ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + + /* Set closed state. */ + gs_set_object_openness(game, object, OBJ_CLOSED); + return TRUE; + + case OBJ_CLOSED: + case OBJ_LOCKED: + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is already closed!\n", + " are already closed!\n")); + return TRUE; + + default: + break; + } + + /* The object isn't closeable. */ + pf_buffer_string(filter, + lib_select_response(game, + "You can't close ", + "I can't close ", + "%player% can't close ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, "!\n"); + return TRUE; } @@ -6702,64 +6078,59 @@ lib_cmd_close_object (sc_gameref_t game) * Automatically get an object being used as a key, if possible. */ static void -lib_attempt_key_acquisition (sc_gameref_t game, sc_int object) -{ - const sc_filterref_t filter = gs_get_filter (game); - - /* Disallow getting static objects. */ - if (obj_is_static (game, object)) - return; - - /* If the object is not seen or available, reject the attempt. */ - if (!(gs_object_seen (game, object) - && obj_indirectly_in_room (game, object, gs_playerroom (game)))) - return; - - /* - * Check if we already have it, or are wearing it, or if a NPC has or is - * wearing it. - */ - if (gs_object_position (game, object) == OBJ_HELD_PLAYER - || gs_object_position (game, object) == OBJ_WORN_PLAYER - || gs_object_position (game, object) == OBJ_HELD_NPC - || gs_object_position (game, object) == OBJ_WORN_NPC) - return; - - /* - * If the object is contained in or on something we're already holding, - * capacity checks are meaningless. - */ - if (!obj_indirectly_held_by_player (game, object)) - { - if (lib_object_too_heavy (game, object, NULL) - || lib_object_too_large (game, object, NULL)) - return; - } - - /* Retry game commands for the object with a standard "get". */ - if (lib_try_game_command_short (game, "get", object)) - return; - - /* Note what we're doing. */ - if (gs_object_position (game, object) == OBJ_IN_OBJECT - || gs_object_position (game, object) == OBJ_ON_OBJECT) - { - pf_buffer_string (filter, "(Taking "); - lib_print_object_np (game, object); - - pf_buffer_string (filter, " from "); - lib_print_object_np (game, gs_object_parent (game, object)); - pf_buffer_string (filter, " first)\n"); - } - else - { - pf_buffer_string (filter, "(Picking up "); - lib_print_object_np (game, object); - pf_buffer_string (filter, " first)\n"); - } - - /* Take possession of the object. */ - gs_object_player_get (game, object); +lib_attempt_key_acquisition(sc_gameref_t game, sc_int object) { + const sc_filterref_t filter = gs_get_filter(game); + + /* Disallow getting static objects. */ + if (obj_is_static(game, object)) + return; + + /* If the object is not seen or available, reject the attempt. */ + if (!(gs_object_seen(game, object) + && obj_indirectly_in_room(game, object, gs_playerroom(game)))) + return; + + /* + * Check if we already have it, or are wearing it, or if a NPC has or is + * wearing it. + */ + if (gs_object_position(game, object) == OBJ_HELD_PLAYER + || gs_object_position(game, object) == OBJ_WORN_PLAYER + || gs_object_position(game, object) == OBJ_HELD_NPC + || gs_object_position(game, object) == OBJ_WORN_NPC) + return; + + /* + * If the object is contained in or on something we're already holding, + * capacity checks are meaningless. + */ + if (!obj_indirectly_held_by_player(game, object)) { + if (lib_object_too_heavy(game, object, NULL) + || lib_object_too_large(game, object, NULL)) + return; + } + + /* Retry game commands for the object with a standard "get". */ + if (lib_try_game_command_short(game, "get", object)) + return; + + /* Note what we're doing. */ + if (gs_object_position(game, object) == OBJ_IN_OBJECT + || gs_object_position(game, object) == OBJ_ON_OBJECT) { + pf_buffer_string(filter, "(Taking "); + lib_print_object_np(game, object); + + pf_buffer_string(filter, " from "); + lib_print_object_np(game, gs_object_parent(game, object)); + pf_buffer_string(filter, " first)\n"); + } else { + pf_buffer_string(filter, "(Picking up "); + lib_print_object_np(game, object); + pf_buffer_string(filter, " first)\n"); + } + + /* Take possession of the object. */ + gs_object_player_get(game, object); } @@ -6769,110 +6140,104 @@ lib_attempt_key_acquisition (sc_gameref_t game, sc_int object) * Attempt to unlock the referenced object. */ sc_bool -lib_cmd_unlock_object_with (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, key, openness; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "unlock", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* - * Now try to get the key from referenced text, and disambiguate as usual. - */ - if (!uip_match ("%object%", var_get_ref_text (vars), game)) - { - pf_buffer_string (filter, "What do you want to unlock that with?\n"); - return TRUE; - } - key = lib_disambiguate_object (game, "unlock that with", NULL); - if (key == -1) - return TRUE; - - /* React to the request based on openness state. */ - openness = gs_object_openness (game, object); - switch (openness) - { - case OBJ_OPEN: - case OBJ_CLOSED: - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is not locked!\n", - " are not locked!\n")); - return TRUE; - - case OBJ_LOCKED: - { - sc_vartype_t vt_key[3]; - sc_int key_index, the_key; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Key"; - key_index = prop_get_integer (bundle, "I<-sis", vt_key); - if (key_index == -1) - break; - - the_key = obj_dynamic_object (game, key_index); - if (the_key != key) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't unlock ", - "I can't unlock ", - "%player% can't unlock ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " with "); - lib_print_object_np (game, key); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - if (gs_object_position (game, key) != OBJ_HELD_PLAYER) - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - lib_print_object_np (game, key); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - gs_set_object_openness (game, object, OBJ_CLOSED); - pf_buffer_string (filter, - lib_select_response (game, - "You unlock ", - "I unlock ", - "%player% unlocks ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " with "); - lib_print_object_np (game, key); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - default: - break; - } - - /* The object isn't lockable. */ - pf_buffer_string (filter, - lib_select_response (game, - "You can't unlock ", - "I can't unlock ", - "%player% can't unlock ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; +lib_cmd_unlock_object_with(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, key, openness; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "unlock", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* + * Now try to get the key from referenced text, and disambiguate as usual. + */ + if (!uip_match("%object%", var_get_ref_text(vars), game)) { + pf_buffer_string(filter, "What do you want to unlock that with?\n"); + return TRUE; + } + key = lib_disambiguate_object(game, "unlock that with", NULL); + if (key == -1) + return TRUE; + + /* React to the request based on openness state. */ + openness = gs_object_openness(game, object); + switch (openness) { + case OBJ_OPEN: + case OBJ_CLOSED: + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is not locked!\n", + " are not locked!\n")); + return TRUE; + + case OBJ_LOCKED: { + sc_vartype_t vt_key[3]; + sc_int key_index, the_key; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Key"; + key_index = prop_get_integer(bundle, "I<-sis", vt_key); + if (key_index == -1) + break; + + the_key = obj_dynamic_object(game, key_index); + if (the_key != key) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't unlock ", + "I can't unlock ", + "%player% can't unlock ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " with "); + lib_print_object_np(game, key); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + if (gs_object_position(game, key) != OBJ_HELD_PLAYER) { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + lib_print_object_np(game, key); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + gs_set_object_openness(game, object, OBJ_CLOSED); + pf_buffer_string(filter, + lib_select_response(game, + "You unlock ", + "I unlock ", + "%player% unlocks ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " with "); + lib_print_object_np(game, key); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + default: + break; + } + + /* The object isn't lockable. */ + pf_buffer_string(filter, + lib_select_response(game, + "You can't unlock ", + "I can't unlock ", + "%player% can't unlock ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } @@ -6882,85 +6247,81 @@ lib_cmd_unlock_object_with (sc_gameref_t game) * Attempt to unlock the referenced object, automatically selecting key. */ sc_bool -lib_cmd_unlock_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, openness; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "unlock", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* React to the request based on openness state. */ - openness = gs_object_openness (game, object); - switch (openness) - { - case OBJ_OPEN: - case OBJ_CLOSED: - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is not locked!\n", - " are not locked!\n")); - return TRUE; - - case OBJ_LOCKED: - { - sc_vartype_t vt_key[3]; - sc_int key_index, key; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Key"; - key_index = prop_get_integer (bundle, "I<-sis", vt_key); - if (key_index == -1) - break; - - key = obj_dynamic_object (game, key_index); - lib_attempt_key_acquisition (game, key); - if (gs_object_position (game, key) != OBJ_HELD_PLAYER) - { - pf_buffer_string (filter, - lib_select_response (game, - "You don't have", - "I don't have", - "%player% doesn't have")); - pf_buffer_string (filter, " anything to unlock "); - lib_print_object_np (game, object); - pf_buffer_string (filter, " with!\n"); - return TRUE; - } - - gs_set_object_openness (game, object, OBJ_CLOSED); - pf_buffer_string (filter, - lib_select_response (game, - "You unlock ", - "I unlock ", - "%player% unlocks ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " with "); - lib_print_object_np (game, key); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - default: - break; - } - - /* The object isn't lockable. */ - pf_buffer_string (filter, - lib_select_response (game, - "You can't unlock ", - "I can't unlock ", - "%player% can't unlock ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; +lib_cmd_unlock_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, openness; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "unlock", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* React to the request based on openness state. */ + openness = gs_object_openness(game, object); + switch (openness) { + case OBJ_OPEN: + case OBJ_CLOSED: + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is not locked!\n", + " are not locked!\n")); + return TRUE; + + case OBJ_LOCKED: { + sc_vartype_t vt_key[3]; + sc_int key_index, key; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Key"; + key_index = prop_get_integer(bundle, "I<-sis", vt_key); + if (key_index == -1) + break; + + key = obj_dynamic_object(game, key_index); + lib_attempt_key_acquisition(game, key); + if (gs_object_position(game, key) != OBJ_HELD_PLAYER) { + pf_buffer_string(filter, + lib_select_response(game, + "You don't have", + "I don't have", + "%player% doesn't have")); + pf_buffer_string(filter, " anything to unlock "); + lib_print_object_np(game, object); + pf_buffer_string(filter, " with!\n"); + return TRUE; + } + + gs_set_object_openness(game, object, OBJ_CLOSED); + pf_buffer_string(filter, + lib_select_response(game, + "You unlock ", + "I unlock ", + "%player% unlocks ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " with "); + lib_print_object_np(game, key); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + default: + break; + } + + /* The object isn't lockable. */ + pf_buffer_string(filter, + lib_select_response(game, + "You can't unlock ", + "I can't unlock ", + "%player% can't unlock ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } @@ -6970,118 +6331,112 @@ lib_cmd_unlock_object (sc_gameref_t game) * Attempt to lock the referenced object. */ sc_bool -lib_cmd_lock_object_with (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, key, openness; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "lock", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* - * Now try to get the key from referenced text, and disambiguate as usual. - */ - if (!uip_match ("%object%", var_get_ref_text (vars), game)) - { - pf_buffer_string (filter, "What do you want to lock that with?\n"); - return TRUE; - } - key = lib_disambiguate_object (game, "lock that with", NULL); - if (key == -1) - return TRUE; - - /* React to the request based on openness state. */ - openness = gs_object_openness (game, object); - switch (openness) - { - case OBJ_OPEN: - pf_buffer_string (filter, - lib_select_response (game, - "You can't lock ", - "I can't lock ", - "%player% can't lock ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " as it is open.\n"); - return TRUE; - - case OBJ_CLOSED: - { - sc_vartype_t vt_key[3]; - sc_int key_index, the_key; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Key"; - key_index = prop_get_integer (bundle, "I<-sis", vt_key); - if (key_index == -1) - break; - - the_key = obj_dynamic_object (game, key_index); - if (the_key != key) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't lock ", - "I can't lock ", - "%player% can't lock ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " with "); - lib_print_object_np (game, key); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - if (gs_object_position (game, key) != OBJ_HELD_PLAYER) - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - lib_print_object_np (game, key); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - gs_set_object_openness (game, object, OBJ_LOCKED); - pf_buffer_string (filter, lib_select_response (game, - "You lock ", - "I lock ", - "%player% locks ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " with "); - lib_print_object_np (game, key); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - case OBJ_LOCKED: - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is already locked!\n", - " are already locked!\n")); - return TRUE; - - default: - break; - } - - /* The object isn't lockable. */ - pf_buffer_string (filter, - lib_select_response (game, - "You can't lock ", - "I can't lock ", - "%player% can't lock ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; +lib_cmd_lock_object_with(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, key, openness; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "lock", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* + * Now try to get the key from referenced text, and disambiguate as usual. + */ + if (!uip_match("%object%", var_get_ref_text(vars), game)) { + pf_buffer_string(filter, "What do you want to lock that with?\n"); + return TRUE; + } + key = lib_disambiguate_object(game, "lock that with", NULL); + if (key == -1) + return TRUE; + + /* React to the request based on openness state. */ + openness = gs_object_openness(game, object); + switch (openness) { + case OBJ_OPEN: + pf_buffer_string(filter, + lib_select_response(game, + "You can't lock ", + "I can't lock ", + "%player% can't lock ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " as it is open.\n"); + return TRUE; + + case OBJ_CLOSED: { + sc_vartype_t vt_key[3]; + sc_int key_index, the_key; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Key"; + key_index = prop_get_integer(bundle, "I<-sis", vt_key); + if (key_index == -1) + break; + + the_key = obj_dynamic_object(game, key_index); + if (the_key != key) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't lock ", + "I can't lock ", + "%player% can't lock ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " with "); + lib_print_object_np(game, key); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + if (gs_object_position(game, key) != OBJ_HELD_PLAYER) { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + lib_print_object_np(game, key); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + gs_set_object_openness(game, object, OBJ_LOCKED); + pf_buffer_string(filter, lib_select_response(game, + "You lock ", + "I lock ", + "%player% locks ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " with "); + lib_print_object_np(game, key); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + case OBJ_LOCKED: + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is already locked!\n", + " are already locked!\n")); + return TRUE; + + default: + break; + } + + /* The object isn't lockable. */ + pf_buffer_string(filter, + lib_select_response(game, + "You can't lock ", + "I can't lock ", + "%player% can't lock ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } @@ -7091,94 +6446,90 @@ lib_cmd_lock_object_with (sc_gameref_t game) * Attempt to lock the referenced object, automatically selecting key. */ sc_bool -lib_cmd_lock_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, openness; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "lock", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* React to the request based on openness state. */ - openness = gs_object_openness (game, object); - switch (openness) - { - case OBJ_OPEN: - pf_buffer_string (filter, - lib_select_response (game, - "You can't lock ", - "I can't lock ", - "%player% can't lock ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " as it is open.\n"); - return TRUE; - - case OBJ_CLOSED: - { - sc_vartype_t vt_key[3]; - sc_int key_index, key; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Key"; - key_index = prop_get_integer (bundle, "I<-sis", vt_key); - if (key_index == -1) - break; - - key = obj_dynamic_object (game, key_index); - lib_attempt_key_acquisition (game, key); - if (gs_object_position (game, key) != OBJ_HELD_PLAYER) - { - pf_buffer_string (filter, - lib_select_response (game, - "You don't have", - "I don't have", - "%player% doesn't have")); - pf_buffer_string (filter, " anything to lock "); - lib_print_object_np (game, object); - pf_buffer_string (filter, " with!\n"); - return TRUE; - } - - gs_set_object_openness (game, object, OBJ_LOCKED); - pf_buffer_string (filter, - lib_select_response (game, - "You lock ", - "I lock ", - "%player% locks ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, " with "); - lib_print_object_np (game, key); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - case OBJ_LOCKED: - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is already locked!\n", - " are already locked!\n")); - return TRUE; - - default: - break; - } - - /* The object isn't lockable. */ - pf_buffer_string (filter, - lib_select_response (game, - "You can't lock ", - "I can't lock ", - "%player% can't lock ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; +lib_cmd_lock_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, openness; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "lock", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* React to the request based on openness state. */ + openness = gs_object_openness(game, object); + switch (openness) { + case OBJ_OPEN: + pf_buffer_string(filter, + lib_select_response(game, + "You can't lock ", + "I can't lock ", + "%player% can't lock ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " as it is open.\n"); + return TRUE; + + case OBJ_CLOSED: { + sc_vartype_t vt_key[3]; + sc_int key_index, key; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Key"; + key_index = prop_get_integer(bundle, "I<-sis", vt_key); + if (key_index == -1) + break; + + key = obj_dynamic_object(game, key_index); + lib_attempt_key_acquisition(game, key); + if (gs_object_position(game, key) != OBJ_HELD_PLAYER) { + pf_buffer_string(filter, + lib_select_response(game, + "You don't have", + "I don't have", + "%player% doesn't have")); + pf_buffer_string(filter, " anything to lock "); + lib_print_object_np(game, object); + pf_buffer_string(filter, " with!\n"); + return TRUE; + } + + gs_set_object_openness(game, object, OBJ_LOCKED); + pf_buffer_string(filter, + lib_select_response(game, + "You lock ", + "I lock ", + "%player% locks ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, " with "); + lib_print_object_np(game, key); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + case OBJ_LOCKED: + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is already locked!\n", + " are already locked!\n")); + return TRUE; + + default: + break; + } + + /* The object isn't lockable. */ + pf_buffer_string(filter, + lib_select_response(game, + "You can't lock ", + "I can't lock ", + "%player% can't lock ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } @@ -7188,58 +6539,55 @@ lib_cmd_lock_object (sc_gameref_t game) * Compare a subject, comma or NUL terminated. Helper for ask. */ static sc_bool -lib_compare_subject (const sc_char *subject, sc_int posn, - const sc_char *string) -{ - sc_int word_posn, string_posn; - - /* Skip any leading subject spaces. */ - for (word_posn = posn; - subject[word_posn] != NUL && sc_isspace (subject[word_posn]);) - word_posn++; - for (string_posn = 0; - string[string_posn] != NUL && sc_isspace (string[string_posn]);) - string_posn++; - - /* Match characters from words with the string at position. */ - while (TRUE) - { - /* Any character mismatch means no match. */ - if (sc_tolower (subject[word_posn]) != sc_tolower (string[string_posn])) - return FALSE; - - /* Move to next character in each. */ - word_posn++; - string_posn++; - - /* - * If at space, advance over whitespace in subjects list. Stop when we - * hit the end of the element or list. - */ - while (sc_isspace (subject[word_posn]) - && subject[word_posn] != COMMA && subject[word_posn] != NUL) - subject++; - - /* Advance over whitespace in the current string too. */ - while (sc_isspace (string[string_posn]) && string[string_posn] != NUL) - string_posn++; - - /* - * If we found the end of the subject, and the end of the current string, - * we've matched. If not at the end of the current string, though, only - * a partial match. - */ - if (subject[word_posn] == NUL || subject[word_posn] == COMMA) - { - if (string[string_posn] == NUL) - break; - else - return FALSE; - } - } - - /* Matched in the loop; return TRUE. */ - return TRUE; +lib_compare_subject(const sc_char *subject, sc_int posn, + const sc_char *string) { + sc_int word_posn, string_posn; + + /* Skip any leading subject spaces. */ + for (word_posn = posn; + subject[word_posn] != NUL && sc_isspace(subject[word_posn]);) + word_posn++; + for (string_posn = 0; + string[string_posn] != NUL && sc_isspace(string[string_posn]);) + string_posn++; + + /* Match characters from words with the string at position. */ + while (TRUE) { + /* Any character mismatch means no match. */ + if (sc_tolower(subject[word_posn]) != sc_tolower(string[string_posn])) + return FALSE; + + /* Move to next character in each. */ + word_posn++; + string_posn++; + + /* + * If at space, advance over whitespace in subjects list. Stop when we + * hit the end of the element or list. + */ + while (sc_isspace(subject[word_posn]) + && subject[word_posn] != COMMA && subject[word_posn] != NUL) + subject++; + + /* Advance over whitespace in the current string too. */ + while (sc_isspace(string[string_posn]) && string[string_posn] != NUL) + string_posn++; + + /* + * If we found the end of the subject, and the end of the current string, + * we've matched. If not at the end of the current string, though, only + * a partial match. + */ + if (subject[word_posn] == NUL || subject[word_posn] == COMMA) { + if (string[string_posn] == NUL) + break; + else + return FALSE; + } + } + + /* Matched in the loop; return TRUE. */ + return TRUE; } @@ -7249,37 +6597,35 @@ lib_compare_subject (const sc_char *subject, sc_int posn, * Reply for an NPC on a given topic. Helper for ask. */ static sc_bool -lib_npc_reply_to (sc_gameref_t game, sc_int npc, sc_int topic) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int task; - const sc_char *response; - - /* Find any associated task to control response. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Topics"; - vt_key[3].integer = topic; - vt_key[4].string = "Task"; - task = prop_get_integer (bundle, "I<-sisis", vt_key); - - /* Get the response, and print if anything there. */ - if (task > 0 && gs_task_done (game, task - 1)) - vt_key[4].string = "AltReply"; - else - vt_key[4].string = "Reply"; - response = prop_get_string (bundle, "S<-sisis", vt_key); - if (!sc_strempty (response)) - { - pf_buffer_string (filter, response); - pf_buffer_character (filter, '\n'); - return TRUE; - } - - /* No response to this combination. */ - return FALSE; +lib_npc_reply_to(sc_gameref_t game, sc_int npc, sc_int topic) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int task; + const sc_char *response; + + /* Find any associated task to control response. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Topics"; + vt_key[3].integer = topic; + vt_key[4].string = "Task"; + task = prop_get_integer(bundle, "I<-sisis", vt_key); + + /* Get the response, and print if anything there. */ + if (task > 0 && gs_task_done(game, task - 1)) + vt_key[4].string = "AltReply"; + else + vt_key[4].string = "Reply"; + response = prop_get_string(bundle, "S<-sisis", vt_key); + if (!sc_strempty(response)) { + pf_buffer_string(filter, response); + pf_buffer_character(filter, '\n'); + return TRUE; + } + + /* No response to this combination. */ + return FALSE; } @@ -7289,91 +6635,86 @@ lib_npc_reply_to (sc_gameref_t game, sc_int npc, sc_int topic) * Converse with NPC. */ sc_bool -lib_cmd_ask_npc_about (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int npc, topic_count, topic, topic_match, default_topic; - sc_bool found, default_found, is_ambiguous; - - /* Get the referenced npc, and if none, consider complete. */ - npc = lib_disambiguate_npc (game, "ask", &is_ambiguous); - if (npc == -1) - return is_ambiguous; - - if (lib_trace) - sc_trace ("Library: asking NPC %ld\n", npc); - - /* Get the topics the NPC converses about. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Topics"; - topic_count = prop_get_child_count (bundle, "I<-sis", vt_key); - topic_match = default_topic = -1; - found = default_found = FALSE; - for (topic = 0; topic < topic_count; topic++) - { - const sc_char *subjects; - sc_int posn; - - /* Get subject list for this topic. */ - vt_key[3].integer = topic; - vt_key[4].string = "Subject"; - subjects = prop_get_string (bundle, "S<-sisis", vt_key); - - /* If this is the special "*" topic, note and continue. */ - if (!sc_strcasecmp (subjects, "*")) - { - if (lib_trace) - sc_trace ("Library: \"*\" is %ld\n", topic); - - default_topic = topic; - default_found = TRUE; - continue; - } - - /* Split into subjects by comma delimiter. */ - for (posn = 0; subjects[posn] != NUL;) - { - if (lib_trace) - sc_trace ("Library: subject %s[%ld]\n", subjects, posn); - - /* See if this subject matches. */ - if (lib_compare_subject (subjects, posn, var_get_ref_text (vars))) - { - if (lib_trace) - sc_trace ("Library: matched\n"); - - topic_match = topic; - found = TRUE; - break; - } - - /* Move to next subject, or end of list. */ - while (subjects[posn] != COMMA && subjects[posn] != NUL) - posn++; - if (subjects[posn] == COMMA) - posn++; - } - } - - /* Handle any matched subject first, and "*" second. */ - if (found && lib_npc_reply_to (game, npc, topic_match)) - return TRUE; - else if (default_found && lib_npc_reply_to (game, npc, default_topic)) - return TRUE; - - /* NPC has no response. */ - pf_new_sentence (filter); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, - lib_select_response (game, - " does not respond to your question.\n", - " does not respond to my question.\n", - " does not respond to %player%'s question.\n")); - return TRUE; +lib_cmd_ask_npc_about(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int npc, topic_count, topic, topic_match, default_topic; + sc_bool found, default_found, is_ambiguous; + + /* Get the referenced npc, and if none, consider complete. */ + npc = lib_disambiguate_npc(game, "ask", &is_ambiguous); + if (npc == -1) + return is_ambiguous; + + if (lib_trace) + sc_trace("Library: asking NPC %ld\n", npc); + + /* Get the topics the NPC converses about. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Topics"; + topic_count = prop_get_child_count(bundle, "I<-sis", vt_key); + topic_match = default_topic = -1; + found = default_found = FALSE; + for (topic = 0; topic < topic_count; topic++) { + const sc_char *subjects; + sc_int posn; + + /* Get subject list for this topic. */ + vt_key[3].integer = topic; + vt_key[4].string = "Subject"; + subjects = prop_get_string(bundle, "S<-sisis", vt_key); + + /* If this is the special "*" topic, note and continue. */ + if (!sc_strcasecmp(subjects, "*")) { + if (lib_trace) + sc_trace("Library: \"*\" is %ld\n", topic); + + default_topic = topic; + default_found = TRUE; + continue; + } + + /* Split into subjects by comma delimiter. */ + for (posn = 0; subjects[posn] != NUL;) { + if (lib_trace) + sc_trace("Library: subject %s[%ld]\n", subjects, posn); + + /* See if this subject matches. */ + if (lib_compare_subject(subjects, posn, var_get_ref_text(vars))) { + if (lib_trace) + sc_trace("Library: matched\n"); + + topic_match = topic; + found = TRUE; + break; + } + + /* Move to next subject, or end of list. */ + while (subjects[posn] != COMMA && subjects[posn] != NUL) + posn++; + if (subjects[posn] == COMMA) + posn++; + } + } + + /* Handle any matched subject first, and "*" second. */ + if (found && lib_npc_reply_to(game, npc, topic_match)) + return TRUE; + else if (default_found && lib_npc_reply_to(game, npc, default_topic)) + return TRUE; + + /* NPC has no response. */ + pf_new_sentence(filter); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, + lib_select_response(game, + " does not respond to your question.\n", + " does not respond to my question.\n", + " does not respond to %player%'s question.\n")); + return TRUE; } @@ -7384,49 +6725,43 @@ lib_cmd_ask_npc_about (sc_gameref_t game) * TRUE if no recursion detected. */ static sc_bool -lib_check_put_in_recursion (sc_gameref_t game, - sc_int object, sc_int container, sc_bool report) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int check; - - /* Avoid the obvious possibility of infinite recursion. */ - if (container == object) - { - if (report) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't put an object inside itself!", - "I can't put an object inside itself!", - "%player% can't put an object inside itself!")); - } - return FALSE; - } - - /* Avoid the subtle possibility of infinite recursion. */ - check = container; - while (gs_object_position (game, check) == OBJ_ON_OBJECT - || gs_object_position (game, check) == OBJ_IN_OBJECT) - { - check = gs_object_parent (game, check); - if (check == object) - { - if (report) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't put an object inside one", - "I can't put an object inside one", - "%player% can't put an object inside one")); - pf_buffer_string (filter, " it's on or in!"); - } - return FALSE; - } - } - - /* No infinite recursion detected. */ - return TRUE; +lib_check_put_in_recursion(sc_gameref_t game, + sc_int object, sc_int container, sc_bool report) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int check; + + /* Avoid the obvious possibility of infinite recursion. */ + if (container == object) { + if (report) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't put an object inside itself!", + "I can't put an object inside itself!", + "%player% can't put an object inside itself!")); + } + return FALSE; + } + + /* Avoid the subtle possibility of infinite recursion. */ + check = container; + while (gs_object_position(game, check) == OBJ_ON_OBJECT + || gs_object_position(game, check) == OBJ_IN_OBJECT) { + check = gs_object_parent(game, check); + if (check == object) { + if (report) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't put an object inside one", + "I can't put an object inside one", + "%player% can't put an object inside one")); + pf_buffer_string(filter, " it's on or in!"); + } + return FALSE; + } + } + + /* No infinite recursion detected. */ + return TRUE; } @@ -7441,269 +6776,233 @@ lib_check_put_in_recursion (sc_gameref_t game, * deemed not actionable are flagged in multiple_references. */ static void -lib_put_in_backend (sc_gameref_t game, sc_int container) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object_count, object, count, trail, capacity, maxsize; - sc_bool has_printed; - - /* - * Try game commands for all referenced objects first. If any succeed, - * remove that reference from the list. At the same time, check for and - * weed out any moves that result in infinite recursion. - */ - has_printed = FALSE; - object_count = gs_object_count (game); - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - /* Reject and remove attempts to place objects in themselves. */ - if (!lib_check_put_in_recursion (game, object, container, !has_printed)) - { - game->object_references[object] = FALSE; - has_printed = TRUE; - continue; - } - - if (lib_try_game_command_with_object (game, - "put", object, "in", container)) - { - game->object_references[object] = FALSE; - has_printed = TRUE; - } - } - - /* Retrieve the container's limits. */ - maxsize = obj_get_container_maxsize (game, container); - capacity = obj_get_container_capacity (game, container); - - /* Put in every object that remains referenced. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - /* If too big, or exceeds container limits, ignore for now. */ - if (obj_get_size (game, object) > maxsize) - continue; - else - { - sc_int other, contains; - - contains = 0; - for (other = 0; other < gs_object_count (game); other++) - { - if (gs_object_position (game, other) == OBJ_IN_OBJECT - && gs_object_parent (game, other) == container) - contains++; - } - if (contains >= capacity) - continue; - } - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You put ", - "I put ", - "%player% puts ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - gs_object_move_into (game, object, container); - game->object_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You put ", - "I put ", - "%player% puts ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_string (filter, " inside "); - lib_print_object_np (game, container); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - - /* - * Report objects not put in because of their size. These objects remain in - * standard references, as do objects rejected because of capacity limits. - * By removing too large objects in this loop, we're left later on with just - * the objects rejected by capacity limits. - */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (!(obj_get_size (game, object) > maxsize)) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, trail); - } - else - pf_buffer_string (filter, ", "); - } - trail = object; - count++; - - game->object_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, trail); - pf_buffer_string (filter, - lib_select_plurality (game, trail, - " is too big", - " are too big")); - } - else - { - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_string (filter, " are too big"); - } - pf_buffer_string (filter, " to fit inside "); - lib_print_object_np (game, container); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - - /* - * Report objects not put in because the container is too full. This should - * be all remaining objects in standard references. - */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->object_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_new_sentence (filter); - lib_print_object_np (game, trail); - } - else - { - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - } - pf_buffer_string (filter, " can't fit inside "); - lib_print_object_np (game, container); - pf_buffer_string (filter, " at the moment."); - } - has_printed |= count > 0; - - /* Note any remaining multiple references left out of the operation. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - } - else - pf_buffer_string (filter, " or "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } +lib_put_in_backend(sc_gameref_t game, sc_int container) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object_count, object, count, trail, capacity, maxsize; + sc_bool has_printed; + + /* + * Try game commands for all referenced objects first. If any succeed, + * remove that reference from the list. At the same time, check for and + * weed out any moves that result in infinite recursion. + */ + has_printed = FALSE; + object_count = gs_object_count(game); + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + /* Reject and remove attempts to place objects in themselves. */ + if (!lib_check_put_in_recursion(game, object, container, !has_printed)) { + game->object_references[object] = FALSE; + has_printed = TRUE; + continue; + } + + if (lib_try_game_command_with_object(game, + "put", object, "in", container)) { + game->object_references[object] = FALSE; + has_printed = TRUE; + } + } + + /* Retrieve the container's limits. */ + maxsize = obj_get_container_maxsize(game, container); + capacity = obj_get_container_capacity(game, container); + + /* Put in every object that remains referenced. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + /* If too big, or exceeds container limits, ignore for now. */ + if (obj_get_size(game, object) > maxsize) + continue; + else { + sc_int other, contains; + + contains = 0; + for (other = 0; other < gs_object_count(game); other++) { + if (gs_object_position(game, other) == OBJ_IN_OBJECT + && gs_object_parent(game, other) == container) + contains++; + } + if (contains >= capacity) + continue; + } + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You put ", + "I put ", + "%player% puts ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + gs_object_move_into(game, object, container); + game->object_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You put ", + "I put ", + "%player% puts ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_string(filter, " inside "); + lib_print_object_np(game, container); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + + /* + * Report objects not put in because of their size. These objects remain in + * standard references, as do objects rejected because of capacity limits. + * By removing too large objects in this loop, we're left later on with just + * the objects rejected by capacity limits. + */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (!(obj_get_size(game, object) > maxsize)) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, trail); + } else + pf_buffer_string(filter, ", "); + } + trail = object; + count++; + + game->object_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, trail); + pf_buffer_string(filter, + lib_select_plurality(game, trail, + " is too big", + " are too big")); + } else { + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_string(filter, " are too big"); + } + pf_buffer_string(filter, " to fit inside "); + lib_print_object_np(game, container); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + + /* + * Report objects not put in because the container is too full. This should + * be all remaining objects in standard references. + */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->object_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_new_sentence(filter); + lib_print_object_np(game, trail); + } else { + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + } + pf_buffer_string(filter, " can't fit inside "); + lib_print_object_np(game, container); + pf_buffer_string(filter, " at the moment."); + } + has_printed |= count > 0; + + /* Note any remaining multiple references left out of the operation. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + } else + pf_buffer_string(filter, " or "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } } @@ -7715,19 +7014,17 @@ lib_put_in_backend (sc_gameref_t game, sc_int container) * context. Returns TRUE if an object may be manipulated, FALSE otherwise. */ static sc_bool -lib_put_in_filter (sc_gameref_t game, sc_int object, sc_int unused) -{ - assert (unused == -1); +lib_put_in_filter(sc_gameref_t game, sc_int object, sc_int unused) { + assert(unused == -1); - return !obj_is_static (game, object) - && gs_object_position (game, object) == OBJ_HELD_PLAYER; + return !obj_is_static(game, object) + && gs_object_position(game, object) == OBJ_HELD_PLAYER; } static sc_bool -lib_put_in_not_container_filter (sc_gameref_t game, - sc_int object, sc_int container) -{ - return lib_put_in_filter (game, object, -1) && object != container; +lib_put_in_not_container_filter(sc_gameref_t game, + sc_int object, sc_int container) { + return lib_put_in_filter(game, object, -1) && object != container; } @@ -7737,39 +7034,36 @@ lib_put_in_not_container_filter (sc_gameref_t game, * Validate the container requested in "put in" commands. */ static sc_bool -lib_put_in_is_valid (sc_gameref_t game, sc_int container) -{ - const sc_filterref_t filter = gs_get_filter (game); - - /* Verify that the container object is a container. */ - if (!obj_is_container (game, container)) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't put anything inside ", - "I can't put anything inside ", - "%player% can't put anything inside ")); - lib_print_object_np (game, container); - pf_buffer_string (filter, "!\n"); - return FALSE; - } - - /* If the container is closed, reject now. */ - if (gs_object_openness (game, container) > OBJ_OPEN) - { - pf_new_sentence (filter); - lib_print_object_np (game, container); - pf_buffer_string (filter, - lib_select_plurality (game, container, " is", " are")); - if (gs_object_openness (game, container) == OBJ_LOCKED) - pf_buffer_string (filter, " locked!\n"); - else - pf_buffer_string (filter, " closed!\n"); - return FALSE; - } - - /* Container is a valid target for "put in". */ - return TRUE; +lib_put_in_is_valid(sc_gameref_t game, sc_int container) { + const sc_filterref_t filter = gs_get_filter(game); + + /* Verify that the container object is a container. */ + if (!obj_is_container(game, container)) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't put anything inside ", + "I can't put anything inside ", + "%player% can't put anything inside ")); + lib_print_object_np(game, container); + pf_buffer_string(filter, "!\n"); + return FALSE; + } + + /* If the container is closed, reject now. */ + if (gs_object_openness(game, container) > OBJ_OPEN) { + pf_new_sentence(filter); + lib_print_object_np(game, container); + pf_buffer_string(filter, + lib_select_plurality(game, container, " is", " are")); + if (gs_object_openness(game, container) == OBJ_LOCKED) + pf_buffer_string(filter, " locked!\n"); + else + pf_buffer_string(filter, " closed!\n"); + return FALSE; + } + + /* Container is a valid target for "put in". */ + return TRUE; } @@ -7779,43 +7073,41 @@ lib_put_in_is_valid (sc_gameref_t game, sc_int container) * Put all objects currently held by the player into a container. */ sc_bool -lib_cmd_put_all_in (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int container, objects; - sc_bool is_ambiguous; +lib_cmd_put_all_in(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int container, objects; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - container = lib_disambiguate_object (game, "put that into", &is_ambiguous); - if (container == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + container = lib_disambiguate_object(game, "put that into", &is_ambiguous); + if (container == -1) + return is_ambiguous; - /* Validate the container object to take from. */ - if (!lib_put_in_is_valid (game, container)) - return TRUE; + /* Validate the container object to take from. */ + if (!lib_put_in_is_valid(game, container)) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - gs_set_multiple_references (game); - objects = lib_apply_multiple_filter (game, - lib_put_in_not_container_filter, - container, NULL); - gs_clear_multiple_references (game); - if (objects > 0) - lib_put_in_backend (game, container); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You're not carrying anything", - "I'm not carrying anything", - "%player%'s not carrying anything")); - if (obj_indirectly_held_by_player (game, container)) - pf_buffer_string (filter, " else"); - pf_buffer_character (filter, '.'); - } + /* Filter objects into references, then handle with the backend. */ + gs_set_multiple_references(game); + objects = lib_apply_multiple_filter(game, + lib_put_in_not_container_filter, + container, NULL); + gs_clear_multiple_references(game); + if (objects > 0) + lib_put_in_backend(game, container); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You're not carrying anything", + "I'm not carrying anything", + "%player%'s not carrying anything")); + if (obj_indirectly_held_by_player(game, container)) + pf_buffer_string(filter, " else"); + pf_buffer_character(filter, '.'); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -7826,59 +7118,56 @@ lib_cmd_put_all_in (sc_gameref_t game) * those listed in %text%. */ sc_bool -lib_cmd_put_in_except_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int container, objects, references; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - container = lib_disambiguate_object (game, "put that into", &is_ambiguous); - if (container == -1) - return is_ambiguous; - - /* Parse the multiple objects list to find retain target objects. */ - if (!lib_parse_multiple_objects (game, "retain", - lib_put_in_not_container_filter, - container, &references)) - return FALSE; - else if (references == 0) - return TRUE; - - /* Validate the container object to put into. */ - if (!lib_put_in_is_valid (game, container)) - return TRUE; - - /* As a special case, complain about requests to retain the container. */ - if (game->multiple_references[container]) - { - pf_buffer_string (filter, - "I only understood you as far as wanting to retain "); - lib_print_object_np (game, container); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_except_filter (game, - lib_put_in_not_container_filter, - container, &references); - if (objects > 0 || references > 0) - lib_put_in_backend (game, container); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything", - "I am not holding anything", - "%player% is not holding anything")); - if (objects == 0) - pf_buffer_string (filter, " else"); - pf_buffer_character (filter, '.'); - } - - pf_buffer_character (filter, '\n'); - return TRUE; +lib_cmd_put_in_except_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int container, objects, references; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + container = lib_disambiguate_object(game, "put that into", &is_ambiguous); + if (container == -1) + return is_ambiguous; + + /* Parse the multiple objects list to find retain target objects. */ + if (!lib_parse_multiple_objects(game, "retain", + lib_put_in_not_container_filter, + container, &references)) + return FALSE; + else if (references == 0) + return TRUE; + + /* Validate the container object to put into. */ + if (!lib_put_in_is_valid(game, container)) + return TRUE; + + /* As a special case, complain about requests to retain the container. */ + if (game->multiple_references[container]) { + pf_buffer_string(filter, + "I only understood you as far as wanting to retain "); + lib_print_object_np(game, container); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_except_filter(game, + lib_put_in_not_container_filter, + container, &references); + if (objects > 0 || references > 0) + lib_put_in_backend(game, container); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything", + "I am not holding anything", + "%player% is not holding anything")); + if (objects == 0) + pf_buffer_string(filter, " else"); + pf_buffer_character(filter, '.'); + } + + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -7889,46 +7178,44 @@ lib_cmd_put_in_except_multiple (sc_gameref_t game) * object. */ sc_bool -lib_cmd_put_in_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int container, objects, references; - sc_bool is_ambiguous; +lib_cmd_put_in_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int container, objects, references; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - container = lib_disambiguate_object (game, "put that into", &is_ambiguous); - if (container == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + container = lib_disambiguate_object(game, "put that into", &is_ambiguous); + if (container == -1) + return is_ambiguous; - /* Parse the multiple objects list to find retain target objects. */ - if (!lib_parse_multiple_objects (game, "move", - lib_put_in_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find retain target objects. */ + if (!lib_parse_multiple_objects(game, "move", + lib_put_in_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Validate the container object to put into. */ - if (!lib_put_in_is_valid (game, container)) - return TRUE; + /* Validate the container object to put into. */ + if (!lib_put_in_is_valid(game, container)) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_multiple_filter (game, - lib_put_in_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_put_in_backend (game, container); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything.", - "I am not holding anything.", - "%player% is not holding anything.")); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_multiple_filter(game, + lib_put_in_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_put_in_backend(game, container); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything.", + "I am not holding anything.", + "%player% is not holding anything.")); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -7939,49 +7226,43 @@ lib_cmd_put_in_multiple (sc_gameref_t game) * TRUE if no recursion detected. */ static sc_bool -lib_check_put_on_recursion (sc_gameref_t game, - sc_int object, sc_int supporter, sc_bool report) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int check; - - /* Avoid the obvious possibility of infinite recursion. */ - if (supporter == object) - { - if (report) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't put an object onto itself!", - "I can't put an object onto itself!", - "%player% can't put an object onto itself!")); - } - return FALSE; - } - - /* Avoid the subtle possibility of infinite recursion. */ - check = supporter; - while (gs_object_position (game, check) == OBJ_ON_OBJECT - || gs_object_position (game, check) == OBJ_IN_OBJECT) - { - check = gs_object_parent (game, check); - if (check == object) - { - if (report) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't put an object onto one", - "I can't put an object onto one", - "%player% can't put an object onto one")); - pf_buffer_string (filter, " it's on or in!"); - } - return FALSE; - } - } - - /* No infinite recursion detected. */ - return TRUE; +lib_check_put_on_recursion(sc_gameref_t game, + sc_int object, sc_int supporter, sc_bool report) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int check; + + /* Avoid the obvious possibility of infinite recursion. */ + if (supporter == object) { + if (report) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't put an object onto itself!", + "I can't put an object onto itself!", + "%player% can't put an object onto itself!")); + } + return FALSE; + } + + /* Avoid the subtle possibility of infinite recursion. */ + check = supporter; + while (gs_object_position(game, check) == OBJ_ON_OBJECT + || gs_object_position(game, check) == OBJ_IN_OBJECT) { + check = gs_object_parent(game, check); + if (check == object) { + if (report) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't put an object onto one", + "I can't put an object onto one", + "%player% can't put an object onto one")); + pf_buffer_string(filter, " it's on or in!"); + } + return FALSE; + } + } + + /* No infinite recursion detected. */ + return TRUE; } @@ -7996,138 +7277,120 @@ lib_check_put_on_recursion (sc_gameref_t game, * deemed not actionable are flagged in multiple_references. */ static void -lib_put_on_backend (sc_gameref_t game, sc_int supporter) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object_count, object, count, trail; - sc_bool has_printed; - - /* - * Try game commands for all referenced objects first. If any succeed, - * remove that reference from the list. At the same time, check for and - * weed out any moves that result in infinite recursion. - */ - has_printed = FALSE; - object_count = gs_object_count (game); - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - /* Reject and remove attempts to place objects on themselves. */ - if (!lib_check_put_on_recursion (game, object, supporter, !has_printed)) - { - game->object_references[object] = FALSE; - has_printed = TRUE; - continue; - } - - if (lib_try_game_command_with_object (game, - "put", object, "on", supporter)) - { - game->object_references[object] = FALSE; - has_printed = TRUE; - } - } - - /* Put on every object that remains referenced. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->object_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You put ", - "I put ", - "%player% puts ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - gs_object_move_onto (game, object, supporter); - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You put ", - "I put ", - "%player% puts ")); - } - else - pf_buffer_string (filter, " and "); - lib_print_object_np (game, trail); - pf_buffer_string (filter, " onto "); - lib_print_object_np (game, supporter); - pf_buffer_character (filter, '.'); - } - has_printed |= count > 0; - - /* Note any remaining multiple references left out of the operation. */ - count = 0; - trail = -1; - for (object = 0; object < object_count; object++) - { - if (!game->multiple_references[object]) - continue; - - if (count > 0) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - } - else - pf_buffer_string (filter, ", "); - lib_print_object_np (game, trail); - } - trail = object; - count++; - - game->multiple_references[object] = FALSE; - } - - if (count >= 1) - { - if (count == 1) - { - if (has_printed) - pf_buffer_string (filter, " "); - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - } - else - pf_buffer_string (filter, " or "); - lib_print_object_np (game, trail); - pf_buffer_character (filter, '.'); - } +lib_put_on_backend(sc_gameref_t game, sc_int supporter) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object_count, object, count, trail; + sc_bool has_printed; + + /* + * Try game commands for all referenced objects first. If any succeed, + * remove that reference from the list. At the same time, check for and + * weed out any moves that result in infinite recursion. + */ + has_printed = FALSE; + object_count = gs_object_count(game); + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + /* Reject and remove attempts to place objects on themselves. */ + if (!lib_check_put_on_recursion(game, object, supporter, !has_printed)) { + game->object_references[object] = FALSE; + has_printed = TRUE; + continue; + } + + if (lib_try_game_command_with_object(game, + "put", object, "on", supporter)) { + game->object_references[object] = FALSE; + has_printed = TRUE; + } + } + + /* Put on every object that remains referenced. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->object_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You put ", + "I put ", + "%player% puts ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + gs_object_move_onto(game, object, supporter); + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You put ", + "I put ", + "%player% puts ")); + } else + pf_buffer_string(filter, " and "); + lib_print_object_np(game, trail); + pf_buffer_string(filter, " onto "); + lib_print_object_np(game, supporter); + pf_buffer_character(filter, '.'); + } + has_printed |= count > 0; + + /* Note any remaining multiple references left out of the operation. */ + count = 0; + trail = -1; + for (object = 0; object < object_count; object++) { + if (!game->multiple_references[object]) + continue; + + if (count > 0) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + } else + pf_buffer_string(filter, ", "); + lib_print_object_np(game, trail); + } + trail = object; + count++; + + game->multiple_references[object] = FALSE; + } + + if (count >= 1) { + if (count == 1) { + if (has_printed) + pf_buffer_string(filter, " "); + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + } else + pf_buffer_string(filter, " or "); + lib_print_object_np(game, trail); + pf_buffer_character(filter, '.'); + } } @@ -8139,19 +7402,17 @@ lib_put_on_backend (sc_gameref_t game, sc_int supporter) * context. Returns TRUE if an object may be manipulated, FALSE otherwise. */ static sc_bool -lib_put_on_filter (sc_gameref_t game, sc_int object, sc_int unused) -{ - assert (unused == -1); +lib_put_on_filter(sc_gameref_t game, sc_int object, sc_int unused) { + assert(unused == -1); - return !obj_is_static (game, object) - && gs_object_position (game, object) == OBJ_HELD_PLAYER; + return !obj_is_static(game, object) + && gs_object_position(game, object) == OBJ_HELD_PLAYER; } static sc_bool -lib_put_on_not_supporter_filter (sc_gameref_t game, - sc_int object, sc_int supporter) -{ - return lib_put_on_filter (game, object, -1) && object != supporter; +lib_put_on_not_supporter_filter(sc_gameref_t game, + sc_int object, sc_int supporter) { + return lib_put_on_filter(game, object, -1) && object != supporter; } @@ -8161,25 +7422,23 @@ lib_put_on_not_supporter_filter (sc_gameref_t game, * Validate the supporter requested in "put on" commands. */ static sc_bool -lib_put_on_is_valid (sc_gameref_t game, sc_int supporter) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_put_on_is_valid(sc_gameref_t game, sc_int supporter) { + const sc_filterref_t filter = gs_get_filter(game); - /* Verify that the supporter object is a supporter. */ - if (!obj_is_surface (game, supporter)) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't put anything on ", - "I can't put anything on ", - "%player% can't put anything on ")); - lib_print_object_np (game, supporter); - pf_buffer_string (filter, "!\n"); - return FALSE; - } + /* Verify that the supporter object is a supporter. */ + if (!obj_is_surface(game, supporter)) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't put anything on ", + "I can't put anything on ", + "%player% can't put anything on ")); + lib_print_object_np(game, supporter); + pf_buffer_string(filter, "!\n"); + return FALSE; + } - /* Surface is a valid target for "put on". */ - return TRUE; + /* Surface is a valid target for "put on". */ + return TRUE; } @@ -8189,43 +7448,41 @@ lib_put_on_is_valid (sc_gameref_t game, sc_int supporter) * Put all objects currently held by the player onto a supporter. */ sc_bool -lib_cmd_put_all_on (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int supporter, objects; - sc_bool is_ambiguous; +lib_cmd_put_all_on(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int supporter, objects; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - supporter = lib_disambiguate_object (game, "put that onto", &is_ambiguous); - if (supporter == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + supporter = lib_disambiguate_object(game, "put that onto", &is_ambiguous); + if (supporter == -1) + return is_ambiguous; - /* Validate the supporter object to take from. */ - if (!lib_put_on_is_valid (game, supporter)) - return TRUE; + /* Validate the supporter object to take from. */ + if (!lib_put_on_is_valid(game, supporter)) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - gs_set_multiple_references (game); - objects = lib_apply_multiple_filter (game, - lib_put_on_not_supporter_filter, - supporter, NULL); - gs_clear_multiple_references (game); - if (objects > 0) - lib_put_on_backend (game, supporter); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You're not carrying anything", - "I'm not carrying anything", - "%player%'s not carrying anything")); - if (obj_indirectly_held_by_player (game, supporter)) - pf_buffer_string (filter, " else"); - pf_buffer_character (filter, '.'); - } + /* Filter objects into references, then handle with the backend. */ + gs_set_multiple_references(game); + objects = lib_apply_multiple_filter(game, + lib_put_on_not_supporter_filter, + supporter, NULL); + gs_clear_multiple_references(game); + if (objects > 0) + lib_put_on_backend(game, supporter); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You're not carrying anything", + "I'm not carrying anything", + "%player%'s not carrying anything")); + if (obj_indirectly_held_by_player(game, supporter)) + pf_buffer_string(filter, " else"); + pf_buffer_character(filter, '.'); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -8236,59 +7493,56 @@ lib_cmd_put_all_on (sc_gameref_t game) * those listed in %text%. */ sc_bool -lib_cmd_put_on_except_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int supporter, objects, references; - sc_bool is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - supporter = lib_disambiguate_object (game, "put that onto", &is_ambiguous); - if (supporter == -1) - return is_ambiguous; - - /* Parse the multiple objects list to find retain target objects. */ - if (!lib_parse_multiple_objects (game, "retain", - lib_put_on_not_supporter_filter, - supporter, &references)) - return FALSE; - else if (references == 0) - return TRUE; - - /* Validate the supporter object to put into. */ - if (!lib_put_on_is_valid (game, supporter)) - return TRUE; - - /* As a special case, complain about requests to retain the supporter. */ - if (game->multiple_references[supporter]) - { - pf_buffer_string (filter, - "I only understood you as far as wanting to retain "); - lib_print_object_np (game, supporter); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_except_filter (game, - lib_put_on_not_supporter_filter, - supporter, &references); - if (objects > 0 || references > 0) - lib_put_on_backend (game, supporter); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything", - "I am not holding anything", - "%player% is not holding anything")); - if (objects == 0) - pf_buffer_string (filter, " else"); - pf_buffer_character (filter, '.'); - } - - pf_buffer_character (filter, '\n'); - return TRUE; +lib_cmd_put_on_except_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int supporter, objects, references; + sc_bool is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + supporter = lib_disambiguate_object(game, "put that onto", &is_ambiguous); + if (supporter == -1) + return is_ambiguous; + + /* Parse the multiple objects list to find retain target objects. */ + if (!lib_parse_multiple_objects(game, "retain", + lib_put_on_not_supporter_filter, + supporter, &references)) + return FALSE; + else if (references == 0) + return TRUE; + + /* Validate the supporter object to put into. */ + if (!lib_put_on_is_valid(game, supporter)) + return TRUE; + + /* As a special case, complain about requests to retain the supporter. */ + if (game->multiple_references[supporter]) { + pf_buffer_string(filter, + "I only understood you as far as wanting to retain "); + lib_print_object_np(game, supporter); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_except_filter(game, + lib_put_on_not_supporter_filter, + supporter, &references); + if (objects > 0 || references > 0) + lib_put_on_backend(game, supporter); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything", + "I am not holding anything", + "%player% is not holding anything")); + if (objects == 0) + pf_buffer_string(filter, " else"); + pf_buffer_character(filter, '.'); + } + + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -8299,46 +7553,44 @@ lib_cmd_put_on_except_multiple (sc_gameref_t game) * object. */ sc_bool -lib_cmd_put_on_multiple (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int supporter, objects, references; - sc_bool is_ambiguous; +lib_cmd_put_on_multiple(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int supporter, objects, references; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - supporter = lib_disambiguate_object (game, "put that onto", &is_ambiguous); - if (supporter == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + supporter = lib_disambiguate_object(game, "put that onto", &is_ambiguous); + if (supporter == -1) + return is_ambiguous; - /* Parse the multiple objects list to find retain target objects. */ - if (!lib_parse_multiple_objects (game, "move", - lib_put_on_filter, -1, - &references)) - return FALSE; - else if (references == 0) - return TRUE; + /* Parse the multiple objects list to find retain target objects. */ + if (!lib_parse_multiple_objects(game, "move", + lib_put_on_filter, -1, + &references)) + return FALSE; + else if (references == 0) + return TRUE; - /* Validate the supporter object to put into. */ - if (!lib_put_on_is_valid (game, supporter)) - return TRUE; + /* Validate the supporter object to put into. */ + if (!lib_put_on_is_valid(game, supporter)) + return TRUE; - /* Filter objects into references, then handle with the backend. */ - objects = lib_apply_multiple_filter (game, - lib_put_on_filter, -1, - &references); - if (objects > 0 || references > 0) - lib_put_on_backend (game, supporter); - else - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding anything.", - "I am not holding anything.", - "%player% is not holding anything.")); - } + /* Filter objects into references, then handle with the backend. */ + objects = lib_apply_multiple_filter(game, + lib_put_on_filter, -1, + &references); + if (objects > 0 || references > 0) + lib_put_on_backend(game, supporter); + else { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding anything.", + "I am not holding anything.", + "%player% is not holding anything.")); + } - pf_buffer_character (filter, '\n'); - return TRUE; + pf_buffer_character(filter, '\n'); + return TRUE; } @@ -8349,84 +7601,79 @@ lib_cmd_put_on_multiple (sc_gameref_t game) * Attempt to read the referenced object, or something else. */ sc_bool -lib_cmd_read_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int object, task; - sc_bool is_readable, is_ambiguous; - const sc_char *readtext, *description; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "read", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Verify that the object is readable. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Readable"; - is_readable = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!is_readable) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't read ", - "I can't read ", - "%player% can't read ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, "!\n"); - return TRUE; - } - - /* Get and print the object's read text, if any. */ - vt_key[2].string = "ReadText"; - readtext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (readtext)) - { - pf_buffer_string (filter, readtext); - pf_buffer_character (filter, '\n'); - return TRUE; - } - - /* Degrade to a shortened object examine. */ - vt_key[2].string = "Task"; - task = prop_get_integer (bundle, "I<-sis", vt_key) - 1; - - /* Select either the main or the alternate description. */ - if (task >= 0 && gs_task_done (game, task)) - vt_key[2].string = "AltDesc"; - else - vt_key[2].string = "Description"; - - /* Print the description, or a "nothing special" default. */ - description = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (description)) - pf_buffer_string (filter, description); - else - { - pf_buffer_string (filter, "There is nothing special about "); - lib_print_object_np (game, object); - pf_buffer_character (filter, '.'); - } - - pf_buffer_character (filter, '\n'); - return TRUE; -} - -sc_bool -lib_cmd_read_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - - /* Reject the attempt. */ - pf_buffer_string (filter, - lib_select_response (game, - "You see no such thing.\n", - "I see no such thing.\n", - "%player% sees no such thing.\n")); - return TRUE; +lib_cmd_read_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int object, task; + sc_bool is_readable, is_ambiguous; + const sc_char *readtext, *description; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "read", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Verify that the object is readable. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Readable"; + is_readable = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!is_readable) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't read ", + "I can't read ", + "%player% can't read ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, "!\n"); + return TRUE; + } + + /* Get and print the object's read text, if any. */ + vt_key[2].string = "ReadText"; + readtext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(readtext)) { + pf_buffer_string(filter, readtext); + pf_buffer_character(filter, '\n'); + return TRUE; + } + + /* Degrade to a shortened object examine. */ + vt_key[2].string = "Task"; + task = prop_get_integer(bundle, "I<-sis", vt_key) - 1; + + /* Select either the main or the alternate description. */ + if (task >= 0 && gs_task_done(game, task)) + vt_key[2].string = "AltDesc"; + else + vt_key[2].string = "Description"; + + /* Print the description, or a "nothing special" default. */ + description = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(description)) + pf_buffer_string(filter, description); + else { + pf_buffer_string(filter, "There is nothing special about "); + lib_print_object_np(game, object); + pf_buffer_character(filter, '.'); + } + + pf_buffer_character(filter, '\n'); + return TRUE; +} + +sc_bool +lib_cmd_read_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + + /* Reject the attempt. */ + pf_buffer_string(filter, + lib_select_response(game, + "You see no such thing.\n", + "I see no such thing.\n", + "%player% sees no such thing.\n")); + return TRUE; } @@ -8437,103 +7684,96 @@ lib_cmd_read_other (sc_gameref_t game) * Attempt to attack an NPC, with and without weaponry. */ sc_bool -lib_cmd_attack_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int npc; - sc_bool is_ambiguous; - - /* Get the referenced npc, and if none, consider complete. */ - npc = lib_disambiguate_npc (game, "attack", &is_ambiguous); - if (npc == -1) - return is_ambiguous; - - /* Print a standard response. */ - pf_new_sentence (filter); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, - lib_select_response (game, - " avoids your feeble attempts.\n", - " avoids my feeble attempts.\n", - " avoids %player%'s feeble attempts.\n")); - return TRUE; -} - -sc_bool -lib_cmd_attack_npc_with (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, npc; - sc_vartype_t vt_key[3]; - sc_bool weapon, is_ambiguous; - - /* Get the referenced npc, and if none, consider complete. */ - npc = lib_disambiguate_npc (game, "attack", &is_ambiguous); - if (npc == -1) - return is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "attack with", NULL); - if (object == -1) - return TRUE; - - /* Ensure the referenced object is held. */ - if (gs_object_position (game, object) != OBJ_HELD_PLAYER) - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - /* Check for static object moved to player by event. */ - if (obj_is_static (game, object)) - { - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, " is", " are")); - pf_buffer_string (filter, " not a weapon.\n"); - return TRUE; - } - - /* Print standard response depending on if the object is a weapon. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Weapon"; - weapon = prop_get_boolean (bundle, "B<-sis", vt_key); - if (weapon) - { - pf_buffer_string (filter, - lib_select_response (game, - "You swing at ", - "I swing at ", - "%player% swings at ")); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " with "); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_response (game, - " but you miss.\n", - " but I miss.\n", - " but misses.\n")); - } - else - { - /* - * TODO Adrift uses "affective" [sic] here. Should SCARE be right, or - * bug-compatible? - */ - pf_buffer_string (filter, "I don't think "); - lib_print_object_np (game, object); - pf_buffer_string (filter, " would be a very effective weapon.\n"); - } - return TRUE; +lib_cmd_attack_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int npc; + sc_bool is_ambiguous; + + /* Get the referenced npc, and if none, consider complete. */ + npc = lib_disambiguate_npc(game, "attack", &is_ambiguous); + if (npc == -1) + return is_ambiguous; + + /* Print a standard response. */ + pf_new_sentence(filter); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, + lib_select_response(game, + " avoids your feeble attempts.\n", + " avoids my feeble attempts.\n", + " avoids %player%'s feeble attempts.\n")); + return TRUE; +} + +sc_bool +lib_cmd_attack_npc_with(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, npc; + sc_vartype_t vt_key[3]; + sc_bool weapon, is_ambiguous; + + /* Get the referenced npc, and if none, consider complete. */ + npc = lib_disambiguate_npc(game, "attack", &is_ambiguous); + if (npc == -1) + return is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "attack with", NULL); + if (object == -1) + return TRUE; + + /* Ensure the referenced object is held. */ + if (gs_object_position(game, object) != OBJ_HELD_PLAYER) { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + /* Check for static object moved to player by event. */ + if (obj_is_static(game, object)) { + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, " is", " are")); + pf_buffer_string(filter, " not a weapon.\n"); + return TRUE; + } + + /* Print standard response depending on if the object is a weapon. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Weapon"; + weapon = prop_get_boolean(bundle, "B<-sis", vt_key); + if (weapon) { + pf_buffer_string(filter, + lib_select_response(game, + "You swing at ", + "I swing at ", + "%player% swings at ")); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " with "); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_response(game, + " but you miss.\n", + " but I miss.\n", + " but misses.\n")); + } else { + /* + * TODO Adrift uses "affective" [sic] here. Should SCARE be right, or + * bug-compatible? + */ + pf_buffer_string(filter, "I don't think "); + lib_print_object_np(game, object); + pf_buffer_string(filter, " would be a very effective weapon.\n"); + } + return TRUE; } @@ -8545,72 +7785,68 @@ lib_cmd_attack_npc_with (sc_gameref_t game) * Reject romantic advances in all cases. */ sc_bool -lib_cmd_kiss_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int npc, gender; - sc_bool is_ambiguous; +lib_cmd_kiss_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int npc, gender; + sc_bool is_ambiguous; - /* Get the referenced npc, and if none, consider complete. */ - npc = lib_disambiguate_npc (game, "kiss", &is_ambiguous); - if (npc == -1) - return is_ambiguous; + /* Get the referenced npc, and if none, consider complete. */ + npc = lib_disambiguate_npc(game, "kiss", &is_ambiguous); + if (npc == -1) + return is_ambiguous; - /* Reject this attempt. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Gender"; - gender = prop_get_integer (bundle, "I<-sis", vt_key); + /* Reject this attempt. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Gender"; + gender = prop_get_integer(bundle, "I<-sis", vt_key); - switch (gender) - { - case NPC_MALE: - pf_buffer_string (filter, "I'm not sure he would appreciate that!\n"); - break; + switch (gender) { + case NPC_MALE: + pf_buffer_string(filter, "I'm not sure he would appreciate that!\n"); + break; - case NPC_FEMALE: - pf_buffer_string (filter, "I'm not sure she would appreciate that!\n"); - break; + case NPC_FEMALE: + pf_buffer_string(filter, "I'm not sure she would appreciate that!\n"); + break; - case NPC_NEUTER: - pf_buffer_string (filter, "I'm not sure it would appreciate that!\n"); - break; + case NPC_NEUTER: + pf_buffer_string(filter, "I'm not sure it would appreciate that!\n"); + break; - default: - sc_error ("lib_cmd_kiss_npc: unknown gender, %ld\n", gender); - } - return TRUE; + default: + sc_error("lib_cmd_kiss_npc: unknown gender, %ld\n", gender); + } + return TRUE; } sc_bool -lib_cmd_kiss_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; +lib_cmd_kiss_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "kiss", &is_ambiguous); - if (object == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "kiss", &is_ambiguous); + if (object == -1) + return is_ambiguous; - /* Reject this attempt. */ - pf_buffer_string (filter, "I'm not sure "); - lib_print_object_np (game, object); - pf_buffer_string (filter, " would appreciate that.\n"); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, "I'm not sure "); + lib_print_object_np(game, object); + pf_buffer_string(filter, " would appreciate that.\n"); + return TRUE; } sc_bool -lib_cmd_kiss_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_kiss_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - /* Reject this attempt. */ - pf_buffer_string (filter, "I'm not sure it would appreciate that.\n"); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, "I'm not sure it would appreciate that.\n"); + return TRUE; } @@ -8621,34 +7857,32 @@ lib_cmd_kiss_other (sc_gameref_t game) * Standard responses to attempts to buy something. */ sc_bool -lib_cmd_buy_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; +lib_cmd_buy_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "buy", &is_ambiguous); - if (object == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "buy", &is_ambiguous); + if (object == -1) + return is_ambiguous; - /* Reject this attempt. */ - pf_buffer_string (filter, "I don't think "); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, " is", " are")); - pf_buffer_string (filter, " for sale.\n"); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, "I don't think "); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, " is", " are")); + pf_buffer_string(filter, " for sale.\n"); + return TRUE; } sc_bool -lib_cmd_buy_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_buy_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - /* Reject this attempt. */ - pf_buffer_string (filter, "I don't think that is for sale.\n"); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, "I don't think that is for sale.\n"); + return TRUE; } @@ -8659,40 +7893,38 @@ lib_cmd_buy_other (sc_gameref_t game) * Standard responses to attempts to break something. */ sc_bool -lib_cmd_break_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; +lib_cmd_break_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "break", &is_ambiguous); - if (object == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "break", &is_ambiguous); + if (object == -1) + return is_ambiguous; - /* Reject this attempt. */ - pf_buffer_string (filter, - lib_select_response (game, - "You might need ", - "I might need ", - "%player% might need ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, + lib_select_response(game, + "You might need ", + "I might need ", + "%player% might need ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } sc_bool -lib_cmd_break_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_break_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - /* Reject this attempt. */ - pf_buffer_string (filter, - lib_select_response (game, - "You might need that.\n", - "I might need that.\n", - "%player% might need that.\n")); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, + lib_select_response(game, + "You might need that.\n", + "I might need that.\n", + "%player% might need that.\n")); + return TRUE; } @@ -8703,32 +7935,30 @@ lib_cmd_break_other (sc_gameref_t game) * Standard responses to attempts to smell something. */ sc_bool -lib_cmd_smell_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; +lib_cmd_smell_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "smell", &is_ambiguous); - if (object == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "smell", &is_ambiguous); + if (object == -1) + return is_ambiguous; - /* Reject this attempt. */ - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, " smells normal.\n"); - return TRUE; + /* Reject this attempt. */ + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, " smells normal.\n"); + return TRUE; } sc_bool -lib_cmd_smell_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_smell_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - /* Reject this attempt. */ - pf_buffer_string (filter, "That smells normal.\n"); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, "That smells normal.\n"); + return TRUE; } @@ -8739,31 +7969,29 @@ lib_cmd_smell_other (sc_gameref_t game) * Standard responses to attempts to sell something. */ sc_bool -lib_cmd_sell_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; +lib_cmd_sell_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "sell", &is_ambiguous); - if (object == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "sell", &is_ambiguous); + if (object == -1) + return is_ambiguous; - /* Reject this attempt. */ - pf_buffer_string (filter, "No-one is interested in buying "); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; + /* Reject this attempt. */ + pf_buffer_string(filter, "No-one is interested in buying "); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } sc_bool -lib_cmd_sell_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_sell_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "No-one is interested in buying that.\n"); - return TRUE; + pf_buffer_string(filter, "No-one is interested in buying that.\n"); + return TRUE; } @@ -8773,83 +8001,79 @@ lib_cmd_sell_other (sc_gameref_t game) * Consume edible objects. */ sc_bool -lib_cmd_eat_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int object; - sc_bool edible, is_ambiguous; - - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "eat", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Check that we have the object to eat. */ - if (gs_object_position (game, object) != OBJ_HELD_PLAYER) - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not holding ", - "I am not holding ", - "%player% is not holding ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - /* Check for static object moved to player by event. */ - if (obj_is_static (game, object)) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't eat ", - "I can't eat ", - "%player% can't eat ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - /* Is this object inedible? */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Edible"; - edible = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!edible) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't eat ", - "I can't eat ", - "%player% can't eat ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - - /* Confirm, and hide the object. */ - pf_buffer_string (filter, - lib_select_response (game, - "You eat ", - "I eat ", "%player% eats ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, - ". Not bad, but it could do with a pinch of salt!\n"); - gs_object_make_hidden (game, object); - return TRUE; +lib_cmd_eat_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int object; + sc_bool edible, is_ambiguous; + + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "eat", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Check that we have the object to eat. */ + if (gs_object_position(game, object) != OBJ_HELD_PLAYER) { + pf_buffer_string(filter, + lib_select_response(game, + "You are not holding ", + "I am not holding ", + "%player% is not holding ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + /* Check for static object moved to player by event. */ + if (obj_is_static(game, object)) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't eat ", + "I can't eat ", + "%player% can't eat ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + /* Is this object inedible? */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Edible"; + edible = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!edible) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't eat ", + "I can't eat ", + "%player% can't eat ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + + /* Confirm, and hide the object. */ + pf_buffer_string(filter, + lib_select_response(game, + "You eat ", + "I eat ", "%player% eats ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, + ". Not bad, but it could do with a pinch of salt!\n"); + gs_object_make_hidden(game, object); + return TRUE; } /* Enumerated sit/stand/lie types. */ -enum -{ OBJ_STANDABLE_MASK = 1 << 0, - OBJ_LIEABLE_MASK = 1 << 1 +enum { + OBJ_STANDABLE_MASK = 1 << 0, + OBJ_LIEABLE_MASK = 1 << 1 }; -enum -{ MOVE_SIT, MOVE_SIT_FLOOR, - MOVE_STAND, MOVE_STAND_FLOOR, MOVE_LIE, MOVE_LIE_FLOOR +enum { + MOVE_SIT, MOVE_SIT_FLOOR, + MOVE_STAND, MOVE_STAND_FLOOR, MOVE_LIE, MOVE_LIE_FLOOR }; /* @@ -8858,221 +8082,209 @@ enum * Central handler for stand, sit, and lie commands. */ static sc_bool -lib_stand_sit_lie (sc_gameref_t game, sc_int movement) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, position; - const sc_char *already_doing_that, *success_message; - - /* Initialize variables to avoid gcc warnings. */ - object = -1; - already_doing_that = FALSE; - success_message = FALSE; - position = 0; - - /* Get a target object for movement, -1 if floor. */ - switch (movement) - { - case MOVE_STAND: - case MOVE_SIT: - case MOVE_LIE: - { - const sc_char *disambiguate, *cant_do_that; - sc_int sit_lie_flags, movement_mask; - sc_vartype_t vt_key[3]; - sc_bool is_ambiguous; - - /* Initialize variables to avoid gcc warnings. */ - disambiguate = NULL; - cant_do_that = NULL; - movement_mask = 0; - - /* Set disambiguation and not amenable messages. */ - switch (movement) - { - case MOVE_STAND: - disambiguate = "stand on"; - cant_do_that = lib_select_response (game, - "You can't stand on ", - "I can't stand on ", - "%player% can't stand on "); - movement_mask = OBJ_STANDABLE_MASK; - break; - case MOVE_SIT: - disambiguate = "sit on"; - cant_do_that = lib_select_response (game, - "You can't sit on ", - "I can't sit on ", - "%player% can't sit on "); - movement_mask = OBJ_STANDABLE_MASK; - break; - case MOVE_LIE: - disambiguate = "lie on"; - cant_do_that = lib_select_response (game, - "You can't lie on ", - "I can't lie on ", - "%player% can't lie on "); - movement_mask = OBJ_LIEABLE_MASK; - break; - default: - sc_fatal ("lib_sit_stand_lie: movement error, %ld\n", movement); - } - - /* Get the referenced object; if none, consider complete. */ - object = lib_disambiguate_object (game, disambiguate, &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Verify the referenced object is amenable. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "SitLie"; - sit_lie_flags = prop_get_integer (bundle, "I<-sis", vt_key); - if (!(sit_lie_flags & movement_mask)) - { - pf_buffer_string (filter, cant_do_that); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; - } - break; - } - - case MOVE_STAND_FLOOR: - case MOVE_SIT_FLOOR: - case MOVE_LIE_FLOOR: - object = -1; - break; - - default: - sc_fatal ("lib_sit_stand_lie: movement error, %ld\n", movement); - } - - /* Set up confirmation messages and position. */ - switch (movement) - { - case MOVE_STAND: - already_doing_that = lib_select_response (game, - "You are already standing on ", - "I am already standing on ", - "%player% is already standing on "); - success_message = lib_select_response (game, - "You stand on ", - "I stand on ", - "%player% stands on "); - position = 0; - break; - - case MOVE_STAND_FLOOR: - already_doing_that = lib_select_response (game, - "You are already standing!\n", - "I am already standing!\n", - "%player% is already standing!\n"); - success_message = lib_select_response (game, - "You stand up", - "I stand up", - "%player% stands up"); - position = 0; - break; - - case MOVE_SIT: - already_doing_that = lib_select_response (game, - "You are already sitting on ", - "I am already sitting on ", - "%player% is already sitting on "); - if (gs_playerposition (game) == 2) - success_message = lib_select_response (game, - "You sit up on ", - "I sit up on ", - "%player% sits up on "); - else - success_message = lib_select_response (game, - "You sit down on ", - "I sit down on ", - "%player% sits down on "); - position = 1; - break; - - case MOVE_SIT_FLOOR: - already_doing_that = lib_select_response (game, - "You are already sitting down.\n", - "I am already sitting down.\n", - "%player% is already sitting down.\n"); - if (gs_playerposition (game) == 2) - success_message = lib_select_response (game, - "You sit up on the ground.\n", - "I sit up on the ground.\n", - "%player% sits up on the ground.\n"); - else - success_message = lib_select_response (game, - "You sit down on the ground.\n", - "I sit down on the ground.\n", - "%player% sits down on the ground.\n"); - position = 1; - break; - - case MOVE_LIE: - already_doing_that = lib_select_response (game, - "You are already lying on ", - "I am already lying on ", - "%player% is already lying on "); - success_message = lib_select_response (game, - "You lie down on ", - "I lie down on ", - "%player% lies down on "); - position = 2; - break; - - case MOVE_LIE_FLOOR: - already_doing_that = lib_select_response (game, - "You are already lying down.\n", - "I am already lying down.\n", - "%player% is already lying down.\n"); - success_message = lib_select_response (game, - "You lie down on the ground.\n", - "I lie down on the ground.\n", - "%player% lies down on the ground.\n"); - position = 2; - break; - - default: - sc_fatal ("lib_sit_stand_lie: movement error, %ld\n", movement); - } - - /* See if already doing this. */ - if (gs_playerposition (game) == position && gs_playerparent (game) == object) - { - pf_buffer_string (filter, already_doing_that); - if (object != -1) - { - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - } - return TRUE; - } - - /* Confirm movement, with special case for getting off an object. */ - pf_buffer_string (filter, success_message); - if (movement == MOVE_STAND_FLOOR) - { - if (gs_playerparent (game) != -1) - { - pf_buffer_string (filter, " from "); - lib_print_object_np (game, gs_playerparent (game)); - } - pf_buffer_string (filter, ".\n"); - } - else if (object != -1) - { - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - } - - /* Adjust player position and parent. */ - gs_set_playerposition (game, position); - gs_set_playerparent (game, object); - return TRUE; +lib_stand_sit_lie(sc_gameref_t game, sc_int movement) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, position; + const sc_char *already_doing_that, *success_message; + + /* Initialize variables to avoid gcc warnings. */ + object = -1; + already_doing_that = FALSE; + success_message = FALSE; + position = 0; + + /* Get a target object for movement, -1 if floor. */ + switch (movement) { + case MOVE_STAND: + case MOVE_SIT: + case MOVE_LIE: { + const sc_char *disambiguate, *cant_do_that; + sc_int sit_lie_flags, movement_mask; + sc_vartype_t vt_key[3]; + sc_bool is_ambiguous; + + /* Initialize variables to avoid gcc warnings. */ + disambiguate = NULL; + cant_do_that = NULL; + movement_mask = 0; + + /* Set disambiguation and not amenable messages. */ + switch (movement) { + case MOVE_STAND: + disambiguate = "stand on"; + cant_do_that = lib_select_response(game, + "You can't stand on ", + "I can't stand on ", + "%player% can't stand on "); + movement_mask = OBJ_STANDABLE_MASK; + break; + case MOVE_SIT: + disambiguate = "sit on"; + cant_do_that = lib_select_response(game, + "You can't sit on ", + "I can't sit on ", + "%player% can't sit on "); + movement_mask = OBJ_STANDABLE_MASK; + break; + case MOVE_LIE: + disambiguate = "lie on"; + cant_do_that = lib_select_response(game, + "You can't lie on ", + "I can't lie on ", + "%player% can't lie on "); + movement_mask = OBJ_LIEABLE_MASK; + break; + default: + sc_fatal("lib_sit_stand_lie: movement error, %ld\n", movement); + } + + /* Get the referenced object; if none, consider complete. */ + object = lib_disambiguate_object(game, disambiguate, &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Verify the referenced object is amenable. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "SitLie"; + sit_lie_flags = prop_get_integer(bundle, "I<-sis", vt_key); + if (!(sit_lie_flags & movement_mask)) { + pf_buffer_string(filter, cant_do_that); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; + } + break; + } + + case MOVE_STAND_FLOOR: + case MOVE_SIT_FLOOR: + case MOVE_LIE_FLOOR: + object = -1; + break; + + default: + sc_fatal("lib_sit_stand_lie: movement error, %ld\n", movement); + } + + /* Set up confirmation messages and position. */ + switch (movement) { + case MOVE_STAND: + already_doing_that = lib_select_response(game, + "You are already standing on ", + "I am already standing on ", + "%player% is already standing on "); + success_message = lib_select_response(game, + "You stand on ", + "I stand on ", + "%player% stands on "); + position = 0; + break; + + case MOVE_STAND_FLOOR: + already_doing_that = lib_select_response(game, + "You are already standing!\n", + "I am already standing!\n", + "%player% is already standing!\n"); + success_message = lib_select_response(game, + "You stand up", + "I stand up", + "%player% stands up"); + position = 0; + break; + + case MOVE_SIT: + already_doing_that = lib_select_response(game, + "You are already sitting on ", + "I am already sitting on ", + "%player% is already sitting on "); + if (gs_playerposition(game) == 2) + success_message = lib_select_response(game, + "You sit up on ", + "I sit up on ", + "%player% sits up on "); + else + success_message = lib_select_response(game, + "You sit down on ", + "I sit down on ", + "%player% sits down on "); + position = 1; + break; + + case MOVE_SIT_FLOOR: + already_doing_that = lib_select_response(game, + "You are already sitting down.\n", + "I am already sitting down.\n", + "%player% is already sitting down.\n"); + if (gs_playerposition(game) == 2) + success_message = lib_select_response(game, + "You sit up on the ground.\n", + "I sit up on the ground.\n", + "%player% sits up on the ground.\n"); + else + success_message = lib_select_response(game, + "You sit down on the ground.\n", + "I sit down on the ground.\n", + "%player% sits down on the ground.\n"); + position = 1; + break; + + case MOVE_LIE: + already_doing_that = lib_select_response(game, + "You are already lying on ", + "I am already lying on ", + "%player% is already lying on "); + success_message = lib_select_response(game, + "You lie down on ", + "I lie down on ", + "%player% lies down on "); + position = 2; + break; + + case MOVE_LIE_FLOOR: + already_doing_that = lib_select_response(game, + "You are already lying down.\n", + "I am already lying down.\n", + "%player% is already lying down.\n"); + success_message = lib_select_response(game, + "You lie down on the ground.\n", + "I lie down on the ground.\n", + "%player% lies down on the ground.\n"); + position = 2; + break; + + default: + sc_fatal("lib_sit_stand_lie: movement error, %ld\n", movement); + } + + /* See if already doing this. */ + if (gs_playerposition(game) == position && gs_playerparent(game) == object) { + pf_buffer_string(filter, already_doing_that); + if (object != -1) { + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + } + return TRUE; + } + + /* Confirm movement, with special case for getting off an object. */ + pf_buffer_string(filter, success_message); + if (movement == MOVE_STAND_FLOOR) { + if (gs_playerparent(game) != -1) { + pf_buffer_string(filter, " from "); + lib_print_object_np(game, gs_playerparent(game)); + } + pf_buffer_string(filter, ".\n"); + } else if (object != -1) { + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + } + + /* Adjust player position and parent. */ + gs_set_playerposition(game, position); + gs_set_playerparent(game, object); + return TRUE; } @@ -9084,39 +8296,33 @@ lib_stand_sit_lie (sc_gameref_t game, sc_int movement) * Stand, sit, or lie on an object, or on the floor. */ sc_bool -lib_cmd_stand_on_object (sc_gameref_t game) -{ - return lib_stand_sit_lie (game, MOVE_STAND); +lib_cmd_stand_on_object(sc_gameref_t game) { + return lib_stand_sit_lie(game, MOVE_STAND); } sc_bool -lib_cmd_stand_on_floor (sc_gameref_t game) -{ - return lib_stand_sit_lie (game, MOVE_STAND_FLOOR); +lib_cmd_stand_on_floor(sc_gameref_t game) { + return lib_stand_sit_lie(game, MOVE_STAND_FLOOR); } sc_bool -lib_cmd_sit_on_object (sc_gameref_t game) -{ - return lib_stand_sit_lie (game, MOVE_SIT); +lib_cmd_sit_on_object(sc_gameref_t game) { + return lib_stand_sit_lie(game, MOVE_SIT); } sc_bool -lib_cmd_sit_on_floor (sc_gameref_t game) -{ - return lib_stand_sit_lie (game, MOVE_SIT_FLOOR); +lib_cmd_sit_on_floor(sc_gameref_t game) { + return lib_stand_sit_lie(game, MOVE_SIT_FLOOR); } sc_bool -lib_cmd_lie_on_object (sc_gameref_t game) -{ - return lib_stand_sit_lie (game, MOVE_LIE); +lib_cmd_lie_on_object(sc_gameref_t game) { + return lib_stand_sit_lie(game, MOVE_LIE); } sc_bool -lib_cmd_lie_on_floor (sc_gameref_t game) -{ - return lib_stand_sit_lie (game, MOVE_LIE_FLOOR); +lib_cmd_lie_on_floor(sc_gameref_t game) { + return lib_stand_sit_lie(game, MOVE_LIE_FLOOR); } @@ -9127,72 +8333,68 @@ lib_cmd_lie_on_floor (sc_gameref_t game) * Get off whatever supporter the player rests on. */ sc_bool -lib_cmd_get_off_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; - - /* Get the referenced object; if none, consider complete. */ - object = lib_disambiguate_object (game, "get off", &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Reject the attempt if the player is not on the given object. */ - if (gs_playerparent (game) != object) - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not on ", - "I am not on ", - "%player% is not on ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, "!\n"); - return TRUE; - } - - /* Confirm movement. */ - pf_buffer_string (filter, - lib_select_response (game, - "You get off ", "I get off ", - "%player% gets off ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - - /* Adjust player position and parent. */ - gs_set_playerposition (game, 0); - gs_set_playerparent (game, -1); - return TRUE; -} - -sc_bool -lib_cmd_get_off (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - - /* Reject the attempt if the player is not on anything. */ - if (gs_playerparent (game) == -1) - { - pf_buffer_string (filter, - lib_select_response (game, - "You are not on anything!\n", - "I am not on anything!\n", - "%player% is not on anything!\n")); - return TRUE; - } - - /* Confirm movement. */ - pf_buffer_string (filter, - lib_select_response (game, - "You get off ", "I get off ", - "%player% gets off ")); - lib_print_object_np (game, gs_playerparent (game)); - pf_buffer_string (filter, ".\n"); - - /* Adjust player position and parent. */ - gs_set_playerposition (game, 0); - gs_set_playerparent (game, -1); - return TRUE; +lib_cmd_get_off_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; + + /* Get the referenced object; if none, consider complete. */ + object = lib_disambiguate_object(game, "get off", &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Reject the attempt if the player is not on the given object. */ + if (gs_playerparent(game) != object) { + pf_buffer_string(filter, + lib_select_response(game, + "You are not on ", + "I am not on ", + "%player% is not on ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, "!\n"); + return TRUE; + } + + /* Confirm movement. */ + pf_buffer_string(filter, + lib_select_response(game, + "You get off ", "I get off ", + "%player% gets off ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + + /* Adjust player position and parent. */ + gs_set_playerposition(game, 0); + gs_set_playerparent(game, -1); + return TRUE; +} + +sc_bool +lib_cmd_get_off(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + + /* Reject the attempt if the player is not on anything. */ + if (gs_playerparent(game) == -1) { + pf_buffer_string(filter, + lib_select_response(game, + "You are not on anything!\n", + "I am not on anything!\n", + "%player% is not on anything!\n")); + return TRUE; + } + + /* Confirm movement. */ + pf_buffer_string(filter, + lib_select_response(game, + "You get off ", "I get off ", + "%player% gets off ")); + lib_print_object_np(game, gs_playerparent(game)); + pf_buffer_string(filter, ".\n"); + + /* Adjust player position and parent. */ + gs_set_playerposition(game, 0); + gs_set_playerparent(game, -1); + return TRUE; } @@ -9203,37 +8405,31 @@ lib_cmd_get_off (sc_gameref_t game) * Save/restore a game. */ sc_bool -lib_cmd_save (sc_gameref_t game) -{ - if (if_confirm (SC_CONF_SAVE)) - { - if (ser_save_game_prompted (game)) - if_print_string ("Ok.\n"); - else - if_print_string ("Save failed.\n"); - } +lib_cmd_save(sc_gameref_t game) { + if (if_confirm(SC_CONF_SAVE)) { + if (ser_save_game_prompted(game)) + if_print_string("Ok.\n"); + else + if_print_string("Save failed.\n"); + } - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } sc_bool -lib_cmd_restore (sc_gameref_t game) -{ - if (if_confirm (SC_CONF_RESTORE)) - { - if (ser_load_game_prompted (game)) - { - if_print_string ("Ok.\n"); - game->is_running = FALSE; - game->do_restore = TRUE; - } - else - if_print_string ("Restore failed.\n"); - } +lib_cmd_restore(sc_gameref_t game) { + if (if_confirm(SC_CONF_RESTORE)) { + if (ser_load_game_prompted(game)) { + if_print_string("Ok.\n"); + game->is_running = FALSE; + game->do_restore = TRUE; + } else + if_print_string("Restore failed.\n"); + } - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -9244,300 +8440,268 @@ lib_cmd_restore (sc_gameref_t game) * Display the location of a selected object, and selected NPC. */ sc_bool -lib_cmd_locate_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int index_, count, object, room, position, parent; - - game->is_admin = TRUE; - - /* - * Filter to remove unseen object references. Note that this is different - * from NPCs, who we acknowledge even when unseen. - */ - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (!gs_object_seen (game, index_)) - game->object_references[index_] = FALSE; - } - - /* Count the number of objects referenced by the last command. */ - count = 0; - object = -1; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (game->object_references[index_]) - { - count++; - object = index_; - } - } - - /* - * If no objects identified, be coy about revealing anything; if more than - * one, be vague. - */ - if (count == 0) - { - pf_buffer_string (filter, "I don't know where that is.\n"); - return TRUE; - } - else if (count > 1) - { - pf_buffer_string (filter, - "Please be more clear about what you want to" - " locate.\n"); - return TRUE; - } - - /* - * The reference is unambiguous, so we're responsible for noting it in - * variables. Disambiguation would normally do this for us, but we just - * bypassed it. - */ - var_set_ref_object (vars, object); - - /* See if we can print a message based on position and parent. */ - position = gs_object_position (game, object); - parent = gs_object_parent (game, object); - switch (position) - { - case OBJ_HIDDEN: - if (!obj_is_static (game, object)) - { - pf_buffer_string (filter, "I don't know where that is.\n"); - return TRUE; - } - break; - - case OBJ_HELD_PLAYER: - pf_new_sentence (filter); - pf_buffer_string (filter, - lib_select_response (game, - "You are carrying ", - "I am carrying ", - "%player% is carrying ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, "!\n"); - return TRUE; - - case OBJ_WORN_PLAYER: - pf_new_sentence (filter); - pf_buffer_string (filter, - lib_select_response (game, - "You are wearing ", - "I am wearing ", - "%player% is wearing ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, "!\n"); - return TRUE; - - case OBJ_HELD_NPC: - case OBJ_WORN_NPC: - if (gs_npc_seen (game, parent)) - { - pf_new_sentence (filter); - lib_print_npc_np (game, parent); - pf_buffer_string (filter, - (position == OBJ_HELD_NPC) - ? " is holding " : " is wearing "); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - } - else - pf_buffer_string (filter, "I don't know where that is.\n"); - return TRUE; - - case OBJ_PART_NPC: - if (parent == -1) - { - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, " is", " are")); - pf_buffer_string (filter, - lib_select_response (game, - " a part of you!\n", - " a part of me!\n", - " a part of %player%!\n")); - } - else - { - if (gs_npc_seen (game, parent)) - { - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, - " is", " are")); - pf_buffer_string (filter, " a part of "); - lib_print_npc_np (game, parent); - pf_buffer_string (filter, ".\n"); - } - else - pf_buffer_string (filter, "I don't know where that is.\n"); - } - return TRUE; - - case OBJ_ON_OBJECT: - case OBJ_IN_OBJECT: - if (gs_object_seen (game, parent)) - { - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, " is", " are")); - pf_buffer_string (filter, - (position == OBJ_ON_OBJECT) ? " on " : " inside "); - lib_print_object_np (game, parent); - pf_buffer_string (filter, ".\n"); - } - else - pf_buffer_string (filter, "I don't know where that is.\n"); - return TRUE; - } - - /* - * Object is either static unmoved, or dynamic and on the floor of a room. - * Check each room for the object, stopping on first found. - */ - for (room = 0; room < gs_room_count (game); room++) - { - if (obj_indirectly_in_room (game, object, room)) - break; - } - if (room == gs_room_count (game)) - { - pf_buffer_string (filter, "I don't know where that is.\n"); - return TRUE; - } - - /* Check that this room's been visited by the player. */ - if (!gs_room_seen (game, room)) - { - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, - lib_select_plurality (game, object, " is", " are")); - pf_buffer_string (filter, - lib_select_response (game, - " somewhere that you haven't been yet.\n", - " somewhere that I haven't been yet.\n", - " somewhere that %player% hasn't been yet.\n")); - return TRUE; - } - - /* Print the details of the object's room. */ - pf_new_sentence (filter); - lib_print_object_np (game, object); - pf_buffer_string (filter, " -- "); - pf_buffer_string (filter, lib_get_room_name (game, room)); - pf_buffer_string (filter, ".\n"); - return TRUE; -} - -sc_bool -lib_cmd_locate_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int index_, count, npc, room; - - game->is_admin = TRUE; - - /* Count the number of NPCs referenced by the last command. */ - count = 0; - npc = -1; - for (index_ = 0; index_ < gs_npc_count (game); index_++) - { - if (game->npc_references[index_]) - { - count++; - npc = index_; - } - } - - /* - * If no NPCs identified, be coy about revealing anything; if more than one, - * be vague. The "... where that is..." is the correct message even for - * NPCs -- it's the same response as for lib_locate_other(). - */ - if (count == 0) - { - pf_buffer_string (filter, "I don't know where that is.\n"); - return TRUE; - } - else if (count > 1) - { - pf_buffer_string (filter, - "Please be more clear about who you want to locate.\n"); - return TRUE; - } - - /* - * The reference is unambiguous, so we're responsible for noting it in - * variables. Disambiguation would normally do this for us, but we just - * bypassed it. - */ - var_set_ref_character (vars, npc); - - /* See if this NPC has been seen yet. */ - if (!gs_npc_seen (game, npc)) - { - pf_buffer_string (filter, - lib_select_response (game, - "You haven't seen ", - "I haven't seen ", - "%player% hasn't seen ")); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " yet!\n"); - return TRUE; - } - - /* Check each room for the NPC, stopping on first found. */ - for (room = 0; room < gs_room_count (game); room++) - { - if (npc_in_room (game, npc, room)) - break; - } - if (room == gs_room_count (game)) - { - pf_buffer_string (filter, "I don't know where "); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " is.\n"); - return TRUE; - } - - /* Check that this room's been visited by the player. */ - if (!gs_room_seen (game, room)) - { - lib_print_npc_np (game, npc); - pf_buffer_string (filter, - lib_select_response (game, - " is somewhere that you haven't been yet.\n", - " is somewhere that I haven't been yet.\n", - " is somewhere that %player% hasn't been yet.\n")); - return TRUE; - } - - /* Print the location, and smart-alec response. */ - pf_new_sentence (filter); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " -- "); - pf_buffer_string (filter, lib_get_room_name (game, room)); +lib_cmd_locate_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int index_, count, object, room, position, parent; + + game->is_admin = TRUE; + + /* + * Filter to remove unseen object references. Note that this is different + * from NPCs, who we acknowledge even when unseen. + */ + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (!gs_object_seen(game, index_)) + game->object_references[index_] = FALSE; + } + + /* Count the number of objects referenced by the last command. */ + count = 0; + object = -1; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (game->object_references[index_]) { + count++; + object = index_; + } + } + + /* + * If no objects identified, be coy about revealing anything; if more than + * one, be vague. + */ + if (count == 0) { + pf_buffer_string(filter, "I don't know where that is.\n"); + return TRUE; + } else if (count > 1) { + pf_buffer_string(filter, + "Please be more clear about what you want to" + " locate.\n"); + return TRUE; + } + + /* + * The reference is unambiguous, so we're responsible for noting it in + * variables. Disambiguation would normally do this for us, but we just + * bypassed it. + */ + var_set_ref_object(vars, object); + + /* See if we can print a message based on position and parent. */ + position = gs_object_position(game, object); + parent = gs_object_parent(game, object); + switch (position) { + case OBJ_HIDDEN: + if (!obj_is_static(game, object)) { + pf_buffer_string(filter, "I don't know where that is.\n"); + return TRUE; + } + break; + + case OBJ_HELD_PLAYER: + pf_new_sentence(filter); + pf_buffer_string(filter, + lib_select_response(game, + "You are carrying ", + "I am carrying ", + "%player% is carrying ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, "!\n"); + return TRUE; + + case OBJ_WORN_PLAYER: + pf_new_sentence(filter); + pf_buffer_string(filter, + lib_select_response(game, + "You are wearing ", + "I am wearing ", + "%player% is wearing ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, "!\n"); + return TRUE; + + case OBJ_HELD_NPC: + case OBJ_WORN_NPC: + if (gs_npc_seen(game, parent)) { + pf_new_sentence(filter); + lib_print_npc_np(game, parent); + pf_buffer_string(filter, + (position == OBJ_HELD_NPC) + ? " is holding " : " is wearing "); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + } else + pf_buffer_string(filter, "I don't know where that is.\n"); + return TRUE; + + case OBJ_PART_NPC: + if (parent == -1) { + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, " is", " are")); + pf_buffer_string(filter, + lib_select_response(game, + " a part of you!\n", + " a part of me!\n", + " a part of %player%!\n")); + } else { + if (gs_npc_seen(game, parent)) { + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, + " is", " are")); + pf_buffer_string(filter, " a part of "); + lib_print_npc_np(game, parent); + pf_buffer_string(filter, ".\n"); + } else + pf_buffer_string(filter, "I don't know where that is.\n"); + } + return TRUE; + + case OBJ_ON_OBJECT: + case OBJ_IN_OBJECT: + if (gs_object_seen(game, parent)) { + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, " is", " are")); + pf_buffer_string(filter, + (position == OBJ_ON_OBJECT) ? " on " : " inside "); + lib_print_object_np(game, parent); + pf_buffer_string(filter, ".\n"); + } else + pf_buffer_string(filter, "I don't know where that is.\n"); + return TRUE; + } + + /* + * Object is either static unmoved, or dynamic and on the floor of a room. + * Check each room for the object, stopping on first found. + */ + for (room = 0; room < gs_room_count(game); room++) { + if (obj_indirectly_in_room(game, object, room)) + break; + } + if (room == gs_room_count(game)) { + pf_buffer_string(filter, "I don't know where that is.\n"); + return TRUE; + } + + /* Check that this room's been visited by the player. */ + if (!gs_room_seen(game, room)) { + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, + lib_select_plurality(game, object, " is", " are")); + pf_buffer_string(filter, + lib_select_response(game, + " somewhere that you haven't been yet.\n", + " somewhere that I haven't been yet.\n", + " somewhere that %player% hasn't been yet.\n")); + return TRUE; + } + + /* Print the details of the object's room. */ + pf_new_sentence(filter); + lib_print_object_np(game, object); + pf_buffer_string(filter, " -- "); + pf_buffer_string(filter, lib_get_room_name(game, room)); + pf_buffer_string(filter, ".\n"); + return TRUE; +} + +sc_bool +lib_cmd_locate_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int index_, count, npc, room; + + game->is_admin = TRUE; + + /* Count the number of NPCs referenced by the last command. */ + count = 0; + npc = -1; + for (index_ = 0; index_ < gs_npc_count(game); index_++) { + if (game->npc_references[index_]) { + count++; + npc = index_; + } + } + + /* + * If no NPCs identified, be coy about revealing anything; if more than one, + * be vague. The "... where that is..." is the correct message even for + * NPCs -- it's the same response as for lib_locate_other(). + */ + if (count == 0) { + pf_buffer_string(filter, "I don't know where that is.\n"); + return TRUE; + } else if (count > 1) { + pf_buffer_string(filter, + "Please be more clear about who you want to locate.\n"); + return TRUE; + } + + /* + * The reference is unambiguous, so we're responsible for noting it in + * variables. Disambiguation would normally do this for us, but we just + * bypassed it. + */ + var_set_ref_character(vars, npc); + + /* See if this NPC has been seen yet. */ + if (!gs_npc_seen(game, npc)) { + pf_buffer_string(filter, + lib_select_response(game, + "You haven't seen ", + "I haven't seen ", + "%player% hasn't seen ")); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " yet!\n"); + return TRUE; + } + + /* Check each room for the NPC, stopping on first found. */ + for (room = 0; room < gs_room_count(game); room++) { + if (npc_in_room(game, npc, room)) + break; + } + if (room == gs_room_count(game)) { + pf_buffer_string(filter, "I don't know where "); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " is.\n"); + return TRUE; + } + + /* Check that this room's been visited by the player. */ + if (!gs_room_seen(game, room)) { + lib_print_npc_np(game, npc); + pf_buffer_string(filter, + lib_select_response(game, + " is somewhere that you haven't been yet.\n", + " is somewhere that I haven't been yet.\n", + " is somewhere that %player% hasn't been yet.\n")); + return TRUE; + } + + /* Print the location, and smart-alec response. */ + pf_new_sentence(filter); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " -- "); + pf_buffer_string(filter, lib_get_room_name(game, room)); #if 0 - if (room == gs_playerroom (game)) - { - pf_buffer_string (filter, - lib_select_response (game, - " (Right next to you, silly!)", - " (Right next to me, silly!)", - " (Right next to %player%, silly!)")); - } + if (room == gs_playerroom(game)) { + pf_buffer_string(filter, + lib_select_response(game, + " (Right next to you, silly!)", + " (Right next to me, silly!)", + " (Right next to %player%, silly!)")); + } #endif - pf_buffer_string (filter, ".\n"); - return TRUE; + pf_buffer_string(filter, ".\n"); + return TRUE; } @@ -9548,59 +8712,57 @@ lib_cmd_locate_npc (sc_gameref_t game) * Display turns taken and score so far. */ sc_bool -lib_cmd_turns (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_char buffer[32]; +lib_cmd_turns(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_char buffer[32]; - pf_buffer_string (filter, "You have taken "); - sprintf (buffer, "%ld", game->turns); - pf_buffer_string (filter, buffer); - if (game->turns == 1) - pf_buffer_string (filter, " turn so far.\n"); - else - pf_buffer_string (filter, " turns so far.\n"); + pf_buffer_string(filter, "You have taken "); + sprintf(buffer, "%ld", game->turns); + pf_buffer_string(filter, buffer); + if (game->turns == 1) + pf_buffer_string(filter, " turn so far.\n"); + else + pf_buffer_string(filter, " turns so far.\n"); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } sc_bool -lib_cmd_score (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_int max_score, percent; - sc_char buffer[32]; +lib_cmd_score(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_int max_score, percent; + sc_char buffer[32]; - /* Get max score, and calculate score as a percentage. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "MaxScore"; - max_score = prop_get_integer (bundle, "I<-ss", vt_key); - if (game->score > 0 && max_score > 0) - percent = (game->score * 100) / max_score; - else - percent = 0; + /* Get max score, and calculate score as a percentage. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "MaxScore"; + max_score = prop_get_integer(bundle, "I<-ss", vt_key); + if (game->score > 0 && max_score > 0) + percent = (game->score * 100) / max_score; + else + percent = 0; - /* Output carefully formatted response. */ - pf_buffer_string (filter, - lib_select_response (game, - "Your score is ", - "My score is ", - "%player%'s score is ")); - sprintf (buffer, "%ld", game->score); - pf_buffer_string (filter, buffer); - pf_buffer_string (filter, " out of a maximum of "); - sprintf (buffer, "%ld", max_score); - pf_buffer_string (filter, buffer); - pf_buffer_string (filter, ". ("); - sprintf (buffer, "%ld", percent); - pf_buffer_string (filter, buffer); - pf_buffer_string (filter, "%)\n"); + /* Output carefully formatted response. */ + pf_buffer_string(filter, + lib_select_response(game, + "Your score is ", + "My score is ", + "%player%'s score is ")); + sprintf(buffer, "%ld", game->score); + pf_buffer_string(filter, buffer); + pf_buffer_string(filter, " out of a maximum of "); + sprintf(buffer, "%ld", max_score); + pf_buffer_string(filter, buffer); + pf_buffer_string(filter, ". ("); + sprintf(buffer, "%ld", percent); + pf_buffer_string(filter, buffer); + pf_buffer_string(filter, "%)\n"); - game->is_admin = TRUE; - return TRUE; + game->is_admin = TRUE; + return TRUE; } @@ -9611,423 +8773,390 @@ lib_cmd_score (sc_gameref_t game) * but it's good to make then right as game ALRs may look for them. */ sc_bool -lib_cmd_profanity (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_profanity(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - "I really don't think there's any need for language like" - " that!\n"); - return TRUE; + pf_buffer_string(filter, + "I really don't think there's any need for language like" + " that!\n"); + return TRUE; } sc_bool -lib_cmd_examine_all (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_examine_all(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "Please examine one object at a time.\n"); - return TRUE; + pf_buffer_string(filter, "Please examine one object at a time.\n"); + return TRUE; } sc_bool -lib_cmd_examine_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_examine_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - lib_select_response (game, - "You see no such thing.\n", - "I see no such thing.\n", - "%player% sees no such thing.\n")); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "You see no such thing.\n", + "I see no such thing.\n", + "%player% sees no such thing.\n")); + return TRUE; } sc_bool -lib_cmd_locate_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_locate_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "I don't know where that is!\n"); - game->is_admin = TRUE; - return TRUE; + pf_buffer_string(filter, "I don't know where that is!\n"); + game->is_admin = TRUE; + return TRUE; } sc_bool -lib_cmd_unix_like (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_unix_like(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "This isn't Unix you know!\n"); - return TRUE; + pf_buffer_string(filter, "This isn't Unix you know!\n"); + return TRUE; } sc_bool -lib_cmd_dos_like (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_dos_like(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "This isn't Dos you know!\n"); - return TRUE; + pf_buffer_string(filter, "This isn't Dos you know!\n"); + return TRUE; } sc_bool -lib_cmd_cry (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_cry(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "There's no need for that!\n"); - return TRUE; + pf_buffer_string(filter, "There's no need for that!\n"); + return TRUE; } sc_bool -lib_cmd_dance (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_dance(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - lib_select_response (game, - "You do a little dance.\n", - "I do a little dance.\n", - "%player% does a little dance.\n")); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "You do a little dance.\n", + "I do a little dance.\n", + "%player% does a little dance.\n")); + return TRUE; } sc_bool -lib_cmd_eat_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_eat_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "I don't understand what you are trying to eat.\n"); - return TRUE; + pf_buffer_string(filter, "I don't understand what you are trying to eat.\n"); + return TRUE; } sc_bool -lib_cmd_fight (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_fight(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "There is nothing worth fighting here.\n"); - return TRUE; + pf_buffer_string(filter, "There is nothing worth fighting here.\n"); + return TRUE; } sc_bool -lib_cmd_feed (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_feed(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "There is nothing worth feeding here.\n"); - return TRUE; + pf_buffer_string(filter, "There is nothing worth feeding here.\n"); + return TRUE; } sc_bool -lib_cmd_feel (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_feel(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - lib_select_response (game, - "You feel nothing out of the ordinary.\n", - "I feel nothing out of the ordinary.\n", - "%player% feels nothing out of the ordinary.\n")); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "You feel nothing out of the ordinary.\n", + "I feel nothing out of the ordinary.\n", + "%player% feels nothing out of the ordinary.\n")); + return TRUE; } sc_bool -lib_cmd_fly (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_fly(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - lib_select_response (game, - "You can't fly.\n", - "I can't fly.\n", - "%player% can't fly.\n")); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "You can't fly.\n", + "I can't fly.\n", + "%player% can't fly.\n")); + return TRUE; } sc_bool -lib_cmd_hint (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_hint(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - "You're just going to have to work it out for" - " yourself...\n"); - return TRUE; + pf_buffer_string(filter, + "You're just going to have to work it out for" + " yourself...\n"); + return TRUE; } sc_bool -lib_cmd_hum (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_hum(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - lib_select_response (game, - "You hum a little tune.\n", - "I hum a little tune.\n", - "%player% hums a little tune.\n")); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "You hum a little tune.\n", + "I hum a little tune.\n", + "%player% hums a little tune.\n")); + return TRUE; } sc_bool -lib_cmd_jump (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_jump(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "Wheee-boinng.\n"); - return TRUE; + pf_buffer_string(filter, "Wheee-boinng.\n"); + return TRUE; } sc_bool -lib_cmd_listen (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_listen(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - lib_select_response (game, - "You hear nothing out of the ordinary.\n", - "I hear nothing out of the ordinary.\n", - "%player% hears nothing out of the ordinary.\n")); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "You hear nothing out of the ordinary.\n", + "I hear nothing out of the ordinary.\n", + "%player% hears nothing out of the ordinary.\n")); + return TRUE; } sc_bool -lib_cmd_please (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_please(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - lib_select_response (game, - "Your kindness gets you nowhere.\n", - "My kindness gets me nowhere.\n", - "%player%'s kindness gets nowhere.\n")); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "Your kindness gets you nowhere.\n", + "My kindness gets me nowhere.\n", + "%player%'s kindness gets nowhere.\n")); + return TRUE; } sc_bool -lib_cmd_punch (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_punch(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "Who do you think you are, Mike Tyson?\n"); - return TRUE; + pf_buffer_string(filter, "Who do you think you are, Mike Tyson?\n"); + return TRUE; } sc_bool -lib_cmd_run (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_run(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - lib_select_response (game, - "Why would you want to run?\n", - "Why would I want to run?\n", - "Why would %player% want to run?\n")); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "Why would you want to run?\n", + "Why would I want to run?\n", + "Why would %player% want to run?\n")); + return TRUE; } sc_bool -lib_cmd_shout (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_shout(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "Aaarrrrgggghhhhhh!\n"); - return TRUE; + pf_buffer_string(filter, "Aaarrrrgggghhhhhh!\n"); + return TRUE; } sc_bool -lib_cmd_say (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_char *string = NULL; +lib_cmd_say(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_char *string = NULL; + + switch (sc_randomint(1, 5)) { + case 1: + string = "Gosh, that was very impressive.\n"; + break; + case 2: + string = lib_select_response(game, + "Not surprisingly, no-one takes any notice" + " of you.\n", + "Not surprisingly, no-one takes any notice" + " of me.\n", + "Not surprisingly, no-one takes any notice" + " of %player%.\n"); + break; + case 3: + string = "Wow! That achieved a lot.\n"; + break; + case 4: + string = "Uh huh, yes, very interesting.\n"; + break; + default: + string = "That's the most interesting thing I've ever heard!\n"; + break; + } + + pf_buffer_string(filter, string); + return TRUE; +} - switch (sc_randomint (1, 5)) - { - case 1: - string = "Gosh, that was very impressive.\n"; - break; - case 2: - string = lib_select_response (game, - "Not surprisingly, no-one takes any notice" - " of you.\n", - "Not surprisingly, no-one takes any notice" - " of me.\n", - "Not surprisingly, no-one takes any notice" - " of %player%.\n"); - break; - case 3: - string = "Wow! That achieved a lot.\n"; - break; - case 4: - string = "Uh huh, yes, very interesting.\n"; - break; - default: - string = "That's the most interesting thing I've ever heard!\n"; - break; - } +sc_bool +lib_cmd_sing(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + + pf_buffer_string(filter, + lib_select_response(game, + "You sing a little song.\n", + "I sing a little song.\n", + "%player% sings a little song.\n")); + return TRUE; +} + +sc_bool +lib_cmd_sleep(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + + pf_buffer_string(filter, "Zzzzz. Bored are you?\n"); + return TRUE; +} + +sc_bool +lib_cmd_talk(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, string); - return TRUE; + pf_buffer_string(filter, + lib_select_response(game, + "No-one listens to your rabblings.\n", + "No-one listens to my rabblings.\n", + "No-one listens to %player%'s rabblings.\n")); + return TRUE; } sc_bool -lib_cmd_sing (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - - pf_buffer_string (filter, - lib_select_response (game, - "You sing a little song.\n", - "I sing a little song.\n", - "%player% sings a little song.\n")); - return TRUE; -} - -sc_bool -lib_cmd_sleep (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - - pf_buffer_string (filter, "Zzzzz. Bored are you?\n"); - return TRUE; -} - -sc_bool -lib_cmd_talk (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - - pf_buffer_string (filter, - lib_select_response (game, - "No-one listens to your rabblings.\n", - "No-one listens to my rabblings.\n", - "No-one listens to %player%'s rabblings.\n")); - return TRUE; -} - -sc_bool -lib_cmd_thank (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - - pf_buffer_string (filter, "You're welcome.\n"); - return TRUE; -} - -sc_bool -lib_cmd_whistle (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - - pf_buffer_string (filter, - lib_select_response (game, - "You whistle a little tune.\n", - "I whistle a little tune.\n", - "%player% whistles a little tune.\n")); - return TRUE; -} - -sc_bool -lib_cmd_interrogation (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_char *string = NULL; - - switch (sc_randomint (1, 17)) - { - case 1: - string = "Why do you want to know?\n"; - break; - case 2: - string = "Interesting question.\n"; - break; - case 3: - string = "Let me think about that one...\n"; - break; - case 4: - string = "I haven't a clue!\n"; - break; - case 5: - string = "All these questions are hurting my head.\n"; - break; - case 6: - string = "I'm not going to tell you.\n"; - break; - case 7: - string = "Someday I'll know the answer to that one.\n"; - break; - case 8: - string = "I could tell you, but then I'd have to kill you.\n"; - break; - case 9: - string = "Ha, as if I'd tell you!\n"; - break; - case 10: - string = "Ask me again later.\n"; - break; - case 11: - string = "I don't know - could you ask anyone else?\n"; - break; - case 12: - string = "Err, yes?!?\n"; - break; - case 13: - string = "Let me just check my memory banks...\n"; - break; - case 14: - string = "Because that's just the way it is.\n"; - break; - case 15: - string = "Do I ask you all sorts of awkward questions?\n"; - break; - case 16: - string = "Questions, questions...\n"; - break; - default: - string = "Who cares.\n"; - break; - } - - pf_buffer_string (filter, string); - return TRUE; -} - -sc_bool -lib_cmd_xyzzy (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - - pf_buffer_string (filter, - "I'm sorry, but XYZZY doesn't do anything special in" - " this game!\n"); - return TRUE; -} - -sc_bool -lib_cmd_egotistic (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_thank(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + + pf_buffer_string(filter, "You're welcome.\n"); + return TRUE; +} + +sc_bool +lib_cmd_whistle(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + + pf_buffer_string(filter, + lib_select_response(game, + "You whistle a little tune.\n", + "I whistle a little tune.\n", + "%player% whistles a little tune.\n")); + return TRUE; +} + +sc_bool +lib_cmd_interrogation(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_char *string = NULL; + + switch (sc_randomint(1, 17)) { + case 1: + string = "Why do you want to know?\n"; + break; + case 2: + string = "Interesting question.\n"; + break; + case 3: + string = "Let me think about that one...\n"; + break; + case 4: + string = "I haven't a clue!\n"; + break; + case 5: + string = "All these questions are hurting my head.\n"; + break; + case 6: + string = "I'm not going to tell you.\n"; + break; + case 7: + string = "Someday I'll know the answer to that one.\n"; + break; + case 8: + string = "I could tell you, but then I'd have to kill you.\n"; + break; + case 9: + string = "Ha, as if I'd tell you!\n"; + break; + case 10: + string = "Ask me again later.\n"; + break; + case 11: + string = "I don't know - could you ask anyone else?\n"; + break; + case 12: + string = "Err, yes?!?\n"; + break; + case 13: + string = "Let me just check my memory banks...\n"; + break; + case 14: + string = "Because that's just the way it is.\n"; + break; + case 15: + string = "Do I ask you all sorts of awkward questions?\n"; + break; + case 16: + string = "Questions, questions...\n"; + break; + default: + string = "Who cares.\n"; + break; + } + + pf_buffer_string(filter, string); + return TRUE; +} + +sc_bool +lib_cmd_xyzzy(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + + pf_buffer_string(filter, + "I'm sorry, but XYZZY doesn't do anything special in" + " this game!\n"); + return TRUE; +} + +sc_bool +lib_cmd_egotistic(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); #if 0 - pf_buffer_string (filter, - "Campbell wrote this Adrift Runner. It's pretty" - " good huh!\n"); + pf_buffer_string(filter, + "Campbell wrote this Adrift Runner. It's pretty" + " good huh!\n"); #else - pf_buffer_string (filter, "No comment.\n"); + pf_buffer_string(filter, "No comment.\n"); #endif - return TRUE; + return TRUE; } sc_bool -lib_cmd_yes_or_no (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_yes_or_no(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, - "That's interesting, but it doesn't mean much.\n"); - return TRUE; + pf_buffer_string(filter, + "That's interesting, but it doesn't mean much.\n"); + return TRUE; } @@ -10039,56 +9168,53 @@ lib_cmd_yes_or_no (sc_gameref_t game) * Malformed and rhetorical question responses. */ sc_bool -lib_cmd_ask_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int npc; - sc_bool is_ambiguous; +lib_cmd_ask_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int npc; + sc_bool is_ambiguous; - /* Get the referenced npc, and if none, consider complete. */ - npc = lib_disambiguate_npc (game, "ask", &is_ambiguous); - if (npc == -1) - return is_ambiguous; + /* Get the referenced npc, and if none, consider complete. */ + npc = lib_disambiguate_npc(game, "ask", &is_ambiguous); + if (npc == -1) + return is_ambiguous; - /* Incomplete ask command, so offer help and return. */ - pf_buffer_string (filter, "Use the format \"ask "); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, " about [subject]\".\n"); - return TRUE; + /* Incomplete ask command, so offer help and return. */ + pf_buffer_string(filter, "Use the format \"ask "); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, " about [subject]\".\n"); + return TRUE; } sc_bool -lib_cmd_ask_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; +lib_cmd_ask_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; - /* Get the referenced object, and if none, consider complete. */ - object = lib_disambiguate_object (game, "ask", &is_ambiguous); - if (object == -1) - return is_ambiguous; + /* Get the referenced object, and if none, consider complete. */ + object = lib_disambiguate_object(game, "ask", &is_ambiguous); + if (object == -1) + return is_ambiguous; - /* No reply. */ - pf_buffer_string (filter, - lib_select_response (game, - "You get no reply from ", - "I get no reply from ", - "%player% gets no reply from ")); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; + /* No reply. */ + pf_buffer_string(filter, + lib_select_response(game, + "You get no reply from ", + "I get no reply from ", + "%player% gets no reply from ")); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } sc_bool -lib_cmd_ask_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_ask_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - /* Incomplete ask command, so offer help and return. */ - pf_buffer_string (filter, - "Use the format \"ask [character] about [subject]\".\n"); - return TRUE; + /* Incomplete ask command, so offer help and return. */ + pf_buffer_string(filter, + "Use the format \"ask [character] about [subject]\".\n"); + return TRUE; } @@ -10098,12 +9224,11 @@ lib_cmd_ask_other (sc_gameref_t game) * Uninteresting kill message when no weaponry is involved. */ sc_bool -lib_cmd_kill_other (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_cmd_kill_other(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, "Now that isn't very nice.\n"); - return TRUE; + pf_buffer_string(filter, "Now that isn't very nice.\n"); + return TRUE; } @@ -10116,82 +9241,77 @@ lib_cmd_kill_other (sc_gameref_t game) * uninteresting responses. */ static sc_bool -lib_nothing_happens_common (sc_gameref_t game, - const sc_char *verb_general, - const sc_char *verb_third_person, - sc_bool is_object) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_int perspective, object; - const sc_char *person, *verb; - sc_bool is_ambiguous; - - /* Use person and verb tense according to perspective. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "Perspective"; - perspective = prop_get_integer (bundle, "I<-ss", vt_key); - switch (perspective) - { - case LIB_FIRST_PERSON: - person = "I "; - verb = verb_general; - break; - case LIB_SECOND_PERSON: - person = "You "; - verb = verb_general; - break; - case LIB_THIRD_PERSON: - person = "%player% "; - verb = verb_third_person; - break; - default: - sc_error ("lib_nothing_happens: unknown perspective, %ld\n", perspective); - person = "You "; - verb = verb_general; - break; - } - - /* If the command target was not an object, end it here. */ - if (!is_object) - { - pf_buffer_string (filter, person); - pf_buffer_string (filter, verb); - pf_buffer_string (filter, ", but nothing happens.\n"); - return TRUE; - } - - /* Get the referenced object. If none, return immediately. */ - object = lib_disambiguate_object (game, verb_general, &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Nothing happens. */ - pf_buffer_string (filter, person); - pf_buffer_string (filter, verb); - pf_buffer_character (filter, ' '); - lib_print_object_np (game, object); - pf_buffer_string (filter, ", but nothing happens.\n"); - return TRUE; +lib_nothing_happens_common(sc_gameref_t game, + const sc_char *verb_general, + const sc_char *verb_third_person, + sc_bool is_object) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_int perspective, object; + const sc_char *person, *verb; + sc_bool is_ambiguous; + + /* Use person and verb tense according to perspective. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "Perspective"; + perspective = prop_get_integer(bundle, "I<-ss", vt_key); + switch (perspective) { + case LIB_FIRST_PERSON: + person = "I "; + verb = verb_general; + break; + case LIB_SECOND_PERSON: + person = "You "; + verb = verb_general; + break; + case LIB_THIRD_PERSON: + person = "%player% "; + verb = verb_third_person; + break; + default: + sc_error("lib_nothing_happens: unknown perspective, %ld\n", perspective); + person = "You "; + verb = verb_general; + break; + } + + /* If the command target was not an object, end it here. */ + if (!is_object) { + pf_buffer_string(filter, person); + pf_buffer_string(filter, verb); + pf_buffer_string(filter, ", but nothing happens.\n"); + return TRUE; + } + + /* Get the referenced object. If none, return immediately. */ + object = lib_disambiguate_object(game, verb_general, &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Nothing happens. */ + pf_buffer_string(filter, person); + pf_buffer_string(filter, verb); + pf_buffer_character(filter, ' '); + lib_print_object_np(game, object); + pf_buffer_string(filter, ", but nothing happens.\n"); + return TRUE; } static sc_bool -lib_nothing_happens_object (sc_gameref_t game, - const sc_char *verb_general, - const sc_char *verb_third_person) -{ - return lib_nothing_happens_common (game, - verb_general, verb_third_person, TRUE); +lib_nothing_happens_object(sc_gameref_t game, + const sc_char *verb_general, + const sc_char *verb_third_person) { + return lib_nothing_happens_common(game, + verb_general, verb_third_person, TRUE); } static sc_bool -lib_nothing_happens_other (sc_gameref_t game, - const sc_char *verb_general, - const sc_char *verb_third_person) -{ - return lib_nothing_happens_common (game, - verb_general, verb_third_person, FALSE); +lib_nothing_happens_other(sc_gameref_t game, + const sc_char *verb_general, + const sc_char *verb_third_person) { + return lib_nothing_happens_common(game, + verb_general, verb_third_person, FALSE); } @@ -10201,75 +9321,63 @@ lib_nothing_happens_other (sc_gameref_t game, * Shake, rattle and roll, and assorted nothing-happens handlers. */ sc_bool -lib_cmd_hit_object (sc_gameref_t game) -{ - return lib_nothing_happens_object (game, "hit", "hits"); +lib_cmd_hit_object(sc_gameref_t game) { + return lib_nothing_happens_object(game, "hit", "hits"); } sc_bool -lib_cmd_kick_object (sc_gameref_t game) -{ - return lib_nothing_happens_object (game, "kick", "kicks"); +lib_cmd_kick_object(sc_gameref_t game) { + return lib_nothing_happens_object(game, "kick", "kicks"); } sc_bool -lib_cmd_press_object (sc_gameref_t game) -{ - return lib_nothing_happens_object (game, "press", "presses"); +lib_cmd_press_object(sc_gameref_t game) { + return lib_nothing_happens_object(game, "press", "presses"); } sc_bool -lib_cmd_push_object (sc_gameref_t game) -{ - return lib_nothing_happens_object (game, "push", "pushes"); +lib_cmd_push_object(sc_gameref_t game) { + return lib_nothing_happens_object(game, "push", "pushes"); } sc_bool -lib_cmd_pull_object (sc_gameref_t game) -{ - return lib_nothing_happens_object (game, "pull", "pulls"); +lib_cmd_pull_object(sc_gameref_t game) { + return lib_nothing_happens_object(game, "pull", "pulls"); } sc_bool -lib_cmd_shake_object (sc_gameref_t game) -{ - return lib_nothing_happens_object (game, "shake", "shakes"); +lib_cmd_shake_object(sc_gameref_t game) { + return lib_nothing_happens_object(game, "shake", "shakes"); } sc_bool -lib_cmd_hit_other (sc_gameref_t game) -{ - return lib_nothing_happens_other (game, "hit", "hits"); +lib_cmd_hit_other(sc_gameref_t game) { + return lib_nothing_happens_other(game, "hit", "hits"); } sc_bool -lib_cmd_kick_other (sc_gameref_t game) -{ - return lib_nothing_happens_other (game, "kick", "kicks"); +lib_cmd_kick_other(sc_gameref_t game) { + return lib_nothing_happens_other(game, "kick", "kicks"); } sc_bool -lib_cmd_press_other (sc_gameref_t game) -{ - return lib_nothing_happens_other (game, "press", "presses"); +lib_cmd_press_other(sc_gameref_t game) { + return lib_nothing_happens_other(game, "press", "presses"); } sc_bool -lib_cmd_push_other (sc_gameref_t game) -{ - return lib_nothing_happens_other (game, "push", "pushes"); +lib_cmd_push_other(sc_gameref_t game) { + return lib_nothing_happens_other(game, "push", "pushes"); } sc_bool -lib_cmd_pull_other (sc_gameref_t game) -{ - return lib_nothing_happens_other (game, "pull", "pulls"); +lib_cmd_pull_other(sc_gameref_t game) { + return lib_nothing_happens_other(game, "pull", "pulls"); } sc_bool -lib_cmd_shake_other (sc_gameref_t game) -{ - return lib_nothing_happens_other (game, "shake", "shakes"); +lib_cmd_shake_other(sc_gameref_t game) { + return lib_nothing_happens_other(game, "shake", "shakes"); } @@ -10282,52 +9390,48 @@ lib_cmd_shake_other (sc_gameref_t game) * ing responses. */ static sc_bool -lib_cant_do_common (sc_gameref_t game, - const sc_char *verb, sc_bool is_object) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; - - /* If the target is not an object, end it here. */ - if (!is_object) - { - pf_buffer_string (filter, - lib_select_response (game, - "You can't ", - "I can't ", "%player% can't ")); - pf_buffer_string (filter, verb); - pf_buffer_string (filter, " that.\n"); - return TRUE; - } - - /* Get the referenced object. If none, return immediately. */ - object = lib_disambiguate_object (game, verb, &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Whatever it is, don't do it. */ - pf_buffer_string (filter, - lib_select_response (game, - "You can't ", - "I can't ", "%player% can't ")); - pf_buffer_string (filter, verb); - pf_buffer_character (filter, ' '); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; +lib_cant_do_common(sc_gameref_t game, + const sc_char *verb, sc_bool is_object) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; + + /* If the target is not an object, end it here. */ + if (!is_object) { + pf_buffer_string(filter, + lib_select_response(game, + "You can't ", + "I can't ", "%player% can't ")); + pf_buffer_string(filter, verb); + pf_buffer_string(filter, " that.\n"); + return TRUE; + } + + /* Get the referenced object. If none, return immediately. */ + object = lib_disambiguate_object(game, verb, &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Whatever it is, don't do it. */ + pf_buffer_string(filter, + lib_select_response(game, + "You can't ", + "I can't ", "%player% can't ")); + pf_buffer_string(filter, verb); + pf_buffer_character(filter, ' '); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } static sc_bool -lib_cant_do_object (sc_gameref_t game, const sc_char *verb) -{ - return lib_cant_do_common (game, verb, TRUE); +lib_cant_do_object(sc_gameref_t game, const sc_char *verb) { + return lib_cant_do_common(game, verb, TRUE); } static sc_bool -lib_cant_do_other (sc_gameref_t game, const sc_char *verb) -{ - return lib_cant_do_common (game, verb, FALSE); +lib_cant_do_other(sc_gameref_t game, const sc_char *verb) { + return lib_cant_do_common(game, verb, FALSE); } @@ -10337,219 +9441,183 @@ lib_cant_do_other (sc_gameref_t game, const sc_char *verb) * Assorted can't-do messages. */ sc_bool -lib_cmd_block_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "block"); +lib_cmd_block_object(sc_gameref_t game) { + return lib_cant_do_object(game, "block"); } sc_bool -lib_cmd_climb_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "climb"); +lib_cmd_climb_object(sc_gameref_t game) { + return lib_cant_do_object(game, "climb"); } sc_bool -lib_cmd_clean_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "clean"); +lib_cmd_clean_object(sc_gameref_t game) { + return lib_cant_do_object(game, "clean"); } sc_bool -lib_cmd_cut_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "cut"); +lib_cmd_cut_object(sc_gameref_t game) { + return lib_cant_do_object(game, "cut"); } sc_bool -lib_cmd_drink_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "drink"); +lib_cmd_drink_object(sc_gameref_t game) { + return lib_cant_do_object(game, "drink"); } sc_bool -lib_cmd_light_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "light"); +lib_cmd_light_object(sc_gameref_t game) { + return lib_cant_do_object(game, "light"); } sc_bool -lib_cmd_lift_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "lift"); +lib_cmd_lift_object(sc_gameref_t game) { + return lib_cant_do_object(game, "lift"); } sc_bool -lib_cmd_move_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "move"); +lib_cmd_move_object(sc_gameref_t game) { + return lib_cant_do_object(game, "move"); } sc_bool -lib_cmd_rub_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "rub"); +lib_cmd_rub_object(sc_gameref_t game) { + return lib_cant_do_object(game, "rub"); } sc_bool -lib_cmd_stop_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "stop"); +lib_cmd_stop_object(sc_gameref_t game) { + return lib_cant_do_object(game, "stop"); } sc_bool -lib_cmd_suck_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "suck"); +lib_cmd_suck_object(sc_gameref_t game) { + return lib_cant_do_object(game, "suck"); } sc_bool -lib_cmd_touch_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "touch"); +lib_cmd_touch_object(sc_gameref_t game) { + return lib_cant_do_object(game, "touch"); } sc_bool -lib_cmd_turn_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "turn"); +lib_cmd_turn_object(sc_gameref_t game) { + return lib_cant_do_object(game, "turn"); } sc_bool -lib_cmd_unblock_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "unblock"); +lib_cmd_unblock_object(sc_gameref_t game) { + return lib_cant_do_object(game, "unblock"); } sc_bool -lib_cmd_wash_object (sc_gameref_t game) -{ - return lib_cant_do_object (game, "wash"); +lib_cmd_wash_object(sc_gameref_t game) { + return lib_cant_do_object(game, "wash"); } sc_bool -lib_cmd_block_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "block"); +lib_cmd_block_other(sc_gameref_t game) { + return lib_cant_do_other(game, "block"); } sc_bool -lib_cmd_climb_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "climb"); +lib_cmd_climb_other(sc_gameref_t game) { + return lib_cant_do_other(game, "climb"); } sc_bool -lib_cmd_clean_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "clean"); +lib_cmd_clean_other(sc_gameref_t game) { + return lib_cant_do_other(game, "clean"); } sc_bool -lib_cmd_close_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "close"); +lib_cmd_close_other(sc_gameref_t game) { + return lib_cant_do_other(game, "close"); } sc_bool -lib_cmd_lock_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "lock"); +lib_cmd_lock_other(sc_gameref_t game) { + return lib_cant_do_other(game, "lock"); } sc_bool -lib_cmd_unlock_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "unlock"); +lib_cmd_unlock_other(sc_gameref_t game) { + return lib_cant_do_other(game, "unlock"); } sc_bool -lib_cmd_stand_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "stand on"); +lib_cmd_stand_other(sc_gameref_t game) { + return lib_cant_do_other(game, "stand on"); } sc_bool -lib_cmd_sit_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "sit on"); +lib_cmd_sit_other(sc_gameref_t game) { + return lib_cant_do_other(game, "sit on"); } sc_bool -lib_cmd_lie_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "lie on"); +lib_cmd_lie_other(sc_gameref_t game) { + return lib_cant_do_other(game, "lie on"); } sc_bool -lib_cmd_cut_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "cut"); +lib_cmd_cut_other(sc_gameref_t game) { + return lib_cant_do_other(game, "cut"); } sc_bool -lib_cmd_drink_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "drink"); +lib_cmd_drink_other(sc_gameref_t game) { + return lib_cant_do_other(game, "drink"); } sc_bool -lib_cmd_lift_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "lift"); +lib_cmd_lift_other(sc_gameref_t game) { + return lib_cant_do_other(game, "lift"); } sc_bool -lib_cmd_light_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "light"); +lib_cmd_light_other(sc_gameref_t game) { + return lib_cant_do_other(game, "light"); } sc_bool -lib_cmd_move_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "move"); +lib_cmd_move_other(sc_gameref_t game) { + return lib_cant_do_other(game, "move"); } sc_bool -lib_cmd_stop_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "stop"); +lib_cmd_stop_other(sc_gameref_t game) { + return lib_cant_do_other(game, "stop"); } sc_bool -lib_cmd_rub_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "rub"); +lib_cmd_rub_other(sc_gameref_t game) { + return lib_cant_do_other(game, "rub"); } sc_bool -lib_cmd_suck_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "suck"); +lib_cmd_suck_other(sc_gameref_t game) { + return lib_cant_do_other(game, "suck"); } sc_bool -lib_cmd_turn_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "turn"); +lib_cmd_turn_other(sc_gameref_t game) { + return lib_cant_do_other(game, "turn"); } sc_bool -lib_cmd_touch_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "touch"); +lib_cmd_touch_other(sc_gameref_t game) { + return lib_cant_do_other(game, "touch"); } sc_bool -lib_cmd_unblock_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "unblock"); +lib_cmd_unblock_other(sc_gameref_t game) { + return lib_cant_do_other(game, "unblock"); } sc_bool -lib_cmd_wash_other (sc_gameref_t game) -{ - return lib_cant_do_other (game, "wash"); +lib_cmd_wash_other(sc_gameref_t game) { + return lib_cant_do_other(game, "wash"); } @@ -10562,50 +9630,46 @@ lib_cmd_wash_other (sc_gameref_t game) * uninteresting responses. */ static sc_bool -lib_dont_think_common (sc_gameref_t game, - const sc_char *verb, sc_bool is_object) -{ - const sc_filterref_t filter = gs_get_filter (game); - sc_int object; - sc_bool is_ambiguous; - - /* If the target is not an object, end it here. */ - if (!is_object) - { - pf_buffer_string (filter, - lib_select_response (game, - "I don't think you can ", - "I don't think I can ", - "I don't think %player% can ")); - pf_buffer_string (filter, verb); - pf_buffer_string (filter, " that.\n"); - return TRUE; - } - - /* Get the referenced object. If none, return immediately. */ - object = lib_disambiguate_object (game, verb, &is_ambiguous); - if (object == -1) - return is_ambiguous; - - /* Whatever it is, don't do it. */ - pf_buffer_string (filter, "I don't think you can "); - pf_buffer_string (filter, verb); - pf_buffer_character (filter, ' '); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; +lib_dont_think_common(sc_gameref_t game, + const sc_char *verb, sc_bool is_object) { + const sc_filterref_t filter = gs_get_filter(game); + sc_int object; + sc_bool is_ambiguous; + + /* If the target is not an object, end it here. */ + if (!is_object) { + pf_buffer_string(filter, + lib_select_response(game, + "I don't think you can ", + "I don't think I can ", + "I don't think %player% can ")); + pf_buffer_string(filter, verb); + pf_buffer_string(filter, " that.\n"); + return TRUE; + } + + /* Get the referenced object. If none, return immediately. */ + object = lib_disambiguate_object(game, verb, &is_ambiguous); + if (object == -1) + return is_ambiguous; + + /* Whatever it is, don't do it. */ + pf_buffer_string(filter, "I don't think you can "); + pf_buffer_string(filter, verb); + pf_buffer_character(filter, ' '); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; } static sc_bool -lib_dont_think_object (sc_gameref_t game, const sc_char *verb) -{ - return lib_dont_think_common (game, verb, TRUE); +lib_dont_think_object(sc_gameref_t game, const sc_char *verb) { + return lib_dont_think_common(game, verb, TRUE); } static sc_bool -lib_dont_think_other (sc_gameref_t game, const sc_char *verb) -{ - return lib_dont_think_common (game, verb, FALSE); +lib_dont_think_other(sc_gameref_t game, const sc_char *verb) { + return lib_dont_think_common(game, verb, FALSE); } @@ -10615,39 +9679,33 @@ lib_dont_think_other (sc_gameref_t game, const sc_char *verb) * Assorted don't-think messages. */ sc_bool -lib_cmd_fix_object (sc_gameref_t game) -{ - return lib_dont_think_object (game, "fix"); +lib_cmd_fix_object(sc_gameref_t game) { + return lib_dont_think_object(game, "fix"); } sc_bool -lib_cmd_mend_object (sc_gameref_t game) -{ - return lib_dont_think_object (game, "mend"); +lib_cmd_mend_object(sc_gameref_t game) { + return lib_dont_think_object(game, "mend"); } sc_bool -lib_cmd_repair_object (sc_gameref_t game) -{ - return lib_dont_think_object (game, "repair"); +lib_cmd_repair_object(sc_gameref_t game) { + return lib_dont_think_object(game, "repair"); } sc_bool -lib_cmd_fix_other (sc_gameref_t game) -{ - return lib_dont_think_other (game, "fix"); +lib_cmd_fix_other(sc_gameref_t game) { + return lib_dont_think_other(game, "fix"); } sc_bool -lib_cmd_mend_other (sc_gameref_t game) -{ - return lib_dont_think_other (game, "mend"); +lib_cmd_mend_other(sc_gameref_t game) { + return lib_dont_think_other(game, "mend"); } sc_bool -lib_cmd_repair_other (sc_gameref_t game) -{ - return lib_dont_think_other (game, "repair"); +lib_cmd_repair_other(sc_gameref_t game) { + return lib_dont_think_other(game, "repair"); } @@ -10657,13 +9715,12 @@ lib_cmd_repair_other (sc_gameref_t game) * Central handler for doing something, but unsure to what. */ static sc_bool -lib_what (sc_gameref_t game, const sc_char *verb) -{ - const sc_filterref_t filter = gs_get_filter (game); +lib_what(sc_gameref_t game, const sc_char *verb) { + const sc_filterref_t filter = gs_get_filter(game); - pf_buffer_string (filter, verb); - pf_buffer_string (filter, " what?\n"); - return TRUE; + pf_buffer_string(filter, verb); + pf_buffer_string(filter, " what?\n"); + return TRUE; } @@ -10673,225 +9730,188 @@ lib_what (sc_gameref_t game, const sc_char *verb) * Assorted "what?" messages. */ sc_bool -lib_cmd_block_what (sc_gameref_t game) -{ - return lib_what (game, "Block"); +lib_cmd_block_what(sc_gameref_t game) { + return lib_what(game, "Block"); } sc_bool -lib_cmd_break_what (sc_gameref_t game) -{ - return lib_what (game, "Break"); +lib_cmd_break_what(sc_gameref_t game) { + return lib_what(game, "Break"); } sc_bool -lib_cmd_destroy_what (sc_gameref_t game) -{ - return lib_what (game, "Destroy"); +lib_cmd_destroy_what(sc_gameref_t game) { + return lib_what(game, "Destroy"); } sc_bool -lib_cmd_smash_what (sc_gameref_t game) -{ - return lib_what (game, "Smash"); +lib_cmd_smash_what(sc_gameref_t game) { + return lib_what(game, "Smash"); } sc_bool -lib_cmd_buy_what (sc_gameref_t game) -{ - return lib_what (game, "Buy"); +lib_cmd_buy_what(sc_gameref_t game) { + return lib_what(game, "Buy"); } sc_bool -lib_cmd_clean_what (sc_gameref_t game) -{ - return lib_what (game, "Clean"); +lib_cmd_clean_what(sc_gameref_t game) { + return lib_what(game, "Clean"); } sc_bool -lib_cmd_climb_what (sc_gameref_t game) -{ - return lib_what (game, "Climb"); +lib_cmd_climb_what(sc_gameref_t game) { + return lib_what(game, "Climb"); } sc_bool -lib_cmd_cut_what (sc_gameref_t game) -{ - return lib_what (game, "Cut"); +lib_cmd_cut_what(sc_gameref_t game) { + return lib_what(game, "Cut"); } sc_bool -lib_cmd_drink_what (sc_gameref_t game) -{ - return lib_what (game, "Drink"); +lib_cmd_drink_what(sc_gameref_t game) { + return lib_what(game, "Drink"); } sc_bool -lib_cmd_fix_what (sc_gameref_t game) -{ - return lib_what (game, "Fix"); +lib_cmd_fix_what(sc_gameref_t game) { + return lib_what(game, "Fix"); } sc_bool -lib_cmd_hit_what (sc_gameref_t game) -{ - return lib_what (game, "Hit"); +lib_cmd_hit_what(sc_gameref_t game) { + return lib_what(game, "Hit"); } sc_bool -lib_cmd_kick_what (sc_gameref_t game) -{ - return lib_what (game, "Kick"); +lib_cmd_kick_what(sc_gameref_t game) { + return lib_what(game, "Kick"); } sc_bool -lib_cmd_light_what (sc_gameref_t game) -{ - return lib_what (game, "Light"); +lib_cmd_light_what(sc_gameref_t game) { + return lib_what(game, "Light"); } sc_bool -lib_cmd_lift_what (sc_gameref_t game) -{ - return lib_what (game, "Lift"); +lib_cmd_lift_what(sc_gameref_t game) { + return lib_what(game, "Lift"); } sc_bool -lib_cmd_mend_what (sc_gameref_t game) -{ - return lib_what (game, "Mend"); +lib_cmd_mend_what(sc_gameref_t game) { + return lib_what(game, "Mend"); } sc_bool -lib_cmd_move_what (sc_gameref_t game) -{ - return lib_what (game, "Move"); +lib_cmd_move_what(sc_gameref_t game) { + return lib_what(game, "Move"); } sc_bool -lib_cmd_press_what (sc_gameref_t game) -{ - return lib_what (game, "Press"); +lib_cmd_press_what(sc_gameref_t game) { + return lib_what(game, "Press"); } sc_bool -lib_cmd_pull_what (sc_gameref_t game) -{ - return lib_what (game, "Pull"); +lib_cmd_pull_what(sc_gameref_t game) { + return lib_what(game, "Pull"); } sc_bool -lib_cmd_push_what (sc_gameref_t game) -{ - return lib_what (game, "Push"); +lib_cmd_push_what(sc_gameref_t game) { + return lib_what(game, "Push"); } sc_bool -lib_cmd_repair_what (sc_gameref_t game) -{ - return lib_what (game, "Repair"); +lib_cmd_repair_what(sc_gameref_t game) { + return lib_what(game, "Repair"); } sc_bool -lib_cmd_sell_what (sc_gameref_t game) -{ - return lib_what (game, "Sell"); +lib_cmd_sell_what(sc_gameref_t game) { + return lib_what(game, "Sell"); } sc_bool -lib_cmd_shake_what (sc_gameref_t game) -{ - return lib_what (game, "Shake"); +lib_cmd_shake_what(sc_gameref_t game) { + return lib_what(game, "Shake"); } sc_bool -lib_cmd_rub_what (sc_gameref_t game) -{ - return lib_what (game, "Rub"); +lib_cmd_rub_what(sc_gameref_t game) { + return lib_what(game, "Rub"); } sc_bool -lib_cmd_stop_what (sc_gameref_t game) -{ - return lib_what (game, "Stop"); +lib_cmd_stop_what(sc_gameref_t game) { + return lib_what(game, "Stop"); } sc_bool -lib_cmd_suck_what (sc_gameref_t game) -{ - return lib_what (game, "Suck"); +lib_cmd_suck_what(sc_gameref_t game) { + return lib_what(game, "Suck"); } sc_bool -lib_cmd_touch_what (sc_gameref_t game) -{ - return lib_what (game, "Touch"); +lib_cmd_touch_what(sc_gameref_t game) { + return lib_what(game, "Touch"); } sc_bool -lib_cmd_turn_what (sc_gameref_t game) -{ - return lib_what (game, "Turn"); +lib_cmd_turn_what(sc_gameref_t game) { + return lib_what(game, "Turn"); } sc_bool -lib_cmd_unblock_what (sc_gameref_t game) -{ - return lib_what (game, "Unblock"); +lib_cmd_unblock_what(sc_gameref_t game) { + return lib_what(game, "Unblock"); } sc_bool -lib_cmd_wash_what (sc_gameref_t game) -{ - return lib_what (game, "Wash"); +lib_cmd_wash_what(sc_gameref_t game) { + return lib_what(game, "Wash"); } sc_bool -lib_cmd_drop_what (sc_gameref_t game) -{ - return lib_what (game, "Drop"); +lib_cmd_drop_what(sc_gameref_t game) { + return lib_what(game, "Drop"); } sc_bool -lib_cmd_get_what (sc_gameref_t game) -{ - return lib_what (game, "Take"); +lib_cmd_get_what(sc_gameref_t game) { + return lib_what(game, "Take"); } sc_bool -lib_cmd_give_what (sc_gameref_t game) -{ - return lib_what (game, "Give"); +lib_cmd_give_what(sc_gameref_t game) { + return lib_what(game, "Give"); } sc_bool -lib_cmd_open_what (sc_gameref_t game) -{ - return lib_what (game, "Open"); +lib_cmd_open_what(sc_gameref_t game) { + return lib_what(game, "Open"); } sc_bool -lib_cmd_remove_what (sc_gameref_t game) -{ - return lib_what (game, "Remove"); +lib_cmd_remove_what(sc_gameref_t game) { + return lib_what(game, "Remove"); } sc_bool -lib_cmd_wear_what (sc_gameref_t game) -{ - return lib_what (game, "Wear"); +lib_cmd_wear_what(sc_gameref_t game) { + return lib_what(game, "Wear"); } sc_bool -lib_cmd_lock_what (sc_gameref_t game) -{ - return lib_what (game, "Lock"); +lib_cmd_lock_what(sc_gameref_t game) { + return lib_what(game, "Lock"); } sc_bool -lib_cmd_unlock_what (sc_gameref_t game) -{ - return lib_what (game, "Unlock"); +lib_cmd_unlock_what(sc_gameref_t game) { + return lib_what(game, "Unlock"); } @@ -10902,69 +9922,63 @@ lib_cmd_unlock_what (sc_gameref_t game) * Handlers for unrecognized verbs with known object/NPC. */ sc_bool -lib_cmd_verb_object (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int count, object, index_; - - /* Ensure the reference is unambiguous. */ - count = 0; - object = -1; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (game->object_references[index_] - && gs_object_seen (game, index_) - && obj_indirectly_in_room (game, index_, gs_playerroom (game))) - { - count++; - object = index_; - } - } - if (count != 1) - return FALSE; - - /* Save in variables. */ - var_set_ref_object (vars, object); - - /* Print don't understand message. */ - pf_buffer_string (filter, "I don't understand what you want me to do with "); - lib_print_object_np (game, object); - pf_buffer_string (filter, ".\n"); - return TRUE; -} - -sc_bool -lib_cmd_verb_npc (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int count, npc, index_; - - /* Ensure the reference is unambiguous. */ - count = 0; - npc = -1; - for (index_ = 0; index_ < gs_npc_count (game); index_++) - { - if (game->npc_references[index_] - && gs_npc_seen (game, index_) - && npc_in_room (game, index_, gs_playerroom (game))) - { - count++; - npc = index_; - } - } - if (count != 1) - return FALSE; - - /* Save in variables. */ - var_set_ref_character (vars, npc); - - /* Print don't understand message; unlike objects, there's no "me" here. */ - pf_buffer_string (filter, "I don't understand what you want to do with "); - lib_print_npc_np (game, npc); - pf_buffer_string (filter, ".\n"); - return TRUE; +lib_cmd_verb_object(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int count, object, index_; + + /* Ensure the reference is unambiguous. */ + count = 0; + object = -1; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (game->object_references[index_] + && gs_object_seen(game, index_) + && obj_indirectly_in_room(game, index_, gs_playerroom(game))) { + count++; + object = index_; + } + } + if (count != 1) + return FALSE; + + /* Save in variables. */ + var_set_ref_object(vars, object); + + /* Print don't understand message. */ + pf_buffer_string(filter, "I don't understand what you want me to do with "); + lib_print_object_np(game, object); + pf_buffer_string(filter, ".\n"); + return TRUE; +} + +sc_bool +lib_cmd_verb_npc(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int count, npc, index_; + + /* Ensure the reference is unambiguous. */ + count = 0; + npc = -1; + for (index_ = 0; index_ < gs_npc_count(game); index_++) { + if (game->npc_references[index_] + && gs_npc_seen(game, index_) + && npc_in_room(game, index_, gs_playerroom(game))) { + count++; + npc = index_; + } + } + if (count != 1) + return FALSE; + + /* Save in variables. */ + var_set_ref_character(vars, npc); + + /* Print don't understand message; unlike objects, there's no "me" here. */ + pf_buffer_string(filter, "I don't understand what you want to do with "); + lib_print_npc_np(game, npc); + pf_buffer_string(filter, ".\n"); + return TRUE; } @@ -10974,9 +9988,8 @@ lib_cmd_verb_npc (sc_gameref_t game) * Set library tracing on/off. */ void -lib_debug_trace (sc_bool flag) -{ - lib_trace = flag; +lib_debug_trace(sc_bool flag) { + lib_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sclocale.cpp b/engines/glk/adrift/sclocale.cpp index 25cf4ed065..b201b7faa4 100644 --- a/engines/glk/adrift/sclocale.cpp +++ b/engines/glk/adrift/sclocale.cpp @@ -51,27 +51,23 @@ enum { TABLE_SIZE = 256 }; * inclusive to TRUE, and iterate this on a ranges array. */ static void -loc_setrange_bool (sc_int start, sc_int end, sc_bool table[]) -{ - sc_int index_; - - for (index_ = start; index_ <= end; index_++) - { - assert (index_ > -1 && index_ < TABLE_SIZE); - table[index_] = TRUE; - } +loc_setrange_bool(sc_int start, sc_int end, sc_bool table[]) { + sc_int index_; + + for (index_ = start; index_ <= end; index_++) { + assert(index_ > -1 && index_ < TABLE_SIZE); + table[index_] = TRUE; + } } static void -loc_setranges_bool (const sc_int ranges[], sc_bool table[]) -{ - sc_int index_; - - for (index_ = 0; ranges[index_] > -1; index_ += 2) - { - assert (ranges[index_] <= ranges[index_ + 1]); - loc_setrange_bool (ranges[index_], ranges[index_ + 1], table); - } +loc_setranges_bool(const sc_int ranges[], sc_bool table[]) { + sc_int index_; + + for (index_ = 0; ranges[index_] > -1; index_ += 2) { + assert(ranges[index_] <= ranges[index_ + 1]); + loc_setrange_bool(ranges[index_], ranges[index_ + 1], table); + } } @@ -84,29 +80,25 @@ loc_setranges_bool (const sc_int ranges[], sc_bool table[]) * this on a ranges array. */ static void -loc_setrange_char (sc_int start, sc_int end, sc_int offset, sc_char table[]) -{ - sc_int index_; - - for (index_ = start; index_ <= end; index_++) - { - assert (index_ > -1 && index_ < TABLE_SIZE); - assert (index_ + offset > -1 && index_ + offset < TABLE_SIZE); - table[index_] = index_ + offset; - } +loc_setrange_char(sc_int start, sc_int end, sc_int offset, sc_char table[]) { + sc_int index_; + + for (index_ = start; index_ <= end; index_++) { + assert(index_ > -1 && index_ < TABLE_SIZE); + assert(index_ + offset > -1 && index_ + offset < TABLE_SIZE); + table[index_] = index_ + offset; + } } static void -loc_setranges_char (const sc_int ranges[], sc_char table[]) -{ - sc_int index_; - - for (index_ = 0; ranges[index_] > -1; index_ += 3) - { - assert (ranges[index_] <= ranges[index_ + 1]); - loc_setrange_char (ranges[index_], - ranges[index_ + 1], ranges[index_ + 2], table); - } +loc_setranges_char(const sc_int ranges[], sc_char table[]) { + sc_int index_; + + for (index_ = 0; ranges[index_] > -1; index_ += 3) { + assert(ranges[index_] <= ranges[index_ + 1]); + loc_setrange_char(ranges[index_], + ranges[index_ + 1], ranges[index_ + 2], table); + } } @@ -117,15 +109,14 @@ loc_setranges_char (const sc_int ranges[], sc_char table[]) */ enum { RANGES_LENGTH = 32 }; enum { SIGNATURE_COUNT = 24, SIGNATURE_LENGTH = 3 }; -typedef struct -{ - const sc_char *const name; - const sc_int isspace_ranges[RANGES_LENGTH]; - const sc_int isdigit_ranges[RANGES_LENGTH]; - const sc_int isalpha_ranges[RANGES_LENGTH]; - const sc_int toupper_ranges[RANGES_LENGTH]; - const sc_int tolower_ranges[RANGES_LENGTH]; - const sc_byte signature[SIGNATURE_COUNT][SIGNATURE_LENGTH]; +typedef struct { + const sc_char *const name; + const sc_int isspace_ranges[RANGES_LENGTH]; + const sc_int isdigit_ranges[RANGES_LENGTH]; + const sc_int isalpha_ranges[RANGES_LENGTH]; + const sc_int toupper_ranges[RANGES_LENGTH]; + const sc_int tolower_ranges[RANGES_LENGTH]; + const sc_byte signature[SIGNATURE_COUNT][SIGNATURE_LENGTH]; } sc_locale_t; @@ -135,14 +126,13 @@ typedef struct * table, for synchronization with changed locales. This is the dynamic data * portion of a locale. */ -typedef struct -{ - const sc_locale_t *locale; - sc_bool isspace[TABLE_SIZE]; - sc_bool isdigit[TABLE_SIZE]; - sc_bool isalpha[TABLE_SIZE]; - sc_char toupper[TABLE_SIZE]; - sc_char tolower[TABLE_SIZE]; +typedef struct { + const sc_locale_t *locale; + sc_bool isspace[TABLE_SIZE]; + sc_bool isdigit[TABLE_SIZE]; + sc_bool isalpha[TABLE_SIZE]; + sc_char toupper[TABLE_SIZE]; + sc_char tolower[TABLE_SIZE]; } sc_locale_table_t; /* @@ -160,26 +150,24 @@ static sc_locale_table_t loc_locale_tables = {NULL, {0}, {0}, {0}, {0}, {0}}; * and if not for the same locale, (re-)initialize. */ static void -loc_synchronize_tables (const sc_locale_t *locale) -{ - /* Clear all tables and the locale pointer. */ - memset (&loc_locale_tables, 0, sizeof (loc_locale_tables)); - - /* Set ranges and attach the new locale. */ - loc_setranges_bool (locale->isspace_ranges, loc_locale_tables.isspace); - loc_setranges_bool (locale->isdigit_ranges, loc_locale_tables.isdigit); - loc_setranges_bool (locale->isalpha_ranges, loc_locale_tables.isalpha); - loc_setranges_char (locale->toupper_ranges, loc_locale_tables.toupper); - loc_setranges_char (locale->tolower_ranges, loc_locale_tables.tolower); - - loc_locale_tables.locale = locale; +loc_synchronize_tables(const sc_locale_t *locale) { + /* Clear all tables and the locale pointer. */ + memset(&loc_locale_tables, 0, sizeof(loc_locale_tables)); + + /* Set ranges and attach the new locale. */ + loc_setranges_bool(locale->isspace_ranges, loc_locale_tables.isspace); + loc_setranges_bool(locale->isdigit_ranges, loc_locale_tables.isdigit); + loc_setranges_bool(locale->isalpha_ranges, loc_locale_tables.isalpha); + loc_setranges_char(locale->toupper_ranges, loc_locale_tables.toupper); + loc_setranges_char(locale->tolower_ranges, loc_locale_tables.tolower); + + loc_locale_tables.locale = locale; } static void -loc_check_tables_synchronized (const sc_locale_t *locale) -{ - if (locale != loc_locale_tables.locale) - loc_synchronize_tables (locale); +loc_check_tables_synchronized(const sc_locale_t *locale) { + if (locale != loc_locale_tables.locale) + loc_synchronize_tables(locale); } @@ -190,16 +178,22 @@ loc_check_tables_synchronized (const sc_locale_t *locale) * practice, it seems that only English and French Adrift Latin1 games exist). */ static const sc_locale_t LATIN1_LOCALE = { - "Latin1", - {9,13, 32,32, 160,160, -1}, - {48,57, -1}, - {65,90, 97,122, 192,214, 216,246, 248,255, 138,138, 140,140, - 142,142, 154,154, 156,156, 158,158, 159,159, -1}, - {0,TABLE_SIZE-1,0, 97,122,-32, 224,246,-32, 248,254,-32, 154,154,-16, - 156,156,-16, 158,158,-16, 255,255,-96, -1}, - {0,TABLE_SIZE-1,0, 65,90,32, 192,214,32, 216,222,32, 138,138,16, - 140,140,16, 142,142,16, 159,159,96, -1}, - {{0}} + "Latin1", + {9, 13, 32, 32, 160, 160, -1}, + {48, 57, -1}, + { + 65, 90, 97, 122, 192, 214, 216, 246, 248, 255, 138, 138, 140, 140, + 142, 142, 154, 154, 156, 156, 158, 158, 159, 159, -1 + }, + { + 0, TABLE_SIZE - 1, 0, 97, 122, -32, 224, 246, -32, 248, 254, -32, 154, 154, -16, + 156, 156, -16, 158, 158, -16, 255, 255, -96, -1 + }, + { + 0, TABLE_SIZE - 1, 0, 65, 90, 32, 192, 214, 32, 216, 222, 32, 138, 138, 16, + 140, 140, 16, 142, 142, 16, 159, 159, 96, -1 + }, + {{0}} }; @@ -208,29 +202,36 @@ static const sc_locale_t LATIN1_LOCALE = { * both mixed case and lowercase Russian Cyrillic. */ static const sc_locale_t CYRILLIC_LOCALE = { - "Cyrillic", - {9,13, 32,32, 160,160, -1}, - {48,57, -1}, - {65,90, 97,122, 168,168, 184,184, 175,175, 191,191, 178,179, - 192,255, -1}, - {0,TABLE_SIZE-1,0, 97,122,-32, 184,184,-16, 191,191,-16, 179,179,-1, - 224,255,-32, -1}, - {0,TABLE_SIZE-1,0, 65,90,32, 168,168,16, 175,175,16, 178,178,1, - 192,223,32, -1}, - {{223, 237, 226}, {212, 229, 226}, {204, 224, 240}, {192, 239, 240}, - {204, 224, 233}, {200, 254, 237}, {200, 254, 235}, {192, 226, 227}, - {209, 229, 237}, {206, 234, 242}, {205, 238, 255}, {196, 229, 234}, - {255, 237, 226}, {244, 229, 226}, {236, 224, 240}, {224, 239, 240}, - {236, 224, 233}, {232, 254, 237}, {232, 254, 235}, {224, 226, 227}, - {241, 229, 237}, {238, 234, 242}, {237, 238, 255}, {228, 229, 234}} + "Cyrillic", + {9, 13, 32, 32, 160, 160, -1}, + {48, 57, -1}, + { + 65, 90, 97, 122, 168, 168, 184, 184, 175, 175, 191, 191, 178, 179, + 192, 255, -1 + }, + { + 0, TABLE_SIZE - 1, 0, 97, 122, -32, 184, 184, -16, 191, 191, -16, 179, 179, -1, + 224, 255, -32, -1 + }, + { + 0, TABLE_SIZE - 1, 0, 65, 90, 32, 168, 168, 16, 175, 175, 16, 178, 178, 1, + 192, 223, 32, -1 + }, + { {223, 237, 226}, {212, 229, 226}, {204, 224, 240}, {192, 239, 240}, + {204, 224, 233}, {200, 254, 237}, {200, 254, 235}, {192, 226, 227}, + {209, 229, 237}, {206, 234, 242}, {205, 238, 255}, {196, 229, 234}, + {255, 237, 226}, {244, 229, 226}, {236, 224, 240}, {224, 239, 240}, + {236, 224, 233}, {232, 254, 237}, {232, 254, 235}, {224, 226, 227}, + {241, 229, 237}, {238, 234, 242}, {237, 238, 255}, {228, 229, 234} + } }; /* List of pointers to supported and available locales, NULL terminated. */ static const sc_locale_t *const AVAILABLE_LOCALES[] = { - &LATIN1_LOCALE, - &CYRILLIC_LOCALE, - NULL + &LATIN1_LOCALE, + &CYRILLIC_LOCALE, + NULL }; /* @@ -250,20 +251,19 @@ static sc_bool loc_is_autodetect_enabled = TRUE; * NULL if it doesn't match the expected format. */ static const sc_char * -loc_locate_signature_in_date (const sc_char *date) -{ - sc_int day, year, converted; - sc_char signature[SIGNATURE_LENGTH + 1]; - - /* Clear signature, and convert using a scanf format. */ - memset (signature, 0, sizeof (signature)); - converted = sscanf (date, "%2ld %3[^ 0-9] %4ld", &day, signature, &year); - - /* Valid if we converted three values, and month has three characters. */ - if (converted == 3 && strlen (signature) == SIGNATURE_LENGTH) - return strstr (date, signature); - else - return NULL; +loc_locate_signature_in_date(const sc_char *date) { + sc_int day, year, converted; + sc_char signature[SIGNATURE_LENGTH + 1]; + + /* Clear signature, and convert using a scanf format. */ + memset(signature, 0, sizeof(signature)); + converted = sscanf(date, "%2ld %3[^ 0-9] %4ld", &day, signature, &year); + + /* Valid if we converted three values, and month has three characters. */ + if (converted == 3 && strlen(signature) == SIGNATURE_LENGTH) + return strstr(date, signature); + else + return NULL; } @@ -276,24 +276,21 @@ loc_locate_signature_in_date (const sc_char *date) * codepage, but the locale is not yet (by definition) set. */ static sc_bool -loc_compare_locale_signatures (const char *signature, const sc_locale_t *locale) -{ - sc_int index_; - sc_bool is_matched; - - /* Compare signatures, stopping on the first match found. */ - is_matched = FALSE; - for (index_ = 0; index_ < SIGNATURE_COUNT; index_++) - { - if (memcmp (locale->signature[index_], - signature, sizeof (locale->signature[0])) == 0) - { - is_matched = TRUE; - break; - } - } - - return is_matched; +loc_compare_locale_signatures(const char *signature, const sc_locale_t *locale) { + sc_int index_; + sc_bool is_matched; + + /* Compare signatures, stopping on the first match found. */ + is_matched = FALSE; + for (index_ = 0; index_ < SIGNATURE_COUNT; index_++) { + if (memcmp(locale->signature[index_], + signature, sizeof(locale->signature[0])) == 0) { + is_matched = TRUE; + break; + } + } + + return is_matched; } @@ -306,31 +303,27 @@ loc_compare_locale_signatures (const char *signature, const sc_locale_t *locale) * first locale that matches, or NULL if none match. */ static const sc_locale_t * -loc_find_matching_locale (const sc_char *date, - const sc_locale_t *const *locales) -{ - const sc_char *signature; - const sc_locale_t *matched = NULL; - - /* Get the month part of date, and if valid, search locale signatures. */ - signature = loc_locate_signature_in_date (date); - if (signature) - { - const sc_locale_t *const *iterator; - - /* Search for this signature in the locale's signatures. */ - for (iterator = locales; *iterator; iterator++) - { - if (loc_compare_locale_signatures (signature, *iterator)) - { - matched = *iterator; - break; - } - } - } - - /* Return the matching locale, NULL if none matched. */ - return matched; +loc_find_matching_locale(const sc_char *date, + const sc_locale_t *const *locales) { + const sc_char *signature; + const sc_locale_t *matched = NULL; + + /* Get the month part of date, and if valid, search locale signatures. */ + signature = loc_locate_signature_in_date(date); + if (signature) { + const sc_locale_t *const *iterator; + + /* Search for this signature in the locale's signatures. */ + for (iterator = locales; *iterator; iterator++) { + if (loc_compare_locale_signatures(signature, *iterator)) { + matched = *iterator; + break; + } + } + } + + /* Return the matching locale, NULL if none matched. */ + return matched; } @@ -341,28 +334,26 @@ loc_find_matching_locale (const sc_char *date, * compilation date. */ void -loc_detect_game_locale (sc_prop_setref_t bundle) -{ - assert (bundle); - - /* If an explicit locale has already been set, ignore the call. */ - if (loc_is_autodetect_enabled) - { - sc_vartype_t vt_key[1]; - const sc_char *compile_date; - const sc_locale_t *matched; - - /* Read the game's compilation date from the properties. */ - vt_key[0].string = "CompileDate"; - compile_date = prop_get_string (bundle, "S<-s", vt_key); - - /* Search for a matching locale based on the game compilation date. */ - matched = loc_find_matching_locale (compile_date, AVAILABLE_LOCALES); - - /* If a locale matched, set the global locale to it. */ - if (matched) - loc_locale = matched; - } +loc_detect_game_locale(sc_prop_setref_t bundle) { + assert(bundle); + + /* If an explicit locale has already been set, ignore the call. */ + if (loc_is_autodetect_enabled) { + sc_vartype_t vt_key[1]; + const sc_char *compile_date; + const sc_locale_t *matched; + + /* Read the game's compilation date from the properties. */ + vt_key[0].string = "CompileDate"; + compile_date = prop_get_string(bundle, "S<-s", vt_key); + + /* Search for a matching locale based on the game compilation date. */ + matched = loc_find_matching_locale(compile_date, AVAILABLE_LOCALES); + + /* If a locale matched, set the global locale to it. */ + if (matched) + loc_locale = matched; + } } @@ -377,26 +368,23 @@ loc_detect_game_locale (sc_prop_setref_t bundle) * of this function. */ static sc_char -loc_ascii_tolower (sc_char ch) -{ - return (ch >= 'A' && ch <= 'Z') ? ch - 'A' + 'a' : ch; +loc_ascii_tolower(sc_char ch) { + return (ch >= 'A' && ch <= 'Z') ? ch - 'A' + 'a' : ch; } static sc_int -loc_ascii_strncasecmp (const sc_char *s1, const sc_char *s2, sc_int n) -{ - sc_int index_; +loc_ascii_strncasecmp(const sc_char *s1, const sc_char *s2, sc_int n) { + sc_int index_; - for (index_ = 0; index_ < n; index_++) - { - sc_int diff; + for (index_ = 0; index_ < n; index_++) { + sc_int diff; - diff = loc_ascii_tolower (s1[index_]) - loc_ascii_tolower (s2[index_]); - if (diff < 0 || diff > 0) - return diff < 0 ? -1 : 1; - } + diff = loc_ascii_tolower(s1[index_]) - loc_ascii_tolower(s2[index_]); + if (diff < 0 || diff > 0) + return diff < 0 ? -1 : 1; + } - return 0; + return 0; } @@ -409,41 +397,36 @@ loc_ascii_strncasecmp (const sc_char *s1, const sc_char *s2, sc_int n) * if none yet set. */ sc_bool -loc_set_locale (const sc_char *name) -{ - const sc_locale_t *matched = NULL; - const sc_locale_t *const *iterator; - assert (name); - - /* - * Search locales for a matching name, abbreviated if necessary. Stop on - * the first match found. - */ - for (iterator = AVAILABLE_LOCALES; *iterator; iterator++) - { - const sc_locale_t *const locale = *iterator; - - if (loc_ascii_strncasecmp (name, locale->name, strlen (name)) == 0) - { - matched = locale; - break; - } - } - - /* If matched, set the global locale, and lock out future autodetection. */ - if (matched) - { - loc_locale = matched; - loc_is_autodetect_enabled = FALSE; - } - - return matched ? TRUE : FALSE; +loc_set_locale(const sc_char *name) { + const sc_locale_t *matched = NULL; + const sc_locale_t *const *iterator; + assert(name); + + /* + * Search locales for a matching name, abbreviated if necessary. Stop on + * the first match found. + */ + for (iterator = AVAILABLE_LOCALES; *iterator; iterator++) { + const sc_locale_t *const locale = *iterator; + + if (loc_ascii_strncasecmp(name, locale->name, strlen(name)) == 0) { + matched = locale; + break; + } + } + + /* If matched, set the global locale, and lock out future autodetection. */ + if (matched) { + loc_locale = matched; + loc_is_autodetect_enabled = FALSE; + } + + return matched ? TRUE : FALSE; } const sc_char * -loc_get_locale (void) -{ - return loc_locale->name; +loc_get_locale(void) { + return loc_locale->name; } @@ -456,55 +439,49 @@ loc_get_locale (void) * Print out locale tables. */ static int -loc_debug_dump_new_line (sc_int index_, sc_int count) -{ - return index_ < TABLE_SIZE - 1 && index_ % count == count - 1; +loc_debug_dump_new_line(sc_int index_, sc_int count) { + return index_ < TABLE_SIZE - 1 && index_ % count == count - 1; } static void -loc_debug_dump_bool_table (const sc_char *label, - sc_int count, const sc_bool table[]) -{ - sc_int index_; - - sc_trace ("loc_locale_tables.%s = {\n ", label); - for (index_ = 0; index_ < TABLE_SIZE; index_++) - { - sc_trace ("%s%s", table[index_] ? "T" : "F", - loc_debug_dump_new_line (index_, count) ? "\n " : ""); - } - sc_trace ("\n}\n"); +loc_debug_dump_bool_table(const sc_char *label, + sc_int count, const sc_bool table[]) { + sc_int index_; + + sc_trace("loc_locale_tables.%s = {\n ", label); + for (index_ = 0; index_ < TABLE_SIZE; index_++) { + sc_trace("%s%s", table[index_] ? "T" : "F", + loc_debug_dump_new_line(index_, count) ? "\n " : ""); + } + sc_trace("\n}\n"); } static void -loc_debug_dump_char_table (const sc_char *label, - sc_int count, const sc_char table[]) -{ - sc_int index_; - - sc_trace ("loc_locale_tables.%s = {\n ", label); - for (index_ = 0; index_ < TABLE_SIZE; index_++) - { - sc_trace ("%02lx%s", (sc_int) (sc_byte) table[index_], - loc_debug_dump_new_line (index_, count) ? "\n " : " "); - } - sc_trace ("\n}\n"); +loc_debug_dump_char_table(const sc_char *label, + sc_int count, const sc_char table[]) { + sc_int index_; + + sc_trace("loc_locale_tables.%s = {\n ", label); + for (index_ = 0; index_ < TABLE_SIZE; index_++) { + sc_trace("%02lx%s", (sc_int)(sc_byte) table[index_], + loc_debug_dump_new_line(index_, count) ? "\n " : " "); + } + sc_trace("\n}\n"); } void -loc_debug_dump (void) -{ - sc_trace ("Locale: debug dump follows...\n"); - - loc_check_tables_synchronized (loc_locale); - sc_trace ("loc_locale_tables" - ".locale->name = %s\n", loc_locale_tables.locale->name); - - loc_debug_dump_bool_table ("isspace", 64, loc_locale_tables.isspace); - loc_debug_dump_bool_table ("isdigit", 64, loc_locale_tables.isdigit); - loc_debug_dump_bool_table ("isalpha", 64, loc_locale_tables.isalpha); - loc_debug_dump_char_table ("toupper", 16, loc_locale_tables.toupper); - loc_debug_dump_char_table ("tolower", 16, loc_locale_tables.tolower); +loc_debug_dump(void) { + sc_trace("Locale: debug dump follows...\n"); + + loc_check_tables_synchronized(loc_locale); + sc_trace("loc_locale_tables" + ".locale->name = %s\n", loc_locale_tables.locale->name); + + loc_debug_dump_bool_table("isspace", 64, loc_locale_tables.isspace); + loc_debug_dump_bool_table("isdigit", 64, loc_locale_tables.isdigit); + loc_debug_dump_bool_table("isalpha", 64, loc_locale_tables.isalpha); + loc_debug_dump_char_table("toupper", 16, loc_locale_tables.toupper); + loc_debug_dump_char_table("tolower", 16, loc_locale_tables.tolower); } @@ -516,17 +493,15 @@ loc_debug_dump (void) * tables to the currently set locale, and return the value from the table. */ static sc_bool -loc_bool_template (sc_char character, const sc_bool table[]) -{ - loc_check_tables_synchronized (loc_locale); - return table[(sc_byte) character]; +loc_bool_template(sc_char character, const sc_bool table[]) { + loc_check_tables_synchronized(loc_locale); + return table[(sc_byte) character]; } static sc_char -loc_char_template (sc_char character, const sc_char table[]) -{ - loc_check_tables_synchronized (loc_locale); - return table[(sc_byte) character]; +loc_char_template(sc_char character, const sc_char table[]) { + loc_check_tables_synchronized(loc_locale); + return table[(sc_byte) character]; } @@ -540,33 +515,28 @@ loc_char_template (sc_char character, const sc_char table[]) * Public entry points into locale variant ctype functions. */ sc_bool -sc_isspace (sc_char character) -{ - return loc_bool_template (character, loc_locale_tables.isspace); +sc_isspace(sc_char character) { + return loc_bool_template(character, loc_locale_tables.isspace); } sc_bool -sc_isalpha (sc_char character) -{ - return loc_bool_template (character, loc_locale_tables.isalpha); +sc_isalpha(sc_char character) { + return loc_bool_template(character, loc_locale_tables.isalpha); } sc_bool -sc_isdigit (sc_char character) -{ - return loc_bool_template (character, loc_locale_tables.isdigit); +sc_isdigit(sc_char character) { + return loc_bool_template(character, loc_locale_tables.isdigit); } sc_char -sc_toupper (sc_char character) -{ - return loc_char_template (character, loc_locale_tables.toupper); +sc_toupper(sc_char character) { + return loc_char_template(character, loc_locale_tables.toupper); } sc_char -sc_tolower (sc_char character) -{ - return loc_char_template (character, loc_locale_tables.tolower); +sc_tolower(sc_char character) { + return loc_char_template(character, loc_locale_tables.tolower); } } // End of namespace Adrift diff --git a/engines/glk/adrift/scmemos.cpp b/engines/glk/adrift/scmemos.cpp index 4809b2078f..9179783baa 100644 --- a/engines/glk/adrift/scmemos.cpp +++ b/engines/glk/adrift/scmemos.cpp @@ -34,11 +34,10 @@ enum { MEMO_ALLOCATION_BLOCK = 32 }; * Game memo structure, saves a serialized game. Allocation is preserved so * that structures can be reused without requiring reallocation. */ -typedef struct sc_memo_s -{ - sc_byte *serialized_game; - sc_int allocation; - sc_int length; +typedef struct sc_memo_s { + sc_byte *serialized_game; + sc_int allocation; + sc_int length; } sc_memo_t; typedef sc_memo_t *sc_memoref_t; @@ -46,14 +45,13 @@ typedef sc_memo_t *sc_memoref_t; * Game command history structure, similar to a memo. Saves a player input * command to create a history, reusing allocation where possible. */ -typedef struct sc_history_s -{ - sc_char *command; - sc_int sequence; - sc_int timestamp; - sc_int turns; - sc_int allocation; - sc_int length; +typedef struct sc_history_s { + sc_char *command; + sc_int sequence; + sc_int timestamp; + sc_int turns; + sc_int allocation; + sc_int length; } sc_history_t; typedef sc_history_t *sc_historyref_t; @@ -66,16 +64,15 @@ typedef sc_history_t *sc_historyref_t; * also a ring with limited capacity. */ enum { MEMO_UNDO_TABLE_SIZE = 16, MEMO_HISTORY_TABLE_SIZE = 64 }; -typedef struct sc_memo_set_s -{ - sc_uint magic; - sc_memo_t memo[MEMO_UNDO_TABLE_SIZE]; - sc_int memo_cursor; - - sc_history_t history[MEMO_HISTORY_TABLE_SIZE]; - sc_int history_count; - sc_int current_history; - sc_bool is_at_start; +typedef struct sc_memo_set_s { + sc_uint magic; + sc_memo_t memo[MEMO_UNDO_TABLE_SIZE]; + sc_int memo_cursor; + + sc_history_t history[MEMO_HISTORY_TABLE_SIZE]; + sc_int history_count; + sc_int current_history; + sc_bool is_at_start; } sc_memo_set_t; @@ -85,9 +82,8 @@ typedef struct sc_memo_set_s * Return TRUE if pointer is a valid memo set, FALSE otherwise. */ static sc_bool -memo_is_valid (sc_memo_setref_t memento) -{ - return memento && memento->magic == MEMENTO_MAGIC; +memo_is_valid(sc_memo_setref_t memento) { + return memento && memento->magic == MEMENTO_MAGIC; } @@ -97,12 +93,11 @@ memo_is_valid (sc_memo_setref_t memento) * Round up an allocation in bytes to the next allocation block. */ static sc_int -memo_round_up (sc_int allocation) -{ - sc_int extended; +memo_round_up(sc_int allocation) { + sc_int extended; - extended = allocation + MEMO_ALLOCATION_BLOCK - 1; - return (extended / MEMO_ALLOCATION_BLOCK) * MEMO_ALLOCATION_BLOCK; + extended = allocation + MEMO_ALLOCATION_BLOCK - 1; + return (extended / MEMO_ALLOCATION_BLOCK) * MEMO_ALLOCATION_BLOCK; } @@ -112,23 +107,22 @@ memo_round_up (sc_int allocation) * Create and return a new set of memos. */ sc_memo_setref_t -memo_create (void) -{ - sc_memo_setref_t memento; +memo_create(void) { + sc_memo_setref_t memento; - /* Create and initialize a clean set of memos. */ - memento = (sc_memo_setref_t)sc_malloc (sizeof (*memento)); - memento->magic = MEMENTO_MAGIC; + /* Create and initialize a clean set of memos. */ + memento = (sc_memo_setref_t)sc_malloc(sizeof(*memento)); + memento->magic = MEMENTO_MAGIC; - memset (memento->memo, 0, sizeof (memento->memo)); - memento->memo_cursor = 0; + memset(memento->memo, 0, sizeof(memento->memo)); + memento->memo_cursor = 0; - memset (memento->history, 0, sizeof (memento->history)); - memento->history_count = 0; - memento->current_history = 0; - memento->is_at_start = FALSE; + memset(memento->history, 0, sizeof(memento->history)); + memento->history_count = 0; + memento->current_history = 0; + memento->is_at_start = FALSE; - return memento; + return memento; } @@ -138,30 +132,27 @@ memo_create (void) * Destroy a memo set, and free its heap memory. */ void -memo_destroy (sc_memo_setref_t memento) -{ - sc_int index_; - assert (memo_is_valid (memento)); - - /* Free the content of any used memo and any used history. */ - for (index_ = 0; index_ < MEMO_UNDO_TABLE_SIZE; index_++) - { - sc_memoref_t memo; - - memo = memento->memo + index_; - sc_free (memo->serialized_game); - } - for (index_ = 0; index_ < MEMO_HISTORY_TABLE_SIZE; index_++) - { - sc_historyref_t history; - - history = memento->history + index_; - sc_free (history->command); - } - - /* Poison and free the memo set itself. */ - memset (memento, 0xaa, sizeof (*memento)); - sc_free (memento); +memo_destroy(sc_memo_setref_t memento) { + sc_int index_; + assert(memo_is_valid(memento)); + + /* Free the content of any used memo and any used history. */ + for (index_ = 0; index_ < MEMO_UNDO_TABLE_SIZE; index_++) { + sc_memoref_t memo; + + memo = memento->memo + index_; + sc_free(memo->serialized_game); + } + for (index_ = 0; index_ < MEMO_HISTORY_TABLE_SIZE; index_++) { + sc_historyref_t history; + + history = memento->history + index_; + sc_free(history->command); + } + + /* Poison and free the memo set itself. */ + memset(memento, 0xaa, sizeof(*memento)); + sc_free(memento); } @@ -172,28 +163,26 @@ memo_destroy (sc_memo_setref_t memento) * that already stored in the memo. */ static void -memo_save_game_callback (void *opaque, const sc_byte *buffer, sc_int length) -{ - sc_memoref_t memo = (sc_memoref_t)opaque; - sc_int required; - assert (opaque && buffer && length > 0); - - /* - * If necessary, increase the allocation for this memo. Serialized games - * tend to grow slightly as the game progresses, so we add a bit of extra - * to the actual allocation. - */ - required = memo->length + length; - if (required > memo->allocation) - { - required = memo_round_up (required + 2 * MEMO_ALLOCATION_BLOCK); - memo->serialized_game = (sc_byte *)sc_realloc (memo->serialized_game, required); - memo->allocation = required; - } - - /* Add this block of data to the buffer. */ - memcpy (memo->serialized_game + memo->length, buffer, length); - memo->length += length; +memo_save_game_callback(void *opaque, const sc_byte *buffer, sc_int length) { + sc_memoref_t memo = (sc_memoref_t)opaque; + sc_int required; + assert(opaque && buffer && length > 0); + + /* + * If necessary, increase the allocation for this memo. Serialized games + * tend to grow slightly as the game progresses, so we add a bit of extra + * to the actual allocation. + */ + required = memo->length + length; + if (required > memo->allocation) { + required = memo_round_up(required + 2 * MEMO_ALLOCATION_BLOCK); + memo->serialized_game = (sc_byte *)sc_realloc(memo->serialized_game, required); + memo->allocation = required; + } + + /* Add this block of data to the buffer. */ + memcpy(memo->serialized_game + memo->length, buffer, length); + memo->length += length; } @@ -203,32 +192,29 @@ memo_save_game_callback (void *opaque, const sc_byte *buffer, sc_int length) * Store a game in the next memo slot. */ void -memo_save_game (sc_memo_setref_t memento, sc_gameref_t game) -{ - sc_memoref_t memo; - assert (memo_is_valid (memento)); - - /* - * If the current slot is in use, we can re-use its allocation. Saved - * games will tend to be of roughly equal sizes, so it's worth doing. - */ - memo = memento->memo + memento->memo_cursor; - memo->length = 0; - - /* Serialize the given game into this memo. */ - ser_save_game (game, memo_save_game_callback, memo); - - /* - * If serialization worked (failure would be a surprise), advance the - * current memo cursor. - */ - if (memo->length > 0) - { - memento->memo_cursor++; - memento->memo_cursor %= MEMO_UNDO_TABLE_SIZE; - } - else - sc_error ("memo_save_game: warning: game save failed\n"); +memo_save_game(sc_memo_setref_t memento, sc_gameref_t game) { + sc_memoref_t memo; + assert(memo_is_valid(memento)); + + /* + * If the current slot is in use, we can re-use its allocation. Saved + * games will tend to be of roughly equal sizes, so it's worth doing. + */ + memo = memento->memo + memento->memo_cursor; + memo->length = 0; + + /* Serialize the given game into this memo. */ + ser_save_game(game, memo_save_game_callback, memo); + + /* + * If serialization worked (failure would be a surprise), advance the + * current memo cursor. + */ + if (memo->length > 0) { + memento->memo_cursor++; + memento->memo_cursor %= MEMO_UNDO_TABLE_SIZE; + } else + sc_error("memo_save_game: warning: game save failed\n"); } @@ -239,23 +225,22 @@ memo_save_game (sc_memo_setref_t memento, sc_gameref_t game) * until it's drained. */ static sc_int -memo_load_game_callback (void *opaque, sc_byte *buffer, sc_int length) -{ - sc_memoref_t memo = (sc_memoref_t)opaque; - sc_int bytes; - assert (opaque && buffer && length > 0); - - /* Send back either all the bytes, or as many as the buffer allows. */ - bytes = (memo->length < length) ? memo->length : length; - - /* Read and remove the first block of data (or all if less than length). */ - memcpy (buffer, memo->serialized_game, bytes); - memmove (memo->serialized_game, - memo->serialized_game + bytes, memo->length - bytes); - memo->length -= bytes; - - /* Return the count of bytes placed in the buffer. */ - return bytes; +memo_load_game_callback(void *opaque, sc_byte *buffer, sc_int length) { + sc_memoref_t memo = (sc_memoref_t)opaque; + sc_int bytes; + assert(opaque && buffer && length > 0); + + /* Send back either all the bytes, or as many as the buffer allows. */ + bytes = (memo->length < length) ? memo->length : length; + + /* Read and remove the first block of data (or all if less than length). */ + memcpy(buffer, memo->serialized_game, bytes); + memmove(memo->serialized_game, + memo->serialized_game + bytes, memo->length - bytes); + memo->length -= bytes; + + /* Return the count of bytes placed in the buffer. */ + return bytes; } @@ -265,48 +250,45 @@ memo_load_game_callback (void *opaque, sc_byte *buffer, sc_int length) * Restore a game from the last memo slot used, if possible. */ sc_bool -memo_load_game (sc_memo_setref_t memento, sc_gameref_t game) -{ - sc_int cursor; - sc_memoref_t memo; - assert (memo_is_valid (memento)); - - /* Look back one from the current memo cursor. */ - cursor = (memento->memo_cursor == 0) - ? MEMO_UNDO_TABLE_SIZE - 1 : memento->memo_cursor - 1; - memo = memento->memo + cursor; - - /* If this slot is not empty, restore the serialized game held in it. */ - if (memo->length > 0) - { - sc_bool status; - - /* - * Deserialize the given game from this memo; failure would be somewhat - * of a surprise here. - */ - status = ser_load_game (game, memo_load_game_callback, memo); - if (!status) - sc_error ("memo_load_game: warning: game load failed\n"); - - /* - * This should have drained the memo of all data, but to be sure that - * there's no chance of trying to restore from this slot again, we'll - * force it anyway. - */ - if (memo->length > 0) - { - sc_error ("memo_load_game: warning: data remains after loading\n"); - memo->length = 0; - } - - /* Regress current memo, and return TRUE if we restored a memo. */ - memento->memo_cursor = cursor; - return status; - } - - /* There are no more memos to restore. */ - return FALSE; +memo_load_game(sc_memo_setref_t memento, sc_gameref_t game) { + sc_int cursor; + sc_memoref_t memo; + assert(memo_is_valid(memento)); + + /* Look back one from the current memo cursor. */ + cursor = (memento->memo_cursor == 0) + ? MEMO_UNDO_TABLE_SIZE - 1 : memento->memo_cursor - 1; + memo = memento->memo + cursor; + + /* If this slot is not empty, restore the serialized game held in it. */ + if (memo->length > 0) { + sc_bool status; + + /* + * Deserialize the given game from this memo; failure would be somewhat + * of a surprise here. + */ + status = ser_load_game(game, memo_load_game_callback, memo); + if (!status) + sc_error("memo_load_game: warning: game load failed\n"); + + /* + * This should have drained the memo of all data, but to be sure that + * there's no chance of trying to restore from this slot again, we'll + * force it anyway. + */ + if (memo->length > 0) { + sc_error("memo_load_game: warning: data remains after loading\n"); + memo->length = 0; + } + + /* Regress current memo, and return TRUE if we restored a memo. */ + memento->memo_cursor = cursor; + return status; + } + + /* There are no more memos to restore. */ + return FALSE; } @@ -317,20 +299,19 @@ memo_load_game (sc_memo_setref_t memento, sc_gameref_t game) * otherwise. */ sc_bool -memo_is_load_available (sc_memo_setref_t memento) -{ - sc_int cursor; - sc_memoref_t memo; - assert (memo_is_valid (memento)); - - /* - * Look back one from the current memo cursor. Return TRUE if this slot - * contains a serialized game. - */ - cursor = (memento->memo_cursor == 0) - ? MEMO_UNDO_TABLE_SIZE - 1 : memento->memo_cursor - 1; - memo = memento->memo + cursor; - return memo->length > 0; +memo_is_load_available(sc_memo_setref_t memento) { + sc_int cursor; + sc_memoref_t memo; + assert(memo_is_valid(memento)); + + /* + * Look back one from the current memo cursor. Return TRUE if this slot + * contains a serialized game. + */ + cursor = (memento->memo_cursor == 0) + ? MEMO_UNDO_TABLE_SIZE - 1 : memento->memo_cursor - 1; + memo = memento->memo + cursor; + return memo->length > 0; } @@ -340,23 +321,21 @@ memo_is_load_available (sc_memo_setref_t memento) * Forget the memos of saved games. */ void -memo_clear_games (sc_memo_setref_t memento) -{ - sc_int index_; - assert (memo_is_valid (memento)); - - /* Deallocate every entry. */ - for (index_ = 0; index_ < MEMO_UNDO_TABLE_SIZE; index_++) - { - sc_memoref_t memo; - - memo = memento->memo + index_; - sc_free (memo->serialized_game); - } - - /* Reset all entries and the cursor. */ - memset (memento->memo, 0, sizeof (memento->memo)); - memento->memo_cursor = 0; +memo_clear_games(sc_memo_setref_t memento) { + sc_int index_; + assert(memo_is_valid(memento)); + + /* Deallocate every entry. */ + for (index_ = 0; index_ < MEMO_UNDO_TABLE_SIZE; index_++) { + sc_memoref_t memo; + + memo = memento->memo + index_; + sc_free(memo->serialized_game); + } + + /* Reset all entries and the cursor. */ + memset(memento->memo, 0, sizeof(memento->memo)); + memento->memo_cursor = 0; } @@ -367,41 +346,39 @@ memo_clear_games (sc_memo_setref_t memento) * used item if necessary. */ void -memo_save_command (sc_memo_setref_t memento, - const sc_char *command, sc_int timestamp, sc_int turns) -{ - sc_historyref_t history; - sc_int length; - assert (memo_is_valid (memento)); - - /* As with memos, reuse the allocation of the next slot if it has one. */ - history = memento->history - + memento->history_count % MEMO_HISTORY_TABLE_SIZE; - - /* - * Resize the allocation for this slot if required. Strings tend to be - * short, so round up to a block to avoid too many reallocs. - */ - length = strlen (command) + 1; - if (history->allocation < length) - { - sc_int required; - - required = memo_round_up (length); - history->command = (sc_char *)sc_realloc (history->command, required); - history->allocation = required; - } - - /* Save the string into this slot, and normalize it for neatness. */ - strcpy (history->command, command); - sc_normalize_string (history->command); - history->sequence = memento->history_count + 1; - history->timestamp = timestamp; - history->turns = turns; - history->length = length; - - /* Increment the count of histories handled. */ - memento->history_count++; +memo_save_command(sc_memo_setref_t memento, + const sc_char *command, sc_int timestamp, sc_int turns) { + sc_historyref_t history; + sc_int length; + assert(memo_is_valid(memento)); + + /* As with memos, reuse the allocation of the next slot if it has one. */ + history = memento->history + + memento->history_count % MEMO_HISTORY_TABLE_SIZE; + + /* + * Resize the allocation for this slot if required. Strings tend to be + * short, so round up to a block to avoid too many reallocs. + */ + length = strlen(command) + 1; + if (history->allocation < length) { + sc_int required; + + required = memo_round_up(length); + history->command = (sc_char *)sc_realloc(history->command, required); + history->allocation = required; + } + + /* Save the string into this slot, and normalize it for neatness. */ + strcpy(history->command, command); + sc_normalize_string(history->command); + history->sequence = memento->history_count + 1; + history->timestamp = timestamp; + history->turns = turns; + history->length = length; + + /* Increment the count of histories handled. */ + memento->history_count++; } @@ -414,24 +391,22 @@ memo_save_command (sc_memo_setref_t memento, * remove it again as the main runner loop will add the real thing. */ void -memo_unsave_command (sc_memo_setref_t memento) -{ - assert (memo_is_valid (memento)); - - /* Do nothing if for some reason there's no history to unsave. */ - if (memento->history_count > 0) - { - sc_historyref_t history; - - /* Decrement the count of histories handled, erase the prior entry. */ - memento->history_count--; - history = memento->history - + memento->history_count % MEMO_HISTORY_TABLE_SIZE; - history->sequence = 0; - history->timestamp = 0; - history->turns = 0; - history->length = 0; - } +memo_unsave_command(sc_memo_setref_t memento) { + assert(memo_is_valid(memento)); + + /* Do nothing if for some reason there's no history to unsave. */ + if (memento->history_count > 0) { + sc_historyref_t history; + + /* Decrement the count of histories handled, erase the prior entry. */ + memento->history_count--; + history = memento->history + + memento->history_count % MEMO_HISTORY_TABLE_SIZE; + history->sequence = 0; + history->timestamp = 0; + history->turns = 0; + history->length = 0; + } } @@ -441,15 +416,14 @@ memo_unsave_command (sc_memo_setref_t memento) * Return a count of available saved commands. */ sc_int -memo_get_command_count (sc_memo_setref_t memento) -{ - assert (memo_is_valid (memento)); - - /* Return the lesser of the history count and the history table size. */ - if (memento->history_count < MEMO_HISTORY_TABLE_SIZE) - return memento->history_count; - else - return MEMO_HISTORY_TABLE_SIZE; +memo_get_command_count(sc_memo_setref_t memento) { + assert(memo_is_valid(memento)); + + /* Return the lesser of the history count and the history table size. */ + if (memento->history_count < MEMO_HISTORY_TABLE_SIZE) + return memento->history_count; + else + return MEMO_HISTORY_TABLE_SIZE; } @@ -459,23 +433,22 @@ memo_get_command_count (sc_memo_setref_t memento) * Iterator rewind function, reset current location to the first command. */ void -memo_first_command (sc_memo_setref_t memento) -{ - sc_int cursor; - sc_historyref_t history; - assert (memo_is_valid (memento)); - - /* - * If the buffer has cycled, we have the full complement of saved commands, - * so start iterating at the current cursor. Otherwise, start from index 0. - * Detect cycling by looking at the current slot; if it's filled, we've - * been here before. Set at_start flag to indicate the special case for - * circular buffers. - */ - cursor = memento->history_count % MEMO_HISTORY_TABLE_SIZE; - history = memento->history + cursor; - memento->current_history = (history->length > 0) ? cursor : 0; - memento->is_at_start = TRUE; +memo_first_command(sc_memo_setref_t memento) { + sc_int cursor; + sc_historyref_t history; + assert(memo_is_valid(memento)); + + /* + * If the buffer has cycled, we have the full complement of saved commands, + * so start iterating at the current cursor. Otherwise, start from index 0. + * Detect cycling by looking at the current slot; if it's filled, we've + * been here before. Set at_start flag to indicate the special case for + * circular buffers. + */ + cursor = memento->history_count % MEMO_HISTORY_TABLE_SIZE; + history = memento->history + cursor; + memento->current_history = (history->length > 0) ? cursor : 0; + memento->is_at_start = TRUE; } @@ -486,37 +459,33 @@ memo_first_command (sc_memo_setref_t memento) * starting at 1, and the timestamp and turns when the command was saved. */ void -memo_next_command (sc_memo_setref_t memento, - const sc_char **command, sc_int *sequence, - sc_int *timestamp, sc_int *turns) -{ - assert (memo_is_valid (memento)); - - /* If valid, return the current command and advance. */ - if (memo_more_commands (memento)) - { - sc_historyref_t history; - - /* Note the current history, and advance its index. */ - history = memento->history + memento->current_history; - memento->current_history++; - memento->current_history %= MEMO_HISTORY_TABLE_SIZE; - memento->is_at_start = FALSE; - - /* Return details from the history noted above. */ - *command = history->command; - *sequence = history->sequence; - *timestamp = history->timestamp; - *turns = history->turns; - } - else - { - /* Return NULL and zeroes if no more commands available. */ - *command = NULL; - *sequence = 0; - *timestamp = 0; - *turns = 0; - } +memo_next_command(sc_memo_setref_t memento, + const sc_char **command, sc_int *sequence, + sc_int *timestamp, sc_int *turns) { + assert(memo_is_valid(memento)); + + /* If valid, return the current command and advance. */ + if (memo_more_commands(memento)) { + sc_historyref_t history; + + /* Note the current history, and advance its index. */ + history = memento->history + memento->current_history; + memento->current_history++; + memento->current_history %= MEMO_HISTORY_TABLE_SIZE; + memento->is_at_start = FALSE; + + /* Return details from the history noted above. */ + *command = history->command; + *sequence = history->sequence; + *timestamp = history->timestamp; + *turns = history->turns; + } else { + /* Return NULL and zeroes if no more commands available. */ + *command = NULL; + *sequence = 0; + *timestamp = 0; + *turns = 0; + } } @@ -526,25 +495,24 @@ memo_next_command (sc_memo_setref_t memento, * Iterator end function, returns TRUE if more commands are readable. */ sc_bool -memo_more_commands (sc_memo_setref_t memento) -{ - sc_int cursor; - sc_historyref_t history; - assert (memo_is_valid (memento)); - - /* Get the current effective write position, and the current history. */ - cursor = memento->history_count % MEMO_HISTORY_TABLE_SIZE; - history = memento->history + memento->current_history; - - /* - * More data if the current history is behind the write position and is - * occupied, or if it matches and is occupied and we're at the start of - * iteration (circular buffer special case). - */ - if (memento->current_history == cursor) - return (memento->is_at_start) ? history->length > 0 : FALSE; - else - return history->length > 0; +memo_more_commands(sc_memo_setref_t memento) { + sc_int cursor; + sc_historyref_t history; + assert(memo_is_valid(memento)); + + /* Get the current effective write position, and the current history. */ + cursor = memento->history_count % MEMO_HISTORY_TABLE_SIZE; + history = memento->history + memento->current_history; + + /* + * More data if the current history is behind the write position and is + * occupied, or if it matches and is occupied and we're at the start of + * iteration (circular buffer special case). + */ + if (memento->current_history == cursor) + return (memento->is_at_start) ? history->length > 0 : FALSE; + else + return history->length > 0; } @@ -555,39 +523,36 @@ memo_more_commands (sc_memo_setref_t memento) * indicates an offset from the last defined), or NULL if not found. */ const sc_char * -memo_find_command (sc_memo_setref_t memento, sc_int sequence) -{ - sc_int target, index_; - sc_historyref_t matched; - assert (memo_is_valid (memento)); - - /* Decide on a search target, depending on the sign of sequence. */ - target = (sequence < 0) ? memento->history_count + sequence + 1: sequence; - - /* - * A backwards search starting at the write position would probably be more - * efficient here, but this is a rarely called function so we'll do it the - * simpler way. - */ - matched = NULL; - for (index_ = 0; index_ < MEMO_HISTORY_TABLE_SIZE; index_++) - { - sc_historyref_t history; - - history = memento->history + index_; - if (history->sequence == target) - { - matched = history; - break; - } - } - - /* - * Return the command or NULL. If sequence passed in was zero, and the - * history was not full, this will still return NULL as it should, since - * this unused history's command found by the search above will be NULL. - */ - return matched ? matched->command : NULL; +memo_find_command(sc_memo_setref_t memento, sc_int sequence) { + sc_int target, index_; + sc_historyref_t matched; + assert(memo_is_valid(memento)); + + /* Decide on a search target, depending on the sign of sequence. */ + target = (sequence < 0) ? memento->history_count + sequence + 1 : sequence; + + /* + * A backwards search starting at the write position would probably be more + * efficient here, but this is a rarely called function so we'll do it the + * simpler way. + */ + matched = NULL; + for (index_ = 0; index_ < MEMO_HISTORY_TABLE_SIZE; index_++) { + sc_historyref_t history; + + history = memento->history + index_; + if (history->sequence == target) { + matched = history; + break; + } + } + + /* + * Return the command or NULL. If sequence passed in was zero, and the + * history was not full, this will still return NULL as it should, since + * this unused history's command found by the search above will be NULL. + */ + return matched ? matched->command : NULL; } @@ -597,25 +562,23 @@ memo_find_command (sc_memo_setref_t memento, sc_int sequence) * Forget all saved commands. */ void -memo_clear_commands (sc_memo_setref_t memento) -{ - sc_int index_; - assert (memo_is_valid (memento)); - - /* Deallocate every entry. */ - for (index_ = 0; index_ < MEMO_HISTORY_TABLE_SIZE; index_++) - { - sc_historyref_t history; - - history = memento->history + index_; - sc_free (history->command); - } - - /* Reset all entries, the count, and the iteration variables. */ - memset (memento->history, 0, sizeof (memento->history)); - memento->history_count = 0; - memento->current_history = 0; - memento->is_at_start = FALSE; +memo_clear_commands(sc_memo_setref_t memento) { + sc_int index_; + assert(memo_is_valid(memento)); + + /* Deallocate every entry. */ + for (index_ = 0; index_ < MEMO_HISTORY_TABLE_SIZE; index_++) { + sc_historyref_t history; + + history = memento->history + index_; + sc_free(history->command); + } + + /* Reset all entries, the count, and the iteration variables. */ + memset(memento->history, 0, sizeof(memento->history)); + memento->history_count = 0; + memento->current_history = 0; + memento->is_at_start = FALSE; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scnpcs.cpp b/engines/glk/adrift/scnpcs.cpp index ab11acc5ae..b9b60d5259 100644 --- a/engines/glk/adrift/scnpcs.cpp +++ b/engines/glk/adrift/scnpcs.cpp @@ -37,15 +37,13 @@ static sc_bool npc_trace = FALSE; * Return TRUE if a given NPC is currently in a given room. */ sc_bool -npc_in_room (sc_gameref_t game, sc_int npc, sc_int room) -{ - if (npc_trace) - { - sc_trace ("NPC: checking NPC %ld in room %ld (NPC is in %ld)\n", - npc, room, gs_npc_location (game, npc)); - } - - return gs_npc_location (game, npc) - 1 == room; +npc_in_room(sc_gameref_t game, sc_int npc, sc_int room) { + if (npc_trace) { + sc_trace("NPC: checking NPC %ld in room %ld (NPC is in %ld)\n", + npc, room, gs_npc_location(game, npc)); + } + + return gs_npc_location(game, npc) - 1 == room; } @@ -55,20 +53,18 @@ npc_in_room (sc_gameref_t game, sc_int npc, sc_int room) * Return the count of characters in the room, including the player. */ sc_int -npc_count_in_room (sc_gameref_t game, sc_int room) -{ - sc_int count, npc; - - /* Start with the player. */ - count = gs_player_in_room (game, room) ? 1 : 0; - - /* Total up other NPCs inhabiting the room. */ - for (npc = 0; npc < gs_npc_count (game); npc++) - { - if (gs_npc_location (game, npc) - 1 == room) - count++; - } - return count; +npc_count_in_room(sc_gameref_t game, sc_int room) { + sc_int count, npc; + + /* Start with the player. */ + count = gs_player_in_room(game, room) ? 1 : 0; + + /* Total up other NPCs inhabiting the room. */ + for (npc = 0; npc < gs_npc_count(game); npc++) { + if (gs_npc_location(game, npc) - 1 == room) + count++; + } + return count; } @@ -78,23 +74,22 @@ npc_count_in_room (sc_gameref_t game, sc_int room) * Start the given walk for the given NPC. */ void -npc_start_npc_walk (sc_gameref_t game, sc_int npc, sc_int walk) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[6]; - sc_int movetime; - - /* Retrieve movetime 0 for the NPC walk. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Walks"; - vt_key[3].integer = walk; - vt_key[4].string = "MoveTimes"; - vt_key[5].integer = 0; - movetime = prop_get_integer (bundle, "I<-sisisi", vt_key) + 1; - - /* Set up walkstep. */ - gs_set_npc_walkstep (game, npc, walk, movetime); +npc_start_npc_walk(sc_gameref_t game, sc_int npc, sc_int walk) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[6]; + sc_int movetime; + + /* Retrieve movetime 0 for the NPC walk. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Walks"; + vt_key[3].integer = walk; + vt_key[4].string = "MoveTimes"; + vt_key[5].integer = 0; + movetime = prop_get_integer(bundle, "I<-sisisi", vt_key) + 1; + + /* Set up walkstep. */ + gs_set_npc_walkstep(game, npc, walk, movetime); } @@ -105,52 +100,47 @@ npc_start_npc_walk (sc_gameref_t game, sc_int npc, sc_int walk) * Set initial values for NPC states, and update on turns. */ void -npc_turn_update (sc_gameref_t game) -{ - sc_int index_; - - /* Set current values for NPC seen states. */ - for (index_ = 0; index_ < gs_npc_count (game); index_++) - { - if (!gs_npc_seen (game, index_) - && npc_in_room (game, index_, gs_playerroom (game))) - gs_set_npc_seen (game, index_, TRUE); - } +npc_turn_update(sc_gameref_t game) { + sc_int index_; + + /* Set current values for NPC seen states. */ + for (index_ = 0; index_ < gs_npc_count(game); index_++) { + if (!gs_npc_seen(game, index_) + && npc_in_room(game, index_, gs_playerroom(game))) + gs_set_npc_seen(game, index_, TRUE); + } } void -npc_setup_initial (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int index_; - - /* Start any walks that do not depend on a StartTask */ - vt_key[0].string = "NPCs"; - for (index_ = 0; index_ < gs_npc_count (game); index_++) - { - sc_int walk; - - /* Set up invariant parts of the properties key. */ - vt_key[1].integer = index_; - vt_key[2].string = "Walks"; - - /* Process each walk, starting at the last and working backwards. */ - for (walk = gs_npc_walkstep_count (game, index_) - 1; walk >= 0; walk--) - { - sc_int starttask; - - /* If StartTask is zero, start walk at game start. */ - vt_key[3].integer = walk; - vt_key[4].string = "StartTask"; - starttask = prop_get_integer (bundle, "I<-sisis", vt_key); - if (starttask == 0) - npc_start_npc_walk (game, index_, walk); - } - } - - /* Update seen flags for initial states. */ - npc_turn_update (game); +npc_setup_initial(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int index_; + + /* Start any walks that do not depend on a StartTask */ + vt_key[0].string = "NPCs"; + for (index_ = 0; index_ < gs_npc_count(game); index_++) { + sc_int walk; + + /* Set up invariant parts of the properties key. */ + vt_key[1].integer = index_; + vt_key[2].string = "Walks"; + + /* Process each walk, starting at the last and working backwards. */ + for (walk = gs_npc_walkstep_count(game, index_) - 1; walk >= 0; walk--) { + sc_int starttask; + + /* If StartTask is zero, start walk at game start. */ + vt_key[3].integer = walk; + vt_key[4].string = "StartTask"; + starttask = prop_get_integer(bundle, "I<-sisis", vt_key); + if (starttask == 0) + npc_start_npc_walk(game, index_, walk); + } + } + + /* Update seen flags for initial states. */ + npc_turn_update(game); } @@ -160,33 +150,32 @@ npc_setup_initial (sc_gameref_t game) * Return TRUE if a given room is in a given group. */ static sc_bool -npc_room_in_roomgroup (sc_gameref_t game, sc_int room, sc_int group) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int member; - - /* Check roomgroup membership. */ - vt_key[0].string = "RoomGroups"; - vt_key[1].integer = group; - vt_key[2].string = "List"; - vt_key[3].integer = room; - member = prop_get_integer (bundle, "I<-sisi", vt_key); - return member != 0; +npc_room_in_roomgroup(sc_gameref_t game, sc_int room, sc_int group) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int member; + + /* Check roomgroup membership. */ + vt_key[0].string = "RoomGroups"; + vt_key[1].integer = group; + vt_key[2].string = "List"; + vt_key[3].integer = room; + member = prop_get_integer(bundle, "I<-sisi", vt_key); + return member != 0; } /* List of direction names, for printing entry/exit messages. */ static const sc_char *const DIRNAMES_4[] = { - "the north", "the east", "the south", "the west", "above", "below", - "inside", "outside", - NULL + "the north", "the east", "the south", "the west", "above", "below", + "inside", "outside", + NULL }; static const sc_char *const DIRNAMES_8[] = { - "the north", "the east", "the south", "the west", "above", "below", - "inside", "outside", - "the north-east", "the south-east", "the south-west", "the north-west", - NULL + "the north", "the east", "the south", "the west", "above", "below", + "inside", "outside", + "the north-east", "the south-east", "the south-west", "the north-west", + NULL }; /* @@ -195,49 +184,46 @@ static const sc_char *const DIRNAMES_8[] = { * Return a random member of group adjacent to given room. */ static sc_int -npc_random_adjacent_roomgroup_member (sc_gameref_t game, - sc_int room, sc_int group) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_bool eightpointcompass; - sc_int roomlist[12], count, length, index_; - - /* If given room is "hidden", return nothing. */ - if (room == -1) - return -1; - - /* How many exits to consider? */ - vt_key[0].string = "Globals"; - vt_key[1].string = "EightPointCompass"; - eightpointcompass = prop_get_boolean (bundle, "B<-ss", vt_key); - if (eightpointcompass) - length = sizeof (DIRNAMES_8) / sizeof (DIRNAMES_8[0]) - 1; - else - length = sizeof (DIRNAMES_4) / sizeof (DIRNAMES_4[0]) - 1; - - /* Poll adjacent rooms. */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Exits"; - count = 0; - for (index_ = 0; index_ < length; index_++) - { - sc_int adjacent; - - vt_key[3].integer = index_; - vt_key[4].string = "Dest"; - adjacent = prop_get_child_count (bundle, "I<-sisis", vt_key); - - if (adjacent > 0 && npc_room_in_roomgroup (game, adjacent - 1, group)) - { - roomlist[count] = adjacent - 1; - count++; - } - } - - /* Return a random adjacent room, or -1 if nothing is adjacent. */ - return (count > 0) ? roomlist[sc_randomint (0, count - 1)] : -1; +npc_random_adjacent_roomgroup_member(sc_gameref_t game, + sc_int room, sc_int group) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_bool eightpointcompass; + sc_int roomlist[12], count, length, index_; + + /* If given room is "hidden", return nothing. */ + if (room == -1) + return -1; + + /* How many exits to consider? */ + vt_key[0].string = "Globals"; + vt_key[1].string = "EightPointCompass"; + eightpointcompass = prop_get_boolean(bundle, "B<-ss", vt_key); + if (eightpointcompass) + length = sizeof(DIRNAMES_8) / sizeof(DIRNAMES_8[0]) - 1; + else + length = sizeof(DIRNAMES_4) / sizeof(DIRNAMES_4[0]) - 1; + + /* Poll adjacent rooms. */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Exits"; + count = 0; + for (index_ = 0; index_ < length; index_++) { + sc_int adjacent; + + vt_key[3].integer = index_; + vt_key[4].string = "Dest"; + adjacent = prop_get_child_count(bundle, "I<-sisis", vt_key); + + if (adjacent > 0 && npc_room_in_roomgroup(game, adjacent - 1, group)) { + roomlist[count] = adjacent - 1; + count++; + } + } + + /* Return a random adjacent room, or -1 if nothing is adjacent. */ + return (count > 0) ? roomlist[sc_randomint(0, count - 1)] : -1; } @@ -247,82 +233,77 @@ npc_random_adjacent_roomgroup_member (sc_gameref_t game, * Helper for npc_tick_npc(). */ static void -npc_announce (sc_gameref_t game, sc_int npc, - sc_int room, sc_bool is_exit, sc_int npc_room) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5], vt_rvalue; - const sc_char *text, *name, *const *dirnames; - sc_int dir, dir_match; - sc_bool eightpointcompass, showenterexit, found; - - /* If no announcement required, return immediately. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "ShowEnterExit"; - showenterexit = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!showenterexit) - return; - - /* Get exit or entry text, and NPC name. */ - vt_key[2].string = is_exit ? "ExitText" : "EnterText"; - text = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - /* Decide on four or eight point compass names list. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "EightPointCompass"; - eightpointcompass = prop_get_boolean (bundle, "B<-ss", vt_key); - dirnames = eightpointcompass ? DIRNAMES_8 : DIRNAMES_4; - - /* Set invariant key for room exit search. */ - vt_key[0].string = "Rooms"; - vt_key[1].integer = room; - vt_key[2].string = "Exits"; - - /* Find the room exit that matches the NPC room. */ - found = FALSE; - dir_match = 0; - for (dir = 0; dirnames[dir]; dir++) - { - vt_key[3].integer = dir; - if (prop_get (bundle, "I<-sisi", &vt_rvalue, vt_key)) - { - sc_int dest; - - /* Get room's direction destination, and compare. */ - vt_key[4].string = "Dest"; - dest = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if (dest == npc_room) - { - dir_match = dir; - found = TRUE; - break; - } - } - } - - /* Print NPC exit/entry details. */ - pf_buffer_character (filter, '\n'); - pf_new_sentence (filter); - pf_buffer_string (filter, name); - pf_buffer_character (filter, ' '); - pf_buffer_string (filter, text); - if (found) - { - pf_buffer_string (filter, is_exit ? " to " : " from "); - pf_buffer_string (filter, dirnames[dir_match]); - } - pf_buffer_string (filter, ".\n"); - - /* Handle any associated resource. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Res"; - vt_key[3].integer = is_exit ? 3 : 2; - res_handle_resource (game, "sisi", vt_key); +npc_announce(sc_gameref_t game, sc_int npc, + sc_int room, sc_bool is_exit, sc_int npc_room) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5], vt_rvalue; + const sc_char *text, *name, *const *dirnames; + sc_int dir, dir_match; + sc_bool eightpointcompass, showenterexit, found; + + /* If no announcement required, return immediately. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "ShowEnterExit"; + showenterexit = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!showenterexit) + return; + + /* Get exit or entry text, and NPC name. */ + vt_key[2].string = is_exit ? "ExitText" : "EnterText"; + text = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + /* Decide on four or eight point compass names list. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "EightPointCompass"; + eightpointcompass = prop_get_boolean(bundle, "B<-ss", vt_key); + dirnames = eightpointcompass ? DIRNAMES_8 : DIRNAMES_4; + + /* Set invariant key for room exit search. */ + vt_key[0].string = "Rooms"; + vt_key[1].integer = room; + vt_key[2].string = "Exits"; + + /* Find the room exit that matches the NPC room. */ + found = FALSE; + dir_match = 0; + for (dir = 0; dirnames[dir]; dir++) { + vt_key[3].integer = dir; + if (prop_get(bundle, "I<-sisi", &vt_rvalue, vt_key)) { + sc_int dest; + + /* Get room's direction destination, and compare. */ + vt_key[4].string = "Dest"; + dest = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if (dest == npc_room) { + dir_match = dir; + found = TRUE; + break; + } + } + } + + /* Print NPC exit/entry details. */ + pf_buffer_character(filter, '\n'); + pf_new_sentence(filter); + pf_buffer_string(filter, name); + pf_buffer_character(filter, ' '); + pf_buffer_string(filter, text); + if (found) { + pf_buffer_string(filter, is_exit ? " to " : " from "); + pf_buffer_string(filter, dirnames[dir_match]); + } + pf_buffer_string(filter, ".\n"); + + /* Handle any associated resource. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Res"; + vt_key[3].integer = is_exit ? 3 : 2; + res_handle_resource(game, "sisi", vt_key); } @@ -332,123 +313,113 @@ npc_announce (sc_gameref_t game, sc_int npc, * Helper for npc_tick_npc(). */ static void -npc_tick_npc_walk (sc_gameref_t game, sc_int npc, sc_int walk) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[6]; - sc_int roomgroups, movetimes, walkstep, start, dest, destnum; - sc_int chartask, objecttask; - - if (npc_trace) - { - sc_trace ("NPC: ticking NPC %ld, walk %ld: step %ld\n", - npc, walk, gs_npc_walkstep (game, npc, walk)); - } - - /* Count roomgroups for later use. */ - vt_key[0].string = "RoomGroups"; - roomgroups = prop_get_child_count (bundle, "I<-s", vt_key); - - /* Get move times array length. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Walks"; - vt_key[3].integer = walk; - vt_key[4].string = "MoveTimes"; - movetimes = prop_get_child_count (bundle, "I<-sisis", vt_key); - - /* Find a step to match the movetime. */ - for (walkstep = 0; walkstep < movetimes - 1; walkstep++) - { - sc_int movetime; - - vt_key[5].integer = walkstep + 1; - movetime = prop_get_integer (bundle, "I<-sisisi", vt_key); - if (gs_npc_walkstep (game, npc, walk) > movetime) - break; - } - - /* Sort out a destination. */ - dest = start = gs_npc_location (game, npc) - 1; - - vt_key[4].string = "Rooms"; - vt_key[5].integer = walkstep; - destnum = prop_get_integer (bundle, "I<-sisisi", vt_key); - - if (destnum == 0) /* Hidden. */ - dest = -1; - else if (destnum == 1) /* Follow player. */ - dest = gs_playerroom (game); - else if (destnum < gs_room_count (game) + 2) - dest = destnum - 2; /* To room. */ - else if (destnum < gs_room_count (game) + 2 + roomgroups) - { - sc_int initial; - - /* For roomgroup walks, move only if walksteps has just refreshed. */ - vt_key[4].string = "MoveTimes"; - vt_key[5].integer = 0; - initial = prop_get_integer (bundle, "I<-sisisi", vt_key); - if (gs_npc_walkstep (game, npc, walk) == initial) - { - sc_int group; - - group = destnum - 2 - gs_room_count (game); - dest = npc_random_adjacent_roomgroup_member (game, start, group); - if (dest == -1) - dest = lib_random_roomgroup_member (game, group); - } - } - - /* See if the NPC actually moved. */ - if (start != dest) - { - if (npc_trace) - sc_trace ("NPC: walking NPC %ld moved to %ld\n", npc, dest); - - /* Move NPC to destination. */ - gs_set_npc_location (game, npc, dest + 1); - - /* Announce NPC movements, and handle meeting characters and objects. */ - if (gs_player_in_room (game, start)) - npc_announce (game, npc, start, TRUE, dest); - else if (gs_player_in_room (game, dest)) - npc_announce (game, npc, dest, FALSE, start); - } - - /* Handle meeting characters and objects. */ - vt_key[4].string = "CharTask"; - chartask = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if (chartask >= 0) - { - sc_int meetchar; - - /* Run meetchar task if appropriate. */ - vt_key[4].string = "MeetChar"; - meetchar = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if ((meetchar == -1 && gs_player_in_room (game, dest)) - || (meetchar >= 0 && dest == gs_npc_location (game, meetchar) - 1)) - { - if (task_can_run_task (game, chartask)) - task_run_task (game, chartask, TRUE); - } - } - - vt_key[4].string = "ObjectTask"; - objecttask = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if (objecttask >= 0) - { - sc_int meetobject; - - /* Run meetobject task if appropriate. */ - vt_key[4].string = "MeetObject"; - meetobject = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if (meetobject >= 0 && obj_directly_in_room (game, meetobject, dest)) - { - if (task_can_run_task (game, objecttask)) - task_run_task (game, objecttask, TRUE); - } - } +npc_tick_npc_walk(sc_gameref_t game, sc_int npc, sc_int walk) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[6]; + sc_int roomgroups, movetimes, walkstep, start, dest, destnum; + sc_int chartask, objecttask; + + if (npc_trace) { + sc_trace("NPC: ticking NPC %ld, walk %ld: step %ld\n", + npc, walk, gs_npc_walkstep(game, npc, walk)); + } + + /* Count roomgroups for later use. */ + vt_key[0].string = "RoomGroups"; + roomgroups = prop_get_child_count(bundle, "I<-s", vt_key); + + /* Get move times array length. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Walks"; + vt_key[3].integer = walk; + vt_key[4].string = "MoveTimes"; + movetimes = prop_get_child_count(bundle, "I<-sisis", vt_key); + + /* Find a step to match the movetime. */ + for (walkstep = 0; walkstep < movetimes - 1; walkstep++) { + sc_int movetime; + + vt_key[5].integer = walkstep + 1; + movetime = prop_get_integer(bundle, "I<-sisisi", vt_key); + if (gs_npc_walkstep(game, npc, walk) > movetime) + break; + } + + /* Sort out a destination. */ + dest = start = gs_npc_location(game, npc) - 1; + + vt_key[4].string = "Rooms"; + vt_key[5].integer = walkstep; + destnum = prop_get_integer(bundle, "I<-sisisi", vt_key); + + if (destnum == 0) /* Hidden. */ + dest = -1; + else if (destnum == 1) /* Follow player. */ + dest = gs_playerroom(game); + else if (destnum < gs_room_count(game) + 2) + dest = destnum - 2; /* To room. */ + else if (destnum < gs_room_count(game) + 2 + roomgroups) { + sc_int initial; + + /* For roomgroup walks, move only if walksteps has just refreshed. */ + vt_key[4].string = "MoveTimes"; + vt_key[5].integer = 0; + initial = prop_get_integer(bundle, "I<-sisisi", vt_key); + if (gs_npc_walkstep(game, npc, walk) == initial) { + sc_int group; + + group = destnum - 2 - gs_room_count(game); + dest = npc_random_adjacent_roomgroup_member(game, start, group); + if (dest == -1) + dest = lib_random_roomgroup_member(game, group); + } + } + + /* See if the NPC actually moved. */ + if (start != dest) { + if (npc_trace) + sc_trace("NPC: walking NPC %ld moved to %ld\n", npc, dest); + + /* Move NPC to destination. */ + gs_set_npc_location(game, npc, dest + 1); + + /* Announce NPC movements, and handle meeting characters and objects. */ + if (gs_player_in_room(game, start)) + npc_announce(game, npc, start, TRUE, dest); + else if (gs_player_in_room(game, dest)) + npc_announce(game, npc, dest, FALSE, start); + } + + /* Handle meeting characters and objects. */ + vt_key[4].string = "CharTask"; + chartask = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if (chartask >= 0) { + sc_int meetchar; + + /* Run meetchar task if appropriate. */ + vt_key[4].string = "MeetChar"; + meetchar = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if ((meetchar == -1 && gs_player_in_room(game, dest)) + || (meetchar >= 0 && dest == gs_npc_location(game, meetchar) - 1)) { + if (task_can_run_task(game, chartask)) + task_run_task(game, chartask, TRUE); + } + } + + vt_key[4].string = "ObjectTask"; + objecttask = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if (objecttask >= 0) { + sc_int meetobject; + + /* Run meetobject task if appropriate. */ + vt_key[4].string = "MeetObject"; + meetobject = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if (meetobject >= 0 && obj_directly_in_room(game, meetobject, dest)) { + if (task_can_run_task(game, objecttask)) + task_run_task(game, objecttask, TRUE); + } + } } @@ -458,99 +429,91 @@ npc_tick_npc_walk (sc_gameref_t game, sc_int npc, sc_int walk) * Move an NPC one step along current walk. */ static void -npc_tick_npc (sc_gameref_t game, sc_int npc) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[6]; - sc_int walk; - sc_bool has_moved = FALSE; - - if (npc_trace) - sc_trace ("NPC: ticking NPC %ld\n", npc); - - /* Set up invariant key parts. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Walks"; - - /* Find active walk, and if any found, make a step along it. */ - for (walk = gs_npc_walkstep_count (game, npc) - 1; walk >= 0; walk--) - { - sc_int starttask, stoppingtask; - - /* Ignore finished walks. */ - if (gs_npc_walkstep (game, npc, walk) <= 0) - continue; - - /* Get start task. */ - vt_key[3].integer = walk; - vt_key[4].string = "StartTask"; - starttask = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - - /* - * Check that the starter is still complete, and if not, stop walk. - * Then keep on looking for an active walk. - */ - if (starttask >= 0 && !gs_task_done (game, starttask)) - { - if (npc_trace) - sc_trace ("NPC: stopping NPC %ld walk, start task undone\n", npc); - - gs_set_npc_walkstep (game, npc, walk, -1); - continue; - } - - /* Get stopping task. */ - vt_key[4].string = "StoppingTask"; - stoppingtask = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - - /* - * If any stopping task has completed, ignore this walk but don't - * actually finish it; more like an event pauser, then. - * - * TODO Is this right? - */ - if (stoppingtask >= 0 && gs_task_done (game, stoppingtask)) - { - if (npc_trace) - sc_trace ("NPC: ignoring NPC %ld walk, stop task done\n", npc); - - continue; - } - - /* Decrement steps. */ - gs_decrement_npc_walkstep (game, npc, walk); - - /* If we just hit a walk end, loop if called for. */ - if (gs_npc_walkstep (game, npc, walk) == 0) - { - sc_bool is_loop; - - /* If walk is a loop, restart it. */ - vt_key[4].string = "Loop"; - is_loop = prop_get_boolean (bundle, "B<-sisis", vt_key); - if (is_loop) - { - vt_key[4].string = "MoveTimes"; - vt_key[5].integer = 0; - gs_set_npc_walkstep (game, npc, walk, - prop_get_integer (bundle, - "I<-sisisi", vt_key)); - } - else - gs_set_npc_walkstep (game, npc, walk, -1); - } - - /* - * If not yet made a move on this walk, make one, and once made, make - * no other - */ - if (!has_moved) - { - npc_tick_npc_walk (game, npc, walk); - has_moved = TRUE; - } - } +npc_tick_npc(sc_gameref_t game, sc_int npc) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[6]; + sc_int walk; + sc_bool has_moved = FALSE; + + if (npc_trace) + sc_trace("NPC: ticking NPC %ld\n", npc); + + /* Set up invariant key parts. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Walks"; + + /* Find active walk, and if any found, make a step along it. */ + for (walk = gs_npc_walkstep_count(game, npc) - 1; walk >= 0; walk--) { + sc_int starttask, stoppingtask; + + /* Ignore finished walks. */ + if (gs_npc_walkstep(game, npc, walk) <= 0) + continue; + + /* Get start task. */ + vt_key[3].integer = walk; + vt_key[4].string = "StartTask"; + starttask = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + + /* + * Check that the starter is still complete, and if not, stop walk. + * Then keep on looking for an active walk. + */ + if (starttask >= 0 && !gs_task_done(game, starttask)) { + if (npc_trace) + sc_trace("NPC: stopping NPC %ld walk, start task undone\n", npc); + + gs_set_npc_walkstep(game, npc, walk, -1); + continue; + } + + /* Get stopping task. */ + vt_key[4].string = "StoppingTask"; + stoppingtask = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + + /* + * If any stopping task has completed, ignore this walk but don't + * actually finish it; more like an event pauser, then. + * + * TODO Is this right? + */ + if (stoppingtask >= 0 && gs_task_done(game, stoppingtask)) { + if (npc_trace) + sc_trace("NPC: ignoring NPC %ld walk, stop task done\n", npc); + + continue; + } + + /* Decrement steps. */ + gs_decrement_npc_walkstep(game, npc, walk); + + /* If we just hit a walk end, loop if called for. */ + if (gs_npc_walkstep(game, npc, walk) == 0) { + sc_bool is_loop; + + /* If walk is a loop, restart it. */ + vt_key[4].string = "Loop"; + is_loop = prop_get_boolean(bundle, "B<-sisis", vt_key); + if (is_loop) { + vt_key[4].string = "MoveTimes"; + vt_key[5].integer = 0; + gs_set_npc_walkstep(game, npc, walk, + prop_get_integer(bundle, + "I<-sisisi", vt_key)); + } else + gs_set_npc_walkstep(game, npc, walk, -1); + } + + /* + * If not yet made a move on this walk, make one, and once made, make + * no other + */ + if (!has_moved) { + npc_tick_npc_walk(game, npc, walk); + has_moved = TRUE; + } + } } @@ -560,68 +523,62 @@ npc_tick_npc (sc_gameref_t game, sc_int npc) * Move each NPC one step along current walk. */ void -npc_tick_npcs (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_gameref_t undo = game->undo; - sc_int npc; - - /* - * Compare the player location to last turn, to see if the player has moved - * this turn. If moved, look for meetings with NPCs. - * - * TODO Is this the right place to do this. After ticking each NPC, rather - * than before, seems more appropriate. But the messages come out in the - * right order by putting it here. - * - * Also, note that we take the shortcut of using the undo gamestate here, - * rather than properly recording the prior location of the player, and - * perhaps also NPCs, in the live gamestate. - */ - if (undo && !gs_player_in_room (undo, gs_playerroom (game))) - { - for (npc = 0; npc < gs_npc_count (game); npc++) - { - sc_int walk; - - /* Iterate each NPC's walks. */ - for (walk = gs_npc_walkstep_count (game, npc) - 1; walk >= 0; walk--) - { - sc_vartype_t vt_key[5]; - sc_int chartask; - - /* Ignore finished walks. */ - if (gs_npc_walkstep (game, npc, walk) <= 0) - continue; - - /* Retrieve any character meeting task for the NPC. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Walks"; - vt_key[3].integer = walk; - vt_key[4].string = "CharTask"; - chartask = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if (chartask >= 0) - { - sc_int meetchar; - - /* Run meetchar task if appropriate. */ - vt_key[4].string = "MeetChar"; - meetchar = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if (meetchar == -1 && - gs_player_in_room (game, gs_npc_location (game, npc) - 1)) - { - if (task_can_run_task (game, chartask)) - task_run_task (game, chartask, TRUE); - } - } - } - } - } - - /* Iterate and tick each individual NPC. */ - for (npc = 0; npc < gs_npc_count (game); npc++) - npc_tick_npc (game, npc); +npc_tick_npcs(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_gameref_t undo = game->undo; + sc_int npc; + + /* + * Compare the player location to last turn, to see if the player has moved + * this turn. If moved, look for meetings with NPCs. + * + * TODO Is this the right place to do this. After ticking each NPC, rather + * than before, seems more appropriate. But the messages come out in the + * right order by putting it here. + * + * Also, note that we take the shortcut of using the undo gamestate here, + * rather than properly recording the prior location of the player, and + * perhaps also NPCs, in the live gamestate. + */ + if (undo && !gs_player_in_room(undo, gs_playerroom(game))) { + for (npc = 0; npc < gs_npc_count(game); npc++) { + sc_int walk; + + /* Iterate each NPC's walks. */ + for (walk = gs_npc_walkstep_count(game, npc) - 1; walk >= 0; walk--) { + sc_vartype_t vt_key[5]; + sc_int chartask; + + /* Ignore finished walks. */ + if (gs_npc_walkstep(game, npc, walk) <= 0) + continue; + + /* Retrieve any character meeting task for the NPC. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Walks"; + vt_key[3].integer = walk; + vt_key[4].string = "CharTask"; + chartask = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if (chartask >= 0) { + sc_int meetchar; + + /* Run meetchar task if appropriate. */ + vt_key[4].string = "MeetChar"; + meetchar = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if (meetchar == -1 && + gs_player_in_room(game, gs_npc_location(game, npc) - 1)) { + if (task_can_run_task(game, chartask)) + task_run_task(game, chartask, TRUE); + } + } + } + } + } + + /* Iterate and tick each individual NPC. */ + for (npc = 0; npc < gs_npc_count(game); npc++) + npc_tick_npc(game, npc); } @@ -631,9 +588,8 @@ npc_tick_npcs (sc_gameref_t game) * Set NPC tracing on/off. */ void -npc_debug_trace (sc_bool flag) -{ - npc_trace = flag; +npc_debug_trace(sc_bool flag) { + npc_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scobjcts.cpp b/engines/glk/adrift/scobjcts.cpp index 9bef9952e3..28a89abed3 100644 --- a/engines/glk/adrift/scobjcts.cpp +++ b/engines/glk/adrift/scobjcts.cpp @@ -42,45 +42,42 @@ static sc_bool obj_trace = FALSE; * Convenience functions to return TRUE for given object attributes. */ sc_bool -obj_is_static (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_bool bstatic; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Static"; - bstatic = prop_get_boolean (bundle, "B<-sis", vt_key); - return bstatic; +obj_is_static(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_bool bstatic; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Static"; + bstatic = prop_get_boolean(bundle, "B<-sis", vt_key); + return bstatic; } sc_bool -obj_is_container (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_bool is_container; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Container"; - is_container = prop_get_boolean (bundle, "B<-sis", vt_key); - return is_container; +obj_is_container(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_bool is_container; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Container"; + is_container = prop_get_boolean(bundle, "B<-sis", vt_key); + return is_container; } sc_bool -obj_is_surface (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_bool is_surface; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Surface"; - is_surface = prop_get_boolean (bundle, "B<-sis", vt_key); - return is_surface; +obj_is_surface(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_bool is_surface; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Surface"; + is_surface = prop_get_boolean(bundle, "B<-sis", vt_key); + return is_surface; } @@ -90,18 +87,16 @@ obj_is_surface (sc_gameref_t game, sc_int object) * Return the index of the n'th container object found. */ sc_int -obj_container_object (sc_gameref_t game, sc_int n) -{ - sc_int object, count; - - /* Progress through objects until n containers found. */ - count = n; - for (object = 0; object < gs_object_count (game) && count >= 0; object++) - { - if (obj_is_container (game, object)) - count--; - } - return object - 1; +obj_container_object(sc_gameref_t game, sc_int n) { + sc_int object, count; + + /* Progress through objects until n containers found. */ + count = n; + for (object = 0; object < gs_object_count(game) && count >= 0; object++) { + if (obj_is_container(game, object)) + count--; + } + return object - 1; } @@ -111,18 +106,16 @@ obj_container_object (sc_gameref_t game, sc_int n) * Return index such that obj_container_object(index) == objnum. */ sc_int -obj_container_index (sc_gameref_t game, sc_int objnum) -{ - sc_int object, count; - - /* Progress through objects up to objnum. */ - count = 0; - for (object = 0; object < objnum; object++) - { - if (obj_is_container (game, object)) - count++; - } - return count; +obj_container_index(sc_gameref_t game, sc_int objnum) { + sc_int object, count; + + /* Progress through objects up to objnum. */ + count = 0; + for (object = 0; object < objnum; object++) { + if (obj_is_container(game, object)) + count++; + } + return count; } @@ -132,18 +125,16 @@ obj_container_index (sc_gameref_t game, sc_int objnum) * Return the index of the n'th surface object found. */ sc_int -obj_surface_object (sc_gameref_t game, sc_int n) -{ - sc_int object, count; - - /* Progress through objects until n surfaces found. */ - count = n; - for (object = 0; object < gs_object_count (game) && count >= 0; object++) - { - if (obj_is_surface (game, object)) - count--; - } - return object - 1; +obj_surface_object(sc_gameref_t game, sc_int n) { + sc_int object, count; + + /* Progress through objects until n surfaces found. */ + count = n; + for (object = 0; object < gs_object_count(game) && count >= 0; object++) { + if (obj_is_surface(game, object)) + count--; + } + return object - 1; } @@ -153,18 +144,16 @@ obj_surface_object (sc_gameref_t game, sc_int n) * Return index such that obj_surface_object(index) == objnum. */ sc_int -obj_surface_index (sc_gameref_t game, sc_int objnum) -{ - sc_int object, count; - - /* Progress through objects up to objnum. */ - count = 0; - for (object = 0; object < objnum; object++) - { - if (obj_is_surface (game, object)) - count++; - } - return count; +obj_surface_index(sc_gameref_t game, sc_int objnum) { + sc_int object, count; + + /* Progress through objects up to objnum. */ + count = 0; + for (object = 0; object < objnum; object++) { + if (obj_is_surface(game, object)) + count++; + } + return count; } @@ -174,28 +163,26 @@ obj_surface_index (sc_gameref_t game, sc_int objnum) * Return the index of the n'th openable or statussed object found. */ sc_int -obj_stateful_object (sc_gameref_t game, sc_int n) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, count; - - /* Progress through objects until n matches found. */ - count = n; - for (object = 0; object < gs_object_count (game) && count >= 0; object++) - { - sc_vartype_t vt_key[3]; - sc_bool is_openable, is_statussed; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Openable"; - is_openable = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - vt_key[2].string = "CurrentState"; - is_statussed = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - if (is_openable || is_statussed) - count--; - } - return object - 1; +obj_stateful_object(sc_gameref_t game, sc_int n) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, count; + + /* Progress through objects until n matches found. */ + count = n; + for (object = 0; object < gs_object_count(game) && count >= 0; object++) { + sc_vartype_t vt_key[3]; + sc_bool is_openable, is_statussed; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Openable"; + is_openable = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + vt_key[2].string = "CurrentState"; + is_statussed = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + if (is_openable || is_statussed) + count--; + } + return object - 1; } @@ -205,28 +192,26 @@ obj_stateful_object (sc_gameref_t game, sc_int n) * Return index such that obj_stateful_object(index) == objnum. */ sc_int -obj_stateful_index (sc_gameref_t game, sc_int objnum) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, count; - - /* Progress through objects up to objnum. */ - count = 0; - for (object = 0; object < objnum; object++) - { - sc_vartype_t vt_key[3]; - sc_bool is_openable, is_statussed; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Openable"; - is_openable = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - vt_key[2].string = "CurrentState"; - is_statussed = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - if (is_openable || is_statussed) - count++; - } - return count; +obj_stateful_index(sc_gameref_t game, sc_int objnum) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, count; + + /* Progress through objects up to objnum. */ + count = 0; + for (object = 0; object < objnum; object++) { + sc_vartype_t vt_key[3]; + sc_bool is_openable, is_statussed; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Openable"; + is_openable = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + vt_key[2].string = "CurrentState"; + is_statussed = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + if (is_openable || is_statussed) + count++; + } + return count; } @@ -238,44 +223,41 @@ obj_stateful_index (sc_gameref_t game, sc_int objnum) * if no valid state string found. */ sc_char * -obj_state_name (sc_gameref_t game, sc_int objnum) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *states; - sc_int length, state, count, first, last; - sc_char *string; - - /* Get the list of state strings for the object. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = objnum; - vt_key[2].string = "States"; - states = prop_get_string (bundle, "S<-sis", vt_key); - - /* Find the start of the element for the current state. */ - state = gs_object_state (game, objnum); - length = strlen (states); - for (first = 0, count = state; first < length && count > 1; first++) - { - if (states[first] == '|') - count--; - } - if (count != 1) - return NULL; - - /* Find the end of the state string. */ - for (last = first; last < length; last++) - { - if (states[last] == '|') - break; - } - - /* Allocate and take a copy of the state string. */ - string = (sc_char *)sc_malloc (last - first + 1); - memcpy (string, states + first, last - first); - string[last - first] = NUL; - - return string; +obj_state_name(sc_gameref_t game, sc_int objnum) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *states; + sc_int length, state, count, first, last; + sc_char *string; + + /* Get the list of state strings for the object. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = objnum; + vt_key[2].string = "States"; + states = prop_get_string(bundle, "S<-sis", vt_key); + + /* Find the start of the element for the current state. */ + state = gs_object_state(game, objnum); + length = strlen(states); + for (first = 0, count = state; first < length && count > 1; first++) { + if (states[first] == '|') + count--; + } + if (count != 1) + return NULL; + + /* Find the end of the state string. */ + for (last = first; last < length; last++) { + if (states[last] == '|') + break; + } + + /* Allocate and take a copy of the state string. */ + string = (sc_char *)sc_malloc(last - first + 1); + memcpy(string, states + first, last - first); + string[last - first] = NUL; + + return string; } @@ -285,18 +267,16 @@ obj_state_name (sc_gameref_t game, sc_int objnum) * Return the index of the n'th non-static object found. */ sc_int -obj_dynamic_object (sc_gameref_t game, sc_int n) -{ - sc_int object, count; - - /* Progress through objects until n matches found. */ - count = n; - for (object = 0; object < gs_object_count (game) && count >= 0; object++) - { - if (!obj_is_static (game, object)) - count--; - } - return object - 1; +obj_dynamic_object(sc_gameref_t game, sc_int n) { + sc_int object, count; + + /* Progress through objects until n matches found. */ + count = n; + for (object = 0; object < gs_object_count(game) && count >= 0; object++) { + if (!obj_is_static(game, object)) + count--; + } + return object - 1; } @@ -306,27 +286,24 @@ obj_dynamic_object (sc_gameref_t game, sc_int n) * Return the index of the n'th wearable object found. */ sc_int -obj_wearable_object (sc_gameref_t game, sc_int n) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, count; - - /* Progress through objects until n matches found. */ - count = n; - for (object = 0; object < gs_object_count (game) && count >= 0; object++) - { - if (!obj_is_static (game, object)) - { - sc_vartype_t vt_key[3]; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Wearable"; - if (prop_get_boolean (bundle, "B<-sis", vt_key)) - count--; - } - } - return object - 1; +obj_wearable_object(sc_gameref_t game, sc_int n) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, count; + + /* Progress through objects until n matches found. */ + count = n; + for (object = 0; object < gs_object_count(game) && count >= 0; object++) { + if (!obj_is_static(game, object)) { + sc_vartype_t vt_key[3]; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Wearable"; + if (prop_get_boolean(bundle, "B<-sis", vt_key)) + count--; + } + } + return object - 1; } @@ -337,9 +314,9 @@ obj_wearable_object (sc_gameref_t game, sc_int n) * are also used for the maximum size of object that can fit in a container, * and the number of these that fit. */ -enum -{ OBJ_DIMENSION_DIVISOR = 10, - OBJ_DIMENSION_MULTIPLE = 3 +enum { + OBJ_DIMENSION_DIVISOR = 10, + OBJ_DIMENSION_MULTIPLE = 3 }; /* @@ -353,83 +330,78 @@ enum * by events -- how should these be handled, as they have no SizeWeight? */ sc_int -obj_get_size (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int size, count; - - /* TODO For now, give static objects no size. */ - if (obj_is_static (game, object)) - return 0; - - /* Size is the 'tens' component of SizeWeight. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "SizeWeight"; - count = prop_get_integer (bundle, "I<-sis", vt_key) / OBJ_DIMENSION_DIVISOR; - - /* - * Calculate base object size. Unlike weights below, we take this as simply - * being the maximum size; that is, when a container carries other objects - * its weight increases by the sum of objects carried, but its size remains - * constant. - */ - size = 1; - for (; count > 0; count--) - size *= OBJ_DIMENSION_MULTIPLE; - - if (obj_trace) - sc_trace ("Object: object %ld is size %ld\n", object, size); - - /* Return total size. */ - return size; +obj_get_size(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int size, count; + + /* TODO For now, give static objects no size. */ + if (obj_is_static(game, object)) + return 0; + + /* Size is the 'tens' component of SizeWeight. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "SizeWeight"; + count = prop_get_integer(bundle, "I<-sis", vt_key) / OBJ_DIMENSION_DIVISOR; + + /* + * Calculate base object size. Unlike weights below, we take this as simply + * being the maximum size; that is, when a container carries other objects + * its weight increases by the sum of objects carried, but its size remains + * constant. + */ + size = 1; + for (; count > 0; count--) + size *= OBJ_DIMENSION_MULTIPLE; + + if (obj_trace) + sc_trace("Object: object %ld is size %ld\n", object, size); + + /* Return total size. */ + return size; } sc_int -obj_get_weight (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int weight, count; - - /* TODO For now, give static objects no weight. */ - if (obj_is_static (game, object)) - return 0; - - /* Weight is the 'units' component of SizeWeight. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "SizeWeight"; - count = prop_get_integer (bundle, "I<-sis", vt_key) % OBJ_DIMENSION_DIVISOR; - - /* Calculate base object weight. */ - weight = 1; - for (; count > 0; count--) - weight *= OBJ_DIMENSION_MULTIPLE; - - /* If this is a container or a surface, add weights of parented objects. */ - if (obj_is_container (game, object) || obj_is_surface (game, object)) - { - sc_int other; - - /* Find and add contained or surface objects. */ - for (other = 0; other < gs_object_count (game); other++) - { - if ((gs_object_position (game, other) == OBJ_IN_OBJECT - || gs_object_position (game, other) == OBJ_ON_OBJECT) - && gs_object_parent (game, other) == object) - { - weight += obj_get_weight (game, other); - } - } - } - - if (obj_trace) - sc_trace ("Object: object %ld is weight %ld\n", object, weight); - - /* Return total weight. */ - return weight; +obj_get_weight(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int weight, count; + + /* TODO For now, give static objects no weight. */ + if (obj_is_static(game, object)) + return 0; + + /* Weight is the 'units' component of SizeWeight. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "SizeWeight"; + count = prop_get_integer(bundle, "I<-sis", vt_key) % OBJ_DIMENSION_DIVISOR; + + /* Calculate base object weight. */ + weight = 1; + for (; count > 0; count--) + weight *= OBJ_DIMENSION_MULTIPLE; + + /* If this is a container or a surface, add weights of parented objects. */ + if (obj_is_container(game, object) || obj_is_surface(game, object)) { + sc_int other; + + /* Find and add contained or surface objects. */ + for (other = 0; other < gs_object_count(game); other++) { + if ((gs_object_position(game, other) == OBJ_IN_OBJECT + || gs_object_position(game, other) == OBJ_ON_OBJECT) + && gs_object_parent(game, other) == object) { + weight += obj_get_weight(game, other); + } + } + } + + if (obj_trace) + sc_trace("Object: object %ld is weight %ld\n", object, weight); + + /* Return total weight. */ + return weight; } @@ -442,44 +414,41 @@ obj_get_weight (sc_gameref_t game, sc_int object) * really object-related except that they deal with sizing multiples. */ static sc_int -obj_convert_player_limit (sc_int value) -{ - sc_int retval, index_; +obj_convert_player_limit(sc_int value) { + sc_int retval, index_; - /* 'Tens' of value multiplied by 3 to the power 'units' of value. */ - retval = value / OBJ_DIMENSION_DIVISOR; - for (index_ = 0; index_ < value % OBJ_DIMENSION_DIVISOR; index_++) - retval *= OBJ_DIMENSION_MULTIPLE; + /* 'Tens' of value multiplied by 3 to the power 'units' of value. */ + retval = value / OBJ_DIMENSION_DIVISOR; + for (index_ = 0; index_ < value % OBJ_DIMENSION_DIVISOR; index_++) + retval *= OBJ_DIMENSION_MULTIPLE; - return retval; + return retval; } sc_int -obj_get_player_size_limit (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_int max_size; +obj_get_player_size_limit(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_int max_size; - vt_key[0].string = "Globals"; - vt_key[1].string = "MaxSize"; - max_size = prop_get_integer (bundle, "I<-ss", vt_key); + vt_key[0].string = "Globals"; + vt_key[1].string = "MaxSize"; + max_size = prop_get_integer(bundle, "I<-ss", vt_key); - return obj_convert_player_limit (max_size); + return obj_convert_player_limit(max_size); } sc_int -obj_get_player_weight_limit (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_int max_weight; +obj_get_player_weight_limit(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_int max_weight; - vt_key[0].string = "Globals"; - vt_key[1].string = "MaxWt"; - max_weight = prop_get_integer (bundle, "I<-ss", vt_key); + vt_key[0].string = "Globals"; + vt_key[1].string = "MaxWt"; + max_weight = prop_get_integer(bundle, "I<-ss", vt_key); - return obj_convert_player_limit (max_weight); + return obj_convert_player_limit(max_weight); } @@ -491,54 +460,52 @@ obj_get_player_weight_limit (sc_gameref_t game) * and the number that will fit. */ sc_int -obj_get_container_maxsize (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int maxsize, count; - - /* Maxsize is found from the 'units' component of Capacity. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Capacity"; - count = prop_get_integer (bundle, "I<-sis", vt_key) % OBJ_DIMENSION_DIVISOR; - - /* Calculate and return maximum size. */ - maxsize = 1; - for (; count > 0; count--) - maxsize *= OBJ_DIMENSION_MULTIPLE; - - if (obj_trace) - sc_trace ("Object: object %ld has max size %ld\n", object, maxsize); - - return maxsize; +obj_get_container_maxsize(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int maxsize, count; + + /* Maxsize is found from the 'units' component of Capacity. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Capacity"; + count = prop_get_integer(bundle, "I<-sis", vt_key) % OBJ_DIMENSION_DIVISOR; + + /* Calculate and return maximum size. */ + maxsize = 1; + for (; count > 0; count--) + maxsize *= OBJ_DIMENSION_MULTIPLE; + + if (obj_trace) + sc_trace("Object: object %ld has max size %ld\n", object, maxsize); + + return maxsize; } sc_int -obj_get_container_capacity (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int capacity; - - /* The count of objects is in the 'tens' component of Capacity. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Capacity"; - capacity = prop_get_integer (bundle, "I<-sis", vt_key) - / OBJ_DIMENSION_DIVISOR; - - if (obj_trace) - sc_trace ("Object: object %ld has capacity %ld\n", object, capacity); - - return capacity; +obj_get_container_capacity(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int capacity; + + /* The count of objects is in the 'tens' component of Capacity. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Capacity"; + capacity = prop_get_integer(bundle, "I<-sis", vt_key) + / OBJ_DIMENSION_DIVISOR; + + if (obj_trace) + sc_trace("Object: object %ld has capacity %ld\n", object, capacity); + + return capacity; } /* Sit/lie bit mask enumerations. */ -enum -{ OBJ_STANDABLE_MASK = 1 << 0, - OBJ_LIEABLE_MASK = 1 << 1 +enum { + OBJ_STANDABLE_MASK = 1 << 0, + OBJ_LIEABLE_MASK = 1 << 1 }; /* @@ -547,26 +514,24 @@ enum * Return the index of the n'th standable object found. */ sc_int -obj_standable_object (sc_gameref_t game, sc_int n) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, count; - - /* Progress through objects until n standable found. */ - count = n; - for (object = 0; object < gs_object_count (game) && count >= 0; object++) - { - sc_vartype_t vt_key[3]; - sc_int sit_lie_flags; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "SitLie"; - sit_lie_flags = prop_get_integer (bundle, "I<-sis", vt_key); - if (sit_lie_flags & OBJ_STANDABLE_MASK) - count--; - } - return object - 1; +obj_standable_object(sc_gameref_t game, sc_int n) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, count; + + /* Progress through objects until n standable found. */ + count = n; + for (object = 0; object < gs_object_count(game) && count >= 0; object++) { + sc_vartype_t vt_key[3]; + sc_int sit_lie_flags; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "SitLie"; + sit_lie_flags = prop_get_integer(bundle, "I<-sis", vt_key); + if (sit_lie_flags & OBJ_STANDABLE_MASK) + count--; + } + return object - 1; } @@ -576,26 +541,24 @@ obj_standable_object (sc_gameref_t game, sc_int n) * Return the index of the n'th lieable object found. */ sc_int -obj_lieable_object (sc_gameref_t game, sc_int n) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int object, count; - - /* Progress through objects until n lieable found. */ - count = n; - for (object = 0; object < gs_object_count (game) && count >= 0; object++) - { - sc_vartype_t vt_key[3]; - sc_int sit_lie_flags; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "SitLie"; - sit_lie_flags = prop_get_integer (bundle, "I<-sis", vt_key); - if (sit_lie_flags & OBJ_LIEABLE_MASK) - count--; - } - return object - 1; +obj_lieable_object(sc_gameref_t game, sc_int n) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int object, count; + + /* Progress through objects until n lieable found. */ + count = n; + for (object = 0; object < gs_object_count(game) && count >= 0; object++) { + sc_vartype_t vt_key[3]; + sc_int sit_lie_flags; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "SitLie"; + sit_lie_flags = prop_get_integer(bundle, "I<-sis", vt_key); + if (sit_lie_flags & OBJ_LIEABLE_MASK) + count--; + } + return object - 1; } @@ -609,37 +572,35 @@ obj_lieable_object (sc_gameref_t game, sc_int n) * that is not preceded by 'u'. */ sc_bool -obj_appears_plural (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *prefix, *name; - - /* Check prefix for "a", "an", or empty. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - - if (!(sc_strempty (prefix) - || sc_compare_word (prefix, "a", 1) - || sc_compare_word (prefix, "an", 2))) - { - sc_int length; - - /* Check name for ending in 's', but not 'us'. */ - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - length = strlen (name); - - if (!sc_strempty (name) - && sc_tolower (name[length - 1]) == 's' - && (length < 2 || sc_tolower (name[length - 2]) != 'u')) - return TRUE; - } - - /* Doesn't look plural. */ - return FALSE; +obj_appears_plural(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *prefix, *name; + + /* Check prefix for "a", "an", or empty. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + + if (!(sc_strempty(prefix) + || sc_compare_word(prefix, "a", 1) + || sc_compare_word(prefix, "an", 2))) { + sc_int length; + + /* Check name for ending in 's', but not 'us'. */ + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + length = strlen(name); + + if (!sc_strempty(name) + && sc_tolower(name[length - 1]) == 's' + && (length < 2 || sc_tolower(name[length - 2]) != 'u')) + return TRUE; + } + + /* Doesn't look plural. */ + return FALSE; } @@ -650,73 +611,66 @@ obj_appears_plural (sc_gameref_t game, sc_int object) * Return TRUE if a given object is currently on the floor of a given room. */ static sc_bool -obj_directly_in_room_internal (sc_gameref_t game, sc_int object, sc_int room) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - - /* See if the object is static or dynamic. */ - if (obj_is_static (game, object)) - { - sc_vartype_t vt_key[5]; - sc_int type; - - /* Static object moved to player or room by event? */ - if (!gs_object_static_unmoved (game, object)) - { - if (gs_object_position (game, object) == OBJ_HELD_PLAYER) - return FALSE; - else - return gs_object_position (game, object) - 1 == room; - } - - /* Check and return the room list for the object. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Where"; - vt_key[3].string = "Type"; - type = prop_get_integer (bundle, "I<-siss", vt_key); - switch (type) - { - case ROOMLIST_ALL_ROOMS: - return TRUE; - case ROOMLIST_NO_ROOMS: - case ROOMLIST_NPC_PART: - return FALSE; - - case ROOMLIST_ONE_ROOM: - vt_key[3].string = "Room"; - return prop_get_integer (bundle, "I<-siss", vt_key) == room + 1; - - case ROOMLIST_SOME_ROOMS: - vt_key[3].string = "Rooms"; - vt_key[4].integer = room + 1; - return prop_get_boolean (bundle, "B<-sissi", vt_key); - - default: - sc_fatal ("obj_directly_in_room_internal:" - " invalid type, %ld\n", type); - return FALSE; - } - } - else - return gs_object_position (game, object) == room + 1; +obj_directly_in_room_internal(sc_gameref_t game, sc_int object, sc_int room) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + + /* See if the object is static or dynamic. */ + if (obj_is_static(game, object)) { + sc_vartype_t vt_key[5]; + sc_int type; + + /* Static object moved to player or room by event? */ + if (!gs_object_static_unmoved(game, object)) { + if (gs_object_position(game, object) == OBJ_HELD_PLAYER) + return FALSE; + else + return gs_object_position(game, object) - 1 == room; + } + + /* Check and return the room list for the object. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Where"; + vt_key[3].string = "Type"; + type = prop_get_integer(bundle, "I<-siss", vt_key); + switch (type) { + case ROOMLIST_ALL_ROOMS: + return TRUE; + case ROOMLIST_NO_ROOMS: + case ROOMLIST_NPC_PART: + return FALSE; + + case ROOMLIST_ONE_ROOM: + vt_key[3].string = "Room"; + return prop_get_integer(bundle, "I<-siss", vt_key) == room + 1; + + case ROOMLIST_SOME_ROOMS: + vt_key[3].string = "Rooms"; + vt_key[4].integer = room + 1; + return prop_get_boolean(bundle, "B<-sissi", vt_key); + + default: + sc_fatal("obj_directly_in_room_internal:" + " invalid type, %ld\n", type); + return FALSE; + } + } else + return gs_object_position(game, object) == room + 1; } sc_bool -obj_directly_in_room (sc_gameref_t game, sc_int object, sc_int room) -{ - sc_bool result; +obj_directly_in_room(sc_gameref_t game, sc_int object, sc_int room) { + sc_bool result; - /* Check, trace result, and return. */ - result = obj_directly_in_room_internal (game, object, room); + /* Check, trace result, and return. */ + result = obj_directly_in_room_internal(game, object, room); - if (obj_trace) - { - sc_trace ("Object: checking for object %ld directly in room %ld, %s\n", - object, room, result ? "true" : "false"); - } + if (obj_trace) { + sc_trace("Object: checking for object %ld directly in room %ld, %s\n", + object, room, result ? "true" : "false"); + } - return result; + return result; } @@ -729,132 +683,119 @@ obj_directly_in_room (sc_gameref_t game, sc_int object, sc_int room) * carried by an NPC in the room. */ static sc_bool -obj_indirectly_in_room_internal (sc_gameref_t game, sc_int object, sc_int room) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - - /* See if the object is static or dynamic. */ - if (obj_is_static (game, object)) - { - sc_vartype_t vt_key[5]; - sc_int type; - - /* Static object moved to player or room by event? */ - if (!gs_object_static_unmoved (game, object)) - { - if (gs_object_position (game, object) == OBJ_HELD_PLAYER) - return gs_player_in_room (game, room); - else - return gs_object_position (game, object) - 1 == room; - } - - /* Check and return the room list for the object. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Where"; - vt_key[3].string = "Type"; - type = prop_get_integer (bundle, "I<-siss", vt_key); - switch (type) - { - case ROOMLIST_ALL_ROOMS: - return TRUE; - case ROOMLIST_NO_ROOMS: - return FALSE; - - case ROOMLIST_ONE_ROOM: - vt_key[3].string = "Room"; - return prop_get_integer (bundle, "I<-siss", vt_key) == room + 1; - - case ROOMLIST_SOME_ROOMS: - vt_key[3].string = "Rooms"; - vt_key[4].integer = room + 1; - return prop_get_boolean (bundle, "B<-sissi", vt_key); - - case ROOMLIST_NPC_PART: - { - sc_int npc; - - vt_key[2].string = "Parent"; - npc = prop_get_integer (bundle, "I<-sis", vt_key); - if (npc == 0) - return gs_player_in_room (game, room); - else - return npc_in_room (game, npc - 1, room); - } - - default: - sc_fatal ("obj_indirectly_in_room_internal:" - " invalid type, %ld\n", type); - return FALSE; - } - } - else - { - sc_int parent, position; - - /* Get dynamic object's parent and position. */ - parent = gs_object_parent (game, object); - position = gs_object_position (game, object); - - /* Decide depending on positioning. */ - switch (position) - { - case OBJ_HIDDEN: /* Hidden. */ - return FALSE; - - case OBJ_HELD_PLAYER: /* Held by player. */ - case OBJ_WORN_PLAYER: /* Worn by player. */ - return gs_player_in_room (game, room); - - case OBJ_HELD_NPC: /* Held by NPC. */ - case OBJ_WORN_NPC: /* Worn by NPC. */ - return npc_in_room (game, parent, room); - - case OBJ_IN_OBJECT: /* In another object. */ - { - sc_int openness; - - openness = gs_object_openness (game, parent); - switch (openness) - { - case OBJ_WONTCLOSE: - case OBJ_OPEN: - return obj_indirectly_in_room (game, parent, room); - default: - return FALSE; - } - } - - case OBJ_ON_OBJECT: /* On another object. */ - return obj_indirectly_in_room (game, parent, room); - - default: /* Within a room. */ - if (position > gs_room_count (game) + 1) - { - sc_error ("sc_object_indirectly_in_room:" - " position out of bounds, %ld\n", position); - } - return position - 1 == room; - } - } +obj_indirectly_in_room_internal(sc_gameref_t game, sc_int object, sc_int room) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + + /* See if the object is static or dynamic. */ + if (obj_is_static(game, object)) { + sc_vartype_t vt_key[5]; + sc_int type; + + /* Static object moved to player or room by event? */ + if (!gs_object_static_unmoved(game, object)) { + if (gs_object_position(game, object) == OBJ_HELD_PLAYER) + return gs_player_in_room(game, room); + else + return gs_object_position(game, object) - 1 == room; + } + + /* Check and return the room list for the object. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Where"; + vt_key[3].string = "Type"; + type = prop_get_integer(bundle, "I<-siss", vt_key); + switch (type) { + case ROOMLIST_ALL_ROOMS: + return TRUE; + case ROOMLIST_NO_ROOMS: + return FALSE; + + case ROOMLIST_ONE_ROOM: + vt_key[3].string = "Room"; + return prop_get_integer(bundle, "I<-siss", vt_key) == room + 1; + + case ROOMLIST_SOME_ROOMS: + vt_key[3].string = "Rooms"; + vt_key[4].integer = room + 1; + return prop_get_boolean(bundle, "B<-sissi", vt_key); + + case ROOMLIST_NPC_PART: { + sc_int npc; + + vt_key[2].string = "Parent"; + npc = prop_get_integer(bundle, "I<-sis", vt_key); + if (npc == 0) + return gs_player_in_room(game, room); + else + return npc_in_room(game, npc - 1, room); + } + + default: + sc_fatal("obj_indirectly_in_room_internal:" + " invalid type, %ld\n", type); + return FALSE; + } + } else { + sc_int parent, position; + + /* Get dynamic object's parent and position. */ + parent = gs_object_parent(game, object); + position = gs_object_position(game, object); + + /* Decide depending on positioning. */ + switch (position) { + case OBJ_HIDDEN: /* Hidden. */ + return FALSE; + + case OBJ_HELD_PLAYER: /* Held by player. */ + case OBJ_WORN_PLAYER: /* Worn by player. */ + return gs_player_in_room(game, room); + + case OBJ_HELD_NPC: /* Held by NPC. */ + case OBJ_WORN_NPC: /* Worn by NPC. */ + return npc_in_room(game, parent, room); + + case OBJ_IN_OBJECT: { /* In another object. */ + sc_int openness; + + openness = gs_object_openness(game, parent); + switch (openness) { + case OBJ_WONTCLOSE: + case OBJ_OPEN: + return obj_indirectly_in_room(game, parent, room); + default: + return FALSE; + } + } + + case OBJ_ON_OBJECT: /* On another object. */ + return obj_indirectly_in_room(game, parent, room); + + default: /* Within a room. */ + if (position > gs_room_count(game) + 1) { + sc_error("sc_object_indirectly_in_room:" + " position out of bounds, %ld\n", position); + } + return position - 1 == room; + } + } } sc_bool -obj_indirectly_in_room (sc_gameref_t game, - sc_int object, sc_int room) -{ - sc_bool result; +obj_indirectly_in_room(sc_gameref_t game, + sc_int object, sc_int room) { + sc_bool result; - /* Check, trace result, and return. */ - result = obj_indirectly_in_room_internal (game, object, room); + /* Check, trace result, and return. */ + result = obj_indirectly_in_room_internal(game, object, room); - if (obj_trace) - { - sc_trace ("Object: checking for object %ld indirectly in room %ld, %s\n", - object, room, result ? "true" : "false"); - } + if (obj_trace) { + sc_trace("Object: checking for object %ld indirectly in room %ld, %s\n", + object, room, result ? "true" : "false"); + } - return result; + return result; } @@ -866,85 +807,75 @@ obj_indirectly_in_room (sc_gameref_t game, * directly, on an object indirectly, or in an open object indirectly. */ static sc_bool -obj_indirectly_held_by_player_internal (sc_gameref_t game, - sc_int object) -{ - /* See if the object is static or dynamic. */ - if (obj_is_static (game, object)) - { - /* Static object moved to player or room by event? */ - if (!gs_object_static_unmoved (game, object)) - { - if (gs_object_position (game, object) == OBJ_HELD_PLAYER) - return TRUE; - else - return FALSE; - } - - /* An unmoved static object is not held by the player. */ - return FALSE; - } - else - { - sc_int parent, position; - - /* Get dynamic object's parent and position. */ - parent = gs_object_parent (game, object); - position = gs_object_position (game, object); - - /* Decide depending on positioning. */ - switch (position) - { - case OBJ_HIDDEN: /* Hidden. */ - return FALSE; - - case OBJ_HELD_PLAYER: /* Held by player. */ - case OBJ_WORN_PLAYER: /* Worn by player. */ - return TRUE; - - case OBJ_HELD_NPC: /* Held by NPC. */ - case OBJ_WORN_NPC: /* Worn by NPC. */ - return FALSE; - - case OBJ_IN_OBJECT: /* In another object. */ - { - sc_int openness; - - openness = gs_object_openness (game, parent); - switch (openness) - { - case OBJ_WONTCLOSE: - case OBJ_OPEN: - return obj_indirectly_held_by_player (game, parent); - default: - return FALSE; - } - } - - case OBJ_ON_OBJECT: /* On another object. */ - return obj_indirectly_held_by_player (game, parent); - - default: /* Within a room. */ - return FALSE; - } - } +obj_indirectly_held_by_player_internal(sc_gameref_t game, + sc_int object) { + /* See if the object is static or dynamic. */ + if (obj_is_static(game, object)) { + /* Static object moved to player or room by event? */ + if (!gs_object_static_unmoved(game, object)) { + if (gs_object_position(game, object) == OBJ_HELD_PLAYER) + return TRUE; + else + return FALSE; + } + + /* An unmoved static object is not held by the player. */ + return FALSE; + } else { + sc_int parent, position; + + /* Get dynamic object's parent and position. */ + parent = gs_object_parent(game, object); + position = gs_object_position(game, object); + + /* Decide depending on positioning. */ + switch (position) { + case OBJ_HIDDEN: /* Hidden. */ + return FALSE; + + case OBJ_HELD_PLAYER: /* Held by player. */ + case OBJ_WORN_PLAYER: /* Worn by player. */ + return TRUE; + + case OBJ_HELD_NPC: /* Held by NPC. */ + case OBJ_WORN_NPC: /* Worn by NPC. */ + return FALSE; + + case OBJ_IN_OBJECT: { /* In another object. */ + sc_int openness; + + openness = gs_object_openness(game, parent); + switch (openness) { + case OBJ_WONTCLOSE: + case OBJ_OPEN: + return obj_indirectly_held_by_player(game, parent); + default: + return FALSE; + } + } + + case OBJ_ON_OBJECT: /* On another object. */ + return obj_indirectly_held_by_player(game, parent); + + default: /* Within a room. */ + return FALSE; + } + } } sc_bool -obj_indirectly_held_by_player (sc_gameref_t game, sc_int object) -{ - sc_bool result; +obj_indirectly_held_by_player(sc_gameref_t game, sc_int object) { + sc_bool result; - /* Check, trace result, and return. */ - result = obj_indirectly_held_by_player_internal (game, object); + /* Check, trace result, and return. */ + result = obj_indirectly_held_by_player_internal(game, object); - if (obj_trace) - { - sc_trace ("Object: checking for object %ld indirectly" - " held by player, %s\n", object, result ? "true" : "false"); - } + if (obj_trace) { + sc_trace("Object: checking for object %ld indirectly" + " held by player, %s\n", object, result ? "true" : "false"); + } - return result; + return result; } @@ -954,42 +885,39 @@ obj_indirectly_held_by_player (sc_gameref_t game, sc_int object) * Return TRUE if this object should be listed as room content. */ sc_bool -obj_shows_initial_description (sc_gameref_t game, sc_int object) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int onlywhennotmoved; - - /* Get only when moved property. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "OnlyWhenNotMoved"; - onlywhennotmoved = prop_get_integer (bundle, "I<-sis", vt_key); - - /* Combine this with game in mysterious ways. */ - switch (onlywhennotmoved) - { - case 0: - return TRUE; - - case 1: - return gs_object_unmoved (game, object); - - case 2: - { - sc_int initialposition; - - if (gs_object_unmoved (game, object)) - return TRUE; - - vt_key[2].string = "InitialPosition"; - initialposition = prop_get_integer (bundle, "I<-sis", vt_key) - 3; - return gs_object_position (game, object) == initialposition; - } - } - - /* What you talkin' 'bout, Willis? */ - return FALSE; +obj_shows_initial_description(sc_gameref_t game, sc_int object) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int onlywhennotmoved; + + /* Get only when moved property. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "OnlyWhenNotMoved"; + onlywhennotmoved = prop_get_integer(bundle, "I<-sis", vt_key); + + /* Combine this with game in mysterious ways. */ + switch (onlywhennotmoved) { + case 0: + return TRUE; + + case 1: + return gs_object_unmoved(game, object); + + case 2: { + sc_int initialposition; + + if (gs_object_unmoved(game, object)) + return TRUE; + + vt_key[2].string = "InitialPosition"; + initialposition = prop_get_integer(bundle, "I<-sis", vt_key) - 3; + return gs_object_position(game, object) == initialposition; + } + } + + /* What you talkin' 'bout, Willis? */ + return FALSE; } @@ -1000,24 +928,21 @@ obj_shows_initial_description (sc_gameref_t game, sc_int object) * Set initial values for object states, and update after a turn. */ void -obj_turn_update (sc_gameref_t game) -{ - sc_int index_; - - /* Update object seen flag to current state. */ - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (!gs_object_seen (game, index_) - && obj_indirectly_in_room (game, index_, gs_playerroom (game))) - gs_set_object_seen (game, index_, TRUE); - } +obj_turn_update(sc_gameref_t game) { + sc_int index_; + + /* Update object seen flag to current state. */ + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (!gs_object_seen(game, index_) + && obj_indirectly_in_room(game, index_, gs_playerroom(game))) + gs_set_object_seen(game, index_, TRUE); + } } void -obj_setup_initial (sc_gameref_t game) -{ - /* Set initial seen states for objects. */ - obj_turn_update (game); +obj_setup_initial(sc_gameref_t game) { + /* Set initial seen states for objects. */ + obj_turn_update(game); } @@ -1027,9 +952,8 @@ obj_setup_initial (sc_gameref_t game) * Set object tracing on/off. */ void -obj_debug_trace (sc_bool flag) -{ - obj_trace = flag; +obj_debug_trace(sc_bool flag) { + obj_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scparser.cpp b/engines/glk/adrift/scparser.cpp index 6f7642c3a7..9372b5e39e 100644 --- a/engines/glk/adrift/scparser.cpp +++ b/engines/glk/adrift/scparser.cpp @@ -48,37 +48,35 @@ static const sc_char *const WHITESPACE = "\t\n\v\f\r "; static sc_bool uip_trace = FALSE; /* Enumeration of tokens. TOK_NONE represents a non-occurring token. */ -typedef enum -{ - TOK_NONE = 0, - TOK_CHOICE, TOK_CHOICE_END, TOK_OPTIONAL, TOK_OPTIONAL_END, - TOK_ALTERNATES_SEPARATOR, - TOK_WILDCARD, TOK_WHITESPACE, TOK_WORD, TOK_VARIABLE, - TOK_CHARACTER_REFERENCE, TOK_OBJECT_REFERENCE, TOK_NUMBER_REFERENCE, - TOK_TEXT_REFERENCE, TOK_EOS +typedef enum { + TOK_NONE = 0, + TOK_CHOICE, TOK_CHOICE_END, TOK_OPTIONAL, TOK_OPTIONAL_END, + TOK_ALTERNATES_SEPARATOR, + TOK_WILDCARD, TOK_WHITESPACE, TOK_WORD, TOK_VARIABLE, + TOK_CHARACTER_REFERENCE, TOK_OBJECT_REFERENCE, TOK_NUMBER_REFERENCE, + TOK_TEXT_REFERENCE, TOK_EOS } sc_uip_tok_t; /* * Small table tying token strings to tokens. Anything not whitespace and * not caught by the table is a plain TOK_WORD. */ -typedef struct -{ - const sc_char *const name; - const sc_int length; - const sc_uip_tok_t token; +typedef struct { + const sc_char *const name; + const sc_int length; + const sc_uip_tok_t token; } sc_uip_token_entry_t; static const sc_uip_token_entry_t UIP_TOKENS[] = { - {"[", 1, TOK_CHOICE}, {"]", 1, TOK_CHOICE_END}, - {"{", 1, TOK_OPTIONAL}, {"}", 1, TOK_OPTIONAL_END}, - {"/", 1, TOK_ALTERNATES_SEPARATOR}, - {"*", 1, TOK_WILDCARD}, - {"%character%", 11, TOK_CHARACTER_REFERENCE}, - {"%object%", 8, TOK_OBJECT_REFERENCE}, - {"%number%", 8, TOK_NUMBER_REFERENCE}, - {"%text%", 6, TOK_TEXT_REFERENCE}, - {NULL, 0, TOK_NONE} + {"[", 1, TOK_CHOICE}, {"]", 1, TOK_CHOICE_END}, + {"{", 1, TOK_OPTIONAL}, {"}", 1, TOK_OPTIONAL_END}, + {"/", 1, TOK_ALTERNATES_SEPARATOR}, + {"*", 1, TOK_WILDCARD}, + {"%character%", 11, TOK_CHARACTER_REFERENCE}, + {"%object%", 8, TOK_OBJECT_REFERENCE}, + {"%number%", 8, TOK_NUMBER_REFERENCE}, + {"%text%", 6, TOK_TEXT_REFERENCE}, + {NULL, 0, TOK_NONE} }; @@ -101,49 +99,44 @@ static sc_char *uip_temporary = NULL; * Start and wrap up pattern string tokenization. */ static void -uip_tokenize_start (const sc_char *pattern) -{ - static sc_bool initialized = FALSE; - sc_int required; - - /* On first call only, verify the string lengths in the table. */ - if (!initialized) - { - const sc_uip_token_entry_t *entry; - - /* Compare table lengths with string lengths. */ - for (entry = UIP_TOKENS; entry->name; entry++) - { - if (entry->length != (sc_int) strlen (entry->name)) - { - sc_fatal ("uip_tokenize_start:" - " table string length is wrong for \"%s\"\n", - entry->name); - } - } - - initialized = TRUE; - } - - /* Save pattern, and restart index. */ - uip_pattern = pattern; - uip_index = 0; - - /* Set up temporary; static if long enough, otherwise allocated. */ - required = strlen (pattern) + 1; - uip_temporary = (required > UIP_ALLOCATION_AVOIDANCE_SIZE) - ? (sc_char *)sc_malloc (required) : uip_static_temporary; +uip_tokenize_start(const sc_char *pattern) { + static sc_bool initialized = FALSE; + sc_int required; + + /* On first call only, verify the string lengths in the table. */ + if (!initialized) { + const sc_uip_token_entry_t *entry; + + /* Compare table lengths with string lengths. */ + for (entry = UIP_TOKENS; entry->name; entry++) { + if (entry->length != (sc_int) strlen(entry->name)) { + sc_fatal("uip_tokenize_start:" + " table string length is wrong for \"%s\"\n", + entry->name); + } + } + + initialized = TRUE; + } + + /* Save pattern, and restart index. */ + uip_pattern = pattern; + uip_index = 0; + + /* Set up temporary; static if long enough, otherwise allocated. */ + required = strlen(pattern) + 1; + uip_temporary = (required > UIP_ALLOCATION_AVOIDANCE_SIZE) + ? (sc_char *)sc_malloc(required) : uip_static_temporary; } static void -uip_tokenize_end (void) -{ - /* Deallocate temporary if required, and clear pattern and index. */ - if (uip_temporary != uip_static_temporary) - sc_free (uip_temporary); - uip_temporary = NULL; - uip_pattern = NULL; - uip_index = 0; +uip_tokenize_end(void) { + /* Deallocate temporary if required, and clear pattern and index. */ + if (uip_temporary != uip_static_temporary) + sc_free(uip_temporary); + uip_temporary = NULL; + uip_pattern = NULL; + uip_index = 0; } @@ -153,68 +146,62 @@ uip_tokenize_end (void) * Return the next token from the current pattern. */ static sc_uip_tok_t -uip_next_token (void) -{ - const sc_uip_token_entry_t *entry; - sc_char close; - assert (uip_pattern); - - /* Get next character, return EOS if at pattern end. */ - if (uip_pattern[uip_index] == NUL) - { - uip_token_value = NULL; - return TOK_EOS; - } - - /* If whitespace, skip it, then return a whitespace token. */ - if (sc_isspace (uip_pattern[uip_index])) - { - uip_index++; - while (sc_isspace (uip_pattern[uip_index]) - && uip_pattern[uip_index] != NUL) - uip_index++; - uip_token_value = NULL; - return TOK_WHITESPACE; - } - - /* Search the table for matching strings. */ - for (entry = UIP_TOKENS; entry->name; entry++) - { - if (strncmp (uip_pattern + uip_index, entry->name, entry->length) == 0) - break; - } - if (entry->name) - { - /* Advance over string, and return token. */ - uip_index += entry->length; - uip_token_value = NULL; - return entry->token; - } - - /* - * Search for a non-special variable reference. This is apparently an - * Adrift extension to the standard pattern match, allowing %user_var% to - * be used in patterns. If found, return a variable with the name as the - * token value. We can't interpolate the value into the string either - * here or earlier, so we have to save the variable's name, and retrieve - * it when we come to try the match. - */ - if (sscanf (uip_pattern + uip_index, "%%%[^%]%c", uip_temporary, &close) == 2 - && close == PERCENT) - { - uip_index += strlen (uip_temporary) + 2; - uip_token_value = uip_temporary; - return TOK_VARIABLE; - } - - /* - * Return a word. This is a contiguous run of non-pattern-special, non- - * whitespace, non-percent characters - */ - sscanf (uip_pattern + uip_index, "%[^][/{}*% \f\n\r\t\v]", uip_temporary); - uip_token_value = uip_temporary; - uip_index += strlen (uip_temporary); - return TOK_WORD; +uip_next_token(void) { + const sc_uip_token_entry_t *entry; + sc_char close; + assert(uip_pattern); + + /* Get next character, return EOS if at pattern end. */ + if (uip_pattern[uip_index] == NUL) { + uip_token_value = NULL; + return TOK_EOS; + } + + /* If whitespace, skip it, then return a whitespace token. */ + if (sc_isspace(uip_pattern[uip_index])) { + uip_index++; + while (sc_isspace(uip_pattern[uip_index]) + && uip_pattern[uip_index] != NUL) + uip_index++; + uip_token_value = NULL; + return TOK_WHITESPACE; + } + + /* Search the table for matching strings. */ + for (entry = UIP_TOKENS; entry->name; entry++) { + if (strncmp(uip_pattern + uip_index, entry->name, entry->length) == 0) + break; + } + if (entry->name) { + /* Advance over string, and return token. */ + uip_index += entry->length; + uip_token_value = NULL; + return entry->token; + } + + /* + * Search for a non-special variable reference. This is apparently an + * Adrift extension to the standard pattern match, allowing %user_var% to + * be used in patterns. If found, return a variable with the name as the + * token value. We can't interpolate the value into the string either + * here or earlier, so we have to save the variable's name, and retrieve + * it when we come to try the match. + */ + if (sscanf(uip_pattern + uip_index, "%%%[^%]%c", uip_temporary, &close) == 2 + && close == PERCENT) { + uip_index += strlen(uip_temporary) + 2; + uip_token_value = uip_temporary; + return TOK_VARIABLE; + } + + /* + * Return a word. This is a contiguous run of non-pattern-special, non- + * whitespace, non-percent characters + */ + sscanf(uip_pattern + uip_index, "%[^][/{}*% \f\n\r\t\v]", uip_temporary); + uip_token_value = uip_temporary; + uip_index += strlen(uip_temporary); + return TOK_WORD; } @@ -225,17 +212,15 @@ uip_next_token (void) * here if the current token is not a TOK_WORD or TOK_VARIABLE. */ static const sc_char * -uip_current_token_value (void) -{ - /* If the token value is NULL, the current token isn't a word. */ - if (!uip_token_value) - { - sc_fatal ("uip_current_token_value:" - " attempt to take undefined token value\n"); - } - - /* Return value. */ - return uip_token_value; +uip_current_token_value(void) { + /* If the token value is NULL, the current token isn't a word. */ + if (!uip_token_value) { + sc_fatal("uip_current_token_value:" + " attempt to take undefined token value\n"); + } + + /* Return value. */ + return uip_token_value; } @@ -245,21 +230,19 @@ uip_current_token_value (void) * NODE_UNUSED must be zero to ensure that the statically allocated array that * forms the node pool appears initially as containing only unused nodes. */ -typedef enum -{ - NODE_UNUSED = 0, - NODE_CHOICE, NODE_OPTIONAL, NODE_WILDCARD, NODE_WHITESPACE, - NODE_CHARACTER_REFERENCE, NODE_OBJECT_REFERENCE, NODE_TEXT_REFERENCE, - NODE_NUMBER_REFERENCE, NODE_WORD, NODE_VARIABLE, NODE_LIST, NODE_EOS +typedef enum { + NODE_UNUSED = 0, + NODE_CHOICE, NODE_OPTIONAL, NODE_WILDCARD, NODE_WHITESPACE, + NODE_CHARACTER_REFERENCE, NODE_OBJECT_REFERENCE, NODE_TEXT_REFERENCE, + NODE_NUMBER_REFERENCE, NODE_WORD, NODE_VARIABLE, NODE_LIST, NODE_EOS } sc_pttype_t; -typedef struct sc_ptnode_s -{ - struct sc_ptnode_s *left_child; - struct sc_ptnode_s *right_sibling; - - sc_pttype_t type; - sc_char *word; - sc_bool is_allocated; +typedef struct sc_ptnode_s { + struct sc_ptnode_s *left_child; + struct sc_ptnode_s *right_sibling; + + sc_pttype_t type; + sc_char *word; + sc_bool is_allocated; } sc_ptnode_t; typedef sc_ptnode_t *sc_ptnoderef_t; @@ -271,7 +254,7 @@ static jmp_buf uip_parse_error; /* Parse tree for cleanup, and forward declaration of pattern list parser. */ static sc_ptnoderef_t uip_parse_tree = NULL; -static void uip_parse_list (sc_ptnoderef_t list); +static void uip_parse_list(sc_ptnoderef_t list); /* * Pool of statically allocated nodes, for faster allocations. Nodes are @@ -290,10 +273,9 @@ static sc_int uip_node_pool_available = UIP_NODE_POOL_SIZE; * first, then by straight malloc() should the pool empty. */ enum { UIP_WORD_POOL_SIZE = 64, UIP_SHORT_WORD_SIZE = 16 }; -typedef struct -{ - sc_bool is_in_use; - sc_char word[UIP_SHORT_WORD_SIZE]; +typedef struct { + sc_bool is_in_use; + sc_char word[UIP_SHORT_WORD_SIZE]; } sc_ptshortword_t; typedef sc_ptshortword_t *sc_ptshortwordref_t; static sc_ptshortword_t uip_word_pool[UIP_WORD_POOL_SIZE]; @@ -306,17 +288,15 @@ static sc_int uip_word_pool_available = UIP_WORD_POOL_SIZE; * Match a token to the lookahead, then advance lookahead. */ static void -uip_parse_match (sc_uip_tok_t token) -{ - if (uip_parse_lookahead == token) - uip_parse_lookahead = uip_next_token (); - else - { - /* Syntax error. */ - sc_error ("uip_parse_match: syntax error, expected %ld, got %ld\n", - (sc_int) uip_parse_lookahead, (sc_int) token); - longjmp (uip_parse_error, 1); - } +uip_parse_match(sc_uip_tok_t token) { + if (uip_parse_lookahead == token) + uip_parse_lookahead = uip_next_token(); + else { + /* Syntax error. */ + sc_error("uip_parse_match: syntax error, expected %ld, got %ld\n", + (sc_int) uip_parse_lookahead, (sc_int) token); + longjmp(uip_parse_error, 1); + } } @@ -328,51 +308,46 @@ uip_parse_match (sc_uip_tok_t token) * exhausted, backs off to standard allocation. */ static sc_char * -uip_new_word (const sc_char *word) -{ - sc_int required; - - /* - * Unless the pool is empty, search forwards from the next cursor position - * until an unused slot is found, or until the index wraps to the cursor. - */ - required = strlen (word) + 1; - if (uip_word_pool_available > 0 && required <= UIP_SHORT_WORD_SIZE) - { - sc_int index_; - sc_ptshortwordref_t shortword; - - index_ = (uip_word_pool_cursor + 1) % UIP_WORD_POOL_SIZE; - while (index_ != uip_word_pool_cursor) - { - if (!uip_word_pool[index_].is_in_use) - break; - index_ = (index_ + 1) % UIP_WORD_POOL_SIZE; - } - - if (uip_word_pool[index_].is_in_use) - sc_fatal ("uip_new_word: no free slot found in the words pool\n"); - - /* Use the slot and update the pool cursor and free count. */ - shortword = uip_word_pool + index_; - strcpy (shortword->word, word); - shortword->is_in_use = TRUE; - - uip_word_pool_cursor = index_; - uip_word_pool_available--; - - /* Return the address of the copied string. */ - return shortword->word; - } - else - { - sc_char *word_copy; - - /* Fall back to less efficient allocations. */ - word_copy = (sc_char *)sc_malloc (required); - strcpy (word_copy, word); - return word_copy; - } +uip_new_word(const sc_char *word) { + sc_int required; + + /* + * Unless the pool is empty, search forwards from the next cursor position + * until an unused slot is found, or until the index wraps to the cursor. + */ + required = strlen(word) + 1; + if (uip_word_pool_available > 0 && required <= UIP_SHORT_WORD_SIZE) { + sc_int index_; + sc_ptshortwordref_t shortword; + + index_ = (uip_word_pool_cursor + 1) % UIP_WORD_POOL_SIZE; + while (index_ != uip_word_pool_cursor) { + if (!uip_word_pool[index_].is_in_use) + break; + index_ = (index_ + 1) % UIP_WORD_POOL_SIZE; + } + + if (uip_word_pool[index_].is_in_use) + sc_fatal("uip_new_word: no free slot found in the words pool\n"); + + /* Use the slot and update the pool cursor and free count. */ + shortword = uip_word_pool + index_; + strcpy(shortword->word, word); + shortword->is_in_use = TRUE; + + uip_word_pool_cursor = index_; + uip_word_pool_available--; + + /* Return the address of the copied string. */ + return shortword->word; + } else { + sc_char *word_copy; + + /* Fall back to less efficient allocations. */ + word_copy = (sc_char *)sc_malloc(required); + strcpy(word_copy, word); + return word_copy; + } } @@ -383,33 +358,30 @@ uip_new_word (const sc_char *word) * pool entry and return it to the pool. */ static void -uip_free_word (sc_char *word) -{ - const sc_char *first_in_pool, *last_in_pool; - - /* Obtain the range of valid addresses for words from the word pool. */ - first_in_pool = uip_word_pool[0].word; - last_in_pool = uip_word_pool[UIP_WORD_POOL_SIZE - 1].word; - - /* If from the pool, mark the entry as no longer in use, otherwise free. */ - if (word >= first_in_pool && word <= last_in_pool) - { - sc_int index_; - sc_ptshortwordref_t shortword; - - /* - * Calculate the index to the word pool entry from which this short - * word was allocated. - */ - index_ = (word - first_in_pool) / sizeof (uip_word_pool[0]); - shortword = uip_word_pool + index_; - assert (shortword->word == word); - - shortword->is_in_use = FALSE; - uip_word_pool_available++; - } - else - sc_free (word); +uip_free_word(sc_char *word) { + const sc_char *first_in_pool, *last_in_pool; + + /* Obtain the range of valid addresses for words from the word pool. */ + first_in_pool = uip_word_pool[0].word; + last_in_pool = uip_word_pool[UIP_WORD_POOL_SIZE - 1].word; + + /* If from the pool, mark the entry as no longer in use, otherwise free. */ + if (word >= first_in_pool && word <= last_in_pool) { + sc_int index_; + sc_ptshortwordref_t shortword; + + /* + * Calculate the index to the word pool entry from which this short + * word was allocated. + */ + index_ = (word - first_in_pool) / sizeof(uip_word_pool[0]); + shortword = uip_word_pool + index_; + assert(shortword->word == word); + + shortword->is_in_use = FALSE; + uip_word_pool_available++; + } else + sc_free(word); } @@ -421,50 +393,45 @@ uip_free_word (sc_char *word) * exhausted, backs off to standard allocation. */ static sc_ptnoderef_t -uip_new_node (sc_pttype_t type) -{ - sc_ptnoderef_t node; - - /* - * Unless the pool is empty, search forwards from the next cursor position - * until an unused slot is found, or until the index wraps to the cursor. - */ - if (uip_node_pool_available > 0) - { - sc_int index_; - - index_ = (uip_node_pool_cursor + 1) % UIP_NODE_POOL_SIZE; - while (index_ != uip_node_pool_cursor) - { - if (uip_node_pool[index_].type == NODE_UNUSED) - break; - index_ = (index_ + 1) % UIP_NODE_POOL_SIZE; - } - - if (uip_node_pool[index_].type != NODE_UNUSED) - sc_fatal ("uip_new_node: no free slot found in the nodes pool\n"); - - /* Use the slot and update the pool cursor and free count. */ - node = uip_node_pool + index_; - node->is_allocated = FALSE; - - uip_node_pool_cursor = index_; - uip_node_pool_available--; - } - else - { - /* Fall back to less efficient allocations. */ - node = (sc_ptnoderef_t)sc_malloc(sizeof (*node)); - node->is_allocated = TRUE; - } - - /* Fill in the remaining fields and return the new node. */ - node->left_child = NULL; - node->right_sibling = NULL; - node->type = type; - node->word = NULL; - - return node; +uip_new_node(sc_pttype_t type) { + sc_ptnoderef_t node; + + /* + * Unless the pool is empty, search forwards from the next cursor position + * until an unused slot is found, or until the index wraps to the cursor. + */ + if (uip_node_pool_available > 0) { + sc_int index_; + + index_ = (uip_node_pool_cursor + 1) % UIP_NODE_POOL_SIZE; + while (index_ != uip_node_pool_cursor) { + if (uip_node_pool[index_].type == NODE_UNUSED) + break; + index_ = (index_ + 1) % UIP_NODE_POOL_SIZE; + } + + if (uip_node_pool[index_].type != NODE_UNUSED) + sc_fatal("uip_new_node: no free slot found in the nodes pool\n"); + + /* Use the slot and update the pool cursor and free count. */ + node = uip_node_pool + index_; + node->is_allocated = FALSE; + + uip_node_pool_cursor = index_; + uip_node_pool_available--; + } else { + /* Fall back to less efficient allocations. */ + node = (sc_ptnoderef_t)sc_malloc(sizeof(*node)); + node->is_allocated = TRUE; + } + + /* Fill in the remaining fields and return the new node. */ + node->left_child = NULL; + node->right_sibling = NULL; + node->type = type; + node->word = NULL; + + return node; } @@ -475,27 +442,23 @@ uip_new_node (sc_pttype_t type) * free its memory; if not, return it to the pool. */ static void -uip_destroy_node (sc_ptnoderef_t node) -{ - /* Free any word contained at this node. */ - if (node->word) - uip_free_word (node->word); - - /* - * If the node was allocated, poison memory and free it. If it came from - * the node pool, set it to unused and update the availability count for - * the pool. - */ - if (node->is_allocated) - { - memset (node, 0xaa, sizeof (*node)); - sc_free (node); - } - else - { - node->type = NODE_UNUSED; - uip_node_pool_available++; - } +uip_destroy_node(sc_ptnoderef_t node) { + /* Free any word contained at this node. */ + if (node->word) + uip_free_word(node->word); + + /* + * If the node was allocated, poison memory and free it. If it came from + * the node pool, set it to unused and update the availability count for + * the pool. + */ + if (node->is_allocated) { + memset(node, 0xaa, sizeof(*node)); + sc_free(node); + } else { + node->type = NODE_UNUSED; + uip_node_pool_available++; + } } @@ -507,30 +470,27 @@ uip_destroy_node (sc_ptnoderef_t node) * first function is a helper, returning a newly constructed parsed list. */ static sc_ptnoderef_t -uip_parse_new_list (void) -{ - sc_ptnoderef_t list; - - /* Create a new list node, parse into it, and return it. */ - list = uip_new_node (NODE_LIST); - uip_parse_list (list); - return list; +uip_parse_new_list(void) { + sc_ptnoderef_t list; + + /* Create a new list node, parse into it, and return it. */ + list = uip_new_node(NODE_LIST); + uip_parse_list(list); + return list; } static void -uip_parse_alternatives (sc_ptnoderef_t node) -{ - sc_ptnoderef_t child; - - /* Parse initial alternative, then add other listed alternatives. */ - node->left_child = uip_parse_new_list (); - child = node->left_child; - while (uip_parse_lookahead == TOK_ALTERNATES_SEPARATOR) - { - uip_parse_match (TOK_ALTERNATES_SEPARATOR); - child->right_sibling = uip_parse_new_list (); - child = child->right_sibling; - } +uip_parse_alternatives(sc_ptnoderef_t node) { + sc_ptnoderef_t child; + + /* Parse initial alternative, then add other listed alternatives. */ + node->left_child = uip_parse_new_list(); + child = node->left_child; + while (uip_parse_lookahead == TOK_ALTERNATES_SEPARATOR) { + uip_parse_match(TOK_ALTERNATES_SEPARATOR); + child->right_sibling = uip_parse_new_list(); + child = child->right_sibling; + } } @@ -540,107 +500,102 @@ uip_parse_alternatives (sc_ptnoderef_t node) * Parse a single pattern element. */ static sc_ptnoderef_t -uip_parse_element (void) -{ - sc_ptnoderef_t node = NULL; - sc_uip_tok_t token; - - /* Handle pattern element based on lookahead token. */ - switch (uip_parse_lookahead) - { - case TOK_WHITESPACE: - uip_parse_match (TOK_WHITESPACE); - node = uip_new_node (NODE_WHITESPACE); - break; - - case TOK_CHOICE: - /* Parse a [...[/.../...]] choice. */ - uip_parse_match (TOK_CHOICE); - node = uip_new_node (NODE_CHOICE); - uip_parse_alternatives (node); - uip_parse_match (TOK_CHOICE_END); - break; - - case TOK_OPTIONAL: - /* Parse a {...[/.../...]} optional element. */ - uip_parse_match (TOK_OPTIONAL); - node = uip_new_node (NODE_OPTIONAL); - uip_parse_alternatives (node); - uip_parse_match (TOK_OPTIONAL_END); - break; - - case TOK_WILDCARD: - case TOK_CHARACTER_REFERENCE: - case TOK_OBJECT_REFERENCE: - case TOK_NUMBER_REFERENCE: - case TOK_TEXT_REFERENCE: - /* Parse %mumble% references and * wildcards. */ - token = uip_parse_lookahead; - uip_parse_match (token); - switch (token) - { - case TOK_WILDCARD: - node = uip_new_node (NODE_WILDCARD); - break; - case TOK_CHARACTER_REFERENCE: - node = uip_new_node (NODE_CHARACTER_REFERENCE); - break; - case TOK_OBJECT_REFERENCE: - node = uip_new_node (NODE_OBJECT_REFERENCE); - break; - case TOK_NUMBER_REFERENCE: - node = uip_new_node (NODE_NUMBER_REFERENCE); - break; - case TOK_TEXT_REFERENCE: - node = uip_new_node (NODE_TEXT_REFERENCE); - break; - default: - sc_fatal ("uip_parse_element: invalid token, %ld\n", (sc_int) token); - } - break; - - case TOK_WORD: - { - const sc_char *token_value; - sc_char *word; - - /* Take a copy of the token's word value. */ - token_value = uip_current_token_value (); - word = uip_new_word (token_value); - - /* Store details in a word node. */ - uip_parse_match (TOK_WORD); - node = uip_new_node (NODE_WORD); - node->word = word; - break; - } - - case TOK_VARIABLE: - { - const sc_char *token_value; - sc_char *name; - - /* Take a copy of the token's variable name value. */ - token_value = uip_current_token_value (); - name = uip_new_word (token_value); - - /* Store details in a variable node, overloading word. */ - uip_parse_match (TOK_VARIABLE); - node = uip_new_node (NODE_VARIABLE); - node->word = name; - break; - } - - default: - /* Syntax error. */ - sc_error ("uip_parse_element: syntax error," - " unexpected token, %ld\n", (sc_int) uip_parse_lookahead); - longjmp (uip_parse_error, 1); - } - - /* Return the newly created node. */ - assert (node); - return node; +uip_parse_element(void) { + sc_ptnoderef_t node = NULL; + sc_uip_tok_t token; + + /* Handle pattern element based on lookahead token. */ + switch (uip_parse_lookahead) { + case TOK_WHITESPACE: + uip_parse_match(TOK_WHITESPACE); + node = uip_new_node(NODE_WHITESPACE); + break; + + case TOK_CHOICE: + /* Parse a [...[/.../...]] choice. */ + uip_parse_match(TOK_CHOICE); + node = uip_new_node(NODE_CHOICE); + uip_parse_alternatives(node); + uip_parse_match(TOK_CHOICE_END); + break; + + case TOK_OPTIONAL: + /* Parse a {...[/.../...]} optional element. */ + uip_parse_match(TOK_OPTIONAL); + node = uip_new_node(NODE_OPTIONAL); + uip_parse_alternatives(node); + uip_parse_match(TOK_OPTIONAL_END); + break; + + case TOK_WILDCARD: + case TOK_CHARACTER_REFERENCE: + case TOK_OBJECT_REFERENCE: + case TOK_NUMBER_REFERENCE: + case TOK_TEXT_REFERENCE: + /* Parse %mumble% references and * wildcards. */ + token = uip_parse_lookahead; + uip_parse_match(token); + switch (token) { + case TOK_WILDCARD: + node = uip_new_node(NODE_WILDCARD); + break; + case TOK_CHARACTER_REFERENCE: + node = uip_new_node(NODE_CHARACTER_REFERENCE); + break; + case TOK_OBJECT_REFERENCE: + node = uip_new_node(NODE_OBJECT_REFERENCE); + break; + case TOK_NUMBER_REFERENCE: + node = uip_new_node(NODE_NUMBER_REFERENCE); + break; + case TOK_TEXT_REFERENCE: + node = uip_new_node(NODE_TEXT_REFERENCE); + break; + default: + sc_fatal("uip_parse_element: invalid token, %ld\n", (sc_int) token); + } + break; + + case TOK_WORD: { + const sc_char *token_value; + sc_char *word; + + /* Take a copy of the token's word value. */ + token_value = uip_current_token_value(); + word = uip_new_word(token_value); + + /* Store details in a word node. */ + uip_parse_match(TOK_WORD); + node = uip_new_node(NODE_WORD); + node->word = word; + break; + } + + case TOK_VARIABLE: { + const sc_char *token_value; + sc_char *name; + + /* Take a copy of the token's variable name value. */ + token_value = uip_current_token_value(); + name = uip_new_word(token_value); + + /* Store details in a variable node, overloading word. */ + uip_parse_match(TOK_VARIABLE); + node = uip_new_node(NODE_VARIABLE); + node->word = name; + break; + } + + default: + /* Syntax error. */ + sc_error("uip_parse_element: syntax error," + " unexpected token, %ld\n", (sc_int) uip_parse_lookahead); + longjmp(uip_parse_error, 1); + } + + /* Return the newly created node. */ + assert(node); + return node; } @@ -650,63 +605,56 @@ uip_parse_element (void) * Parse a list of pattern elements. */ static void -uip_parse_list (sc_ptnoderef_t list) -{ - sc_ptnoderef_t child, node; - - /* Add elements until a list terminator token is encountered. */ - child = list; - while (TRUE) - { - switch (uip_parse_lookahead) - { - case TOK_CHOICE_END: - case TOK_OPTIONAL_END: - case TOK_ALTERNATES_SEPARATOR: - /* Terminate list building and return. */ - return; - - case TOK_EOS: - /* Place EOS at the appropriate link and return. */ - node = uip_new_node (NODE_EOS); - if (child == list) - child->left_child = node; - else - child->right_sibling = node; - return; - - default: - /* Add the next node at the appropriate link. */ - node = uip_parse_element (); - if (child == list) - { - child->left_child = node; - child = child->left_child; - } - else - { - /* - * Make a special case of a choice or option next to another - * choice or option. In this case, add an (invented) whitespace - * node, to ensure a match with suitable input. - */ - if ((child->type == NODE_OPTIONAL || child->type == NODE_CHOICE) - && (node->type == NODE_OPTIONAL || node->type == NODE_CHOICE)) - { - sc_ptnoderef_t whitespace; - - /* Interpose invented whitespace. */ - whitespace = uip_new_node (NODE_WHITESPACE); - child->right_sibling = whitespace; - child = child->right_sibling; - } - - child->right_sibling = node; - child = child->right_sibling; - } - continue; - } - } +uip_parse_list(sc_ptnoderef_t list) { + sc_ptnoderef_t child, node; + + /* Add elements until a list terminator token is encountered. */ + child = list; + while (TRUE) { + switch (uip_parse_lookahead) { + case TOK_CHOICE_END: + case TOK_OPTIONAL_END: + case TOK_ALTERNATES_SEPARATOR: + /* Terminate list building and return. */ + return; + + case TOK_EOS: + /* Place EOS at the appropriate link and return. */ + node = uip_new_node(NODE_EOS); + if (child == list) + child->left_child = node; + else + child->right_sibling = node; + return; + + default: + /* Add the next node at the appropriate link. */ + node = uip_parse_element(); + if (child == list) { + child->left_child = node; + child = child->left_child; + } else { + /* + * Make a special case of a choice or option next to another + * choice or option. In this case, add an (invented) whitespace + * node, to ensure a match with suitable input. + */ + if ((child->type == NODE_OPTIONAL || child->type == NODE_CHOICE) + && (node->type == NODE_OPTIONAL || node->type == NODE_CHOICE)) { + sc_ptnoderef_t whitespace; + + /* Interpose invented whitespace. */ + whitespace = uip_new_node(NODE_WHITESPACE); + child->right_sibling = whitespace; + child = child->right_sibling; + } + + child->right_sibling = node; + child = child->right_sibling; + } + continue; + } + } } @@ -716,17 +664,15 @@ uip_parse_list (sc_ptnoderef_t list) * Free and destroy a parsed pattern tree. */ static void -uip_destroy_tree (sc_ptnoderef_t node) -{ - if (node) - { - /* Recursively destroy siblings, then left child. */ - uip_destroy_tree (node->right_sibling); - uip_destroy_tree (node->left_child); - - /* Destroy the node itself. */ - uip_destroy_node (node); - } +uip_destroy_tree(sc_ptnoderef_t node) { + if (node) { + /* Recursively destroy siblings, then left child. */ + uip_destroy_tree(node->right_sibling); + uip_destroy_tree(node->left_child); + + /* Destroy the node itself. */ + uip_destroy_node(node); + } } @@ -737,84 +683,78 @@ uip_destroy_tree (sc_ptnoderef_t node) * Print out a pattern match tree. */ static void -uip_debug_dump_node (sc_ptnoderef_t node, sc_int depth) -{ - /* End recursion on null node. */ - if (node) - { - sc_int index_; - - sc_trace (" "); - for (index_ = 0; index_ < depth; index_++) - sc_trace (" "); - - sc_trace ("%p", (void *) node); - switch (node->type) - { - case NODE_CHOICE: - sc_trace (", choice"); - break; - case NODE_OPTIONAL: - sc_trace (", optional"); - break; - case NODE_WILDCARD: - sc_trace (", wildcard"); - break; - case NODE_WHITESPACE: - sc_trace (", whitespace"); - break; - case NODE_CHARACTER_REFERENCE: - sc_trace (", character"); - break; - case NODE_OBJECT_REFERENCE: - sc_trace (", object"); - break; - case NODE_TEXT_REFERENCE: - sc_trace (", text"); - break; - case NODE_NUMBER_REFERENCE: - sc_trace (", number"); - break; - case NODE_WORD: - sc_trace (", word \"%s\"", node->word); - break; - case NODE_VARIABLE: - sc_trace (", variable \"%s\"", node->word); - break; - case NODE_LIST: - sc_trace (", list"); - break; - case NODE_EOS: - sc_trace (", "); - break; - default: - sc_trace (", unknown type %ld", (sc_int) node->type); - break; - } - if (node->left_child) - sc_trace (", left child %p", (void *) node->left_child); - if (node->right_sibling) - sc_trace (", right sibling %p", (void *) node->right_sibling); - sc_trace ("\n"); - - /* Recursively dump left child, then siblings. */ - uip_debug_dump_node (node->left_child, depth + 1); - uip_debug_dump_node (node->right_sibling, depth); - } +uip_debug_dump_node(sc_ptnoderef_t node, sc_int depth) { + /* End recursion on null node. */ + if (node) { + sc_int index_; + + sc_trace(" "); + for (index_ = 0; index_ < depth; index_++) + sc_trace(" "); + + sc_trace("%p", (void *) node); + switch (node->type) { + case NODE_CHOICE: + sc_trace(", choice"); + break; + case NODE_OPTIONAL: + sc_trace(", optional"); + break; + case NODE_WILDCARD: + sc_trace(", wildcard"); + break; + case NODE_WHITESPACE: + sc_trace(", whitespace"); + break; + case NODE_CHARACTER_REFERENCE: + sc_trace(", character"); + break; + case NODE_OBJECT_REFERENCE: + sc_trace(", object"); + break; + case NODE_TEXT_REFERENCE: + sc_trace(", text"); + break; + case NODE_NUMBER_REFERENCE: + sc_trace(", number"); + break; + case NODE_WORD: + sc_trace(", word \"%s\"", node->word); + break; + case NODE_VARIABLE: + sc_trace(", variable \"%s\"", node->word); + break; + case NODE_LIST: + sc_trace(", list"); + break; + case NODE_EOS: + sc_trace(", "); + break; + default: + sc_trace(", unknown type %ld", (sc_int) node->type); + break; + } + if (node->left_child) + sc_trace(", left child %p", (void *) node->left_child); + if (node->right_sibling) + sc_trace(", right sibling %p", (void *) node->right_sibling); + sc_trace("\n"); + + /* Recursively dump left child, then siblings. */ + uip_debug_dump_node(node->left_child, depth + 1); + uip_debug_dump_node(node->right_sibling, depth); + } } static void -uip_debug_dump (void) -{ - sc_trace ("UIParser: debug dump follows...\n"); - if (uip_parse_tree) - { - sc_trace ("uip_parse_tree = {\n"); - uip_debug_dump_node (uip_parse_tree, 0); - sc_trace ("}\n"); - } - else - sc_trace ("uip_parse_tree = (nil)\n"); +uip_debug_dump(void) { + sc_trace("UIParser: debug dump follows...\n"); + if (uip_parse_tree) { + sc_trace("uip_parse_tree = {\n"); + uip_debug_dump_node(uip_parse_tree, 0); + sc_trace("}\n"); + } else + sc_trace("uip_parse_tree = (nil)\n"); } @@ -830,23 +770,21 @@ static sc_gameref_t uip_game = NULL; * Set up a string for matching to a pattern tree, and wrap up matching. */ static void -uip_match_start (const sc_char *string, sc_gameref_t game) -{ - /* Save string, and restart index. */ - uip_string = string; - uip_posn = 0; - - /* Save the game we're working on. */ - uip_game = game; +uip_match_start(const sc_char *string, sc_gameref_t game) { + /* Save string, and restart index. */ + uip_string = string; + uip_posn = 0; + + /* Save the game we're working on. */ + uip_game = game; } static void -uip_match_end (void) -{ - /* Clear match target string, and variable set. */ - uip_string = NULL; - uip_posn = 0; - uip_game = NULL; +uip_match_end(void) { + /* Clear match target string, and variable set. */ + uip_string = NULL; + uip_posn = 0; + uip_game = NULL; } @@ -857,15 +795,14 @@ uip_match_end (void) * one. */ static sc_gameref_t -uip_get_game (void) -{ - assert (gs_is_game_valid (uip_game)); - return uip_game; +uip_get_game(void) { + assert(gs_is_game_valid(uip_game)); + return uip_game; } /* Forward declaration of low level node matcher. */ -static sc_bool uip_match_node (sc_ptnoderef_t node); +static sc_bool uip_match_node(sc_ptnoderef_t node); /* * uip_match_eos() @@ -883,298 +820,276 @@ static sc_bool uip_match_node (sc_ptnoderef_t node); * unchanged. */ static sc_bool -uip_match_eos (void) -{ - /* Check that we hit the string's end. */ - return uip_string[uip_posn] == NUL; +uip_match_eos(void) { + /* Check that we hit the string's end. */ + return uip_string[uip_posn] == NUL; } static sc_bool -uip_match_word (sc_ptnoderef_t node) -{ - sc_int length; - const sc_char *word; - - /* Get the word to match. */ - assert (node->word); - word = node->word; - - /* Compare string text with this node's word, ignore case. */ - length = strlen (word); - if (sc_strncasecmp (uip_string + uip_posn, word, length) == 0) - { - /* Word match, advance position and return. */ - uip_posn += length; - return TRUE; - } - - /* No match. */ - return FALSE; +uip_match_word(sc_ptnoderef_t node) { + sc_int length; + const sc_char *word; + + /* Get the word to match. */ + assert(node->word); + word = node->word; + + /* Compare string text with this node's word, ignore case. */ + length = strlen(word); + if (sc_strncasecmp(uip_string + uip_posn, word, length) == 0) { + /* Word match, advance position and return. */ + uip_posn += length; + return TRUE; + } + + /* No match. */ + return FALSE; } static sc_bool -uip_match_variable (sc_ptnoderef_t node) -{ - const sc_gameref_t game = uip_get_game (); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int type; - sc_vartype_t vt_rvalue; - const sc_char *name; - - /* Get the variable name to match, from overloaded word. */ - assert (node->word); - name = node->word; - - /* Get the variable's value. */ - if (var_get (vars, name, &type, &vt_rvalue)) - { - sc_int length; - - /* Compare the value against the current string position. */ - switch (type) - { - case VAR_INTEGER: - { - sc_char value[32]; - - /* Compare numeric against the current string position. */ - sprintf (value, "%ld", vt_rvalue.integer); - length = strlen (value); - if (strncmp (uip_string + uip_posn, value, length) == 0) - { - /* Integer match, advance position and return. */ - uip_posn += length; - return TRUE; - } - break; - } - - case VAR_STRING: - /* Compare string value against the current string position. */ - length = strlen (vt_rvalue.string); - if (sc_strncasecmp (uip_string + uip_posn, - vt_rvalue.string, length) == 0) - { - /* String match, advance position and return. */ - uip_posn += length; - return TRUE; - } - break; - - default: - sc_fatal ("uip_match_variable: invalid variable type, %ld\n", type); - } - } - - /* No match, or no such variable. */ - return FALSE; +uip_match_variable(sc_ptnoderef_t node) { + const sc_gameref_t game = uip_get_game(); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int type; + sc_vartype_t vt_rvalue; + const sc_char *name; + + /* Get the variable name to match, from overloaded word. */ + assert(node->word); + name = node->word; + + /* Get the variable's value. */ + if (var_get(vars, name, &type, &vt_rvalue)) { + sc_int length; + + /* Compare the value against the current string position. */ + switch (type) { + case VAR_INTEGER: { + sc_char value[32]; + + /* Compare numeric against the current string position. */ + sprintf(value, "%ld", vt_rvalue.integer); + length = strlen(value); + if (strncmp(uip_string + uip_posn, value, length) == 0) { + /* Integer match, advance position and return. */ + uip_posn += length; + return TRUE; + } + break; + } + + case VAR_STRING: + /* Compare string value against the current string position. */ + length = strlen(vt_rvalue.string); + if (sc_strncasecmp(uip_string + uip_posn, + vt_rvalue.string, length) == 0) { + /* String match, advance position and return. */ + uip_posn += length; + return TRUE; + } + break; + + default: + sc_fatal("uip_match_variable: invalid variable type, %ld\n", type); + } + } + + /* No match, or no such variable. */ + return FALSE; } static sc_bool -uip_match_whitespace (void) -{ - /* If next character is space, read whitespace and return. */ - if (sc_isspace (uip_string[uip_posn])) - { - /* Space match, advance position and return. */ - while (uip_string[uip_posn] != NUL && sc_isspace (uip_string[uip_posn])) - uip_posn++; - return TRUE; - } - - /* - * No match. However, if we're trying to match space, this is a word - * boundary. So... even though we're not sitting on a space, if the string - * prior character is whitespace, "double-match" the space. - * - * Also, match if we haven't yet matched any text. In effect, this means - * leading spaces on patterns will be ignored. - * - * TODO Is this what we want to happen? It seems harmless, even useful. - */ - if (uip_posn == 0 || sc_isspace (uip_string[uip_posn - 1])) - return TRUE; - - /* - * And that's not all. We also want to match whitespace if we're at the end - * of a string (another word boundary). This will permit patterns that end - * in optional elements to succeed since options and wildcards always match, - * even if to no text. - */ - if (uip_string[uip_posn] == NUL) - return TRUE; - - /* No match. Really. */ - return FALSE; +uip_match_whitespace(void) { + /* If next character is space, read whitespace and return. */ + if (sc_isspace(uip_string[uip_posn])) { + /* Space match, advance position and return. */ + while (uip_string[uip_posn] != NUL && sc_isspace(uip_string[uip_posn])) + uip_posn++; + return TRUE; + } + + /* + * No match. However, if we're trying to match space, this is a word + * boundary. So... even though we're not sitting on a space, if the string + * prior character is whitespace, "double-match" the space. + * + * Also, match if we haven't yet matched any text. In effect, this means + * leading spaces on patterns will be ignored. + * + * TODO Is this what we want to happen? It seems harmless, even useful. + */ + if (uip_posn == 0 || sc_isspace(uip_string[uip_posn - 1])) + return TRUE; + + /* + * And that's not all. We also want to match whitespace if we're at the end + * of a string (another word boundary). This will permit patterns that end + * in optional elements to succeed since options and wildcards always match, + * even if to no text. + */ + if (uip_string[uip_posn] == NUL) + return TRUE; + + /* No match. Really. */ + return FALSE; } static sc_bool -uip_match_list (sc_ptnoderef_t node) -{ - sc_ptnoderef_t child; - - /* - * If this list is empty, fail the match. This special-case handling is - * what catches constructed temporary lists for wildcard-like items that - * don't actually encompass anything. - */ - if (!node->left_child) - return FALSE; - - /* Match everything listed sequentially. */ - for (child = node->left_child; child; child = child->right_sibling) - { - if (!uip_match_node (child)) - { - /* No match. */ - return FALSE; - } - } - - /* Matched. */ - return TRUE; +uip_match_list(sc_ptnoderef_t node) { + sc_ptnoderef_t child; + + /* + * If this list is empty, fail the match. This special-case handling is + * what catches constructed temporary lists for wildcard-like items that + * don't actually encompass anything. + */ + if (!node->left_child) + return FALSE; + + /* Match everything listed sequentially. */ + for (child = node->left_child; child; child = child->right_sibling) { + if (!uip_match_node(child)) { + /* No match. */ + return FALSE; + } + } + + /* Matched. */ + return TRUE; } static sc_bool -uip_match_alternatives (sc_ptnoderef_t node) -{ - sc_ptnoderef_t child; - sc_int start_posn, extent; - sc_bool matched; - - /* Note the start position for rewind between tries. */ - start_posn = uip_posn; - - /* - * Try a match on each of the children, looking to see which one moves the - * position on the furthest. Match on this one. This is a "maximal munch". - */ - extent = uip_posn; - matched = FALSE; - for (child = node->left_child; child; child = child->right_sibling) - { - uip_posn = start_posn; - if (uip_match_node (child)) - { - /* Matched. */ - matched = TRUE; - if (uip_posn > extent) - extent = uip_posn; - } - } - - /* If matched, set position to extent; if not, back to start. */ - uip_posn = matched ? extent : start_posn; - - /* Return match status. */ - return matched; +uip_match_alternatives(sc_ptnoderef_t node) { + sc_ptnoderef_t child; + sc_int start_posn, extent; + sc_bool matched; + + /* Note the start position for rewind between tries. */ + start_posn = uip_posn; + + /* + * Try a match on each of the children, looking to see which one moves the + * position on the furthest. Match on this one. This is a "maximal munch". + */ + extent = uip_posn; + matched = FALSE; + for (child = node->left_child; child; child = child->right_sibling) { + uip_posn = start_posn; + if (uip_match_node(child)) { + /* Matched. */ + matched = TRUE; + if (uip_posn > extent) + extent = uip_posn; + } + } + + /* If matched, set position to extent; if not, back to start. */ + uip_posn = matched ? extent : start_posn; + + /* Return match status. */ + return matched; } static sc_bool -uip_match_choice (sc_ptnoderef_t node) -{ - /* - * Return the result of matching alternatives. The choice will therefore - * fail if none of the alternatives match. - */ - return uip_match_alternatives (node); +uip_match_choice(sc_ptnoderef_t node) { + /* + * Return the result of matching alternatives. The choice will therefore + * fail if none of the alternatives match. + */ + return uip_match_alternatives(node); } static sc_bool -uip_match_optional (sc_ptnoderef_t node) -{ - sc_int start_posn; - sc_ptnoderef_t list; - sc_bool matched; - - /* Note the start position for rewind on empty match. */ - start_posn = uip_posn; - - /* - * Look ahead to see if we can match to nothing, and still have the main - * pattern match. If we can, we'll go with this. It's a "minimal munch"-ish - * strategy, but seems to be what Adrift does in this situation. - */ - list = uip_new_node (NODE_LIST); - list->left_child = node->right_sibling; - - /* Match on the temporary list. */ - matched = uip_match_node (list); - - /* Free the temporary list node. */ - uip_destroy_node (list); - - /* - * If the temporary matched and consumed text, rewind position to match - * nothing. If it didn't, match alternatives to consume anything that may - * match our options. - */ - if (matched && uip_posn > start_posn) - uip_posn = start_posn; - else - uip_match_alternatives (node); - - /* Return TRUE no matter what. */ - return TRUE; +uip_match_optional(sc_ptnoderef_t node) { + sc_int start_posn; + sc_ptnoderef_t list; + sc_bool matched; + + /* Note the start position for rewind on empty match. */ + start_posn = uip_posn; + + /* + * Look ahead to see if we can match to nothing, and still have the main + * pattern match. If we can, we'll go with this. It's a "minimal munch"-ish + * strategy, but seems to be what Adrift does in this situation. + */ + list = uip_new_node(NODE_LIST); + list->left_child = node->right_sibling; + + /* Match on the temporary list. */ + matched = uip_match_node(list); + + /* Free the temporary list node. */ + uip_destroy_node(list); + + /* + * If the temporary matched and consumed text, rewind position to match + * nothing. If it didn't, match alternatives to consume anything that may + * match our options. + */ + if (matched && uip_posn > start_posn) + uip_posn = start_posn; + else + uip_match_alternatives(node); + + /* Return TRUE no matter what. */ + return TRUE; } static sc_bool -uip_match_wildcard (sc_ptnoderef_t node) -{ - sc_int start_posn, limit, index_; - sc_bool matched; - sc_ptnoderef_t list; - - /* - * At least one game uses patterns like "thing******...". Why? Who knows. - * But if we're in a list of wildcards, and not the first, ignore the call; - * only the final one needs handling. - */ - if (node->right_sibling && node->right_sibling->type == NODE_WILDCARD) - return TRUE; - - /* Note the start position for rewind on no match. */ - start_posn = uip_posn; - - /* - * To make life a little easier, we'll match on the tree to the right of - * this node by constructing a temporary list node, containing stuff to the - * right of the wildcard, and then matching on that. - */ - list = uip_new_node (NODE_LIST); - list->left_child = node->right_sibling; - - /* - * Repeatedly try to match the rest of the tree at successive character - * positions, and stop if we succeed. This is a "minimal munch", which may - * or may not be the right thing to be doing here. - * - * When scanning forward, take care to include the NUL, needed to match - * TOK_EOS. - */ - matched = FALSE; - limit = strlen (uip_string) + 1; - for (index_ = uip_posn + 1; index_ < limit; index_++) - { - uip_posn = index_; - if (uip_match_node (list)) - { - /* Wildcard match at this point. */ - uip_posn = index_; - matched = TRUE; - break; - } - } - - /* Free the temporary list node. */ - uip_destroy_node (list); - - /* If we didn't match in the loop, restore position. */ - if (!matched) - uip_posn = start_posn; - - /* Return TRUE whether we matched text or not. */ - return TRUE; +uip_match_wildcard(sc_ptnoderef_t node) { + sc_int start_posn, limit, index_; + sc_bool matched; + sc_ptnoderef_t list; + + /* + * At least one game uses patterns like "thing******...". Why? Who knows. + * But if we're in a list of wildcards, and not the first, ignore the call; + * only the final one needs handling. + */ + if (node->right_sibling && node->right_sibling->type == NODE_WILDCARD) + return TRUE; + + /* Note the start position for rewind on no match. */ + start_posn = uip_posn; + + /* + * To make life a little easier, we'll match on the tree to the right of + * this node by constructing a temporary list node, containing stuff to the + * right of the wildcard, and then matching on that. + */ + list = uip_new_node(NODE_LIST); + list->left_child = node->right_sibling; + + /* + * Repeatedly try to match the rest of the tree at successive character + * positions, and stop if we succeed. This is a "minimal munch", which may + * or may not be the right thing to be doing here. + * + * When scanning forward, take care to include the NUL, needed to match + * TOK_EOS. + */ + matched = FALSE; + limit = strlen(uip_string) + 1; + for (index_ = uip_posn + 1; index_ < limit; index_++) { + uip_posn = index_; + if (uip_match_node(list)) { + /* Wildcard match at this point. */ + uip_posn = index_; + matched = TRUE; + break; + } + } + + /* Free the temporary list node. */ + uip_destroy_node(list); + + /* If we didn't match in the loop, restore position. */ + if (!matched) + uip_posn = start_posn; + + /* Return TRUE whether we matched text or not. */ + return TRUE; } @@ -1185,100 +1100,92 @@ uip_match_wildcard (sc_ptnoderef_t node) * Attempt to match a number, or a word, from the string. */ static sc_bool -uip_match_number (void) -{ - const sc_gameref_t game = uip_get_game (); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int number; - - /* Attempt to read a number from input. */ - if (sscanf (uip_string + uip_posn, "%ld", &number) == 1) - { - /* Advance position over the number. */ - while (uip_string[uip_posn] == MINUS || uip_string[uip_posn] == PLUS) - uip_posn++; - while (sc_isdigit (uip_string[uip_posn])) - uip_posn++; - - /* Set number reference in variables and return. */ - var_set_ref_number (vars, number); - return TRUE; - } - - /* No match. */ - return FALSE; +uip_match_number(void) { + const sc_gameref_t game = uip_get_game(); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int number; + + /* Attempt to read a number from input. */ + if (sscanf(uip_string + uip_posn, "%ld", &number) == 1) { + /* Advance position over the number. */ + while (uip_string[uip_posn] == MINUS || uip_string[uip_posn] == PLUS) + uip_posn++; + while (sc_isdigit(uip_string[uip_posn])) + uip_posn++; + + /* Set number reference in variables and return. */ + var_set_ref_number(vars, number); + return TRUE; + } + + /* No match. */ + return FALSE; } static sc_bool -uip_match_text (sc_ptnoderef_t node) -{ - const sc_gameref_t game = uip_get_game (); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int start_posn, limit, index_; - sc_bool matched; - sc_ptnoderef_t list; - - /* Note the start position for rewind on no match. */ - start_posn = uip_posn; - - /* - * As with wildcards, create a temporary list of the stuff to the right of - * the reference node, and match on that. - */ - list = uip_new_node (NODE_LIST); - list->left_child = node->right_sibling; - - /* - * Again, as with wildcards, repeatedly try to match the rest of the tree at - * successive character positions, stopping if we succeed. - */ - matched = FALSE; - limit = strlen (uip_string) + 1; - for (index_ = uip_posn + 1; index_ < limit; index_++) - { - uip_posn = index_; - if (uip_match_node (list)) - { - /* Text reference match at this point. */ - uip_posn = index_; - matched = TRUE; - break; - } - } - - /* Free the temporary list node. */ - uip_destroy_node (list); - - /* See if we found a match in the loop. */ - if (matched) - { - sc_char *string; - - /* Found a match; create a string and save the text. */ - string = (sc_char *)sc_malloc (uip_posn - start_posn + 1); - memcpy (string, uip_string + start_posn, uip_posn - start_posn); - string[uip_posn - start_posn] = NUL; - - /* - * Adrift seems to save referenced text as all-lowercase; we need to do - * the same. - */ - for (index_ = 0; string[index_] != NUL; index_++) - string[index_] = sc_tolower (string[index_]); - var_set_ref_text (vars, string); - sc_free (string); - - /* Return TRUE since we matched text. */ - return TRUE; - } - else - { - /* We didn't match in the loop; restore position. */ - uip_posn = start_posn; - - /* Return FALSE on no match. */ - return FALSE; - } +uip_match_text(sc_ptnoderef_t node) { + const sc_gameref_t game = uip_get_game(); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int start_posn, limit, index_; + sc_bool matched; + sc_ptnoderef_t list; + + /* Note the start position for rewind on no match. */ + start_posn = uip_posn; + + /* + * As with wildcards, create a temporary list of the stuff to the right of + * the reference node, and match on that. + */ + list = uip_new_node(NODE_LIST); + list->left_child = node->right_sibling; + + /* + * Again, as with wildcards, repeatedly try to match the rest of the tree at + * successive character positions, stopping if we succeed. + */ + matched = FALSE; + limit = strlen(uip_string) + 1; + for (index_ = uip_posn + 1; index_ < limit; index_++) { + uip_posn = index_; + if (uip_match_node(list)) { + /* Text reference match at this point. */ + uip_posn = index_; + matched = TRUE; + break; + } + } + + /* Free the temporary list node. */ + uip_destroy_node(list); + + /* See if we found a match in the loop. */ + if (matched) { + sc_char *string; + + /* Found a match; create a string and save the text. */ + string = (sc_char *)sc_malloc(uip_posn - start_posn + 1); + memcpy(string, uip_string + start_posn, uip_posn - start_posn); + string[uip_posn - start_posn] = NUL; + + /* + * Adrift seems to save referenced text as all-lowercase; we need to do + * the same. + */ + for (index_ = 0; string[index_] != NUL; index_++) + string[index_] = sc_tolower(string[index_]); + var_set_ref_text(vars, string); + sc_free(string); + + /* Return TRUE since we matched text. */ + return TRUE; + } else { + /* We didn't match in the loop; restore position. */ + uip_posn = start_posn; + + /* Return FALSE on no match. */ + return FALSE; + } } @@ -1289,25 +1196,24 @@ uip_match_text (sc_ptnoderef_t node) * %character% and %object% matchers. Returns the revised string position. */ static sc_int -uip_skip_article (const sc_char *string, sc_int start) -{ - sc_int posn; - - /* Skip over articles. */ - posn = start; - if (sc_compare_word (string + posn, "a", 1)) - posn += 1; - else if (sc_compare_word (string + posn, "an", 2)) - posn += 2; - else if (sc_compare_word (string + posn, "the", 3)) - posn += 3; - else if (sc_compare_word (string + posn, "some", 4)) - posn += 4; - - /* Skip any whitespace, and return. */ - while (sc_isspace (string[posn]) && string[posn] != NUL) - posn++; - return posn; +uip_skip_article(const sc_char *string, sc_int start) { + sc_int posn; + + /* Skip over articles. */ + posn = start; + if (sc_compare_word(string + posn, "a", 1)) + posn += 1; + else if (sc_compare_word(string + posn, "an", 2)) + posn += 2; + else if (sc_compare_word(string + posn, "the", 3)) + posn += 3; + else if (sc_compare_word(string + posn, "some", 4)) + posn += 4; + + /* Skip any whitespace, and return. */ + while (sc_isspace(string[posn]) && string[posn] != NUL) + posn++; + return posn; } @@ -1320,51 +1226,49 @@ uip_skip_article (const sc_char *string, sc_int start) * the words passed in (the new value of uip_posn on match). */ static sc_int -uip_compare_reference (const sc_char *words) -{ - sc_int wpos, posn; - - /* Skip articles and lead in space on words and string. */ - wpos = uip_skip_article (words, 0); - posn = uip_skip_article (uip_string, uip_posn); - - /* Match characters from words with the string at position. */ - while (TRUE) - { - /* Any character mismatch means no words match. */ - if (sc_tolower (words[wpos]) != sc_tolower (uip_string[posn])) - return 0; - - /* Move to next character in each. */ - wpos++; - posn++; - - /* - * If at space, advance over whitespace in words list. Stop when we - * hit the end of the words list. - */ - while (sc_isspace (words[wpos]) && words[wpos] != NUL) - wpos++; - if (words[wpos] == NUL) - break; - - /* - * About to match another word, so advance over whitespace in the - * current string too. - */ - while (sc_isspace (uip_string[posn]) && uip_string[posn] != NUL) - posn++; - } - - /* - * We reached the end of words. If we're at the end of the match string, or - * at spaces, we've matched. - */ - if (sc_isspace (uip_string[posn]) || uip_string[posn] == NUL) - return posn; - - /* More text after the match, so it's not quite a match. */ - return 0; +uip_compare_reference(const sc_char *words) { + sc_int wpos, posn; + + /* Skip articles and lead in space on words and string. */ + wpos = uip_skip_article(words, 0); + posn = uip_skip_article(uip_string, uip_posn); + + /* Match characters from words with the string at position. */ + while (TRUE) { + /* Any character mismatch means no words match. */ + if (sc_tolower(words[wpos]) != sc_tolower(uip_string[posn])) + return 0; + + /* Move to next character in each. */ + wpos++; + posn++; + + /* + * If at space, advance over whitespace in words list. Stop when we + * hit the end of the words list. + */ + while (sc_isspace(words[wpos]) && words[wpos] != NUL) + wpos++; + if (words[wpos] == NUL) + break; + + /* + * About to match another word, so advance over whitespace in the + * current string too. + */ + while (sc_isspace(uip_string[posn]) && uip_string[posn] != NUL) + posn++; + } + + /* + * We reached the end of words. If we're at the end of the match string, or + * at spaces, we've matched. + */ + if (sc_isspace(uip_string[posn]) || uip_string[posn] == NUL) + return posn; + + /* More text after the match, so it's not quite a match. */ + return 0; } @@ -1376,28 +1280,27 @@ uip_compare_reference (const sc_char *words) * Returns the extent of the match, or zero if no match. */ static sc_int -uip_compare_prefixed_name (const sc_char *prefix, const sc_char *name) -{ - sc_char buffer[UIP_SHORT_WORD_SIZE + UIP_SHORT_WORD_SIZE + 1]; - sc_char *string; - sc_int required, extent; - - /* Create a prefixed string, using the local buffer if possible. */ - required = strlen (prefix) + strlen (name) + 2; - string = required > (sc_int) sizeof (buffer) ? (sc_char *)sc_malloc (required) : buffer; - sprintf (string, "%s %s", prefix, name); - - /* Check against the prefixed name first, free string if required. */ - extent = uip_compare_reference (string); - if (string != buffer) - sc_free (string); - - /* If no match there, retry with just the plain name. */ - if (extent == 0) - extent = uip_compare_reference (name); - - /* Return the count of characters consumed in matching. */ - return extent; +uip_compare_prefixed_name(const sc_char *prefix, const sc_char *name) { + sc_char buffer[UIP_SHORT_WORD_SIZE + UIP_SHORT_WORD_SIZE + 1]; + sc_char *string; + sc_int required, extent; + + /* Create a prefixed string, using the local buffer if possible. */ + required = strlen(prefix) + strlen(name) + 2; + string = required > (sc_int) sizeof(buffer) ? (sc_char *)sc_malloc(required) : buffer; + sprintf(string, "%s %s", prefix, name); + + /* Check against the prefixed name first, free string if required. */ + extent = uip_compare_reference(string); + if (string != buffer) + sc_free(string); + + /* If no match there, retry with just the plain name. */ + if (extent == 0) + extent = uip_compare_reference(name); + + /* Return the count of characters consumed in matching. */ + return extent; } @@ -1409,32 +1312,31 @@ uip_compare_prefixed_name (const sc_char *prefix, const sc_char *name) * "table". */ static sc_bool -uip_match_remainder (sc_ptnoderef_t node, sc_int extent) -{ - sc_ptnoderef_t list; - sc_int start_posn; - sc_bool matched; - - /* Note the start position, then advance to the given extent. */ - start_posn = uip_posn; - uip_posn = extent; - - /* - * Try to match everything after the node passed in, at this position in the - * string. - */ - list = uip_new_node (NODE_LIST); - list->left_child = node->right_sibling; - - /* Match on the temporary list. */ - matched = uip_match_node (list); - - /* Free the temporary list node, and restore position. */ - uip_destroy_node (list); - uip_posn = start_posn; - - /* Return TRUE if the pattern remainder matched. */ - return matched; +uip_match_remainder(sc_ptnoderef_t node, sc_int extent) { + sc_ptnoderef_t list; + sc_int start_posn; + sc_bool matched; + + /* Note the start position, then advance to the given extent. */ + start_posn = uip_posn; + uip_posn = extent; + + /* + * Try to match everything after the node passed in, at this position in the + * string. + */ + list = uip_new_node(NODE_LIST); + list->left_child = node->right_sibling; + + /* Match on the temporary list. */ + matched = uip_match_node(list); + + /* Free the temporary list node, and restore position. */ + uip_destroy_node(list); + uip_posn = start_posn; + + /* Return TRUE if the pattern remainder matched. */ + return matched; } @@ -1446,100 +1348,94 @@ uip_match_remainder (sc_ptnoderef_t node, sc_int extent) * for any that match. The final one to match is also stored in variables. */ static sc_bool -uip_match_character (sc_ptnoderef_t node) -{ - const sc_gameref_t game = uip_get_game (); - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int npc_count, npc, max_extent; - - if (uip_trace) - sc_trace ("UIParser: attempting to match %%character%%\n"); - - /* Clear all current character references. */ - gs_clear_npc_references (game); - - /* Iterate characters, looking for a name or alias match. */ - max_extent = 0; - npc_count = gs_npc_count (game); - for (npc = 0; npc < npc_count; npc++) - { - sc_vartype_t vt_key[4]; - const sc_char *prefix, *name; - sc_int alias_count, alias, extent; - - /* Get the NPC's prefix and name. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - if (uip_trace) - sc_trace ("UIParser: trying %s\n", name); - - /* Compare this name, both prefixed and not. */ - extent = uip_compare_prefixed_name (prefix, name); - if (extent > 0 && uip_match_remainder (node, extent)) - { - if (uip_trace) - sc_trace ("UIParser: matched\n"); - - /* Increase the maximum match extent if required. */ - max_extent = (extent > max_extent) ? extent : max_extent; - - /* Save match in variables and game. */ - var_set_ref_character (vars, npc); - game->npc_references[npc] = TRUE; - } - - /* Now compare against all NPC aliases. */ - vt_key[2].string = "Alias"; - alias_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - for (alias = 0; alias < alias_count; alias++) - { - const sc_char *alias_name; - - /* - * Get the NPC alias. Version 3.9 games introduce empty aliases, - * so check here. - */ - vt_key[3].integer = alias; - alias_name = prop_get_string (bundle, "S<-sisi", vt_key); - if (sc_strempty (alias_name)) - continue; - - if (uip_trace) - sc_trace ("UIParser: trying alias %s\n", alias_name); - - /* Compare this alias name, both prefixed and not. */ - extent = uip_compare_prefixed_name (prefix, alias_name); - if (extent > 0 && uip_match_remainder (node, extent)) - { - if (uip_trace) - sc_trace ("UIParser: matched\n"); - - /* Increase the maximum match extent if required. */ - max_extent = (extent > max_extent) ? extent : max_extent; - - /* Save match in variables and game. */ - var_set_ref_character (vars, npc); - game->npc_references[npc] = TRUE; - } - } - } - - /* On match, advance position and return successfully. */ - if (max_extent > 0) - { - uip_posn = max_extent; - return TRUE; - } - - /* No match. */ - return FALSE; +uip_match_character(sc_ptnoderef_t node) { + const sc_gameref_t game = uip_get_game(); + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int npc_count, npc, max_extent; + + if (uip_trace) + sc_trace("UIParser: attempting to match %%character%%\n"); + + /* Clear all current character references. */ + gs_clear_npc_references(game); + + /* Iterate characters, looking for a name or alias match. */ + max_extent = 0; + npc_count = gs_npc_count(game); + for (npc = 0; npc < npc_count; npc++) { + sc_vartype_t vt_key[4]; + const sc_char *prefix, *name; + sc_int alias_count, alias, extent; + + /* Get the NPC's prefix and name. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + if (uip_trace) + sc_trace("UIParser: trying %s\n", name); + + /* Compare this name, both prefixed and not. */ + extent = uip_compare_prefixed_name(prefix, name); + if (extent > 0 && uip_match_remainder(node, extent)) { + if (uip_trace) + sc_trace("UIParser: matched\n"); + + /* Increase the maximum match extent if required. */ + max_extent = (extent > max_extent) ? extent : max_extent; + + /* Save match in variables and game. */ + var_set_ref_character(vars, npc); + game->npc_references[npc] = TRUE; + } + + /* Now compare against all NPC aliases. */ + vt_key[2].string = "Alias"; + alias_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + for (alias = 0; alias < alias_count; alias++) { + const sc_char *alias_name; + + /* + * Get the NPC alias. Version 3.9 games introduce empty aliases, + * so check here. + */ + vt_key[3].integer = alias; + alias_name = prop_get_string(bundle, "S<-sisi", vt_key); + if (sc_strempty(alias_name)) + continue; + + if (uip_trace) + sc_trace("UIParser: trying alias %s\n", alias_name); + + /* Compare this alias name, both prefixed and not. */ + extent = uip_compare_prefixed_name(prefix, alias_name); + if (extent > 0 && uip_match_remainder(node, extent)) { + if (uip_trace) + sc_trace("UIParser: matched\n"); + + /* Increase the maximum match extent if required. */ + max_extent = (extent > max_extent) ? extent : max_extent; + + /* Save match in variables and game. */ + var_set_ref_character(vars, npc); + game->npc_references[npc] = TRUE; + } + } + } + + /* On match, advance position and return successfully. */ + if (max_extent > 0) { + uip_posn = max_extent; + return TRUE; + } + + /* No match. */ + return FALSE; } @@ -1551,100 +1447,94 @@ uip_match_character (sc_ptnoderef_t node) * for any that match. The final one to match is also stored in variables. */ static sc_bool -uip_match_object (sc_ptnoderef_t node) -{ - const sc_gameref_t game = uip_get_game (); - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int object_count, object, max_extent; - - if (uip_trace) - sc_trace ("UIParser: attempting to match %%object%%\n"); - - /* Clear all current object references. */ - gs_clear_object_references (game); - - /* Iterate objects, looking for a name or alias match. */ - max_extent = 0; - object_count = gs_object_count (game); - for (object = 0; object < object_count; object++) - { - sc_vartype_t vt_key[4]; - const sc_char *prefix, *name; - sc_int alias_count, alias, extent; - - /* Get the object's prefix and name. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - if (uip_trace) - sc_trace ("UIParser: trying %s\n", name); - - /* Compare this name, both prefixed and not. */ - extent = uip_compare_prefixed_name (prefix, name); - if (extent > 0 && uip_match_remainder (node, extent)) - { - if (uip_trace) - sc_trace ("UIParser: matched\n"); - - /* Increase the maximum match extent if required. */ - max_extent = (extent > max_extent) ? extent : max_extent; - - /* Save match in variables and game. */ - var_set_ref_object (vars, object); - game->object_references[object] = TRUE; - } - - /* Now compare against all object aliases. */ - vt_key[2].string = "Alias"; - alias_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - for (alias = 0; alias < alias_count; alias++) - { - const sc_char *alias_name; - - /* - * Get the object alias. Version 3.9 games introduce empty aliases, - * so check here. - */ - vt_key[3].integer = alias; - alias_name = prop_get_string (bundle, "S<-sisi", vt_key); - if (sc_strempty (alias_name)) - continue; - - if (uip_trace) - sc_trace ("UIParser: trying alias %s\n", alias_name); - - /* Compare this alias name, both prefixed and not. */ - extent = uip_compare_prefixed_name (prefix, alias_name); - if (extent > 0 && uip_match_remainder (node, extent)) - { - if (uip_trace) - sc_trace ("UIParser: matched\n"); - - /* Increase the maximum match extent if required. */ - max_extent = (extent > max_extent) ? extent : max_extent; - - /* Save match in variables and game. */ - var_set_ref_object (vars, object); - game->object_references[object] = TRUE; - } - } - } - - /* On match, advance position and return successfully. */ - if (max_extent > 0) - { - uip_posn = max_extent; - return TRUE; - } - - /* No match. */ - return FALSE; +uip_match_object(sc_ptnoderef_t node) { + const sc_gameref_t game = uip_get_game(); + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int object_count, object, max_extent; + + if (uip_trace) + sc_trace("UIParser: attempting to match %%object%%\n"); + + /* Clear all current object references. */ + gs_clear_object_references(game); + + /* Iterate objects, looking for a name or alias match. */ + max_extent = 0; + object_count = gs_object_count(game); + for (object = 0; object < object_count; object++) { + sc_vartype_t vt_key[4]; + const sc_char *prefix, *name; + sc_int alias_count, alias, extent; + + /* Get the object's prefix and name. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + if (uip_trace) + sc_trace("UIParser: trying %s\n", name); + + /* Compare this name, both prefixed and not. */ + extent = uip_compare_prefixed_name(prefix, name); + if (extent > 0 && uip_match_remainder(node, extent)) { + if (uip_trace) + sc_trace("UIParser: matched\n"); + + /* Increase the maximum match extent if required. */ + max_extent = (extent > max_extent) ? extent : max_extent; + + /* Save match in variables and game. */ + var_set_ref_object(vars, object); + game->object_references[object] = TRUE; + } + + /* Now compare against all object aliases. */ + vt_key[2].string = "Alias"; + alias_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + for (alias = 0; alias < alias_count; alias++) { + const sc_char *alias_name; + + /* + * Get the object alias. Version 3.9 games introduce empty aliases, + * so check here. + */ + vt_key[3].integer = alias; + alias_name = prop_get_string(bundle, "S<-sisi", vt_key); + if (sc_strempty(alias_name)) + continue; + + if (uip_trace) + sc_trace("UIParser: trying alias %s\n", alias_name); + + /* Compare this alias name, both prefixed and not. */ + extent = uip_compare_prefixed_name(prefix, alias_name); + if (extent > 0 && uip_match_remainder(node, extent)) { + if (uip_trace) + sc_trace("UIParser: matched\n"); + + /* Increase the maximum match extent if required. */ + max_extent = (extent > max_extent) ? extent : max_extent; + + /* Save match in variables and game. */ + var_set_ref_object(vars, object); + game->object_references[object] = TRUE; + } + } + } + + /* On match, advance position and return successfully. */ + if (max_extent > 0) { + uip_posn = max_extent; + return TRUE; + } + + /* No match. */ + return FALSE; } @@ -1656,54 +1546,52 @@ uip_match_object (sc_ptnoderef_t node) * position unchanged. */ static sc_bool -uip_match_node (sc_ptnoderef_t node) -{ - sc_bool match = FALSE; - - /* Match depending on node type. */ - switch (node->type) - { - case NODE_EOS: - match = uip_match_eos (); - break; - case NODE_WORD: - match = uip_match_word (node); - break; - case NODE_VARIABLE: - match = uip_match_variable (node); - break; - case NODE_WHITESPACE: - match = uip_match_whitespace (); - break; - case NODE_LIST: - match = uip_match_list (node); - break; - case NODE_CHOICE: - match = uip_match_choice (node); - break; - case NODE_OPTIONAL: - match = uip_match_optional (node); - break; - case NODE_WILDCARD: - match = uip_match_wildcard (node); - break; - case NODE_CHARACTER_REFERENCE: - match = uip_match_character (node); - break; - case NODE_OBJECT_REFERENCE: - match = uip_match_object (node); - break; - case NODE_NUMBER_REFERENCE: - match = uip_match_number (); - break; - case NODE_TEXT_REFERENCE: - match = uip_match_text (node); - break; - default: - sc_fatal ("uip_match_node: invalid type, %ld\n", (sc_int) node->type); - } - - return match; +uip_match_node(sc_ptnoderef_t node) { + sc_bool match = FALSE; + + /* Match depending on node type. */ + switch (node->type) { + case NODE_EOS: + match = uip_match_eos(); + break; + case NODE_WORD: + match = uip_match_word(node); + break; + case NODE_VARIABLE: + match = uip_match_variable(node); + break; + case NODE_WHITESPACE: + match = uip_match_whitespace(); + break; + case NODE_LIST: + match = uip_match_list(node); + break; + case NODE_CHOICE: + match = uip_match_choice(node); + break; + case NODE_OPTIONAL: + match = uip_match_optional(node); + break; + case NODE_WILDCARD: + match = uip_match_wildcard(node); + break; + case NODE_CHARACTER_REFERENCE: + match = uip_match_character(node); + break; + case NODE_OBJECT_REFERENCE: + match = uip_match_object(node); + break; + case NODE_NUMBER_REFERENCE: + match = uip_match_number(); + break; + case NODE_TEXT_REFERENCE: + match = uip_match_text(node); + break; + default: + sc_fatal("uip_match_node: invalid type, %ld\n", (sc_int) node->type); + } + + return match; } @@ -1718,33 +1606,31 @@ uip_match_node (sc_ptnoderef_t node) * buffer passed in), or call uip_free_cleansed_string. */ static sc_char * -uip_cleanse_string (const sc_char *original, sc_char *buffer, sc_int length) -{ - sc_int required; - sc_char *string; - - /* - * Use the supplied buffer if it is long enough, otherwise allocate, and - * copy the string. - */ - required = strlen (original) + 1; - string = (required < length) ? buffer : (sc_char *)sc_malloc (required); - strcpy (string, original); - - /* Trim, and return the string. */ - sc_trim_string (string); - return string; +uip_cleanse_string(const sc_char *original, sc_char *buffer, sc_int length) { + sc_int required; + sc_char *string; + + /* + * Use the supplied buffer if it is long enough, otherwise allocate, and + * copy the string. + */ + required = strlen(original) + 1; + string = (required < length) ? buffer : (sc_char *)sc_malloc(required); + strcpy(string, original); + + /* Trim, and return the string. */ + sc_trim_string(string); + return string; } static sc_char * -uip_free_cleansed_string (sc_char *string, const sc_char *buffer) -{ - /* Free if the string was allocated by the function above. */ - if (string != buffer) - sc_free (string); - - /* Always returns NULL, for the syntactic convenience of the caller. */ - return NULL; +uip_free_cleansed_string(sc_char *string, const sc_char *buffer) { + /* Free if the string was allocated by the function above. */ + if (string != buffer) + sc_free(string); + + /* Always returns NULL, for the syntactic convenience of the caller. */ + return NULL; } @@ -1754,9 +1640,8 @@ uip_free_cleansed_string (sc_char *string, const sc_char *buffer) * Set pattern match tracing on/off. */ void -uip_debug_trace (sc_bool flag) -{ - uip_trace = flag; +uip_debug_trace(sc_bool flag) { + uip_trace = flag; } @@ -1768,60 +1653,56 @@ uip_debug_trace (sc_bool flag) * need to copy each of the pattern and match strings passed in. */ sc_bool -uip_match (const sc_char *pattern, const sc_char *string, sc_gameref_t game) -{ - static sc_char *cleansed; /* For setjmp safety. */ - sc_char buffer[UIP_ALLOCATION_AVOIDANCE_SIZE]; - sc_bool match; - assert (pattern && string && game); - - /* Start tokenizer. */ - cleansed = uip_cleanse_string (pattern, buffer, sizeof (buffer)); - if (uip_trace) - sc_trace ("UIParser: pattern \"%s\"\n", cleansed); - uip_tokenize_start (cleansed); - - /* Try parsing the pattern, and catch errors. */ - if (setjmp (uip_parse_error) == 0) - { - /* Parse the pattern into a match tree. */ - uip_parse_lookahead = uip_next_token (); - uip_parse_tree = uip_new_node (NODE_LIST); - uip_parse_list (uip_parse_tree); - uip_tokenize_end (); - cleansed = uip_free_cleansed_string (cleansed, buffer); - } - else - { - /* Parse error -- clean up and fail. */ - uip_tokenize_end (); - uip_destroy_tree (uip_parse_tree); - uip_parse_tree = NULL; - cleansed = uip_free_cleansed_string (cleansed, buffer); - return FALSE; - } - - /* Dump out the pattern tree if requested. */ - if (if_get_trace_flag (SC_DUMP_PARSER_TREES)) - uip_debug_dump (); - - /* Match the string to the pattern tree. */ - cleansed = uip_cleanse_string (string, buffer, sizeof (buffer)); - if (uip_trace) - sc_trace ("UIParser: string \"%s\"\n", cleansed); - uip_match_start (cleansed, game); - match = uip_match_node (uip_parse_tree); - - /* Clean up matching and free the parsed pattern tree. */ - uip_match_end (); - cleansed = uip_free_cleansed_string (cleansed, buffer); - uip_destroy_tree (uip_parse_tree); - uip_parse_tree = NULL; - - /* Return result of matching. */ - if (uip_trace) - sc_trace ("UIParser: %s\n", match ? "MATCHED!" : "No match"); - return match; +uip_match(const sc_char *pattern, const sc_char *string, sc_gameref_t game) { + static sc_char *cleansed; /* For setjmp safety. */ + sc_char buffer[UIP_ALLOCATION_AVOIDANCE_SIZE]; + sc_bool match; + assert(pattern && string && game); + + /* Start tokenizer. */ + cleansed = uip_cleanse_string(pattern, buffer, sizeof(buffer)); + if (uip_trace) + sc_trace("UIParser: pattern \"%s\"\n", cleansed); + uip_tokenize_start(cleansed); + + /* Try parsing the pattern, and catch errors. */ + if (setjmp(uip_parse_error) == 0) { + /* Parse the pattern into a match tree. */ + uip_parse_lookahead = uip_next_token(); + uip_parse_tree = uip_new_node(NODE_LIST); + uip_parse_list(uip_parse_tree); + uip_tokenize_end(); + cleansed = uip_free_cleansed_string(cleansed, buffer); + } else { + /* Parse error -- clean up and fail. */ + uip_tokenize_end(); + uip_destroy_tree(uip_parse_tree); + uip_parse_tree = NULL; + cleansed = uip_free_cleansed_string(cleansed, buffer); + return FALSE; + } + + /* Dump out the pattern tree if requested. */ + if (if_get_trace_flag(SC_DUMP_PARSER_TREES)) + uip_debug_dump(); + + /* Match the string to the pattern tree. */ + cleansed = uip_cleanse_string(string, buffer, sizeof(buffer)); + if (uip_trace) + sc_trace("UIParser: string \"%s\"\n", cleansed); + uip_match_start(cleansed, game); + match = uip_match_node(uip_parse_tree); + + /* Clean up matching and free the parsed pattern tree. */ + uip_match_end(); + cleansed = uip_free_cleansed_string(cleansed, buffer); + uip_destroy_tree(uip_parse_tree); + uip_parse_tree = NULL; + + /* Return result of matching. */ + if (uip_trace) + sc_trace("UIParser: %s\n", match ? "MATCHED!" : "No match"); + return match; } @@ -1833,157 +1714,137 @@ uip_match (const sc_char *pattern, const sc_char *string, sc_gameref_t game) * return string is malloc'ed, so the caller needs to remember to free it. */ sc_char * -uip_replace_pronouns (sc_gameref_t game, const sc_char *string) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_int buffer_allocation; - sc_char *buffer; - const sc_char *current; - assert (string); - - if (uip_trace) - sc_trace ("UIParser: pronoun search \"%s\"\n", string); - - /* Begin with a NULL buffer for lazy allocation. */ - buffer_allocation = 0; - buffer = NULL; - - /* Search for pronouns until no more string remains. */ - current = string + strspn (string, WHITESPACE); - while (current[0] != NUL) - { - sc_vartype_t vt_key[3]; - sc_int object, npc, extent; - const sc_char *prefix, *name; - - /* Initially, no object or NPC, no names, and a zero extent. */ - object = npc = -1; - prefix = name = NULL; - extent = 0; - - /* - * Search for pronouns where we have an assigned object or NPC. We - * can't be sure of getting plurality right, and it's not always - * intuitive even in English -- is "a pair of scissors" an "it", or - * a "them"? Because of this, we just treat "it" and "them" equally - * for now. - */ - if (game->it_object != -1 && sc_compare_word (current, "it", 2)) - { - object = game->it_object; - extent = 2; - } - else if (game->it_object != -1 && sc_compare_word (current, "them", 4)) - { - object = game->it_object; - extent = 4; - } - else if (game->him_npc != -1 && sc_compare_word (current, "him", 3)) - { - npc = game->him_npc; - extent = 3; - } - else if (game->her_npc != -1 && sc_compare_word (current, "her", 3)) - { - npc = game->her_npc; - extent = 3; - } - else if (game->it_npc != -1 && sc_compare_word (current, "it", 2)) - { - npc = game->it_npc; - extent = 2; - } - - /* Assign prefix and name to the full object or NPC name, if any. */ - if (object > -1) - { - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - } - else if (npc > -1) - { - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - } - - /* - * If a pronoun was found, prefix and name indicate what to insert, and - * extent shows how much of the buffer to replace with them. - */ - if (prefix && name && extent > 0) - { - sc_char *position; - sc_int prefix_length, name_length, length, final; - - /* - * If not yet allocated, allocate a buffer now, and copy the input - * string into it. Then switch current to the equivalent location - * in the allocated buffer; basic copy-on-write. - */ - if (!buffer) - { - buffer_allocation = strlen (string) + 1; - buffer = (sc_char *)sc_malloc (buffer_allocation); - strcpy (buffer, string); - current = buffer + (current - string); - } - - /* - * If necessary, grow the output buffer for the replacement, - * remembering to adjust current for the new buffer allocated. - * At the same time, note the last character index for the move. - */ - prefix_length = strlen (prefix); - name_length = strlen (name); - length = prefix_length + name_length + 1; - if (length > extent) - { - sc_int offset; - - offset = current - buffer; - buffer_allocation += length - extent; - buffer = (sc_char *)sc_realloc (buffer, buffer_allocation); - current = buffer + offset; - final = length; - } - else - final = extent; - - /* Insert the replacement strings into the buffer. */ - position = buffer + (current - buffer); - memmove (position + length, - position + extent, - buffer_allocation - (current - buffer) - final); - memcpy (position, prefix, prefix_length); - position[prefix_length] = ' '; - memcpy (position + prefix_length + 1, name, name_length); - - /* Adjust current to skip over the replacement. */ - current += length; - - if (uip_trace) - sc_trace ("Parser: pronoun \"%s\"\n", buffer); - } - else - { - /* If no match, advance current over the unmatched word. */ - current += strcspn (current, WHITESPACE); - } - - /* Set current to the next word start. */ - current += strspn (current, WHITESPACE); - } - - /* Return the final string, or NULL if no pronoun replacements. */ - return buffer; +uip_replace_pronouns(sc_gameref_t game, const sc_char *string) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_int buffer_allocation; + sc_char *buffer; + const sc_char *current; + assert(string); + + if (uip_trace) + sc_trace("UIParser: pronoun search \"%s\"\n", string); + + /* Begin with a NULL buffer for lazy allocation. */ + buffer_allocation = 0; + buffer = NULL; + + /* Search for pronouns until no more string remains. */ + current = string + strspn(string, WHITESPACE); + while (current[0] != NUL) { + sc_vartype_t vt_key[3]; + sc_int object, npc, extent; + const sc_char *prefix, *name; + + /* Initially, no object or NPC, no names, and a zero extent. */ + object = npc = -1; + prefix = name = NULL; + extent = 0; + + /* + * Search for pronouns where we have an assigned object or NPC. We + * can't be sure of getting plurality right, and it's not always + * intuitive even in English -- is "a pair of scissors" an "it", or + * a "them"? Because of this, we just treat "it" and "them" equally + * for now. + */ + if (game->it_object != -1 && sc_compare_word(current, "it", 2)) { + object = game->it_object; + extent = 2; + } else if (game->it_object != -1 && sc_compare_word(current, "them", 4)) { + object = game->it_object; + extent = 4; + } else if (game->him_npc != -1 && sc_compare_word(current, "him", 3)) { + npc = game->him_npc; + extent = 3; + } else if (game->her_npc != -1 && sc_compare_word(current, "her", 3)) { + npc = game->her_npc; + extent = 3; + } else if (game->it_npc != -1 && sc_compare_word(current, "it", 2)) { + npc = game->it_npc; + extent = 2; + } + + /* Assign prefix and name to the full object or NPC name, if any. */ + if (object > -1) { + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + } else if (npc > -1) { + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + } + + /* + * If a pronoun was found, prefix and name indicate what to insert, and + * extent shows how much of the buffer to replace with them. + */ + if (prefix && name && extent > 0) { + sc_char *position; + sc_int prefix_length, name_length, length, final; + + /* + * If not yet allocated, allocate a buffer now, and copy the input + * string into it. Then switch current to the equivalent location + * in the allocated buffer; basic copy-on-write. + */ + if (!buffer) { + buffer_allocation = strlen(string) + 1; + buffer = (sc_char *)sc_malloc(buffer_allocation); + strcpy(buffer, string); + current = buffer + (current - string); + } + + /* + * If necessary, grow the output buffer for the replacement, + * remembering to adjust current for the new buffer allocated. + * At the same time, note the last character index for the move. + */ + prefix_length = strlen(prefix); + name_length = strlen(name); + length = prefix_length + name_length + 1; + if (length > extent) { + sc_int offset; + + offset = current - buffer; + buffer_allocation += length - extent; + buffer = (sc_char *)sc_realloc(buffer, buffer_allocation); + current = buffer + offset; + final = length; + } else + final = extent; + + /* Insert the replacement strings into the buffer. */ + position = buffer + (current - buffer); + memmove(position + length, + position + extent, + buffer_allocation - (current - buffer) - final); + memcpy(position, prefix, prefix_length); + position[prefix_length] = ' '; + memcpy(position + prefix_length + 1, name, name_length); + + /* Adjust current to skip over the replacement. */ + current += length; + + if (uip_trace) + sc_trace("Parser: pronoun \"%s\"\n", buffer); + } else { + /* If no match, advance current over the unmatched word. */ + current += strcspn(current, WHITESPACE); + } + + /* Set current to the next word start. */ + current += strspn(current, WHITESPACE); + } + + /* Return the final string, or NULL if no pronoun replacements. */ + return buffer; } @@ -1996,143 +1857,128 @@ uip_replace_pronouns (sc_gameref_t game, const sc_char *string) * earlier ones if there is more than one in the string. */ void -uip_assign_pronouns (sc_gameref_t game, const sc_char *string) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - const sc_char *current; - sc_int saved_ref_object, saved_ref_character; - assert (string); - - if (uip_trace) - sc_trace ("UIParser: pronoun assignment \"%s\"\n", string); - - /* Save var references so we can restore them later. */ - saved_ref_object = var_get_ref_object (vars); - saved_ref_character = var_get_ref_character (vars); - - /* Search for object and NPC names until no more string remains. */ - current = string + strspn (string, WHITESPACE); - while (current[0] != NUL) - { - if (uip_match ("%object% *", current, game)) - { - sc_int count, index_, object; - - /* - * "Disambiguate" by rejecting objects that the player hasn't seen - * or can't see. If the reference is unique, assign to the 'it' - * object pronoun. - */ - count = 0; - object = -1; - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - if (game->object_references[index_] - && gs_object_seen (game, index_) - && obj_indirectly_in_room (game, - index_, gs_playerroom (game))) - { - count++; - object = index_; - } - } - - if (count == 1) - { - game->it_object = object; - game->it_npc = -1; - - if (uip_trace) - sc_trace ("UIParser: object 'it/them' assigned %ld\n", object); - } - } - - if (uip_match ("%character% *", current, game)) - { - sc_int count, index_, npc; - - /* Do the same "disambiguation" as for objects above. */ - count = 0; - npc = -1; - for (index_ = 0; index_ < gs_npc_count (game); index_++) - { - if (game->npc_references[index_] - && gs_npc_seen (game, index_) - && npc_in_room (game, index_, gs_playerroom (game))) - { - count++; - npc = index_; - } - } - - if (count == 1) - { - sc_vartype_t vt_key[3]; - sc_int version, gender; - - /* - * Version 3.8 games lack NPC gender information, so for this - * case set "him"/"her" on each match, and never set "it"; this - * matches the version 3.8 runner. - */ - vt_key[0].string = "Version"; - version = prop_get_integer (bundle, "I<-s", vt_key); - if (version == TAF_VERSION_380) - { - game->him_npc = npc; - game->her_npc = npc; - game->it_npc = -1; - - if (uip_trace) - { - sc_trace ("UIParser: 3.8 pronouns" - " 'him' and 'her' assigned %ld\n", npc); - } - } - else - { - /* Find the NPC gender, so we know the pronoun to assign. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc; - vt_key[2].string = "Gender"; - gender = prop_get_integer (bundle, "I<-sis", vt_key); - - switch (gender) - { - case NPC_MALE: - game->him_npc = npc; - break; - case NPC_FEMALE: - game->her_npc = npc; - break; - case NPC_NEUTER: - game->it_npc = npc; - game->it_object = -1; - break; - default: - sc_error ("uip_assign_pronouns:" - " unknown gender, %ld\n", gender); - } - - if (uip_trace) - sc_trace ("UIParser: NPC 'him/her/it' assigned %ld\n", npc); - } - } - } - - /* - * Advance the string position by a complete word. This saves a lot - * of time -- there's no point looking for an object or NPC name in - * mid-word, and anyway it's not the right thing to do. - */ - current += strcspn (current, WHITESPACE); - current += strspn (current, WHITESPACE); - } - - /* Restore variables references. */ - var_set_ref_object (vars, saved_ref_object); - var_set_ref_character (vars, saved_ref_character); +uip_assign_pronouns(sc_gameref_t game, const sc_char *string) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + const sc_char *current; + sc_int saved_ref_object, saved_ref_character; + assert(string); + + if (uip_trace) + sc_trace("UIParser: pronoun assignment \"%s\"\n", string); + + /* Save var references so we can restore them later. */ + saved_ref_object = var_get_ref_object(vars); + saved_ref_character = var_get_ref_character(vars); + + /* Search for object and NPC names until no more string remains. */ + current = string + strspn(string, WHITESPACE); + while (current[0] != NUL) { + if (uip_match("%object% *", current, game)) { + sc_int count, index_, object; + + /* + * "Disambiguate" by rejecting objects that the player hasn't seen + * or can't see. If the reference is unique, assign to the 'it' + * object pronoun. + */ + count = 0; + object = -1; + for (index_ = 0; index_ < gs_object_count(game); index_++) { + if (game->object_references[index_] + && gs_object_seen(game, index_) + && obj_indirectly_in_room(game, + index_, gs_playerroom(game))) { + count++; + object = index_; + } + } + + if (count == 1) { + game->it_object = object; + game->it_npc = -1; + + if (uip_trace) + sc_trace("UIParser: object 'it/them' assigned %ld\n", object); + } + } + + if (uip_match("%character% *", current, game)) { + sc_int count, index_, npc; + + /* Do the same "disambiguation" as for objects above. */ + count = 0; + npc = -1; + for (index_ = 0; index_ < gs_npc_count(game); index_++) { + if (game->npc_references[index_] + && gs_npc_seen(game, index_) + && npc_in_room(game, index_, gs_playerroom(game))) { + count++; + npc = index_; + } + } + + if (count == 1) { + sc_vartype_t vt_key[3]; + sc_int version, gender; + + /* + * Version 3.8 games lack NPC gender information, so for this + * case set "him"/"her" on each match, and never set "it"; this + * matches the version 3.8 runner. + */ + vt_key[0].string = "Version"; + version = prop_get_integer(bundle, "I<-s", vt_key); + if (version == TAF_VERSION_380) { + game->him_npc = npc; + game->her_npc = npc; + game->it_npc = -1; + + if (uip_trace) { + sc_trace("UIParser: 3.8 pronouns" + " 'him' and 'her' assigned %ld\n", npc); + } + } else { + /* Find the NPC gender, so we know the pronoun to assign. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc; + vt_key[2].string = "Gender"; + gender = prop_get_integer(bundle, "I<-sis", vt_key); + + switch (gender) { + case NPC_MALE: + game->him_npc = npc; + break; + case NPC_FEMALE: + game->her_npc = npc; + break; + case NPC_NEUTER: + game->it_npc = npc; + game->it_object = -1; + break; + default: + sc_error("uip_assign_pronouns:" + " unknown gender, %ld\n", gender); + } + + if (uip_trace) + sc_trace("UIParser: NPC 'him/her/it' assigned %ld\n", npc); + } + } + } + + /* + * Advance the string position by a complete word. This saves a lot + * of time -- there's no point looking for an object or NPC name in + * mid-word, and anyway it's not the right thing to do. + */ + current += strcspn(current, WHITESPACE); + current += strspn(current, WHITESPACE); + } + + /* Restore variables references. */ + var_set_ref_object(vars, saved_ref_object); + var_set_ref_character(vars, saved_ref_character); } } // End of namespace Adrift diff --git a/engines/glk/adrift/scprintf.cpp b/engines/glk/adrift/scprintf.cpp index 91ee94e94f..1ea93e880a 100644 --- a/engines/glk/adrift/scprintf.cpp +++ b/engines/glk/adrift/scprintf.cpp @@ -37,20 +37,20 @@ namespace Adrift { /* Assorted definitions and constants. */ static const sc_uint PRINTFILTER_MAGIC = 0xb4736417; -enum -{ BUFFER_GROW_INCREMENT = 32, - ITERATION_LIMIT = 32 +enum { + BUFFER_GROW_INCREMENT = 32, + ITERATION_LIMIT = 32 }; static const sc_char NUL = '\0'; static const sc_char LESSTHAN = '<'; static const sc_char GREATERTHAN = '>'; static const sc_char PERCENT = '%'; static const sc_char *const ENTITY_LESSTHAN = "<", - *const ENTITY_GREATERTHAN = ">", - *const ENTITY_PERCENT = "+percent+"; -enum -{ ENTITY_LENGTH = 4, - PERCENT_LENGTH = 9 + *const ENTITY_GREATERTHAN = ">", + *const ENTITY_PERCENT = "+percent+"; +enum { + ENTITY_LENGTH = 4, + PERCENT_LENGTH = 9 }; static const sc_char *const ESCAPES = "<>%&+"; static const sc_char *const WHITESPACE = "\t\n\v\f\r "; @@ -65,26 +65,25 @@ static sc_bool pf_trace = FALSE; * come before shorter ones. The
tag is missing because this is * handled separately, as a simple put of '\n'. */ -typedef struct -{ - const sc_char *const name; - const sc_int length; - const sc_int tag; +typedef struct { + const sc_char *const name; + const sc_int length; + const sc_int tag; } sc_html_tags_t; static const sc_html_tags_t HTML_TAGS_TABLE[] = { - {"bgcolour", 8, SC_TAG_BGCOLOR}, {"bgcolor", 7, SC_TAG_BGCOLOR}, - {"waitkey", 7, SC_TAG_WAITKEY}, - {"center", 6, SC_TAG_CENTER}, {"/center", 7, SC_TAG_ENDCENTER}, - {"centre", 6, SC_TAG_CENTER}, {"/centre", 7, SC_TAG_ENDCENTER}, - {"right", 5, SC_TAG_RIGHT}, {"/right", 6, SC_TAG_ENDRIGHT}, - {"font", 4, SC_TAG_FONT}, {"/font", 5, SC_TAG_ENDFONT}, - {"wait", 4, SC_TAG_WAIT}, {"cls", 3, SC_TAG_CLS}, - {"i", 1, SC_TAG_ITALICS}, {"/i", 2, SC_TAG_ENDITALICS}, - {"b", 1, SC_TAG_BOLD}, {"/b", 2, SC_TAG_ENDBOLD}, - {"u", 1, SC_TAG_UNDERLINE}, {"/u", 2, SC_TAG_ENDUNDERLINE}, - {"c", 1, SC_TAG_COLOR}, {"/c", 2, SC_TAG_ENDCOLOR}, - {NULL, 0, SC_TAG_UNKNOWN} + {"bgcolour", 8, SC_TAG_BGCOLOR}, {"bgcolor", 7, SC_TAG_BGCOLOR}, + {"waitkey", 7, SC_TAG_WAITKEY}, + {"center", 6, SC_TAG_CENTER}, {"/center", 7, SC_TAG_ENDCENTER}, + {"centre", 6, SC_TAG_CENTER}, {"/centre", 7, SC_TAG_ENDCENTER}, + {"right", 5, SC_TAG_RIGHT}, {"/right", 6, SC_TAG_ENDRIGHT}, + {"font", 4, SC_TAG_FONT}, {"/font", 5, SC_TAG_ENDFONT}, + {"wait", 4, SC_TAG_WAIT}, {"cls", 3, SC_TAG_CLS}, + {"i", 1, SC_TAG_ITALICS}, {"/i", 2, SC_TAG_ENDITALICS}, + {"b", 1, SC_TAG_BOLD}, {"/b", 2, SC_TAG_ENDBOLD}, + {"u", 1, SC_TAG_UNDERLINE}, {"/u", 2, SC_TAG_ENDUNDERLINE}, + {"c", 1, SC_TAG_COLOR}, {"/c", 2, SC_TAG_ENDCOLOR}, + {NULL, 0, SC_TAG_UNKNOWN} }; /* @@ -92,15 +91,14 @@ static const sc_html_tags_t HTML_TAGS_TABLE[] = { * associated size and length, a note of any conversion to apply to the next * buffered character, and a flag to let the filter ignore incoming text. */ -typedef struct sc_filter_s -{ - sc_uint magic; - sc_int buffer_length; - sc_int buffer_allocation; - sc_char *buffer; - sc_bool new_sentence; - sc_bool is_muted; - sc_bool needs_filtering; +typedef struct sc_filter_s { + sc_uint magic; + sc_int buffer_length; + sc_int buffer_allocation; + sc_char *buffer; + sc_bool new_sentence; + sc_bool is_muted; + sc_bool needs_filtering; } sc_filter_t; @@ -110,9 +108,8 @@ typedef struct sc_filter_s * Return TRUE if pointer is a valid printfilter, FALSE otherwise. */ static sc_bool -pf_is_valid (sc_filterref_t filter) -{ - return filter && filter->magic == PRINTFILTER_MAGIC; +pf_is_valid(sc_filterref_t filter) { + return filter && filter->magic == PRINTFILTER_MAGIC; } @@ -122,42 +119,38 @@ pf_is_valid (sc_filterref_t filter) * Create and return a new printfilter. */ sc_filterref_t -pf_create (void) -{ - static sc_bool initialized = FALSE; - - sc_filterref_t filter; - - /* On first call only, verify the string lengths in the table. */ - if (!initialized) - { - const sc_html_tags_t *entry; - - /* Compare table lengths with string lengths. */ - for (entry = HTML_TAGS_TABLE; entry->name; entry++) - { - if (entry->length != (sc_int) strlen (entry->name)) - { - sc_fatal ("pf_create:" - " table string length is wrong for \"%s\"\n", - entry->name); - } - } - - initialized = TRUE; - } - - /* Create a new printfilter. */ - filter = (sc_filterref_t)sc_malloc(sizeof (*filter)); - filter->magic = PRINTFILTER_MAGIC; - filter->buffer_length = 0; - filter->buffer_allocation = 0; - filter->buffer = NULL; - filter->new_sentence = FALSE; - filter->is_muted = FALSE; - filter->needs_filtering = FALSE; - - return filter; +pf_create(void) { + static sc_bool initialized = FALSE; + + sc_filterref_t filter; + + /* On first call only, verify the string lengths in the table. */ + if (!initialized) { + const sc_html_tags_t *entry; + + /* Compare table lengths with string lengths. */ + for (entry = HTML_TAGS_TABLE; entry->name; entry++) { + if (entry->length != (sc_int) strlen(entry->name)) { + sc_fatal("pf_create:" + " table string length is wrong for \"%s\"\n", + entry->name); + } + } + + initialized = TRUE; + } + + /* Create a new printfilter. */ + filter = (sc_filterref_t)sc_malloc(sizeof(*filter)); + filter->magic = PRINTFILTER_MAGIC; + filter->buffer_length = 0; + filter->buffer_allocation = 0; + filter->buffer = NULL; + filter->new_sentence = FALSE; + filter->is_muted = FALSE; + filter->needs_filtering = FALSE; + + return filter; } @@ -167,14 +160,13 @@ pf_create (void) * Destroy a printfilter and free its allocated memory. */ void -pf_destroy (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); - - /* Free buffer space, and poison and free the printfilter. */ - sc_free (filter->buffer); - memset (filter, 0xaa, sizeof (*filter)); - sc_free (filter); +pf_destroy(sc_filterref_t filter) { + assert(pf_is_valid(filter)); + + /* Free buffer space, and poison and free the printfilter. */ + sc_free(filter->buffer); + memset(filter, 0xaa, sizeof(*filter)); + sc_free(filter); } @@ -192,115 +184,103 @@ pf_destroy (sc_filterref_t filter) * this is probably all that can be done. */ static sc_char * -pf_interpolate_vars (const sc_char *string, sc_var_setref_t vars) -{ - sc_char *buffer, *name; - const sc_char *cursor; - const sc_char *marker; - sc_bool is_interpolated; - - /* - * Begin with NULL buffer and name strings for lazy allocation, and clear - * interpolation detection flag. - */ - buffer = NULL; - name = NULL; - is_interpolated = FALSE; - - /* Run through the string looking for variables. */ - marker = string; - for (cursor = (const sc_char *)strchr (marker, PERCENT); - cursor; cursor = (const sc_char *)strchr(marker, PERCENT)) - { - sc_int type; - sc_vartype_t vt_rvalue; - sc_char close; - - /* - * If not yet allocated, allocate a buffer for the return string and - * copy up to the percent character into it; otherwise append to buffer - * up to percent character. And if not yet done, allocate a name - * buffer guaranteed long enough. - */ - if (!buffer) - { - buffer = (sc_char *)sc_malloc (cursor - marker + 1); - memcpy (buffer, marker, cursor - marker); - buffer[cursor - marker] = NUL; - } - else - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + cursor - marker + 1); - strncat (buffer, marker, cursor - marker); - } - if (!name) - name = (sc_char *)sc_malloc (strlen (string) + 1); - - /* - * Get the variable name, and from that, the value. If we encounter a - * mismatched '%' or unknown variable, skip it. - */ - if (sscanf (cursor, "%%%[^%]%c", name, &close) != 2 - || close != PERCENT - || !var_get (vars, name, &type, &vt_rvalue)) - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + 2); - strncat (buffer, cursor, 1); - marker = cursor + 1; - continue; - } - - /* Get variable value and append to the string. */ - switch (type) - { - case VAR_INTEGER: - { - sc_char value[32]; - - sprintf (value, "%ld", vt_rvalue.integer); - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + strlen (value) + 1); - strcat (buffer, value); - break; - } - - case VAR_STRING: - buffer = (sc_char *)sc_realloc (buffer, - strlen (buffer) + strlen (vt_rvalue.string) + 1); - strcat (buffer, vt_rvalue.string); - break; - - default: - sc_fatal ("pf_interpolate_vars: invalid variable type, %ld\n", type); - } - - /* Advance over the %...% variable name, and note success. */ - marker = cursor + strlen (name) + 2; - is_interpolated = TRUE; - } - - /* - * If we allocated a buffer and interpolated into it, append the remainder - * of the string. If we didn't interpolate successfully (the input contained - * a rogue '%' character), throw out the buffer as it will be the same as - * our input. - */ - if (buffer) - { - if (is_interpolated) - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + strlen (marker) + 1); - strcat (buffer, marker); - } - else - { - sc_free (buffer); - buffer = NULL; - } - } - - /* Clean up, and return either the updated string or NULL. */ - sc_free (name); - return buffer; +pf_interpolate_vars(const sc_char *string, sc_var_setref_t vars) { + sc_char *buffer, *name; + const sc_char *cursor; + const sc_char *marker; + sc_bool is_interpolated; + + /* + * Begin with NULL buffer and name strings for lazy allocation, and clear + * interpolation detection flag. + */ + buffer = NULL; + name = NULL; + is_interpolated = FALSE; + + /* Run through the string looking for variables. */ + marker = string; + for (cursor = (const sc_char *)strchr(marker, PERCENT); + cursor; cursor = (const sc_char *)strchr(marker, PERCENT)) { + sc_int type; + sc_vartype_t vt_rvalue; + sc_char close; + + /* + * If not yet allocated, allocate a buffer for the return string and + * copy up to the percent character into it; otherwise append to buffer + * up to percent character. And if not yet done, allocate a name + * buffer guaranteed long enough. + */ + if (!buffer) { + buffer = (sc_char *)sc_malloc(cursor - marker + 1); + memcpy(buffer, marker, cursor - marker); + buffer[cursor - marker] = NUL; + } else { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + cursor - marker + 1); + strncat(buffer, marker, cursor - marker); + } + if (!name) + name = (sc_char *)sc_malloc(strlen(string) + 1); + + /* + * Get the variable name, and from that, the value. If we encounter a + * mismatched '%' or unknown variable, skip it. + */ + if (sscanf(cursor, "%%%[^%]%c", name, &close) != 2 + || close != PERCENT + || !var_get(vars, name, &type, &vt_rvalue)) { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + 2); + strncat(buffer, cursor, 1); + marker = cursor + 1; + continue; + } + + /* Get variable value and append to the string. */ + switch (type) { + case VAR_INTEGER: { + sc_char value[32]; + + sprintf(value, "%ld", vt_rvalue.integer); + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + strlen(value) + 1); + strcat(buffer, value); + break; + } + + case VAR_STRING: + buffer = (sc_char *)sc_realloc(buffer, + strlen(buffer) + strlen(vt_rvalue.string) + 1); + strcat(buffer, vt_rvalue.string); + break; + + default: + sc_fatal("pf_interpolate_vars: invalid variable type, %ld\n", type); + } + + /* Advance over the %...% variable name, and note success. */ + marker = cursor + strlen(name) + 2; + is_interpolated = TRUE; + } + + /* + * If we allocated a buffer and interpolated into it, append the remainder + * of the string. If we didn't interpolate successfully (the input contained + * a rogue '%' character), throw out the buffer as it will be the same as + * our input. + */ + if (buffer) { + if (is_interpolated) { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + strlen(marker) + 1); + strcat(buffer, marker); + } else { + sc_free(buffer); + buffer = NULL; + } + } + + /* Clean up, and return either the updated string or NULL. */ + sc_free(name); + return buffer; } @@ -312,69 +292,62 @@ pf_interpolate_vars (const sc_char *string, sc_var_setref_t vars) * reallocating if necessary. Return TRUE if the buffer was changed. */ static sc_bool -pf_replace_alr (const sc_char *string, - sc_char **buffer, sc_int alr, sc_prop_setref_t bundle) -{ - sc_vartype_t vt_key[3]; - const sc_char *marker, *cursor, *original, *replacement; - sc_char *buffer_ = *buffer; - - /* Retrieve the ALR original string, set replacement to NULL for now. */ - vt_key[0].string = "ALRs"; - vt_key[1].integer = alr; - vt_key[2].string = "Original"; - original = prop_get_string (bundle, "S<-sis", vt_key); - replacement = NULL; - - /* Ignore pathological empty originals. */ - if (original[0] == NUL) - return FALSE; - - /* Run through the marker string looking for things to replace. */ - marker = string; - for (cursor = strstr (marker, original); - cursor; cursor = strstr (marker, original)) - { - /* Optimize by retrieving the replacement string only on demand. */ - if (!replacement) - { - vt_key[2].string = "Replacement"; - replacement = prop_get_string (bundle, "S<-sis", vt_key); - } - - /* - * If not yet allocated, allocate a buffer for the return string and - * copy; else append to the existing buffer: basic copy-on-write. - */ - if (!buffer_) - { - buffer_ = (sc_char *)sc_malloc (cursor - marker + strlen (replacement) + 1); - memcpy (buffer_, marker, cursor - marker); - buffer_[cursor - marker] = NUL; - strcat (buffer_, replacement); - } - else - { - buffer_ = (sc_char *)sc_realloc (buffer_, strlen (buffer_) + - cursor - marker + strlen (replacement) + 1); - strncat (buffer_, marker, cursor - marker); - strcat (buffer_, replacement); - } - - /* Advance over the original. */ - marker = cursor + strlen (original); - } - - /* If any pending text, append it to the buffer. */ - if (replacement) - { - buffer_ = (sc_char *)sc_realloc (buffer_, strlen (buffer_) + strlen (marker) + 1); - strcat (buffer_, marker); - } - - /* Write back buffer, and if replacement set, the buffer was altered. */ - *buffer = buffer_; - return replacement != NULL; +pf_replace_alr(const sc_char *string, + sc_char **buffer, sc_int alr, sc_prop_setref_t bundle) { + sc_vartype_t vt_key[3]; + const sc_char *marker, *cursor, *original, *replacement; + sc_char *buffer_ = *buffer; + + /* Retrieve the ALR original string, set replacement to NULL for now. */ + vt_key[0].string = "ALRs"; + vt_key[1].integer = alr; + vt_key[2].string = "Original"; + original = prop_get_string(bundle, "S<-sis", vt_key); + replacement = NULL; + + /* Ignore pathological empty originals. */ + if (original[0] == NUL) + return FALSE; + + /* Run through the marker string looking for things to replace. */ + marker = string; + for (cursor = strstr(marker, original); + cursor; cursor = strstr(marker, original)) { + /* Optimize by retrieving the replacement string only on demand. */ + if (!replacement) { + vt_key[2].string = "Replacement"; + replacement = prop_get_string(bundle, "S<-sis", vt_key); + } + + /* + * If not yet allocated, allocate a buffer for the return string and + * copy; else append to the existing buffer: basic copy-on-write. + */ + if (!buffer_) { + buffer_ = (sc_char *)sc_malloc(cursor - marker + strlen(replacement) + 1); + memcpy(buffer_, marker, cursor - marker); + buffer_[cursor - marker] = NUL; + strcat(buffer_, replacement); + } else { + buffer_ = (sc_char *)sc_realloc(buffer_, strlen(buffer_) + + cursor - marker + strlen(replacement) + 1); + strncat(buffer_, marker, cursor - marker); + strcat(buffer_, replacement); + } + + /* Advance over the original. */ + marker = cursor + strlen(original); + } + + /* If any pending text, append it to the buffer. */ + if (replacement) { + buffer_ = (sc_char *)sc_realloc(buffer_, strlen(buffer_) + strlen(marker) + 1); + strcat(buffer_, marker); + } + + /* Write back buffer, and if replacement set, the buffer was altered. */ + *buffer = buffer_; + return replacement != NULL; } @@ -386,82 +359,75 @@ pf_replace_alr (const sc_char *string, * otherwise returns NULL. */ static sc_char * -pf_replace_alrs (const sc_char *string, sc_prop_setref_t bundle, - sc_bool alr_applied[], sc_int alr_count) -{ - sc_int index_; - sc_char *buffer1, *buffer2, **buffer; - const sc_char *marker; - - /* - * Begin with NULL buffers and alternate for lazy allocation. To avoid a - * lot of allocation and copying, we use two buffers to help with repeated - * ALR replacement. - */ - buffer1 = buffer2 = NULL; - buffer = &buffer1; - - /* Run through each ALR that exists. */ - marker = string; - for (index_ = 0; index_ < alr_count; index_++) - { - sc_vartype_t vt_key[3]; - sc_int alr; - - /* - * Ignore ALR indexes that have already been applied. This prevents - * endless loops in ALR replacement. - */ - if (alr_applied[index_]) - continue; - - /* - * Get the actual ALR number for the ALR. This comes from the index - * that we sorted earlier by length of original string. Try replacing - * that ALR in the current marker string. - */ - vt_key[0].string = "ALRs2"; - vt_key[1].integer = index_; - vt_key[2].string = "ALRIndex"; - alr = prop_get_integer (bundle, "I<-sis", vt_key); - - if (pf_replace_alr (marker, buffer, alr, bundle)) - { - /* - * The current buffer in use has been altered. This means that we - * have to switch the marker string to the buffer containing the - * replacement, and switch 'buffer' to the other one for the next - * ALR iteration. - */ - marker = *buffer; - buffer = (buffer == &buffer1) ? &buffer2 : &buffer1; - - /* Discard any content in the buffer switched to above. */ - if (*buffer) - (*buffer)[0] = NUL; - - /* Note this ALR as "used up", and unavailable for future passes. */ - alr_applied[index_] = TRUE; - } - } - - /* - * If marker points to one or other of the buffers, that buffer is the - * return string, and the other is garbage, and should now be freed (or - * was never used, in which case it is NULL). - */ - if (marker == buffer1) - { - sc_free (buffer2); - return buffer1; - } - else if (marker == buffer2) - { - sc_free (buffer1); - return buffer2; - } - else - return NULL; +pf_replace_alrs(const sc_char *string, sc_prop_setref_t bundle, + sc_bool alr_applied[], sc_int alr_count) { + sc_int index_; + sc_char *buffer1, *buffer2, **buffer; + const sc_char *marker; + + /* + * Begin with NULL buffers and alternate for lazy allocation. To avoid a + * lot of allocation and copying, we use two buffers to help with repeated + * ALR replacement. + */ + buffer1 = buffer2 = NULL; + buffer = &buffer1; + + /* Run through each ALR that exists. */ + marker = string; + for (index_ = 0; index_ < alr_count; index_++) { + sc_vartype_t vt_key[3]; + sc_int alr; + + /* + * Ignore ALR indexes that have already been applied. This prevents + * endless loops in ALR replacement. + */ + if (alr_applied[index_]) + continue; + + /* + * Get the actual ALR number for the ALR. This comes from the index + * that we sorted earlier by length of original string. Try replacing + * that ALR in the current marker string. + */ + vt_key[0].string = "ALRs2"; + vt_key[1].integer = index_; + vt_key[2].string = "ALRIndex"; + alr = prop_get_integer(bundle, "I<-sis", vt_key); + + if (pf_replace_alr(marker, buffer, alr, bundle)) { + /* + * The current buffer in use has been altered. This means that we + * have to switch the marker string to the buffer containing the + * replacement, and switch 'buffer' to the other one for the next + * ALR iteration. + */ + marker = *buffer; + buffer = (buffer == &buffer1) ? &buffer2 : &buffer1; + + /* Discard any content in the buffer switched to above. */ + if (*buffer) + (*buffer)[0] = NUL; + + /* Note this ALR as "used up", and unavailable for future passes. */ + alr_applied[index_] = TRUE; + } + } + + /* + * If marker points to one or other of the buffers, that buffer is the + * return string, and the other is garbage, and should now be freed (or + * was never used, in which case it is NULL). + */ + if (marker == buffer1) { + sc_free(buffer2); + return buffer1; + } else if (marker == buffer2) { + sc_free(buffer1); + return buffer2; + } else + return NULL; } @@ -472,56 +438,47 @@ pf_replace_alrs (const sc_char *string, sc_prop_setref_t bundle, * +percent+ with < > %, then send to the OS-specific output functions. */ static void -pf_output_text (const sc_char *string) -{ - sc_int index_, b_index; - sc_char *buffer; - - /* Optimize away the allocation and copy if possible. */ - if (!(strstr (string, ENTITY_LESSTHAN) - || strstr (string, ENTITY_GREATERTHAN) - || strstr (string, ENTITY_PERCENT))) - { - if_print_string (string); - return; - } - - /* - * Copy characters from the string into the buffer, replacing any &..; - * elements by their single-character equivalents. We also replace any - * +percent+ elements by percent characters; apparently an undocumented - * Adrift Runner extension. - */ - buffer = (sc_char *)sc_malloc (strlen (string) + 1); - for (index_ = 0, b_index = 0; - string[index_] != NUL; index_++, b_index++) - { - if (sc_strncasecmp (string + index_, - ENTITY_LESSTHAN, ENTITY_LENGTH) == 0) - { - buffer[b_index] = LESSTHAN; - index_ += ENTITY_LENGTH - 1; - } - else if (sc_strncasecmp (string + index_, - ENTITY_GREATERTHAN, ENTITY_LENGTH) == 0) - { - buffer[b_index] = GREATERTHAN; - index_ += ENTITY_LENGTH - 1; - } - else if (sc_strncasecmp (string + index_, - ENTITY_PERCENT, PERCENT_LENGTH) == 0) - { - buffer[b_index] = PERCENT; - index_ += PERCENT_LENGTH - 1; - } - else - buffer[b_index] = string[index_]; - } - - /* Terminate, print, and free the buffer. */ - buffer[b_index] = NUL; - if_print_string (buffer); - sc_free (buffer); +pf_output_text(const sc_char *string) { + sc_int index_, b_index; + sc_char *buffer; + + /* Optimize away the allocation and copy if possible. */ + if (!(strstr(string, ENTITY_LESSTHAN) + || strstr(string, ENTITY_GREATERTHAN) + || strstr(string, ENTITY_PERCENT))) { + if_print_string(string); + return; + } + + /* + * Copy characters from the string into the buffer, replacing any &..; + * elements by their single-character equivalents. We also replace any + * +percent+ elements by percent characters; apparently an undocumented + * Adrift Runner extension. + */ + buffer = (sc_char *)sc_malloc(strlen(string) + 1); + for (index_ = 0, b_index = 0; + string[index_] != NUL; index_++, b_index++) { + if (sc_strncasecmp(string + index_, + ENTITY_LESSTHAN, ENTITY_LENGTH) == 0) { + buffer[b_index] = LESSTHAN; + index_ += ENTITY_LENGTH - 1; + } else if (sc_strncasecmp(string + index_, + ENTITY_GREATERTHAN, ENTITY_LENGTH) == 0) { + buffer[b_index] = GREATERTHAN; + index_ += ENTITY_LENGTH - 1; + } else if (sc_strncasecmp(string + index_, + ENTITY_PERCENT, PERCENT_LENGTH) == 0) { + buffer[b_index] = PERCENT; + index_ += PERCENT_LENGTH - 1; + } else + buffer[b_index] = string[index_]; + } + + /* Terminate, print, and free the buffer. */ + buffer[b_index] = NUL; + if_print_string(buffer); + sc_free(buffer); } @@ -531,53 +488,48 @@ pf_output_text (const sc_char *string) * Output an HTML-like tag element to the OS-specific tag handling function. */ static void -pf_output_tag (const sc_char *contents) -{ - const sc_html_tags_t *entry; - const sc_char *argument; - - /* For a simple
tag, just print out a newline. */ - if (sc_compare_word (contents, "br", 2)) - { - if_print_character ('\n'); - return; - } - - /* - * Search for the name in the HTML tags table. It should be a full match, - * that is, the character after the matched name must be space or NUL. - * The tag is the exception; here the terminator is '='. - */ - for (entry = HTML_TAGS_TABLE; entry->name; entry++) - { - if (sc_strncasecmp (contents, entry->name, entry->length) == 0) - { - sc_char next; - - next = contents[entry->length]; - if (next == NUL || sc_isspace (next) - || (entry->tag == SC_TAG_BGCOLOR && next == '=')) - break; - } - } - - /* If not matched, output an unknown tag with contents as its argument. */ - if (!entry->name) - { - if_print_tag (SC_TAG_UNKNOWN, contents); - return; - } - - /* - * Find the argument by skipping the tag name and any spaces. Again, for - * , make a special case, passing the complete contents as - * argument (to match for the client. - */ - argument = contents; - argument += (entry->tag != SC_TAG_BGCOLOR) ? entry->length : 0; - while (sc_isspace (argument[0])) - argument++; - if_print_tag (entry->tag, argument); +pf_output_tag(const sc_char *contents) { + const sc_html_tags_t *entry; + const sc_char *argument; + + /* For a simple
tag, just print out a newline. */ + if (sc_compare_word(contents, "br", 2)) { + if_print_character('\n'); + return; + } + + /* + * Search for the name in the HTML tags table. It should be a full match, + * that is, the character after the matched name must be space or NUL. + * The tag is the exception; here the terminator is '='. + */ + for (entry = HTML_TAGS_TABLE; entry->name; entry++) { + if (sc_strncasecmp(contents, entry->name, entry->length) == 0) { + sc_char next; + + next = contents[entry->length]; + if (next == NUL || sc_isspace(next) + || (entry->tag == SC_TAG_BGCOLOR && next == '=')) + break; + } + } + + /* If not matched, output an unknown tag with contents as its argument. */ + if (!entry->name) { + if_print_tag(SC_TAG_UNKNOWN, contents); + return; + } + + /* + * Find the argument by skipping the tag name and any spaces. Again, for + * , make a special case, passing the complete contents as + * argument (to match for the client. + */ + argument = contents; + argument += (entry->tag != SC_TAG_BGCOLOR) ? entry->length : 0; + while (sc_isspace(argument[0])) + argument++; + if_print_tag(entry->tag, argument); } @@ -588,79 +540,73 @@ pf_output_tag (const sc_char *contents) * tags. */ static void -pf_output_untagged (const sc_char *string) -{ +pf_output_untagged(const sc_char *string) { sc_char *temporary, *untagged, *contents; const sc_char *cursor; - const sc_char *marker; - - /* - * Optimize away the allocation and copy if possible. We need to check - * here both for tags and for entities; only if neither occurs is it safe - * to output the string directly. - */ - if (!strchr (string, LESSTHAN) - && !(strstr (string, ENTITY_LESSTHAN) - || strstr (string, ENTITY_GREATERTHAN) - || strstr (string, ENTITY_PERCENT))) - { - if_print_string (string); - return; - } - - /* - * Create a general temporary string, and alias it to both untagged text - * and the tag name, for sharing inside the loop. - */ - temporary = (sc_char *)sc_malloc (strlen (string) + 1); - untagged = contents = temporary; - - /* Run through the string looking for <...> tags. */ - marker = string; - for (cursor = (const sc_char *)strchr (marker, LESSTHAN); - cursor; cursor = (const sc_char *)strchr (marker, LESSTHAN)) - { - sc_char close; - - /* Handle characters up to the tag start; untagged text. */ - memcpy (untagged, marker, cursor - marker); - untagged[cursor - marker] = NUL; - pf_output_text (untagged); - - /* Catch and ignore completely empty tags. */ - if (cursor[1] == GREATERTHAN) - { - marker = cursor + 2; - continue; - } - - /* - * Get the text within the tag, reusing the temporary buffer. If this - * fails, allow the remainder of the line to be delivered as a tag; - * unknown, probably. - */ - if (sscanf (cursor, "<%[^>]%c", contents, &close) != 2 - || close != GREATERTHAN) - { - if (sscanf (cursor, "<%[^>]", contents) != 1) - { - sc_error ("pf_output_untagged: mismatched '%c'\n", LESSTHAN); - if_print_character (LESSTHAN); - marker = cursor + 1; - continue; - } - } - - /* Output tag, and advance marker over the <...> tag. */ - if (!sc_strempty (contents)) - pf_output_tag (contents); - marker = cursor + strlen (contents) + 1; - marker += (marker[0] == GREATERTHAN) ? 1 : 0; - } - - /* Output any remaining string text, and free the temporary buffer. */ - pf_output_text (marker); - sc_free (temporary); + const sc_char *marker; + + /* + * Optimize away the allocation and copy if possible. We need to check + * here both for tags and for entities; only if neither occurs is it safe + * to output the string directly. + */ + if (!strchr(string, LESSTHAN) + && !(strstr(string, ENTITY_LESSTHAN) + || strstr(string, ENTITY_GREATERTHAN) + || strstr(string, ENTITY_PERCENT))) { + if_print_string(string); + return; + } + + /* + * Create a general temporary string, and alias it to both untagged text + * and the tag name, for sharing inside the loop. + */ + temporary = (sc_char *)sc_malloc(strlen(string) + 1); + untagged = contents = temporary; + + /* Run through the string looking for <...> tags. */ + marker = string; + for (cursor = (const sc_char *)strchr(marker, LESSTHAN); + cursor; cursor = (const sc_char *)strchr(marker, LESSTHAN)) { + sc_char close; + + /* Handle characters up to the tag start; untagged text. */ + memcpy(untagged, marker, cursor - marker); + untagged[cursor - marker] = NUL; + pf_output_text(untagged); + + /* Catch and ignore completely empty tags. */ + if (cursor[1] == GREATERTHAN) { + marker = cursor + 2; + continue; + } + + /* + * Get the text within the tag, reusing the temporary buffer. If this + * fails, allow the remainder of the line to be delivered as a tag; + * unknown, probably. + */ + if (sscanf(cursor, "<%[^>]%c", contents, &close) != 2 + || close != GREATERTHAN) { + if (sscanf(cursor, "<%[^>]", contents) != 1) { + sc_error("pf_output_untagged: mismatched '%c'\n", LESSTHAN); + if_print_character(LESSTHAN); + marker = cursor + 1; + continue; + } + } + + /* Output tag, and advance marker over the <...> tag. */ + if (!sc_strempty(contents)) + pf_output_tag(contents); + marker = cursor + strlen(contents) + 1; + marker += (marker[0] == GREATERTHAN) ? 1 : 0; + } + + /* Output any remaining string text, and free the temporary buffer. */ + pf_output_text(marker); + sc_free(temporary); } @@ -691,118 +637,102 @@ pf_output_untagged (const sc_char *string) * */ static sc_char * -pf_filter_internal (const sc_char *string, - sc_var_setref_t vars, sc_prop_setref_t bundle) -{ - sc_int alr_count, iteration; - sc_char *current; - sc_bool *alr_applied; - assert (string && vars); - - if (pf_trace) - sc_trace ("Printfilter: initial \"%s\"\n", string); - - /* If including ALRs, create a common set of ALR application flags. */ - if (bundle) - { - sc_vartype_t vt_key; - - /* Obtain a count of ALRs. */ - vt_key.string = "ALRs"; - alr_count = prop_get_child_count (bundle, "I<-s", &vt_key); - - /* - * Create a new set of ALR application flags. These are used to ensure - * that a given ALR is applied only once on a given pass. If the game - * has no ALRs, don't create a flag set. - */ - if (alr_count > 0) - { - alr_applied = (sc_bool *)sc_malloc (alr_count * sizeof (*alr_applied)); - memset (alr_applied, FALSE, alr_count * sizeof (*alr_applied)); - } - else - alr_applied = NULL; - } - else - { - /* Not including ALRs, so set alr count to 0, and flags to NULL. */ - alr_count = 0; - alr_applied = NULL; - } - - /* Loop for a sort-of arbitrary number of passes; probably enough. */ - current = NULL; - for (iteration = 0; iteration < ITERATION_LIMIT; iteration++) - { - sc_int inner_iteration; - const sc_char *initial; - sc_char *intermediate; - - /* Note the initial string, so we can check for no change. */ - initial = current; - - for (inner_iteration = 0; - inner_iteration < ITERATION_LIMIT; inner_iteration++) - { - /* - * Interpolate variables. If any changes were made, advance current - * to the interpolated version, and free the old current if required. - * Work on the current string, if any, otherwise the input string. - */ - intermediate = pf_interpolate_vars (current ? current : string, vars); - if (intermediate) - { - sc_free (current); - current = intermediate; - if (pf_trace) - { - sc_trace ("Printfilter: interpolated [%ld,%ld] \"%s\"\n", - iteration, inner_iteration, current); - } - } - else - break; - } - - /* If we have ALRs to process, search out and replace all findable. */ - if (alr_count > 0) - { - /* Replace ALRs until no more ALRs can be found. */ - inner_iteration = 0; - while (TRUE) - { - /* - * Replace ALRs, and advance current as for variables above. - * Leave the loop when ALR replacements stop. Again, work on - * the current string if any, otherwise the input string. - */ - intermediate = pf_replace_alrs (current ? current : string, - bundle, alr_applied, alr_count); - if (intermediate) - { - sc_free (current); - current = intermediate; - if (pf_trace) - { - sc_trace ("Printfilter: replaced [%ld,%ld] \"%s\"\n", - iteration, inner_iteration, current); - } - } - else - break; - inner_iteration++; - } - } - - /* If nothing changed this iteration, stop now. */ - if (current == initial) - break; - } - - /* Free any ALR application flags, and return current, NULL if no change. */ - sc_free (alr_applied); - return current; +pf_filter_internal(const sc_char *string, + sc_var_setref_t vars, sc_prop_setref_t bundle) { + sc_int alr_count, iteration; + sc_char *current; + sc_bool *alr_applied; + assert(string && vars); + + if (pf_trace) + sc_trace("Printfilter: initial \"%s\"\n", string); + + /* If including ALRs, create a common set of ALR application flags. */ + if (bundle) { + sc_vartype_t vt_key; + + /* Obtain a count of ALRs. */ + vt_key.string = "ALRs"; + alr_count = prop_get_child_count(bundle, "I<-s", &vt_key); + + /* + * Create a new set of ALR application flags. These are used to ensure + * that a given ALR is applied only once on a given pass. If the game + * has no ALRs, don't create a flag set. + */ + if (alr_count > 0) { + alr_applied = (sc_bool *)sc_malloc(alr_count * sizeof(*alr_applied)); + memset(alr_applied, FALSE, alr_count * sizeof(*alr_applied)); + } else + alr_applied = NULL; + } else { + /* Not including ALRs, so set alr count to 0, and flags to NULL. */ + alr_count = 0; + alr_applied = NULL; + } + + /* Loop for a sort-of arbitrary number of passes; probably enough. */ + current = NULL; + for (iteration = 0; iteration < ITERATION_LIMIT; iteration++) { + sc_int inner_iteration; + const sc_char *initial; + sc_char *intermediate; + + /* Note the initial string, so we can check for no change. */ + initial = current; + + for (inner_iteration = 0; + inner_iteration < ITERATION_LIMIT; inner_iteration++) { + /* + * Interpolate variables. If any changes were made, advance current + * to the interpolated version, and free the old current if required. + * Work on the current string, if any, otherwise the input string. + */ + intermediate = pf_interpolate_vars(current ? current : string, vars); + if (intermediate) { + sc_free(current); + current = intermediate; + if (pf_trace) { + sc_trace("Printfilter: interpolated [%ld,%ld] \"%s\"\n", + iteration, inner_iteration, current); + } + } else + break; + } + + /* If we have ALRs to process, search out and replace all findable. */ + if (alr_count > 0) { + /* Replace ALRs until no more ALRs can be found. */ + inner_iteration = 0; + while (TRUE) { + /* + * Replace ALRs, and advance current as for variables above. + * Leave the loop when ALR replacements stop. Again, work on + * the current string if any, otherwise the input string. + */ + intermediate = pf_replace_alrs(current ? current : string, + bundle, alr_applied, alr_count); + if (intermediate) { + sc_free(current); + current = intermediate; + if (pf_trace) { + sc_trace("Printfilter: replaced [%ld,%ld] \"%s\"\n", + iteration, inner_iteration, current); + } + } else + break; + inner_iteration++; + } + } + + /* If nothing changed this iteration, stop now. */ + if (current == initial) + break; + } + + /* Free any ALR application flags, and return current, NULL if no change. */ + sc_free(alr_applied); + return current; } @@ -814,22 +744,20 @@ pf_filter_internal (const sc_char *string, * needs to free. */ sc_char * -pf_filter (const sc_char *string, - sc_var_setref_t vars, sc_prop_setref_t bundle) -{ - sc_char *current; - - /* Filter this string, including ALRs replacements. */ - current = pf_filter_internal (string, vars, bundle); - - /* Our contract is to return an allocated string; copy if required. */ - if (!current) - { - current = (sc_char *)sc_malloc (strlen (string) + 1); - strcpy (current, string); - } - - return current; +pf_filter(const sc_char *string, + sc_var_setref_t vars, sc_prop_setref_t bundle) { + sc_char *current; + + /* Filter this string, including ALRs replacements. */ + current = pf_filter_internal(string, vars, bundle); + + /* Our contract is to return an allocated string; copy if required. */ + if (!current) { + current = (sc_char *)sc_malloc(strlen(string) + 1); + strcpy(current, string); + } + + return current; } @@ -842,21 +770,19 @@ pf_filter (const sc_char *string, * an allocated string that the caller needs to free. */ sc_char * -pf_filter_for_info (const sc_char *string, sc_var_setref_t vars) -{ - sc_char *current; +pf_filter_for_info(const sc_char *string, sc_var_setref_t vars) { + sc_char *current; - /* Filter this string, excluding ALRs replacements. */ - current = pf_filter_internal (string, vars, NULL); + /* Filter this string, excluding ALRs replacements. */ + current = pf_filter_internal(string, vars, NULL); - /* Our contract is to return an allocated string; copy if required. */ - if (!current) - { - current = (sc_char *)sc_malloc (strlen (string) + 1); - strcpy (current, string); - } + /* Our contract is to return an allocated string; copy if required. */ + if (!current) { + current = (sc_char *)sc_malloc(strlen(string) + 1); + strcpy(current, string); + } - return current; + return current; } @@ -867,45 +793,39 @@ pf_filter_for_info (const sc_char *string, sc_var_setref_t vars) * send the resulting string to the output channel. */ void -pf_flush (sc_filterref_t filter, - sc_var_setref_t vars, sc_prop_setref_t bundle) -{ - assert (pf_is_valid (filter)); - assert (vars && bundle); - - /* See if there is any buffered data to flush. */ - if (filter->buffer_length > 0) - { - /* - * Filter the buffered string, then print it untagged. Remember to free - * the filtered version. If filtering made no difference, or if the - * buffer was already filtered by, say, checkpointing, just print the - * original buffer untagged instead. - */ - if (filter->needs_filtering) - { - sc_char *filtered; - - filtered = pf_filter_internal (filter->buffer, vars, bundle); - if (filtered) - { - pf_output_untagged (filtered); - sc_free (filtered); - } - else - pf_output_untagged (filter->buffer); - } - else - pf_output_untagged (filter->buffer); - - /* Remove buffered data by resetting length to zero. */ - filter->buffer_length = 0; - filter->needs_filtering = FALSE; - } - - /* Reset new sentence and mute flags. */ - filter->new_sentence = FALSE; - filter->is_muted = FALSE; +pf_flush(sc_filterref_t filter, + sc_var_setref_t vars, sc_prop_setref_t bundle) { + assert(pf_is_valid(filter)); + assert(vars && bundle); + + /* See if there is any buffered data to flush. */ + if (filter->buffer_length > 0) { + /* + * Filter the buffered string, then print it untagged. Remember to free + * the filtered version. If filtering made no difference, or if the + * buffer was already filtered by, say, checkpointing, just print the + * original buffer untagged instead. + */ + if (filter->needs_filtering) { + sc_char *filtered; + + filtered = pf_filter_internal(filter->buffer, vars, bundle); + if (filtered) { + pf_output_untagged(filtered); + sc_free(filtered); + } else + pf_output_untagged(filter->buffer); + } else + pf_output_untagged(filter->buffer); + + /* Remove buffered data by resetting length to zero. */ + filter->buffer_length = 0; + filter->needs_filtering = FALSE; + } + + /* Reset new sentence and mute flags. */ + filter->new_sentence = FALSE; + filter->is_muted = FALSE; } @@ -915,38 +835,36 @@ pf_flush (sc_filterref_t filter, * Append a string to the filter buffer. */ static void -pf_append_string (sc_filterref_t filter, const sc_char *string) -{ - sc_int length, required; - - /* - * Calculate the required buffer size to append string. Remember to add - * one for the terminating NUL. - */ - length = strlen (string); - required = filter->buffer_length + length + 1; - - /* If this is more than the current buffer allocation, resize it. */ - if (required > filter->buffer_allocation) - { - sc_int new_allocation; - - /* Calculate the new malloc size, in increment chunks. */ - new_allocation = ((required + BUFFER_GROW_INCREMENT - 1) - / BUFFER_GROW_INCREMENT) * BUFFER_GROW_INCREMENT; - - /* Grow the buffer. */ - filter->buffer = (sc_char *)sc_realloc (filter->buffer, new_allocation); - filter->buffer_allocation = new_allocation; - } - - /* If empty, put a NUL into the buffer to permit strcat. */ - if (filter->buffer_length == 0) - filter->buffer[0] = NUL; - - /* Append the string to the buffer and extend length. */ - strcat (filter->buffer, string); - filter->buffer_length += length; +pf_append_string(sc_filterref_t filter, const sc_char *string) { + sc_int length, required; + + /* + * Calculate the required buffer size to append string. Remember to add + * one for the terminating NUL. + */ + length = strlen(string); + required = filter->buffer_length + length + 1; + + /* If this is more than the current buffer allocation, resize it. */ + if (required > filter->buffer_allocation) { + sc_int new_allocation; + + /* Calculate the new malloc size, in increment chunks. */ + new_allocation = ((required + BUFFER_GROW_INCREMENT - 1) + / BUFFER_GROW_INCREMENT) * BUFFER_GROW_INCREMENT; + + /* Grow the buffer. */ + filter->buffer = (sc_char *)sc_realloc(filter->buffer, new_allocation); + filter->buffer_allocation = new_allocation; + } + + /* If empty, put a NUL into the buffer to permit strcat. */ + if (filter->buffer_length == 0) + filter->buffer[0] = NUL; + + /* Append the string to the buffer and extend length. */ + strcat(filter->buffer, string); + filter->buffer_length += length; } @@ -959,37 +877,33 @@ pf_append_string (sc_filterref_t filter, const sc_char *string) * values before those values are updated by task actions. */ void -pf_checkpoint (sc_filterref_t filter, - sc_var_setref_t vars, sc_prop_setref_t bundle) -{ - assert (pf_is_valid (filter)); - assert (vars && bundle); - - /* See if there is any buffered data to filter. */ - if (filter->buffer_length > 0) - { - /* - * Filter the buffered string, and place the filtered result, if any, - * back into the filter buffer. We do this by setting the buffer length - * back to zero, then appending the filtered string; this keeps the - * grown buffer intact. - */ - if (filter->needs_filtering) - { - sc_char *filtered; - - filtered = pf_filter_internal (filter->buffer, vars, bundle); - if (filtered) - { - filter->buffer_length = 0; - pf_append_string (filter, filtered); - sc_free (filtered); - } - } - - /* Note the buffer as filtered, to avoid pointless filtering. */ - filter->needs_filtering = FALSE; - } +pf_checkpoint(sc_filterref_t filter, + sc_var_setref_t vars, sc_prop_setref_t bundle) { + assert(pf_is_valid(filter)); + assert(vars && bundle); + + /* See if there is any buffered data to filter. */ + if (filter->buffer_length > 0) { + /* + * Filter the buffered string, and place the filtered result, if any, + * back into the filter buffer. We do this by setting the buffer length + * back to zero, then appending the filtered string; this keeps the + * grown buffer intact. + */ + if (filter->needs_filtering) { + sc_char *filtered; + + filtered = pf_filter_internal(filter->buffer, vars, bundle); + if (filtered) { + filter->buffer_length = 0; + pf_append_string(filter, filtered); + sc_free(filtered); + } + } + + /* Note the buffer as filtered, to avoid pointless filtering. */ + filter->needs_filtering = FALSE; + } } @@ -1005,54 +919,48 @@ pf_checkpoint (sc_filterref_t filter, * in client code. */ const sc_char * -pf_get_buffer (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); - - /* - * Return buffer if filter length is greater than zero. Note that this - * assumes that the buffer is a nul-terminated string. - */ - if (filter->buffer_length > 0) - { - assert (filter->buffer[filter->buffer_length] == NUL); - return filter->buffer; - } - else - return NULL; +pf_get_buffer(sc_filterref_t filter) { + assert(pf_is_valid(filter)); + + /* + * Return buffer if filter length is greater than zero. Note that this + * assumes that the buffer is a nul-terminated string. + */ + if (filter->buffer_length > 0) { + assert(filter->buffer[filter->buffer_length] == NUL); + return filter->buffer; + } else + return NULL; } sc_char * -pf_transfer_buffer (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); - - /* - * If the filter length is greater than zero, pass out the buffer (a nul- - * terminated string) and zero our length, allocation, and set the buffer - * back to NULL; an empty in all except the free-ing. - */ - if (filter->buffer_length > 0) - { - sc_char *retval; - - /* Set the return value to be the buffered text. */ - assert (filter->buffer[filter->buffer_length] == NUL); - retval = filter->buffer; - - /* Clear all filter fields down to empty values. */ - filter->buffer_length = 0; - filter->buffer_allocation = 0; - filter->buffer = NULL; - filter->new_sentence = FALSE; - filter->is_muted = FALSE; - filter->needs_filtering = FALSE; - - /* Return the allocated buffered text. */ - return retval; - } - else - return NULL; +pf_transfer_buffer(sc_filterref_t filter) { + assert(pf_is_valid(filter)); + + /* + * If the filter length is greater than zero, pass out the buffer (a nul- + * terminated string) and zero our length, allocation, and set the buffer + * back to NULL; an empty in all except the free-ing. + */ + if (filter->buffer_length > 0) { + sc_char *retval; + + /* Set the return value to be the buffered text. */ + assert(filter->buffer[filter->buffer_length] == NUL); + retval = filter->buffer; + + /* Clear all filter fields down to empty values. */ + filter->buffer_length = 0; + filter->buffer_allocation = 0; + filter->buffer = NULL; + filter->new_sentence = FALSE; + filter->is_muted = FALSE; + filter->needs_filtering = FALSE; + + /* Return the allocated buffered text. */ + return retval; + } else + return NULL; } @@ -1062,18 +970,17 @@ pf_transfer_buffer (sc_filterref_t filter) * Empty any text currently buffered in the filter. */ void -pf_empty (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); - - /* Free any allocation, and return the filter to initialization state. */ - filter->buffer_length = 0; - filter->buffer_allocation = 0; - sc_free (filter->buffer); - filter->buffer = NULL; - filter->new_sentence = FALSE; - filter->is_muted = FALSE; - filter->needs_filtering = FALSE; +pf_empty(sc_filterref_t filter) { + assert(pf_is_valid(filter)); + + /* Free any allocation, and return the filter to initialization state. */ + filter->buffer_length = 0; + filter->buffer_allocation = 0; + sc_free(filter->buffer); + filter->buffer = NULL; + filter->new_sentence = FALSE; + filter->is_muted = FALSE; + filter->needs_filtering = FALSE; } @@ -1085,39 +992,36 @@ pf_empty (sc_filterref_t filter) * these functions do nothing. */ void -pf_buffer_string (sc_filterref_t filter, const sc_char *string) -{ - assert (pf_is_valid (filter)); - assert (string); - - /* Ignore the call if the printfilter is muted. */ - if (!filter->is_muted) - { - sc_int noted; - - /* Note append start, then append the string to the buffer. */ - noted = filter->buffer_length; - pf_append_string (filter, string); - - /* Adjust the first character of the appended string if flagged. */ - if (filter->new_sentence) - filter->buffer[noted] = sc_toupper (filter->buffer[noted]); - - /* Clear new sentence, and note as currently needing filtering. */ - filter->needs_filtering = TRUE; - filter->new_sentence = FALSE; - } +pf_buffer_string(sc_filterref_t filter, const sc_char *string) { + assert(pf_is_valid(filter)); + assert(string); + + /* Ignore the call if the printfilter is muted. */ + if (!filter->is_muted) { + sc_int noted; + + /* Note append start, then append the string to the buffer. */ + noted = filter->buffer_length; + pf_append_string(filter, string); + + /* Adjust the first character of the appended string if flagged. */ + if (filter->new_sentence) + filter->buffer[noted] = sc_toupper(filter->buffer[noted]); + + /* Clear new sentence, and note as currently needing filtering. */ + filter->needs_filtering = TRUE; + filter->new_sentence = FALSE; + } } void -pf_buffer_character (sc_filterref_t filter, sc_char character) -{ - sc_char buffer[2]; - assert (pf_is_valid (filter)); - - buffer[0] = character; - buffer[1] = NUL; - pf_buffer_string (filter, buffer); +pf_buffer_character(sc_filterref_t filter, sc_char character) { + sc_char buffer[2]; + assert(pf_is_valid(filter)); + + buffer[0] = character; + buffer[1] = NUL; + pf_buffer_string(filter, buffer); } @@ -1130,47 +1034,43 @@ pf_buffer_character (sc_filterref_t filter, sc_char character) * completion text. If muted, this function does nothing. */ void -pf_prepend_string (sc_filterref_t filter, const sc_char *string) -{ - assert (pf_is_valid (filter)); - assert (string); - - /* Ignore the call if the printfilter is muted. */ - if (!filter->is_muted) - { - if (filter->buffer_length > 0) - { - sc_char *copy; - - /* Take a copy of the current buffered string. */ - assert (filter->buffer[filter->buffer_length] == NUL); - copy = (sc_char *)sc_malloc (filter->buffer_length + 1); - strcpy (copy, filter->buffer); - - /* - * Now restart buffering with the input string passed in. Removing - * the current content by zeroing the length preserves the grown - * allocation of the main buffer. - */ - filter->buffer_length = 0; - pf_append_string (filter, string); - - /* Append the string saved above and then free it. */ - pf_append_string (filter, copy); - sc_free (copy); - - /* Adjust the first character of the prepended string if flagged. */ - if (filter->new_sentence) - filter->buffer[0] = sc_toupper (filter->buffer[0]); - - /* Clear new sentence, and note as currently needing filtering. */ - filter->needs_filtering = TRUE; - filter->new_sentence = FALSE; - } - else - /* No data, so the call is equivalent to a normal buffer. */ - pf_buffer_string (filter, string); - } +pf_prepend_string(sc_filterref_t filter, const sc_char *string) { + assert(pf_is_valid(filter)); + assert(string); + + /* Ignore the call if the printfilter is muted. */ + if (!filter->is_muted) { + if (filter->buffer_length > 0) { + sc_char *copy; + + /* Take a copy of the current buffered string. */ + assert(filter->buffer[filter->buffer_length] == NUL); + copy = (sc_char *)sc_malloc(filter->buffer_length + 1); + strcpy(copy, filter->buffer); + + /* + * Now restart buffering with the input string passed in. Removing + * the current content by zeroing the length preserves the grown + * allocation of the main buffer. + */ + filter->buffer_length = 0; + pf_append_string(filter, string); + + /* Append the string saved above and then free it. */ + pf_append_string(filter, copy); + sc_free(copy); + + /* Adjust the first character of the prepended string if flagged. */ + if (filter->new_sentence) + filter->buffer[0] = sc_toupper(filter->buffer[0]); + + /* Clear new sentence, and note as currently needing filtering. */ + filter->needs_filtering = TRUE; + filter->new_sentence = FALSE; + } else + /* No data, so the call is equivalent to a normal buffer. */ + pf_buffer_string(filter, string); + } } @@ -1181,12 +1081,11 @@ pf_prepend_string (sc_filterref_t filter, const sc_char *string) * Ignored if the printfilter is muted. */ void -pf_new_sentence (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); +pf_new_sentence(sc_filterref_t filter) { + assert(pf_is_valid(filter)); - if (!filter->is_muted) - filter->new_sentence = TRUE; + if (!filter->is_muted) + filter->new_sentence = TRUE; } @@ -1197,19 +1096,17 @@ pf_new_sentence (sc_filterref_t filter) * A muted printfilter ignores all new text additions. */ void -pf_mute (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); +pf_mute(sc_filterref_t filter) { + assert(pf_is_valid(filter)); - filter->is_muted = TRUE; + filter->is_muted = TRUE; } void -pf_clear_mute (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); +pf_clear_mute(sc_filterref_t filter) { + assert(pf_is_valid(filter)); - filter->is_muted = FALSE; + filter->is_muted = FALSE; } @@ -1220,27 +1117,23 @@ pf_clear_mute (sc_filterref_t filter) * if the printfilter is muted. */ void -pf_buffer_tag (sc_filterref_t filter, sc_int tag) -{ - const sc_html_tags_t *entry; - assert (pf_is_valid (filter)); - - /* Search the tags table for this tag. */ - for (entry = HTML_TAGS_TABLE; entry->name; entry++) - { - if (tag == entry->tag) - break; - } - - /* If found, output the equivalent string, enclosed in '<>' characters. */ - if (entry->name) - { - pf_buffer_character (filter, LESSTHAN); - pf_buffer_string (filter, entry->name); - pf_buffer_character (filter, GREATERTHAN); - } - else - sc_error ("pf_buffer_tag: invalid tag, %ld\n", tag); +pf_buffer_tag(sc_filterref_t filter, sc_int tag) { + const sc_html_tags_t *entry; + assert(pf_is_valid(filter)); + + /* Search the tags table for this tag. */ + for (entry = HTML_TAGS_TABLE; entry->name; entry++) { + if (tag == entry->tag) + break; + } + + /* If found, output the equivalent string, enclosed in '<>' characters. */ + if (entry->name) { + pf_buffer_character(filter, LESSTHAN); + pf_buffer_string(filter, entry->name); + pf_buffer_character(filter, GREATERTHAN); + } else + sc_error("pf_buffer_tag: invalid tag, %ld\n", tag); } @@ -1253,34 +1146,31 @@ pf_buffer_tag (sc_filterref_t filter, sc_int tag) * a newline if requested by allow_newlines. */ static void -pf_strip_tags_common (sc_char *string, sc_bool allow_newlines) -{ - sc_char *marker, *cursor; - - /* Run through the string looking for <...> tags. */ - marker = string; - for (cursor = strchr (marker, LESSTHAN); - cursor; cursor = strchr (marker, LESSTHAN)) - { - sc_char *tag_end; - - /* Locate tag end, and break if unterminated. */ - tag_end = strchr (cursor, GREATERTHAN); - if (!tag_end) - break; - - /* If the tag is
, replace with newline if requested. */ - if (allow_newlines) - { - if (tag_end - cursor == 3 - && sc_strncasecmp (cursor + 1, "br", 2) == 0) - *cursor++ = '\n'; - } - - /* Remove the tag from the string, then advance input. */ - memmove (cursor, tag_end + 1, strlen (tag_end)); - marker = cursor; - } +pf_strip_tags_common(sc_char *string, sc_bool allow_newlines) { + sc_char *marker, *cursor; + + /* Run through the string looking for <...> tags. */ + marker = string; + for (cursor = strchr(marker, LESSTHAN); + cursor; cursor = strchr(marker, LESSTHAN)) { + sc_char *tag_end; + + /* Locate tag end, and break if unterminated. */ + tag_end = strchr(cursor, GREATERTHAN); + if (!tag_end) + break; + + /* If the tag is
, replace with newline if requested. */ + if (allow_newlines) { + if (tag_end - cursor == 3 + && sc_strncasecmp(cursor + 1, "br", 2) == 0) + *cursor++ = '\n'; + } + + /* Remove the tag from the string, then advance input. */ + memmove(cursor, tag_end + 1, strlen(tag_end)); + marker = cursor; + } } @@ -1292,15 +1182,13 @@ pf_strip_tags_common (sc_char *string, sc_bool allow_newlines) * allow
tags to map into newlines in hints strings. */ void -pf_strip_tags (sc_char *string) -{ - pf_strip_tags_common (string, FALSE); +pf_strip_tags(sc_char *string) { + pf_strip_tags_common(string, FALSE); } void -pf_strip_tags_for_hints (sc_char *string) -{ - pf_strip_tags_common (string, TRUE); +pf_strip_tags_for_hints(sc_char *string) { + pf_strip_tags_common(string, TRUE); } @@ -1315,78 +1203,71 @@ pf_strip_tags_for_hints (sc_char *string) * so the caller needs to remember to free it. */ sc_char * -pf_escape (const sc_char *string) -{ - const sc_char *marker, *cursor; - sc_char *buffer; - - /* Start with an empty return buffer. */ - buffer = (sc_char *)sc_malloc (strlen (string) + 1); - buffer[0] = NUL; - - /* Run through the string looking for <, >, %, or other escapes. */ - marker = string; - for (cursor = marker + strcspn (marker, ESCAPES); - cursor[0] != NUL; cursor = marker + strcspn (marker, ESCAPES)) - { - const sc_char *escape; - sc_char escape_buffer[3]; - - /* Extend buffer to hold the string so far. */ - if (cursor > marker) - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + cursor - marker + 1); - buffer[strlen (buffer) + cursor - marker] = NUL; - memcpy (buffer + strlen (buffer), marker, cursor - marker); - } - - /* Determine the appropriate character escape. */ - if (cursor[0] == LESSTHAN) - escape = ENTITY_LESSTHAN; - else if (cursor[0] == GREATERTHAN) - escape = ENTITY_GREATERTHAN; - else if (cursor[0] == PERCENT) - escape = ENTITY_PERCENT; - else - { - /* - * No real escape available, so fake, badly, by appending a space - * for cases where we've encountered a character entity; leave - * others untouched. - */ - escape_buffer[0] = cursor[0]; - if (sc_strncasecmp (cursor, - ENTITY_LESSTHAN, ENTITY_LENGTH) == 0 - || sc_strncasecmp (cursor, - ENTITY_GREATERTHAN, ENTITY_LENGTH) == 0 - || sc_strncasecmp (cursor, - ENTITY_PERCENT, PERCENT_LENGTH) == 0) - { - escape_buffer[1] = ' '; - escape_buffer[2] = NUL; - } - else - escape_buffer[1] = NUL; - escape = escape_buffer; - } - - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + strlen (escape) + 1); - strcat (buffer, escape); - - /* Pass over character escaped and continue. */ - cursor++; - marker = cursor; - } - - /* Add all remaining characters to the buffer. */ - if (cursor > marker) - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + cursor - marker + 1); - buffer[strlen (buffer) + cursor - marker] = NUL; - memcpy (buffer + strlen (buffer), marker, cursor - marker); - } - - return buffer; +pf_escape(const sc_char *string) { + const sc_char *marker, *cursor; + sc_char *buffer; + + /* Start with an empty return buffer. */ + buffer = (sc_char *)sc_malloc(strlen(string) + 1); + buffer[0] = NUL; + + /* Run through the string looking for <, >, %, or other escapes. */ + marker = string; + for (cursor = marker + strcspn(marker, ESCAPES); + cursor[0] != NUL; cursor = marker + strcspn(marker, ESCAPES)) { + const sc_char *escape; + sc_char escape_buffer[3]; + + /* Extend buffer to hold the string so far. */ + if (cursor > marker) { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + cursor - marker + 1); + buffer[strlen(buffer) + cursor - marker] = NUL; + memcpy(buffer + strlen(buffer), marker, cursor - marker); + } + + /* Determine the appropriate character escape. */ + if (cursor[0] == LESSTHAN) + escape = ENTITY_LESSTHAN; + else if (cursor[0] == GREATERTHAN) + escape = ENTITY_GREATERTHAN; + else if (cursor[0] == PERCENT) + escape = ENTITY_PERCENT; + else { + /* + * No real escape available, so fake, badly, by appending a space + * for cases where we've encountered a character entity; leave + * others untouched. + */ + escape_buffer[0] = cursor[0]; + if (sc_strncasecmp(cursor, + ENTITY_LESSTHAN, ENTITY_LENGTH) == 0 + || sc_strncasecmp(cursor, + ENTITY_GREATERTHAN, ENTITY_LENGTH) == 0 + || sc_strncasecmp(cursor, + ENTITY_PERCENT, PERCENT_LENGTH) == 0) { + escape_buffer[1] = ' '; + escape_buffer[2] = NUL; + } else + escape_buffer[1] = NUL; + escape = escape_buffer; + } + + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + strlen(escape) + 1); + strcat(buffer, escape); + + /* Pass over character escaped and continue. */ + cursor++; + marker = cursor; + } + + /* Add all remaining characters to the buffer. */ + if (cursor > marker) { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + cursor - marker + 1); + buffer[strlen(buffer) + cursor - marker] = NUL; + memcpy(buffer + strlen(buffer), marker, cursor - marker); + } + + return buffer; } @@ -1397,52 +1278,50 @@ pf_escape (const sc_char *string) * the match if the string matched, 0 otherwise. */ static sc_int -pf_compare_words (const sc_char *string, const sc_char *words) -{ - sc_int word_posn, posn; - - /* None expected, but skip leading space. */ - for (word_posn = 0; sc_isspace (words[word_posn]) && words[word_posn] != NUL;) - word_posn++; - - /* Match characters from words with the string at position. */ - posn = 0; - while (TRUE) - { - /* Any character mismatch means no words match. */ - if (sc_tolower (words[word_posn]) != sc_tolower (string[posn])) - return 0; - - /* Move to next character in each. */ - word_posn++; - posn++; - - /* - * If at space, advance over whitespace in words list. Stop when we - * hit the end of the words list. - */ - while (sc_isspace (words[word_posn]) && words[word_posn] != NUL) - word_posn++; - if (words[word_posn] == NUL) - break; - - /* - * About to match another word, so advance over whitespace in the - * current string too. - */ - while (sc_isspace (string[posn]) && string[posn] != NUL) - posn++; - } - - /* - * We reached the end of words. If we're at the end of the match string, - * or at spaces, we've matched. - */ - if (sc_isspace (string[posn]) || string[posn] == NUL) - return posn; - - /* More text after the match, so it's not quite a match. */ - return 0; +pf_compare_words(const sc_char *string, const sc_char *words) { + sc_int word_posn, posn; + + /* None expected, but skip leading space. */ + for (word_posn = 0; sc_isspace(words[word_posn]) && words[word_posn] != NUL;) + word_posn++; + + /* Match characters from words with the string at position. */ + posn = 0; + while (TRUE) { + /* Any character mismatch means no words match. */ + if (sc_tolower(words[word_posn]) != sc_tolower(string[posn])) + return 0; + + /* Move to next character in each. */ + word_posn++; + posn++; + + /* + * If at space, advance over whitespace in words list. Stop when we + * hit the end of the words list. + */ + while (sc_isspace(words[word_posn]) && words[word_posn] != NUL) + word_posn++; + if (words[word_posn] == NUL) + break; + + /* + * About to match another word, so advance over whitespace in the + * current string too. + */ + while (sc_isspace(string[posn]) && string[posn] != NUL) + posn++; + } + + /* + * We reached the end of words. If we're at the end of the match string, + * or at spaces, we've matched. + */ + if (sc_isspace(string[posn]) || string[posn] == NUL) + return posn; + + /* More text after the match, so it's not quite a match. */ + return 0; } @@ -1454,122 +1333,113 @@ pf_compare_words (const sc_char *string, const sc_char *words) * return string is malloc'ed, so the caller needs to remember to free it. */ sc_char * -pf_filter_input (const sc_char *string, sc_prop_setref_t bundle) -{ - sc_vartype_t vt_key[3]; - sc_int synonym_count, buffer_allocation; - sc_char *buffer; - const sc_char *current; - assert (string && bundle); - - if (pf_trace) - sc_trace ("Printfilter: input \"%s\"\n", string); - - /* Obtain a count of synonyms. */ - vt_key[0].string = "Synonyms"; - synonym_count = prop_get_child_count (bundle, "I<-s", vt_key); - - /* Begin with a NULL buffer for lazy allocation. */ - buffer_allocation = 0; - buffer = NULL; - - /* Loop over each word in the string. */ - current = string + strspn (string, WHITESPACE); - while (current[0] != NUL) - { - sc_int index_, extent; - - /* Search for a synonym match at this index into the buffer. */ - extent = 0; - for (index_ = 0; index_ < synonym_count; index_++) - { - const sc_char *original; - - /* Retrieve the synonym original string. */ - vt_key[0].string = "Synonyms"; - vt_key[1].integer = index_; - vt_key[2].string = "Original"; - original = prop_get_string (bundle, "S<-sis", vt_key); - - /* Compare the original at this point. */ - extent = pf_compare_words (current, original); - if (extent > 0) - break; - } - - /* - * If a synonym found was, index_ indicates it, and extent shows how - * much of the buffer to replace with it. - */ - if (index_ < synonym_count && extent > 0) - { - const sc_char *replacement; - sc_char *position; - sc_int length, final; - - /* - * If not yet allocated, allocate a buffer now, and copy the input - * string into it. Then switch current to the equivalent location - * in the allocated buffer. More basic copy-on-write. - */ - if (!buffer) - { - buffer_allocation = strlen (string) + 1; - buffer = (sc_char *)sc_malloc (buffer_allocation); - strcpy (buffer, string); - current = buffer + (current - string); - } - - /* Find the replacement text for this synonym. */ - vt_key[0].string = "Synonyms"; - vt_key[1].integer = index_; - vt_key[2].string = "Replacement"; - replacement = prop_get_string (bundle, "S<-sis", vt_key); - length = strlen (replacement); - - /* - * If necessary, grow the output buffer for the replacement, - * remembering to adjust current for the new buffer allocated. - * At the same time, note the last character index for the move. - */ - if (length > extent) - { - sc_int offset; - - offset = current - buffer; - buffer_allocation += length - extent; - buffer = (sc_char *)sc_realloc (buffer, buffer_allocation); - current = buffer + offset; - final = length; - } - else - final = extent; - - /* Insert the replacement string into the buffer. */ - position = buffer + (current - buffer); - memmove (position + length, - position + extent, - buffer_allocation - (current - buffer) - final); - memcpy (position, replacement, length); - - /* Adjust current to skip over the replacement. */ - current += length; - - if (pf_trace) - sc_trace ("Printfilter: synonym \"%s\"\n", buffer); - } - else - { - /* If no match, advance current over the unmatched word. */ - current += strcspn (current, WHITESPACE); - } - - /* Set current to the next word start. */ - current += strspn (current, WHITESPACE); - } - - /* Return the final string, or NULL if no synonym replacements. */ - return buffer; +pf_filter_input(const sc_char *string, sc_prop_setref_t bundle) { + sc_vartype_t vt_key[3]; + sc_int synonym_count, buffer_allocation; + sc_char *buffer; + const sc_char *current; + assert(string && bundle); + + if (pf_trace) + sc_trace("Printfilter: input \"%s\"\n", string); + + /* Obtain a count of synonyms. */ + vt_key[0].string = "Synonyms"; + synonym_count = prop_get_child_count(bundle, "I<-s", vt_key); + + /* Begin with a NULL buffer for lazy allocation. */ + buffer_allocation = 0; + buffer = NULL; + + /* Loop over each word in the string. */ + current = string + strspn(string, WHITESPACE); + while (current[0] != NUL) { + sc_int index_, extent; + + /* Search for a synonym match at this index into the buffer. */ + extent = 0; + for (index_ = 0; index_ < synonym_count; index_++) { + const sc_char *original; + + /* Retrieve the synonym original string. */ + vt_key[0].string = "Synonyms"; + vt_key[1].integer = index_; + vt_key[2].string = "Original"; + original = prop_get_string(bundle, "S<-sis", vt_key); + + /* Compare the original at this point. */ + extent = pf_compare_words(current, original); + if (extent > 0) + break; + } + + /* + * If a synonym found was, index_ indicates it, and extent shows how + * much of the buffer to replace with it. + */ + if (index_ < synonym_count && extent > 0) { + const sc_char *replacement; + sc_char *position; + sc_int length, final; + + /* + * If not yet allocated, allocate a buffer now, and copy the input + * string into it. Then switch current to the equivalent location + * in the allocated buffer. More basic copy-on-write. + */ + if (!buffer) { + buffer_allocation = strlen(string) + 1; + buffer = (sc_char *)sc_malloc(buffer_allocation); + strcpy(buffer, string); + current = buffer + (current - string); + } + + /* Find the replacement text for this synonym. */ + vt_key[0].string = "Synonyms"; + vt_key[1].integer = index_; + vt_key[2].string = "Replacement"; + replacement = prop_get_string(bundle, "S<-sis", vt_key); + length = strlen(replacement); + + /* + * If necessary, grow the output buffer for the replacement, + * remembering to adjust current for the new buffer allocated. + * At the same time, note the last character index for the move. + */ + if (length > extent) { + sc_int offset; + + offset = current - buffer; + buffer_allocation += length - extent; + buffer = (sc_char *)sc_realloc(buffer, buffer_allocation); + current = buffer + offset; + final = length; + } else + final = extent; + + /* Insert the replacement string into the buffer. */ + position = buffer + (current - buffer); + memmove(position + length, + position + extent, + buffer_allocation - (current - buffer) - final); + memcpy(position, replacement, length); + + /* Adjust current to skip over the replacement. */ + current += length; + + if (pf_trace) + sc_trace("Printfilter: synonym \"%s\"\n", buffer); + } else { + /* If no match, advance current over the unmatched word. */ + current += strcspn(current, WHITESPACE); + } + + /* Set current to the next word start. */ + current += strspn(current, WHITESPACE); + } + + /* Return the final string, or NULL if no synonym replacements. */ + return buffer; } @@ -1579,9 +1449,8 @@ pf_filter_input (const sc_char *string, sc_prop_setref_t bundle) * Set filter tracing on/off. */ void -pf_debug_trace (sc_bool flag) -{ - pf_trace = flag; +pf_debug_trace(sc_bool flag) { + pf_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scprops.cpp b/engines/glk/adrift/scprops.cpp index bdf51dc4db..aeb0d24db0 100644 --- a/engines/glk/adrift/scprops.cpp +++ b/engines/glk/adrift/scprops.cpp @@ -28,10 +28,10 @@ namespace Adrift { /* Assorted definitions and constants. */ static const sc_uint PROP_MAGIC = 0x7927b2e0; -enum -{ PROP_GROW_INCREMENT = 32, - MAX_INTEGER_KEY = 65535, - NODE_POOL_CAPACITY = 512 +enum { + PROP_GROW_INCREMENT = 32, + MAX_INTEGER_KEY = 65535, + NODE_POOL_CAPACITY = 512 }; static const sc_char NUL = '\0'; @@ -81,9 +81,8 @@ typedef sc_prop_set_s sc_prop_set_t; * Return TRUE if pointer is a valid properties set, FALSE otherwise. */ static sc_bool -prop_is_valid (sc_prop_setref_t bundle) -{ - return bundle && bundle->magic == PROP_MAGIC; +prop_is_valid(sc_prop_setref_t bundle) { + return bundle && bundle->magic == PROP_MAGIC; } @@ -93,12 +92,11 @@ prop_is_valid (sc_prop_setref_t bundle) * Round up a count of elements to the next block of grow increments. */ static sc_int -prop_round_up (sc_int elements) -{ - sc_int extended; +prop_round_up(sc_int elements) { + sc_int extended; - extended = elements + PROP_GROW_INCREMENT - 1; - return (extended / PROP_GROW_INCREMENT) * PROP_GROW_INCREMENT; + extended = elements + PROP_GROW_INCREMENT - 1; + return (extended / PROP_GROW_INCREMENT) * PROP_GROW_INCREMENT; } @@ -114,31 +112,29 @@ prop_round_up (sc_int elements) * frequently. */ static void * -prop_ensure_capacity (void *array, - sc_int old_size, sc_int new_size, sc_int element_size) -{ - sc_int current, required; - - /* - * See if there's any resize necessary, that is, does the new size round up - * to a larger number of elements than the old size. - */ - current = prop_round_up (old_size); - required = prop_round_up (new_size); - if (required > current) - { - sc_byte *new_array, *start_clearing; - - /* Grow array to the required size, and zero new elements. */ - new_array = (sc_byte *)sc_realloc (array, required * element_size); - start_clearing = new_array + current * element_size; - memset (start_clearing, 0, (required - current) * element_size); - - return new_array; - } - - /* No resize necessary. */ - return array; +prop_ensure_capacity(void *array, + sc_int old_size, sc_int new_size, sc_int element_size) { + sc_int current, required; + + /* + * See if there's any resize necessary, that is, does the new size round up + * to a larger number of elements than the old size. + */ + current = prop_round_up(old_size); + required = prop_round_up(new_size); + if (required > current) { + sc_byte *new_array, *start_clearing; + + /* Grow array to the required size, and zero new elements. */ + new_array = (sc_byte *)sc_realloc(array, required * element_size); + start_clearing = new_array + current * element_size; + memset(start_clearing, 0, (required - current) * element_size); + + return new_array; + } + + /* No resize necessary. */ + return array; } @@ -150,12 +146,11 @@ prop_ensure_capacity (void *array, * the array cannot ever be grown safely again. */ static void * -prop_trim_capacity (void *array, sc_int size, sc_int element_size) -{ - if (prop_round_up (size) > size) - return sc_realloc (array, size * element_size); - else - return array; +prop_trim_capacity(void *array, sc_int size, sc_int element_size) { + if (prop_round_up(size) > size) + return sc_realloc(array, size * element_size); + else + return array; } @@ -167,9 +162,8 @@ prop_trim_capacity (void *array, sc_int size, sc_int element_size) * bsearch() and qsort(). */ static int -prop_compare (const void *string1, const void *string2) -{ - return strcmp (*(sc_char *const *) string1, *(sc_char *const *) string2); +prop_compare(const void *string1, const void *string2) { + return strcmp(*(sc_char * const *) string1, *(sc_char * const *) string2); } @@ -182,44 +176,42 @@ prop_compare (const void *string1, const void *string2) * contain a malloced copy of the string passed in. */ static const sc_char * -prop_dictionary_lookup (sc_prop_setref_t bundle, const sc_char *string) -{ - sc_char *dict_string; - - /* - * Search the existing dictionary for the string. Although not GNU libc, - * some libc's loop or crash when given a list of zero length, so we need to - * trap that here. - */ - if (bundle->dictionary_length > 0) - { - const sc_char *const *dict_search; - - dict_search = (const sc_char *const *)bsearch (&string, bundle->dictionary, - bundle->dictionary_length, - sizeof (bundle->dictionary[0]), prop_compare); - if (dict_search) - return *dict_search; - } - - /* Not found, so copy the string for dictionary insertion. */ - dict_string = (sc_char *)sc_malloc (strlen (string) + 1); - strcpy (dict_string, string); - - /* Extend the dictionary if necessary. */ - bundle->dictionary = (sc_char **)prop_ensure_capacity (bundle->dictionary, - bundle->dictionary_length, - bundle->dictionary_length + 1, - sizeof (bundle->dictionary[0])); - - /* Add the new entry to the end of the dictionary array, and sort. */ - bundle->dictionary[bundle->dictionary_length++] = dict_string; - qsort (bundle->dictionary, - bundle->dictionary_length, - sizeof (bundle->dictionary[0]), prop_compare); - - /* Return the address of the new string. */ - return dict_string; +prop_dictionary_lookup(sc_prop_setref_t bundle, const sc_char *string) { + sc_char *dict_string; + + /* + * Search the existing dictionary for the string. Although not GNU libc, + * some libc's loop or crash when given a list of zero length, so we need to + * trap that here. + */ + if (bundle->dictionary_length > 0) { + const sc_char *const *dict_search; + + dict_search = (const sc_char * const *)bsearch(&string, bundle->dictionary, + bundle->dictionary_length, + sizeof(bundle->dictionary[0]), prop_compare); + if (dict_search) + return *dict_search; + } + + /* Not found, so copy the string for dictionary insertion. */ + dict_string = (sc_char *)sc_malloc(strlen(string) + 1); + strcpy(dict_string, string); + + /* Extend the dictionary if necessary. */ + bundle->dictionary = (sc_char **)prop_ensure_capacity(bundle->dictionary, + bundle->dictionary_length, + bundle->dictionary_length + 1, + sizeof(bundle->dictionary[0])); + + /* Add the new entry to the end of the dictionary array, and sort. */ + bundle->dictionary[bundle->dictionary_length++] = dict_string; + qsort(bundle->dictionary, + bundle->dictionary_length, + sizeof(bundle->dictionary[0]), prop_compare); + + /* Return the address of the new string. */ + return dict_string; } @@ -232,36 +224,34 @@ prop_dictionary_lookup (sc_prop_setref_t bundle, const sc_char *string) * malloc's of small individual nodes. */ static sc_prop_noderef_t -prop_new_node (sc_prop_setref_t bundle) -{ - sc_int node_index; - sc_prop_noderef_t node; - - /* See if we need to create a new node pool. */ - node_index = bundle->node_count % NODE_POOL_CAPACITY; - if (node_index == 0) - { - sc_int required; - - /* Extend the node pools array if necessary. */ - bundle->node_pools = (sc_prop_noderef_t *)prop_ensure_capacity (bundle->node_pools, - bundle->node_pools_length, - bundle->node_pools_length + 1, - sizeof (bundle-> - node_pools[0])); - - /* Create a new node pool, and increment the length. */ - required = NODE_POOL_CAPACITY * sizeof (*bundle->node_pools[0]); - bundle->node_pools[bundle->node_pools_length] = (sc_prop_noderef_t)sc_malloc(required); - bundle->node_pools_length++; - } - - /* Find the next node address, and increment the node counter. */ - node = bundle->node_pools[bundle->node_pools_length - 1] + node_index; - bundle->node_count++; - - /* Return the new node. */ - return node; +prop_new_node(sc_prop_setref_t bundle) { + sc_int node_index; + sc_prop_noderef_t node; + + /* See if we need to create a new node pool. */ + node_index = bundle->node_count % NODE_POOL_CAPACITY; + if (node_index == 0) { + sc_int required; + + /* Extend the node pools array if necessary. */ + bundle->node_pools = (sc_prop_noderef_t *)prop_ensure_capacity(bundle->node_pools, + bundle->node_pools_length, + bundle->node_pools_length + 1, + sizeof(bundle-> + node_pools[0])); + + /* Create a new node pool, and increment the length. */ + required = NODE_POOL_CAPACITY * sizeof(*bundle->node_pools[0]); + bundle->node_pools[bundle->node_pools_length] = (sc_prop_noderef_t)sc_malloc(required); + bundle->node_pools_length++; + } + + /* Find the next node address, and increment the node counter. */ + node = bundle->node_pools[bundle->node_pools_length - 1] + node_index; + bundle->node_count++; + + /* Return the new node. */ + return node; } @@ -271,73 +261,66 @@ prop_new_node (sc_prop_setref_t bundle) * Find a child node of the given parent whose name matches that passed in. */ static sc_prop_noderef_t -prop_find_child (sc_prop_noderef_t parent, sc_int type, sc_vartype_t name) -{ - /* See if this node has any children. */ - if (parent->child_list) - { - sc_int index_; - sc_prop_noderef_t child; - - /* Do the lookup based on name type. */ - switch (type) - { - case PROP_KEY_INTEGER: - /* - * As with adding a child below, here we'll range-check an integer - * key just to make sure nobody has any unreal expectations of us. - */ - if (name.integer < 0) - sc_fatal ("prop_find_child: integer key cannot be negative\n"); - else if (name.integer > MAX_INTEGER_KEY) - sc_fatal ("prop_find_child: integer key is too large\n"); - - /* - * For integer lookups, return the child at the indexed offset - * directly, provided it exists. - */ - if (name.integer >= 0 && name.integer < parent->property.integer) - { - child = parent->child_list[name.integer]; - return child; - } - break; - - case PROP_KEY_STRING: - /* Scan children for a string name match. */ - for (index_ = 0; index_ < parent->property.integer; index_++) - { - child = parent->child_list[index_]; - if (strcmp (child->name.string, name.string) == 0) - break; - } - - /* Return child if we found a match. */ - if (index_ < parent->property.integer) - { - /* - * Before returning the child, try to improve future scans by - * moving the matched entry to index_ 0 -- this gives a key set - * sorted by recent usage, helpful as the same string key is - * used repeatedly in loops. - */ - if (index_ > 0) - { - memmove (parent->child_list + 1, - parent->child_list, index_ * sizeof (child)); - parent->child_list[0] = child; - } - return child; - } - break; - - default: - sc_fatal ("prop_find_child: invalid key type\n"); - } - } - - /* No matching child found. */ - return NULL; +prop_find_child(sc_prop_noderef_t parent, sc_int type, sc_vartype_t name) { + /* See if this node has any children. */ + if (parent->child_list) { + sc_int index_; + sc_prop_noderef_t child; + + /* Do the lookup based on name type. */ + switch (type) { + case PROP_KEY_INTEGER: + /* + * As with adding a child below, here we'll range-check an integer + * key just to make sure nobody has any unreal expectations of us. + */ + if (name.integer < 0) + sc_fatal("prop_find_child: integer key cannot be negative\n"); + else if (name.integer > MAX_INTEGER_KEY) + sc_fatal("prop_find_child: integer key is too large\n"); + + /* + * For integer lookups, return the child at the indexed offset + * directly, provided it exists. + */ + if (name.integer >= 0 && name.integer < parent->property.integer) { + child = parent->child_list[name.integer]; + return child; + } + break; + + case PROP_KEY_STRING: + /* Scan children for a string name match. */ + for (index_ = 0; index_ < parent->property.integer; index_++) { + child = parent->child_list[index_]; + if (strcmp(child->name.string, name.string) == 0) + break; + } + + /* Return child if we found a match. */ + if (index_ < parent->property.integer) { + /* + * Before returning the child, try to improve future scans by + * moving the matched entry to index_ 0 -- this gives a key set + * sorted by recent usage, helpful as the same string key is + * used repeatedly in loops. + */ + if (index_ > 0) { + memmove(parent->child_list + 1, + parent->child_list, index_ * sizeof(child)); + parent->child_list[0] = child; + } + return child; + } + break; + + default: + sc_fatal("prop_find_child: invalid key type\n"); + } + } + + /* No matching child found. */ + return NULL; } @@ -348,83 +331,80 @@ prop_find_child (sc_prop_noderef_t parent, sc_int type, sc_vartype_t name) * needs to be passed so that string names can be added to the dictionary. */ static sc_prop_noderef_t -prop_add_child (sc_prop_noderef_t parent, - sc_int type, sc_vartype_t name, sc_prop_setref_t bundle) -{ - sc_prop_noderef_t child; - - /* Not possible if growable allocations have been trimmed. */ - if (bundle->is_readonly) - sc_fatal ("prop_add_child: can't add to readonly properties\n"); - - /* Create the new node. */ - child = prop_new_node (bundle); - switch (type) - { - case PROP_KEY_INTEGER: - child->name.integer = name.integer; - break; - case PROP_KEY_STRING: - child->name.string = prop_dictionary_lookup (bundle, name.string); - break; - - default: - sc_fatal ("prop_add_child: invalid key type\n"); - } - - /* Initialize property and child list to visible nulls. */ - child->property.voidp = NULL; - child->child_list = NULL; - - /* Make a brief check for obvious overwrites. */ - if (!parent->child_list && parent->property.voidp) - sc_error ("prop_add_child: node overwritten, probable data loss\n"); - - /* Add the child to the parent, position dependent on key type. */ - switch (type) - { - case PROP_KEY_INTEGER: - /* - * Range check on integer keys, must be >= 0 for direct indexing to work, - * and we'll also apply a reasonableness constraint, to try to catch - * errors where string pointers are passed in as integers, which would - * otherwise lead to some extreme malloc() attempts. - */ - if (name.integer < 0) - sc_fatal ("prop_add_child: integer key cannot be negative\n"); - else if (name.integer > MAX_INTEGER_KEY) - sc_fatal ("prop_add_child: integer key is too large\n"); - - /* Resize the parent's child list if necessary. */ - parent->child_list = (sc_prop_noderef_t *)prop_ensure_capacity (parent->child_list, - parent->property.integer, - name.integer + 1, - sizeof (*parent->child_list)); - - /* Update the child count if the new node increases it. */ - if (parent->property.integer <= name.integer) - parent->property.integer = name.integer + 1; - - /* Store the child in its indexed list location. */ - parent->child_list[name.integer] = child; - break; - - case PROP_KEY_STRING: - /* Add a single entry to the child list, and resize. */ - parent->child_list = (sc_prop_noderef_t *)prop_ensure_capacity (parent->child_list, - parent->property.integer, - parent->property.integer + 1, - sizeof (*parent->child_list)); - - /* Store the child at the end of the list. */ - parent->child_list[parent->property.integer++] = child; - break; - - default: - sc_fatal ("prop_add_child: invalid key type\n"); - } - - return child; +prop_add_child(sc_prop_noderef_t parent, + sc_int type, sc_vartype_t name, sc_prop_setref_t bundle) { + sc_prop_noderef_t child; + + /* Not possible if growable allocations have been trimmed. */ + if (bundle->is_readonly) + sc_fatal("prop_add_child: can't add to readonly properties\n"); + + /* Create the new node. */ + child = prop_new_node(bundle); + switch (type) { + case PROP_KEY_INTEGER: + child->name.integer = name.integer; + break; + case PROP_KEY_STRING: + child->name.string = prop_dictionary_lookup(bundle, name.string); + break; + + default: + sc_fatal("prop_add_child: invalid key type\n"); + } + + /* Initialize property and child list to visible nulls. */ + child->property.voidp = NULL; + child->child_list = NULL; + + /* Make a brief check for obvious overwrites. */ + if (!parent->child_list && parent->property.voidp) + sc_error("prop_add_child: node overwritten, probable data loss\n"); + + /* Add the child to the parent, position dependent on key type. */ + switch (type) { + case PROP_KEY_INTEGER: + /* + * Range check on integer keys, must be >= 0 for direct indexing to work, + * and we'll also apply a reasonableness constraint, to try to catch + * errors where string pointers are passed in as integers, which would + * otherwise lead to some extreme malloc() attempts. + */ + if (name.integer < 0) + sc_fatal("prop_add_child: integer key cannot be negative\n"); + else if (name.integer > MAX_INTEGER_KEY) + sc_fatal("prop_add_child: integer key is too large\n"); + + /* Resize the parent's child list if necessary. */ + parent->child_list = (sc_prop_noderef_t *)prop_ensure_capacity(parent->child_list, + parent->property.integer, + name.integer + 1, + sizeof(*parent->child_list)); + + /* Update the child count if the new node increases it. */ + if (parent->property.integer <= name.integer) + parent->property.integer = name.integer + 1; + + /* Store the child in its indexed list location. */ + parent->child_list[name.integer] = child; + break; + + case PROP_KEY_STRING: + /* Add a single entry to the child list, and resize. */ + parent->child_list = (sc_prop_noderef_t *)prop_ensure_capacity(parent->child_list, + parent->property.integer, + parent->property.integer + 1, + sizeof(*parent->child_list)); + + /* Store the child at the end of the list. */ + parent->child_list[parent->property.integer++] = child; + break; + + default: + sc_fatal("prop_add_child: invalid key type\n"); + } + + return child; } @@ -443,104 +423,97 @@ prop_add_child (sc_prop_noderef_t parent, * integer, and another string. */ void -prop_put (sc_prop_setref_t bundle, const sc_char *format, - sc_vartype_t vt_value, const sc_vartype_t vt_key[]) -{ - sc_prop_noderef_t node; - sc_int index_; - assert (prop_is_valid (bundle)); - - /* Format check. */ - if (!format || format[0] == NUL - || format[1] != '-' || format[2] != '>' || format[3] == NUL) - sc_fatal ("prop_put: format error\n"); - - /* Trace property put. */ - if (prop_trace) - { - sc_trace ("Property: put "); - switch (format[0]) - { - case PROP_STRING: - sc_trace ("\"%s\"", vt_value.string); - break; - case PROP_INTEGER: - sc_trace ("%ld", vt_value.integer); - break; - case PROP_BOOLEAN: - sc_trace ("%s", vt_value.boolean ? "true" : "false"); - break; - - default: - sc_trace ("%p [invalid type]", vt_value.voidp); - break; - } - sc_trace (", key \"%s\" : ", format); - for (index_ = 0; format[index_ + 3] != NUL; index_++) - { - sc_trace ("%s", index_ > 0 ? "," : ""); - switch (format[index_ + 3]) - { - case PROP_KEY_STRING: - sc_trace ("\"%s\"", vt_key[index_].string); - break; - case PROP_KEY_INTEGER: - sc_trace ("%ld", vt_key[index_].integer); - break; - - default: - sc_trace ("%p [invalid type]", vt_key[index_].voidp); - break; - } - } - sc_trace ("\n"); - } - - /* - * Iterate keys, finding matching child nodes at each level. If no matching - * child is found, insert one and continue. - */ - node = bundle->root_node; - for (index_ = 0; format[index_ + 3] != NUL; index_++) - { - sc_prop_noderef_t child; - sc_int type; - - /* - * Search this level for a name matching the key. If found, advance - * to that child node. Otherwise, add the node to the tree, including - * the set so that the dictionary can be extended. - */ - type = format[index_ + 3]; - child = prop_find_child (node, type, vt_key[index_]); - if (child) - node = child; - else - node = prop_add_child (node, type, vt_key[index_], bundle); - } - - /* - * Ensure that we're not about to overwrite an internal node child count. - */ - if (node->child_list) - sc_fatal ("prop_put: overwrite of internal node\n"); - - /* Set our properties in the final node. */ - switch (format[0]) - { - case PROP_INTEGER: - node->property.integer = vt_value.integer; - break; - case PROP_BOOLEAN: - node->property.boolean = vt_value.boolean; - break; - case PROP_STRING: - node->property.string = vt_value.string; - break; - - default: - sc_fatal ("prop_put: invalid property type\n"); - } +prop_put(sc_prop_setref_t bundle, const sc_char *format, + sc_vartype_t vt_value, const sc_vartype_t vt_key[]) { + sc_prop_noderef_t node; + sc_int index_; + assert(prop_is_valid(bundle)); + + /* Format check. */ + if (!format || format[0] == NUL + || format[1] != '-' || format[2] != '>' || format[3] == NUL) + sc_fatal("prop_put: format error\n"); + + /* Trace property put. */ + if (prop_trace) { + sc_trace("Property: put "); + switch (format[0]) { + case PROP_STRING: + sc_trace("\"%s\"", vt_value.string); + break; + case PROP_INTEGER: + sc_trace("%ld", vt_value.integer); + break; + case PROP_BOOLEAN: + sc_trace("%s", vt_value.boolean ? "true" : "false"); + break; + + default: + sc_trace("%p [invalid type]", vt_value.voidp); + break; + } + sc_trace(", key \"%s\" : ", format); + for (index_ = 0; format[index_ + 3] != NUL; index_++) { + sc_trace("%s", index_ > 0 ? "," : ""); + switch (format[index_ + 3]) { + case PROP_KEY_STRING: + sc_trace("\"%s\"", vt_key[index_].string); + break; + case PROP_KEY_INTEGER: + sc_trace("%ld", vt_key[index_].integer); + break; + + default: + sc_trace("%p [invalid type]", vt_key[index_].voidp); + break; + } + } + sc_trace("\n"); + } + + /* + * Iterate keys, finding matching child nodes at each level. If no matching + * child is found, insert one and continue. + */ + node = bundle->root_node; + for (index_ = 0; format[index_ + 3] != NUL; index_++) { + sc_prop_noderef_t child; + sc_int type; + + /* + * Search this level for a name matching the key. If found, advance + * to that child node. Otherwise, add the node to the tree, including + * the set so that the dictionary can be extended. + */ + type = format[index_ + 3]; + child = prop_find_child(node, type, vt_key[index_]); + if (child) + node = child; + else + node = prop_add_child(node, type, vt_key[index_], bundle); + } + + /* + * Ensure that we're not about to overwrite an internal node child count. + */ + if (node->child_list) + sc_fatal("prop_put: overwrite of internal node\n"); + + /* Set our properties in the final node. */ + switch (format[0]) { + case PROP_INTEGER: + node->property.integer = vt_value.integer; + break; + case PROP_BOOLEAN: + node->property.boolean = vt_value.boolean; + break; + case PROP_STRING: + node->property.string = vt_value.string; + break; + + default: + sc_fatal("prop_put: invalid property type\n"); + } } @@ -551,114 +524,105 @@ prop_put (sc_prop_setref_t bundle, const sc_char *format, * with "->" replaced with "<-". Returns FALSE if no such property exists. */ sc_bool -prop_get (sc_prop_setref_t bundle, const sc_char *format, - sc_vartype_t *vt_rvalue, const sc_vartype_t vt_key[]) -{ - sc_prop_noderef_t node; - sc_int index_; - assert (prop_is_valid (bundle)); - - /* Format check. */ - if (!format || format[0] == NUL - || format[1] != '<' || format[2] != '-' || format[3] == NUL) - sc_fatal ("prop_get: format error\n"); - - /* Trace property get. */ - if (prop_trace) - { - sc_trace ("Property: get, key \"%s\" : ", format); - for (index_ = 0; format[index_ + 3] != NUL; index_++) - { - sc_trace ("%s", index_ > 0 ? "," : ""); - switch (format[index_ + 3]) - { - case PROP_KEY_STRING: - sc_trace ("\"%s\"", vt_key[index_].string); - break; - case PROP_KEY_INTEGER: - sc_trace ("%ld", vt_key[index_].integer); - break; - - default: - sc_trace ("%p [invalid type]", vt_key[index_].voidp); - break; - } - } - sc_trace ("\n"); - } - - /* - * Iterate keys, finding matching child nodes at each level. Stop if no - * matching child is found. - */ - node = bundle->root_node; - for (index_ = 0; format[index_ + 3] != NUL; index_++) - { - sc_int type; - - /* Move node down to the matching child, NULL if no match. */ - type = format[index_ + 3 ]; - node = prop_find_child (node, type, vt_key[index_]); - if (!node) - break; - } - - /* If key iteration halted because no child was found, return FALSE. */ - if (!node) - { - if (prop_trace) - sc_trace ("Property: ...get FAILED\n"); - - return FALSE; - } - - /* - * Enforce integer-only queries on internal nodes, since this is the only - * type of query that makes sense -- any other type is probably a mistake. - */ - if (node->child_list && format[0] != PROP_INTEGER) - sc_fatal ("prop_get: only integer gets on internal nodes\n"); - - /* Return the properties of the final node. */ - switch (format[0]) - { - case PROP_INTEGER: - vt_rvalue->integer = node->property.integer; - break; - case PROP_BOOLEAN: - vt_rvalue->boolean = node->property.boolean; - break; - case PROP_STRING: - vt_rvalue->string = node->property.string; - break; - - default: - sc_fatal ("prop_get: invalid property type\n"); - } - - /* Complete tracing property get. */ - if (prop_trace) - { - sc_trace ("Property: ...get returned : "); - switch (format[0]) - { - case PROP_STRING: - sc_trace ("\"%s\"", vt_rvalue->string); - break; - case PROP_INTEGER: - sc_trace ("%ld", vt_rvalue->integer); - break; - case PROP_BOOLEAN: - sc_trace ("%s", vt_rvalue->boolean ? "true" : "false"); - break; - - default: - sc_trace ("%p [invalid type]", vt_rvalue->voidp); - break; - } - sc_trace ("\n"); - } - return TRUE; +prop_get(sc_prop_setref_t bundle, const sc_char *format, + sc_vartype_t *vt_rvalue, const sc_vartype_t vt_key[]) { + sc_prop_noderef_t node; + sc_int index_; + assert(prop_is_valid(bundle)); + + /* Format check. */ + if (!format || format[0] == NUL + || format[1] != '<' || format[2] != '-' || format[3] == NUL) + sc_fatal("prop_get: format error\n"); + + /* Trace property get. */ + if (prop_trace) { + sc_trace("Property: get, key \"%s\" : ", format); + for (index_ = 0; format[index_ + 3] != NUL; index_++) { + sc_trace("%s", index_ > 0 ? "," : ""); + switch (format[index_ + 3]) { + case PROP_KEY_STRING: + sc_trace("\"%s\"", vt_key[index_].string); + break; + case PROP_KEY_INTEGER: + sc_trace("%ld", vt_key[index_].integer); + break; + + default: + sc_trace("%p [invalid type]", vt_key[index_].voidp); + break; + } + } + sc_trace("\n"); + } + + /* + * Iterate keys, finding matching child nodes at each level. Stop if no + * matching child is found. + */ + node = bundle->root_node; + for (index_ = 0; format[index_ + 3] != NUL; index_++) { + sc_int type; + + /* Move node down to the matching child, NULL if no match. */ + type = format[index_ + 3 ]; + node = prop_find_child(node, type, vt_key[index_]); + if (!node) + break; + } + + /* If key iteration halted because no child was found, return FALSE. */ + if (!node) { + if (prop_trace) + sc_trace("Property: ...get FAILED\n"); + + return FALSE; + } + + /* + * Enforce integer-only queries on internal nodes, since this is the only + * type of query that makes sense -- any other type is probably a mistake. + */ + if (node->child_list && format[0] != PROP_INTEGER) + sc_fatal("prop_get: only integer gets on internal nodes\n"); + + /* Return the properties of the final node. */ + switch (format[0]) { + case PROP_INTEGER: + vt_rvalue->integer = node->property.integer; + break; + case PROP_BOOLEAN: + vt_rvalue->boolean = node->property.boolean; + break; + case PROP_STRING: + vt_rvalue->string = node->property.string; + break; + + default: + sc_fatal("prop_get: invalid property type\n"); + } + + /* Complete tracing property get. */ + if (prop_trace) { + sc_trace("Property: ...get returned : "); + switch (format[0]) { + case PROP_STRING: + sc_trace("\"%s\"", vt_rvalue->string); + break; + case PROP_INTEGER: + sc_trace("%ld", vt_rvalue->integer); + break; + case PROP_BOOLEAN: + sc_trace("%s", vt_rvalue->boolean ? "true" : "false"); + break; + + default: + sc_trace("%p [invalid type]", vt_rvalue->voidp); + break; + } + sc_trace("\n"); + } + return TRUE; } @@ -670,49 +634,46 @@ prop_get (sc_prop_setref_t bundle, const sc_char *format, * so that no further property insertions are allowed. */ static void -prop_trim_node (sc_prop_noderef_t node) -{ - /* End recursion on null or childless node. */ - if (node && node->child_list) - { - sc_int index_; - - /* Recursively trim allocation on children. */ - for (index_ = 0; index_ < node->property.integer; index_++) - prop_trim_node (node->child_list[index_]); - - /* Trim allocation on this node. */ - node->child_list = (sc_prop_noderef_t *)prop_trim_capacity (node->child_list, - node->property.integer, - sizeof (*node->child_list)); - } +prop_trim_node(sc_prop_noderef_t node) { + /* End recursion on null or childless node. */ + if (node && node->child_list) { + sc_int index_; + + /* Recursively trim allocation on children. */ + for (index_ = 0; index_ < node->property.integer; index_++) + prop_trim_node(node->child_list[index_]); + + /* Trim allocation on this node. */ + node->child_list = (sc_prop_noderef_t *)prop_trim_capacity(node->child_list, + node->property.integer, + sizeof(*node->child_list)); + } } void -prop_solidify (sc_prop_setref_t bundle) -{ - assert (prop_is_valid (bundle)); - - /* - * Trim back the dictionary, orphans, pools array, and every internal tree - * node. The one thing _not_ to trim is the final node pool -- there are - * references to nodes within it strewn all over the properties tree, and - * it's a large job to try to find and update them; instead, we just live - * with a little wasted heap memory. - */ - bundle->dictionary = (sc_char **)prop_trim_capacity (bundle->dictionary, - bundle->dictionary_length, - sizeof (bundle->dictionary[0])); - bundle->node_pools = (sc_prop_noderef_t *)prop_trim_capacity (bundle->node_pools, - bundle->node_pools_length, - sizeof (bundle->node_pools[0])); - bundle->orphans = (void **)prop_trim_capacity (bundle->orphans, - bundle->orphans_length, - sizeof (bundle->orphans[0])); - prop_trim_node (bundle->root_node); - - /* Set the bundle so that no more properties can be added. */ - bundle->is_readonly = TRUE; +prop_solidify(sc_prop_setref_t bundle) { + assert(prop_is_valid(bundle)); + + /* + * Trim back the dictionary, orphans, pools array, and every internal tree + * node. The one thing _not_ to trim is the final node pool -- there are + * references to nodes within it strewn all over the properties tree, and + * it's a large job to try to find and update them; instead, we just live + * with a little wasted heap memory. + */ + bundle->dictionary = (sc_char **)prop_trim_capacity(bundle->dictionary, + bundle->dictionary_length, + sizeof(bundle->dictionary[0])); + bundle->node_pools = (sc_prop_noderef_t *)prop_trim_capacity(bundle->node_pools, + bundle->node_pools_length, + sizeof(bundle->node_pools[0])); + bundle->orphans = (void **)prop_trim_capacity(bundle->orphans, + bundle->orphans_length, + sizeof(bundle->orphans[0])); + prop_trim_node(bundle->root_node); + + /* Set the bundle so that no more properties can be added. */ + bundle->is_readonly = TRUE; } @@ -725,42 +686,39 @@ prop_solidify (sc_prop_setref_t bundle) * It is an error for the property not to exist on retrieval. */ sc_int -prop_get_integer (sc_prop_setref_t bundle, - const sc_char *format, const sc_vartype_t vt_key[]) -{ - sc_vartype_t vt_rvalue; - assert (format[0] == PROP_INTEGER); +prop_get_integer(sc_prop_setref_t bundle, + const sc_char *format, const sc_vartype_t vt_key[]) { + sc_vartype_t vt_rvalue; + assert(format[0] == PROP_INTEGER); - if (!prop_get (bundle, format, &vt_rvalue, vt_key)) - sc_fatal ("prop_get_integer: can't retrieve property\n"); + if (!prop_get(bundle, format, &vt_rvalue, vt_key)) + sc_fatal("prop_get_integer: can't retrieve property\n"); - return vt_rvalue.integer; + return vt_rvalue.integer; } sc_bool -prop_get_boolean (sc_prop_setref_t bundle, - const sc_char *format, const sc_vartype_t vt_key[]) -{ - sc_vartype_t vt_rvalue; - assert (format[0] == PROP_BOOLEAN); +prop_get_boolean(sc_prop_setref_t bundle, + const sc_char *format, const sc_vartype_t vt_key[]) { + sc_vartype_t vt_rvalue; + assert(format[0] == PROP_BOOLEAN); - if (!prop_get (bundle, format, &vt_rvalue, vt_key)) - sc_fatal ("prop_get_boolean: can't retrieve property\n"); + if (!prop_get(bundle, format, &vt_rvalue, vt_key)) + sc_fatal("prop_get_boolean: can't retrieve property\n"); - return vt_rvalue.boolean; + return vt_rvalue.boolean; } const sc_char * -prop_get_string (sc_prop_setref_t bundle, - const sc_char *format, const sc_vartype_t vt_key[]) -{ - sc_vartype_t vt_rvalue; - assert (format[0] == PROP_STRING); +prop_get_string(sc_prop_setref_t bundle, + const sc_char *format, const sc_vartype_t vt_key[]) { + sc_vartype_t vt_rvalue; + assert(format[0] == PROP_STRING); - if (!prop_get (bundle, format, &vt_rvalue, vt_key)) - sc_fatal ("prop_get_string: can't retrieve property\n"); + if (!prop_get(bundle, format, &vt_rvalue, vt_key)) + sc_fatal("prop_get_string: can't retrieve property\n"); - return vt_rvalue.string; + return vt_rvalue.string; } @@ -771,17 +729,16 @@ prop_get_string (sc_prop_setref_t bundle, * for a given property. Returns zero if the property does not exist. */ sc_int -prop_get_child_count (sc_prop_setref_t bundle, - const sc_char *format, const sc_vartype_t vt_key[]) -{ - sc_vartype_t vt_rvalue; - assert (format[0] == PROP_INTEGER); +prop_get_child_count(sc_prop_setref_t bundle, + const sc_char *format, const sc_vartype_t vt_key[]) { + sc_vartype_t vt_rvalue; + assert(format[0] == PROP_INTEGER); - if (!prop_get (bundle, format, &vt_rvalue, vt_key)) - return 0; + if (!prop_get(bundle, format, &vt_rvalue, vt_key)) + return 0; - /* Return overloaded integer property value, the child count. */ - return vt_rvalue.integer; + /* Return overloaded integer property value, the child count. */ + return vt_rvalue.integer; } @@ -792,41 +749,41 @@ prop_get_child_count (sc_prop_setref_t bundle, */ static sc_prop_setref_t prop_create_empty() { - sc_prop_setref_t bundle; + sc_prop_setref_t bundle; - /* Create a new, empty set. */ - bundle = (sc_prop_setref_t)sc_malloc(sizeof (*bundle)); - bundle->magic = PROP_MAGIC; + /* Create a new, empty set. */ + bundle = (sc_prop_setref_t)sc_malloc(sizeof(*bundle)); + bundle->magic = PROP_MAGIC; - /* Begin with an empty strings dictionary. */ - bundle->dictionary_length = 0; - bundle->dictionary = NULL; + /* Begin with an empty strings dictionary. */ + bundle->dictionary_length = 0; + bundle->dictionary = NULL; - /* Begin with no allocated node pools. */ - bundle->node_pools_length = 0; - bundle->node_pools = NULL; - bundle->node_count = 0; + /* Begin with no allocated node pools. */ + bundle->node_pools_length = 0; + bundle->node_pools = NULL; + bundle->node_count = 0; - /* Begin with no adopted addresses. */ - bundle->orphans_length = 0; - bundle->orphans = NULL; + /* Begin with no adopted addresses. */ + bundle->orphans_length = 0; + bundle->orphans = NULL; - /* Leave open for insertions. */ - bundle->is_readonly = FALSE; + /* Leave open for insertions. */ + bundle->is_readonly = FALSE; - /* - * Start the set off with a root node. This will also kick off node pools, - * ensuring that every set has at least one node and one allocated pool. - */ - bundle->root_node = prop_new_node (bundle); - bundle->root_node->child_list = NULL; - bundle->root_node->name.string = "ROOT"; - bundle->root_node->property.voidp = NULL; + /* + * Start the set off with a root node. This will also kick off node pools, + * ensuring that every set has at least one node and one allocated pool. + */ + bundle->root_node = prop_new_node(bundle); + bundle->root_node->child_list = NULL; + bundle->root_node->name.string = "ROOT"; + bundle->root_node->property.voidp = NULL; - /* No taf is yet connected with this set. */ - bundle->taf = NULL; + /* No taf is yet connected with this set. */ + bundle->taf = NULL; - return bundle; + return bundle; } @@ -837,60 +794,57 @@ prop_create_empty() { * Free set memory, and destroy a properties set structure. */ static void -prop_destroy_child_list (sc_prop_noderef_t node) -{ - /* End recursion on null or childless node. */ - if (node && node->child_list) - { - sc_int index_; - - /* Recursively destroy the children's child lists. */ - for (index_ = 0; index_ < node->property.integer; index_++) - prop_destroy_child_list (node->child_list[index_]); - - /* Free our own child list. */ - sc_free (node->child_list); - } +prop_destroy_child_list(sc_prop_noderef_t node) { + /* End recursion on null or childless node. */ + if (node && node->child_list) { + sc_int index_; + + /* Recursively destroy the children's child lists. */ + for (index_ = 0; index_ < node->property.integer; index_++) + prop_destroy_child_list(node->child_list[index_]); + + /* Free our own child list. */ + sc_free(node->child_list); + } } void -prop_destroy (sc_prop_setref_t bundle) -{ - sc_int index_; - assert (prop_is_valid (bundle)); - - /* Destroy the dictionary, and free it. */ - for (index_ = 0; index_ < bundle->dictionary_length; index_++) - sc_free (bundle->dictionary[index_]); - bundle->dictionary_length = 0; - sc_free (bundle->dictionary); - bundle->dictionary = NULL; - - /* Free adopted addresses. */ - for (index_ = 0; index_ < bundle->orphans_length; index_++) - sc_free (bundle->orphans[index_]); - bundle->orphans_length = 0; - sc_free (bundle->orphans); - bundle->orphans = NULL; - - /* Walk the tree, destroying the child list for each node found. */ - prop_destroy_child_list (bundle->root_node); - bundle->root_node = NULL; - - /* Destroy each node pool. */ - for (index_ = 0; index_ < bundle->node_pools_length; index_++) - sc_free (bundle->node_pools[index_]); - bundle->node_pools_length = 0; - sc_free (bundle->node_pools); - bundle->node_pools = NULL; - - /* Destroy any taf associated with the bundle. */ - if (bundle->taf) - taf_destroy (bundle->taf); - - /* Poison and free the bundle. */ - memset (bundle, 0xaa, sizeof (*bundle)); - sc_free (bundle); +prop_destroy(sc_prop_setref_t bundle) { + sc_int index_; + assert(prop_is_valid(bundle)); + + /* Destroy the dictionary, and free it. */ + for (index_ = 0; index_ < bundle->dictionary_length; index_++) + sc_free(bundle->dictionary[index_]); + bundle->dictionary_length = 0; + sc_free(bundle->dictionary); + bundle->dictionary = NULL; + + /* Free adopted addresses. */ + for (index_ = 0; index_ < bundle->orphans_length; index_++) + sc_free(bundle->orphans[index_]); + bundle->orphans_length = 0; + sc_free(bundle->orphans); + bundle->orphans = NULL; + + /* Walk the tree, destroying the child list for each node found. */ + prop_destroy_child_list(bundle->root_node); + bundle->root_node = NULL; + + /* Destroy each node pool. */ + for (index_ = 0; index_ < bundle->node_pools_length; index_++) + sc_free(bundle->node_pools[index_]); + bundle->node_pools_length = 0; + sc_free(bundle->node_pools); + bundle->node_pools = NULL; + + /* Destroy any taf associated with the bundle. */ + if (bundle->taf) + taf_destroy(bundle->taf); + + /* Poison and free the bundle. */ + memset(bundle, 0xaa, sizeof(*bundle)); + sc_free(bundle); } @@ -900,23 +854,21 @@ prop_destroy (sc_prop_setref_t bundle) * Create a new properties set based on a taf, and return it. */ sc_prop_setref_t -prop_create (const sc_tafref_t taf) -{ - sc_prop_setref_t bundle; - - /* Create a new, empty set. */ - bundle = prop_create_empty (); - - /* Populate it with data parsed from the taf file. */ - if (!parse_game (taf, bundle)) - { - prop_destroy (bundle); - return NULL; - } - - /* Note the taf for destruction later, and return the new set. */ - bundle->taf = taf; - return bundle; +prop_create(const sc_tafref_t taf) { + sc_prop_setref_t bundle; + + /* Create a new, empty set. */ + bundle = prop_create_empty(); + + /* Populate it with data parsed from the taf file. */ + if (!parse_game(taf, bundle)) { + prop_destroy(bundle); + return NULL; + } + + /* Note the taf for destruction later, and return the new set. */ + bundle->taf = taf; + return bundle; } @@ -926,18 +878,17 @@ prop_create (const sc_tafref_t taf) * Adopt a memory address for free'ing on destroy. */ void -prop_adopt (sc_prop_setref_t bundle, void *addr) -{ - assert (prop_is_valid (bundle)); - - /* Extend the orphans array if necessary. */ - bundle->orphans = (void **)prop_ensure_capacity (bundle->orphans, - bundle->orphans_length, - bundle->orphans_length + 1, - sizeof (bundle->orphans[0])); - - /* Add the new address to the end of the array. */ - bundle->orphans[bundle->orphans_length++] = addr; +prop_adopt(sc_prop_setref_t bundle, void *addr) { + assert(prop_is_valid(bundle)); + + /* Extend the orphans array if necessary. */ + bundle->orphans = (void **)prop_ensure_capacity(bundle->orphans, + bundle->orphans_length, + bundle->orphans_length + 1, + sizeof(bundle->orphans[0])); + + /* Add the new address to the end of the array. */ + bundle->orphans[bundle->orphans_length++] = addr; } @@ -949,98 +900,86 @@ prop_adopt (sc_prop_setref_t bundle, void *addr) * Print out a complete properties set. */ static sc_bool -prop_debug_is_dictionary_string (sc_prop_setref_t bundle, const void *pointer) -{ - const sc_char *const pointer_ = (const sc_char *const )pointer; - sc_int index_; - - /* Compare by pointer directly, not by string value comparisons. */ - for (index_ = 0; index_ < bundle->dictionary_length; index_++) - { - if (bundle->dictionary[index_] == pointer_) - return TRUE; - } - - return FALSE; +prop_debug_is_dictionary_string(sc_prop_setref_t bundle, const void *pointer) { + const sc_char *const pointer_ = (const sc_char * const)pointer; + sc_int index_; + + /* Compare by pointer directly, not by string value comparisons. */ + for (index_ = 0; index_ < bundle->dictionary_length; index_++) { + if (bundle->dictionary[index_] == pointer_) + return TRUE; + } + + return FALSE; } static void -prop_debug_dump_node (sc_prop_setref_t bundle, - sc_int depth, sc_int child_index, sc_prop_noderef_t node) -{ - sc_int index_; - - /* Write node preamble, indented two spaces for each depth count. */ - for (index_ = 0; index_ < depth; index_++) - sc_trace (" "); - sc_trace ("%ld : %p", child_index, (void *) node); - - /* Write node, or just a newline if none. */ - if (node) - { - /* Print out the node's key, as hex and either string or decimal. */ - sc_trace (", name %p", node->name.voidp); - if (node != bundle->root_node) - { - if (prop_debug_is_dictionary_string (bundle, node->name.string)) - sc_trace (" \"%s\"", node->name.string); - else - sc_trace (" %ld", node->name.integer); - } - - if (node->child_list) - { - /* Recursively dump children. */ - sc_trace (", child count %ld\n", node->property.integer); - for (index_ = 0; index_ < node->property.integer; index_++) - { - prop_debug_dump_node (bundle, depth + 1, - index_, node->child_list[index_]); - } - } - else - { - /* Print out the node's property, again hex and string or decimal. */ - sc_trace (", property %p", node->property.voidp); - if (taf_debug_is_taf_string (bundle->taf, node->property.string)) - sc_trace (" \"%s\"\n", node->property.string); - else - sc_trace (" %ld\n", node->property.integer); - } - } - else - sc_trace ("\n"); +prop_debug_dump_node(sc_prop_setref_t bundle, + sc_int depth, sc_int child_index, sc_prop_noderef_t node) { + sc_int index_; + + /* Write node preamble, indented two spaces for each depth count. */ + for (index_ = 0; index_ < depth; index_++) + sc_trace(" "); + sc_trace("%ld : %p", child_index, (void *) node); + + /* Write node, or just a newline if none. */ + if (node) { + /* Print out the node's key, as hex and either string or decimal. */ + sc_trace(", name %p", node->name.voidp); + if (node != bundle->root_node) { + if (prop_debug_is_dictionary_string(bundle, node->name.string)) + sc_trace(" \"%s\"", node->name.string); + else + sc_trace(" %ld", node->name.integer); + } + + if (node->child_list) { + /* Recursively dump children. */ + sc_trace(", child count %ld\n", node->property.integer); + for (index_ = 0; index_ < node->property.integer; index_++) { + prop_debug_dump_node(bundle, depth + 1, + index_, node->child_list[index_]); + } + } else { + /* Print out the node's property, again hex and string or decimal. */ + sc_trace(", property %p", node->property.voidp); + if (taf_debug_is_taf_string(bundle->taf, node->property.string)) + sc_trace(" \"%s\"\n", node->property.string); + else + sc_trace(" %ld\n", node->property.integer); + } + } else + sc_trace("\n"); } void -prop_debug_dump (sc_prop_setref_t bundle) -{ - sc_int index_; - assert (prop_is_valid (bundle)); - - /* Dump complete structure. */ - sc_trace ("Property: debug dump follows...\n"); - sc_trace ("bundle->is_readonly = %s\n", - bundle->is_readonly ? "true" : "false"); - sc_trace ("bundle->dictionary_length = %ld\n", bundle->dictionary_length); - - sc_trace ("bundle->dictionary =\n"); - for (index_ = 0; index_ < bundle->dictionary_length; index_++) - { - sc_trace ("%3ld : %p \"%s\"\n", index_, - bundle->dictionary[index_], bundle->dictionary[index_]); - } - - sc_trace ("bundle->node_pools_length = %ld\n", bundle->node_pools_length); - - sc_trace ("bundle->node_pools =\n"); - for (index_ = 0; index_ < bundle->node_pools_length; index_++) - sc_trace ("%3ld : %p\n", index_, (void *) bundle->node_pools[index_]); - - sc_trace ("bundle->node_count = %ld\n", bundle->node_count); - sc_trace ("bundle->root_node = {\n"); - prop_debug_dump_node (bundle, 0, 0, bundle->root_node); - sc_trace ("}\nbundle->taf = %p\n", (void *) bundle->taf); +prop_debug_dump(sc_prop_setref_t bundle) { + sc_int index_; + assert(prop_is_valid(bundle)); + + /* Dump complete structure. */ + sc_trace("Property: debug dump follows...\n"); + sc_trace("bundle->is_readonly = %s\n", + bundle->is_readonly ? "true" : "false"); + sc_trace("bundle->dictionary_length = %ld\n", bundle->dictionary_length); + + sc_trace("bundle->dictionary =\n"); + for (index_ = 0; index_ < bundle->dictionary_length; index_++) { + sc_trace("%3ld : %p \"%s\"\n", index_, + bundle->dictionary[index_], bundle->dictionary[index_]); + } + + sc_trace("bundle->node_pools_length = %ld\n", bundle->node_pools_length); + + sc_trace("bundle->node_pools =\n"); + for (index_ = 0; index_ < bundle->node_pools_length; index_++) + sc_trace("%3ld : %p\n", index_, (void *) bundle->node_pools[index_]); + + sc_trace("bundle->node_count = %ld\n", bundle->node_count); + sc_trace("bundle->root_node = {\n"); + prop_debug_dump_node(bundle, 0, 0, bundle->root_node); + sc_trace("}\nbundle->taf = %p\n", (void *) bundle->taf); } @@ -1050,9 +989,8 @@ prop_debug_dump (sc_prop_setref_t bundle) * Set property tracing on/off. */ void -prop_debug_trace (sc_bool flag) -{ - prop_trace = flag; +prop_debug_trace(sc_bool flag) { + prop_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scprotos.h b/engines/glk/adrift/scprotos.h index 549a0144fe..24103b93f8 100644 --- a/engines/glk/adrift/scprotos.h +++ b/engines/glk/adrift/scprotos.h @@ -48,18 +48,17 @@ namespace Adrift { #endif /* Vartype typedef, supports relaxed typing. */ -typedef union -{ - sc_int integer; - sc_bool boolean; - const sc_char *string; - sc_char *mutable_string; - void *voidp; +typedef union { + sc_int integer; + sc_bool boolean; + const sc_char *string; + sc_char *mutable_string; + void *voidp; } sc_vartype_t; /* Standard reader and writer callback function typedefs. */ -typedef sc_int (*sc_read_callbackref_t) (void *, sc_byte *, sc_int); -typedef void (*sc_write_callbackref_t) (void *, const sc_byte *, sc_int); +typedef sc_int(*sc_read_callbackref_t)(void *, sc_byte *, sc_int); +typedef void (*sc_write_callbackref_t)(void *, const sc_byte *, sc_int); /* * Small utility and wrapper functions. For printf wrappers, try to apply @@ -67,102 +66,102 @@ typedef void (*sc_write_callbackref_t) (void *, const sc_byte *, sc_int); * checks. */ #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) -extern void sc_trace (const sc_char *format, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); -extern void sc_error (const sc_char *format, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); -extern void sc_fatal (const sc_char *format, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); +extern void sc_trace(const sc_char *format, ...) +__attribute__((__format__(__printf__, 1, 2))); +extern void sc_error(const sc_char *format, ...) +__attribute__((__format__(__printf__, 1, 2))); +extern void sc_fatal(const sc_char *format, ...) +__attribute__((__format__(__printf__, 1, 2))); #else -extern void sc_trace (const sc_char *format, ...); -extern void sc_error (const sc_char *format, ...); -extern void sc_fatal (const sc_char *format, ...); +extern void sc_trace(const sc_char *format, ...); +extern void sc_error(const sc_char *format, ...); +extern void sc_fatal(const sc_char *format, ...); #endif -extern void *sc_malloc (size_t size); -extern void *sc_realloc (void *pointer, size_t size); -extern void sc_free (void *pointer); -extern void sc_set_congruential_random (void); -extern void sc_set_platform_random (void); -extern sc_bool sc_is_congruential_random (void); -extern void sc_seed_random (sc_uint new_seed); -extern sc_int sc_rand (void); -extern sc_int sc_randomint (sc_int low, sc_int high); -extern sc_bool sc_strempty (const sc_char *string); -extern sc_char *sc_trim_string (sc_char *string); -extern sc_char *sc_normalize_string (sc_char *string); -extern sc_bool sc_compare_word (const sc_char *string, - const sc_char *word, sc_int length); -extern sc_uint sc_hash (const sc_char *string); +extern void *sc_malloc(size_t size); +extern void *sc_realloc(void *pointer, size_t size); +extern void sc_free(void *pointer); +extern void sc_set_congruential_random(void); +extern void sc_set_platform_random(void); +extern sc_bool sc_is_congruential_random(void); +extern void sc_seed_random(sc_uint new_seed); +extern sc_int sc_rand(void); +extern sc_int sc_randomint(sc_int low, sc_int high); +extern sc_bool sc_strempty(const sc_char *string); +extern sc_char *sc_trim_string(sc_char *string); +extern sc_char *sc_normalize_string(sc_char *string); +extern sc_bool sc_compare_word(const sc_char *string, + const sc_char *word, sc_int length); +extern sc_uint sc_hash(const sc_char *string); /* TAF file reader/decompressor enumerations, opaque typedef and functions. */ -enum -{ TAF_VERSION_NONE = 0, - TAF_VERSION_400 = 400, - TAF_VERSION_390 = 390, - TAF_VERSION_380 = 380 +enum { + TAF_VERSION_NONE = 0, + TAF_VERSION_400 = 400, + TAF_VERSION_390 = 390, + TAF_VERSION_380 = 380 }; typedef struct sc_taf_s *sc_tafref_t; -extern void taf_destroy (sc_tafref_t taf); -extern sc_tafref_t taf_create (sc_read_callbackref_t callback, void *opaque); -extern sc_tafref_t taf_create_tas (sc_read_callbackref_t callback, - void *opaque); -extern void taf_first_line (sc_tafref_t taf); -extern const sc_char *taf_next_line (sc_tafref_t taf); -extern sc_bool taf_more_lines (sc_tafref_t taf); -extern sc_int taf_get_game_data_length (sc_tafref_t taf); -extern sc_int taf_get_version (sc_tafref_t taf); -extern sc_bool taf_debug_is_taf_string (sc_tafref_t taf, const void *addr); -extern void taf_debug_dump (sc_tafref_t taf); +extern void taf_destroy(sc_tafref_t taf); +extern sc_tafref_t taf_create(sc_read_callbackref_t callback, void *opaque); +extern sc_tafref_t taf_create_tas(sc_read_callbackref_t callback, + void *opaque); +extern void taf_first_line(sc_tafref_t taf); +extern const sc_char *taf_next_line(sc_tafref_t taf); +extern sc_bool taf_more_lines(sc_tafref_t taf); +extern sc_int taf_get_game_data_length(sc_tafref_t taf); +extern sc_int taf_get_version(sc_tafref_t taf); +extern sc_bool taf_debug_is_taf_string(sc_tafref_t taf, const void *addr); +extern void taf_debug_dump(sc_tafref_t taf); /* Properties store enumerations, opaque typedef, and functions. */ -enum -{ PROP_KEY_STRING = 's', - PROP_KEY_INTEGER = 'i' +enum { + PROP_KEY_STRING = 's', + PROP_KEY_INTEGER = 'i' }; -enum -{ PROP_INTEGER = 'I', - PROP_BOOLEAN = 'B', - PROP_STRING = 'S' +enum { + PROP_INTEGER = 'I', + PROP_BOOLEAN = 'B', + PROP_STRING = 'S' }; typedef struct sc_prop_set_s *sc_prop_setref_t; -extern sc_prop_setref_t prop_create (const sc_tafref_t taf); -extern void prop_destroy (sc_prop_setref_t bundle); -extern void prop_put (sc_prop_setref_t bundle, - const sc_char *format, sc_vartype_t vt_value, - const sc_vartype_t vt_key[]); -extern sc_bool prop_get (sc_prop_setref_t bundle, - const sc_char *format, sc_vartype_t *vt_value, - const sc_vartype_t vt_key[]); -extern void prop_solidify (sc_prop_setref_t bundle); -extern sc_int prop_get_integer (sc_prop_setref_t bundle, +extern sc_prop_setref_t prop_create(const sc_tafref_t taf); +extern void prop_destroy(sc_prop_setref_t bundle); +extern void prop_put(sc_prop_setref_t bundle, + const sc_char *format, sc_vartype_t vt_value, + const sc_vartype_t vt_key[]); +extern sc_bool prop_get(sc_prop_setref_t bundle, + const sc_char *format, sc_vartype_t *vt_value, + const sc_vartype_t vt_key[]); +extern void prop_solidify(sc_prop_setref_t bundle); +extern sc_int prop_get_integer(sc_prop_setref_t bundle, + const sc_char *format, + const sc_vartype_t vt_key[]); +extern sc_bool prop_get_boolean(sc_prop_setref_t bundle, const sc_char *format, const sc_vartype_t vt_key[]); -extern sc_bool prop_get_boolean (sc_prop_setref_t bundle, - const sc_char *format, - const sc_vartype_t vt_key[]); -extern const sc_char *prop_get_string (sc_prop_setref_t bundle, - const sc_char *format, - const sc_vartype_t vt_key[]); -extern sc_int prop_get_child_count (sc_prop_setref_t bundle, - const sc_char *format, - const sc_vartype_t vt_key[]); -extern void prop_adopt (sc_prop_setref_t bundle, void *addr); -extern void prop_debug_trace (sc_bool flag); -extern void prop_debug_dump (sc_prop_setref_t bundle); +extern const sc_char *prop_get_string(sc_prop_setref_t bundle, + const sc_char *format, + const sc_vartype_t vt_key[]); +extern sc_int prop_get_child_count(sc_prop_setref_t bundle, + const sc_char *format, + const sc_vartype_t vt_key[]); +extern void prop_adopt(sc_prop_setref_t bundle, void *addr); +extern void prop_debug_trace(sc_bool flag); +extern void prop_debug_dump(sc_prop_setref_t bundle); /* Game parser enumeration and functions. */ -enum -{ ROOMLIST_NO_ROOMS = 0, - ROOMLIST_ONE_ROOM = 1, - ROOMLIST_SOME_ROOMS = 2, - ROOMLIST_ALL_ROOMS = 3, - ROOMLIST_NPC_PART = 4 +enum { + ROOMLIST_NO_ROOMS = 0, + ROOMLIST_ONE_ROOM = 1, + ROOMLIST_SOME_ROOMS = 2, + ROOMLIST_ALL_ROOMS = 3, + ROOMLIST_NPC_PART = 4 }; -extern sc_bool parse_game (sc_tafref_t taf, sc_prop_setref_t bundle); -extern void parse_debug_trace (sc_bool flag); +extern sc_bool parse_game(sc_tafref_t taf, sc_prop_setref_t bundle); +extern void parse_debug_trace(sc_bool flag); /* Game state structure for modules that use it. */ typedef struct sc_game_s *sc_gameref_t; @@ -171,627 +170,627 @@ typedef struct sc_game_s *sc_gameref_t; typedef struct sc_taskstate_s *sc_hintref_t; /* Variables set enumerations, opaque typedef, and functions. */ -enum -{ TAFVAR_NUMERIC = 0, - TAFVAR_STRING = 1 +enum { + TAFVAR_NUMERIC = 0, + TAFVAR_STRING = 1 }; -enum -{ VAR_INTEGER = 'I', - VAR_STRING = 'S' +enum { + VAR_INTEGER = 'I', + VAR_STRING = 'S' }; typedef struct sc_var_set_s *sc_var_setref_t; -extern void var_put (sc_var_setref_t vars, - const sc_char *name, sc_int type, sc_vartype_t vt_value); -extern sc_bool var_get (sc_var_setref_t vars, - const sc_char *name, sc_int *type, - sc_vartype_t *vt_rvalue); -extern void var_put_integer (sc_var_setref_t vars, - const sc_char *name, sc_int value); -extern sc_int var_get_integer (sc_var_setref_t vars, const sc_char *name); -extern void var_put_string (sc_var_setref_t vars, - const sc_char *name, const sc_char *string); -extern const sc_char *var_get_string (sc_var_setref_t vars, - const sc_char *name); -extern sc_var_setref_t var_create (sc_prop_setref_t bundle); -extern void var_destroy (sc_var_setref_t vars); -extern void var_register_game (sc_var_setref_t vars, sc_gameref_t game); -extern void var_set_ref_character (sc_var_setref_t vars, sc_int character); -extern void var_set_ref_object (sc_var_setref_t vars, sc_int object); -extern void var_set_ref_number (sc_var_setref_t vars, sc_int number); -extern void var_set_ref_text (sc_var_setref_t vars, const sc_char *text); -extern sc_int var_get_ref_character (sc_var_setref_t vars); -extern sc_int var_get_ref_object (sc_var_setref_t vars); -extern sc_int var_get_ref_number (sc_var_setref_t vars); -extern const sc_char *var_get_ref_text (sc_var_setref_t vars); -extern sc_uint var_get_elapsed_seconds (sc_var_setref_t vars); -extern void var_set_elapsed_seconds (sc_var_setref_t vars, sc_uint seconds); -extern void var_debug_trace (sc_bool flag); -extern void var_debug_dump (sc_var_setref_t vars); +extern void var_put(sc_var_setref_t vars, + const sc_char *name, sc_int type, sc_vartype_t vt_value); +extern sc_bool var_get(sc_var_setref_t vars, + const sc_char *name, sc_int *type, + sc_vartype_t *vt_rvalue); +extern void var_put_integer(sc_var_setref_t vars, + const sc_char *name, sc_int value); +extern sc_int var_get_integer(sc_var_setref_t vars, const sc_char *name); +extern void var_put_string(sc_var_setref_t vars, + const sc_char *name, const sc_char *string); +extern const sc_char *var_get_string(sc_var_setref_t vars, + const sc_char *name); +extern sc_var_setref_t var_create(sc_prop_setref_t bundle); +extern void var_destroy(sc_var_setref_t vars); +extern void var_register_game(sc_var_setref_t vars, sc_gameref_t game); +extern void var_set_ref_character(sc_var_setref_t vars, sc_int character); +extern void var_set_ref_object(sc_var_setref_t vars, sc_int object); +extern void var_set_ref_number(sc_var_setref_t vars, sc_int number); +extern void var_set_ref_text(sc_var_setref_t vars, const sc_char *text); +extern sc_int var_get_ref_character(sc_var_setref_t vars); +extern sc_int var_get_ref_object(sc_var_setref_t vars); +extern sc_int var_get_ref_number(sc_var_setref_t vars); +extern const sc_char *var_get_ref_text(sc_var_setref_t vars); +extern sc_uint var_get_elapsed_seconds(sc_var_setref_t vars); +extern void var_set_elapsed_seconds(sc_var_setref_t vars, sc_uint seconds); +extern void var_debug_trace(sc_bool flag); +extern void var_debug_dump(sc_var_setref_t vars); /* Expression evaluation functions. */ -extern sc_bool expr_eval_numeric_expression (const sc_char *expression, - sc_var_setref_t vars, - sc_int *rvalue); -extern sc_bool expr_eval_string_expression (const sc_char *expression, - sc_var_setref_t vars, - sc_char **rvalue); +extern sc_bool expr_eval_numeric_expression(const sc_char *expression, + sc_var_setref_t vars, + sc_int *rvalue); +extern sc_bool expr_eval_string_expression(const sc_char *expression, + sc_var_setref_t vars, + sc_char **rvalue); /* Print filtering opaque typedef and functions. */ typedef struct sc_filter_s *sc_filterref_t; -extern sc_filterref_t pf_create (void); -extern void pf_destroy (sc_filterref_t filter); -extern void pf_buffer_string (sc_filterref_t filter, +extern sc_filterref_t pf_create(void); +extern void pf_destroy(sc_filterref_t filter); +extern void pf_buffer_string(sc_filterref_t filter, + const sc_char *string); +extern void pf_buffer_character(sc_filterref_t filter, + sc_char character); +extern void pf_prepend_string(sc_filterref_t filter, const sc_char *string); -extern void pf_buffer_character (sc_filterref_t filter, - sc_char character); -extern void pf_prepend_string (sc_filterref_t filter, - const sc_char *string); -extern void pf_new_sentence (sc_filterref_t filter); -extern void pf_mute (sc_filterref_t filter); -extern void pf_clear_mute (sc_filterref_t filter); -extern void pf_buffer_tag (sc_filterref_t filter, sc_int tag); -extern void pf_strip_tags (sc_char *string); -extern void pf_strip_tags_for_hints (sc_char *string); -extern sc_char *pf_filter (const sc_char *string, - sc_var_setref_t vars, sc_prop_setref_t bundle); -extern sc_char *pf_filter_for_info (const sc_char *string, - sc_var_setref_t vars); -extern void pf_flush (sc_filterref_t filter, - sc_var_setref_t vars, sc_prop_setref_t bundle); -extern void pf_checkpoint (sc_filterref_t filter, - sc_var_setref_t vars, sc_prop_setref_t bundle); -extern const sc_char *pf_get_buffer (sc_filterref_t filter); -extern sc_char *pf_transfer_buffer (sc_filterref_t filter); -extern void pf_empty (sc_filterref_t filter); -extern sc_char *pf_escape (const sc_char *string); -extern sc_char *pf_filter_input (const sc_char *string, - sc_prop_setref_t bundle); -extern void pf_debug_trace (sc_bool flag); +extern void pf_new_sentence(sc_filterref_t filter); +extern void pf_mute(sc_filterref_t filter); +extern void pf_clear_mute(sc_filterref_t filter); +extern void pf_buffer_tag(sc_filterref_t filter, sc_int tag); +extern void pf_strip_tags(sc_char *string); +extern void pf_strip_tags_for_hints(sc_char *string); +extern sc_char *pf_filter(const sc_char *string, + sc_var_setref_t vars, sc_prop_setref_t bundle); +extern sc_char *pf_filter_for_info(const sc_char *string, + sc_var_setref_t vars); +extern void pf_flush(sc_filterref_t filter, + sc_var_setref_t vars, sc_prop_setref_t bundle); +extern void pf_checkpoint(sc_filterref_t filter, + sc_var_setref_t vars, sc_prop_setref_t bundle); +extern const sc_char *pf_get_buffer(sc_filterref_t filter); +extern sc_char *pf_transfer_buffer(sc_filterref_t filter); +extern void pf_empty(sc_filterref_t filter); +extern sc_char *pf_escape(const sc_char *string); +extern sc_char *pf_filter_input(const sc_char *string, + sc_prop_setref_t bundle); +extern void pf_debug_trace(sc_bool flag); /* Game memo opaque typedef and functions. */ typedef struct sc_memo_set_s *sc_memo_setref_t; -extern sc_memo_setref_t memo_create (void); -extern void memo_destroy (sc_memo_setref_t memento); -extern void memo_save_game (sc_memo_setref_t memento, sc_gameref_t game); -extern sc_bool memo_load_game (sc_memo_setref_t memento, sc_gameref_t game); -extern sc_bool memo_is_load_available (sc_memo_setref_t memento); -extern void memo_clear_games (sc_memo_setref_t memento); -extern void memo_save_command (sc_memo_setref_t memento, - const sc_char *command, sc_int timestamp, - sc_int turns); -extern void memo_unsave_command (sc_memo_setref_t memento); -extern sc_int memo_get_command_count (sc_memo_setref_t memento); -extern void memo_first_command (sc_memo_setref_t memento); -extern void memo_next_command (sc_memo_setref_t memento, - const sc_char **command, sc_int *sequence, - sc_int *timestamp, sc_int *turns); -extern sc_bool memo_more_commands (sc_memo_setref_t memento); -extern const sc_char *memo_find_command (sc_memo_setref_t memento, - sc_int sequence); -extern void memo_clear_commands (sc_memo_setref_t memento); +extern sc_memo_setref_t memo_create(void); +extern void memo_destroy(sc_memo_setref_t memento); +extern void memo_save_game(sc_memo_setref_t memento, sc_gameref_t game); +extern sc_bool memo_load_game(sc_memo_setref_t memento, sc_gameref_t game); +extern sc_bool memo_is_load_available(sc_memo_setref_t memento); +extern void memo_clear_games(sc_memo_setref_t memento); +extern void memo_save_command(sc_memo_setref_t memento, + const sc_char *command, sc_int timestamp, + sc_int turns); +extern void memo_unsave_command(sc_memo_setref_t memento); +extern sc_int memo_get_command_count(sc_memo_setref_t memento); +extern void memo_first_command(sc_memo_setref_t memento); +extern void memo_next_command(sc_memo_setref_t memento, + const sc_char **command, sc_int *sequence, + sc_int *timestamp, sc_int *turns); +extern sc_bool memo_more_commands(sc_memo_setref_t memento); +extern const sc_char *memo_find_command(sc_memo_setref_t memento, + sc_int sequence); +extern void memo_clear_commands(sc_memo_setref_t memento); /* Game state functions. */ -extern sc_gameref_t gs_create (sc_var_setref_t vars, sc_prop_setref_t bundle, - sc_filterref_t filter); -extern sc_bool gs_is_game_valid (sc_gameref_t game); -extern void gs_copy (sc_gameref_t to, sc_gameref_t from); -extern void gs_destroy (sc_gameref_t game); +extern sc_gameref_t gs_create(sc_var_setref_t vars, sc_prop_setref_t bundle, + sc_filterref_t filter); +extern sc_bool gs_is_game_valid(sc_gameref_t game); +extern void gs_copy(sc_gameref_t to, sc_gameref_t from); +extern void gs_destroy(sc_gameref_t game); /* Game state accessors and mutators. */ -extern void gs_move_player_to_room (sc_gameref_t game, sc_int room); -extern sc_bool gs_player_in_room (sc_gameref_t game, sc_int room); -extern sc_var_setref_t gs_get_vars (sc_gameref_t gs); -extern sc_prop_setref_t gs_get_bundle (sc_gameref_t gs); -extern sc_filterref_t gs_get_filter (sc_gameref_t gs); -extern sc_memo_setref_t gs_get_memento (sc_gameref_t gs); -extern void gs_set_playerroom (sc_gameref_t gs, sc_int room); -extern void gs_set_playerposition (sc_gameref_t gs, sc_int position); -extern void gs_set_playerparent (sc_gameref_t gs, sc_int parent); -extern sc_int gs_playerroom (sc_gameref_t gs); -extern sc_int gs_playerposition (sc_gameref_t gs); -extern sc_int gs_playerparent (sc_gameref_t gs); -extern sc_int gs_event_count (sc_gameref_t gs); -extern void gs_set_event_state (sc_gameref_t gs, sc_int event, sc_int state); -extern void gs_set_event_time (sc_gameref_t gs, sc_int event, sc_int etime); -extern sc_int gs_event_state (sc_gameref_t gs, sc_int event); -extern sc_int gs_event_time (sc_gameref_t gs, sc_int event); -extern void gs_decrement_event_time (sc_gameref_t gs, sc_int event); -extern sc_int gs_room_count (sc_gameref_t gs); -extern void gs_set_room_seen (sc_gameref_t gs, sc_int room, sc_bool seen); -extern sc_bool gs_room_seen (sc_gameref_t gs, sc_int room); -extern sc_int gs_task_count (sc_gameref_t gs); -extern void gs_set_task_done (sc_gameref_t gs, sc_int task, sc_bool done); -extern void gs_set_task_scored (sc_gameref_t gs, sc_int task, sc_bool scored); -extern sc_bool gs_task_done (sc_gameref_t gs, sc_int task); -extern sc_bool gs_task_scored (sc_gameref_t gs, sc_int task); -extern sc_int gs_object_count (sc_gameref_t gs); -extern void gs_set_object_openness (sc_gameref_t gs, - sc_int object, sc_int openness); -extern void gs_set_object_state (sc_gameref_t gs, sc_int object, sc_int state); -extern void gs_set_object_seen (sc_gameref_t gs, sc_int object, sc_bool seen); -extern void gs_set_object_unmoved (sc_gameref_t gs, - sc_int object, sc_bool unmoved); -extern void gs_set_object_static_unmoved (sc_gameref_t gs, - sc_int object, sc_bool unmoved); -extern sc_int gs_object_openness (sc_gameref_t gs, sc_int object); -extern sc_int gs_object_state (sc_gameref_t gs, sc_int object); -extern sc_bool gs_object_seen (sc_gameref_t gs, sc_int object); -extern sc_bool gs_object_unmoved (sc_gameref_t gs, sc_int object); -extern sc_bool gs_object_static_unmoved (sc_gameref_t gs, sc_int object); -extern sc_int gs_object_position (sc_gameref_t gs, sc_int object); -extern sc_int gs_object_parent (sc_gameref_t gs, sc_int object); -extern void gs_object_move_onto (sc_gameref_t gs, sc_int object, sc_int onto); -extern void gs_object_move_into (sc_gameref_t gs, sc_int object, sc_int into); -extern void gs_object_make_hidden (sc_gameref_t gs, sc_int object); -extern void gs_object_player_get (sc_gameref_t gs, sc_int object); -extern void gs_object_npc_get (sc_gameref_t gs, sc_int object, sc_int npc); -extern void gs_object_player_wear (sc_gameref_t gs, sc_int object); -extern void gs_object_npc_wear (sc_gameref_t gs, sc_int object, sc_int npc); -extern void gs_object_to_room (sc_gameref_t gs, sc_int object, sc_int room); -extern sc_int gs_npc_count (sc_gameref_t gs); -extern void gs_set_npc_location (sc_gameref_t gs, sc_int npc, sc_int location); -extern sc_int gs_npc_location (sc_gameref_t gs, sc_int npc); -extern void gs_set_npc_position (sc_gameref_t gs, sc_int npc, sc_int position); -extern sc_int gs_npc_position (sc_gameref_t gs, sc_int npc); -extern void gs_set_npc_parent (sc_gameref_t gs, sc_int npc, sc_int parent); -extern sc_int gs_npc_parent (sc_gameref_t gs, sc_int npc); -extern void gs_set_npc_seen (sc_gameref_t gs, sc_int npc, sc_bool seen); -extern sc_bool gs_npc_seen (sc_gameref_t gs, sc_int npc); -extern sc_int gs_npc_walkstep_count (sc_gameref_t gs, sc_int npc); -extern void gs_set_npc_walkstep (sc_gameref_t gs, sc_int npc, - sc_int walk, sc_int walkstep); -extern sc_int gs_npc_walkstep (sc_gameref_t gs, sc_int npc, sc_int walk); -extern void gs_decrement_npc_walkstep (sc_gameref_t gs, - sc_int npc, sc_int walkstep); -extern void gs_clear_npc_references (sc_gameref_t gs); -extern void gs_clear_object_references (sc_gameref_t gs); -extern void gs_set_multiple_references (sc_gameref_t gs); -extern void gs_clear_multiple_references (sc_gameref_t gs); +extern void gs_move_player_to_room(sc_gameref_t game, sc_int room); +extern sc_bool gs_player_in_room(sc_gameref_t game, sc_int room); +extern sc_var_setref_t gs_get_vars(sc_gameref_t gs); +extern sc_prop_setref_t gs_get_bundle(sc_gameref_t gs); +extern sc_filterref_t gs_get_filter(sc_gameref_t gs); +extern sc_memo_setref_t gs_get_memento(sc_gameref_t gs); +extern void gs_set_playerroom(sc_gameref_t gs, sc_int room); +extern void gs_set_playerposition(sc_gameref_t gs, sc_int position); +extern void gs_set_playerparent(sc_gameref_t gs, sc_int parent); +extern sc_int gs_playerroom(sc_gameref_t gs); +extern sc_int gs_playerposition(sc_gameref_t gs); +extern sc_int gs_playerparent(sc_gameref_t gs); +extern sc_int gs_event_count(sc_gameref_t gs); +extern void gs_set_event_state(sc_gameref_t gs, sc_int event, sc_int state); +extern void gs_set_event_time(sc_gameref_t gs, sc_int event, sc_int etime); +extern sc_int gs_event_state(sc_gameref_t gs, sc_int event); +extern sc_int gs_event_time(sc_gameref_t gs, sc_int event); +extern void gs_decrement_event_time(sc_gameref_t gs, sc_int event); +extern sc_int gs_room_count(sc_gameref_t gs); +extern void gs_set_room_seen(sc_gameref_t gs, sc_int room, sc_bool seen); +extern sc_bool gs_room_seen(sc_gameref_t gs, sc_int room); +extern sc_int gs_task_count(sc_gameref_t gs); +extern void gs_set_task_done(sc_gameref_t gs, sc_int task, sc_bool done); +extern void gs_set_task_scored(sc_gameref_t gs, sc_int task, sc_bool scored); +extern sc_bool gs_task_done(sc_gameref_t gs, sc_int task); +extern sc_bool gs_task_scored(sc_gameref_t gs, sc_int task); +extern sc_int gs_object_count(sc_gameref_t gs); +extern void gs_set_object_openness(sc_gameref_t gs, + sc_int object, sc_int openness); +extern void gs_set_object_state(sc_gameref_t gs, sc_int object, sc_int state); +extern void gs_set_object_seen(sc_gameref_t gs, sc_int object, sc_bool seen); +extern void gs_set_object_unmoved(sc_gameref_t gs, + sc_int object, sc_bool unmoved); +extern void gs_set_object_static_unmoved(sc_gameref_t gs, + sc_int object, sc_bool unmoved); +extern sc_int gs_object_openness(sc_gameref_t gs, sc_int object); +extern sc_int gs_object_state(sc_gameref_t gs, sc_int object); +extern sc_bool gs_object_seen(sc_gameref_t gs, sc_int object); +extern sc_bool gs_object_unmoved(sc_gameref_t gs, sc_int object); +extern sc_bool gs_object_static_unmoved(sc_gameref_t gs, sc_int object); +extern sc_int gs_object_position(sc_gameref_t gs, sc_int object); +extern sc_int gs_object_parent(sc_gameref_t gs, sc_int object); +extern void gs_object_move_onto(sc_gameref_t gs, sc_int object, sc_int onto); +extern void gs_object_move_into(sc_gameref_t gs, sc_int object, sc_int into); +extern void gs_object_make_hidden(sc_gameref_t gs, sc_int object); +extern void gs_object_player_get(sc_gameref_t gs, sc_int object); +extern void gs_object_npc_get(sc_gameref_t gs, sc_int object, sc_int npc); +extern void gs_object_player_wear(sc_gameref_t gs, sc_int object); +extern void gs_object_npc_wear(sc_gameref_t gs, sc_int object, sc_int npc); +extern void gs_object_to_room(sc_gameref_t gs, sc_int object, sc_int room); +extern sc_int gs_npc_count(sc_gameref_t gs); +extern void gs_set_npc_location(sc_gameref_t gs, sc_int npc, sc_int location); +extern sc_int gs_npc_location(sc_gameref_t gs, sc_int npc); +extern void gs_set_npc_position(sc_gameref_t gs, sc_int npc, sc_int position); +extern sc_int gs_npc_position(sc_gameref_t gs, sc_int npc); +extern void gs_set_npc_parent(sc_gameref_t gs, sc_int npc, sc_int parent); +extern sc_int gs_npc_parent(sc_gameref_t gs, sc_int npc); +extern void gs_set_npc_seen(sc_gameref_t gs, sc_int npc, sc_bool seen); +extern sc_bool gs_npc_seen(sc_gameref_t gs, sc_int npc); +extern sc_int gs_npc_walkstep_count(sc_gameref_t gs, sc_int npc); +extern void gs_set_npc_walkstep(sc_gameref_t gs, sc_int npc, + sc_int walk, sc_int walkstep); +extern sc_int gs_npc_walkstep(sc_gameref_t gs, sc_int npc, sc_int walk); +extern void gs_decrement_npc_walkstep(sc_gameref_t gs, + sc_int npc, sc_int walkstep); +extern void gs_clear_npc_references(sc_gameref_t gs); +extern void gs_clear_object_references(sc_gameref_t gs); +extern void gs_set_multiple_references(sc_gameref_t gs); +extern void gs_clear_multiple_references(sc_gameref_t gs); /* Pattern matching functions. */ -extern sc_bool uip_match (const sc_char *pattern, - const sc_char *string, sc_gameref_t game); -extern sc_char *uip_replace_pronouns (sc_gameref_t game, const sc_char *string); -extern void uip_assign_pronouns (sc_gameref_t game, const sc_char *string); -extern void uip_debug_trace (sc_bool flag); +extern sc_bool uip_match(const sc_char *pattern, + const sc_char *string, sc_gameref_t game); +extern sc_char *uip_replace_pronouns(sc_gameref_t game, const sc_char *string); +extern void uip_assign_pronouns(sc_gameref_t game, const sc_char *string); +extern void uip_debug_trace(sc_bool flag); /* Library perspective enumeration and functions. */ -enum -{ LIB_FIRST_PERSON = 0, - LIB_SECOND_PERSON = 1, - LIB_THIRD_PERSON = 2 +enum { + LIB_FIRST_PERSON = 0, + LIB_SECOND_PERSON = 1, + LIB_THIRD_PERSON = 2 }; -extern void lib_warn_battle_system (void); -extern sc_int lib_random_roomgroup_member (sc_gameref_t game, sc_int roomgroup); -extern const sc_char *lib_get_room_name (sc_gameref_t game, sc_int room); -extern void lib_print_room_name (sc_gameref_t game, sc_int room); -extern void lib_print_room_description (sc_gameref_t game, sc_int room); -extern sc_bool lib_cmd_go_north (sc_gameref_t game); -extern sc_bool lib_cmd_go_east (sc_gameref_t game); -extern sc_bool lib_cmd_go_south (sc_gameref_t game); -extern sc_bool lib_cmd_go_west (sc_gameref_t game); -extern sc_bool lib_cmd_go_up (sc_gameref_t game); -extern sc_bool lib_cmd_go_down (sc_gameref_t game); -extern sc_bool lib_cmd_go_in (sc_gameref_t game); -extern sc_bool lib_cmd_go_out (sc_gameref_t game); -extern sc_bool lib_cmd_go_northeast (sc_gameref_t game); -extern sc_bool lib_cmd_go_southeast (sc_gameref_t game); -extern sc_bool lib_cmd_go_northwest (sc_gameref_t game); -extern sc_bool lib_cmd_go_southwest (sc_gameref_t game); -extern sc_bool lib_cmd_go_room (sc_gameref_t game); -extern sc_bool lib_cmd_verbose (sc_gameref_t game); -extern sc_bool lib_cmd_brief (sc_gameref_t game); -extern sc_bool lib_cmd_notify_on_off (sc_gameref_t game); -extern sc_bool lib_cmd_notify (sc_gameref_t game); -extern sc_bool lib_cmd_time (sc_gameref_t game); -extern sc_bool lib_cmd_date (sc_gameref_t game); -extern sc_bool lib_cmd_quit (sc_gameref_t game); -extern sc_bool lib_cmd_restart (sc_gameref_t game); -extern sc_bool lib_cmd_undo (sc_gameref_t game); -extern sc_bool lib_cmd_history (sc_gameref_t game); -extern sc_bool lib_cmd_history_number (sc_gameref_t game); -extern sc_bool lib_cmd_again (sc_gameref_t game); -extern sc_bool lib_cmd_redo_number (sc_gameref_t game); -extern sc_bool lib_cmd_redo_text (sc_gameref_t game); -extern sc_bool lib_cmd_redo_last (sc_gameref_t game); -extern sc_bool lib_cmd_hints (sc_gameref_t game); -extern sc_bool lib_cmd_help (sc_gameref_t game); -extern sc_bool lib_cmd_license (sc_gameref_t game); -extern sc_bool lib_cmd_information (sc_gameref_t game); -extern sc_bool lib_cmd_clear (sc_gameref_t game); -extern sc_bool lib_cmd_statusline (sc_gameref_t game); -extern sc_bool lib_cmd_version (sc_gameref_t game); -extern sc_bool lib_cmd_look (sc_gameref_t game); -extern sc_bool lib_cmd_print_room_exits (sc_gameref_t game); -extern sc_bool lib_cmd_wait (sc_gameref_t game); -extern sc_bool lib_cmd_wait_number (sc_gameref_t game); -extern sc_bool lib_cmd_examine_self (sc_gameref_t game); -extern sc_bool lib_cmd_examine_npc (sc_gameref_t game); -extern sc_bool lib_cmd_examine_object (sc_gameref_t game); -extern sc_bool lib_cmd_count (sc_gameref_t game); -extern sc_bool lib_cmd_take_all (sc_gameref_t game); -extern sc_bool lib_cmd_take_except_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_take_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_take_all_from (sc_gameref_t game); -extern sc_bool lib_cmd_take_from_except_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_take_from_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_take_all_from_npc (sc_gameref_t game); -extern sc_bool lib_cmd_take_from_npc_except_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_take_from_npc_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_take_npc (sc_gameref_t game); -extern sc_bool lib_cmd_drop_all (sc_gameref_t game); -extern sc_bool lib_cmd_drop_except_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_drop_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_wear_all (sc_gameref_t game); -extern sc_bool lib_cmd_wear_except_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_wear_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_remove_all (sc_gameref_t game); -extern sc_bool lib_cmd_remove_except_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_remove_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_kiss_npc (sc_gameref_t game); -extern sc_bool lib_cmd_kiss_object (sc_gameref_t game); -extern sc_bool lib_cmd_kiss_other (sc_gameref_t game); -extern sc_bool lib_cmd_kill_other (sc_gameref_t game); -extern sc_bool lib_cmd_eat_object (sc_gameref_t game); -extern sc_bool lib_cmd_give_object_npc (sc_gameref_t game); -extern sc_bool lib_cmd_inventory (sc_gameref_t game); -extern sc_bool lib_cmd_open_object (sc_gameref_t game); -extern sc_bool lib_cmd_close_object (sc_gameref_t game); -extern sc_bool lib_cmd_unlock_object_with (sc_gameref_t game); -extern sc_bool lib_cmd_lock_object_with (sc_gameref_t game); -extern sc_bool lib_cmd_unlock_object (sc_gameref_t game); -extern sc_bool lib_cmd_lock_object (sc_gameref_t game); -extern sc_bool lib_cmd_ask_npc_about (sc_gameref_t game); -extern sc_bool lib_cmd_put_all_in (sc_gameref_t game); -extern sc_bool lib_cmd_put_in_except_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_put_in_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_put_all_on (sc_gameref_t game); -extern sc_bool lib_cmd_put_on_except_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_put_on_multiple (sc_gameref_t game); -extern sc_bool lib_cmd_read_object (sc_gameref_t game); -extern sc_bool lib_cmd_read_other (sc_gameref_t game); -extern sc_bool lib_cmd_stand_on_object (sc_gameref_t game); -extern sc_bool lib_cmd_stand_on_floor (sc_gameref_t game); -extern sc_bool lib_cmd_attack_npc_with (sc_gameref_t game); -extern sc_bool lib_cmd_sit_on_object (sc_gameref_t game); -extern sc_bool lib_cmd_sit_on_floor (sc_gameref_t game); -extern sc_bool lib_cmd_lie_on_object (sc_gameref_t game); -extern sc_bool lib_cmd_lie_on_floor (sc_gameref_t game); -extern sc_bool lib_cmd_get_off_object (sc_gameref_t game); -extern sc_bool lib_cmd_get_off (sc_gameref_t game); -extern sc_bool lib_cmd_save (sc_gameref_t game); -extern sc_bool lib_cmd_restore (sc_gameref_t game); -extern sc_bool lib_cmd_locate_object (sc_gameref_t game); -extern sc_bool lib_cmd_locate_npc (sc_gameref_t game); -extern sc_bool lib_cmd_turns (sc_gameref_t game); -extern sc_bool lib_cmd_score (sc_gameref_t game); -extern sc_bool lib_cmd_get_what (sc_gameref_t game); -extern sc_bool lib_cmd_open_what (sc_gameref_t game); -extern sc_bool lib_cmd_close_other (sc_gameref_t game); -extern sc_bool lib_cmd_lock_other (sc_gameref_t game); -extern sc_bool lib_cmd_lock_what (sc_gameref_t game); -extern sc_bool lib_cmd_unlock_other (sc_gameref_t game); -extern sc_bool lib_cmd_unlock_what (sc_gameref_t game); -extern sc_bool lib_cmd_stand_other (sc_gameref_t game); -extern sc_bool lib_cmd_sit_other (sc_gameref_t game); -extern sc_bool lib_cmd_lie_other (sc_gameref_t game); -extern sc_bool lib_cmd_give_object (sc_gameref_t game); -extern sc_bool lib_cmd_give_what (sc_gameref_t game); -extern sc_bool lib_cmd_remove_what (sc_gameref_t game); -extern sc_bool lib_cmd_drop_what (sc_gameref_t game); -extern sc_bool lib_cmd_wear_what (sc_gameref_t game); -extern sc_bool lib_cmd_profanity (sc_gameref_t game); -extern sc_bool lib_cmd_examine_all (sc_gameref_t game); -extern sc_bool lib_cmd_examine_other (sc_gameref_t game); -extern sc_bool lib_cmd_locate_other (sc_gameref_t game); -extern sc_bool lib_cmd_unix_like (sc_gameref_t game); -extern sc_bool lib_cmd_dos_like (sc_gameref_t game); -extern sc_bool lib_cmd_ask_object (sc_gameref_t game); -extern sc_bool lib_cmd_ask_npc (sc_gameref_t game); -extern sc_bool lib_cmd_ask_other (sc_gameref_t game); -extern sc_bool lib_cmd_block_object (sc_gameref_t game); -extern sc_bool lib_cmd_block_other (sc_gameref_t game); -extern sc_bool lib_cmd_block_what (sc_gameref_t game); -extern sc_bool lib_cmd_break_object (sc_gameref_t game); -extern sc_bool lib_cmd_break_other (sc_gameref_t game); -extern sc_bool lib_cmd_break_what (sc_gameref_t game); -extern sc_bool lib_cmd_destroy_what (sc_gameref_t game); -extern sc_bool lib_cmd_smash_what (sc_gameref_t game); -extern sc_bool lib_cmd_buy_object (sc_gameref_t game); -extern sc_bool lib_cmd_buy_other (sc_gameref_t game); -extern sc_bool lib_cmd_buy_what (sc_gameref_t game); -extern sc_bool lib_cmd_clean_object (sc_gameref_t game); -extern sc_bool lib_cmd_clean_other (sc_gameref_t game); -extern sc_bool lib_cmd_clean_what (sc_gameref_t game); -extern sc_bool lib_cmd_climb_object (sc_gameref_t game); -extern sc_bool lib_cmd_climb_other (sc_gameref_t game); -extern sc_bool lib_cmd_climb_what (sc_gameref_t game); -extern sc_bool lib_cmd_cry (sc_gameref_t game); -extern sc_bool lib_cmd_cut_object (sc_gameref_t game); -extern sc_bool lib_cmd_cut_other (sc_gameref_t game); -extern sc_bool lib_cmd_cut_what (sc_gameref_t game); -extern sc_bool lib_cmd_drink_object (sc_gameref_t game); -extern sc_bool lib_cmd_drink_other (sc_gameref_t game); -extern sc_bool lib_cmd_drink_what (sc_gameref_t game); -extern sc_bool lib_cmd_dance (sc_gameref_t game); -extern sc_bool lib_cmd_eat_other (sc_gameref_t game); -extern sc_bool lib_cmd_feed (sc_gameref_t game); -extern sc_bool lib_cmd_fight (sc_gameref_t game); -extern sc_bool lib_cmd_feel (sc_gameref_t game); -extern sc_bool lib_cmd_fix_object (sc_gameref_t game); -extern sc_bool lib_cmd_fix_other (sc_gameref_t game); -extern sc_bool lib_cmd_fix_what (sc_gameref_t game); -extern sc_bool lib_cmd_fly (sc_gameref_t game); -extern sc_bool lib_cmd_hint (sc_gameref_t game); -extern sc_bool lib_cmd_attack_npc (sc_gameref_t game); -extern sc_bool lib_cmd_hit_object (sc_gameref_t game); -extern sc_bool lib_cmd_hit_other (sc_gameref_t game); -extern sc_bool lib_cmd_hit_what (sc_gameref_t game); -extern sc_bool lib_cmd_hum (sc_gameref_t game); -extern sc_bool lib_cmd_jump (sc_gameref_t game); -extern sc_bool lib_cmd_kick_object (sc_gameref_t game); -extern sc_bool lib_cmd_kick_other (sc_gameref_t game); -extern sc_bool lib_cmd_kick_what (sc_gameref_t game); -extern sc_bool lib_cmd_light_object (sc_gameref_t game); -extern sc_bool lib_cmd_light_other (sc_gameref_t game); -extern sc_bool lib_cmd_light_what (sc_gameref_t game); -extern sc_bool lib_cmd_lift_object (sc_gameref_t game); -extern sc_bool lib_cmd_lift_other (sc_gameref_t game); -extern sc_bool lib_cmd_lift_what (sc_gameref_t game); -extern sc_bool lib_cmd_listen (sc_gameref_t game); -extern sc_bool lib_cmd_mend_object (sc_gameref_t game); -extern sc_bool lib_cmd_mend_other (sc_gameref_t game); -extern sc_bool lib_cmd_mend_what (sc_gameref_t game); -extern sc_bool lib_cmd_move_object (sc_gameref_t game); -extern sc_bool lib_cmd_move_other (sc_gameref_t game); -extern sc_bool lib_cmd_move_what (sc_gameref_t game); -extern sc_bool lib_cmd_please (sc_gameref_t game); -extern sc_bool lib_cmd_press_object (sc_gameref_t game); -extern sc_bool lib_cmd_press_other (sc_gameref_t game); -extern sc_bool lib_cmd_press_what (sc_gameref_t game); -extern sc_bool lib_cmd_pull_object (sc_gameref_t game); -extern sc_bool lib_cmd_pull_other (sc_gameref_t game); -extern sc_bool lib_cmd_pull_what (sc_gameref_t game); -extern sc_bool lib_cmd_punch (sc_gameref_t game); -extern sc_bool lib_cmd_push_object (sc_gameref_t game); -extern sc_bool lib_cmd_push_other (sc_gameref_t game); -extern sc_bool lib_cmd_push_what (sc_gameref_t game); -extern sc_bool lib_cmd_repair_object (sc_gameref_t game); -extern sc_bool lib_cmd_repair_other (sc_gameref_t game); -extern sc_bool lib_cmd_repair_what (sc_gameref_t game); -extern sc_bool lib_cmd_rub_object (sc_gameref_t game); -extern sc_bool lib_cmd_rub_other (sc_gameref_t game); -extern sc_bool lib_cmd_rub_what (sc_gameref_t game); -extern sc_bool lib_cmd_run (sc_gameref_t game); -extern sc_bool lib_cmd_say (sc_gameref_t game); -extern sc_bool lib_cmd_sell_object (sc_gameref_t game); -extern sc_bool lib_cmd_sell_other (sc_gameref_t game); -extern sc_bool lib_cmd_sell_what (sc_gameref_t game); -extern sc_bool lib_cmd_shake_object (sc_gameref_t game); -extern sc_bool lib_cmd_shake_npc (sc_gameref_t game); -extern sc_bool lib_cmd_shake_other (sc_gameref_t game); -extern sc_bool lib_cmd_shake_what (sc_gameref_t game); -extern sc_bool lib_cmd_shout (sc_gameref_t game); -extern sc_bool lib_cmd_sing (sc_gameref_t game); -extern sc_bool lib_cmd_sleep (sc_gameref_t game); -extern sc_bool lib_cmd_smell_object (sc_gameref_t game); -extern sc_bool lib_cmd_smell_other (sc_gameref_t game); -extern sc_bool lib_cmd_stop_object (sc_gameref_t game); -extern sc_bool lib_cmd_stop_other (sc_gameref_t game); -extern sc_bool lib_cmd_stop_what (sc_gameref_t game); -extern sc_bool lib_cmd_suck_object (sc_gameref_t game); -extern sc_bool lib_cmd_suck_other (sc_gameref_t game); -extern sc_bool lib_cmd_suck_what (sc_gameref_t game); -extern sc_bool lib_cmd_talk (sc_gameref_t game); -extern sc_bool lib_cmd_thank (sc_gameref_t game); -extern sc_bool lib_cmd_touch_object (sc_gameref_t game); -extern sc_bool lib_cmd_touch_other (sc_gameref_t game); -extern sc_bool lib_cmd_touch_what (sc_gameref_t game); -extern sc_bool lib_cmd_turn_object (sc_gameref_t game); -extern sc_bool lib_cmd_turn_other (sc_gameref_t game); -extern sc_bool lib_cmd_turn_what (sc_gameref_t game); -extern sc_bool lib_cmd_unblock_object (sc_gameref_t game); -extern sc_bool lib_cmd_unblock_other (sc_gameref_t game); -extern sc_bool lib_cmd_unblock_what (sc_gameref_t game); -extern sc_bool lib_cmd_wash_object (sc_gameref_t game); -extern sc_bool lib_cmd_wash_other (sc_gameref_t game); -extern sc_bool lib_cmd_wash_what (sc_gameref_t game); -extern sc_bool lib_cmd_whistle (sc_gameref_t game); -extern sc_bool lib_cmd_interrogation (sc_gameref_t game); -extern sc_bool lib_cmd_xyzzy (sc_gameref_t game); -extern sc_bool lib_cmd_egotistic (sc_gameref_t game); -extern sc_bool lib_cmd_yes_or_no (sc_gameref_t game); -extern sc_bool lib_cmd_verb_object (sc_gameref_t game); -extern sc_bool lib_cmd_verb_npc (sc_gameref_t game); -extern void lib_debug_trace (sc_bool flag); +extern void lib_warn_battle_system(void); +extern sc_int lib_random_roomgroup_member(sc_gameref_t game, sc_int roomgroup); +extern const sc_char *lib_get_room_name(sc_gameref_t game, sc_int room); +extern void lib_print_room_name(sc_gameref_t game, sc_int room); +extern void lib_print_room_description(sc_gameref_t game, sc_int room); +extern sc_bool lib_cmd_go_north(sc_gameref_t game); +extern sc_bool lib_cmd_go_east(sc_gameref_t game); +extern sc_bool lib_cmd_go_south(sc_gameref_t game); +extern sc_bool lib_cmd_go_west(sc_gameref_t game); +extern sc_bool lib_cmd_go_up(sc_gameref_t game); +extern sc_bool lib_cmd_go_down(sc_gameref_t game); +extern sc_bool lib_cmd_go_in(sc_gameref_t game); +extern sc_bool lib_cmd_go_out(sc_gameref_t game); +extern sc_bool lib_cmd_go_northeast(sc_gameref_t game); +extern sc_bool lib_cmd_go_southeast(sc_gameref_t game); +extern sc_bool lib_cmd_go_northwest(sc_gameref_t game); +extern sc_bool lib_cmd_go_southwest(sc_gameref_t game); +extern sc_bool lib_cmd_go_room(sc_gameref_t game); +extern sc_bool lib_cmd_verbose(sc_gameref_t game); +extern sc_bool lib_cmd_brief(sc_gameref_t game); +extern sc_bool lib_cmd_notify_on_off(sc_gameref_t game); +extern sc_bool lib_cmd_notify(sc_gameref_t game); +extern sc_bool lib_cmd_time(sc_gameref_t game); +extern sc_bool lib_cmd_date(sc_gameref_t game); +extern sc_bool lib_cmd_quit(sc_gameref_t game); +extern sc_bool lib_cmd_restart(sc_gameref_t game); +extern sc_bool lib_cmd_undo(sc_gameref_t game); +extern sc_bool lib_cmd_history(sc_gameref_t game); +extern sc_bool lib_cmd_history_number(sc_gameref_t game); +extern sc_bool lib_cmd_again(sc_gameref_t game); +extern sc_bool lib_cmd_redo_number(sc_gameref_t game); +extern sc_bool lib_cmd_redo_text(sc_gameref_t game); +extern sc_bool lib_cmd_redo_last(sc_gameref_t game); +extern sc_bool lib_cmd_hints(sc_gameref_t game); +extern sc_bool lib_cmd_help(sc_gameref_t game); +extern sc_bool lib_cmd_license(sc_gameref_t game); +extern sc_bool lib_cmd_information(sc_gameref_t game); +extern sc_bool lib_cmd_clear(sc_gameref_t game); +extern sc_bool lib_cmd_statusline(sc_gameref_t game); +extern sc_bool lib_cmd_version(sc_gameref_t game); +extern sc_bool lib_cmd_look(sc_gameref_t game); +extern sc_bool lib_cmd_print_room_exits(sc_gameref_t game); +extern sc_bool lib_cmd_wait(sc_gameref_t game); +extern sc_bool lib_cmd_wait_number(sc_gameref_t game); +extern sc_bool lib_cmd_examine_self(sc_gameref_t game); +extern sc_bool lib_cmd_examine_npc(sc_gameref_t game); +extern sc_bool lib_cmd_examine_object(sc_gameref_t game); +extern sc_bool lib_cmd_count(sc_gameref_t game); +extern sc_bool lib_cmd_take_all(sc_gameref_t game); +extern sc_bool lib_cmd_take_except_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_take_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_take_all_from(sc_gameref_t game); +extern sc_bool lib_cmd_take_from_except_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_take_from_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_take_all_from_npc(sc_gameref_t game); +extern sc_bool lib_cmd_take_from_npc_except_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_take_from_npc_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_take_npc(sc_gameref_t game); +extern sc_bool lib_cmd_drop_all(sc_gameref_t game); +extern sc_bool lib_cmd_drop_except_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_drop_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_wear_all(sc_gameref_t game); +extern sc_bool lib_cmd_wear_except_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_wear_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_remove_all(sc_gameref_t game); +extern sc_bool lib_cmd_remove_except_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_remove_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_kiss_npc(sc_gameref_t game); +extern sc_bool lib_cmd_kiss_object(sc_gameref_t game); +extern sc_bool lib_cmd_kiss_other(sc_gameref_t game); +extern sc_bool lib_cmd_kill_other(sc_gameref_t game); +extern sc_bool lib_cmd_eat_object(sc_gameref_t game); +extern sc_bool lib_cmd_give_object_npc(sc_gameref_t game); +extern sc_bool lib_cmd_inventory(sc_gameref_t game); +extern sc_bool lib_cmd_open_object(sc_gameref_t game); +extern sc_bool lib_cmd_close_object(sc_gameref_t game); +extern sc_bool lib_cmd_unlock_object_with(sc_gameref_t game); +extern sc_bool lib_cmd_lock_object_with(sc_gameref_t game); +extern sc_bool lib_cmd_unlock_object(sc_gameref_t game); +extern sc_bool lib_cmd_lock_object(sc_gameref_t game); +extern sc_bool lib_cmd_ask_npc_about(sc_gameref_t game); +extern sc_bool lib_cmd_put_all_in(sc_gameref_t game); +extern sc_bool lib_cmd_put_in_except_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_put_in_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_put_all_on(sc_gameref_t game); +extern sc_bool lib_cmd_put_on_except_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_put_on_multiple(sc_gameref_t game); +extern sc_bool lib_cmd_read_object(sc_gameref_t game); +extern sc_bool lib_cmd_read_other(sc_gameref_t game); +extern sc_bool lib_cmd_stand_on_object(sc_gameref_t game); +extern sc_bool lib_cmd_stand_on_floor(sc_gameref_t game); +extern sc_bool lib_cmd_attack_npc_with(sc_gameref_t game); +extern sc_bool lib_cmd_sit_on_object(sc_gameref_t game); +extern sc_bool lib_cmd_sit_on_floor(sc_gameref_t game); +extern sc_bool lib_cmd_lie_on_object(sc_gameref_t game); +extern sc_bool lib_cmd_lie_on_floor(sc_gameref_t game); +extern sc_bool lib_cmd_get_off_object(sc_gameref_t game); +extern sc_bool lib_cmd_get_off(sc_gameref_t game); +extern sc_bool lib_cmd_save(sc_gameref_t game); +extern sc_bool lib_cmd_restore(sc_gameref_t game); +extern sc_bool lib_cmd_locate_object(sc_gameref_t game); +extern sc_bool lib_cmd_locate_npc(sc_gameref_t game); +extern sc_bool lib_cmd_turns(sc_gameref_t game); +extern sc_bool lib_cmd_score(sc_gameref_t game); +extern sc_bool lib_cmd_get_what(sc_gameref_t game); +extern sc_bool lib_cmd_open_what(sc_gameref_t game); +extern sc_bool lib_cmd_close_other(sc_gameref_t game); +extern sc_bool lib_cmd_lock_other(sc_gameref_t game); +extern sc_bool lib_cmd_lock_what(sc_gameref_t game); +extern sc_bool lib_cmd_unlock_other(sc_gameref_t game); +extern sc_bool lib_cmd_unlock_what(sc_gameref_t game); +extern sc_bool lib_cmd_stand_other(sc_gameref_t game); +extern sc_bool lib_cmd_sit_other(sc_gameref_t game); +extern sc_bool lib_cmd_lie_other(sc_gameref_t game); +extern sc_bool lib_cmd_give_object(sc_gameref_t game); +extern sc_bool lib_cmd_give_what(sc_gameref_t game); +extern sc_bool lib_cmd_remove_what(sc_gameref_t game); +extern sc_bool lib_cmd_drop_what(sc_gameref_t game); +extern sc_bool lib_cmd_wear_what(sc_gameref_t game); +extern sc_bool lib_cmd_profanity(sc_gameref_t game); +extern sc_bool lib_cmd_examine_all(sc_gameref_t game); +extern sc_bool lib_cmd_examine_other(sc_gameref_t game); +extern sc_bool lib_cmd_locate_other(sc_gameref_t game); +extern sc_bool lib_cmd_unix_like(sc_gameref_t game); +extern sc_bool lib_cmd_dos_like(sc_gameref_t game); +extern sc_bool lib_cmd_ask_object(sc_gameref_t game); +extern sc_bool lib_cmd_ask_npc(sc_gameref_t game); +extern sc_bool lib_cmd_ask_other(sc_gameref_t game); +extern sc_bool lib_cmd_block_object(sc_gameref_t game); +extern sc_bool lib_cmd_block_other(sc_gameref_t game); +extern sc_bool lib_cmd_block_what(sc_gameref_t game); +extern sc_bool lib_cmd_break_object(sc_gameref_t game); +extern sc_bool lib_cmd_break_other(sc_gameref_t game); +extern sc_bool lib_cmd_break_what(sc_gameref_t game); +extern sc_bool lib_cmd_destroy_what(sc_gameref_t game); +extern sc_bool lib_cmd_smash_what(sc_gameref_t game); +extern sc_bool lib_cmd_buy_object(sc_gameref_t game); +extern sc_bool lib_cmd_buy_other(sc_gameref_t game); +extern sc_bool lib_cmd_buy_what(sc_gameref_t game); +extern sc_bool lib_cmd_clean_object(sc_gameref_t game); +extern sc_bool lib_cmd_clean_other(sc_gameref_t game); +extern sc_bool lib_cmd_clean_what(sc_gameref_t game); +extern sc_bool lib_cmd_climb_object(sc_gameref_t game); +extern sc_bool lib_cmd_climb_other(sc_gameref_t game); +extern sc_bool lib_cmd_climb_what(sc_gameref_t game); +extern sc_bool lib_cmd_cry(sc_gameref_t game); +extern sc_bool lib_cmd_cut_object(sc_gameref_t game); +extern sc_bool lib_cmd_cut_other(sc_gameref_t game); +extern sc_bool lib_cmd_cut_what(sc_gameref_t game); +extern sc_bool lib_cmd_drink_object(sc_gameref_t game); +extern sc_bool lib_cmd_drink_other(sc_gameref_t game); +extern sc_bool lib_cmd_drink_what(sc_gameref_t game); +extern sc_bool lib_cmd_dance(sc_gameref_t game); +extern sc_bool lib_cmd_eat_other(sc_gameref_t game); +extern sc_bool lib_cmd_feed(sc_gameref_t game); +extern sc_bool lib_cmd_fight(sc_gameref_t game); +extern sc_bool lib_cmd_feel(sc_gameref_t game); +extern sc_bool lib_cmd_fix_object(sc_gameref_t game); +extern sc_bool lib_cmd_fix_other(sc_gameref_t game); +extern sc_bool lib_cmd_fix_what(sc_gameref_t game); +extern sc_bool lib_cmd_fly(sc_gameref_t game); +extern sc_bool lib_cmd_hint(sc_gameref_t game); +extern sc_bool lib_cmd_attack_npc(sc_gameref_t game); +extern sc_bool lib_cmd_hit_object(sc_gameref_t game); +extern sc_bool lib_cmd_hit_other(sc_gameref_t game); +extern sc_bool lib_cmd_hit_what(sc_gameref_t game); +extern sc_bool lib_cmd_hum(sc_gameref_t game); +extern sc_bool lib_cmd_jump(sc_gameref_t game); +extern sc_bool lib_cmd_kick_object(sc_gameref_t game); +extern sc_bool lib_cmd_kick_other(sc_gameref_t game); +extern sc_bool lib_cmd_kick_what(sc_gameref_t game); +extern sc_bool lib_cmd_light_object(sc_gameref_t game); +extern sc_bool lib_cmd_light_other(sc_gameref_t game); +extern sc_bool lib_cmd_light_what(sc_gameref_t game); +extern sc_bool lib_cmd_lift_object(sc_gameref_t game); +extern sc_bool lib_cmd_lift_other(sc_gameref_t game); +extern sc_bool lib_cmd_lift_what(sc_gameref_t game); +extern sc_bool lib_cmd_listen(sc_gameref_t game); +extern sc_bool lib_cmd_mend_object(sc_gameref_t game); +extern sc_bool lib_cmd_mend_other(sc_gameref_t game); +extern sc_bool lib_cmd_mend_what(sc_gameref_t game); +extern sc_bool lib_cmd_move_object(sc_gameref_t game); +extern sc_bool lib_cmd_move_other(sc_gameref_t game); +extern sc_bool lib_cmd_move_what(sc_gameref_t game); +extern sc_bool lib_cmd_please(sc_gameref_t game); +extern sc_bool lib_cmd_press_object(sc_gameref_t game); +extern sc_bool lib_cmd_press_other(sc_gameref_t game); +extern sc_bool lib_cmd_press_what(sc_gameref_t game); +extern sc_bool lib_cmd_pull_object(sc_gameref_t game); +extern sc_bool lib_cmd_pull_other(sc_gameref_t game); +extern sc_bool lib_cmd_pull_what(sc_gameref_t game); +extern sc_bool lib_cmd_punch(sc_gameref_t game); +extern sc_bool lib_cmd_push_object(sc_gameref_t game); +extern sc_bool lib_cmd_push_other(sc_gameref_t game); +extern sc_bool lib_cmd_push_what(sc_gameref_t game); +extern sc_bool lib_cmd_repair_object(sc_gameref_t game); +extern sc_bool lib_cmd_repair_other(sc_gameref_t game); +extern sc_bool lib_cmd_repair_what(sc_gameref_t game); +extern sc_bool lib_cmd_rub_object(sc_gameref_t game); +extern sc_bool lib_cmd_rub_other(sc_gameref_t game); +extern sc_bool lib_cmd_rub_what(sc_gameref_t game); +extern sc_bool lib_cmd_run(sc_gameref_t game); +extern sc_bool lib_cmd_say(sc_gameref_t game); +extern sc_bool lib_cmd_sell_object(sc_gameref_t game); +extern sc_bool lib_cmd_sell_other(sc_gameref_t game); +extern sc_bool lib_cmd_sell_what(sc_gameref_t game); +extern sc_bool lib_cmd_shake_object(sc_gameref_t game); +extern sc_bool lib_cmd_shake_npc(sc_gameref_t game); +extern sc_bool lib_cmd_shake_other(sc_gameref_t game); +extern sc_bool lib_cmd_shake_what(sc_gameref_t game); +extern sc_bool lib_cmd_shout(sc_gameref_t game); +extern sc_bool lib_cmd_sing(sc_gameref_t game); +extern sc_bool lib_cmd_sleep(sc_gameref_t game); +extern sc_bool lib_cmd_smell_object(sc_gameref_t game); +extern sc_bool lib_cmd_smell_other(sc_gameref_t game); +extern sc_bool lib_cmd_stop_object(sc_gameref_t game); +extern sc_bool lib_cmd_stop_other(sc_gameref_t game); +extern sc_bool lib_cmd_stop_what(sc_gameref_t game); +extern sc_bool lib_cmd_suck_object(sc_gameref_t game); +extern sc_bool lib_cmd_suck_other(sc_gameref_t game); +extern sc_bool lib_cmd_suck_what(sc_gameref_t game); +extern sc_bool lib_cmd_talk(sc_gameref_t game); +extern sc_bool lib_cmd_thank(sc_gameref_t game); +extern sc_bool lib_cmd_touch_object(sc_gameref_t game); +extern sc_bool lib_cmd_touch_other(sc_gameref_t game); +extern sc_bool lib_cmd_touch_what(sc_gameref_t game); +extern sc_bool lib_cmd_turn_object(sc_gameref_t game); +extern sc_bool lib_cmd_turn_other(sc_gameref_t game); +extern sc_bool lib_cmd_turn_what(sc_gameref_t game); +extern sc_bool lib_cmd_unblock_object(sc_gameref_t game); +extern sc_bool lib_cmd_unblock_other(sc_gameref_t game); +extern sc_bool lib_cmd_unblock_what(sc_gameref_t game); +extern sc_bool lib_cmd_wash_object(sc_gameref_t game); +extern sc_bool lib_cmd_wash_other(sc_gameref_t game); +extern sc_bool lib_cmd_wash_what(sc_gameref_t game); +extern sc_bool lib_cmd_whistle(sc_gameref_t game); +extern sc_bool lib_cmd_interrogation(sc_gameref_t game); +extern sc_bool lib_cmd_xyzzy(sc_gameref_t game); +extern sc_bool lib_cmd_egotistic(sc_gameref_t game); +extern sc_bool lib_cmd_yes_or_no(sc_gameref_t game); +extern sc_bool lib_cmd_verb_object(sc_gameref_t game); +extern sc_bool lib_cmd_verb_npc(sc_gameref_t game); +extern void lib_debug_trace(sc_bool flag); /* Resource opaque typedef and control functions. */ typedef struct sc_resource_s *sc_resourceref_t; -extern sc_bool res_has_sound (sc_gameref_t game); -extern sc_bool res_has_graphics (sc_gameref_t game); -extern void res_clear_resource (sc_resourceref_t resource); -extern sc_bool res_compare_resource (sc_resourceref_t from, - sc_resourceref_t with); -extern void res_handle_resource (sc_gameref_t game, - const sc_char *partial_format, - const sc_vartype_t vt_partial[]); -extern void res_sync_resources (sc_gameref_t game); -extern void res_cancel_resources (sc_gameref_t game); +extern sc_bool res_has_sound(sc_gameref_t game); +extern sc_bool res_has_graphics(sc_gameref_t game); +extern void res_clear_resource(sc_resourceref_t resource); +extern sc_bool res_compare_resource(sc_resourceref_t from, + sc_resourceref_t with); +extern void res_handle_resource(sc_gameref_t game, + const sc_char *partial_format, + const sc_vartype_t vt_partial[]); +extern void res_sync_resources(sc_gameref_t game); +extern void res_cancel_resources(sc_gameref_t game); /* Game runner functions. */ -extern sc_bool run_game_task_commands (sc_gameref_t game, - const sc_char *string); -extern sc_gameref_t run_create (sc_read_callbackref_t callback, void *opaque); -extern void run_interpret (sc_gameref_t game); -extern void run_destroy (sc_gameref_t game); -extern void run_restart (sc_gameref_t game); -extern void run_save (sc_gameref_t game, - sc_write_callbackref_t callback, void *opaque); -extern sc_bool run_save_prompted (sc_gameref_t game); -extern sc_bool run_restore (sc_gameref_t game, - sc_read_callbackref_t callback, void *opaque); -extern sc_bool run_restore_prompted (sc_gameref_t game); -extern sc_bool run_undo (sc_gameref_t game); -extern void run_quit (sc_gameref_t game); -extern sc_bool run_is_running (sc_gameref_t game); -extern sc_bool run_has_completed (sc_gameref_t game); -extern sc_bool run_is_undo_available (sc_gameref_t game); -extern void run_debug_trace (sc_bool flag); -extern void run_get_attributes (sc_gameref_t game, - const sc_char **game_name, - const sc_char **game_author, - const sc_char **game_compile_date, - sc_int *turns, sc_int *score, - sc_int *max_score, - const sc_char **current_room_name, - const sc_char **status_line, - const sc_char **preferred_font, - sc_bool *bold_room_names, sc_bool *verbose, - sc_bool *notify_score_change); -extern void run_set_attributes (sc_gameref_t game, - sc_bool bold_room_names, sc_bool verbose, - sc_bool notify_score_change); -extern sc_hintref_t run_hint_iterate (sc_gameref_t game, sc_hintref_t hint); -extern const sc_char *run_get_hint_question (sc_gameref_t game, - sc_hintref_t hint); -extern const sc_char *run_get_subtle_hint (sc_gameref_t game, - sc_hintref_t hint); -extern const sc_char *run_get_unsubtle_hint (sc_gameref_t game, - sc_hintref_t hint); +extern sc_bool run_game_task_commands(sc_gameref_t game, + const sc_char *string); +extern sc_gameref_t run_create(sc_read_callbackref_t callback, void *opaque); +extern void run_interpret(sc_gameref_t game); +extern void run_destroy(sc_gameref_t game); +extern void run_restart(sc_gameref_t game); +extern void run_save(sc_gameref_t game, + sc_write_callbackref_t callback, void *opaque); +extern sc_bool run_save_prompted(sc_gameref_t game); +extern sc_bool run_restore(sc_gameref_t game, + sc_read_callbackref_t callback, void *opaque); +extern sc_bool run_restore_prompted(sc_gameref_t game); +extern sc_bool run_undo(sc_gameref_t game); +extern void run_quit(sc_gameref_t game); +extern sc_bool run_is_running(sc_gameref_t game); +extern sc_bool run_has_completed(sc_gameref_t game); +extern sc_bool run_is_undo_available(sc_gameref_t game); +extern void run_debug_trace(sc_bool flag); +extern void run_get_attributes(sc_gameref_t game, + const sc_char **game_name, + const sc_char **game_author, + const sc_char **game_compile_date, + sc_int *turns, sc_int *score, + sc_int *max_score, + const sc_char **current_room_name, + const sc_char **status_line, + const sc_char **preferred_font, + sc_bool *bold_room_names, sc_bool *verbose, + sc_bool *notify_score_change); +extern void run_set_attributes(sc_gameref_t game, + sc_bool bold_room_names, sc_bool verbose, + sc_bool notify_score_change); +extern sc_hintref_t run_hint_iterate(sc_gameref_t game, sc_hintref_t hint); +extern const sc_char *run_get_hint_question(sc_gameref_t game, + sc_hintref_t hint); +extern const sc_char *run_get_subtle_hint(sc_gameref_t game, + sc_hintref_t hint); +extern const sc_char *run_get_unsubtle_hint(sc_gameref_t game, + sc_hintref_t hint); /* Event functions. */ -extern sc_bool evt_can_see_event (sc_gameref_t game, sc_int event); -extern void evt_tick_events (sc_gameref_t game); -extern void evt_debug_trace (sc_bool flag); +extern sc_bool evt_can_see_event(sc_gameref_t game, sc_int event); +extern void evt_tick_events(sc_gameref_t game); +extern void evt_debug_trace(sc_bool flag); /* Task functions. */ -extern sc_bool task_has_hints (sc_gameref_t game, sc_int task); -extern const sc_char *task_get_hint_question (sc_gameref_t game, sc_int task); -extern const sc_char *task_get_hint_subtle (sc_gameref_t game, sc_int task); -extern const sc_char *task_get_hint_unsubtle (sc_gameref_t game, sc_int task); -extern sc_bool task_can_run_task_directional (sc_gameref_t game, - sc_int task, sc_bool forwards); -extern sc_bool task_can_run_task (sc_gameref_t game, sc_int task); -extern sc_bool task_run_task (sc_gameref_t game, sc_int task, sc_bool forwards); -extern void task_debug_trace (sc_bool flag); +extern sc_bool task_has_hints(sc_gameref_t game, sc_int task); +extern const sc_char *task_get_hint_question(sc_gameref_t game, sc_int task); +extern const sc_char *task_get_hint_subtle(sc_gameref_t game, sc_int task); +extern const sc_char *task_get_hint_unsubtle(sc_gameref_t game, sc_int task); +extern sc_bool task_can_run_task_directional(sc_gameref_t game, + sc_int task, sc_bool forwards); +extern sc_bool task_can_run_task(sc_gameref_t game, sc_int task); +extern sc_bool task_run_task(sc_gameref_t game, sc_int task, sc_bool forwards); +extern void task_debug_trace(sc_bool flag); /* Task restriction functions. */ -extern sc_bool restr_pass_task_object_state (sc_gameref_t game, - sc_int var1, sc_int var2); -extern sc_bool restr_eval_task_restrictions (sc_gameref_t game, - sc_int task, sc_bool *pass, - const sc_char **fail_message); -extern void restr_debug_trace (sc_bool flag); +extern sc_bool restr_pass_task_object_state(sc_gameref_t game, + sc_int var1, sc_int var2); +extern sc_bool restr_eval_task_restrictions(sc_gameref_t game, + sc_int task, sc_bool *pass, + const sc_char **fail_message); +extern void restr_debug_trace(sc_bool flag); /* NPC gender enumeration and functions. */ -enum -{ NPC_MALE = 0, - NPC_FEMALE = 1, - NPC_NEUTER = 2 +enum { + NPC_MALE = 0, + NPC_FEMALE = 1, + NPC_NEUTER = 2 }; -extern sc_bool npc_in_room (sc_gameref_t game, sc_int npc, sc_int room); -extern sc_int npc_count_in_room (sc_gameref_t game, sc_int room); -extern void npc_setup_initial (sc_gameref_t game); -extern void npc_start_npc_walk (sc_gameref_t game, sc_int npc, sc_int walk); -extern void npc_tick_npcs (sc_gameref_t game); -extern void npc_turn_update (sc_gameref_t game); -extern void npc_debug_trace (sc_bool flag); +extern sc_bool npc_in_room(sc_gameref_t game, sc_int npc, sc_int room); +extern sc_int npc_count_in_room(sc_gameref_t game, sc_int room); +extern void npc_setup_initial(sc_gameref_t game); +extern void npc_start_npc_walk(sc_gameref_t game, sc_int npc, sc_int walk); +extern void npc_tick_npcs(sc_gameref_t game); +extern void npc_turn_update(sc_gameref_t game); +extern void npc_debug_trace(sc_bool flag); /* Object open/closed state enumeration and functions. */ -enum -{ OBJ_WONTCLOSE = 0, - OBJ_OPEN = 5, - OBJ_CLOSED = 6, - OBJ_LOCKED = 7 +enum { + OBJ_WONTCLOSE = 0, + OBJ_OPEN = 5, + OBJ_CLOSED = 6, + OBJ_LOCKED = 7 }; -extern sc_bool obj_is_static (sc_gameref_t game, sc_int object); -extern sc_bool obj_is_container (sc_gameref_t game, sc_int object); -extern sc_bool obj_is_surface (sc_gameref_t game, sc_int object); -extern sc_int obj_container_object (sc_gameref_t game, sc_int n); -extern sc_int obj_surface_object (sc_gameref_t game, sc_int n); -extern sc_bool obj_indirectly_in_room (sc_gameref_t game, - sc_int object, sc_int room); -extern sc_bool obj_indirectly_held_by_player (sc_gameref_t game, sc_int object); -extern sc_bool obj_directly_in_room (sc_gameref_t game, - sc_int object, sc_int room); -extern sc_int obj_stateful_object (sc_gameref_t game, sc_int n); -extern sc_int obj_dynamic_object (sc_gameref_t game, sc_int n); -extern sc_int obj_wearable_object (sc_gameref_t game, sc_int n); -extern sc_int obj_standable_object (sc_gameref_t game, sc_int n); -extern sc_int obj_get_size (sc_gameref_t game, sc_int object); -extern sc_int obj_get_weight (sc_gameref_t game, sc_int object); -extern sc_int obj_get_player_size_limit (sc_gameref_t game); -extern sc_int obj_get_player_weight_limit (sc_gameref_t game); -extern sc_int obj_get_container_maxsize (sc_gameref_t game, sc_int object); -extern sc_int obj_get_container_capacity (sc_gameref_t game, sc_int object); -extern sc_int obj_lieable_object (sc_gameref_t game, sc_int n); -extern sc_bool obj_appears_plural (sc_gameref_t game, sc_int object); -extern void obj_setup_initial (sc_gameref_t game); -extern sc_int obj_container_index (sc_gameref_t game, sc_int object); -extern sc_int obj_surface_index (sc_gameref_t game, sc_int object); -extern sc_int obj_stateful_index (sc_gameref_t game, sc_int object); -extern sc_char *obj_state_name (sc_gameref_t game, sc_int object); -extern sc_bool obj_shows_initial_description (sc_gameref_t game, sc_int object); -extern void obj_turn_update (sc_gameref_t game); -extern void obj_debug_trace (sc_bool flag); +extern sc_bool obj_is_static(sc_gameref_t game, sc_int object); +extern sc_bool obj_is_container(sc_gameref_t game, sc_int object); +extern sc_bool obj_is_surface(sc_gameref_t game, sc_int object); +extern sc_int obj_container_object(sc_gameref_t game, sc_int n); +extern sc_int obj_surface_object(sc_gameref_t game, sc_int n); +extern sc_bool obj_indirectly_in_room(sc_gameref_t game, + sc_int object, sc_int room); +extern sc_bool obj_indirectly_held_by_player(sc_gameref_t game, sc_int object); +extern sc_bool obj_directly_in_room(sc_gameref_t game, + sc_int object, sc_int room); +extern sc_int obj_stateful_object(sc_gameref_t game, sc_int n); +extern sc_int obj_dynamic_object(sc_gameref_t game, sc_int n); +extern sc_int obj_wearable_object(sc_gameref_t game, sc_int n); +extern sc_int obj_standable_object(sc_gameref_t game, sc_int n); +extern sc_int obj_get_size(sc_gameref_t game, sc_int object); +extern sc_int obj_get_weight(sc_gameref_t game, sc_int object); +extern sc_int obj_get_player_size_limit(sc_gameref_t game); +extern sc_int obj_get_player_weight_limit(sc_gameref_t game); +extern sc_int obj_get_container_maxsize(sc_gameref_t game, sc_int object); +extern sc_int obj_get_container_capacity(sc_gameref_t game, sc_int object); +extern sc_int obj_lieable_object(sc_gameref_t game, sc_int n); +extern sc_bool obj_appears_plural(sc_gameref_t game, sc_int object); +extern void obj_setup_initial(sc_gameref_t game); +extern sc_int obj_container_index(sc_gameref_t game, sc_int object); +extern sc_int obj_surface_index(sc_gameref_t game, sc_int object); +extern sc_int obj_stateful_index(sc_gameref_t game, sc_int object); +extern sc_char *obj_state_name(sc_gameref_t game, sc_int object); +extern sc_bool obj_shows_initial_description(sc_gameref_t game, sc_int object); +extern void obj_turn_update(sc_gameref_t game); +extern void obj_debug_trace(sc_bool flag); /* Game serialization functions. */ -extern void ser_save_game (sc_gameref_t game, - sc_write_callbackref_t callback, void *opaque); -extern sc_bool ser_save_game_prompted (sc_gameref_t game); -extern sc_bool ser_load_game (sc_gameref_t game, - sc_read_callbackref_t callback, void *opaque); -extern sc_bool ser_load_game_prompted (sc_gameref_t game); +extern void ser_save_game(sc_gameref_t game, + sc_write_callbackref_t callback, void *opaque); +extern sc_bool ser_save_game_prompted(sc_gameref_t game); +extern sc_bool ser_load_game(sc_gameref_t game, + sc_read_callbackref_t callback, void *opaque); +extern sc_bool ser_load_game_prompted(sc_gameref_t game); /* Locale support, and locale-sensitive functions. */ -extern void loc_detect_game_locale (sc_prop_setref_t bundle); -extern sc_bool loc_set_locale (const sc_char *name); -extern const sc_char *loc_get_locale (void); -extern sc_bool sc_isspace (sc_char character); -extern sc_bool sc_isdigit (sc_char character); -extern sc_bool sc_isalpha (sc_char character); -extern sc_char sc_toupper (sc_char character); -extern sc_char sc_tolower (sc_char character); -extern void loc_debug_dump (void); +extern void loc_detect_game_locale(sc_prop_setref_t bundle); +extern sc_bool loc_set_locale(const sc_char *name); +extern const sc_char *loc_get_locale(void); +extern sc_bool sc_isspace(sc_char character); +extern sc_bool sc_isdigit(sc_char character); +extern sc_bool sc_isalpha(sc_char character); +extern sc_char sc_toupper(sc_char character); +extern sc_char sc_tolower(sc_char character); +extern void loc_debug_dump(void); /* Debugger interface. */ typedef struct sc_debugger_s *sc_debuggerref_t; -extern sc_bool debug_run_command (sc_gameref_t game, - const sc_char *debug_command); -extern sc_bool debug_cmd_debugger (sc_gameref_t game); -extern void debug_set_enabled (sc_gameref_t game, sc_bool enable); -extern sc_bool debug_get_enabled (sc_gameref_t game); -extern void debug_game_started (sc_gameref_t game); -extern void debug_game_ended (sc_gameref_t game); -extern void debug_turn_update (sc_gameref_t game); +extern sc_bool debug_run_command(sc_gameref_t game, + const sc_char *debug_command); +extern sc_bool debug_cmd_debugger(sc_gameref_t game); +extern void debug_set_enabled(sc_gameref_t game, sc_bool enable); +extern sc_bool debug_get_enabled(sc_gameref_t game); +extern void debug_game_started(sc_gameref_t game); +extern void debug_game_ended(sc_gameref_t game); +extern void debug_turn_update(sc_gameref_t game); /* OS interface functions. */ -extern sc_bool if_get_trace_flag (sc_uint bitmask); -extern void if_print_string (const sc_char *string); -extern void if_print_debug (const sc_char *string); -extern void if_print_character (sc_char character); -extern void if_print_debug_character (sc_char character); -extern void if_print_tag (sc_int tag, const sc_char *arg); -extern void if_read_line (sc_char *buffer, sc_int length); -extern void if_read_debug (sc_char *buffer, sc_int length); -extern sc_bool if_confirm (sc_int type); -extern void *if_open_saved_game (sc_bool is_save); -extern void if_write_saved_game (void *opaque, - const sc_byte *buffer, sc_int length); -extern sc_int if_read_saved_game (void *opaque, - sc_byte *buffer, sc_int length); -extern void if_close_saved_game (void *opaque); -extern void if_display_hints (sc_gameref_t game); -extern void if_update_sound (const sc_char *filepath, - sc_int sound_offset, - sc_int sound_length, sc_bool is_looping); -extern void if_update_graphic (const sc_char *filepath, - sc_int graphic_offset, - sc_int graphic_length); +extern sc_bool if_get_trace_flag(sc_uint bitmask); +extern void if_print_string(const sc_char *string); +extern void if_print_debug(const sc_char *string); +extern void if_print_character(sc_char character); +extern void if_print_debug_character(sc_char character); +extern void if_print_tag(sc_int tag, const sc_char *arg); +extern void if_read_line(sc_char *buffer, sc_int length); +extern void if_read_debug(sc_char *buffer, sc_int length); +extern sc_bool if_confirm(sc_int type); +extern void *if_open_saved_game(sc_bool is_save); +extern void if_write_saved_game(void *opaque, + const sc_byte *buffer, sc_int length); +extern sc_int if_read_saved_game(void *opaque, + sc_byte *buffer, sc_int length); +extern void if_close_saved_game(void *opaque); +extern void if_display_hints(sc_gameref_t game); +extern void if_update_sound(const sc_char *filepath, + sc_int sound_offset, + sc_int sound_length, sc_bool is_looping); +extern void if_update_graphic(const sc_char *filepath, + sc_int graphic_offset, + sc_int graphic_length); #endif diff --git a/engines/glk/adrift/scresour.cpp b/engines/glk/adrift/scresour.cpp index bc78bf3dea..739c3d73f6 100644 --- a/engines/glk/adrift/scresour.cpp +++ b/engines/glk/adrift/scresour.cpp @@ -38,31 +38,29 @@ static const sc_char NUL = '\0'; * Return TRUE if the game uses sound or graphics. */ sc_bool -res_has_sound (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_bool has_sound; - assert (gs_is_game_valid (game)); - - vt_key[0].string = "Globals"; - vt_key[1].string = "Sound"; - has_sound = prop_get_boolean (bundle, "B<-ss", vt_key); - return has_sound; +res_has_sound(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_bool has_sound; + assert(gs_is_game_valid(game)); + + vt_key[0].string = "Globals"; + vt_key[1].string = "Sound"; + has_sound = prop_get_boolean(bundle, "B<-ss", vt_key); + return has_sound; } sc_bool -res_has_graphics (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_bool has_graphics; - assert (gs_is_game_valid (game)); - - vt_key[0].string = "Globals"; - vt_key[1].string = "Graphics"; - has_graphics = prop_get_boolean (bundle, "B<-ss", vt_key); - return has_graphics; +res_has_graphics(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_bool has_graphics; + assert(gs_is_game_valid(game)); + + vt_key[0].string = "Globals"; + vt_key[1].string = "Graphics"; + has_graphics = prop_get_boolean(bundle, "B<-ss", vt_key); + return has_graphics; } @@ -74,25 +72,22 @@ res_has_graphics (sc_gameref_t game) * Convenience functions to set, clear, and compare resource fields. */ static void -res_set_resource (sc_resourceref_t resource, const sc_char *name, - sc_int offset, sc_int length) -{ - resource->name = name; - resource->offset = offset; - resource->length = length; +res_set_resource(sc_resourceref_t resource, const sc_char *name, + sc_int offset, sc_int length) { + resource->name = name; + resource->offset = offset; + resource->length = length; } void -res_clear_resource (sc_resourceref_t resource) -{ - res_set_resource (resource, "", 0, 0); +res_clear_resource(sc_resourceref_t resource) { + res_set_resource(resource, "", 0, 0); } sc_bool -res_compare_resource (sc_resourceref_t from, sc_resourceref_t with) -{ - return strcmp (from->name, with->name) == 0 - && from->offset == with->offset && from->length == with->length; +res_compare_resource(sc_resourceref_t from, sc_resourceref_t with) { + return strcmp(from->name, with->name) == 0 + && from->offset == with->offset && from->length == with->length; } @@ -109,157 +104,143 @@ res_compare_resource (sc_resourceref_t from, sc_resourceref_t with) * strlen(partial_format) elements. */ void -res_handle_resource (sc_gameref_t game, - const sc_char *partial_format, - const sc_vartype_t vt_partial[]) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2], *vt_full; - sc_int partial_length, resource_start_offset; - sc_bool embedded; - sc_char *format; - assert (gs_is_game_valid (game)); - assert (partial_format && vt_partial); - - /* - * Check for resources. If this game doesn't use any, exit now to avoid the - * overhead of pointless lookups and allocations. - */ - if (!(res_has_sound (game) || res_has_graphics (game))) - return; - - /* - * Get the global offset for all resources. For version 3.9 games this - * should be zero. For version 4.0 games, it's the start of resource data - * in the TAF file where resources are embedded. - */ - vt_key[0].string = "ResourceOffset"; - resource_start_offset = prop_get_integer (bundle, "I<-s", vt_key); - - /* - * Get the flag that indicated embedded resources. For version 3.9 games - * this should be false. If not set, offset and length are forced to zero - * for interface functions. - */ - vt_key[0].string = "Globals"; - vt_key[1].string = "Embedded"; - embedded = prop_get_boolean (bundle, "B<-ss", vt_key); - - /* - * Allocate a format for use with properties calls, five characters longer - * than the partial passed in. Build a key one element larger than the - * partial supplied, and copy over all supplied elements. - */ - partial_length = strlen (partial_format); - format = (sc_char *)sc_malloc (partial_length + 5); - - vt_full = (sc_vartype_t *)sc_malloc ((partial_length + 1) * sizeof (vt_partial[0])); - memcpy (vt_full, vt_partial, partial_length * sizeof (vt_partial[0])); - - /* Search for sound resources, and offer if found. */ - if (res_has_sound (game)) - { - const sc_char *soundfile; - sc_int soundoffset, soundlen; - - /* Get soundfile property from the node supplied. */ - vt_full[partial_length].string = "SoundFile"; - strcpy (format, "S<-"); - strcat (format, partial_format); - strcat (format, "s"); - soundfile = prop_get_string (bundle, format, vt_full); - - /* If a sound is defined, handle it. */ - if (!sc_strempty (soundfile)) - { - if (embedded) - { - /* Retrieve offset and length. */ - vt_full[partial_length].string = "SoundOffset"; - strcpy (format, "I<-"); - strcat (format, partial_format); - strcat (format, "s"); - soundoffset = prop_get_integer (bundle, format, vt_full) - + resource_start_offset; - - vt_full[partial_length].string = "SoundLen"; - strcpy (format, "I<-"); - strcat (format, partial_format); - strcat (format, "s"); - soundlen = prop_get_integer (bundle, format, vt_full); - } - else - { - /* Coerce offset and length to zero. */ - soundoffset = 0; - soundlen = 0; - } - - /* - * If the sound is the special "##", latch stop, otherwise note - * details to play on sync. - */ - if (!strcmp (soundfile, "##")) - { - game->stop_sound = TRUE; - res_clear_resource (&game->requested_sound); - } - else - { - res_set_resource (&game->requested_sound, - soundfile, soundoffset, soundlen); - } - } - } - - /* Now do the same thing for graphics resources. */ - if (res_has_graphics (game)) - { - const sc_char *graphicfile; - sc_int graphicoffset, graphiclen; - - /* Get graphicfile property from the node supplied. */ - vt_full[partial_length].string = "GraphicFile"; - strcpy (format, "S<-"); - strcat (format, partial_format); - strcat (format, "s"); - graphicfile = prop_get_string (bundle, format, vt_full); - - /* If a graphic is defined, handle it. */ - if (!sc_strempty (graphicfile)) - { - if (embedded) - { - /* Retrieve offset and length. */ - vt_full[partial_length].string = "GraphicOffset"; - strcpy (format, "I<-"); - strcat (format, partial_format); - strcat (format, "s"); - graphicoffset = prop_get_integer (bundle, format, vt_full) - + resource_start_offset; - - vt_full[partial_length].string = "GraphicLen"; - strcpy (format, "I<-"); - strcat (format, partial_format); - strcat (format, "s"); - graphiclen = prop_get_integer (bundle, format, vt_full); - } - else - { - /* Coerce offset and length to zero. */ - graphicoffset = 0; - graphiclen = 0; - } - - /* Graphics resource retrieved, note to show on sync. */ - res_set_resource (&game->requested_graphic, - graphicfile, graphicoffset, graphiclen); - } - } - - /* Free allocated memory. */ - sc_free (format); - sc_free (vt_full); +res_handle_resource(sc_gameref_t game, + const sc_char *partial_format, + const sc_vartype_t vt_partial[]) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2], *vt_full; + sc_int partial_length, resource_start_offset; + sc_bool embedded; + sc_char *format; + assert(gs_is_game_valid(game)); + assert(partial_format && vt_partial); + + /* + * Check for resources. If this game doesn't use any, exit now to avoid the + * overhead of pointless lookups and allocations. + */ + if (!(res_has_sound(game) || res_has_graphics(game))) + return; + + /* + * Get the global offset for all resources. For version 3.9 games this + * should be zero. For version 4.0 games, it's the start of resource data + * in the TAF file where resources are embedded. + */ + vt_key[0].string = "ResourceOffset"; + resource_start_offset = prop_get_integer(bundle, "I<-s", vt_key); + + /* + * Get the flag that indicated embedded resources. For version 3.9 games + * this should be false. If not set, offset and length are forced to zero + * for interface functions. + */ + vt_key[0].string = "Globals"; + vt_key[1].string = "Embedded"; + embedded = prop_get_boolean(bundle, "B<-ss", vt_key); + + /* + * Allocate a format for use with properties calls, five characters longer + * than the partial passed in. Build a key one element larger than the + * partial supplied, and copy over all supplied elements. + */ + partial_length = strlen(partial_format); + format = (sc_char *)sc_malloc(partial_length + 5); + + vt_full = (sc_vartype_t *)sc_malloc((partial_length + 1) * sizeof(vt_partial[0])); + memcpy(vt_full, vt_partial, partial_length * sizeof(vt_partial[0])); + + /* Search for sound resources, and offer if found. */ + if (res_has_sound(game)) { + const sc_char *soundfile; + sc_int soundoffset, soundlen; + + /* Get soundfile property from the node supplied. */ + vt_full[partial_length].string = "SoundFile"; + strcpy(format, "S<-"); + strcat(format, partial_format); + strcat(format, "s"); + soundfile = prop_get_string(bundle, format, vt_full); + + /* If a sound is defined, handle it. */ + if (!sc_strempty(soundfile)) { + if (embedded) { + /* Retrieve offset and length. */ + vt_full[partial_length].string = "SoundOffset"; + strcpy(format, "I<-"); + strcat(format, partial_format); + strcat(format, "s"); + soundoffset = prop_get_integer(bundle, format, vt_full) + + resource_start_offset; + + vt_full[partial_length].string = "SoundLen"; + strcpy(format, "I<-"); + strcat(format, partial_format); + strcat(format, "s"); + soundlen = prop_get_integer(bundle, format, vt_full); + } else { + /* Coerce offset and length to zero. */ + soundoffset = 0; + soundlen = 0; + } + + /* + * If the sound is the special "##", latch stop, otherwise note + * details to play on sync. + */ + if (!strcmp(soundfile, "##")) { + game->stop_sound = TRUE; + res_clear_resource(&game->requested_sound); + } else { + res_set_resource(&game->requested_sound, + soundfile, soundoffset, soundlen); + } + } + } + + /* Now do the same thing for graphics resources. */ + if (res_has_graphics(game)) { + const sc_char *graphicfile; + sc_int graphicoffset, graphiclen; + + /* Get graphicfile property from the node supplied. */ + vt_full[partial_length].string = "GraphicFile"; + strcpy(format, "S<-"); + strcat(format, partial_format); + strcat(format, "s"); + graphicfile = prop_get_string(bundle, format, vt_full); + + /* If a graphic is defined, handle it. */ + if (!sc_strempty(graphicfile)) { + if (embedded) { + /* Retrieve offset and length. */ + vt_full[partial_length].string = "GraphicOffset"; + strcpy(format, "I<-"); + strcat(format, partial_format); + strcat(format, "s"); + graphicoffset = prop_get_integer(bundle, format, vt_full) + + resource_start_offset; + + vt_full[partial_length].string = "GraphicLen"; + strcpy(format, "I<-"); + strcat(format, partial_format); + strcat(format, "s"); + graphiclen = prop_get_integer(bundle, format, vt_full); + } else { + /* Coerce offset and length to zero. */ + graphicoffset = 0; + graphiclen = 0; + } + + /* Graphics resource retrieved, note to show on sync. */ + res_set_resource(&game->requested_graphic, + graphicfile, graphicoffset, graphiclen); + } + } + + /* Free allocated memory. */ + sc_free(format); + sc_free(vt_full); } @@ -270,58 +251,53 @@ res_handle_resource (sc_gameref_t game, * restore, and so on. */ void -res_sync_resources (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); - - /* Deal with any latched sound stop first. */ - if (game->stop_sound) - { - if (game->sound_active) - { - if_update_sound ("", 0, 0, FALSE); - game->sound_active = FALSE; - - res_clear_resource (&game->playing_sound); - } - game->stop_sound = FALSE; - } - - /* Look for a change of sound, and pass to interface on change. */ - if (!res_compare_resource (&game->playing_sound, - &game->requested_sound)) - { - const sc_char *name; - sc_char *clean_name; - sc_bool is_looping; - - /* If the sound name ends '##', this is a looping sound. */ - name = game->requested_sound.name; - is_looping = !strcmp (name + strlen (name) - 2, "##"); - - clean_name = (sc_char *)sc_malloc (strlen (name) + 1); - strcpy (clean_name, name); - if (is_looping) - clean_name[strlen (clean_name) - 2] = NUL; - - if_update_sound (clean_name, - game->requested_sound.offset, - game->requested_sound.length, is_looping); - game->playing_sound = game->requested_sound; - game->sound_active = TRUE; - - sc_free (clean_name); - } - - /* Look for a change of graphic, and pass to interface on change. */ - if (!res_compare_resource (&game->displayed_graphic, - &game->requested_graphic)) - { - if_update_graphic (game->requested_graphic.name, - game->requested_graphic.offset, - game->requested_graphic.length); - game->displayed_graphic = game->requested_graphic; - } +res_sync_resources(sc_gameref_t game) { + assert(gs_is_game_valid(game)); + + /* Deal with any latched sound stop first. */ + if (game->stop_sound) { + if (game->sound_active) { + if_update_sound("", 0, 0, FALSE); + game->sound_active = FALSE; + + res_clear_resource(&game->playing_sound); + } + game->stop_sound = FALSE; + } + + /* Look for a change of sound, and pass to interface on change. */ + if (!res_compare_resource(&game->playing_sound, + &game->requested_sound)) { + const sc_char *name; + sc_char *clean_name; + sc_bool is_looping; + + /* If the sound name ends '##', this is a looping sound. */ + name = game->requested_sound.name; + is_looping = !strcmp(name + strlen(name) - 2, "##"); + + clean_name = (sc_char *)sc_malloc(strlen(name) + 1); + strcpy(clean_name, name); + if (is_looping) + clean_name[strlen(clean_name) - 2] = NUL; + + if_update_sound(clean_name, + game->requested_sound.offset, + game->requested_sound.length, is_looping); + game->playing_sound = game->requested_sound; + game->sound_active = TRUE; + + sc_free(clean_name); + } + + /* Look for a change of graphic, and pass to interface on change. */ + if (!res_compare_resource(&game->displayed_graphic, + &game->requested_graphic)) { + if_update_graphic(game->requested_graphic.name, + game->requested_graphic.offset, + game->requested_graphic.length); + game->displayed_graphic = game->requested_graphic; + } } @@ -332,17 +308,16 @@ res_sync_resources (sc_gameref_t game) * use to match. Called on game restart or restore. */ void -res_cancel_resources (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); +res_cancel_resources(sc_gameref_t game) { + assert(gs_is_game_valid(game)); - /* Request that everything stops and clears. */ - game->stop_sound = FALSE; - res_clear_resource (&game->requested_sound); - res_clear_resource (&game->requested_graphic); + /* Request that everything stops and clears. */ + game->stop_sound = FALSE; + res_clear_resource(&game->requested_sound); + res_clear_resource(&game->requested_graphic); - /* Synchronize to have the above take effect. */ - res_sync_resources (game); + /* Synchronize to have the above take effect. */ + res_sync_resources(game); } } // End of namespace Adrift diff --git a/engines/glk/adrift/screstrs.cpp b/engines/glk/adrift/screstrs.cpp index 549ae5a50d..3f1db887f4 100644 --- a/engines/glk/adrift/screstrs.cpp +++ b/engines/glk/adrift/screstrs.cpp @@ -41,29 +41,27 @@ static sc_bool restr_trace = FALSE; * Return the index of the n'th integer found. */ static sc_int -restr_integer_variable (sc_gameref_t game, sc_int n) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int var_count, var, count; - - /* Get the count of variables. */ - vt_key[0].string = "Variables"; - var_count = prop_get_child_count (bundle, "I<-s", vt_key); - - /* Progress through variables until n integers found. */ - count = n; - for (var = 0; var < var_count && count >= 0; var++) - { - sc_int type; - - vt_key[1].integer = var; - vt_key[2].string = "Type"; - type = prop_get_integer (bundle, "I<-sis", vt_key); - if (type == TAFVAR_NUMERIC) - count--; - } - return var - 1; +restr_integer_variable(sc_gameref_t game, sc_int n) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int var_count, var, count; + + /* Get the count of variables. */ + vt_key[0].string = "Variables"; + var_count = prop_get_child_count(bundle, "I<-s", vt_key); + + /* Progress through variables until n integers found. */ + count = n; + for (var = 0; var < var_count && count >= 0; var++) { + sc_int type; + + vt_key[1].integer = var; + vt_key[2].string = "Type"; + type = prop_get_integer(bundle, "I<-sis", vt_key); + if (type == TAFVAR_NUMERIC) + count--; + } + return var - 1; } @@ -73,87 +71,84 @@ restr_integer_variable (sc_gameref_t game, sc_int n) * Is object in a certain place, state, or condition. */ static sc_bool -restr_object_in_place (sc_gameref_t game, - sc_int object, sc_int var2, sc_int var3) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int npc; - - if (restr_trace) - { - sc_trace ("Restr: checking" - " object in place, %ld, %ld, %ld\n", object, var2, var3); - } - - /* Var2 controls what we do. */ - switch (var2) - { - case 0: - case 6: /* In room */ - if (var3 == 0) - return gs_object_position (game, object) == OBJ_HIDDEN; - else - return gs_object_position (game, object) == var3; - - case 1: - case 7: /* Held by */ - if (var3 == 0) /* Player */ - return gs_object_position (game, object) == OBJ_HELD_PLAYER; - else if (var3 == 1) /* Ref character */ - npc = var_get_ref_character (vars); - else - npc = var3 - 2; - - return gs_object_position (game, object) == OBJ_HELD_NPC - && gs_object_parent (game, object) == npc; - - case 2: - case 8: /* Worn by */ - if (var3 == 0) /* Player */ - return gs_object_position (game, object) == OBJ_WORN_PLAYER; - else if (var3 == 1) /* Ref character */ - npc = var_get_ref_character (vars); - else - npc = var3 - 2; - - return gs_object_position (game, object) == OBJ_WORN_NPC - && gs_object_parent (game, object) == npc; - - case 3: - case 9: /* Visible to */ - if (var3 == 0) /* Player */ - return obj_indirectly_in_room (game, - object, gs_playerroom (game)); - else if (var3 == 1) /* Ref character */ - npc = var_get_ref_character (vars); - else - npc = var3 - 2; - - return obj_indirectly_in_room (game, object, - gs_npc_location (game, npc) - 1); - - case 4: - case 10: /* Inside */ - if (var3 == 0) /* Nothing? */ - return gs_object_position (game, object) != OBJ_IN_OBJECT; - - return gs_object_position (game, object) == OBJ_IN_OBJECT - && gs_object_parent (game, object) == obj_container_object (game, - var3 - 1); - - case 5: - case 11: /* On top of */ - if (var3 == 0) /* Nothing? */ - return gs_object_position (game, object) != OBJ_ON_OBJECT; - - return gs_object_position (game, object) == OBJ_ON_OBJECT - && gs_object_parent (game, object) == obj_surface_object (game, - var3 - 1); - - default: - sc_fatal ("restr_object_in_place: bad var2, %ld\n", var2); - return FALSE; - } +restr_object_in_place(sc_gameref_t game, + sc_int object, sc_int var2, sc_int var3) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int npc; + + if (restr_trace) { + sc_trace("Restr: checking" + " object in place, %ld, %ld, %ld\n", object, var2, var3); + } + + /* Var2 controls what we do. */ + switch (var2) { + case 0: + case 6: /* In room */ + if (var3 == 0) + return gs_object_position(game, object) == OBJ_HIDDEN; + else + return gs_object_position(game, object) == var3; + + case 1: + case 7: /* Held by */ + if (var3 == 0) /* Player */ + return gs_object_position(game, object) == OBJ_HELD_PLAYER; + else if (var3 == 1) /* Ref character */ + npc = var_get_ref_character(vars); + else + npc = var3 - 2; + + return gs_object_position(game, object) == OBJ_HELD_NPC + && gs_object_parent(game, object) == npc; + + case 2: + case 8: /* Worn by */ + if (var3 == 0) /* Player */ + return gs_object_position(game, object) == OBJ_WORN_PLAYER; + else if (var3 == 1) /* Ref character */ + npc = var_get_ref_character(vars); + else + npc = var3 - 2; + + return gs_object_position(game, object) == OBJ_WORN_NPC + && gs_object_parent(game, object) == npc; + + case 3: + case 9: /* Visible to */ + if (var3 == 0) /* Player */ + return obj_indirectly_in_room(game, + object, gs_playerroom(game)); + else if (var3 == 1) /* Ref character */ + npc = var_get_ref_character(vars); + else + npc = var3 - 2; + + return obj_indirectly_in_room(game, object, + gs_npc_location(game, npc) - 1); + + case 4: + case 10: /* Inside */ + if (var3 == 0) /* Nothing? */ + return gs_object_position(game, object) != OBJ_IN_OBJECT; + + return gs_object_position(game, object) == OBJ_IN_OBJECT + && gs_object_parent(game, object) == obj_container_object(game, + var3 - 1); + + case 5: + case 11: /* On top of */ + if (var3 == 0) /* Nothing? */ + return gs_object_position(game, object) != OBJ_ON_OBJECT; + + return gs_object_position(game, object) == OBJ_ON_OBJECT + && gs_object_parent(game, object) == obj_surface_object(game, + var3 - 1); + + default: + sc_fatal("restr_object_in_place: bad var2, %ld\n", var2); + return FALSE; + } } @@ -163,78 +158,70 @@ restr_object_in_place (sc_gameref_t game, * Evaluate restrictions relating to object location. */ static sc_bool -restr_pass_task_object_location (sc_gameref_t game, - sc_int var1, sc_int var2, sc_int var3) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_bool should_be; - sc_int object; - - if (restr_trace) - { - sc_trace ("Restr: running object" - " location restriction, %ld, %ld, %ld\n", var1, var2, var3); - } - - /* Initialize variables to avoid gcc warnings. */ - should_be = FALSE; - object = -1; - - /* See how things should look. */ - if (var2 >= 0 && var2 < 6) - should_be = TRUE; - else if (var2 >= 6 && var2 < 12) - should_be = FALSE; - else - sc_fatal ("restr_pass_task_object_location: bad var2, %ld\n", var2); - - /* Now find the addressed object. */ - if (var1 == 0) - { - object = -1; /* No object */ - should_be = !should_be; - } - else if (var1 == 1) - object = -1; /* Any object */ - else if (var1 == 2) - object = var_get_ref_object (vars); - else if (var1 >= 3) - object = obj_dynamic_object (game, var1 - 3); - else - sc_fatal ("restr_pass_task_object_location: bad var1, %ld\n", var1); - - /* - * Here it seems that we have to special case static objects that may have - * crept in through the referenced object. The object in place function - * isn't built to handle these. - * - * TODO What is the meaning of applying object restrictions to static - * objects? - */ - if (var1 == 2 && object != -1 && obj_is_static (game, object)) - { - if (restr_trace) - { - sc_trace ("Restr:" - " restriction object %ld is static, rejecting\n", object); - } - - return FALSE; - } - - /* Try to put it all together. */ - if (object == -1) - { - sc_int target; - - for (target = 0; target < gs_object_count (game); target++) - { - if (restr_object_in_place (game, target, var2, var3)) - return should_be; - } - return !should_be; - } - return should_be == restr_object_in_place (game, object, var2, var3); +restr_pass_task_object_location(sc_gameref_t game, + sc_int var1, sc_int var2, sc_int var3) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_bool should_be; + sc_int object; + + if (restr_trace) { + sc_trace("Restr: running object" + " location restriction, %ld, %ld, %ld\n", var1, var2, var3); + } + + /* Initialize variables to avoid gcc warnings. */ + should_be = FALSE; + object = -1; + + /* See how things should look. */ + if (var2 >= 0 && var2 < 6) + should_be = TRUE; + else if (var2 >= 6 && var2 < 12) + should_be = FALSE; + else + sc_fatal("restr_pass_task_object_location: bad var2, %ld\n", var2); + + /* Now find the addressed object. */ + if (var1 == 0) { + object = -1; /* No object */ + should_be = !should_be; + } else if (var1 == 1) + object = -1; /* Any object */ + else if (var1 == 2) + object = var_get_ref_object(vars); + else if (var1 >= 3) + object = obj_dynamic_object(game, var1 - 3); + else + sc_fatal("restr_pass_task_object_location: bad var1, %ld\n", var1); + + /* + * Here it seems that we have to special case static objects that may have + * crept in through the referenced object. The object in place function + * isn't built to handle these. + * + * TODO What is the meaning of applying object restrictions to static + * objects? + */ + if (var1 == 2 && object != -1 && obj_is_static(game, object)) { + if (restr_trace) { + sc_trace("Restr:" + " restriction object %ld is static, rejecting\n", object); + } + + return FALSE; + } + + /* Try to put it all together. */ + if (object == -1) { + sc_int target; + + for (target = 0; target < gs_object_count(game); target++) { + if (restr_object_in_place(game, target, var2, var3)) + return should_be; + } + return !should_be; + } + return should_be == restr_object_in_place(game, object, var2, var3); } @@ -245,52 +232,45 @@ restr_pass_task_object_location (sc_gameref_t game, * from the library by lib_pass_alt_room(), so cannot be static. */ sc_bool -restr_pass_task_object_state (sc_gameref_t game, sc_int var1, sc_int var2) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[3]; - sc_int object, openable, key; - - if (restr_trace) - { - sc_trace ("Restr:" - " running object state restriction, %ld, %ld\n", var1, var2); - } - - /* Find the object being addressed. */ - if (var1 == 0) - object = var_get_ref_object (vars); - else - object = obj_stateful_object (game, var1 - 1); - - /* We're interested only in openable objects. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Openable"; - openable = prop_get_integer (bundle, "I<-sis", vt_key); - if (openable > 0) - { - /* Is this object lockable? */ - vt_key[2].string = "Key"; - key = prop_get_integer (bundle, "I<-sis", vt_key); - if (key >= 0) - { - if (var2 <= 2) - return gs_object_openness (game, object) == var2 + 5; - else - return gs_object_state (game, object) == var2 - 2; - } - else - { - if (var2 <= 1) - return gs_object_openness (game, object) == var2 + 5; - else - return gs_object_state (game, object) == var2 - 1; - } - } - else - return gs_object_state (game, object) == var2 + 1; +restr_pass_task_object_state(sc_gameref_t game, sc_int var1, sc_int var2) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[3]; + sc_int object, openable, key; + + if (restr_trace) { + sc_trace("Restr:" + " running object state restriction, %ld, %ld\n", var1, var2); + } + + /* Find the object being addressed. */ + if (var1 == 0) + object = var_get_ref_object(vars); + else + object = obj_stateful_object(game, var1 - 1); + + /* We're interested only in openable objects. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Openable"; + openable = prop_get_integer(bundle, "I<-sis", vt_key); + if (openable > 0) { + /* Is this object lockable? */ + vt_key[2].string = "Key"; + key = prop_get_integer(bundle, "I<-sis", vt_key); + if (key >= 0) { + if (var2 <= 2) + return gs_object_openness(game, object) == var2 + 5; + else + return gs_object_state(game, object) == var2 - 2; + } else { + if (var2 <= 1) + return gs_object_openness(game, object) == var2 + 5; + else + return gs_object_state(game, object) == var2 - 1; + } + } else + return gs_object_state(game, object) == var2 + 1; } @@ -300,39 +280,36 @@ restr_pass_task_object_state (sc_gameref_t game, sc_int var1, sc_int var2) * Evaluate restrictions relating to task states. */ static sc_bool -restr_pass_task_task_state (sc_gameref_t game, sc_int var1, sc_int var2) -{ - sc_bool should_be; - - if (restr_trace) - sc_trace ("Restr: running task restriction, %ld, %ld\n", var1, var2); - - /* Initialize variables to avoid gcc warnings. */ - should_be = FALSE; - - /* See if the task should be done or not done. */ - if (var2 == 0) - should_be = TRUE; - else if (var2 == 1) - should_be = FALSE; - else - sc_fatal ("restr_pass_task_task_state: bad var2, %ld\n", var2); - - /* Check all tasks? */ - if (var1 == 0) - { - sc_int task; - - for (task = 0; task < gs_task_count (game); task++) - { - if (gs_task_done (game, task) == should_be) - return FALSE; - } - return TRUE; - } - - /* Check just the given task. */ - return gs_task_done (game, var1 - 1) == should_be; +restr_pass_task_task_state(sc_gameref_t game, sc_int var1, sc_int var2) { + sc_bool should_be; + + if (restr_trace) + sc_trace("Restr: running task restriction, %ld, %ld\n", var1, var2); + + /* Initialize variables to avoid gcc warnings. */ + should_be = FALSE; + + /* See if the task should be done or not done. */ + if (var2 == 0) + should_be = TRUE; + else if (var2 == 1) + should_be = FALSE; + else + sc_fatal("restr_pass_task_task_state: bad var2, %ld\n", var2); + + /* Check all tasks? */ + if (var1 == 0) { + sc_int task; + + for (task = 0; task < gs_task_count(game); task++) { + if (gs_task_done(game, task) == should_be) + return FALSE; + } + return TRUE; + } + + /* Check just the given task. */ + return gs_task_done(game, var1 - 1) == should_be; } @@ -342,123 +319,116 @@ restr_pass_task_task_state (sc_gameref_t game, sc_int var1, sc_int var2) * Evaluate restrictions relating to player and NPCs. */ static sc_bool -restr_pass_task_char (sc_gameref_t game, sc_int var1, sc_int var2, sc_int var3) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int npc1, npc2; - - if (restr_trace) - { - sc_trace ("Restr:" - " running char restriction, %ld, %ld, %ld\n", var1, var2, var3); - } - - /* Handle var2 types 1 and 2. */ - if (var2 == 1) /* Not in same room as */ - return !restr_pass_task_char (game, var1, 0, var3); - else if (var2 == 2) /* Alone */ - return !restr_pass_task_char (game, var1, 3, var3); - - /* Decode NPC number, -1 if none. */ - npc1 = npc2 = -1; - if (var1 == 1) - npc1 = var_get_ref_character (vars); - else if (var1 > 1) - npc1 = var1 - 2; - - /* Player or NPC? */ - if (var1 == 0) - { - sc_vartype_t vt_key[2]; - sc_int gender; - - /* Player -- decode based on var2. */ - switch (var2) - { - case 0: /* In same room as */ - if (var3 == 1) - npc2 = var_get_ref_character (vars); - else if (var3 > 1) - npc2 = var3 - 2; - if (var3 == 0) /* Player */ - return TRUE; - else - return npc_in_room (game, npc2, gs_playerroom (game)); - - case 3: /* Not alone */ - return npc_count_in_room (game, gs_playerroom (game)) > 1; - - case 4: /* Standing on */ - return gs_playerposition (game) == 0 - && gs_playerparent (game) == obj_standable_object (game, - var3 - 1); - - case 5: /* Sitting on */ - return gs_playerposition (game) == 1 - && gs_playerparent (game) == obj_standable_object (game, - var3 - 1); - - case 6: /* Lying on */ - return gs_playerposition (game) == 2 - && gs_playerparent (game) == obj_lieable_object (game, - var3 - 1); - - case 7: /* Player gender */ - vt_key[0].string = "Globals"; - vt_key[1].string = "PlayerGender"; - gender = prop_get_integer (bundle, "I<-ss", vt_key); - return gender == var3; - - default: - sc_fatal ("restr_pass_task_char: invalid type, %ld\n", var2); - return FALSE; - } - } - else - { - sc_vartype_t vt_key[3]; - sc_int gender; - - /* NPC -- decode based on var2. */ - switch (var2) - { - case 0: /* In same room as */ - if (var3 == 0) - return npc_in_room (game, npc1, gs_playerroom (game)); - if (var3 == 1) - npc2 = var_get_ref_character (vars); - else if (var3 > 1) - npc2 = var3 - 2; - return npc_in_room (game, npc1, gs_npc_location (game, npc2) - 1); - - case 3: /* Not alone */ - return npc_count_in_room (game, gs_npc_location (game, npc1) - 1) > 1; - - case 4: /* Standing on */ - return gs_npc_position (game, npc1) == 0 - && gs_playerparent (game) == obj_standable_object (game, var3); - - case 5: /* Sitting on */ - return gs_npc_position (game, npc1) == 1 - && gs_playerparent (game) == obj_standable_object (game, var3); - - case 6: /* Lying on */ - return gs_npc_position (game, npc1) == 2 - && gs_playerparent (game) == obj_lieable_object (game, var3); - - case 7: /* NPC gender */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = npc1; - vt_key[2].string = "Gender"; - gender = prop_get_integer (bundle, "I<-sis", vt_key); - return gender == var3; - - default: - sc_fatal ("restr_pass_task_char: invalid type, %ld\n", var2); - return FALSE; - } - } +restr_pass_task_char(sc_gameref_t game, sc_int var1, sc_int var2, sc_int var3) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int npc1, npc2; + + if (restr_trace) { + sc_trace("Restr:" + " running char restriction, %ld, %ld, %ld\n", var1, var2, var3); + } + + /* Handle var2 types 1 and 2. */ + if (var2 == 1) /* Not in same room as */ + return !restr_pass_task_char(game, var1, 0, var3); + else if (var2 == 2) /* Alone */ + return !restr_pass_task_char(game, var1, 3, var3); + + /* Decode NPC number, -1 if none. */ + npc1 = npc2 = -1; + if (var1 == 1) + npc1 = var_get_ref_character(vars); + else if (var1 > 1) + npc1 = var1 - 2; + + /* Player or NPC? */ + if (var1 == 0) { + sc_vartype_t vt_key[2]; + sc_int gender; + + /* Player -- decode based on var2. */ + switch (var2) { + case 0: /* In same room as */ + if (var3 == 1) + npc2 = var_get_ref_character(vars); + else if (var3 > 1) + npc2 = var3 - 2; + if (var3 == 0) /* Player */ + return TRUE; + else + return npc_in_room(game, npc2, gs_playerroom(game)); + + case 3: /* Not alone */ + return npc_count_in_room(game, gs_playerroom(game)) > 1; + + case 4: /* Standing on */ + return gs_playerposition(game) == 0 + && gs_playerparent(game) == obj_standable_object(game, + var3 - 1); + + case 5: /* Sitting on */ + return gs_playerposition(game) == 1 + && gs_playerparent(game) == obj_standable_object(game, + var3 - 1); + + case 6: /* Lying on */ + return gs_playerposition(game) == 2 + && gs_playerparent(game) == obj_lieable_object(game, + var3 - 1); + + case 7: /* Player gender */ + vt_key[0].string = "Globals"; + vt_key[1].string = "PlayerGender"; + gender = prop_get_integer(bundle, "I<-ss", vt_key); + return gender == var3; + + default: + sc_fatal("restr_pass_task_char: invalid type, %ld\n", var2); + return FALSE; + } + } else { + sc_vartype_t vt_key[3]; + sc_int gender; + + /* NPC -- decode based on var2. */ + switch (var2) { + case 0: /* In same room as */ + if (var3 == 0) + return npc_in_room(game, npc1, gs_playerroom(game)); + if (var3 == 1) + npc2 = var_get_ref_character(vars); + else if (var3 > 1) + npc2 = var3 - 2; + return npc_in_room(game, npc1, gs_npc_location(game, npc2) - 1); + + case 3: /* Not alone */ + return npc_count_in_room(game, gs_npc_location(game, npc1) - 1) > 1; + + case 4: /* Standing on */ + return gs_npc_position(game, npc1) == 0 + && gs_playerparent(game) == obj_standable_object(game, var3); + + case 5: /* Sitting on */ + return gs_npc_position(game, npc1) == 1 + && gs_playerparent(game) == obj_standable_object(game, var3); + + case 6: /* Lying on */ + return gs_npc_position(game, npc1) == 2 + && gs_playerparent(game) == obj_lieable_object(game, var3); + + case 7: /* NPC gender */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = npc1; + vt_key[2].string = "Gender"; + gender = prop_get_integer(bundle, "I<-sis", vt_key); + return gender == var3; + + default: + sc_fatal("restr_pass_task_char: invalid type, %ld\n", var2); + return FALSE; + } + } } @@ -468,88 +438,82 @@ restr_pass_task_char (sc_gameref_t game, sc_int var1, sc_int var2, sc_int var3) * Helper for restr_pass_task_var(), handles integer variable restrictions. */ static sc_bool -restr_pass_task_int_var (sc_gameref_t game, - sc_int var2, sc_int var3, sc_int value) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[3]; - sc_int value2; - - if (restr_trace) - { - sc_trace ("Restr: running" - " integer var restriction, %ld, %ld, %ld\n", var2, var3, value); - } - - /* Compare against var3 if that's what var2 says. */ - switch (var2) - { - case 0: - return value < var3; - case 1: - return value <= var3; - case 2: - return value == var3; - case 3: - return value >= var3; - case 4: - return value > var3; - case 5: - return value != var3; - - default: - /* - * Compare against the integer var numbered in var3 - 1, or the - * referenced number if var3 is zero. Make sure that we're comparing - * integer variables. - */ - if (var3 == 0) - value2 = var_get_ref_number (vars); - else - { - const sc_char *name; - sc_int ivar, type; - - ivar = restr_integer_variable (game, var3 - 1); - vt_key[0].string = "Variables"; - vt_key[1].integer = ivar; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Type"; - type = prop_get_integer (bundle, "I<-sis", vt_key); - - if (type != TAFVAR_NUMERIC) - { - sc_fatal ("restr_pass_task_int_var:" - " non-integer in comparison, %s\n", name); - } - - /* Get the value in variable numbered in var3 - 1. */ - value2 = var_get_integer (vars, name); - } - - switch (var2) - { - case 10: - return value < value2; - case 11: - return value <= value2; - case 12: - return value == value2; - case 13: - return value >= value2; - case 14: - return value > value2; - case 15: - return value != value2; - - default: - sc_fatal ("restr_pass_task_int_var:" - " unknown int comparison, %ld\n", var2); - return FALSE; - } - } +restr_pass_task_int_var(sc_gameref_t game, + sc_int var2, sc_int var3, sc_int value) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[3]; + sc_int value2; + + if (restr_trace) { + sc_trace("Restr: running" + " integer var restriction, %ld, %ld, %ld\n", var2, var3, value); + } + + /* Compare against var3 if that's what var2 says. */ + switch (var2) { + case 0: + return value < var3; + case 1: + return value <= var3; + case 2: + return value == var3; + case 3: + return value >= var3; + case 4: + return value > var3; + case 5: + return value != var3; + + default: + /* + * Compare against the integer var numbered in var3 - 1, or the + * referenced number if var3 is zero. Make sure that we're comparing + * integer variables. + */ + if (var3 == 0) + value2 = var_get_ref_number(vars); + else { + const sc_char *name; + sc_int ivar, type; + + ivar = restr_integer_variable(game, var3 - 1); + vt_key[0].string = "Variables"; + vt_key[1].integer = ivar; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Type"; + type = prop_get_integer(bundle, "I<-sis", vt_key); + + if (type != TAFVAR_NUMERIC) { + sc_fatal("restr_pass_task_int_var:" + " non-integer in comparison, %s\n", name); + } + + /* Get the value in variable numbered in var3 - 1. */ + value2 = var_get_integer(vars, name); + } + + switch (var2) { + case 10: + return value < value2; + case 11: + return value <= value2; + case 12: + return value == value2; + case 13: + return value >= value2; + case 14: + return value > value2; + case 15: + return value != value2; + + default: + sc_fatal("restr_pass_task_int_var:" + " unknown int comparison, %ld\n", var2); + return FALSE; + } + } } @@ -559,28 +523,25 @@ restr_pass_task_int_var (sc_gameref_t game, * Helper for restr_pass_task_var(), handles string variable restrictions. */ static sc_bool -restr_pass_task_string_var (sc_int var2, - const sc_char *var4, const sc_char *value) -{ - if (restr_trace) - { - sc_trace ("Restr: running string" - " var restriction, %ld, \"%s\", \"%s\"\n", var2, var4, value); - } - - /* Make comparison against var4 based on var2 value. */ - switch (var2) - { - case 0: - return strcmp (value, var4) == 0; /* == */ - case 1: - return strcmp (value, var4) != 0; /* != */ - - default: - sc_fatal ("restr_pass_task_string_var:" - " unknown string comparison, %ld\n", var2); - return FALSE; - } +restr_pass_task_string_var(sc_int var2, + const sc_char *var4, const sc_char *value) { + if (restr_trace) { + sc_trace("Restr: running string" + " var restriction, %ld, \"%s\", \"%s\"\n", var2, var4, value); + } + + /* Make comparison against var4 based on var2 value. */ + switch (var2) { + case 0: + return strcmp(value, var4) == 0; /* == */ + case 1: + return strcmp(value, var4) != 0; /* != */ + + default: + sc_fatal("restr_pass_task_string_var:" + " unknown string comparison, %ld\n", var2); + return FALSE; + } } @@ -590,60 +551,54 @@ restr_pass_task_string_var (sc_int var2, * Evaluate restrictions relating to variables. */ static sc_bool -restr_pass_task_var (sc_gameref_t game, - sc_int var1, sc_int var2, sc_int var3, - const sc_char *var4) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[3]; - sc_int type, value; - const sc_char *name, *string; - - if (restr_trace) - { - sc_trace ("Restr: running var restriction," - " %ld, %ld, %ld, \"%s\"\n", var1, var2, var3, var4); - } - - /* - * For var1=0, compare against referenced number. For var1=1, compare - * against referenced text. - */ - if (var1 == 0) - { - value = var_get_ref_number (vars); - return restr_pass_task_int_var (game, var2, var3, value); - } - else if (var1 == 1) - { - string = var_get_ref_text (vars); - return restr_pass_task_string_var (var2, var4, string); - } - - /* Get the name and type of the variable being addressed. */ - vt_key[0].string = "Variables"; - vt_key[1].integer = var1 - 2; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Type"; - type = prop_get_integer (bundle, "I<-sis", vt_key); - - /* Select first based on variable type. */ - switch (type) - { - case TAFVAR_NUMERIC: - value = var_get_integer (vars, name); - return restr_pass_task_int_var (game, var2, var3, value); - - case TAFVAR_STRING: - string = var_get_string (vars, name); - return restr_pass_task_string_var (var2, var4, string); - - default: - sc_fatal ("restr_pass_task_var: invalid variable type, %ld\n", type); - return FALSE; - } +restr_pass_task_var(sc_gameref_t game, + sc_int var1, sc_int var2, sc_int var3, + const sc_char *var4) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[3]; + sc_int type, value; + const sc_char *name, *string; + + if (restr_trace) { + sc_trace("Restr: running var restriction," + " %ld, %ld, %ld, \"%s\"\n", var1, var2, var3, var4); + } + + /* + * For var1=0, compare against referenced number. For var1=1, compare + * against referenced text. + */ + if (var1 == 0) { + value = var_get_ref_number(vars); + return restr_pass_task_int_var(game, var2, var3, value); + } else if (var1 == 1) { + string = var_get_ref_text(vars); + return restr_pass_task_string_var(var2, var4, string); + } + + /* Get the name and type of the variable being addressed. */ + vt_key[0].string = "Variables"; + vt_key[1].integer = var1 - 2; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Type"; + type = prop_get_integer(bundle, "I<-sis", vt_key); + + /* Select first based on variable type. */ + switch (type) { + case TAFVAR_NUMERIC: + value = var_get_integer(vars, name); + return restr_pass_task_int_var(game, var2, var3, value); + + case TAFVAR_STRING: + string = var_get_string(vars, name); + return restr_pass_task_string_var(var2, var4, string); + + default: + sc_fatal("restr_pass_task_var: invalid variable type, %ld\n", type); + return FALSE; + } } @@ -653,102 +608,98 @@ restr_pass_task_var (sc_gameref_t game, * Demultiplexer for task restrictions. */ static sc_bool -restr_pass_task_restriction (sc_gameref_t game, sc_int task, sc_int restriction) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int type, var1, var2, var3; - const sc_char *var4; - sc_bool result = FALSE; - - if (restr_trace) - { - sc_trace ("Restr:" - " evaluating task %ld restriction %ld\n", task, restriction); - } - - /* Get the task restriction type. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Restrictions"; - vt_key[3].integer = restriction; - vt_key[4].string = "Type"; - type = prop_get_integer (bundle, "I<-sisis", vt_key); - - /* Demultiplex depending on type. */ - switch (type) - { - case 0: /* Object location. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - result = restr_pass_task_object_location (game, var1, var2, var3); - break; - - case 1: /* Object state. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - result = restr_pass_task_object_state (game, var1, var2); - break; - - case 2: /* Task state. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - result = restr_pass_task_task_state (game, var1, var2); - break; - - case 3: /* Player and NPCs. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - result = restr_pass_task_char (game, var1, var2, var3); - break; - - case 4: /* Variable. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var4"; - var4 = prop_get_string (bundle, "S<-sisis", vt_key); - result = restr_pass_task_var (game, var1, var2, var3, var4); - break; - - default: - sc_fatal ("restr_pass_task_restriction:" - " unknown restriction type %ld\n", type); - } - - if (restr_trace) - { - sc_trace ("Restr: task %ld restriction" - " %ld is %s\n", task, restriction, result ? "PASS" : "FAIL"); - } - - return result; +restr_pass_task_restriction(sc_gameref_t game, sc_int task, sc_int restriction) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int type, var1, var2, var3; + const sc_char *var4; + sc_bool result = FALSE; + + if (restr_trace) { + sc_trace("Restr:" + " evaluating task %ld restriction %ld\n", task, restriction); + } + + /* Get the task restriction type. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Restrictions"; + vt_key[3].integer = restriction; + vt_key[4].string = "Type"; + type = prop_get_integer(bundle, "I<-sisis", vt_key); + + /* Demultiplex depending on type. */ + switch (type) { + case 0: /* Object location. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + result = restr_pass_task_object_location(game, var1, var2, var3); + break; + + case 1: /* Object state. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + result = restr_pass_task_object_state(game, var1, var2); + break; + + case 2: /* Task state. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + result = restr_pass_task_task_state(game, var1, var2); + break; + + case 3: /* Player and NPCs. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + result = restr_pass_task_char(game, var1, var2, var3); + break; + + case 4: /* Variable. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var4"; + var4 = prop_get_string(bundle, "S<-sisis", vt_key); + result = restr_pass_task_var(game, var1, var2, var3, var4); + break; + + default: + sc_fatal("restr_pass_task_restriction:" + " unknown restriction type %ld\n", type); + } + + if (restr_trace) { + sc_trace("Restr: task %ld restriction" + " %ld is %s\n", task, restriction, result ? "PASS" : "FAIL"); + } + + return result; } /* Enumeration of restrictions combination string tokens. */ -enum -{ TOK_RESTRICTION = '#', - TOK_AND = 'A', - TOK_OR = 'O', - TOK_LPAREN = '(', - TOK_RPAREN = ')', - TOK_EOS = '\0' +enum { + TOK_RESTRICTION = '#', + TOK_AND = 'A', + TOK_OR = 'O', + TOK_LPAREN = '(', + TOK_RPAREN = ')', + TOK_EOS = '\0' }; /* #O#A(#O#)-style expression, for tokenizing. */ @@ -762,18 +713,16 @@ static sc_int restr_index = 0; * Start and wrap up restrictions combinations string tokenization. */ static void -restr_tokenize_start (const sc_char *expression) -{ - /* Save expression, and restart index. */ - restr_expression = expression; - restr_index = 0; +restr_tokenize_start(const sc_char *expression) { + /* Save expression, and restart index. */ + restr_expression = expression; + restr_index = 0; } static void -restr_tokenize_end (void) -{ - restr_expression = NULL; - restr_index = 0; +restr_tokenize_end(void) { + restr_expression = NULL; + restr_index = 0; } @@ -783,25 +732,23 @@ restr_tokenize_end (void) * Simple tokenizer for restrictions combination expressions. */ static sc_char -restr_next_token (void) -{ - assert (restr_expression); - - /* Find the next non-space, and return it. */ - while (TRUE) - { - /* Return NUL if at string end. */ - if (restr_expression[restr_index] == NUL) - return restr_expression[restr_index]; - - /* Spin on whitespace. */ - restr_index++; - if (sc_isspace (restr_expression[restr_index - 1])) - continue; - - /* Return the character just passed. */ - return restr_expression[restr_index - 1]; - } +restr_next_token(void) { + assert(restr_expression); + + /* Find the next non-space, and return it. */ + while (TRUE) { + /* Return NUL if at string end. */ + if (restr_expression[restr_index] == NUL) + return restr_expression[restr_index]; + + /* Spin on whitespace. */ + restr_index++; + if (sc_isspace(restr_expression[restr_index - 1])) + continue; + + /* Return the character just passed. */ + return restr_expression[restr_index - 1]; + } } @@ -829,18 +776,17 @@ static sc_int restr_lowest_fail = -1; * to note for when we need to evaluate a restriction. */ static void -restr_eval_start (sc_gameref_t game, sc_int task) -{ - /* Clear stack. */ - restr_eval_stack = 0; - restr_eval_restriction = 0; - - /* Note evaluation details. */ - restr_eval_game = game; - restr_eval_task = task; - - /* Clear lowest indexed failing restriction. */ - restr_lowest_fail = -1; +restr_eval_start(sc_gameref_t game, sc_int task) { + /* Clear stack. */ + restr_eval_stack = 0; + restr_eval_restriction = 0; + + /* Note evaluation details. */ + restr_eval_game = game; + restr_eval_task = task; + + /* Clear lowest indexed failing restriction. */ + restr_lowest_fail = -1; } @@ -850,12 +796,11 @@ restr_eval_start (sc_gameref_t game, sc_int task) * Push a value onto the values stack. */ static void -restr_eval_push (sc_bool value) -{ - if (restr_eval_stack >= MAX_NESTING_DEPTH) - sc_fatal ("restr_eval_push: stack overflow\n"); +restr_eval_push(sc_bool value) { + if (restr_eval_stack >= MAX_NESTING_DEPTH) + sc_fatal("restr_eval_push: stack overflow\n"); - restr_eval_values[restr_eval_stack++] = value; + restr_eval_values[restr_eval_stack++] = value; } @@ -865,68 +810,63 @@ restr_eval_push (sc_bool value) * Evaluate the effect of an and/or into the values stack. */ static void -restr_eval_action (sc_char token) -{ - /* Select action based on parsed token. */ - switch (token) - { - /* Handle evaluating and pushing a restriction result. */ - case TOK_RESTRICTION: - { - sc_bool result; - - /* Evaluate and push the next restriction. */ - result = restr_pass_task_restriction (restr_eval_game, - restr_eval_task, - restr_eval_restriction); - restr_eval_push (result); - - /* - * If the restriction failed, and there isn't yet a first failing one - * set, note this one as the first to fail. - */ - if (restr_lowest_fail == -1 && !result) - restr_lowest_fail = restr_eval_restriction; - - /* Increment restriction sequence identifier. */ - restr_eval_restriction++; - break; - } - - /* Handle cases of or-ing/and-ing restrictions. */ - case TOK_OR: - case TOK_AND: - { - sc_bool val1, val2, result = FALSE; - assert (restr_eval_stack >= 2); - - /* Get the top two stack values. */ - val1 = restr_eval_values[restr_eval_stack - 2]; - val2 = restr_eval_values[restr_eval_stack - 1]; - - /* Or, or and, into result. */ - switch (token) - { - case TOK_OR: - result = val1 || val2; - break; - case TOK_AND: - result = val1 && val2; - break; - - default: - sc_fatal ("restr_eval_action: bad token, '%c'\n", token); - } - - /* Put result back at top of stack. */ - restr_eval_stack--; - restr_eval_values[restr_eval_stack - 1] = result; - break; - } - - default: - sc_fatal ("restr_eval_action: bad token, '%c'\n", token); - } +restr_eval_action(sc_char token) { + /* Select action based on parsed token. */ + switch (token) { + /* Handle evaluating and pushing a restriction result. */ + case TOK_RESTRICTION: { + sc_bool result; + + /* Evaluate and push the next restriction. */ + result = restr_pass_task_restriction(restr_eval_game, + restr_eval_task, + restr_eval_restriction); + restr_eval_push(result); + + /* + * If the restriction failed, and there isn't yet a first failing one + * set, note this one as the first to fail. + */ + if (restr_lowest_fail == -1 && !result) + restr_lowest_fail = restr_eval_restriction; + + /* Increment restriction sequence identifier. */ + restr_eval_restriction++; + break; + } + + /* Handle cases of or-ing/and-ing restrictions. */ + case TOK_OR: + case TOK_AND: { + sc_bool val1, val2, result = FALSE; + assert(restr_eval_stack >= 2); + + /* Get the top two stack values. */ + val1 = restr_eval_values[restr_eval_stack - 2]; + val2 = restr_eval_values[restr_eval_stack - 1]; + + /* Or, or and, into result. */ + switch (token) { + case TOK_OR: + result = val1 || val2; + break; + case TOK_AND: + result = val1 && val2; + break; + + default: + sc_fatal("restr_eval_action: bad token, '%c'\n", token); + } + + /* Put result back at top of stack. */ + restr_eval_stack--; + restr_eval_values[restr_eval_stack - 1] = result; + break; + } + + default: + sc_fatal("restr_eval_action: bad token, '%c'\n", token); + } } @@ -936,13 +876,12 @@ restr_eval_action (sc_char token) * Return the top of the values stack as the evaluation result. */ static sc_int -restr_eval_result (sc_int *lowest_fail) -{ - if (restr_eval_stack != 1) - sc_fatal ("restr_eval_result: values stack not completed\n"); +restr_eval_result(sc_int *lowest_fail) { + if (restr_eval_stack != 1) + sc_fatal("restr_eval_result: values stack not completed\n"); - *lowest_fail = restr_lowest_fail; - return restr_eval_values[0]; + *lowest_fail = restr_lowest_fail; + return restr_eval_values[0]; } @@ -958,21 +897,19 @@ static sc_char restr_lookahead = '\0'; * Match a token with an expectation. */ static void -restr_match (sc_char c) -{ - if (restr_lookahead == c) - restr_lookahead = restr_next_token (); - else - { - sc_error ("restr_match:" - " syntax error, expected %d, got %d\n", c, restr_lookahead); - longjmp (restr_parse_error, 1); - } +restr_match(sc_char c) { + if (restr_lookahead == c) + restr_lookahead = restr_next_token(); + else { + sc_error("restr_match:" + " syntax error, expected %d, got %d\n", c, restr_lookahead); + longjmp(restr_parse_error, 1); + } } /* Forward declaration for recursion. */ -static void restr_bexpr (void); +static void restr_bexpr(void); /* * restr_andexpr() @@ -982,49 +919,43 @@ static void restr_bexpr (void); * Expression parsers. Here we go again... */ static void -restr_andexpr (void) -{ - restr_bexpr (); - while (restr_lookahead == TOK_AND) - { - restr_match (TOK_AND); - restr_bexpr (); - restr_eval_action (TOK_AND); - } +restr_andexpr(void) { + restr_bexpr(); + while (restr_lookahead == TOK_AND) { + restr_match(TOK_AND); + restr_bexpr(); + restr_eval_action(TOK_AND); + } } static void -restr_orexpr (void) -{ - restr_andexpr (); - while (restr_lookahead == TOK_OR) - { - restr_match (TOK_OR); - restr_andexpr (); - restr_eval_action (TOK_OR); - } +restr_orexpr(void) { + restr_andexpr(); + while (restr_lookahead == TOK_OR) { + restr_match(TOK_OR); + restr_andexpr(); + restr_eval_action(TOK_OR); + } } static void -restr_bexpr (void) -{ - switch (restr_lookahead) - { - case TOK_RESTRICTION: - restr_match (TOK_RESTRICTION); - restr_eval_action (TOK_RESTRICTION); - break; - - case TOK_LPAREN: - restr_match (TOK_LPAREN); - restr_orexpr (); - restr_match (TOK_RPAREN); - break; - - default: - sc_error ("restr_bexpr: syntax error, unexpected %d\n", restr_lookahead); - longjmp (restr_parse_error, 1); - } +restr_bexpr(void) { + switch (restr_lookahead) { + case TOK_RESTRICTION: + restr_match(TOK_RESTRICTION); + restr_eval_action(TOK_RESTRICTION); + break; + + case TOK_LPAREN: + restr_match(TOK_LPAREN); + restr_orexpr(); + restr_match(TOK_RPAREN); + break; + + default: + sc_error("restr_bexpr: syntax error, unexpected %d\n", restr_lookahead); + longjmp(restr_parse_error, 1); + } } @@ -1034,22 +965,21 @@ restr_bexpr (void) * Get the FailMessage for the given task restriction; NULL if none. */ static const sc_char * -restr_get_fail_message (sc_gameref_t game, sc_int task, sc_int restriction) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - const sc_char *message; - - /* Get the restriction message. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Restrictions"; - vt_key[3].integer = restriction; - vt_key[4].string = "FailMessage"; - message = prop_get_string (bundle, "S<-sisis", vt_key); - - /* Return it, or NULL if empty. */ - return !sc_strempty (message) ? message : NULL; +restr_get_fail_message(sc_gameref_t game, sc_int task, sc_int restriction) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + const sc_char *message; + + /* Get the restriction message. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Restrictions"; + vt_key[3].integer = restriction; + vt_key[4].string = "FailMessage"; + message = prop_get_string(bundle, "S<-sisis", vt_key); + + /* Return it, or NULL if empty. */ + return !sc_strempty(message) ? message : NULL; } @@ -1059,9 +989,8 @@ restr_get_fail_message (sc_gameref_t game, sc_int task, sc_int restriction) * Set restrictions tracing on/off. */ void -restr_debug_trace (sc_bool flag) -{ - restr_trace = flag; +restr_debug_trace(sc_bool flag) { + restr_trace = flag; } @@ -1076,87 +1005,80 @@ restr_debug_trace (sc_bool flag) * value is TRUE if restrictions parsed successfully, FALSE otherwise. */ sc_bool -restr_eval_task_restrictions (sc_gameref_t game, - sc_int task, sc_bool *pass, - const sc_char **fail_message) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int restr_count, lowest_fail; - const sc_char *pattern; - sc_bool result; - assert (pass && fail_message); - - /* Get the count of restrictions on the task. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Restrictions"; - restr_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - /* If none, stop now, acting as if all passed. */ - if (restr_count == 0) - { - if (restr_trace) - sc_trace ("Restr: task %ld has no restrictions\n", task); - - *pass = TRUE; - *fail_message = NULL; - return TRUE; - } - - /* Get the task's restriction combination pattern. */ - vt_key[2].string = "RestrMask"; - pattern = prop_get_string (bundle, "S<-sis", vt_key); - - if (restr_trace) - { - sc_trace ("Restr: task %ld" - " has %ld restrictions, %s\n", task, restr_count, pattern); - } - - /* Set up the evaluation stack and tokenizer. */ - restr_eval_start (game, task); - restr_tokenize_start (pattern); - - /* Try parsing the pattern, and catch errors. */ - if (setjmp (restr_parse_error) == 0) - { - /* Parse the pattern, and ensure it ends at string end. */ - restr_lookahead = restr_next_token (); - restr_orexpr (); - restr_match (TOK_EOS); - } - else - { - /* Parse error -- clean up tokenizer and return fail. */ - restr_tokenize_end (); - return FALSE; - } - - /* Clean up tokenizer and get the evaluation result. */ - restr_tokenize_end (); - result = restr_eval_result (&lowest_fail); - - if (restr_trace) - { - sc_trace ("Restr: task %ld" - " restrictions %s\n", task, result ? "PASS" : "FAIL"); - } - - /* - * Return the result, and if a restriction fails, then return the - * FailMessage of the lowest indexed failing restriction (or NULL if this - * restriction has no FailMessage). - * - * Then return TRUE since parsing and running the restrictions succeeded - * (even if the restrictions themselves didn't). - */ - *pass = result; - if (result) - *fail_message = NULL; - else - *fail_message = restr_get_fail_message (game, task, lowest_fail); - return TRUE; +restr_eval_task_restrictions(sc_gameref_t game, + sc_int task, sc_bool *pass, + const sc_char **fail_message) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int restr_count, lowest_fail; + const sc_char *pattern; + sc_bool result; + assert(pass && fail_message); + + /* Get the count of restrictions on the task. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Restrictions"; + restr_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + /* If none, stop now, acting as if all passed. */ + if (restr_count == 0) { + if (restr_trace) + sc_trace("Restr: task %ld has no restrictions\n", task); + + *pass = TRUE; + *fail_message = NULL; + return TRUE; + } + + /* Get the task's restriction combination pattern. */ + vt_key[2].string = "RestrMask"; + pattern = prop_get_string(bundle, "S<-sis", vt_key); + + if (restr_trace) { + sc_trace("Restr: task %ld" + " has %ld restrictions, %s\n", task, restr_count, pattern); + } + + /* Set up the evaluation stack and tokenizer. */ + restr_eval_start(game, task); + restr_tokenize_start(pattern); + + /* Try parsing the pattern, and catch errors. */ + if (setjmp(restr_parse_error) == 0) { + /* Parse the pattern, and ensure it ends at string end. */ + restr_lookahead = restr_next_token(); + restr_orexpr(); + restr_match(TOK_EOS); + } else { + /* Parse error -- clean up tokenizer and return fail. */ + restr_tokenize_end(); + return FALSE; + } + + /* Clean up tokenizer and get the evaluation result. */ + restr_tokenize_end(); + result = restr_eval_result(&lowest_fail); + + if (restr_trace) { + sc_trace("Restr: task %ld" + " restrictions %s\n", task, result ? "PASS" : "FAIL"); + } + + /* + * Return the result, and if a restriction fails, then return the + * FailMessage of the lowest indexed failing restriction (or NULL if this + * restriction has no FailMessage). + * + * Then return TRUE since parsing and running the restrictions succeeded + * (even if the restrictions themselves didn't). + */ + *pass = result; + if (result) + *fail_message = NULL; + else + *fail_message = restr_get_fail_message(game, task, lowest_fail); + return TRUE; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scrunner.cpp b/engines/glk/adrift/scrunner.cpp index ab6bfd8305..9e979d1193 100644 --- a/engines/glk/adrift/scrunner.cpp +++ b/engines/glk/adrift/scrunner.cpp @@ -45,396 +45,427 @@ static const sc_char *const SEPARATORS = ".,"; * and handled. */ static sc_bool -run_is_task_function (const sc_char *pattern, sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[3]; - sc_int room, object; - sc_char *argument; - - /* Simple comparison against the one known task expression. */ - argument = (sc_char *)sc_malloc (strlen (pattern) + 1); - if (sscanf (pattern, " # %%object%% = getdynfromroom (%[^)])", argument) == 0) - { - sc_free (argument); - return FALSE; - } - - /* - * Compare the argument read in against known room names. - * - * TODO Is this simple room name comparison good enough? - */ - vt_key[0].string = "Rooms"; - for (room = 0; room < gs_room_count (game); room++) - { - const sc_char *name; - - vt_key[1].integer = room; - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - if (sc_strcasecmp (name, argument) == 0) - break; - } - sc_free (argument); - if (room == gs_room_count (game)) - return FALSE; - - /* - * Select a dynamic object from the room. - * - * TODO What are the selection criteria supposed to be? Here we use "on - * the floor". - */ - vt_key[0].string = "Objects"; - for (object = 0; object < gs_object_count (game); object++) - { - sc_bool bstatic; - - vt_key[1].integer = object; - vt_key[2].string = "Static"; - bstatic = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!bstatic && obj_directly_in_room (game, object, room)) - break; - } - if (object == gs_object_count (game)) - return FALSE; - - /* Set this object reference, unambiguously, as if %object% match. */ - gs_clear_object_references (game); - game->object_references[object] = TRUE; - var_set_ref_object (vars, object); - - return TRUE; +run_is_task_function(const sc_char *pattern, sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[3]; + sc_int room, object; + sc_char *argument; + + /* Simple comparison against the one known task expression. */ + argument = (sc_char *)sc_malloc(strlen(pattern) + 1); + if (sscanf(pattern, " # %%object%% = getdynfromroom (%[^)])", argument) == 0) { + sc_free(argument); + return FALSE; + } + + /* + * Compare the argument read in against known room names. + * + * TODO Is this simple room name comparison good enough? + */ + vt_key[0].string = "Rooms"; + for (room = 0; room < gs_room_count(game); room++) { + const sc_char *name; + + vt_key[1].integer = room; + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + if (sc_strcasecmp(name, argument) == 0) + break; + } + sc_free(argument); + if (room == gs_room_count(game)) + return FALSE; + + /* + * Select a dynamic object from the room. + * + * TODO What are the selection criteria supposed to be? Here we use "on + * the floor". + */ + vt_key[0].string = "Objects"; + for (object = 0; object < gs_object_count(game); object++) { + sc_bool bstatic; + + vt_key[1].integer = object; + vt_key[2].string = "Static"; + bstatic = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!bstatic && obj_directly_in_room(game, object, room)) + break; + } + if (object == gs_object_count(game)) + return FALSE; + + /* Set this object reference, unambiguously, as if %object% match. */ + gs_clear_object_references(game); + game->object_references[object] = TRUE; + var_set_ref_object(vars, object); + + return TRUE; } /* Structure used to associate a pattern with a handler function. */ -typedef struct sc_commands_s -{ - const sc_char *const command; - sc_bool (*const handler) (sc_gameref_t game); +typedef struct sc_commands_s { + const sc_char *const command; + sc_bool(*const handler)(sc_gameref_t game); } sc_commands_t; typedef sc_commands_t *sc_commandsref_t; /* Movement commands for the four point compass. */ static sc_commands_t MOVE_COMMANDS_4[] = { - {"{go {to {the}}} [north/n]", lib_cmd_go_north}, - {"{go {to {the}}} [east/e]", lib_cmd_go_east}, - {"{go {to {the}}} [south/s]", lib_cmd_go_south}, - {"{go {to {the}}} [west/w]", lib_cmd_go_west}, - {"{go {to {the}}} [up/u]", lib_cmd_go_up}, - {"{go {to {the}}} [down/d]", lib_cmd_go_down}, - {"{go {to {the}}} [in]", lib_cmd_go_in}, - {"{go {to {the}}} [out/o]", lib_cmd_go_out}, - {NULL, NULL} + {"{go {to {the}}} [north/n]", lib_cmd_go_north}, + {"{go {to {the}}} [east/e]", lib_cmd_go_east}, + {"{go {to {the}}} [south/s]", lib_cmd_go_south}, + {"{go {to {the}}} [west/w]", lib_cmd_go_west}, + {"{go {to {the}}} [up/u]", lib_cmd_go_up}, + {"{go {to {the}}} [down/d]", lib_cmd_go_down}, + {"{go {to {the}}} [in]", lib_cmd_go_in}, + {"{go {to {the}}} [out/o]", lib_cmd_go_out}, + {NULL, NULL} }; /* Movement commands for the eight point compass. */ static sc_commands_t MOVE_COMMANDS_8[] = { - {"{go {to {the}}} [north/n]", lib_cmd_go_north}, - {"{go {to {the}}} [east/e]", lib_cmd_go_east}, - {"{go {to {the}}} [south/s]", lib_cmd_go_south}, - {"{go {to {the}}} [west/w]", lib_cmd_go_west}, - {"{go {to {the}}} [up/u]", lib_cmd_go_up}, - {"{go {to {the}}} [down/d]", lib_cmd_go_down}, - {"{go {to {the}}} [in]", lib_cmd_go_in}, - {"{go {to {the}}} [out/o]", lib_cmd_go_out}, - {"{go {to {the}}} [northeast/north-east/ne]", lib_cmd_go_northeast}, - {"{go {to {the}}} [southeast/south-east/se]", lib_cmd_go_southeast}, - {"{go {to {the}}} [northwest/north-west/nw]", lib_cmd_go_northwest}, - {"{go {to {the}}} [southwest/south-west/sw]", lib_cmd_go_southwest}, - {NULL, NULL} + {"{go {to {the}}} [north/n]", lib_cmd_go_north}, + {"{go {to {the}}} [east/e]", lib_cmd_go_east}, + {"{go {to {the}}} [south/s]", lib_cmd_go_south}, + {"{go {to {the}}} [west/w]", lib_cmd_go_west}, + {"{go {to {the}}} [up/u]", lib_cmd_go_up}, + {"{go {to {the}}} [down/d]", lib_cmd_go_down}, + {"{go {to {the}}} [in]", lib_cmd_go_in}, + {"{go {to {the}}} [out/o]", lib_cmd_go_out}, + {"{go {to {the}}} [northeast/north-east/ne]", lib_cmd_go_northeast}, + {"{go {to {the}}} [southeast/south-east/se]", lib_cmd_go_southeast}, + {"{go {to {the}}} [northwest/north-west/nw]", lib_cmd_go_northwest}, + {"{go {to {the}}} [southwest/south-west/sw]", lib_cmd_go_southwest}, + {NULL, NULL} }; /* "Priority" library commands, may take precedence over the game. */ static sc_commands_t PRIORITY_COMMANDS[] = { - /* Acquisition of and disposal of inventory. */ - {"[[get/take/remove/extract] [all/everything] from/empty] %object%", - lib_cmd_take_all_from}, - {"[[get/take/remove/extract] [all/everything] from/empty] %object%" - " [[except/but] {for}/apart from] %text%", - lib_cmd_take_from_except_multiple}, - {"[get/take/remove/extract] [all/everything]" - " [[except/but] {for}/apart from] %text% from %object%", - lib_cmd_take_from_except_multiple}, - {"[get/take/remove/extract] %text% from %object%", - lib_cmd_take_from_multiple}, - {"[get/take] [all/everything] from %character%", lib_cmd_take_all_from_npc}, - {"[get/take] [all/everything] from %character%" - " [[except/but] {for}/apart from] %text%", - lib_cmd_take_from_npc_except_multiple}, - {"[get/take] [all/everything]" - " [[except/but] {for}/apart from] %text% from %character%", - lib_cmd_take_from_npc_except_multiple}, - {"[get/take] %text% from %character%", lib_cmd_take_from_npc_multiple}, - {"[[get/take/pick up] [all/everything]/pick [all/everything] up]", - lib_cmd_take_all}, - {"[get/take/pick up] [all/everything] [[except/but] {for}/apart from] %text%", - lib_cmd_take_except_multiple}, - {"[get/take/pick up] %text%", lib_cmd_take_multiple}, - {"pick %text% up", lib_cmd_take_multiple}, - {"[[drop/put down] [all/everything]/put [all/everything] down]", - lib_cmd_drop_all}, - {"[drop/put down] [all/everything] [[except/but] {for}/apart from] %text%", - lib_cmd_drop_except_multiple}, - {"[drop/put down] %text%", lib_cmd_drop_multiple}, - {"put %text% down", lib_cmd_drop_multiple}, - {NULL, NULL} + /* Acquisition of and disposal of inventory. */ + { + "[[get/take/remove/extract] [all/everything] from/empty] %object%", + lib_cmd_take_all_from + }, + { + "[[get/take/remove/extract] [all/everything] from/empty] %object%" + " [[except/but] {for}/apart from] %text%", + lib_cmd_take_from_except_multiple + }, + { + "[get/take/remove/extract] [all/everything]" + " [[except/but] {for}/apart from] %text% from %object%", + lib_cmd_take_from_except_multiple + }, + { + "[get/take/remove/extract] %text% from %object%", + lib_cmd_take_from_multiple + }, + {"[get/take] [all/everything] from %character%", lib_cmd_take_all_from_npc}, + { + "[get/take] [all/everything] from %character%" + " [[except/but] {for}/apart from] %text%", + lib_cmd_take_from_npc_except_multiple + }, + { + "[get/take] [all/everything]" + " [[except/but] {for}/apart from] %text% from %character%", + lib_cmd_take_from_npc_except_multiple + }, + {"[get/take] %text% from %character%", lib_cmd_take_from_npc_multiple}, + { + "[[get/take/pick up] [all/everything]/pick [all/everything] up]", + lib_cmd_take_all + }, + { + "[get/take/pick up] [all/everything] [[except/but] {for}/apart from] %text%", + lib_cmd_take_except_multiple + }, + {"[get/take/pick up] %text%", lib_cmd_take_multiple}, + {"pick %text% up", lib_cmd_take_multiple}, + { + "[[drop/put down] [all/everything]/put [all/everything] down]", + lib_cmd_drop_all + }, + { + "[drop/put down] [all/everything] [[except/but] {for}/apart from] %text%", + lib_cmd_drop_except_multiple + }, + {"[drop/put down] %text%", lib_cmd_drop_multiple}, + {"put %text% down", lib_cmd_drop_multiple}, + {NULL, NULL} }; /* Standard library commands, other than movement and priority above. */ static sc_commands_t STANDARD_COMMANDS[] = { - /* Inventory, and general investigation of surroundings. */ - {"[inventory/inv/i]", lib_cmd_inventory}, - {"[x/ex/exam/examine/l/look {at}] {{the} [room/location]}", lib_cmd_look}, - {"[x/ex/exam/examine/look {at/in}] %object%", lib_cmd_examine_object}, - {"[x/ex/exam/examine/look {at}] %character%", lib_cmd_examine_npc}, - {"[x/ex/exam/examine/look {at}] [me/self/myself]", lib_cmd_examine_self}, - {"[x/ex/exam/examine/look {at}] all", lib_cmd_examine_all}, - - /* Attempted acquisition of and disposal of NPCs. */ - {"[get/take/pick up] %character%", lib_cmd_take_npc}, - {"pick %character% up", lib_cmd_take_npc}, - - /* Manipulating selected objects. */ - {"put [all/everything] [in/into/inside {of}] %object%", lib_cmd_put_all_in}, - {"put [all/everything] [[except/but] {for}/apart from] %text%" - " [in/into/inside {of}] %object%", lib_cmd_put_in_except_multiple}, - {"put %text% [in/into/inside {of}] %object%", lib_cmd_put_in_multiple}, - {"put [all/everything] [on/onto/on top of] %object%", lib_cmd_put_all_on}, - {"put [all/everything] [[except/but] {for}/apart from] %text%" - " [on/onto/on top of] %object%", lib_cmd_put_on_except_multiple}, - {"put %text% [on/onto/on top of] %object%", lib_cmd_put_on_multiple}, - {"open %object%", lib_cmd_open_object}, - {"close %object%", lib_cmd_close_object}, - {"unlock %object% with %text%", lib_cmd_unlock_object_with}, - {"lock %object% with %text%", lib_cmd_lock_object_with}, - {"unlock %object%", lib_cmd_unlock_object}, - {"lock %object%", lib_cmd_lock_object}, - {"read %object%", lib_cmd_read_object}, - {"read *", lib_cmd_read_other}, - {"give %object% to %character%", lib_cmd_give_object_npc}, - {"sit {down/up} [on/in] %object%", lib_cmd_sit_on_object}, - {"stand {up/down} [on/in] %object%", lib_cmd_stand_on_object}, - {"[lie/lay] on %object%", lib_cmd_lie_on_object}, - {"get {down/up} off %object%", lib_cmd_get_off_object}, - {"get off", lib_cmd_get_off}, - {"sit {down/up} {[on/in] {the} [ground/floor]}", lib_cmd_sit_on_floor}, - {"stand {up/down} {[on/in] {the} [ground/floor]}", lib_cmd_stand_on_floor}, - {"[lie/lay] {down/up} {[on/in] {the} [ground/floor]}", lib_cmd_lie_on_floor}, - {"eat %object%", lib_cmd_eat_object}, - - /* Dressing up, and dressing down. */ - {"[[wear/put on/don] [all/everything]/put [all/everything] on]", - lib_cmd_wear_all}, - {"[wear/put on/don] [all/everything] [[except/but] {for}/apart from] %text%", - lib_cmd_wear_except_multiple}, - {"[wear/put on/don] %text%", lib_cmd_wear_multiple}, - {"put %text% on", lib_cmd_wear_multiple}, - {"[[remove/take off/doff] [all/everything]/take [all/everything] off/strip]", - lib_cmd_remove_all}, - {"[remove/take off/doff] [all/everything]" - " [[except/but] {for}/apart from] %text%", - lib_cmd_remove_except_multiple}, - {"[remove/take off/doff] %text%", lib_cmd_remove_multiple}, - {"take %text% off", lib_cmd_remove_multiple}, - - /* Selected NPC interactions and conversation. */ - {"ask %character% about %text%", lib_cmd_ask_npc_about}, - {"[attack/hit/kick/slap/shoot/stab] %character% with %object%", - lib_cmd_attack_npc_with}, - {"[attack/shoot] %character%", lib_cmd_attack_npc}, - - /* More movement, waiting, and miscellaneous administrative commands. */ - {"[goto/go {to}] %text%", lib_cmd_go_room}, - {"[goto/go {to}] *", lib_cmd_print_room_exits}, - {"[exit/exits/directions/where]", lib_cmd_print_room_exits}, - {"[wait/z] %number%", lib_cmd_wait_number}, - {"[wait/z]", lib_cmd_wait}, - {"save", lib_cmd_save}, - {"[restore/load]", lib_cmd_restore}, - {"restart", lib_cmd_restart}, - {"[again/g]", lib_cmd_again}, - {"[redo /!]%number%", lib_cmd_redo_number}, - {"[redo /!]%text%", lib_cmd_redo_text}, - {"[redo/!]", lib_cmd_redo_last}, - {"[quit/q]", lib_cmd_quit}, - {"turns", lib_cmd_turns}, - {"score", lib_cmd_score}, - {"undo", lib_cmd_undo}, - {"[hist/history] %number%", lib_cmd_history_number}, - {"[hist/history]", lib_cmd_history}, - {"[hint/hints]", lib_cmd_hints}, - {"verbose", lib_cmd_verbose}, - {"brief", lib_cmd_brief}, - {"[notify/notification] %text%", lib_cmd_notify_on_off}, - {"[notify/notification]", lib_cmd_notify}, - {"time", lib_cmd_time}, - {"date", lib_cmd_date}, - {"[help/commands]", lib_cmd_help}, - {"[gpl/license]", lib_cmd_license}, - {"[about/info/information/author]", lib_cmd_information}, - {"[clear/cls/clr]", lib_cmd_clear}, - {"status{line}", lib_cmd_statusline}, - {"version", lib_cmd_version}, - - {"[locate/where {is/are}/find] %object%", lib_cmd_locate_object}, - {"[locate/where {is}/find] %character%", lib_cmd_locate_npc}, - - {"[count/num]", lib_cmd_count}, - - /* Standard response commands; no real action, just output. */ - {"[get/take/pick up] *", lib_cmd_get_what}, - {"open *", lib_cmd_open_what}, - {"close *", lib_cmd_close_other}, - {"give %object% *", lib_cmd_give_object}, - {"give *", lib_cmd_give_what}, - {"lock %text%", lib_cmd_lock_other}, - {"lock", lib_cmd_lock_what}, - {"unlock %text%", lib_cmd_unlock_other}, - {"unlock", lib_cmd_unlock_what}, - {"sit {down/up} [on/in] *", lib_cmd_sit_other}, - {"stand {up/down} [on/in] *", lib_cmd_stand_other}, - {"[lie/lay] {down/up} [on/in] *", lib_cmd_lie_other}, - {"[remove/take off/doff] *", lib_cmd_remove_what}, - {"[drop/put down] *", lib_cmd_drop_what}, - {"[wear/put on/don] *", lib_cmd_wear_what}, - {"[shit/fuck/bastard/cunt/crap/hell/shag/bollocks/bollox/bugger] *", - lib_cmd_profanity}, - {"[x/examine/look {at}] *", lib_cmd_examine_other}, - {"[locate/where {is/are}/find] *", lib_cmd_locate_other}, - {"[cp/mv/ln/ls] *", lib_cmd_unix_like}, - {"dir *", lib_cmd_dos_like}, - {"ask %character% *", lib_cmd_ask_npc}, - {"ask %object% *", lib_cmd_ask_object}, - {"ask *", lib_cmd_ask_other}, - {"block %object% *", lib_cmd_block_object}, - {"block %text%", lib_cmd_block_other}, - {"block", lib_cmd_block_what}, - {"[break/destroy/smash] %object% *", lib_cmd_break_object}, - {"[break/destroy/smash] %text%", lib_cmd_break_other}, - {"break", lib_cmd_break_what}, - {"destroy", lib_cmd_destroy_what}, - {"smash", lib_cmd_smash_what}, - {"buy %object% *", lib_cmd_buy_object}, - {"buy %text%", lib_cmd_buy_other}, - {"buy", lib_cmd_buy_what}, - {"clean %object% *", lib_cmd_clean_object}, - {"clean %text%", lib_cmd_clean_other}, - {"clean", lib_cmd_clean_what}, - {"climb %object% *", lib_cmd_climb_object}, - {"climb %text%", lib_cmd_climb_other}, - {"climb", lib_cmd_climb_what}, - {"cry *", lib_cmd_cry}, - {"cut %object% *", lib_cmd_cut_object}, - {"cut %text%", lib_cmd_cut_other}, - {"cut", lib_cmd_cut_what}, - {"dance *", lib_cmd_dance}, - {"drink %object% *", lib_cmd_drink_object}, - {"drink %text%", lib_cmd_drink_other}, - {"drink", lib_cmd_drink_what}, - {"eat *", lib_cmd_eat_other}, - {"feed *", lib_cmd_feed}, - {"feel *", lib_cmd_feel}, - {"fight *", lib_cmd_fight}, - {"fix %object% *", lib_cmd_fix_object}, - {"fix %text%", lib_cmd_fix_other}, - {"fix", lib_cmd_fix_what}, - {"fly *", lib_cmd_fly}, - {"hint *", lib_cmd_hint}, - {"hit %character%", lib_cmd_attack_npc}, - {"hit %object% *", lib_cmd_hit_object}, - {"hit %text%", lib_cmd_hit_other}, - {"hit", lib_cmd_hit_what}, - {"hum *", lib_cmd_hum}, - {"jump *", lib_cmd_jump}, - {"kick %character%", lib_cmd_attack_npc}, - {"kick %object% *", lib_cmd_kick_object}, - {"kick %text%", lib_cmd_kick_other}, - {"kick", lib_cmd_kick_what}, - {"kiss %character% *", lib_cmd_kiss_npc}, - {"kiss %object% *", lib_cmd_kiss_object}, - {"kiss *", lib_cmd_kiss_other}, - {"kill *", lib_cmd_kill_other}, - {"lift %object% *", lib_cmd_lift_object}, - {"lift %text%", lib_cmd_lift_other}, - {"lift", lib_cmd_lift_what}, - {"light %object% *", lib_cmd_light_object}, - {"light %text%", lib_cmd_light_other}, - {"light", lib_cmd_light_what}, - {"listen *", lib_cmd_listen}, - {"mend %object% *", lib_cmd_mend_object}, - {"mend %text%", lib_cmd_mend_other}, - {"mend", lib_cmd_mend_what}, - {"move %object% *", lib_cmd_move_object}, - {"move %text%", lib_cmd_move_other}, - {"move", lib_cmd_move_what}, - {"please *", lib_cmd_please}, - {"press %object% *", lib_cmd_press_object}, - {"press %text%", lib_cmd_press_other}, - {"press", lib_cmd_press_what}, - {"pull %object% *", lib_cmd_pull_object}, - {"pull %text%", lib_cmd_pull_other}, - {"pull", lib_cmd_pull_what}, - {"punch *", lib_cmd_punch}, - {"push %object% *", lib_cmd_push_object}, - {"push %text%", lib_cmd_push_other}, - {"push", lib_cmd_push_what}, - {"repair %object% *", lib_cmd_repair_object}, - {"repair %text%", lib_cmd_repair_other}, - {"repair", lib_cmd_repair_what}, - {"rub %object% *", lib_cmd_rub_object}, - {"rub %text%", lib_cmd_rub_other}, - {"rub", lib_cmd_rub_what}, - {"run *", lib_cmd_run}, - {"say *", lib_cmd_say}, - {"sell %object% *", lib_cmd_sell_object}, - {"sell %text%", lib_cmd_sell_other}, - {"sell", lib_cmd_sell_what}, - {"shake %object% *", lib_cmd_shake_object}, - {"shake %text%", lib_cmd_shake_other}, - {"shake", lib_cmd_shake_what}, - {"shout *", lib_cmd_shout}, - {"sing *", lib_cmd_sing}, - {"sleep *", lib_cmd_sleep}, - {"smell %object% *", lib_cmd_smell_object}, - {"smell *", lib_cmd_smell_other}, - {"stop %object% *", lib_cmd_stop_object}, - {"stop %text%", lib_cmd_stop_other}, - {"stop", lib_cmd_stop_what}, - {"suck %object% *", lib_cmd_suck_object}, - {"suck %text%", lib_cmd_suck_other}, - {"suck", lib_cmd_suck_what}, - {"talk *", lib_cmd_talk}, - {"thank *", lib_cmd_thank}, - {"turn %object% *", lib_cmd_turn_object}, - {"turn %text%", lib_cmd_turn_other}, - {"turn", lib_cmd_turn_what}, - {"touch %object% *", lib_cmd_touch_object}, - {"touch %text%", lib_cmd_touch_other}, - {"touch", lib_cmd_touch_what}, - {"unblock %object% *", lib_cmd_unblock_object}, - {"unblock %text%", lib_cmd_unblock_other}, - {"unblock", lib_cmd_unblock_what}, - {"wash %object% *", lib_cmd_wash_object}, - {"wash %text%", lib_cmd_wash_other}, - {"wash", lib_cmd_wash_what}, - {"whistle *", lib_cmd_whistle}, - {"[why/when/what/can/how] *", lib_cmd_interrogation}, - {"xyzzy *", lib_cmd_xyzzy}, - {"campbell", lib_cmd_egotistic}, - {"[yes/no] *", lib_cmd_yes_or_no}, - {"* %object% *", lib_cmd_verb_object}, - {"* %character% *", lib_cmd_verb_npc}, - - /* SCARE debugger hook command, placed last just in case... */ - {"{#}debug{ger}", debug_cmd_debugger}, - - {NULL, NULL} + /* Inventory, and general investigation of surroundings. */ + {"[inventory/inv/i]", lib_cmd_inventory}, + {"[x/ex/exam/examine/l/look {at}] {{the} [room/location]}", lib_cmd_look}, + {"[x/ex/exam/examine/look {at/in}] %object%", lib_cmd_examine_object}, + {"[x/ex/exam/examine/look {at}] %character%", lib_cmd_examine_npc}, + {"[x/ex/exam/examine/look {at}] [me/self/myself]", lib_cmd_examine_self}, + {"[x/ex/exam/examine/look {at}] all", lib_cmd_examine_all}, + + /* Attempted acquisition of and disposal of NPCs. */ + {"[get/take/pick up] %character%", lib_cmd_take_npc}, + {"pick %character% up", lib_cmd_take_npc}, + + /* Manipulating selected objects. */ + {"put [all/everything] [in/into/inside {of}] %object%", lib_cmd_put_all_in}, + { + "put [all/everything] [[except/but] {for}/apart from] %text%" + " [in/into/inside {of}] %object%", lib_cmd_put_in_except_multiple + }, + {"put %text% [in/into/inside {of}] %object%", lib_cmd_put_in_multiple}, + {"put [all/everything] [on/onto/on top of] %object%", lib_cmd_put_all_on}, + { + "put [all/everything] [[except/but] {for}/apart from] %text%" + " [on/onto/on top of] %object%", lib_cmd_put_on_except_multiple + }, + {"put %text% [on/onto/on top of] %object%", lib_cmd_put_on_multiple}, + {"open %object%", lib_cmd_open_object}, + {"close %object%", lib_cmd_close_object}, + {"unlock %object% with %text%", lib_cmd_unlock_object_with}, + {"lock %object% with %text%", lib_cmd_lock_object_with}, + {"unlock %object%", lib_cmd_unlock_object}, + {"lock %object%", lib_cmd_lock_object}, + {"read %object%", lib_cmd_read_object}, + {"read *", lib_cmd_read_other}, + {"give %object% to %character%", lib_cmd_give_object_npc}, + {"sit {down/up} [on/in] %object%", lib_cmd_sit_on_object}, + {"stand {up/down} [on/in] %object%", lib_cmd_stand_on_object}, + {"[lie/lay] on %object%", lib_cmd_lie_on_object}, + {"get {down/up} off %object%", lib_cmd_get_off_object}, + {"get off", lib_cmd_get_off}, + {"sit {down/up} {[on/in] {the} [ground/floor]}", lib_cmd_sit_on_floor}, + {"stand {up/down} {[on/in] {the} [ground/floor]}", lib_cmd_stand_on_floor}, + {"[lie/lay] {down/up} {[on/in] {the} [ground/floor]}", lib_cmd_lie_on_floor}, + {"eat %object%", lib_cmd_eat_object}, + + /* Dressing up, and dressing down. */ + { + "[[wear/put on/don] [all/everything]/put [all/everything] on]", + lib_cmd_wear_all + }, + { + "[wear/put on/don] [all/everything] [[except/but] {for}/apart from] %text%", + lib_cmd_wear_except_multiple + }, + {"[wear/put on/don] %text%", lib_cmd_wear_multiple}, + {"put %text% on", lib_cmd_wear_multiple}, + { + "[[remove/take off/doff] [all/everything]/take [all/everything] off/strip]", + lib_cmd_remove_all + }, + { + "[remove/take off/doff] [all/everything]" + " [[except/but] {for}/apart from] %text%", + lib_cmd_remove_except_multiple + }, + {"[remove/take off/doff] %text%", lib_cmd_remove_multiple}, + {"take %text% off", lib_cmd_remove_multiple}, + + /* Selected NPC interactions and conversation. */ + {"ask %character% about %text%", lib_cmd_ask_npc_about}, + { + "[attack/hit/kick/slap/shoot/stab] %character% with %object%", + lib_cmd_attack_npc_with + }, + {"[attack/shoot] %character%", lib_cmd_attack_npc}, + + /* More movement, waiting, and miscellaneous administrative commands. */ + {"[goto/go {to}] %text%", lib_cmd_go_room}, + {"[goto/go {to}] *", lib_cmd_print_room_exits}, + {"[exit/exits/directions/where]", lib_cmd_print_room_exits}, + {"[wait/z] %number%", lib_cmd_wait_number}, + {"[wait/z]", lib_cmd_wait}, + {"save", lib_cmd_save}, + {"[restore/load]", lib_cmd_restore}, + {"restart", lib_cmd_restart}, + {"[again/g]", lib_cmd_again}, + {"[redo /!]%number%", lib_cmd_redo_number}, + {"[redo /!]%text%", lib_cmd_redo_text}, + {"[redo/!]", lib_cmd_redo_last}, + {"[quit/q]", lib_cmd_quit}, + {"turns", lib_cmd_turns}, + {"score", lib_cmd_score}, + {"undo", lib_cmd_undo}, + {"[hist/history] %number%", lib_cmd_history_number}, + {"[hist/history]", lib_cmd_history}, + {"[hint/hints]", lib_cmd_hints}, + {"verbose", lib_cmd_verbose}, + {"brief", lib_cmd_brief}, + {"[notify/notification] %text%", lib_cmd_notify_on_off}, + {"[notify/notification]", lib_cmd_notify}, + {"time", lib_cmd_time}, + {"date", lib_cmd_date}, + {"[help/commands]", lib_cmd_help}, + {"[gpl/license]", lib_cmd_license}, + {"[about/info/information/author]", lib_cmd_information}, + {"[clear/cls/clr]", lib_cmd_clear}, + {"status{line}", lib_cmd_statusline}, + {"version", lib_cmd_version}, + + {"[locate/where {is/are}/find] %object%", lib_cmd_locate_object}, + {"[locate/where {is}/find] %character%", lib_cmd_locate_npc}, + + {"[count/num]", lib_cmd_count}, + + /* Standard response commands; no real action, just output. */ + {"[get/take/pick up] *", lib_cmd_get_what}, + {"open *", lib_cmd_open_what}, + {"close *", lib_cmd_close_other}, + {"give %object% *", lib_cmd_give_object}, + {"give *", lib_cmd_give_what}, + {"lock %text%", lib_cmd_lock_other}, + {"lock", lib_cmd_lock_what}, + {"unlock %text%", lib_cmd_unlock_other}, + {"unlock", lib_cmd_unlock_what}, + {"sit {down/up} [on/in] *", lib_cmd_sit_other}, + {"stand {up/down} [on/in] *", lib_cmd_stand_other}, + {"[lie/lay] {down/up} [on/in] *", lib_cmd_lie_other}, + {"[remove/take off/doff] *", lib_cmd_remove_what}, + {"[drop/put down] *", lib_cmd_drop_what}, + {"[wear/put on/don] *", lib_cmd_wear_what}, + { + "[shit/fuck/bastard/cunt/crap/hell/shag/bollocks/bollox/bugger] *", + lib_cmd_profanity + }, + {"[x/examine/look {at}] *", lib_cmd_examine_other}, + {"[locate/where {is/are}/find] *", lib_cmd_locate_other}, + {"[cp/mv/ln/ls] *", lib_cmd_unix_like}, + {"dir *", lib_cmd_dos_like}, + {"ask %character% *", lib_cmd_ask_npc}, + {"ask %object% *", lib_cmd_ask_object}, + {"ask *", lib_cmd_ask_other}, + {"block %object% *", lib_cmd_block_object}, + {"block %text%", lib_cmd_block_other}, + {"block", lib_cmd_block_what}, + {"[break/destroy/smash] %object% *", lib_cmd_break_object}, + {"[break/destroy/smash] %text%", lib_cmd_break_other}, + {"break", lib_cmd_break_what}, + {"destroy", lib_cmd_destroy_what}, + {"smash", lib_cmd_smash_what}, + {"buy %object% *", lib_cmd_buy_object}, + {"buy %text%", lib_cmd_buy_other}, + {"buy", lib_cmd_buy_what}, + {"clean %object% *", lib_cmd_clean_object}, + {"clean %text%", lib_cmd_clean_other}, + {"clean", lib_cmd_clean_what}, + {"climb %object% *", lib_cmd_climb_object}, + {"climb %text%", lib_cmd_climb_other}, + {"climb", lib_cmd_climb_what}, + {"cry *", lib_cmd_cry}, + {"cut %object% *", lib_cmd_cut_object}, + {"cut %text%", lib_cmd_cut_other}, + {"cut", lib_cmd_cut_what}, + {"dance *", lib_cmd_dance}, + {"drink %object% *", lib_cmd_drink_object}, + {"drink %text%", lib_cmd_drink_other}, + {"drink", lib_cmd_drink_what}, + {"eat *", lib_cmd_eat_other}, + {"feed *", lib_cmd_feed}, + {"feel *", lib_cmd_feel}, + {"fight *", lib_cmd_fight}, + {"fix %object% *", lib_cmd_fix_object}, + {"fix %text%", lib_cmd_fix_other}, + {"fix", lib_cmd_fix_what}, + {"fly *", lib_cmd_fly}, + {"hint *", lib_cmd_hint}, + {"hit %character%", lib_cmd_attack_npc}, + {"hit %object% *", lib_cmd_hit_object}, + {"hit %text%", lib_cmd_hit_other}, + {"hit", lib_cmd_hit_what}, + {"hum *", lib_cmd_hum}, + {"jump *", lib_cmd_jump}, + {"kick %character%", lib_cmd_attack_npc}, + {"kick %object% *", lib_cmd_kick_object}, + {"kick %text%", lib_cmd_kick_other}, + {"kick", lib_cmd_kick_what}, + {"kiss %character% *", lib_cmd_kiss_npc}, + {"kiss %object% *", lib_cmd_kiss_object}, + {"kiss *", lib_cmd_kiss_other}, + {"kill *", lib_cmd_kill_other}, + {"lift %object% *", lib_cmd_lift_object}, + {"lift %text%", lib_cmd_lift_other}, + {"lift", lib_cmd_lift_what}, + {"light %object% *", lib_cmd_light_object}, + {"light %text%", lib_cmd_light_other}, + {"light", lib_cmd_light_what}, + {"listen *", lib_cmd_listen}, + {"mend %object% *", lib_cmd_mend_object}, + {"mend %text%", lib_cmd_mend_other}, + {"mend", lib_cmd_mend_what}, + {"move %object% *", lib_cmd_move_object}, + {"move %text%", lib_cmd_move_other}, + {"move", lib_cmd_move_what}, + {"please *", lib_cmd_please}, + {"press %object% *", lib_cmd_press_object}, + {"press %text%", lib_cmd_press_other}, + {"press", lib_cmd_press_what}, + {"pull %object% *", lib_cmd_pull_object}, + {"pull %text%", lib_cmd_pull_other}, + {"pull", lib_cmd_pull_what}, + {"punch *", lib_cmd_punch}, + {"push %object% *", lib_cmd_push_object}, + {"push %text%", lib_cmd_push_other}, + {"push", lib_cmd_push_what}, + {"repair %object% *", lib_cmd_repair_object}, + {"repair %text%", lib_cmd_repair_other}, + {"repair", lib_cmd_repair_what}, + {"rub %object% *", lib_cmd_rub_object}, + {"rub %text%", lib_cmd_rub_other}, + {"rub", lib_cmd_rub_what}, + {"run *", lib_cmd_run}, + {"say *", lib_cmd_say}, + {"sell %object% *", lib_cmd_sell_object}, + {"sell %text%", lib_cmd_sell_other}, + {"sell", lib_cmd_sell_what}, + {"shake %object% *", lib_cmd_shake_object}, + {"shake %text%", lib_cmd_shake_other}, + {"shake", lib_cmd_shake_what}, + {"shout *", lib_cmd_shout}, + {"sing *", lib_cmd_sing}, + {"sleep *", lib_cmd_sleep}, + {"smell %object% *", lib_cmd_smell_object}, + {"smell *", lib_cmd_smell_other}, + {"stop %object% *", lib_cmd_stop_object}, + {"stop %text%", lib_cmd_stop_other}, + {"stop", lib_cmd_stop_what}, + {"suck %object% *", lib_cmd_suck_object}, + {"suck %text%", lib_cmd_suck_other}, + {"suck", lib_cmd_suck_what}, + {"talk *", lib_cmd_talk}, + {"thank *", lib_cmd_thank}, + {"turn %object% *", lib_cmd_turn_object}, + {"turn %text%", lib_cmd_turn_other}, + {"turn", lib_cmd_turn_what}, + {"touch %object% *", lib_cmd_touch_object}, + {"touch %text%", lib_cmd_touch_other}, + {"touch", lib_cmd_touch_what}, + {"unblock %object% *", lib_cmd_unblock_object}, + {"unblock %text%", lib_cmd_unblock_other}, + {"unblock", lib_cmd_unblock_what}, + {"wash %object% *", lib_cmd_wash_object}, + {"wash %text%", lib_cmd_wash_other}, + {"wash", lib_cmd_wash_what}, + {"whistle *", lib_cmd_whistle}, + {"[why/when/what/can/how] *", lib_cmd_interrogation}, + {"xyzzy *", lib_cmd_xyzzy}, + {"campbell", lib_cmd_egotistic}, + {"[yes/no] *", lib_cmd_yes_or_no}, + {"* %object% *", lib_cmd_verb_object}, + {"* %character% *", lib_cmd_verb_npc}, + + /* SCARE debugger hook command, placed last just in case... */ + {"{#}debug{ger}", debug_cmd_debugger}, + + {NULL, NULL} }; @@ -457,61 +488,53 @@ static sc_commands_t STANDARD_COMMANDS[] = { * object acquisition take precedence over game commands. */ static sc_bool -run_priority_commands (sc_gameref_t game, const sc_char *string) -{ - sc_commandsref_t command; - - for (command = PRIORITY_COMMANDS; command->command; command++) - { - if (uip_match (command->command, string, game)) - { - if (command->handler (game)) - return TRUE; - } - } - - /* Nothing matched match the string. Or if it did, its handler failed. */ - return FALSE; +run_priority_commands(sc_gameref_t game, const sc_char *string) { + sc_commandsref_t command; + + for (command = PRIORITY_COMMANDS; command->command; command++) { + if (uip_match(command->command, string, game)) { + if (command->handler(game)) + return TRUE; + } + } + + /* Nothing matched match the string. Or if it did, its handler failed. */ + return FALSE; } static sc_bool -run_standard_commands (sc_gameref_t game, const sc_char *string) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[2]; - sc_bool eightpointcompass; - sc_commandsref_t command; - - /* Select the appropriate movement commands. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "EightPointCompass"; - eightpointcompass = prop_get_boolean (bundle, "B<-ss", vt_key); - command = eightpointcompass ? MOVE_COMMANDS_8 : MOVE_COMMANDS_4; - - /* - * Search movement commands first, returning TRUE if any matching command - * handler succeeded. Then repeat for standard library commands. - */ - for (; command->command; command++) - { - if (uip_match (command->command, string, game)) - { - if (command->handler (game)) - return TRUE; - } - } - - for (command = STANDARD_COMMANDS; command->command; command++) - { - if (uip_match (command->command, string, game)) - { - if (command->handler (game)) - return TRUE; - } - } - - /* Nothing matched match the string. Or if it did, its handler failed. */ - return FALSE; +run_standard_commands(sc_gameref_t game, const sc_char *string) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[2]; + sc_bool eightpointcompass; + sc_commandsref_t command; + + /* Select the appropriate movement commands. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "EightPointCompass"; + eightpointcompass = prop_get_boolean(bundle, "B<-ss", vt_key); + command = eightpointcompass ? MOVE_COMMANDS_8 : MOVE_COMMANDS_4; + + /* + * Search movement commands first, returning TRUE if any matching command + * handler succeeded. Then repeat for standard library commands. + */ + for (; command->command; command++) { + if (uip_match(command->command, string, game)) { + if (command->handler(game)) + return TRUE; + } + } + + for (command = STANDARD_COMMANDS; command->command; command++) { + if (uip_match(command->command, string, game)) { + if (command->handler(game)) + return TRUE; + } + } + + /* Nothing matched match the string. Or if it did, its handler failed. */ + return FALSE; } @@ -521,43 +544,40 @@ run_standard_commands (sc_gameref_t game, const sc_char *string) * Update the game's current room and status line strings. */ static void -run_update_status (sc_gameref_t game) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[2]; - const sc_char *name, *status; - sc_char *filtered; - sc_bool statusbox; - - /* Get the current room name, and filter and untag it. */ - name = lib_get_room_name (game, gs_playerroom (game)); - filtered = pf_filter (name, vars, bundle); - pf_strip_tags (filtered); - - /* Free any existing room name, then save this room name. */ - sc_free (game->current_room_name); - game->current_room_name = filtered; - - /* See if the game does a status box. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "StatusBox"; - statusbox = prop_get_boolean (bundle, "B<-ss", vt_key); - if (statusbox) - { - /* Get the status line, and filter and untag it. */ - vt_key[1].string = "StatusBoxText"; - status = prop_get_string (bundle, "S<-ss", vt_key); - filtered = pf_filter (status, vars, bundle); - pf_strip_tags (filtered); - } - else - /* No status line, so use NULL. */ - filtered = NULL; - - /* Free any existing status line, then save this status text. */ - sc_free (game->status_line); - game->status_line = filtered; +run_update_status(sc_gameref_t game) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[2]; + const sc_char *name, *status; + sc_char *filtered; + sc_bool statusbox; + + /* Get the current room name, and filter and untag it. */ + name = lib_get_room_name(game, gs_playerroom(game)); + filtered = pf_filter(name, vars, bundle); + pf_strip_tags(filtered); + + /* Free any existing room name, then save this room name. */ + sc_free(game->current_room_name); + game->current_room_name = filtered; + + /* See if the game does a status box. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "StatusBox"; + statusbox = prop_get_boolean(bundle, "B<-ss", vt_key); + if (statusbox) { + /* Get the status line, and filter and untag it. */ + vt_key[1].string = "StatusBoxText"; + status = prop_get_string(bundle, "S<-ss", vt_key); + filtered = pf_filter(status, vars, bundle); + pf_strip_tags(filtered); + } else + /* No status line, so use NULL. */ + filtered = NULL; + + /* Free any existing status line, then save this status text. */ + sc_free(game->status_line); + game->status_line = filtered; } @@ -570,36 +590,32 @@ run_update_status (sc_gameref_t game) * output ahead of buffered printfilter text. */ static void -run_notify_score_change (sc_gameref_t game) -{ - const sc_gameref_t undo = game->undo; - sc_char buffer[32]; - assert (gs_is_game_valid (undo)); - - /* - * Do nothing if no undo available, or if notification is off, or if we've - * already done this once this turn. - */ - if (!game->undo_available - || !game->notify_score_change || game->has_notified) - return; - - /* Note any change in the score. */ - if (game->score > undo->score) - { - if_print_string ("(Your score has increased by "); - sprintf (buffer, "%ld", game->score - undo->score); - if_print_string (buffer); - if_print_string (")\n"); - } - else if (game->score < undo->score) - { - if_print_string ("(Your score has decreased by "); - sprintf (buffer, "%ld", undo->score - game->score); - if_print_string (buffer); - if_print_string (")\n"); - } - game->has_notified = TRUE; +run_notify_score_change(sc_gameref_t game) { + const sc_gameref_t undo = game->undo; + sc_char buffer[32]; + assert(gs_is_game_valid(undo)); + + /* + * Do nothing if no undo available, or if notification is off, or if we've + * already done this once this turn. + */ + if (!game->undo_available + || !game->notify_score_change || game->has_notified) + return; + + /* Note any change in the score. */ + if (game->score > undo->score) { + if_print_string("(Your score has increased by "); + sprintf(buffer, "%ld", game->score - undo->score); + if_print_string(buffer); + if_print_string(")\n"); + } else if (game->score < undo->score) { + if_print_string("(Your score has decreased by "); + sprintf(buffer, "%ld", undo->score - game->score); + if_print_string(buffer); + if_print_string(")\n"); + } + game->has_notified = TRUE; } @@ -615,81 +631,73 @@ run_notify_score_change (sc_gameref_t game) * are selected by 'forwards'. */ static sc_bool -run_match_task_common (sc_gameref_t game, - sc_int task, const sc_char *string, sc_bool forwards, - sc_bool is_library, sc_bool is_normal) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int command_count, command; - sc_bool is_matched; - - /* Get the count of task commands. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = forwards ? "Command" : "ReverseCommand"; - command_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - /* Iterate over commands, looking for patterns that match string. */ - is_matched = FALSE; - for (command = 0; command < command_count; command++) - { - const sc_char *pattern; - sc_int first; - - /* Retrieve the pattern for this command, find its first character. */ - vt_key[3].integer = command; - pattern = prop_get_string (bundle, "S<-sisi", vt_key); - first = strspn (pattern, WHITESPACE); - - /* Match using either the parser, or the special function matcher. */ - if (is_normal) - { - if (pattern[first] != SPECIAL_PATTERN) - { - /* - * Make a special case of library calls and commands that begin - * with a wildcard; these we ignore for this match attempt. - */ - if (is_library && pattern[first] == WILDCARD_PATTERN) - is_matched = FALSE; - else - is_matched = uip_match (pattern, string, game); - } - } - else - { - if (pattern[first] == SPECIAL_PATTERN) - is_matched = run_is_task_function (pattern, game); - } - - /* Stop searching if we find a match. */ - if (is_matched) - break; - } - - /* Return TRUE if we found a pattern match. */ - return is_matched; +run_match_task_common(sc_gameref_t game, + sc_int task, const sc_char *string, sc_bool forwards, + sc_bool is_library, sc_bool is_normal) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int command_count, command; + sc_bool is_matched; + + /* Get the count of task commands. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = forwards ? "Command" : "ReverseCommand"; + command_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + /* Iterate over commands, looking for patterns that match string. */ + is_matched = FALSE; + for (command = 0; command < command_count; command++) { + const sc_char *pattern; + sc_int first; + + /* Retrieve the pattern for this command, find its first character. */ + vt_key[3].integer = command; + pattern = prop_get_string(bundle, "S<-sisi", vt_key); + first = strspn(pattern, WHITESPACE); + + /* Match using either the parser, or the special function matcher. */ + if (is_normal) { + if (pattern[first] != SPECIAL_PATTERN) { + /* + * Make a special case of library calls and commands that begin + * with a wildcard; these we ignore for this match attempt. + */ + if (is_library && pattern[first] == WILDCARD_PATTERN) + is_matched = FALSE; + else + is_matched = uip_match(pattern, string, game); + } + } else { + if (pattern[first] == SPECIAL_PATTERN) + is_matched = run_is_task_function(pattern, game); + } + + /* Stop searching if we find a match. */ + if (is_matched) + break; + } + + /* Return TRUE if we found a pattern match. */ + return is_matched; } static sc_bool -run_match_task_commands (sc_gameref_t game, - sc_int task, const sc_char *string, - sc_bool forwards, sc_bool is_library) -{ - /* - * Match tasks using the normal pattern matcher, with or without any note - * about whether the call is from the library. - */ - return run_match_task_common (game, task, string, forwards, is_library, TRUE); +run_match_task_commands(sc_gameref_t game, + sc_int task, const sc_char *string, + sc_bool forwards, sc_bool is_library) { + /* + * Match tasks using the normal pattern matcher, with or without any note + * about whether the call is from the library. + */ + return run_match_task_common(game, task, string, forwards, is_library, TRUE); } static sc_bool -run_match_task_functions (sc_gameref_t game, - sc_int task, const sc_char *string, sc_bool forwards) -{ - /* Match tasks against "task command functions". */ - return run_match_task_common (game, task, string, forwards, FALSE, FALSE); +run_match_task_functions(sc_gameref_t game, + sc_int task, const sc_char *string, sc_bool forwards) { + /* Match tasks against "task command functions". */ + return run_match_task_common(game, task, string, forwards, FALSE, FALSE); } @@ -706,46 +714,42 @@ run_match_task_functions (sc_gameref_t game, * and don't change state. */ static sc_bool -run_task_is_unrestricted (sc_gameref_t game, sc_int task) -{ - sc_bool restrictions_passed; - const sc_char *fail_message; - - /* - * Evaluate task restrictions, and if they fail to parse for some reason, - * return as if restrictions did not pass. - */ - if (!restr_eval_task_restrictions (game, task, - &restrictions_passed, &fail_message)) - { - sc_error ("run_task_is_unrestricted: restrictions error, %ld\n", task); - return FALSE; - } - - /* Return TRUE if the task is unrestricted. */ - return restrictions_passed; +run_task_is_unrestricted(sc_gameref_t game, sc_int task) { + sc_bool restrictions_passed; + const sc_char *fail_message; + + /* + * Evaluate task restrictions, and if they fail to parse for some reason, + * return as if restrictions did not pass. + */ + if (!restr_eval_task_restrictions(game, task, + &restrictions_passed, &fail_message)) { + sc_error("run_task_is_unrestricted: restrictions error, %ld\n", task); + return FALSE; + } + + /* Return TRUE if the task is unrestricted. */ + return restrictions_passed; } static sc_bool -run_task_is_loudly_restricted (sc_gameref_t game, sc_int task) -{ - sc_bool restrictions_passed; - const sc_char *fail_message; - - /* - * Evaluate task restrictions, and if they fail to parse for some reason, - * return as if restrictions did not pass. - */ - if (!restr_eval_task_restrictions (game, task, - &restrictions_passed, &fail_message)) - { - sc_error ("run_task_is_loudly_restricted:" - " restrictions error, %ld\n", task); - return TRUE; - } - - /* Return TRUE if the task is restricted and indicates why. */ - return !restrictions_passed && (fail_message != NULL); +run_task_is_loudly_restricted(sc_gameref_t game, sc_int task) { + sc_bool restrictions_passed; + const sc_char *fail_message; + + /* + * Evaluate task restrictions, and if they fail to parse for some reason, + * return as if restrictions did not pass. + */ + if (!restr_eval_task_restrictions(game, task, + &restrictions_passed, &fail_message)) { + sc_error("run_task_is_loudly_restricted:" + " restrictions error, %ld\n", task); + return TRUE; + } + + /* Return TRUE if the task is restricted and indicates why. */ + return !restrictions_passed && (fail_message != NULL); } @@ -785,134 +789,119 @@ run_task_is_loudly_restricted (sc_gameref_t game, sc_int task) * handlers and get_all/drop_all handlers. No pressure, then. */ static sc_bool -run_game_commands_common (sc_gameref_t game, const sc_char *string, - sc_bool include_restrictions, sc_bool is_library) -{ - sc_bool is_matched = FALSE, is_handled = FALSE; - sc_bool *is_matching; - sc_int task_count, task, direction; - - /* - * Matching is expensive, so it helps to use a cache of results from the - * first loop in the second. If we're using the second, that is. - */ - task_count = gs_task_count (game); - if (include_restrictions) - { - is_matching = (sc_bool *)sc_malloc (task_count * sizeof (*is_matching)); - memset (is_matching, FALSE, task_count * sizeof (*is_matching)); - } - else - is_matching = NULL; - - /* - * Iterate over every task, ignoring those not runnable. For each runnable - * task, try matching task commands, and on matches, check restrictions and - * if they pass, try running the task. - */ - for (task = 0; task < task_count; task++) - { - if (!task_can_run_task (game, task)) - continue; - - /* - * Try matching forwards and reverse commands. If there's a match for - * unrestricted tasks, run the task, and if it runs (defined as printing - * some game output), we're done; otherwise, note the command match but - * keep searching for other possible matches. - */ - for (direction = 0; direction < 2; direction++) - { - const sc_bool is_forwards = !direction; - - if (task_can_run_task_directional (game, task, is_forwards) - && run_match_task_commands (game, task, string, - is_forwards, is_library)) - { - if (run_task_is_unrestricted (game, task)) - { - if (task_run_task (game, task, is_forwards)) - is_handled = TRUE; - is_matched = TRUE; - break; - } - - if (is_matching) - is_matching[task] = TRUE; - } - } - if (is_matched) - break; - } - - /* - * If no match, and we've been asked to consider failing restrictions, look - * through all of the runnable tasks again, this time searching for - * restricted ones with a fail message. Use the cache built above to weed - * out matches that are certain to fail. - */ - if (!is_handled && !is_matched && include_restrictions) - { - for (task = 0; task < task_count; task++) - { - if (!is_matching[task] || !task_can_run_task (game, task)) - continue; - - /* - * Check matches of forwards and reverse commands. If there's a - * match for restricted tasks (ones that have and will print a fail - * message if we try to run them), run the task to get the print of - * the fail message, and we're done. - */ - for (direction = 0; direction < 2; direction++) - { - const sc_bool is_forwards = !direction; - - if (task_can_run_task_directional (game, task, is_forwards) - && run_match_task_commands (game, task, string, - is_forwards, is_library)) - { - if (run_task_is_loudly_restricted (game, task)) - { - if (task_run_task (game, task, is_forwards)) - { - is_handled = TRUE; - break; - } - } - } - } - if (is_handled) - break; - } - } - - /* Return TRUE if any game task handled the command in some way. */ - sc_free (is_matching); - return is_handled; +run_game_commands_common(sc_gameref_t game, const sc_char *string, + sc_bool include_restrictions, sc_bool is_library) { + sc_bool is_matched = FALSE, is_handled = FALSE; + sc_bool *is_matching; + sc_int task_count, task, direction; + + /* + * Matching is expensive, so it helps to use a cache of results from the + * first loop in the second. If we're using the second, that is. + */ + task_count = gs_task_count(game); + if (include_restrictions) { + is_matching = (sc_bool *)sc_malloc(task_count * sizeof(*is_matching)); + memset(is_matching, FALSE, task_count * sizeof(*is_matching)); + } else + is_matching = NULL; + + /* + * Iterate over every task, ignoring those not runnable. For each runnable + * task, try matching task commands, and on matches, check restrictions and + * if they pass, try running the task. + */ + for (task = 0; task < task_count; task++) { + if (!task_can_run_task(game, task)) + continue; + + /* + * Try matching forwards and reverse commands. If there's a match for + * unrestricted tasks, run the task, and if it runs (defined as printing + * some game output), we're done; otherwise, note the command match but + * keep searching for other possible matches. + */ + for (direction = 0; direction < 2; direction++) { + const sc_bool is_forwards = !direction; + + if (task_can_run_task_directional(game, task, is_forwards) + && run_match_task_commands(game, task, string, + is_forwards, is_library)) { + if (run_task_is_unrestricted(game, task)) { + if (task_run_task(game, task, is_forwards)) + is_handled = TRUE; + is_matched = TRUE; + break; + } + + if (is_matching) + is_matching[task] = TRUE; + } + } + if (is_matched) + break; + } + + /* + * If no match, and we've been asked to consider failing restrictions, look + * through all of the runnable tasks again, this time searching for + * restricted ones with a fail message. Use the cache built above to weed + * out matches that are certain to fail. + */ + if (!is_handled && !is_matched && include_restrictions) { + for (task = 0; task < task_count; task++) { + if (!is_matching[task] || !task_can_run_task(game, task)) + continue; + + /* + * Check matches of forwards and reverse commands. If there's a + * match for restricted tasks (ones that have and will print a fail + * message if we try to run them), run the task to get the print of + * the fail message, and we're done. + */ + for (direction = 0; direction < 2; direction++) { + const sc_bool is_forwards = !direction; + + if (task_can_run_task_directional(game, task, is_forwards) + && run_match_task_commands(game, task, string, + is_forwards, is_library)) { + if (run_task_is_loudly_restricted(game, task)) { + if (task_run_task(game, task, is_forwards)) { + is_handled = TRUE; + break; + } + } + } + } + if (is_handled) + break; + } + } + + /* Return TRUE if any game task handled the command in some way. */ + sc_free(is_matching); + return is_handled; } static sc_bool -run_game_commands_in_parser_context (sc_gameref_t game, const sc_char *string, - sc_bool include_restrictions) -{ - /* - * Try game commands, either with or without restrictions, and all full and - * complete parse matching (no special case for game commands that begin - * with a '*' wildcard). - */ - return run_game_commands_common (game, string, include_restrictions, FALSE); +run_game_commands_in_parser_context(sc_gameref_t game, const sc_char *string, + sc_bool include_restrictions) { + /* + * Try game commands, either with or without restrictions, and all full and + * complete parse matching (no special case for game commands that begin + * with a '*' wildcard). + */ + return run_game_commands_common(game, string, include_restrictions, FALSE); } static sc_bool -run_game_commands_in_library_context (sc_gameref_t game, const sc_char *string) -{ - /* - * Try game commands, including restrictions, and noting that this is a - * library call so that the parse matcher can exclude game commands that - * begin with a '*' wildcard. - */ - return run_game_commands_common (game, string, TRUE, TRUE); +run_game_commands_in_library_context(sc_gameref_t game, const sc_char *string) { + /* + * Try game commands, including restrictions, and noting that this is a + * library call so that the parse matcher can exclude game commands that + * begin with a '*' wildcard. + */ + return run_game_commands_common(game, string, TRUE, TRUE); } @@ -924,33 +913,29 @@ run_game_commands_in_library_context (sc_gameref_t game, const sc_char *string) * command matches, so we try them as a separate action. */ static void -run_game_functions (sc_gameref_t game, const sc_char *string) -{ - sc_int task_count, task, direction; - - /* Iterate over every task, ignoring those not runnable. */ - task_count = gs_task_count (game); - for (task = 0; task < task_count; task++) - { - if (!task_can_run_task (game, task)) - continue; - - /* - * Try matching forwards and reverse commands. I don't know if it's - * valid to put a function in a reverse command, but nevertheless... - */ - for (direction = 0; direction < 2; direction++) - { - const sc_bool is_forwards = !direction; - - if (task_can_run_task_directional (game, task, is_forwards) - && run_match_task_functions (game, task, string, is_forwards)) - { - if (run_task_is_unrestricted (game, task)) - task_run_task (game, task, is_forwards); - } - } - } +run_game_functions(sc_gameref_t game, const sc_char *string) { + sc_int task_count, task, direction; + + /* Iterate over every task, ignoring those not runnable. */ + task_count = gs_task_count(game); + for (task = 0; task < task_count; task++) { + if (!task_can_run_task(game, task)) + continue; + + /* + * Try matching forwards and reverse commands. I don't know if it's + * valid to put a function in a reverse command, but nevertheless... + */ + for (direction = 0; direction < 2; direction++) { + const sc_bool is_forwards = !direction; + + if (task_can_run_task_directional(game, task, is_forwards) + && run_match_task_functions(game, task, string, is_forwards)) { + if (run_task_is_unrestricted(game, task)) + task_run_task(game, task, is_forwards); + } + } + } } @@ -963,73 +948,70 @@ run_game_functions (sc_gameref_t game, const sc_char *string) * game commands that override standard actions. */ static sc_bool -run_all_commands (sc_gameref_t game, const sc_char *string) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_bool status; - - /* - * Adrift command matching is just weird, perhaps broken. In theory, a - * game can override system commands with a properly constructed task and - * set of command matchers. However, the Runner isn't terribly consistent - * in when this will work and when not, and some games rely on that in- - * consistency. In particular, a game with a "* object" task that has - * failing restrictions will not be able to override the system's "take - * object", whereas a game's "take object", under the same circumstances, - * will. Yet if the restrictions pass, a game's "* object" overrides the - * system's "take object" with no apparent difficulty. - * - * For example, "The Woods Are Dark" has a "* ball *" task with the - * restriction "must be holding ball". Without special casing it, there's - * no way to get the ball in the first place. - * - * Trying to find the right way to do things here, then, has been tricky. - * Here's the current process: First, run game commands, ignoring any - * cases where restrictions fail to let the task run. Next, try "priority" - * system commands; ones that move objects to inventory. These system - * commands will call back into trying game commands for objects taken or - * dropped, and in those tries, allow overrides only if the game task is - * explicit about what it's doing (that is, doesn't start with "*"), and - * handle restrictions in those tries. After that, retry all game commands - * again with restrictions enabled. And finally, try all other standard - * library commands. - * - * TODO This is the fourth or fifth attempt at getting this to match the - * Runner, which is surprisingly inconsistent in this area. What on earth - * is the real behavior supposed to be? - */ - status = run_game_commands_in_parser_context (game, string, FALSE); - if (!status) - status = run_priority_commands (game, string); - if (!status) - status = run_game_commands_in_parser_context (game, string, TRUE); - if (!status) - status = run_standard_commands (game, string); - - /* - * For version 4.0 games, it seems that if any command succeeded, we need - * need to scan for and run any matching "task command functions", in - * addition to anything done above. - */ - if (status && !game->is_admin) - { - sc_vartype_t vt_key; - sc_int version; - - /* Check "task command functions" for version 4.0 only. */ - vt_key.string = "Version"; - version = prop_get_integer (bundle, "I<-s", &vt_key); - if (version == TAF_VERSION_400) - run_game_functions (game, string); - } - - return status; +run_all_commands(sc_gameref_t game, const sc_char *string) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_bool status; + + /* + * Adrift command matching is just weird, perhaps broken. In theory, a + * game can override system commands with a properly constructed task and + * set of command matchers. However, the Runner isn't terribly consistent + * in when this will work and when not, and some games rely on that in- + * consistency. In particular, a game with a "* object" task that has + * failing restrictions will not be able to override the system's "take + * object", whereas a game's "take object", under the same circumstances, + * will. Yet if the restrictions pass, a game's "* object" overrides the + * system's "take object" with no apparent difficulty. + * + * For example, "The Woods Are Dark" has a "* ball *" task with the + * restriction "must be holding ball". Without special casing it, there's + * no way to get the ball in the first place. + * + * Trying to find the right way to do things here, then, has been tricky. + * Here's the current process: First, run game commands, ignoring any + * cases where restrictions fail to let the task run. Next, try "priority" + * system commands; ones that move objects to inventory. These system + * commands will call back into trying game commands for objects taken or + * dropped, and in those tries, allow overrides only if the game task is + * explicit about what it's doing (that is, doesn't start with "*"), and + * handle restrictions in those tries. After that, retry all game commands + * again with restrictions enabled. And finally, try all other standard + * library commands. + * + * TODO This is the fourth or fifth attempt at getting this to match the + * Runner, which is surprisingly inconsistent in this area. What on earth + * is the real behavior supposed to be? + */ + status = run_game_commands_in_parser_context(game, string, FALSE); + if (!status) + status = run_priority_commands(game, string); + if (!status) + status = run_game_commands_in_parser_context(game, string, TRUE); + if (!status) + status = run_standard_commands(game, string); + + /* + * For version 4.0 games, it seems that if any command succeeded, we need + * need to scan for and run any matching "task command functions", in + * addition to anything done above. + */ + if (status && !game->is_admin) { + sc_vartype_t vt_key; + sc_int version; + + /* Check "task command functions" for version 4.0 only. */ + vt_key.string = "Version"; + version = prop_get_integer(bundle, "I<-s", &vt_key); + if (version == TAF_VERSION_400) + run_game_functions(game, string); + } + + return status; } sc_bool -run_game_task_commands (sc_gameref_t game, const sc_char *string) -{ - return run_game_commands_in_library_context (game, string); +run_game_task_commands(sc_gameref_t game, const sc_char *string) { + return run_game_commands_in_library_context(game, string); } @@ -1051,238 +1033,219 @@ run_game_task_commands (sc_gameref_t game, const sc_char *string) * just return. Sorry about the ugliness. */ static sc_bool -run_player_input (sc_gameref_t game) -{ - static sc_char line_buffer[LINE_BUFFER_SIZE]; - static sc_char prior_element[LINE_BUFFER_SIZE]; - static sc_char line_element[LINE_BUFFER_SIZE]; - - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - const sc_memo_setref_t memento = gs_get_memento (game); - sc_bool is_rerunning, was_undo_available, status; - sc_char *filtered, *replaced; - const sc_char *command; - - /* Special case; reset statics if the game isn't running. */ - if (!game->is_running) - { - memset (line_buffer, NUL, sizeof (line_buffer)); - memset (prior_element, NUL, sizeof (prior_element)); - memset (line_element, NUL, sizeof (line_element)); - return TRUE; - } - - /* - * Save the settings of the game's do_again and undo_available flags for - * later checks. - */ - is_rerunning = game->do_again; - was_undo_available = game->undo_available; - - /* See if the player asked to rerun a command element. */ - if (game->do_again) - { - game->do_again = FALSE; - - /* Check there is a last element to repeat. */ - if (prior_element[0] == NUL) - { - pf_buffer_string (filter, "You can hardly repeat that.\n"); - return FALSE; - } - - /* Make the last element the current input element. */ - strcpy (line_element, prior_element); - } - else - { - sc_int length, extent; - - /* - * If there's none buffered, read a new line of player input. Other- - * wise, separate output so far with a newline. - */ - if (line_buffer[0] == NUL) - if_read_line (line_buffer, sizeof (line_buffer)); - else - if_print_character ('\n'); - - /* - * Find the length of the next input line element. Unless the line - * buffer is empty, we always take the first character, even if it's a - * separator. This catches odd input like "." and turns it into a - * parser complaint, rather than treating it as two empty commands with - * a separator between them; this makes it close to what Inform does - * with similar inputs. - */ - length = (line_buffer[0] == NUL) ? 0 : 1; - while (line_buffer[length] != NUL - && strchr (SEPARATORS, line_buffer[length]) == NULL) - length++; - - /* - * Make this the current input element, and remove it, the separator, - * and any trailing whitespace, from the front of the line buffer. - * Removing whitespace prevents "i. ." looking like "i" and ""; it - * instead looks like "i" and ".", and results in a parser complaint. - */ - memcpy (line_element, line_buffer, length); - line_element[length] = NUL; - - extent = length; - extent += (line_buffer[length] == NUL - || strchr (SEPARATORS, line_buffer[length]) == NULL) ? 0 : 1; - extent += strspn (line_buffer + extent, WHITESPACE); - memmove (line_buffer, - line_buffer + extent, strlen (line_buffer) - extent + 1); - } - - /* Copy the current game to the temporary undo buffer. */ - gs_copy (game->temporary, game); - - /* Filter the input element for synonyms, then for pronouns. */ - filtered = pf_filter_input (line_element, bundle); - replaced = uip_replace_pronouns (game, filtered ? filtered : line_element); - - /* - * If filtering didn't replace synonyms, or no pronouns were replaced, use - * the original line element. - */ - command = replaced ? sc_normalize_string (replaced) - : (filtered ? sc_normalize_string (filtered) : line_element); - if (command != line_element) - { - if_print_tag (SC_TAG_ITALICS, ""); - if_print_character ('['); - if_print_string (command); - if_print_character (']'); - if_print_tag (SC_TAG_ENDITALICS, ""); - if_print_character ('\n'); - } - - /* Try the command line element against command matchers. */ - status = run_all_commands (game, command); - if (!status) - { - /* Only complain on non-empty command input line elements. */ - if (!sc_strempty (command)) - { - sc_vartype_t vt_key[2]; - sc_char *escaped; - const sc_char *message; - - /* Command line element not understood. */ - escaped = pf_escape (sc_normalize_string (line_element)); - var_set_ref_text (vars, escaped); - sc_free (escaped); - vt_key[0].string = "Globals"; - vt_key[1].string = "DontUnderstand"; - message = prop_get_string (bundle, "S<-ss", vt_key); - pf_buffer_string (filter, message); - pf_buffer_character (filter, '\n'); - - /* - * On a line element that's not understood, throw out any remaining - * input line elements. - */ - line_buffer[0] = NUL; - sc_free (filtered); - sc_free (replaced); - return status; - } - } - else - { - /* - * Unless administrative, back up any valid undo, copy the temporary - * game into the undo buffer, flag the undo buffer as available, and - * assign any pronouns used in the command ready for the next iteration. - */ - if (!game->is_admin) - { - if (game->undo_available) - memo_save_game (memento, game->undo); - - gs_copy (game->undo, game->temporary); - game->undo_available = TRUE; - - uip_assign_pronouns (game, command); - } - } - sc_free (filtered); - sc_free (replaced); - - /* - * If do_again is set, we'll come round with the prior command in line - * element in a moment, so save nothing for that case. Otherwise save the - * command in the history. - */ - if (!sc_strempty (line_element) && !game->do_again) - { - /* - * If this is a failed redo, redo_sequence will be set but do_again will - * be clear. Suppress the save for this special case; otherwise, failed - * redo commands get into the history, where they can cause problems - * later on. - */ - if (game->redo_sequence == 0) - { - sc_int timestamp; - - timestamp = var_get_elapsed_seconds (vars); - memo_save_command (memento, line_element, timestamp, game->turns); - } - else - game->redo_sequence = 0; - } - - /* - * Special case restart and restore commands; throw out any remaining input - * and return straight away. Do the same if this was an undo, detected by - * noting that undo is no longer available, where it was on entry. - */ - if (game->do_restart || game->do_restore - || (was_undo_available && !game->undo_available)) - { - line_buffer[0] = NUL; - return status; - } - - /* If not empty, consider as saving for "again" calls and in the history. */ - if (!sc_strempty (line_element)) - { - /* - * Unless "again", note this line element as prior input. "Again" shows - * up as do_again set in the game, where it wasn't when we entered here. - */ - if (!game->do_again && !is_rerunning) - strcpy (prior_element, line_element); - - /* - * If this was a request to run a command from the history, copy that - * command into the prior_element for the next iteration. The library - * should have verified the value in redo_sequence, so fetching the - * command string should not fail. - */ - if (game->do_again && game->redo_sequence != 0) - { - const sc_char *redo_command; - - redo_command = memo_find_command (memento, game->redo_sequence); - if (redo_command) - strcpy (prior_element, redo_command); - else - { - sc_error ("run_player_input: invalid redo sequence request\n"); - game->do_again = FALSE; - } - game->redo_sequence = 0; - } - } - - return status; +run_player_input(sc_gameref_t game) { + static sc_char line_buffer[LINE_BUFFER_SIZE]; + static sc_char prior_element[LINE_BUFFER_SIZE]; + static sc_char line_element[LINE_BUFFER_SIZE]; + + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + const sc_memo_setref_t memento = gs_get_memento(game); + sc_bool is_rerunning, was_undo_available, status; + sc_char *filtered, *replaced; + const sc_char *command; + + /* Special case; reset statics if the game isn't running. */ + if (!game->is_running) { + memset(line_buffer, NUL, sizeof(line_buffer)); + memset(prior_element, NUL, sizeof(prior_element)); + memset(line_element, NUL, sizeof(line_element)); + return TRUE; + } + + /* + * Save the settings of the game's do_again and undo_available flags for + * later checks. + */ + is_rerunning = game->do_again; + was_undo_available = game->undo_available; + + /* See if the player asked to rerun a command element. */ + if (game->do_again) { + game->do_again = FALSE; + + /* Check there is a last element to repeat. */ + if (prior_element[0] == NUL) { + pf_buffer_string(filter, "You can hardly repeat that.\n"); + return FALSE; + } + + /* Make the last element the current input element. */ + strcpy(line_element, prior_element); + } else { + sc_int length, extent; + + /* + * If there's none buffered, read a new line of player input. Other- + * wise, separate output so far with a newline. + */ + if (line_buffer[0] == NUL) + if_read_line(line_buffer, sizeof(line_buffer)); + else + if_print_character('\n'); + + /* + * Find the length of the next input line element. Unless the line + * buffer is empty, we always take the first character, even if it's a + * separator. This catches odd input like "." and turns it into a + * parser complaint, rather than treating it as two empty commands with + * a separator between them; this makes it close to what Inform does + * with similar inputs. + */ + length = (line_buffer[0] == NUL) ? 0 : 1; + while (line_buffer[length] != NUL + && strchr(SEPARATORS, line_buffer[length]) == NULL) + length++; + + /* + * Make this the current input element, and remove it, the separator, + * and any trailing whitespace, from the front of the line buffer. + * Removing whitespace prevents "i. ." looking like "i" and ""; it + * instead looks like "i" and ".", and results in a parser complaint. + */ + memcpy(line_element, line_buffer, length); + line_element[length] = NUL; + + extent = length; + extent += (line_buffer[length] == NUL + || strchr(SEPARATORS, line_buffer[length]) == NULL) ? 0 : 1; + extent += strspn(line_buffer + extent, WHITESPACE); + memmove(line_buffer, + line_buffer + extent, strlen(line_buffer) - extent + 1); + } + + /* Copy the current game to the temporary undo buffer. */ + gs_copy(game->temporary, game); + + /* Filter the input element for synonyms, then for pronouns. */ + filtered = pf_filter_input(line_element, bundle); + replaced = uip_replace_pronouns(game, filtered ? filtered : line_element); + + /* + * If filtering didn't replace synonyms, or no pronouns were replaced, use + * the original line element. + */ + command = replaced ? sc_normalize_string(replaced) + : (filtered ? sc_normalize_string(filtered) : line_element); + if (command != line_element) { + if_print_tag(SC_TAG_ITALICS, ""); + if_print_character('['); + if_print_string(command); + if_print_character(']'); + if_print_tag(SC_TAG_ENDITALICS, ""); + if_print_character('\n'); + } + + /* Try the command line element against command matchers. */ + status = run_all_commands(game, command); + if (!status) { + /* Only complain on non-empty command input line elements. */ + if (!sc_strempty(command)) { + sc_vartype_t vt_key[2]; + sc_char *escaped; + const sc_char *message; + + /* Command line element not understood. */ + escaped = pf_escape(sc_normalize_string(line_element)); + var_set_ref_text(vars, escaped); + sc_free(escaped); + vt_key[0].string = "Globals"; + vt_key[1].string = "DontUnderstand"; + message = prop_get_string(bundle, "S<-ss", vt_key); + pf_buffer_string(filter, message); + pf_buffer_character(filter, '\n'); + + /* + * On a line element that's not understood, throw out any remaining + * input line elements. + */ + line_buffer[0] = NUL; + sc_free(filtered); + sc_free(replaced); + return status; + } + } else { + /* + * Unless administrative, back up any valid undo, copy the temporary + * game into the undo buffer, flag the undo buffer as available, and + * assign any pronouns used in the command ready for the next iteration. + */ + if (!game->is_admin) { + if (game->undo_available) + memo_save_game(memento, game->undo); + + gs_copy(game->undo, game->temporary); + game->undo_available = TRUE; + + uip_assign_pronouns(game, command); + } + } + sc_free(filtered); + sc_free(replaced); + + /* + * If do_again is set, we'll come round with the prior command in line + * element in a moment, so save nothing for that case. Otherwise save the + * command in the history. + */ + if (!sc_strempty(line_element) && !game->do_again) { + /* + * If this is a failed redo, redo_sequence will be set but do_again will + * be clear. Suppress the save for this special case; otherwise, failed + * redo commands get into the history, where they can cause problems + * later on. + */ + if (game->redo_sequence == 0) { + sc_int timestamp; + + timestamp = var_get_elapsed_seconds(vars); + memo_save_command(memento, line_element, timestamp, game->turns); + } else + game->redo_sequence = 0; + } + + /* + * Special case restart and restore commands; throw out any remaining input + * and return straight away. Do the same if this was an undo, detected by + * noting that undo is no longer available, where it was on entry. + */ + if (game->do_restart || game->do_restore + || (was_undo_available && !game->undo_available)) { + line_buffer[0] = NUL; + return status; + } + + /* If not empty, consider as saving for "again" calls and in the history. */ + if (!sc_strempty(line_element)) { + /* + * Unless "again", note this line element as prior input. "Again" shows + * up as do_again set in the game, where it wasn't when we entered here. + */ + if (!game->do_again && !is_rerunning) + strcpy(prior_element, line_element); + + /* + * If this was a request to run a command from the history, copy that + * command into the prior_element for the next iteration. The library + * should have verified the value in redo_sequence, so fetching the + * command string should not fail. + */ + if (game->do_again && game->redo_sequence != 0) { + const sc_char *redo_command; + + redo_command = memo_find_command(memento, game->redo_sequence); + if (redo_command) + strcpy(prior_element, redo_command); + else { + sc_error("run_player_input: invalid redo sequence request\n"); + game->do_again = FALSE; + } + game->redo_sequence = 0; + } + } + + return status; } @@ -1292,190 +1255,179 @@ run_player_input (sc_gameref_t game) * Main interpreter loop. */ static void -run_main_loop (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - - /* - * This may not be the very first time this game has been used, for example - * saving a game right at the start, or undo-ing back to the start through - * memos. Caught by looking to see if the player room is marked as seen. - */ - if (!gs_room_seen (game, gs_playerroom (game))) - { - sc_vartype_t vt_key[2]; - const sc_char *gamename, *startuptext; - sc_bool disp_first_room, battle_system; - - /* If battle system and no debugger display a warning. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "BattleSystem"; - battle_system = prop_get_boolean (bundle, "B<-ss", vt_key); - if (battle_system && !debug_get_enabled (game)) - { - if_print_tag (SC_TAG_CLS, ""); - lib_warn_battle_system (); - } - - /* Initial clear screen. */ - pf_buffer_tag (filter, SC_TAG_CLS); - - /* Print the game name. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "GameName"; - gamename = prop_get_string (bundle, "S<-ss", vt_key); - pf_buffer_string (filter, gamename); - pf_buffer_character (filter, '\n'); - - /* Print the game header. */ - vt_key[0].string = "Header"; - vt_key[1].string = "StartupText"; - startuptext = prop_get_string (bundle, "S<-ss", vt_key); - pf_buffer_string (filter, startuptext); - pf_buffer_character (filter, '\n'); - - /* If flagged, describe the initial room. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "DispFirstRoom"; - disp_first_room = prop_get_boolean (bundle, "B<-ss", vt_key); - if (disp_first_room) - lib_cmd_look (game); - - /* Handle any introductory resources. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "IntroRes"; - res_handle_resource (game, "ss", vt_key); - - /* Set initial values for NPC and object states. */ - npc_setup_initial (game); - obj_setup_initial (game); - - /* Nudge events and NPCs. */ - evt_tick_events (game); - npc_tick_npcs (game); - - /* - * Notify the debugger that the game has started. This is a chance to - * set watchpoints to catch game startup actions. Done before setting - * the initial room visited as this is how the debugger differentiates - * restarts from restore or undo back to game start. - */ - debug_game_started (game); - - /* Note the initial room as visited. */ - gs_set_room_seen (game, gs_playerroom (game), TRUE); - } - else - { - /* Notify the debugger that the game has restarted. */ - debug_game_started (game); - } - - /* - * Game loop, exits either when a command parser handler sets the game - * running flag to FALSE, or by call to run_quit(). - */ - game->is_running &= !g_vm->shouldQuit(); - while (game->is_running) - { - sc_bool status; - - /* - * Synchronize any resources in use; do this before flushing so that any - * appropriate graphics/sound appear before waits or waitkey tag delays - * invoked by flushing the printfilter. Also, print any score change - * notifications. - */ - res_sync_resources (game); - run_notify_score_change (game); - - /* - * Flush printfilter of any accumulated output, and clear any prior - * notion of administrative commands from input. - */ - pf_flush (filter, vars, bundle); - game->is_admin = FALSE; - - /* If waitcounter is zero, accept and try a command. */ - if (game->waitcounter == 0) - { - /* Not waiting, so handle a player input line. */ - run_update_status (game); - status = run_player_input (game); - - /* - * If waitcounter is now set, decrement it, as this turn counts as - * one of them. - */ - if (game->waitcounter > 0) - game->waitcounter--; - } - else - { - /* - * Currently "waiting"; decrement wait turns, then run a turn having - * taken no input. - */ - game->waitcounter--; - status = TRUE; - } - - /* - * Do usual turn stuff unless either something stopped the game, or the - * last command didn't match, or the last command did match but was - * administrative. - */ - if (status && !game->is_admin) - { - /* Increment turn counter, and clear notifications done flag. */ - game->turns++; - game->has_notified = FALSE; - - if (game->is_running) - { - /* Nudge events and NPCs. */ - evt_tick_events (game); - npc_tick_npcs (game); - - /* Update NPC and object states. */ - npc_turn_update (game); - obj_turn_update (game); - - /* Note the current room as visited. */ - gs_set_room_seen (game, gs_playerroom (game), TRUE); - - /* Give the debugger a chance to catch watchpoints. */ - debug_turn_update (game); - } - } - - game->is_running &= !g_vm->shouldQuit(); - } - - /* - * Final status update, for games that vary it on completion, then notify - * the debugger that the game has ended, to let it make a last watchpoint - * scan and offer the dialog if appropriate. - */ - run_update_status (game); - debug_game_ended (game); - - /* - * Final resource sync, score change notification and printfilter flush - * on game-instigated loop exit. - */ - res_sync_resources (game); - run_notify_score_change (game); - pf_flush (filter, vars, bundle); - - /* - * Reset static variables inside run_player_input() with a call to it with - * is_running false; this is a special case. - */ - assert (!game->is_running); - run_player_input (game); +run_main_loop(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + + /* + * This may not be the very first time this game has been used, for example + * saving a game right at the start, or undo-ing back to the start through + * memos. Caught by looking to see if the player room is marked as seen. + */ + if (!gs_room_seen(game, gs_playerroom(game))) { + sc_vartype_t vt_key[2]; + const sc_char *gamename, *startuptext; + sc_bool disp_first_room, battle_system; + + /* If battle system and no debugger display a warning. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "BattleSystem"; + battle_system = prop_get_boolean(bundle, "B<-ss", vt_key); + if (battle_system && !debug_get_enabled(game)) { + if_print_tag(SC_TAG_CLS, ""); + lib_warn_battle_system(); + } + + /* Initial clear screen. */ + pf_buffer_tag(filter, SC_TAG_CLS); + + /* Print the game name. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "GameName"; + gamename = prop_get_string(bundle, "S<-ss", vt_key); + pf_buffer_string(filter, gamename); + pf_buffer_character(filter, '\n'); + + /* Print the game header. */ + vt_key[0].string = "Header"; + vt_key[1].string = "StartupText"; + startuptext = prop_get_string(bundle, "S<-ss", vt_key); + pf_buffer_string(filter, startuptext); + pf_buffer_character(filter, '\n'); + + /* If flagged, describe the initial room. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "DispFirstRoom"; + disp_first_room = prop_get_boolean(bundle, "B<-ss", vt_key); + if (disp_first_room) + lib_cmd_look(game); + + /* Handle any introductory resources. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "IntroRes"; + res_handle_resource(game, "ss", vt_key); + + /* Set initial values for NPC and object states. */ + npc_setup_initial(game); + obj_setup_initial(game); + + /* Nudge events and NPCs. */ + evt_tick_events(game); + npc_tick_npcs(game); + + /* + * Notify the debugger that the game has started. This is a chance to + * set watchpoints to catch game startup actions. Done before setting + * the initial room visited as this is how the debugger differentiates + * restarts from restore or undo back to game start. + */ + debug_game_started(game); + + /* Note the initial room as visited. */ + gs_set_room_seen(game, gs_playerroom(game), TRUE); + } else { + /* Notify the debugger that the game has restarted. */ + debug_game_started(game); + } + + /* + * Game loop, exits either when a command parser handler sets the game + * running flag to FALSE, or by call to run_quit(). + */ + game->is_running &= !g_vm->shouldQuit(); + while (game->is_running) { + sc_bool status; + + /* + * Synchronize any resources in use; do this before flushing so that any + * appropriate graphics/sound appear before waits or waitkey tag delays + * invoked by flushing the printfilter. Also, print any score change + * notifications. + */ + res_sync_resources(game); + run_notify_score_change(game); + + /* + * Flush printfilter of any accumulated output, and clear any prior + * notion of administrative commands from input. + */ + pf_flush(filter, vars, bundle); + game->is_admin = FALSE; + + /* If waitcounter is zero, accept and try a command. */ + if (game->waitcounter == 0) { + /* Not waiting, so handle a player input line. */ + run_update_status(game); + status = run_player_input(game); + + /* + * If waitcounter is now set, decrement it, as this turn counts as + * one of them. + */ + if (game->waitcounter > 0) + game->waitcounter--; + } else { + /* + * Currently "waiting"; decrement wait turns, then run a turn having + * taken no input. + */ + game->waitcounter--; + status = TRUE; + } + + /* + * Do usual turn stuff unless either something stopped the game, or the + * last command didn't match, or the last command did match but was + * administrative. + */ + if (status && !game->is_admin) { + /* Increment turn counter, and clear notifications done flag. */ + game->turns++; + game->has_notified = FALSE; + + if (game->is_running) { + /* Nudge events and NPCs. */ + evt_tick_events(game); + npc_tick_npcs(game); + + /* Update NPC and object states. */ + npc_turn_update(game); + obj_turn_update(game); + + /* Note the current room as visited. */ + gs_set_room_seen(game, gs_playerroom(game), TRUE); + + /* Give the debugger a chance to catch watchpoints. */ + debug_turn_update(game); + } + } + + game->is_running &= !g_vm->shouldQuit(); + } + + /* + * Final status update, for games that vary it on completion, then notify + * the debugger that the game has ended, to let it make a last watchpoint + * scan and offer the dialog if appropriate. + */ + run_update_status(game); + debug_game_ended(game); + + /* + * Final resource sync, score change notification and printfilter flush + * on game-instigated loop exit. + */ + res_sync_resources(game); + run_notify_score_change(game); + pf_flush(filter, vars, bundle); + + /* + * Reset static variables inside run_player_input() with a call to it with + * is_running false; this is a special case. + */ + assert(!game->is_running); + run_player_input(game); } @@ -1485,66 +1437,63 @@ run_main_loop (sc_gameref_t game) * Create a game context from a callback. */ sc_gameref_t -run_create (sc_read_callbackref_t callback, void *opaque) -{ - sc_tafref_t taf; - sc_prop_setref_t bundle; - sc_var_setref_t vars, temporary_vars, undo_vars; - sc_filterref_t filter; - sc_gameref_t game, temporary_game, undo_game; - assert (callback); - - /* Create a new TAF using the callback; return NULL if this fails. */ - taf = taf_create (callback, opaque); - if (!taf) - return NULL; - else if (if_get_trace_flag (SC_DUMP_TAF)) - taf_debug_dump (taf); - - /* Create a properties bundle, and parse the TAF data into it. */ - bundle = prop_create (taf); - if (!bundle) - { - sc_error ("run_create: error parsing game data\n"); - taf_destroy (taf); - return NULL; - } - else if (if_get_trace_flag (SC_DUMP_PROPERTIES)) - prop_debug_dump (bundle); - - /* Try to set an interpreter locale from the properties bundle. */ - loc_detect_game_locale (bundle); - if (if_get_trace_flag (SC_DUMP_LOCALE_TABLES)) - loc_debug_dump (); - - /* Create a set of variables from the bundle. */ - vars = var_create (bundle); - if (if_get_trace_flag (SC_DUMP_VARIABLES)) - var_debug_dump (vars); - - /* Create a printfilter for the game. */ - filter = pf_create (); - - /* - * Create an initial game state, and register it with variables. Also, - * create undo buffers, and initialize them in the same way. - */ - game = gs_create (vars, bundle, filter); - var_register_game (vars, game); - - temporary_vars = var_create (bundle); - temporary_game = gs_create (temporary_vars, bundle, filter); - var_register_game (temporary_vars, temporary_game); - - undo_vars = var_create (bundle); - undo_game = gs_create (undo_vars, bundle, filter); - var_register_game (undo_vars, undo_game); - - /* Add the undo buffers and memos to the game, and return it. */ - game->temporary = temporary_game; - game->undo = undo_game; - game->memento = memo_create (); - return game; +run_create(sc_read_callbackref_t callback, void *opaque) { + sc_tafref_t taf; + sc_prop_setref_t bundle; + sc_var_setref_t vars, temporary_vars, undo_vars; + sc_filterref_t filter; + sc_gameref_t game, temporary_game, undo_game; + assert(callback); + + /* Create a new TAF using the callback; return NULL if this fails. */ + taf = taf_create(callback, opaque); + if (!taf) + return NULL; + else if (if_get_trace_flag(SC_DUMP_TAF)) + taf_debug_dump(taf); + + /* Create a properties bundle, and parse the TAF data into it. */ + bundle = prop_create(taf); + if (!bundle) { + sc_error("run_create: error parsing game data\n"); + taf_destroy(taf); + return NULL; + } else if (if_get_trace_flag(SC_DUMP_PROPERTIES)) + prop_debug_dump(bundle); + + /* Try to set an interpreter locale from the properties bundle. */ + loc_detect_game_locale(bundle); + if (if_get_trace_flag(SC_DUMP_LOCALE_TABLES)) + loc_debug_dump(); + + /* Create a set of variables from the bundle. */ + vars = var_create(bundle); + if (if_get_trace_flag(SC_DUMP_VARIABLES)) + var_debug_dump(vars); + + /* Create a printfilter for the game. */ + filter = pf_create(); + + /* + * Create an initial game state, and register it with variables. Also, + * create undo buffers, and initialize them in the same way. + */ + game = gs_create(vars, bundle, filter); + var_register_game(vars, game); + + temporary_vars = var_create(bundle); + temporary_game = gs_create(temporary_vars, bundle, filter); + var_register_game(temporary_vars, temporary_game); + + undo_vars = var_create(bundle); + undo_game = gs_create(undo_vars, bundle, filter); + var_register_game(undo_vars, undo_game); + + /* Add the undo buffers and memos to the game, and return it. */ + game->temporary = temporary_game; + game->undo = undo_game; + game->memento = memo_create(); + return game; } @@ -1554,44 +1503,43 @@ run_create (sc_read_callbackref_t callback, void *opaque) * Return a game context to initial states to restart a game. */ static void -run_restart_handler (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_gameref_t new_game; - sc_var_setref_t new_vars; - - /* - * Create a fresh set of variables from the current game properties, - * then a new game using these variables and existing properties and - * printfilter. - */ - new_vars = var_create (bundle); - new_game = gs_create (new_vars, bundle, filter); - var_register_game (new_vars, new_game); - - /* - * Overwrite the dynamic parts of the current game with the new one. - */ - new_game->temporary = game->temporary; - new_game->undo = game->undo; - gs_copy (game, new_game); - - /* Destroy invalid game status strings. */ - sc_free (game->current_room_name); - game->current_room_name = NULL; - sc_free (game->status_line); - game->status_line = NULL; - - /* - * Now it's safely copied, destroy the temporary new game, and its - * associated variable set. - */ - gs_destroy (new_game); - var_destroy (new_vars); - - /* Reset resources handling. */ - res_cancel_resources (game); +run_restart_handler(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_gameref_t new_game; + sc_var_setref_t new_vars; + + /* + * Create a fresh set of variables from the current game properties, + * then a new game using these variables and existing properties and + * printfilter. + */ + new_vars = var_create(bundle); + new_game = gs_create(new_vars, bundle, filter); + var_register_game(new_vars, new_game); + + /* + * Overwrite the dynamic parts of the current game with the new one. + */ + new_game->temporary = game->temporary; + new_game->undo = game->undo; + gs_copy(game, new_game); + + /* Destroy invalid game status strings. */ + sc_free(game->current_room_name); + game->current_room_name = NULL; + sc_free(game->status_line); + game->status_line = NULL; + + /* + * Now it's safely copied, destroy the temporary new game, and its + * associated variable set. + */ + gs_destroy(new_game); + var_destroy(new_vars); + + /* Reset resources handling. */ + res_cancel_resources(game); } @@ -1601,20 +1549,19 @@ run_restart_handler (sc_gameref_t game) * Adjust a game context for continuation after restoring a game. */ static void -run_restore_handler (sc_gameref_t game) -{ - /* Invalidate the undo buffer. */ - game->undo_available = FALSE; - - /* - * Resources handling? Arguably we should re-offer resources active when - * the game was saved, but I can't see how this can be achieved with Adrift - * the way it is. Canceling is too broad, so I'll go here with just - * stopping sounds (in case looping). - * - * TODO Rationalize what happens here. - */ - game->stop_sound = TRUE; +run_restore_handler(sc_gameref_t game) { + /* Invalidate the undo buffer. */ + game->undo_available = FALSE; + + /* + * Resources handling? Arguably we should re-offer resources active when + * the game was saved, but I can't see how this can be achieved with Adrift + * the way it is. Canceling is too broad, so I'll go here with just + * stopping sounds (in case looping). + * + * TODO Rationalize what happens here. + */ + game->stop_sound = TRUE; } @@ -1624,25 +1571,24 @@ run_restore_handler (sc_gameref_t game) * Tidy up printfilter and input statics on game quit. */ static void -run_quit_handler (sc_gameref_t game) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - - /* Flush printfilter and notifications of any dangling output. */ - run_notify_score_change (game); - pf_flush (filter, vars, bundle); - - /* Cancel any active resources. */ - res_cancel_resources (game); - - /* - * Make the special call to reset all of the static variables inside - * run_player_input(). - */ - assert (!game->is_running); - run_player_input (game); +run_quit_handler(sc_gameref_t game) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + + /* Flush printfilter and notifications of any dangling output. */ + run_notify_score_change(game); + pf_flush(filter, vars, bundle); + + /* Cancel any active resources. */ + res_cancel_resources(game); + + /* + * Make the special call to reset all of the static variables inside + * run_player_input(). + */ + assert(!game->is_running); + run_player_input(game); } @@ -1652,60 +1598,52 @@ run_quit_handler (sc_gameref_t game) * Intepret the game in a game context. */ void -run_interpret (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); - - /* Verify the game is not already running, and is runnable. */ - if (game->is_running) - { - sc_error ("run_interpret: game is already running\n"); - return; - } - if (game->has_completed) - { - sc_error ("run_interpret: game has already completed\n"); - return; - } - - /* Refuse to run a game with no rooms. */ - if (gs_room_count (game) == 0) - { - sc_error ("run_interpret: game contains no rooms\n"); - return; - } - - /* Run the main interpreter loop until no more restarts. */ - game->is_running = TRUE; - do - { - /* Run the game until some form of halt is requested. */ - if (setjmp (game->quitter) == 0) - run_main_loop (game); - - /* - * If the halt was a restart or restore, cancel the request, handle - * restart or restore game adjustments, and set the game running - * again. - */ - if (game->do_restart) - { - game->do_restart = FALSE; - run_restart_handler (game); - game->is_running = TRUE; - } - - if (game->do_restore) - { - game->do_restore = FALSE; - run_restore_handler (game); - game->is_running = TRUE; - } - } - while (game->is_running); - - /* Tidy up the printfilter and input statics. */ - run_quit_handler (game); +run_interpret(sc_gameref_t game) { + assert(gs_is_game_valid(game)); + + /* Verify the game is not already running, and is runnable. */ + if (game->is_running) { + sc_error("run_interpret: game is already running\n"); + return; + } + if (game->has_completed) { + sc_error("run_interpret: game has already completed\n"); + return; + } + + /* Refuse to run a game with no rooms. */ + if (gs_room_count(game) == 0) { + sc_error("run_interpret: game contains no rooms\n"); + return; + } + + /* Run the main interpreter loop until no more restarts. */ + game->is_running = TRUE; + do { + /* Run the game until some form of halt is requested. */ + if (setjmp(game->quitter) == 0) + run_main_loop(game); + + /* + * If the halt was a restart or restore, cancel the request, handle + * restart or restore game adjustments, and set the game running + * again. + */ + if (game->do_restart) { + game->do_restart = FALSE; + run_restart_handler(game); + game->is_running = TRUE; + } + + if (game->do_restore) { + game->do_restore = FALSE; + run_restore_handler(game); + game->is_running = TRUE; + } + } while (game->is_running); + + /* Tidy up the printfilter and input statics. */ + run_quit_handler(game); } @@ -1715,52 +1653,50 @@ run_interpret (sc_gameref_t game) * Destroy a game context, and free all resources. */ void -run_destroy (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); - - /* Can't destroy the context of a running game. */ - if (game->is_running) - { - sc_error ("run_destroy: game is running, stop it first\n"); - return; - } - - /* - * Cancel any game state debugger -- this frees its resources. Only the - * primary game may have acquired a debugger. - */ - debug_set_enabled (game, FALSE); - assert (!debug_get_enabled (game->temporary)); - assert (!debug_get_enabled (game->undo)); - - /* - * Destroy the game state, variables, properties bundle, memos, undo - * buffers and their variables, and filter. The bundle and printfilter - * are shared by the main game, the undo game, and the temporary game, so - * destroy these only once! The main game has a memento, but it is not - * visible to these other two games, neither of which have one. - */ - assert (gs_get_bundle (game->temporary) == gs_get_bundle (game)); - assert (gs_get_filter (game->temporary) == gs_get_filter (game)); - assert (gs_get_vars (game->temporary) != gs_get_vars (game)); - assert (!gs_get_memento (game->temporary)); - var_destroy (gs_get_vars (game->temporary)); - gs_destroy (game->temporary); - - assert (gs_get_bundle (game->undo) == gs_get_bundle (game)); - assert (gs_get_filter (game->undo) == gs_get_filter (game)); - assert (gs_get_vars (game->undo) != gs_get_vars (game)); - assert (!gs_get_memento (game->undo)); - var_destroy (gs_get_vars (game->undo)); - gs_destroy (game->undo); - - prop_destroy (gs_get_bundle (game)); - pf_destroy (gs_get_filter (game)); - var_destroy (gs_get_vars (game)); - memo_destroy (gs_get_memento (game)); - - gs_destroy (game); +run_destroy(sc_gameref_t game) { + assert(gs_is_game_valid(game)); + + /* Can't destroy the context of a running game. */ + if (game->is_running) { + sc_error("run_destroy: game is running, stop it first\n"); + return; + } + + /* + * Cancel any game state debugger -- this frees its resources. Only the + * primary game may have acquired a debugger. + */ + debug_set_enabled(game, FALSE); + assert(!debug_get_enabled(game->temporary)); + assert(!debug_get_enabled(game->undo)); + + /* + * Destroy the game state, variables, properties bundle, memos, undo + * buffers and their variables, and filter. The bundle and printfilter + * are shared by the main game, the undo game, and the temporary game, so + * destroy these only once! The main game has a memento, but it is not + * visible to these other two games, neither of which have one. + */ + assert(gs_get_bundle(game->temporary) == gs_get_bundle(game)); + assert(gs_get_filter(game->temporary) == gs_get_filter(game)); + assert(gs_get_vars(game->temporary) != gs_get_vars(game)); + assert(!gs_get_memento(game->temporary)); + var_destroy(gs_get_vars(game->temporary)); + gs_destroy(game->temporary); + + assert(gs_get_bundle(game->undo) == gs_get_bundle(game)); + assert(gs_get_filter(game->undo) == gs_get_filter(game)); + assert(gs_get_vars(game->undo) != gs_get_vars(game)); + assert(!gs_get_memento(game->undo)); + var_destroy(gs_get_vars(game->undo)); + gs_destroy(game->undo); + + prop_destroy(gs_get_bundle(game)); + pf_destroy(gs_get_filter(game)); + var_destroy(gs_get_vars(game)); + memo_destroy(gs_get_memento(game)); + + gs_destroy(game); } @@ -1771,21 +1707,19 @@ run_destroy (sc_gameref_t game) * run_main_loop() returned, and so never returns to its caller. */ void -run_quit (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); - - /* Disallow quitting a non-running game. */ - if (!game->is_running) - { - sc_error ("run_quit: game is not running\n"); - return; - } - - /* Exit the main loop with a longjump. */ - game->is_running = FALSE; - longjmp (game->quitter, 1); - sc_fatal ("run_quit: unable to quit cleanly\n"); +run_quit(sc_gameref_t game) { + assert(gs_is_game_valid(game)); + + /* Disallow quitting a non-running game. */ + if (!game->is_running) { + sc_error("run_quit: game is not running\n"); + return; + } + + /* Exit the main loop with a longjump. */ + game->is_running = FALSE; + longjmp(game->quitter, 1); + sc_fatal("run_quit: unable to quit cleanly\n"); } @@ -1797,25 +1731,23 @@ run_quit (sc_gameref_t game) * never returns to its caller. For stopped games, it returns. */ void -run_restart (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); - - /* - * If the game is running, stop it, request a restart, and exit the main - * loop with a longjump. - */ - if (game->is_running) - { - game->is_running = FALSE; - game->do_restart = TRUE; - longjmp (game->quitter, 1); - sc_fatal ("run_restart: unable to restart cleanly\n"); - } - - /* Restart locally, and ensure that the game remains stopped. */ - run_restart_handler (game); - game->is_running = FALSE; +run_restart(sc_gameref_t game) { + assert(gs_is_game_valid(game)); + + /* + * If the game is running, stop it, request a restart, and exit the main + * loop with a longjump. + */ + if (game->is_running) { + game->is_running = FALSE; + game->do_restart = TRUE; + longjmp(game->quitter, 1); + sc_fatal("run_restart: unable to restart cleanly\n"); + } + + /* Restart locally, and ensure that the game remains stopped. */ + run_restart_handler(game); + game->is_running = FALSE; } @@ -1826,20 +1758,18 @@ run_restart (sc_gameref_t game) * Saves either a running or a stopped game. */ void -run_save (sc_gameref_t game, sc_write_callbackref_t callback, void *opaque) -{ - assert (gs_is_game_valid (game)); - assert (callback); +run_save(sc_gameref_t game, sc_write_callbackref_t callback, void *opaque) { + assert(gs_is_game_valid(game)); + assert(callback); - ser_save_game (game, callback, opaque); + ser_save_game(game, callback, opaque); } sc_bool -run_save_prompted (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); +run_save_prompted(sc_gameref_t game) { + assert(gs_is_game_valid(game)); - return ser_save_game_prompted (game); + return ser_save_game_prompted(game); } @@ -1855,56 +1785,51 @@ run_save_prompted (sc_gameref_t game) * FALSE if restore failed. */ static sc_bool -run_restore_common (sc_gameref_t game, - sc_read_callbackref_t callback, void *opaque) -{ - sc_bool is_running, status; - - /* - * Save the game running flag, and call the restore appropriate for the - * caller. The indication of a call from run_restore_prompted() is a - * callback of NULL; callback cannot be NULL for run_restore() calls. - */ - is_running = game->is_running; - status = callback ? ser_load_game (game, callback, opaque) - : ser_load_game_prompted (game); - if (status) - { - /* Loading a game clears is_running -- restore it here. */ - game->is_running = is_running; - - /* - * If the game is (was) running, set flags so that the interpreter - * loop cycles, and exit the main loop with a longjump. - */ - if (game->is_running) - { - game->is_running = FALSE; - game->do_restore = TRUE; - longjmp (game->quitter, 1); - sc_fatal ("run_restore_common: unable to restart cleanly\n"); - } - } - - /* Return TRUE on successful restore of a stopped game, FALSE on error. */ - return status; +run_restore_common(sc_gameref_t game, + sc_read_callbackref_t callback, void *opaque) { + sc_bool is_running, status; + + /* + * Save the game running flag, and call the restore appropriate for the + * caller. The indication of a call from run_restore_prompted() is a + * callback of NULL; callback cannot be NULL for run_restore() calls. + */ + is_running = game->is_running; + status = callback ? ser_load_game(game, callback, opaque) + : ser_load_game_prompted(game); + if (status) { + /* Loading a game clears is_running -- restore it here. */ + game->is_running = is_running; + + /* + * If the game is (was) running, set flags so that the interpreter + * loop cycles, and exit the main loop with a longjump. + */ + if (game->is_running) { + game->is_running = FALSE; + game->do_restore = TRUE; + longjmp(game->quitter, 1); + sc_fatal("run_restore_common: unable to restart cleanly\n"); + } + } + + /* Return TRUE on successful restore of a stopped game, FALSE on error. */ + return status; } sc_bool -run_restore (sc_gameref_t game, sc_read_callbackref_t callback, void *opaque) -{ - assert (gs_is_game_valid (game)); - assert (callback); +run_restore(sc_gameref_t game, sc_read_callbackref_t callback, void *opaque) { + assert(gs_is_game_valid(game)); + assert(callback); - return run_restore_common (game, callback, opaque); + return run_restore_common(game, callback, opaque); } sc_bool -run_restore_prompted (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); +run_restore_prompted(sc_gameref_t game) { + assert(gs_is_game_valid(game)); - return run_restore_common (game, NULL, NULL); + return run_restore_common(game, NULL, NULL); } @@ -1915,58 +1840,54 @@ run_restore_prompted (sc_gameref_t game) * successful undo, FALSE if no undo buffer is available. */ sc_bool -run_undo (sc_gameref_t game) -{ - const sc_memo_setref_t memento = gs_get_memento (game); - sc_bool is_running; - assert (gs_is_game_valid (game)); - - /* Save the game's running state, so we can restore it later. */ - is_running = game->is_running; - - /* If there's an undo buffer available, restore it. */ - if (game->undo_available) - { - /* Restore the undo buffer, and then restore running flag. */ - gs_copy (game, game->undo); - game->undo_available = FALSE; - game->is_running = is_running; - - /* Location may have changed; update status. */ - run_update_status (game); - - /* Bring resources into line with the revised game. */ - res_sync_resources (game); - return TRUE; - } - - /* - * If there is no undo buffer, try to restore one saved previously in a - * memo. Handle as if restoring from a file. - */ - if (memo_load_game (memento, game)) - { - /* Loading a game clears is_running -- restore it here. */ - game->is_running = is_running; - - /* - * If the game is (was) running, set flags so that the interpreter - * loop cycles, and exit the main loop with a longjump. - */ - if (game->is_running) - { - game->is_running = FALSE; - game->do_restore = TRUE; - longjmp (game->quitter, 1); - sc_fatal ("run_undo: unable to restart cleanly\n"); - } - - /* Game undo on non-running game accomplished with memos. */ - return TRUE; - } - - /* No undo buffer and no memos available. */ - return FALSE; +run_undo(sc_gameref_t game) { + const sc_memo_setref_t memento = gs_get_memento(game); + sc_bool is_running; + assert(gs_is_game_valid(game)); + + /* Save the game's running state, so we can restore it later. */ + is_running = game->is_running; + + /* If there's an undo buffer available, restore it. */ + if (game->undo_available) { + /* Restore the undo buffer, and then restore running flag. */ + gs_copy(game, game->undo); + game->undo_available = FALSE; + game->is_running = is_running; + + /* Location may have changed; update status. */ + run_update_status(game); + + /* Bring resources into line with the revised game. */ + res_sync_resources(game); + return TRUE; + } + + /* + * If there is no undo buffer, try to restore one saved previously in a + * memo. Handle as if restoring from a file. + */ + if (memo_load_game(memento, game)) { + /* Loading a game clears is_running -- restore it here. */ + game->is_running = is_running; + + /* + * If the game is (was) running, set flags so that the interpreter + * loop cycles, and exit the main loop with a longjump. + */ + if (game->is_running) { + game->is_running = FALSE; + game->do_restore = TRUE; + longjmp(game->quitter, 1); + sc_fatal("run_undo: unable to restart cleanly\n"); + } + + /* Game undo on non-running game accomplished with memos. */ + return TRUE; + } + + /* No undo buffer and no memos available. */ + return FALSE; } @@ -1976,11 +1897,10 @@ run_undo (sc_gameref_t game) * Query the game running state. */ sc_bool -run_is_running (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); +run_is_running(sc_gameref_t game) { + assert(gs_is_game_valid(game)); - return game->is_running; + return game->is_running; } @@ -1991,11 +1911,10 @@ run_is_running (sc_gameref_t game) * since they've run the exit task and thus have nowhere to go. */ sc_bool -run_has_completed (sc_gameref_t game) -{ - assert (gs_is_game_valid (game)); +run_has_completed(sc_gameref_t game) { + assert(gs_is_game_valid(game)); - return game->has_completed; + return game->has_completed; } @@ -2005,12 +1924,11 @@ run_has_completed (sc_gameref_t game) * Query the game turn undo buffer and memo availability. */ sc_bool -run_is_undo_available (sc_gameref_t game) -{ - const sc_memo_setref_t memento = gs_get_memento (game); - assert (gs_is_game_valid (game)); +run_is_undo_available(sc_gameref_t game) { + const sc_memo_setref_t memento = gs_get_memento(game); + assert(gs_is_game_valid(game)); - return game->undo_available || memo_is_load_available (memento); + return game->undo_available || memo_is_load_available(memento); } @@ -2021,110 +1939,99 @@ run_is_undo_available (sc_gameref_t game) * Get and set selected game attributes. */ void -run_get_attributes (sc_gameref_t game, - const sc_char **game_name, const sc_char **game_author, - const sc_char **game_compile_date, - sc_int *turns, sc_int *score, sc_int *max_score, - const sc_char **current_room_name, - const sc_char **status_line, const sc_char **preferred_font, - sc_bool *bold_room_names, sc_bool *verbose, - sc_bool *notify_score_change) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[2]; - assert (gs_is_game_valid (game)); - - /* Return the game name, author, and compile date if requested. */ - if (game_name) - { - if (!game->title) - { - const sc_char *gamename; - sc_char *filtered; - - vt_key[0].string = "Globals"; - vt_key[1].string = "GameName"; - gamename = prop_get_string (bundle, "S<-ss", vt_key); - - filtered = pf_filter_for_info (gamename, vars); - pf_strip_tags (filtered); - game->title = filtered; - } - *game_name = game->title; - } - if (game_author) - { - if (!game->author) - { - const sc_char *gameauthor; - sc_char *filtered; - - vt_key[0].string = "Globals"; - vt_key[1].string = "GameAuthor"; - gameauthor = prop_get_string (bundle, "S<-ss", vt_key); - - filtered = pf_filter_for_info (gameauthor, vars); - pf_strip_tags (filtered); - game->author = filtered; - } - *game_author = game->author; - } - if (game_compile_date) - { - vt_key[0].string = "CompileDate"; - *game_compile_date = prop_get_string (bundle, "S<-s", vt_key); - } - - /* Return the current room name and status line if requested. */ - if (current_room_name) - *current_room_name = game->current_room_name; - if (status_line) - *status_line = game->status_line; - - /* Return any game preferred font, or NULL if none. */ - if (preferred_font) - { - vt_key[0].string = "CustomFont"; - if (prop_get_boolean (bundle, "B<-s", vt_key)) - { - vt_key[0].string = "FontNameSize"; - *preferred_font = prop_get_string (bundle, "S<-s", vt_key); - } - else - *preferred_font = NULL; - } - - /* Return any other selected game attributes. */ - if (turns) - *turns = game->turns; - if (score) - *score = game->score; - if (max_score) - { - vt_key[0].string = "Globals"; - vt_key[1].string = "MaxScore"; - *max_score = prop_get_integer (bundle, "I<-ss", vt_key); - } - if (bold_room_names) - *bold_room_names = game->bold_room_names; - if (verbose) - *verbose = game->verbose; - if (notify_score_change) - *notify_score_change = game->notify_score_change; +run_get_attributes(sc_gameref_t game, + const sc_char **game_name, const sc_char **game_author, + const sc_char **game_compile_date, + sc_int *turns, sc_int *score, sc_int *max_score, + const sc_char **current_room_name, + const sc_char **status_line, const sc_char **preferred_font, + sc_bool *bold_room_names, sc_bool *verbose, + sc_bool *notify_score_change) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[2]; + assert(gs_is_game_valid(game)); + + /* Return the game name, author, and compile date if requested. */ + if (game_name) { + if (!game->title) { + const sc_char *gamename; + sc_char *filtered; + + vt_key[0].string = "Globals"; + vt_key[1].string = "GameName"; + gamename = prop_get_string(bundle, "S<-ss", vt_key); + + filtered = pf_filter_for_info(gamename, vars); + pf_strip_tags(filtered); + game->title = filtered; + } + *game_name = game->title; + } + if (game_author) { + if (!game->author) { + const sc_char *gameauthor; + sc_char *filtered; + + vt_key[0].string = "Globals"; + vt_key[1].string = "GameAuthor"; + gameauthor = prop_get_string(bundle, "S<-ss", vt_key); + + filtered = pf_filter_for_info(gameauthor, vars); + pf_strip_tags(filtered); + game->author = filtered; + } + *game_author = game->author; + } + if (game_compile_date) { + vt_key[0].string = "CompileDate"; + *game_compile_date = prop_get_string(bundle, "S<-s", vt_key); + } + + /* Return the current room name and status line if requested. */ + if (current_room_name) + *current_room_name = game->current_room_name; + if (status_line) + *status_line = game->status_line; + + /* Return any game preferred font, or NULL if none. */ + if (preferred_font) { + vt_key[0].string = "CustomFont"; + if (prop_get_boolean(bundle, "B<-s", vt_key)) { + vt_key[0].string = "FontNameSize"; + *preferred_font = prop_get_string(bundle, "S<-s", vt_key); + } else + *preferred_font = NULL; + } + + /* Return any other selected game attributes. */ + if (turns) + *turns = game->turns; + if (score) + *score = game->score; + if (max_score) { + vt_key[0].string = "Globals"; + vt_key[1].string = "MaxScore"; + *max_score = prop_get_integer(bundle, "I<-ss", vt_key); + } + if (bold_room_names) + *bold_room_names = game->bold_room_names; + if (verbose) + *verbose = game->verbose; + if (notify_score_change) + *notify_score_change = game->notify_score_change; } void -run_set_attributes (sc_gameref_t game, - sc_bool bold_room_names, sc_bool verbose, - sc_bool notify_score_change) -{ - assert (gs_is_game_valid (game)); - - /* Set game options. */ - game->bold_room_names = bold_room_names; - game->verbose = verbose; - game->notify_score_change = notify_score_change; +run_set_attributes(sc_gameref_t game, + sc_bool bold_room_names, sc_bool verbose, + sc_bool notify_score_change) { + assert(gs_is_game_valid(game)); + + /* Set game options. */ + game->bold_room_names = bold_room_names; + game->verbose = verbose; + game->notify_score_change = notify_score_change; } @@ -2138,40 +2045,36 @@ run_set_attributes (sc_gameref_t game, * the client as a void*. */ sc_hintref_t -run_hint_iterate (sc_gameref_t game, sc_hintref_t hint) -{ - sc_int task; - assert (gs_is_game_valid (game)); - - /* - * Hint is a pointer to a task state; convert to a task index, adding one - * to move on to the next task, or start at the first task if null. - */ - if (!hint) - task = 0; - else - { - /* Convert into pointer, and range check. */ - task = hint - game->tasks; - if (task < 0 || task >= gs_task_count (game)) - { - sc_error ("run_hint_iterate: invalid iteration hint\n"); - return NULL; - } - - /* Advance beyond current task. */ - task++; - } - - /* Scan for the next runnable task that offers a hint. */ - for (; task < gs_task_count (game); task++) - { - if (task_can_run_task (game, task) && task_has_hints (game, task)) - break; - } - - /* Return a pointer to the state of the task identified, or NULL. */ - return task < gs_task_count (game) ? game->tasks + task : NULL; +run_hint_iterate(sc_gameref_t game, sc_hintref_t hint) { + sc_int task; + assert(gs_is_game_valid(game)); + + /* + * Hint is a pointer to a task state; convert to a task index, adding one + * to move on to the next task, or start at the first task if null. + */ + if (!hint) + task = 0; + else { + /* Convert into pointer, and range check. */ + task = hint - game->tasks; + if (task < 0 || task >= gs_task_count(game)) { + sc_error("run_hint_iterate: invalid iteration hint\n"); + return NULL; + } + + /* Advance beyond current task. */ + task++; + } + + /* Scan for the next runnable task that offers a hint. */ + for (; task < gs_task_count(game); task++) { + if (task_can_run_task(game, task) && task_has_hints(game, task)) + break; + } + + /* Return a pointer to the state of the task identified, or NULL. */ + return task < gs_task_count(game) ? game->tasks + task : NULL; } @@ -2189,66 +2092,56 @@ run_hint_iterate (sc_gameref_t game, sc_hintref_t hint) * Hint strings are NULL if empty (not defined by the game). */ static const sc_char * -run_get_hint_common (sc_gameref_t game, sc_hintref_t hint, - const sc_char *(*handler) (sc_gameref_t, sc_int)) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_int task; - const sc_char *string; - assert (gs_is_game_valid (game)); - - /* Verify the caller passed in a valid hint. */ - task = hint - game->tasks; - if (task < 0 || task >= gs_task_count (game)) - { - sc_error ("run_get_hint_common: invalid iteration hint\n"); - return NULL; - } - else if (!task_has_hints (game, task)) - { - sc_error ("run_get_hint_common: task has no hint\n"); - return NULL; - } - - /* Get the required game text by calling the given handler function. */ - string = handler (game, task); - if (!sc_strempty (string)) - { - sc_char *filtered; - - /* Filter and strip tags, note in game. */ - filtered = pf_filter (string, vars, bundle); - pf_strip_tags_for_hints (filtered); - sc_free (game->hint_text); - game->hint_text = filtered; - } - else - { - /* Hint text is empty; drop any text noted in game. */ - sc_free (game->hint_text); - game->hint_text = NULL; - } - - return game->hint_text; +run_get_hint_common(sc_gameref_t game, sc_hintref_t hint, + const sc_char * (*handler)(sc_gameref_t, sc_int)) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_int task; + const sc_char *string; + assert(gs_is_game_valid(game)); + + /* Verify the caller passed in a valid hint. */ + task = hint - game->tasks; + if (task < 0 || task >= gs_task_count(game)) { + sc_error("run_get_hint_common: invalid iteration hint\n"); + return NULL; + } else if (!task_has_hints(game, task)) { + sc_error("run_get_hint_common: task has no hint\n"); + return NULL; + } + + /* Get the required game text by calling the given handler function. */ + string = handler(game, task); + if (!sc_strempty(string)) { + sc_char *filtered; + + /* Filter and strip tags, note in game. */ + filtered = pf_filter(string, vars, bundle); + pf_strip_tags_for_hints(filtered); + sc_free(game->hint_text); + game->hint_text = filtered; + } else { + /* Hint text is empty; drop any text noted in game. */ + sc_free(game->hint_text); + game->hint_text = NULL; + } + + return game->hint_text; } const sc_char * -run_get_hint_question (sc_gameref_t game, sc_hintref_t hint) -{ - return run_get_hint_common (game, hint, task_get_hint_question); +run_get_hint_question(sc_gameref_t game, sc_hintref_t hint) { + return run_get_hint_common(game, hint, task_get_hint_question); } const sc_char * -run_get_subtle_hint (sc_gameref_t game, sc_hintref_t hint) -{ - return run_get_hint_common (game, hint, task_get_hint_subtle); +run_get_subtle_hint(sc_gameref_t game, sc_hintref_t hint) { + return run_get_hint_common(game, hint, task_get_hint_subtle); } const sc_char * -run_get_unsubtle_hint (sc_gameref_t game, sc_hintref_t hint) -{ - return run_get_hint_common (game, hint, task_get_hint_unsubtle); +run_get_unsubtle_hint(sc_gameref_t game, sc_hintref_t hint) { + return run_get_hint_common(game, hint, task_get_hint_unsubtle); } } // End of namespace Adrift diff --git a/engines/glk/adrift/scserial.cpp b/engines/glk/adrift/scserial.cpp index 3ade8ac124..9c41db25b4 100644 --- a/engines/glk/adrift/scserial.cpp +++ b/engines/glk/adrift/scserial.cpp @@ -50,156 +50,145 @@ static void *ser_opaque = NULL; * * Flush pending buffer contents; add a character to the buffer. */ -static void ser_flush (sc_bool is_final) -{ +static void ser_flush(sc_bool is_final) { error("TODO"); #ifdef TODO - static sc_bool initialized = FALSE; - static sc_byte *out_buffer = NULL; - static sc_int out_buffer_size = 0; - static z_stream stream; - - sc_int status; - - /* If this is an initial call, initialize deflation. */ - if (!initialized) - { - /* Allocate an initial output buffer. */ - out_buffer_size = BUFFER_SIZE; - out_buffer = sc_malloc (out_buffer_size); - - /* Initialize Zlib deflation functions. */ - stream.next_out = out_buffer; - stream.avail_out = out_buffer_size; - stream.next_in = ser_buffer; - stream.avail_in = 0; - - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - - status = deflateInit (&stream, Z_DEFAULT_COMPRESSION); - if (status != Z_OK) - { - sc_error ("ser_flush: deflateInit: error %ld\n", status); - ser_buffer_length = 0; - - sc_free (out_buffer); - out_buffer = NULL; - out_buffer_size = 0; - return; - } - - initialized = TRUE; - } - - /* Deflate data from the current output buffer. */ - stream.next_in = ser_buffer; - stream.avail_in = ser_buffer_length; - - /* Loop while deflate output is pending and buffer not emptied. */ - while (TRUE) - { - sc_int in_bytes, out_bytes; - - /* Compress stream data, with finish if this is the final flush. */ - if (is_final) - status = deflate (&stream, Z_FINISH); - else - status = deflate (&stream, Z_NO_FLUSH); - if (status != Z_STREAM_END && status != Z_OK) - { - sc_error ("ser_flush: deflate: error %ld\n", status); - ser_buffer_length = 0; - - sc_free (out_buffer); - out_buffer = NULL; - out_buffer_size = 0; - initialized = FALSE; - return; - } - - /* Calculate bytes used, and output. */ - in_bytes = ser_buffer_length - stream.avail_in; - out_bytes = out_buffer_size - stream.avail_out; - - /* See if compressed data is available. */ - if (out_bytes > 0) - { - /* Write it to save file output through the callback. */ - ser_callback (ser_opaque, out_buffer, out_bytes); - - /* Reset deflation stream for available space. */ - stream.next_out = out_buffer; - stream.avail_out = out_buffer_size; - } - - /* Remove consumed data from the input buffer. */ - if (in_bytes > 0) - { - /* Move any unused data, and reduce length. */ - memmove (ser_buffer, - ser_buffer + in_bytes, ser_buffer_length - in_bytes); - ser_buffer_length -= in_bytes; - - /* Reset deflation stream for consumed data. */ - stream.next_in = ser_buffer; - stream.avail_in = ser_buffer_length; - } - - /* If final flush, wait until deflate indicates finished. */ - if (is_final && status == Z_OK) - continue; - - /* If data was consumed or produced, break. */ - if (out_bytes > 0 || in_bytes > 0) - break; - } - - /* If this was a final call, clean up. */ - if (is_final) - { - /* Compression completed. */ - status = deflateEnd (&stream); - if (status != Z_OK) - sc_error ("ser_flush: warning: deflateEnd: error %ld\n", status); - - if (ser_buffer_length != 0) - { - sc_error ("ser_flush: warning: deflate missed data\n"); - ser_buffer_length = 0; - } - - /* Free the allocated compression buffer. */ - sc_free (ser_buffer); - ser_buffer = NULL; - - /* - * Free output buffer, and reset flag for reinitialization on the next - * call. - */ - sc_free (out_buffer); - out_buffer = NULL; - out_buffer_size = 0; - initialized = FALSE; - } + static sc_bool initialized = FALSE; + static sc_byte *out_buffer = NULL; + static sc_int out_buffer_size = 0; + static z_stream stream; + + sc_int status; + + /* If this is an initial call, initialize deflation. */ + if (!initialized) { + /* Allocate an initial output buffer. */ + out_buffer_size = BUFFER_SIZE; + out_buffer = sc_malloc(out_buffer_size); + + /* Initialize Zlib deflation functions. */ + stream.next_out = out_buffer; + stream.avail_out = out_buffer_size; + stream.next_in = ser_buffer; + stream.avail_in = 0; + + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + status = deflateInit(&stream, Z_DEFAULT_COMPRESSION); + if (status != Z_OK) { + sc_error("ser_flush: deflateInit: error %ld\n", status); + ser_buffer_length = 0; + + sc_free(out_buffer); + out_buffer = NULL; + out_buffer_size = 0; + return; + } + + initialized = TRUE; + } + + /* Deflate data from the current output buffer. */ + stream.next_in = ser_buffer; + stream.avail_in = ser_buffer_length; + + /* Loop while deflate output is pending and buffer not emptied. */ + while (TRUE) { + sc_int in_bytes, out_bytes; + + /* Compress stream data, with finish if this is the final flush. */ + if (is_final) + status = deflate(&stream, Z_FINISH); + else + status = deflate(&stream, Z_NO_FLUSH); + if (status != Z_STREAM_END && status != Z_OK) { + sc_error("ser_flush: deflate: error %ld\n", status); + ser_buffer_length = 0; + + sc_free(out_buffer); + out_buffer = NULL; + out_buffer_size = 0; + initialized = FALSE; + return; + } + + /* Calculate bytes used, and output. */ + in_bytes = ser_buffer_length - stream.avail_in; + out_bytes = out_buffer_size - stream.avail_out; + + /* See if compressed data is available. */ + if (out_bytes > 0) { + /* Write it to save file output through the callback. */ + ser_callback(ser_opaque, out_buffer, out_bytes); + + /* Reset deflation stream for available space. */ + stream.next_out = out_buffer; + stream.avail_out = out_buffer_size; + } + + /* Remove consumed data from the input buffer. */ + if (in_bytes > 0) { + /* Move any unused data, and reduce length. */ + memmove(ser_buffer, + ser_buffer + in_bytes, ser_buffer_length - in_bytes); + ser_buffer_length -= in_bytes; + + /* Reset deflation stream for consumed data. */ + stream.next_in = ser_buffer; + stream.avail_in = ser_buffer_length; + } + + /* If final flush, wait until deflate indicates finished. */ + if (is_final && status == Z_OK) + continue; + + /* If data was consumed or produced, break. */ + if (out_bytes > 0 || in_bytes > 0) + break; + } + + /* If this was a final call, clean up. */ + if (is_final) { + /* Compression completed. */ + status = deflateEnd(&stream); + if (status != Z_OK) + sc_error("ser_flush: warning: deflateEnd: error %ld\n", status); + + if (ser_buffer_length != 0) { + sc_error("ser_flush: warning: deflate missed data\n"); + ser_buffer_length = 0; + } + + /* Free the allocated compression buffer. */ + sc_free(ser_buffer); + ser_buffer = NULL; + + /* + * Free output buffer, and reset flag for reinitialization on the next + * call. + */ + sc_free(out_buffer); + out_buffer = NULL; + out_buffer_size = 0; + initialized = FALSE; + } #endif } static void -ser_buffer_character (sc_char character) -{ - /* Allocate the buffer if not yet done. */ - if (!ser_buffer) - { - assert (ser_buffer_length == 0); - ser_buffer = (sc_byte *)sc_malloc (BUFFER_SIZE); - } - - /* Add to the buffer, with intermediate flush if filled. */ - ser_buffer[ser_buffer_length++] = character; - if (ser_buffer_length == BUFFER_SIZE) - ser_flush (FALSE); +ser_buffer_character(sc_char character) { + /* Allocate the buffer if not yet done. */ + if (!ser_buffer) { + assert(ser_buffer_length == 0); + ser_buffer = (sc_byte *)sc_malloc(BUFFER_SIZE); + } + + /* Add to the buffer, with intermediate flush if filled. */ + ser_buffer[ser_buffer_length++] = character; + if (ser_buffer_length == BUFFER_SIZE) + ser_flush(FALSE); } @@ -214,59 +203,53 @@ ser_buffer_character (sc_char character) * Buffer a buffer, a string, an unsigned and signed integer, and a boolean. */ static void -ser_buffer_buffer (const sc_char *buffer, sc_int length) -{ - sc_int index_; +ser_buffer_buffer(const sc_char *buffer, sc_int length) { + sc_int index_; - /* Add each character to the buffer. */ - for (index_ = 0; index_ < length; index_++) - ser_buffer_character (buffer[index_]); + /* Add each character to the buffer. */ + for (index_ = 0; index_ < length; index_++) + ser_buffer_character(buffer[index_]); } static void -ser_buffer_string (const sc_char *string) -{ - /* Buffer string, followed by DOS style end-of-line. */ - ser_buffer_buffer (string, strlen (string)); - ser_buffer_character (CARRIAGE_RETURN); - ser_buffer_character (NEWLINE); +ser_buffer_string(const sc_char *string) { + /* Buffer string, followed by DOS style end-of-line. */ + ser_buffer_buffer(string, strlen(string)); + ser_buffer_character(CARRIAGE_RETURN); + ser_buffer_character(NEWLINE); } static void -ser_buffer_int (sc_int value) -{ - sc_char buffer[32]; +ser_buffer_int(sc_int value) { + sc_char buffer[32]; - /* Convert to a string and buffer that. */ - sprintf (buffer, "%ld", value); - ser_buffer_string (buffer); + /* Convert to a string and buffer that. */ + sprintf(buffer, "%ld", value); + ser_buffer_string(buffer); } static void -ser_buffer_int_special (sc_int value) -{ - sc_char buffer[32]; +ser_buffer_int_special(sc_int value) { + sc_char buffer[32]; - /* Weirdo formatting for compatibility. */ - sprintf (buffer, "% ld ", value); - ser_buffer_string (buffer); + /* Weirdo formatting for compatibility. */ + sprintf(buffer, "% ld ", value); + ser_buffer_string(buffer); } static void -ser_buffer_uint (sc_uint value) -{ - sc_char buffer[32]; +ser_buffer_uint(sc_uint value) { + sc_char buffer[32]; - /* Convert to a string and buffer that. */ - sprintf (buffer, "%lu", value); - ser_buffer_string (buffer); + /* Convert to a string and buffer that. */ + sprintf(buffer, "%lu", value); + ser_buffer_string(buffer); } static void -ser_buffer_boolean (sc_bool boolean) -{ - /* Write a 1 for TRUE, 0 for FALSE. */ - ser_buffer_string (boolean ? "1" : "0"); +ser_buffer_boolean(sc_bool boolean) { + /* Write a 1 for TRUE, 0 for FALSE. */ + ser_buffer_string(boolean ? "1" : "0"); } @@ -276,165 +259,156 @@ ser_buffer_boolean (sc_bool boolean) * Serialize a game and save its state using the given callback and opaque. */ void -ser_save_game (sc_gameref_t game, - sc_write_callbackref_t callback, void *opaque) -{ - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int index_, var_count; - assert (callback); - - /* Store the callback and opaque references, for writer functions. */ - ser_callback = callback; - ser_opaque = opaque; - - /* Write the game name. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "GameName"; - ser_buffer_string (prop_get_string (bundle, "S<-ss", vt_key)); - - /* Write the counts of rooms, objects, etc. */ - ser_buffer_int (gs_room_count (game)); - ser_buffer_int (gs_object_count (game)); - ser_buffer_int (gs_task_count (game)); - ser_buffer_int (gs_event_count (game)); - ser_buffer_int (gs_npc_count (game)); - - /* Write the score and player information. */ - ser_buffer_int (game->score); - ser_buffer_int (gs_playerroom (game) + 1); - ser_buffer_int (gs_playerparent (game)); - ser_buffer_int (gs_playerposition (game)); - - /* Write player gender. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "PlayerGender"; - ser_buffer_int (prop_get_integer (bundle, "I<-ss", vt_key)); - - /* - * Write encumbrance details. The player limits are constant for a given - * game, and can be extracted from properties. The current sizes and - * weights can also be recalculated from held objects, so we don't maintain - * them in the game. We can write constants here, then, and ignore - * the values on restoring. Note however that if the Adrift Runner is - * relying on these values, this may give it problems with one of our saved - * games. - */ - ser_buffer_int (90); - ser_buffer_int (0); - ser_buffer_int (90); - ser_buffer_int (0); - - /* Save rooms information. */ - for (index_ = 0; index_ < gs_room_count (game); index_++) - ser_buffer_boolean (gs_room_seen (game, index_)); - - /* Save objects information. */ - for (index_ = 0; index_ < gs_object_count (game); index_++) - { - ser_buffer_int (gs_object_position (game, index_)); - ser_buffer_boolean (gs_object_seen (game, index_)); - ser_buffer_int (gs_object_parent (game, index_)); - if (gs_object_openness (game, index_) != 0) - ser_buffer_int (gs_object_openness (game, index_)); - - if (gs_object_state (game, index_) != 0) - ser_buffer_int (gs_object_state (game, index_)); - - ser_buffer_boolean (gs_object_unmoved (game, index_)); - } - - /* Save tasks information. */ - for (index_ = 0; index_ < gs_task_count (game); index_++) - { - ser_buffer_boolean (gs_task_done (game, index_)); - ser_buffer_boolean (gs_task_scored (game, index_)); - } - - /* Save events information. */ - for (index_ = 0; index_ < gs_event_count (game); index_++) - { - sc_int startertype, task; - - /* Get starter task, if any. */ - vt_key[0].string = "Events"; - vt_key[1].integer = index_; - vt_key[2].string = "StarterType"; - startertype = prop_get_integer (bundle, "I<-sis", vt_key); - if (startertype == 3) - { - vt_key[2].string = "TaskNum"; - task = prop_get_integer (bundle, "I<-sis", vt_key); - } - else - task = 0; - - /* Save event details. */ - ser_buffer_int (gs_event_time (game, index_)); - ser_buffer_int (task); - ser_buffer_int (gs_event_state (game, index_) - 1); - if (task > 0) - ser_buffer_boolean (gs_task_done (game, task - 1)); - else - ser_buffer_boolean (FALSE); - } - - /* Save NPCs information. */ - for (index_ = 0; index_ < gs_npc_count (game); index_++) - { - sc_int walk; - - ser_buffer_int (gs_npc_location (game, index_)); - ser_buffer_boolean (gs_npc_seen (game, index_)); - for (walk = 0; walk < gs_npc_walkstep_count (game, index_); walk++) - ser_buffer_int_special (gs_npc_walkstep (game, index_, walk)); - } - - /* Save each variable. */ - vt_key[0].string = "Variables"; - var_count = prop_get_child_count (bundle, "I<-s", vt_key); - - for (index_ = 0; index_ < var_count; index_++) - { - const sc_char *name; - sc_int var_type; - - vt_key[1].integer = index_; - - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Type"; - var_type = prop_get_integer (bundle, "I<-sis", vt_key); - - switch (var_type) - { - case TAFVAR_NUMERIC: - ser_buffer_int (var_get_integer (vars, name)); - break; - - case TAFVAR_STRING: - ser_buffer_string (var_get_string (vars, name)); - break; - - default: - sc_fatal ("ser_save_game: unknown variable type, %ld\n", var_type); - } - } - - /* Save timing information. */ - ser_buffer_uint (var_get_elapsed_seconds (vars)); - - /* Save turns count. */ - ser_buffer_uint ((sc_uint) game->turns); - - /* - * Flush the last buffer contents, and drop the callback and opaque - * references. - */ - ser_flush (TRUE); - ser_callback = NULL; - ser_opaque = NULL; +ser_save_game(sc_gameref_t game, + sc_write_callbackref_t callback, void *opaque) { + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int index_, var_count; + assert(callback); + + /* Store the callback and opaque references, for writer functions. */ + ser_callback = callback; + ser_opaque = opaque; + + /* Write the game name. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "GameName"; + ser_buffer_string(prop_get_string(bundle, "S<-ss", vt_key)); + + /* Write the counts of rooms, objects, etc. */ + ser_buffer_int(gs_room_count(game)); + ser_buffer_int(gs_object_count(game)); + ser_buffer_int(gs_task_count(game)); + ser_buffer_int(gs_event_count(game)); + ser_buffer_int(gs_npc_count(game)); + + /* Write the score and player information. */ + ser_buffer_int(game->score); + ser_buffer_int(gs_playerroom(game) + 1); + ser_buffer_int(gs_playerparent(game)); + ser_buffer_int(gs_playerposition(game)); + + /* Write player gender. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "PlayerGender"; + ser_buffer_int(prop_get_integer(bundle, "I<-ss", vt_key)); + + /* + * Write encumbrance details. The player limits are constant for a given + * game, and can be extracted from properties. The current sizes and + * weights can also be recalculated from held objects, so we don't maintain + * them in the game. We can write constants here, then, and ignore + * the values on restoring. Note however that if the Adrift Runner is + * relying on these values, this may give it problems with one of our saved + * games. + */ + ser_buffer_int(90); + ser_buffer_int(0); + ser_buffer_int(90); + ser_buffer_int(0); + + /* Save rooms information. */ + for (index_ = 0; index_ < gs_room_count(game); index_++) + ser_buffer_boolean(gs_room_seen(game, index_)); + + /* Save objects information. */ + for (index_ = 0; index_ < gs_object_count(game); index_++) { + ser_buffer_int(gs_object_position(game, index_)); + ser_buffer_boolean(gs_object_seen(game, index_)); + ser_buffer_int(gs_object_parent(game, index_)); + if (gs_object_openness(game, index_) != 0) + ser_buffer_int(gs_object_openness(game, index_)); + + if (gs_object_state(game, index_) != 0) + ser_buffer_int(gs_object_state(game, index_)); + + ser_buffer_boolean(gs_object_unmoved(game, index_)); + } + + /* Save tasks information. */ + for (index_ = 0; index_ < gs_task_count(game); index_++) { + ser_buffer_boolean(gs_task_done(game, index_)); + ser_buffer_boolean(gs_task_scored(game, index_)); + } + + /* Save events information. */ + for (index_ = 0; index_ < gs_event_count(game); index_++) { + sc_int startertype, task; + + /* Get starter task, if any. */ + vt_key[0].string = "Events"; + vt_key[1].integer = index_; + vt_key[2].string = "StarterType"; + startertype = prop_get_integer(bundle, "I<-sis", vt_key); + if (startertype == 3) { + vt_key[2].string = "TaskNum"; + task = prop_get_integer(bundle, "I<-sis", vt_key); + } else + task = 0; + + /* Save event details. */ + ser_buffer_int(gs_event_time(game, index_)); + ser_buffer_int(task); + ser_buffer_int(gs_event_state(game, index_) - 1); + if (task > 0) + ser_buffer_boolean(gs_task_done(game, task - 1)); + else + ser_buffer_boolean(FALSE); + } + + /* Save NPCs information. */ + for (index_ = 0; index_ < gs_npc_count(game); index_++) { + sc_int walk; + + ser_buffer_int(gs_npc_location(game, index_)); + ser_buffer_boolean(gs_npc_seen(game, index_)); + for (walk = 0; walk < gs_npc_walkstep_count(game, index_); walk++) + ser_buffer_int_special(gs_npc_walkstep(game, index_, walk)); + } + + /* Save each variable. */ + vt_key[0].string = "Variables"; + var_count = prop_get_child_count(bundle, "I<-s", vt_key); + + for (index_ = 0; index_ < var_count; index_++) { + const sc_char *name; + sc_int var_type; + + vt_key[1].integer = index_; + + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Type"; + var_type = prop_get_integer(bundle, "I<-sis", vt_key); + + switch (var_type) { + case TAFVAR_NUMERIC: + ser_buffer_int(var_get_integer(vars, name)); + break; + + case TAFVAR_STRING: + ser_buffer_string(var_get_string(vars, name)); + break; + + default: + sc_fatal("ser_save_game: unknown variable type, %ld\n", var_type); + } + } + + /* Save timing information. */ + ser_buffer_uint(var_get_elapsed_seconds(vars)); + + /* Save turns count. */ + ser_buffer_uint((sc_uint) game->turns); + + /* + * Flush the last buffer contents, and drop the callback and opaque + * references. + */ + ser_flush(TRUE); + ser_callback = NULL; + ser_opaque = NULL; } @@ -445,23 +419,21 @@ ser_save_game (sc_gameref_t game, * the user. */ sc_bool -ser_save_game_prompted (sc_gameref_t game) -{ - void *opaque; - - /* - * Open an output stream, and if successful, save a game using the opaque - * value returned. - */ - opaque = if_open_saved_game (TRUE); - if (opaque) - { - ser_save_game (game, if_write_saved_game, opaque); - if_close_saved_game (opaque); - return TRUE; - } - - return FALSE; +ser_save_game_prompted(sc_gameref_t game) { + void *opaque; + + /* + * Open an output stream, and if successful, save a game using the opaque + * value returned. + */ + opaque = if_open_saved_game(TRUE); + if (opaque) { + ser_save_game(game, if_write_saved_game, opaque); + if_close_saved_game(opaque); + return TRUE; + } + + return FALSE; } @@ -482,82 +454,73 @@ static jmp_buf ser_tas_error; * the line content into an appropriate type. */ static const sc_char * -ser_get_string (void) -{ - const sc_char *string; - - /* Get the next line, and complain if absent. */ - string = taf_next_line (ser_tas); - if (!string) - { - sc_error ("ser_get_string: out of TAS data at line %ld\n", ser_tasline); - longjmp (ser_tas_error, 1); - } - - ser_tasline++; - return string; +ser_get_string(void) { + const sc_char *string; + + /* Get the next line, and complain if absent. */ + string = taf_next_line(ser_tas); + if (!string) { + sc_error("ser_get_string: out of TAS data at line %ld\n", ser_tasline); + longjmp(ser_tas_error, 1); + } + + ser_tasline++; + return string; } static sc_int -ser_get_int (void) -{ - const sc_char *string; - sc_int value; - - /* Get line, and scan for a single integer; return it. */ - string = ser_get_string (); - if (sscanf (string, "%ld", &value) != 1) - { - sc_error ("ser_get_int:" - " invalid integer at line %ld\n", ser_tasline - 1); - longjmp (ser_tas_error, 1); - } - - return value; +ser_get_int(void) { + const sc_char *string; + sc_int value; + + /* Get line, and scan for a single integer; return it. */ + string = ser_get_string(); + if (sscanf(string, "%ld", &value) != 1) { + sc_error("ser_get_int:" + " invalid integer at line %ld\n", ser_tasline - 1); + longjmp(ser_tas_error, 1); + } + + return value; } static sc_uint -ser_get_uint (void) -{ - const sc_char *string; - sc_uint value; - - /* Get line, and scan for a single integer; return it. */ - string = ser_get_string (); - if (sscanf (string, "%lu", &value) != 1) - { - sc_error ("ser_get_uint:" - " invalid integer at line %ld\n", ser_tasline - 1); - longjmp (ser_tas_error, 1); - } - - return value; +ser_get_uint(void) { + const sc_char *string; + sc_uint value; + + /* Get line, and scan for a single integer; return it. */ + string = ser_get_string(); + if (sscanf(string, "%lu", &value) != 1) { + sc_error("ser_get_uint:" + " invalid integer at line %ld\n", ser_tasline - 1); + longjmp(ser_tas_error, 1); + } + + return value; } static sc_bool -ser_get_boolean (void) -{ - const sc_char *string; - sc_uint value; - - /* - * Get line, and scan for a single integer; check it's a valid-looking flag, - * and return it. - */ - string = ser_get_string (); - if (sscanf (string, "%lu", &value) != 1) - { - sc_error ("ser_get_boolean:" - " invalid boolean at line %ld\n", ser_tasline - 1); - longjmp (ser_tas_error, 1); - } - if (value != 0 && value != 1) - { - sc_error ("ser_get_boolean:" - " warning: suspect boolean at line %ld\n", ser_tasline - 1); - } - - return value != 0; +ser_get_boolean(void) { + const sc_char *string; + sc_uint value; + + /* + * Get line, and scan for a single integer; check it's a valid-looking flag, + * and return it. + */ + string = ser_get_string(); + if (sscanf(string, "%lu", &value) != 1) { + sc_error("ser_get_boolean:" + " invalid boolean at line %ld\n", ser_tasline - 1); + longjmp(ser_tas_error, 1); + } + if (value != 0 && value != 1) { + sc_error("ser_get_boolean:" + " warning: suspect boolean at line %ld\n", ser_tasline - 1); + } + + return value != 0; } @@ -568,229 +531,219 @@ ser_get_boolean (void) * callback() function. */ sc_bool -ser_load_game (sc_gameref_t game, - sc_read_callbackref_t callback, void *opaque) -{ - static sc_var_setref_t new_vars; /* For setjmp safety */ - static sc_gameref_t new_game; /* For setjmp safety */ - - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int index_, var_count; - const sc_char *gamename; - - /* Create a TAF (TAS) reference from callbacks, for reader functions. */ - ser_tas = taf_create_tas (callback, opaque); - if (!ser_tas) - return FALSE; - - /* Reset line counter for error messages. */ - ser_tasline = 1; - - new_game = NULL; - new_vars = NULL; - - /* Set up error handling jump buffer, and handle errors. */ - if (setjmp (ser_tas_error) != 0) - { - /* Destroy any temporary game and variables. */ - if (new_game) - gs_destroy (new_game); - if (new_vars) - var_destroy (new_vars); - - /* Destroy the TAF (TAS) file and return fail status. */ - taf_destroy (ser_tas); - ser_tas = NULL; - return FALSE; - } - - /* - * Read the game name, and compare with the one in the game. Fail if - * they don't match exactly. A tighter check than this would perhaps be - * preferable, say, something based on the TAF file header, but this isn't - * in the save file format. - */ - vt_key[0].string = "Globals"; - vt_key[1].string = "GameName"; - gamename = prop_get_string (bundle, "S<-ss", vt_key); - if (strcmp (ser_get_string (), gamename) != 0) - longjmp (ser_tas_error, 1); - - /* Read and verify the counts in the saved game. */ - if (ser_get_int () != gs_room_count (game) - || ser_get_int () != gs_object_count (game) - || ser_get_int () != gs_task_count (game) - || ser_get_int () != gs_event_count (game) - || ser_get_int () != gs_npc_count (game)) - longjmp (ser_tas_error, 1); - - /* Create a variables set and game to restore into. */ - new_vars = var_create (bundle); - new_game = gs_create (new_vars, bundle, filter); - var_register_game (new_vars, new_game); - - /* All set to load TAF (TAS) data into the new game. */ - - /* Restore the score and player information. */ - new_game->score = ser_get_int (); - gs_set_playerroom (new_game, ser_get_int () - 1); - gs_set_playerparent (new_game, ser_get_int ()); - gs_set_playerposition (new_game, ser_get_int ()); - - /* Skip player gender. */ - (void) ser_get_int (); - - /* Skip encumbrance details, not currently maintained by the game. */ - (void) ser_get_int (); - (void) ser_get_int (); - (void) ser_get_int (); - (void) ser_get_int (); - - /* Restore rooms information. */ - for (index_ = 0; index_ < gs_room_count (new_game); index_++) - gs_set_room_seen (new_game, index_, ser_get_boolean ()); - - /* Restore objects information. */ - for (index_ = 0; index_ < gs_object_count (new_game); index_++) - { - sc_int openable, currentstate; - - /* Bypass mutators for position and parent. Fix later? */ - new_game->objects[index_].position = ser_get_int (); - gs_set_object_seen (new_game, index_, ser_get_boolean ()); - new_game->objects[index_].parent = ser_get_int (); - - vt_key[0].string = "Objects"; - vt_key[1].integer = index_; - vt_key[2].string = "Openable"; - openable = prop_get_integer (bundle, "I<-sis", vt_key); - gs_set_object_openness (new_game, index_, - openable != 0 ? ser_get_int () : 0); - - vt_key[2].string = "CurrentState"; - currentstate = prop_get_integer (bundle, "I<-sis", vt_key); - gs_set_object_state (new_game, index_, - currentstate != 0 ? ser_get_int () : 0); - - gs_set_object_unmoved (new_game, index_, ser_get_boolean ()); - } - - /* Restore tasks information. */ - for (index_ = 0; index_ < gs_task_count (new_game); index_++) - { - gs_set_task_done (new_game, index_, ser_get_boolean ()); - gs_set_task_scored (new_game, index_, ser_get_boolean ()); - } - - /* Restore events information. */ - for (index_ = 0; index_ < gs_event_count (new_game); index_++) - { - sc_int startertype, task; - - /* Restore first event details. */ - gs_set_event_time (new_game, index_, ser_get_int ()); - task = ser_get_int (); - gs_set_event_state (new_game, index_, ser_get_int () + 1); - - /* Verify and restore the starter task, if any. */ - if (task > 0) - { - vt_key[0].string = "Events"; - vt_key[1].integer = index_; - vt_key[2].string = "StarterType"; - startertype = prop_get_integer (bundle, "I<-sis", vt_key); - if (startertype != 3) - longjmp (ser_tas_error, 1); - - /* Restore task state. */ - gs_set_task_done (new_game, task - 1, ser_get_boolean ()); - } - else - (void) ser_get_boolean (); - } - - /* Restore NPCs information. */ - for (index_ = 0; index_ < gs_npc_count (new_game); index_++) - { - sc_int walk; - - gs_set_npc_location (new_game, index_, ser_get_int ()); - gs_set_npc_seen (new_game, index_, ser_get_boolean ()); - for (walk = 0; walk < gs_npc_walkstep_count (new_game, index_); walk++) - gs_set_npc_walkstep (new_game, index_, walk, ser_get_int ()); - } - - /* Restore each variable. */ - vt_key[0].string = "Variables"; - var_count = prop_get_child_count (bundle, "I<-s", vt_key); - - for (index_ = 0; index_ < var_count; index_++) - { - const sc_char *name; - sc_int var_type; - - vt_key[1].integer = index_; - - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Type"; - var_type = prop_get_integer (bundle, "I<-sis", vt_key); - - switch (var_type) - { - case TAFVAR_NUMERIC: - var_put_integer (new_vars, name, ser_get_int ()); - break; - - case TAFVAR_STRING: - var_put_string (new_vars, name, ser_get_string ()); - break; - - default: - sc_fatal ("ser_load_game: unknown variable type, %ld\n", var_type); - } - } - - /* Restore timing information. */ - var_set_elapsed_seconds (new_vars, ser_get_uint ()); - - /* Restore turns count. */ - new_game->turns = (sc_int) ser_get_uint (); - - /* - * Resources tweak -- set requested to match those in the current game - * so that they remain unchanged by the gs_copy() of new_game onto - * game. This way, both the requested and the active resources in the - * game are unchanged by restore. - */ - new_game->requested_sound = game->requested_sound; - new_game->requested_graphic = game->requested_graphic; - - /* - * Quitter tweak -- set the quit jump buffer in the new game to be the - * same as the current one, so that it remains unchanged by gs_copy(). The - * one in the new game is still the unset one from gs_create(). - */ - memcpy (&new_game->quitter, &game->quitter, sizeof (game->quitter)); - - /* - * If we got this far, we successfully restored the game from the file. - * As our final act, copy the new game onto the old one. - */ - new_game->temporary = game->temporary; - new_game->undo = game->undo; - gs_copy (game, new_game); - - /* Done with the temporary game and variables. */ - gs_destroy (new_game); - var_destroy (new_vars); - - /* Done with TAF (TAS) file; destroy it and return successfully. */ - taf_destroy (ser_tas); - ser_tas = NULL; - return TRUE; +ser_load_game(sc_gameref_t game, + sc_read_callbackref_t callback, void *opaque) { + static sc_var_setref_t new_vars; /* For setjmp safety */ + static sc_gameref_t new_game; /* For setjmp safety */ + + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int index_, var_count; + const sc_char *gamename; + + /* Create a TAF (TAS) reference from callbacks, for reader functions. */ + ser_tas = taf_create_tas(callback, opaque); + if (!ser_tas) + return FALSE; + + /* Reset line counter for error messages. */ + ser_tasline = 1; + + new_game = NULL; + new_vars = NULL; + + /* Set up error handling jump buffer, and handle errors. */ + if (setjmp(ser_tas_error) != 0) { + /* Destroy any temporary game and variables. */ + if (new_game) + gs_destroy(new_game); + if (new_vars) + var_destroy(new_vars); + + /* Destroy the TAF (TAS) file and return fail status. */ + taf_destroy(ser_tas); + ser_tas = NULL; + return FALSE; + } + + /* + * Read the game name, and compare with the one in the game. Fail if + * they don't match exactly. A tighter check than this would perhaps be + * preferable, say, something based on the TAF file header, but this isn't + * in the save file format. + */ + vt_key[0].string = "Globals"; + vt_key[1].string = "GameName"; + gamename = prop_get_string(bundle, "S<-ss", vt_key); + if (strcmp(ser_get_string(), gamename) != 0) + longjmp(ser_tas_error, 1); + + /* Read and verify the counts in the saved game. */ + if (ser_get_int() != gs_room_count(game) + || ser_get_int() != gs_object_count(game) + || ser_get_int() != gs_task_count(game) + || ser_get_int() != gs_event_count(game) + || ser_get_int() != gs_npc_count(game)) + longjmp(ser_tas_error, 1); + + /* Create a variables set and game to restore into. */ + new_vars = var_create(bundle); + new_game = gs_create(new_vars, bundle, filter); + var_register_game(new_vars, new_game); + + /* All set to load TAF (TAS) data into the new game. */ + + /* Restore the score and player information. */ + new_game->score = ser_get_int(); + gs_set_playerroom(new_game, ser_get_int() - 1); + gs_set_playerparent(new_game, ser_get_int()); + gs_set_playerposition(new_game, ser_get_int()); + + /* Skip player gender. */ + (void) ser_get_int(); + + /* Skip encumbrance details, not currently maintained by the game. */ + (void) ser_get_int(); + (void) ser_get_int(); + (void) ser_get_int(); + (void) ser_get_int(); + + /* Restore rooms information. */ + for (index_ = 0; index_ < gs_room_count(new_game); index_++) + gs_set_room_seen(new_game, index_, ser_get_boolean()); + + /* Restore objects information. */ + for (index_ = 0; index_ < gs_object_count(new_game); index_++) { + sc_int openable, currentstate; + + /* Bypass mutators for position and parent. Fix later? */ + new_game->objects[index_].position = ser_get_int(); + gs_set_object_seen(new_game, index_, ser_get_boolean()); + new_game->objects[index_].parent = ser_get_int(); + + vt_key[0].string = "Objects"; + vt_key[1].integer = index_; + vt_key[2].string = "Openable"; + openable = prop_get_integer(bundle, "I<-sis", vt_key); + gs_set_object_openness(new_game, index_, + openable != 0 ? ser_get_int() : 0); + + vt_key[2].string = "CurrentState"; + currentstate = prop_get_integer(bundle, "I<-sis", vt_key); + gs_set_object_state(new_game, index_, + currentstate != 0 ? ser_get_int() : 0); + + gs_set_object_unmoved(new_game, index_, ser_get_boolean()); + } + + /* Restore tasks information. */ + for (index_ = 0; index_ < gs_task_count(new_game); index_++) { + gs_set_task_done(new_game, index_, ser_get_boolean()); + gs_set_task_scored(new_game, index_, ser_get_boolean()); + } + + /* Restore events information. */ + for (index_ = 0; index_ < gs_event_count(new_game); index_++) { + sc_int startertype, task; + + /* Restore first event details. */ + gs_set_event_time(new_game, index_, ser_get_int()); + task = ser_get_int(); + gs_set_event_state(new_game, index_, ser_get_int() + 1); + + /* Verify and restore the starter task, if any. */ + if (task > 0) { + vt_key[0].string = "Events"; + vt_key[1].integer = index_; + vt_key[2].string = "StarterType"; + startertype = prop_get_integer(bundle, "I<-sis", vt_key); + if (startertype != 3) + longjmp(ser_tas_error, 1); + + /* Restore task state. */ + gs_set_task_done(new_game, task - 1, ser_get_boolean()); + } else + (void) ser_get_boolean(); + } + + /* Restore NPCs information. */ + for (index_ = 0; index_ < gs_npc_count(new_game); index_++) { + sc_int walk; + + gs_set_npc_location(new_game, index_, ser_get_int()); + gs_set_npc_seen(new_game, index_, ser_get_boolean()); + for (walk = 0; walk < gs_npc_walkstep_count(new_game, index_); walk++) + gs_set_npc_walkstep(new_game, index_, walk, ser_get_int()); + } + + /* Restore each variable. */ + vt_key[0].string = "Variables"; + var_count = prop_get_child_count(bundle, "I<-s", vt_key); + + for (index_ = 0; index_ < var_count; index_++) { + const sc_char *name; + sc_int var_type; + + vt_key[1].integer = index_; + + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Type"; + var_type = prop_get_integer(bundle, "I<-sis", vt_key); + + switch (var_type) { + case TAFVAR_NUMERIC: + var_put_integer(new_vars, name, ser_get_int()); + break; + + case TAFVAR_STRING: + var_put_string(new_vars, name, ser_get_string()); + break; + + default: + sc_fatal("ser_load_game: unknown variable type, %ld\n", var_type); + } + } + + /* Restore timing information. */ + var_set_elapsed_seconds(new_vars, ser_get_uint()); + + /* Restore turns count. */ + new_game->turns = (sc_int) ser_get_uint(); + + /* + * Resources tweak -- set requested to match those in the current game + * so that they remain unchanged by the gs_copy() of new_game onto + * game. This way, both the requested and the active resources in the + * game are unchanged by restore. + */ + new_game->requested_sound = game->requested_sound; + new_game->requested_graphic = game->requested_graphic; + + /* + * Quitter tweak -- set the quit jump buffer in the new game to be the + * same as the current one, so that it remains unchanged by gs_copy(). The + * one in the new game is still the unset one from gs_create(). + */ + memcpy(&new_game->quitter, &game->quitter, sizeof(game->quitter)); + + /* + * If we got this far, we successfully restored the game from the file. + * As our final act, copy the new game onto the old one. + */ + new_game->temporary = game->temporary; + new_game->undo = game->undo; + gs_copy(game, new_game); + + /* Done with the temporary game and variables. */ + gs_destroy(new_game); + var_destroy(new_vars); + + /* Done with TAF (TAS) file; destroy it and return successfully. */ + taf_destroy(ser_tas); + ser_tas = NULL; + return TRUE; } @@ -801,25 +754,23 @@ ser_load_game (sc_gameref_t game, * stream from the user. */ sc_bool -ser_load_game_prompted (sc_gameref_t game) -{ - void *opaque; - - /* - * Open an input stream, and if successful, try to load a game using - * the opaque value returned and the saved game callback. - */ - opaque = if_open_saved_game (FALSE); - if (opaque) - { - sc_bool status; - - status = ser_load_game (game, if_read_saved_game, opaque); - if_close_saved_game (opaque); - return status; - } - - return FALSE; +ser_load_game_prompted(sc_gameref_t game) { + void *opaque; + + /* + * Open an input stream, and if successful, try to load a game using + * the opaque value returned and the saved game callback. + */ + opaque = if_open_saved_game(FALSE); + if (opaque) { + sc_bool status; + + status = ser_load_game(game, if_read_saved_game, opaque); + if_close_saved_game(opaque); + return status; + } + + return FALSE; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sctaffil.cpp b/engines/glk/adrift/sctaffil.cpp index c8a25edaeb..f365a7fa46 100644 --- a/engines/glk/adrift/sctaffil.cpp +++ b/engines/glk/adrift/sctaffil.cpp @@ -27,15 +27,15 @@ #include "common/memstream.h" #if defined(USE_ZLIB) - #ifdef __SYMBIAN32__ - #include - #else - #include - #endif - - #if ZLIB_VERNUM < 0x1204 - #error Version 1.2.0.4 or newer of zlib is required for this code - #endif +#ifdef __SYMBIAN32__ +#include +#else +#include +#endif + +#if ZLIB_VERNUM < 0x1204 +#error Version 1.2.0.4 or newer of zlib is required for this code +#endif #endif namespace Glk { @@ -49,14 +49,14 @@ namespace Adrift { /* Assorted definitions and constants. */ static const sc_uint TAF_MAGIC = 0x5bdcfa41; -enum -{ VERSION_HEADER_SIZE = 14, - V400_HEADER_EXTRA = 8 +enum { + VERSION_HEADER_SIZE = 14, + V400_HEADER_EXTRA = 8 }; -enum -{ OUT_BUFFER_SIZE = 31744, - IN_BUFFER_SIZE = 16384, - GROW_INCREMENT = 8 +enum { + OUT_BUFFER_SIZE = 31744, + IN_BUFFER_SIZE = 16384, + GROW_INCREMENT = 8 }; static const sc_char NEWLINE = '\n'; static const sc_char CARRIAGE_RETURN = '\r'; @@ -64,17 +64,20 @@ static const sc_char NUL = '\0'; /* Version 4.0, version 3.9, and version 3.8 TAF file signatures. */ static const sc_byte - V400_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, - 0xc2, 0xcf, 0x93, 0x45, 0x3e, 0x61, - 0x39, 0xfa}; +V400_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, + 0xc2, 0xcf, 0x93, 0x45, 0x3e, 0x61, + 0x39, 0xfa + }; static const sc_byte - V390_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, - 0xc2, 0xcf, 0x94, 0x45, 0x37, 0x61, - 0x39, 0xfa}; +V390_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, + 0xc2, 0xcf, 0x94, 0x45, 0x37, 0x61, + 0x39, 0xfa + }; static const sc_byte - V380_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, - 0xc2, 0xcf, 0x94, 0x45, 0x36, 0x61, - 0x39, 0xfa}; +V380_SIGNATURE[VERSION_HEADER_SIZE] = {0x3c, 0x42, 0x3f, 0xc9, 0x6a, 0x87, + 0xc2, 0xcf, 0x94, 0x45, 0x36, 0x61, + 0x39, 0xfa + }; /* * Game TAF data structure. The game structure contains the original TAF @@ -87,22 +90,21 @@ static const sc_byte * header. So for files of this type, the header is all zeroes. */ struct sc_slabdesc_t { - sc_byte *data; - sc_int size; + sc_byte *data; + sc_int size; }; typedef sc_slabdesc_t *sc_slabdescref_t; -typedef struct sc_taf_s -{ - sc_uint magic; - sc_byte header[VERSION_HEADER_SIZE + V400_HEADER_EXTRA]; - sc_int version; - sc_int total_in_bytes; - sc_slabdescref_t slabs; - sc_int slab_count; - sc_int slabs_allocated; - sc_bool is_unterminated; - sc_int current_slab; - sc_int current_offset; +typedef struct sc_taf_s { + sc_uint magic; + sc_byte header[VERSION_HEADER_SIZE + V400_HEADER_EXTRA]; + sc_int version; + sc_int total_in_bytes; + sc_slabdescref_t slabs; + sc_int slab_count; + sc_int slabs_allocated; + sc_bool is_unterminated; + sc_int current_slab; + sc_int current_offset; } sc_taf_t; @@ -124,18 +126,16 @@ static sc_int taf_random_state = 0x00a09e86; * range 0..254. Thanks to Rik Snel for uncovering this obfuscation. */ static sc_byte -taf_random (void) -{ - /* Generate and return the next pseudo-random number. */ - taf_random_state = (taf_random_state * PRNG_CST1 + PRNG_CST2) & PRNG_CST3; - return (UCHAR_MAX * (sc_uint) taf_random_state) / (sc_uint) (PRNG_CST3 + 1); +taf_random(void) { + /* Generate and return the next pseudo-random number. */ + taf_random_state = (taf_random_state * PRNG_CST1 + PRNG_CST2) & PRNG_CST3; + return (UCHAR_MAX * (sc_uint) taf_random_state) / (sc_uint)(PRNG_CST3 + 1); } static void -taf_random_reset (void) -{ - /* Reset PRNG to initial conditions. */ - taf_random_state = PRNG_INITIAL_STATE; +taf_random_reset(void) { + /* Reset PRNG to initial conditions. */ + taf_random_state = PRNG_INITIAL_STATE; } @@ -145,9 +145,8 @@ taf_random_reset (void) * Return TRUE if pointer is a valid TAF structure, FALSE otherwise. */ static sc_bool -taf_is_valid (sc_tafref_t taf) -{ - return taf && taf->magic == TAF_MAGIC; +taf_is_valid(sc_tafref_t taf) { + return taf && taf->magic == TAF_MAGIC; } @@ -157,25 +156,24 @@ taf_is_valid (sc_tafref_t taf) * Allocate and return a new, empty TAF structure. */ static sc_tafref_t -taf_create_empty (void) -{ - sc_tafref_t taf; - - /* Create an empty TAF structure. */ - taf = (sc_tafref_t)sc_malloc(sizeof (*taf)); - taf->magic = TAF_MAGIC; - memset (taf->header, 0, sizeof (taf->header)); - taf->version = TAF_VERSION_NONE; - taf->total_in_bytes = 0; - taf->slabs = NULL; - taf->slab_count = 0; - taf->slabs_allocated = 0; - taf->is_unterminated = FALSE; - taf->current_slab = 0; - taf->current_offset = 0; - - /* Return the new TAF structure. */ - return taf; +taf_create_empty(void) { + sc_tafref_t taf; + + /* Create an empty TAF structure. */ + taf = (sc_tafref_t)sc_malloc(sizeof(*taf)); + taf->magic = TAF_MAGIC; + memset(taf->header, 0, sizeof(taf->header)); + taf->version = TAF_VERSION_NONE; + taf->total_in_bytes = 0; + taf->slabs = NULL; + taf->slab_count = 0; + taf->slabs_allocated = 0; + taf->is_unterminated = FALSE; + taf->current_slab = 0; + taf->current_offset = 0; + + /* Return the new TAF structure. */ + return taf; } @@ -185,22 +183,21 @@ taf_create_empty (void) * Free TAF memory, and destroy a TAF structure. */ void -taf_destroy (sc_tafref_t taf) -{ - sc_int index_; - assert (taf_is_valid (taf)); - - /* First free each slab in the slabs array,... */ - for (index_ = 0; index_ < taf->slab_count; index_++) - sc_free (taf->slabs[index_].data); - - /* - * ...then free slabs growable array, and poison and free the TAF structure - * itself. - */ - sc_free (taf->slabs); - memset (taf, 0xaa, sizeof (*taf)); - sc_free (taf); +taf_destroy(sc_tafref_t taf) { + sc_int index_; + assert(taf_is_valid(taf)); + + /* First free each slab in the slabs array,... */ + for (index_ = 0; index_ < taf->slab_count; index_++) + sc_free(taf->slabs[index_].data); + + /* + * ...then free slabs growable array, and poison and free the TAF structure + * itself. + */ + sc_free(taf->slabs); + memset(taf, 0xaa, sizeof(*taf)); + sc_free(taf); } @@ -211,37 +208,32 @@ taf_destroy (sc_tafref_t taf) * strings. Nul's are used to replace carriage return and newline pairs. */ static void -taf_finalize_last_slab (sc_tafref_t taf) -{ - sc_slabdescref_t slab; - sc_int index_; - - /* Locate the final slab in the slab descriptors array. */ - assert (taf->slab_count > 0); - slab = taf->slabs + taf->slab_count - 1; - - /* - * Replace carriage return and newline pairs with nuls, and individual - * carriage returns with a single newline. - */ - for (index_ = 0; index_ < slab->size; index_++) - { - if (slab->data[index_] == CARRIAGE_RETURN) - { - if (index_ < slab->size - 1 && slab->data[index_ + 1] == NEWLINE) - { - slab->data[index_] = NUL; - slab->data[index_ + 1] = NUL; - index_++; - } - else - slab->data[index_] = NEWLINE; - } - - /* Also protect against unlikely incoming nul characters. */ - else if (slab->data[index_] == NUL) - slab->data[index_] = NEWLINE; - } +taf_finalize_last_slab(sc_tafref_t taf) { + sc_slabdescref_t slab; + sc_int index_; + + /* Locate the final slab in the slab descriptors array. */ + assert(taf->slab_count > 0); + slab = taf->slabs + taf->slab_count - 1; + + /* + * Replace carriage return and newline pairs with nuls, and individual + * carriage returns with a single newline. + */ + for (index_ = 0; index_ < slab->size; index_++) { + if (slab->data[index_] == CARRIAGE_RETURN) { + if (index_ < slab->size - 1 && slab->data[index_ + 1] == NEWLINE) { + slab->data[index_] = NUL; + slab->data[index_ + 1] = NUL; + index_++; + } else + slab->data[index_] = NEWLINE; + } + + /* Also protect against unlikely incoming nul characters. */ + else if (slab->data[index_] == NUL) + slab->data[index_] = NEWLINE; + } } @@ -253,26 +245,23 @@ taf_finalize_last_slab (sc_tafref_t taf) * Otherwise, return the count of usable bytes found in the buffer. */ static sc_int -taf_find_buffer_extent (const sc_byte *buffer, - sc_int length, sc_bool *is_unterminated) -{ - sc_int bytes; - - /* Search backwards from the buffer end for the final line feed. */ - for (bytes = length; bytes > 1; bytes--) - { - if (buffer[bytes - 2] == CARRIAGE_RETURN && buffer[bytes - 1] == NEWLINE) - break; - } - if (bytes < 2) - { - /* No carriage return and newline termination found. */ - *is_unterminated = TRUE; - return length; - } - - *is_unterminated = FALSE; - return bytes; +taf_find_buffer_extent(const sc_byte *buffer, + sc_int length, sc_bool *is_unterminated) { + sc_int bytes; + + /* Search backwards from the buffer end for the final line feed. */ + for (bytes = length; bytes > 1; bytes--) { + if (buffer[bytes - 2] == CARRIAGE_RETURN && buffer[bytes - 1] == NEWLINE) + break; + } + if (bytes < 2) { + /* No carriage return and newline termination found. */ + *is_unterminated = TRUE; + return length; + } + + *is_unterminated = FALSE; + return bytes; } @@ -283,75 +272,70 @@ taf_find_buffer_extent (const sc_byte *buffer, * number of characters consumed from the buffer. */ static sc_int -taf_append_buffer (sc_tafref_t taf, const sc_byte *buffer, sc_int length) -{ - sc_int bytes; - sc_bool is_unterminated; - - /* Locate the extent of appendable data in the buffer. */ - bytes = taf_find_buffer_extent (buffer, length, &is_unterminated); - - /* See if the last buffer handled contained at least one data line. */ - if (!taf->is_unterminated) - { - sc_slabdescref_t slab; - - /* Extend the slabs array if we've reached the current allocation. */ - if (taf->slab_count == taf->slabs_allocated) - { - taf->slabs_allocated += GROW_INCREMENT; - taf->slabs = (sc_slabdescref_t)sc_realloc (taf->slabs, - taf->slabs_allocated * sizeof (*taf->slabs)); - } - - /* Advance to the next unused slab in the slab descriptors array. */ - slab = taf->slabs + taf->slab_count; - taf->slab_count++; - - /* Copy the input buffer into the new slab. */ - slab->data = (sc_byte *)sc_malloc (bytes); - memcpy (slab->data, buffer, bytes); - slab->size = bytes; - } - else - { - sc_slabdescref_t slab; - - /* Locate the final slab in the slab descriptors array. */ - assert (taf->slab_count > 0); - slab = taf->slabs + taf->slab_count - 1; - - /* - * The last buffer we saw had no line endings in it. In this case, - * append the input buffer to the end of the last slab's data, rather - * than creating a new slab. This may cause allocation to overflow - * the system limits on single allocated areas on some platforms. - */ - slab->data = (sc_byte *)sc_realloc(slab->data, slab->size + bytes); - memcpy (slab->data + slab->size, buffer, bytes); - slab->size += bytes; - - /* - * Use a special case for the final carriage return and newline pairing - * that are split over two buffers; force correct termination of this - * slab. - */ - if (slab->size > 1 - && slab->data[slab->size - 2] == CARRIAGE_RETURN - && slab->data[slab->size - 1] == NEWLINE) - is_unterminated = FALSE; - } - - /* - * Note if this buffer requires that the next be coalesced with it. If it - * doesn't, finalize the last slab by breaking it into separate lines. - */ - taf->is_unterminated = is_unterminated; - if (!is_unterminated) - taf_finalize_last_slab (taf); - - /* Return count of buffer bytes consumed. */ - return bytes; +taf_append_buffer(sc_tafref_t taf, const sc_byte *buffer, sc_int length) { + sc_int bytes; + sc_bool is_unterminated; + + /* Locate the extent of appendable data in the buffer. */ + bytes = taf_find_buffer_extent(buffer, length, &is_unterminated); + + /* See if the last buffer handled contained at least one data line. */ + if (!taf->is_unterminated) { + sc_slabdescref_t slab; + + /* Extend the slabs array if we've reached the current allocation. */ + if (taf->slab_count == taf->slabs_allocated) { + taf->slabs_allocated += GROW_INCREMENT; + taf->slabs = (sc_slabdescref_t)sc_realloc(taf->slabs, + taf->slabs_allocated * sizeof(*taf->slabs)); + } + + /* Advance to the next unused slab in the slab descriptors array. */ + slab = taf->slabs + taf->slab_count; + taf->slab_count++; + + /* Copy the input buffer into the new slab. */ + slab->data = (sc_byte *)sc_malloc(bytes); + memcpy(slab->data, buffer, bytes); + slab->size = bytes; + } else { + sc_slabdescref_t slab; + + /* Locate the final slab in the slab descriptors array. */ + assert(taf->slab_count > 0); + slab = taf->slabs + taf->slab_count - 1; + + /* + * The last buffer we saw had no line endings in it. In this case, + * append the input buffer to the end of the last slab's data, rather + * than creating a new slab. This may cause allocation to overflow + * the system limits on single allocated areas on some platforms. + */ + slab->data = (sc_byte *)sc_realloc(slab->data, slab->size + bytes); + memcpy(slab->data + slab->size, buffer, bytes); + slab->size += bytes; + + /* + * Use a special case for the final carriage return and newline pairing + * that are split over two buffers; force correct termination of this + * slab. + */ + if (slab->size > 1 + && slab->data[slab->size - 2] == CARRIAGE_RETURN + && slab->data[slab->size - 1] == NEWLINE) + is_unterminated = FALSE; + } + + /* + * Note if this buffer requires that the next be coalesced with it. If it + * doesn't, finalize the last slab by breaking it into separate lines. + */ + taf->is_unterminated = is_unterminated; + if (!is_unterminated) + taf_finalize_last_slab(taf); + + /* Return count of buffer bytes consumed. */ + return bytes; } @@ -364,80 +348,75 @@ taf_append_buffer (sc_tafref_t taf, const sc_byte *buffer, sc_int length) * Assumes that the file has been read past the header. */ static sc_bool -taf_unobfuscate (sc_tafref_t taf, sc_read_callbackref_t callback, - void *opaque, sc_bool is_gamefile) -{ - sc_byte *buffer; - sc_int bytes, used_bytes, total_bytes, index_; - - /* Reset the PRNG, and synchronize with the header already read. */ - taf_random_reset (); - for (index_ = 0; index_ < VERSION_HEADER_SIZE; index_++) - taf_random (); - - /* - * Malloc buffer, done to help systems with limited stacks, and initialize - * count of bytes read and used in the buffer to zero. - */ - buffer = (sc_byte *)sc_malloc (IN_BUFFER_SIZE); - used_bytes = 0; - total_bytes = 0; - - /* Unobfuscate in buffer sized chunks. */ - do - { - /* Try to obtain more data. */ - bytes = callback (opaque, - buffer + used_bytes, IN_BUFFER_SIZE - used_bytes); - - /* Unobfuscate data read in. */ - for (index_ = 0; index_ < bytes; index_++) - buffer[used_bytes + index_] ^= taf_random (); - - /* - * Add data read in and unobfuscated to buffer used data, and if - * unobfuscated data is available, add it to the TAF. - */ - used_bytes += bytes; - if (used_bytes > 0) - { - sc_int consumed; - - /* Add lines from this buffer to the TAF. */ - consumed = taf_append_buffer (taf, buffer, used_bytes); - - /* Move unused buffer data to buffer start. */ - memmove (buffer, buffer + consumed, IN_BUFFER_SIZE - consumed); - - /* Note counts of bytes consumed and remaining in the buffer. */ - used_bytes -= consumed; - total_bytes += consumed; - } - } - while (bytes > 0); - - /* - * Unobfuscation completed, note the total bytes read. This value is - * actually not used for version 3.9 and version 3.8 games, but we maintain - * it just in case. - */ - taf->total_in_bytes = total_bytes; - if (is_gamefile) - taf->total_in_bytes += VERSION_HEADER_SIZE; - - /* Check that we found the end of the input file as expected. */ - if (used_bytes > 0) - { - sc_error ("taf_unobfuscate:" - " warning: %ld unhandled bytes in the buffer\n", used_bytes); - } - - if (taf->is_unterminated) - sc_fatal ("taf_unobfuscate: unterminated final data slab\n"); - - /* Return successfully. */ - sc_free (buffer); - return TRUE; +taf_unobfuscate(sc_tafref_t taf, sc_read_callbackref_t callback, + void *opaque, sc_bool is_gamefile) { + sc_byte *buffer; + sc_int bytes, used_bytes, total_bytes, index_; + + /* Reset the PRNG, and synchronize with the header already read. */ + taf_random_reset(); + for (index_ = 0; index_ < VERSION_HEADER_SIZE; index_++) + taf_random(); + + /* + * Malloc buffer, done to help systems with limited stacks, and initialize + * count of bytes read and used in the buffer to zero. + */ + buffer = (sc_byte *)sc_malloc(IN_BUFFER_SIZE); + used_bytes = 0; + total_bytes = 0; + + /* Unobfuscate in buffer sized chunks. */ + do { + /* Try to obtain more data. */ + bytes = callback(opaque, + buffer + used_bytes, IN_BUFFER_SIZE - used_bytes); + + /* Unobfuscate data read in. */ + for (index_ = 0; index_ < bytes; index_++) + buffer[used_bytes + index_] ^= taf_random(); + + /* + * Add data read in and unobfuscated to buffer used data, and if + * unobfuscated data is available, add it to the TAF. + */ + used_bytes += bytes; + if (used_bytes > 0) { + sc_int consumed; + + /* Add lines from this buffer to the TAF. */ + consumed = taf_append_buffer(taf, buffer, used_bytes); + + /* Move unused buffer data to buffer start. */ + memmove(buffer, buffer + consumed, IN_BUFFER_SIZE - consumed); + + /* Note counts of bytes consumed and remaining in the buffer. */ + used_bytes -= consumed; + total_bytes += consumed; + } + } while (bytes > 0); + + /* + * Unobfuscation completed, note the total bytes read. This value is + * actually not used for version 3.9 and version 3.8 games, but we maintain + * it just in case. + */ + taf->total_in_bytes = total_bytes; + if (is_gamefile) + taf->total_in_bytes += VERSION_HEADER_SIZE; + + /* Check that we found the end of the input file as expected. */ + if (used_bytes > 0) { + sc_error("taf_unobfuscate:" + " warning: %ld unhandled bytes in the buffer\n", used_bytes); + } + + if (taf->is_unterminated) + sc_fatal("taf_unobfuscate: unterminated final data slab\n"); + + /* Return successfully. */ + sc_free(buffer); + return TRUE; } #define BUFFER_SIZE 16384 @@ -448,7 +427,7 @@ taf_unobfuscate (sc_tafref_t taf, sc_read_callbackref_t callback, * Decompress a version 4.0 TAF */ static sc_bool taf_decompress(sc_tafref_t taf, sc_read_callbackref_t callback, - void *opaque, sc_bool is_gamefile) { + void *opaque, sc_bool is_gamefile) { #if USE_ZLIB Common::SeekableReadStream *src = (Common::SeekableReadStream *)opaque; assert(src); @@ -484,99 +463,88 @@ static sc_bool taf_decompress(sc_tafref_t taf, sc_read_callbackref_t callback, * in the buffer, or 0 if no more (end of file). */ static sc_tafref_t -taf_create_from_callback (sc_read_callbackref_t callback, - void *opaque, sc_bool is_gamefile) -{ - sc_tafref_t taf; - sc_bool status = FALSE; - assert (callback); - - /* Create an empty TAF structure. */ - taf = taf_create_empty (); - - /* - * Determine the TAF file version in use. For saved games, we always use - * version 4.0 format. For others, it's determined from the header. - */ - if (is_gamefile) - { - sc_int in_bytes; - - /* - * Read in the ADRIFT header for game files. Start by reading in the - * shorter header common to all. - */ - in_bytes = callback (opaque, taf->header, VERSION_HEADER_SIZE); - if (in_bytes != VERSION_HEADER_SIZE) - { - sc_error ("taf_create: not enough data for standard TAF header\n"); - taf_destroy (taf); - return NULL; - } - - /* - * Compare the header with the known TAF signatures, and set TAF version - * appropriately. - */ - if (memcmp (taf->header, V400_SIGNATURE, VERSION_HEADER_SIZE) == 0) - { - /* Read in the version 4.0 header extension. */ - in_bytes = callback (opaque, - taf->header + VERSION_HEADER_SIZE, - V400_HEADER_EXTRA); - if (in_bytes != V400_HEADER_EXTRA) - { - sc_error ("taf_create:" - " not enough data for extended TAF header\n"); - taf_destroy (taf); - return NULL; - } - - taf->version = TAF_VERSION_400; - } - else if (memcmp (taf->header, V390_SIGNATURE, VERSION_HEADER_SIZE) == 0) - taf->version = TAF_VERSION_390; - else if (memcmp (taf->header, V380_SIGNATURE, VERSION_HEADER_SIZE) == 0) - taf->version = TAF_VERSION_380; - else - { - taf_destroy (taf); - return NULL; - } - } - else - { - /* Saved games are always considered to be version 4.0. */ - taf->version = TAF_VERSION_400; - } - - /* - * Call the appropriate game file reader function. For version 4.0 games, - * data is compressed with Zlib. For version 3.9 and version 3.8 games, - * it's obfuscated with the Visual Basic PRNG. - */ - switch (taf->version) - { - case TAF_VERSION_400: - status = taf_decompress (taf, callback, opaque, is_gamefile); - break; - - case TAF_VERSION_390: - case TAF_VERSION_380: - status = taf_unobfuscate (taf, callback, opaque, is_gamefile); - break; - - default: - sc_fatal ("taf_create: invalid version\n"); - } - if (!status) - { - taf_destroy (taf); - return NULL; - } - - /* Return successfully. */ - return taf; +taf_create_from_callback(sc_read_callbackref_t callback, + void *opaque, sc_bool is_gamefile) { + sc_tafref_t taf; + sc_bool status = FALSE; + assert(callback); + + /* Create an empty TAF structure. */ + taf = taf_create_empty(); + + /* + * Determine the TAF file version in use. For saved games, we always use + * version 4.0 format. For others, it's determined from the header. + */ + if (is_gamefile) { + sc_int in_bytes; + + /* + * Read in the ADRIFT header for game files. Start by reading in the + * shorter header common to all. + */ + in_bytes = callback(opaque, taf->header, VERSION_HEADER_SIZE); + if (in_bytes != VERSION_HEADER_SIZE) { + sc_error("taf_create: not enough data for standard TAF header\n"); + taf_destroy(taf); + return NULL; + } + + /* + * Compare the header with the known TAF signatures, and set TAF version + * appropriately. + */ + if (memcmp(taf->header, V400_SIGNATURE, VERSION_HEADER_SIZE) == 0) { + /* Read in the version 4.0 header extension. */ + in_bytes = callback(opaque, + taf->header + VERSION_HEADER_SIZE, + V400_HEADER_EXTRA); + if (in_bytes != V400_HEADER_EXTRA) { + sc_error("taf_create:" + " not enough data for extended TAF header\n"); + taf_destroy(taf); + return NULL; + } + + taf->version = TAF_VERSION_400; + } else if (memcmp(taf->header, V390_SIGNATURE, VERSION_HEADER_SIZE) == 0) + taf->version = TAF_VERSION_390; + else if (memcmp(taf->header, V380_SIGNATURE, VERSION_HEADER_SIZE) == 0) + taf->version = TAF_VERSION_380; + else { + taf_destroy(taf); + return NULL; + } + } else { + /* Saved games are always considered to be version 4.0. */ + taf->version = TAF_VERSION_400; + } + + /* + * Call the appropriate game file reader function. For version 4.0 games, + * data is compressed with Zlib. For version 3.9 and version 3.8 games, + * it's obfuscated with the Visual Basic PRNG. + */ + switch (taf->version) { + case TAF_VERSION_400: + status = taf_decompress(taf, callback, opaque, is_gamefile); + break; + + case TAF_VERSION_390: + case TAF_VERSION_380: + status = taf_unobfuscate(taf, callback, opaque, is_gamefile); + break; + + default: + sc_fatal("taf_create: invalid version\n"); + } + if (!status) { + taf_destroy(taf); + return NULL; + } + + /* Return successfully. */ + return taf; } @@ -588,31 +556,28 @@ taf_create_from_callback (sc_read_callbackref_t callback, * constructed from either *.TAF (game) or *.TAS (saved game state) file data. */ sc_tafref_t -taf_create (sc_read_callbackref_t callback, void *opaque) -{ - return taf_create_from_callback (callback, opaque, TRUE); +taf_create(sc_read_callbackref_t callback, void *opaque) { + return taf_create_from_callback(callback, opaque, TRUE); } sc_tafref_t -taf_create_tas (sc_read_callbackref_t callback, void *opaque) -{ - return taf_create_from_callback (callback, opaque, FALSE); +taf_create_tas(sc_read_callbackref_t callback, void *opaque) { + return taf_create_from_callback(callback, opaque, FALSE); } - + /* * taf_first_line() * * Iterator rewind function, reset current slab location to TAF data start. */ void -taf_first_line (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); +taf_first_line(sc_tafref_t taf) { + assert(taf_is_valid(taf)); - /* Set current locations to TAF start. */ - taf->current_slab = 0; - taf->current_offset = 0; + /* Set current locations to TAF start. */ + taf->current_slab = 0; + taf->current_offset = 0; } @@ -623,35 +588,32 @@ taf_first_line (sc_tafref_t taf) * if no more lines. */ const sc_char * -taf_next_line (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); - - /* If there is a next line, return it and advance current. */ - if (taf->current_slab < taf->slab_count) - { - sc_char *line; - - /* Get the effective address of the current line. */ - line = (sc_char *) taf->slabs[taf->current_slab].data; - line += taf->current_offset; - - /* - * Advance to the next line. The + 2 skips the NULs used to replace the - * carriage return and line feed. - */ - taf->current_offset += strlen (line) + 2; - if (taf->current_offset >= taf->slabs[taf->current_slab].size) - { - taf->current_slab++; - taf->current_offset = 0; - } - - return line; - } - - /* No more lines, so return NULL. */ - return NULL; +taf_next_line(sc_tafref_t taf) { + assert(taf_is_valid(taf)); + + /* If there is a next line, return it and advance current. */ + if (taf->current_slab < taf->slab_count) { + sc_char *line; + + /* Get the effective address of the current line. */ + line = (sc_char *) taf->slabs[taf->current_slab].data; + line += taf->current_offset; + + /* + * Advance to the next line. The + 2 skips the NULs used to replace the + * carriage return and line feed. + */ + taf->current_offset += strlen(line) + 2; + if (taf->current_offset >= taf->slabs[taf->current_slab].size) { + taf->current_slab++; + taf->current_offset = 0; + } + + return line; + } + + /* No more lines, so return NULL. */ + return NULL; } @@ -661,12 +623,11 @@ taf_next_line (sc_tafref_t taf) * Iterator end function, returns TRUE if more TAF lines are readable. */ sc_bool -taf_more_lines (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); +taf_more_lines(sc_tafref_t taf) { + assert(taf_is_valid(taf)); - /* Return TRUE if not at TAF data end. */ - return taf->current_slab < taf->slab_count; + /* Return TRUE if not at TAF data end. */ + return taf->current_slab < taf->slab_count; } @@ -678,16 +639,15 @@ taf_more_lines (sc_tafref_t taf) * be located. */ sc_int -taf_get_game_data_length (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); - - /* - * Return the count of bytes inflated; this includes the TAF header length - * for TAF, rather than TAS, files. For TAS files, the count of file bytes - * read is irrelevant, and is never used. - */ - return taf->total_in_bytes; +taf_get_game_data_length(sc_tafref_t taf) { + assert(taf_is_valid(taf)); + + /* + * Return the count of bytes inflated; this includes the TAF header length + * for TAF, rather than TAS, files. For TAS files, the count of file bytes + * read is irrelevant, and is never used. + */ + return taf->total_in_bytes; } @@ -697,12 +657,11 @@ taf_get_game_data_length (sc_tafref_t taf) * Return the version number of the TAF file, 400, 390, or 380. */ sc_int -taf_get_version (sc_tafref_t taf) -{ - assert (taf_is_valid (taf)); +taf_get_version(sc_tafref_t taf) { + assert(taf_is_valid(taf)); - assert (taf->version != TAF_VERSION_NONE); - return taf->version; + assert(taf->version != TAF_VERSION_NONE); + return taf->version; } @@ -715,67 +674,64 @@ taf_get_version (sc_tafref_t taf) * slab, and therefore safe to print. */ sc_bool -taf_debug_is_taf_string (sc_tafref_t taf, const void *addr) { - const sc_byte *const addr_ = (const sc_byte *const)addr; - sc_int index_; - - /* - * Compare pointer, by address directly, against all memory contained in - * the TAF slabs. Return TRUE if in range. - */ - for (index_ = 0; index_ < taf->slab_count; index_++) - { - if (addr_ >= taf->slabs[index_].data - && addr_ < taf->slabs[index_].data + taf->slabs[index_].size) - return TRUE; - } - - return FALSE; +taf_debug_is_taf_string(sc_tafref_t taf, const void *addr) { + const sc_byte *const addr_ = (const sc_byte * const)addr; + sc_int index_; + + /* + * Compare pointer, by address directly, against all memory contained in + * the TAF slabs. Return TRUE if in range. + */ + for (index_ = 0; index_ < taf->slab_count; index_++) { + if (addr_ >= taf->slabs[index_].data + && addr_ < taf->slabs[index_].data + taf->slabs[index_].size) + return TRUE; + } + + return FALSE; } void -taf_debug_dump (sc_tafref_t taf) -{ - sc_int index_, current_slab, current_offset; - assert (taf_is_valid (taf)); - - /* Dump complete structure. */ - sc_trace ("TAFfile: debug dump follows...\n"); - sc_trace ("taf->header ="); - for (index_ = 0; index_ < (sc_int) sizeof (taf->header); index_++) - sc_trace (" %02x", taf->header[index_]); - sc_trace ("\n"); - - sc_trace ("taf->version = %s\n", - taf->version == TAF_VERSION_400 ? "4.00" : - taf->version == TAF_VERSION_390 ? "3.90" : - taf->version == TAF_VERSION_380 ? "3.80" : "[Unknown]"); - - sc_trace ("taf->slabs = \n"); - for (index_ = 0; index_ < taf->slab_count; index_++) - { - sc_trace ("%3ld : %p, %ld bytes\n", index_, - taf->slabs[index_].data, taf->slabs[index_].size); - } - - sc_trace ("taf->slab_count = %ld\n", taf->slab_count); - sc_trace ("taf->slabs_allocated = %ld\n", taf->slabs_allocated); - sc_trace ("taf->current_slab = %ld\n", taf->current_slab); - sc_trace ("taf->current_offset = %ld\n", taf->current_offset); - - /* Save current location. */ - current_slab = taf->current_slab; - current_offset = taf->current_offset; - - /* Print out taf lines using taf iterators. */ - sc_trace ("\ntaf iterators:\n"); - taf_first_line (taf); - for (index_ = 0; taf_more_lines (taf); index_++) - sc_trace ("%5ld %s\n", index_, taf_next_line (taf)); - - /* Restore current location. */ - taf->current_slab = current_slab; - taf->current_offset = current_offset; +taf_debug_dump(sc_tafref_t taf) { + sc_int index_, current_slab, current_offset; + assert(taf_is_valid(taf)); + + /* Dump complete structure. */ + sc_trace("TAFfile: debug dump follows...\n"); + sc_trace("taf->header ="); + for (index_ = 0; index_ < (sc_int) sizeof(taf->header); index_++) + sc_trace(" %02x", taf->header[index_]); + sc_trace("\n"); + + sc_trace("taf->version = %s\n", + taf->version == TAF_VERSION_400 ? "4.00" : + taf->version == TAF_VERSION_390 ? "3.90" : + taf->version == TAF_VERSION_380 ? "3.80" : "[Unknown]"); + + sc_trace("taf->slabs = \n"); + for (index_ = 0; index_ < taf->slab_count; index_++) { + sc_trace("%3ld : %p, %ld bytes\n", index_, + taf->slabs[index_].data, taf->slabs[index_].size); + } + + sc_trace("taf->slab_count = %ld\n", taf->slab_count); + sc_trace("taf->slabs_allocated = %ld\n", taf->slabs_allocated); + sc_trace("taf->current_slab = %ld\n", taf->current_slab); + sc_trace("taf->current_offset = %ld\n", taf->current_offset); + + /* Save current location. */ + current_slab = taf->current_slab; + current_offset = taf->current_offset; + + /* Print out taf lines using taf iterators. */ + sc_trace("\ntaf iterators:\n"); + taf_first_line(taf); + for (index_ = 0; taf_more_lines(taf); index_++) + sc_trace("%5ld %s\n", index_, taf_next_line(taf)); + + /* Restore current location. */ + taf->current_slab = current_slab; + taf->current_offset = current_offset; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sctafpar.cpp b/engines/glk/adrift/sctafpar.cpp index 269308a953..9880603faf 100644 --- a/engines/glk/adrift/sctafpar.cpp +++ b/engines/glk/adrift/sctafpar.cpp @@ -42,9 +42,9 @@ namespace Adrift { /* Assorted definitions and constants. */ static const sc_char NUL = '\0'; -enum -{ PARSE_TEMP_LENGTH = 256, - PARSE_MAX_DEPTH = 32 +enum { + PARSE_TEMP_LENGTH = 256, + PARSE_MAX_DEPTH = 32 }; /* Multiline separator sequences for the various versions supported. */ @@ -71,257 +71,382 @@ static const sc_byte V380_SEPARATOR[SEPARATOR_SIZE] = {0x2a, 0x2a, 0x00}; * |...| - fixup specials for versions < 4 * {special} - because some things just defy description */ -typedef struct -{ - const sc_char *const class_name; - const sc_char *const descriptor; +typedef struct { + const sc_char *const class_name; + const sc_char *const descriptor; } sc_parse_schema_t; /* Version 4.0 TAF file properties descriptor table. */ static const sc_parse_schema_t V400_PARSE_SCHEMA[] = { - {"_GAME_", - "
Header Globals VRooms VObjects VTasks" - " VEvents VNPCs VRoomGroups VSynonyms" - " VVariables VALRs BCustomFont ?BCustomFont:$FontNameSize" - " $CompileDate"}, - {"HEADER", - "MStartupText #StartRoom MWinText"}, - {"GLOBAL", - "$GameName $GameAuthor $DontUnderstand #Perspective BShowExits #WaitTurns" - " BDispFirstRoom BBattleSystem #MaxScore $PlayerName BPromptName $PlayerDesc" - " #Task ?!#Task=0:$AltDesc #Position #ParentObject #PlayerGender" - " #MaxSize #MaxWt ?GBattleSystem:Battle BEightPointCompass bNoDebug" - " BNoScoreNotify BNoMap bNoAutoComplete bNoControlPanel bNoMouse BSound" - " BGraphics IntroRes WinRes BStatusBox $StatusBoxText" - " iUnk1 iUnk2 BEmbedded"}, - {"BATTLE", - "iStaminaLo iStaminaHi iStrengthLo iStrengthHi iAccuracyLo iAccuracyHi" - " iDefenseLo iDefenseHi iAgilityLo iAgilityHi iRecovery"}, - {"ROOM", - "$Short $Long ?GEightPointCompass:[12]Exits" - " ?!GEightPointCompass:[8]Exits Res VAlts" - " ?!GNoMap:bHideOnMap"}, - {"ROOM_EXIT", - "{V400_ROOM_EXIT:#Dest_#Var1_#Var2_#Var3}"}, - {"ROOM_ALT", - "$M1 #Type Res1 $M2 #Var2 Res2 #HideObjects $Changed" - " #Var3 #DisplayRoom"}, - {"RESOURCE", - "?GSound:$SoundFile,#SoundLen,ZSoundOffset" - " ?GGraphics:$GraphicFile,#GraphicLen,ZGraphicOffset {V400_RESOURCE}"}, - {"OBJECT", - "$Prefix $Short V$Alias BStatic $Description #InitialPosition #Task" - " BTaskNotDone $AltDesc ?BStatic:Where BContainer BSurface" - " #Capacity ?!BStatic:BWearable,#SizeWeight,#Parent" - " ?BStatic:{OBJECT:#Parent} #Openable ?#Openable=5:#Key ?#Openable=6:#Key" - " ?#Openable=7:#Key #SitLie ?!BStatic:BEdible BReadable ?BReadable:$ReadText" - " ?!BStatic:BWeapon #CurrentState ?!#CurrentState=0:$States,BStateListed" - " BListFlag Res1 Res2 ?GBattleSystem:Battle" - " $InRoomDesc #OnlyWhenNotMoved"}, - {"OBJ_BATTLE", - "iProtectionValue iHitValue iMethod iAccuracy"}, - {"ROOM_LIST1", - "#Type {ROOM_LIST1}"}, - {"TASK", - "V$Command $CompleteText $ReverseMessage $RepeatText $AdditionalMessage" - " #ShowRoomDesc BRepeatable BReversible V$ReverseCommand Where" - " $Question ?$Question:$Hint1,$Hint2 VRestrictions" - " VActions $RestrMask Res"}, - {"TASK_RESTR", - "#Type ?#Type=0:#Var1,#Var2,#Var3 ?#Type=1:#Var1,#Var2 ?#Type=2:#Var1,#Var2" - " ?#Type=3:#Var1,#Var2,#Var3 ?#Type=4:#Var1,#Var2,#Var3,$Var4 $FailMessage"}, - {"TASK_ACTION", - "#Type ?#Type=0:#Var1,#Var2,#Var3 ?#Type=1:#Var1,#Var2,#Var3" - " ?#Type=2:#Var1,#Var2 ?#Type=3:#Var1,#Var2,#Var3,$Expr,#Var5" - " ?#Type=4:#Var1 ?#Type=5:#Var1,#Var2 ?#Type=6:#Var1,#Var2,#Var3" - " ?#Type=7:iVar1,iVar2,iVar3"}, - {"ROOM_LIST0", - "#Type {ROOM_LIST0}"}, - {"EVENT", - "$Short #StarterType ?#StarterType=2:#StartTime,#EndTime" - " ?#StarterType=3:#TaskNum #RestartType BTaskFinished #Time1 #Time2" - " $StartText $LookText $FinishText Where #PauseTask" - " BPauserCompleted #PrefTime1 $PrefText1 #ResumeTask BResumerCompleted" - " #PrefTime2 $PrefText2 #Obj2 #Obj2Dest #Obj3 #Obj3Dest #Obj1 #Obj1Dest" - " #TaskAffected [5]Res"}, - {"NPC", - "$Name $Prefix V$Alias $Descr #StartRoom $AltText #Task VTopics" - " VWalks BShowEnterExit ?BShowEnterExit:$EnterText,$ExitText" - " $InRoomText #Gender [4]Res ?GBattleSystem:Battle"}, - {"NPC_BATTLE", - "iAttitude iStaminaLo iStaminaHi iStrengthLo iStrengthHi iAccuracyLo" - " iAccuracyHi iDefenseLo iDefenseHi iAgilityLo iAgilityHi iSpeed" - " iKilledTask iRecovery iStaminaTask"}, - {"TOPIC", - "$Subject $Reply #Task $AltReply"}, - {"WALK", - "#NumStops BLoop #StartTask #CharTask #MeetObject #ObjectTask #StoppingTask" - " #MeetChar $ChangedDesc {WALK:#Rooms_#Times}"}, - {"ROOM_GROUP", - "$Name {ROOM_GROUP:[]BList}"}, - {"SYNONYM", - "$Replacement $Original"}, - {"VARIABLE", - "$Name #Type $Value"}, - {"ALR", - "$Original $Replacement"}, - {NULL, NULL} + { + "_GAME_", + "
Header Globals VRooms VObjects VTasks" + " VEvents VNPCs VRoomGroups VSynonyms" + " VVariables VALRs BCustomFont ?BCustomFont:$FontNameSize" + " $CompileDate" + }, + { + "HEADER", + "MStartupText #StartRoom MWinText" + }, + { + "GLOBAL", + "$GameName $GameAuthor $DontUnderstand #Perspective BShowExits #WaitTurns" + " BDispFirstRoom BBattleSystem #MaxScore $PlayerName BPromptName $PlayerDesc" + " #Task ?!#Task=0:$AltDesc #Position #ParentObject #PlayerGender" + " #MaxSize #MaxWt ?GBattleSystem:Battle BEightPointCompass bNoDebug" + " BNoScoreNotify BNoMap bNoAutoComplete bNoControlPanel bNoMouse BSound" + " BGraphics IntroRes WinRes BStatusBox $StatusBoxText" + " iUnk1 iUnk2 BEmbedded" + }, + { + "BATTLE", + "iStaminaLo iStaminaHi iStrengthLo iStrengthHi iAccuracyLo iAccuracyHi" + " iDefenseLo iDefenseHi iAgilityLo iAgilityHi iRecovery" + }, + { + "ROOM", + "$Short $Long ?GEightPointCompass:[12]Exits" + " ?!GEightPointCompass:[8]Exits Res VAlts" + " ?!GNoMap:bHideOnMap" + }, + { + "ROOM_EXIT", + "{V400_ROOM_EXIT:#Dest_#Var1_#Var2_#Var3}" + }, + { + "ROOM_ALT", + "$M1 #Type Res1 $M2 #Var2 Res2 #HideObjects $Changed" + " #Var3 #DisplayRoom" + }, + { + "RESOURCE", + "?GSound:$SoundFile,#SoundLen,ZSoundOffset" + " ?GGraphics:$GraphicFile,#GraphicLen,ZGraphicOffset {V400_RESOURCE}" + }, + { + "OBJECT", + "$Prefix $Short V$Alias BStatic $Description #InitialPosition #Task" + " BTaskNotDone $AltDesc ?BStatic:Where BContainer BSurface" + " #Capacity ?!BStatic:BWearable,#SizeWeight,#Parent" + " ?BStatic:{OBJECT:#Parent} #Openable ?#Openable=5:#Key ?#Openable=6:#Key" + " ?#Openable=7:#Key #SitLie ?!BStatic:BEdible BReadable ?BReadable:$ReadText" + " ?!BStatic:BWeapon #CurrentState ?!#CurrentState=0:$States,BStateListed" + " BListFlag Res1 Res2 ?GBattleSystem:Battle" + " $InRoomDesc #OnlyWhenNotMoved" + }, + { + "OBJ_BATTLE", + "iProtectionValue iHitValue iMethod iAccuracy" + }, + { + "ROOM_LIST1", + "#Type {ROOM_LIST1}" + }, + { + "TASK", + "V$Command $CompleteText $ReverseMessage $RepeatText $AdditionalMessage" + " #ShowRoomDesc BRepeatable BReversible V$ReverseCommand Where" + " $Question ?$Question:$Hint1,$Hint2 VRestrictions" + " VActions $RestrMask Res" + }, + { + "TASK_RESTR", + "#Type ?#Type=0:#Var1,#Var2,#Var3 ?#Type=1:#Var1,#Var2 ?#Type=2:#Var1,#Var2" + " ?#Type=3:#Var1,#Var2,#Var3 ?#Type=4:#Var1,#Var2,#Var3,$Var4 $FailMessage" + }, + { + "TASK_ACTION", + "#Type ?#Type=0:#Var1,#Var2,#Var3 ?#Type=1:#Var1,#Var2,#Var3" + " ?#Type=2:#Var1,#Var2 ?#Type=3:#Var1,#Var2,#Var3,$Expr,#Var5" + " ?#Type=4:#Var1 ?#Type=5:#Var1,#Var2 ?#Type=6:#Var1,#Var2,#Var3" + " ?#Type=7:iVar1,iVar2,iVar3" + }, + { + "ROOM_LIST0", + "#Type {ROOM_LIST0}" + }, + { + "EVENT", + "$Short #StarterType ?#StarterType=2:#StartTime,#EndTime" + " ?#StarterType=3:#TaskNum #RestartType BTaskFinished #Time1 #Time2" + " $StartText $LookText $FinishText Where #PauseTask" + " BPauserCompleted #PrefTime1 $PrefText1 #ResumeTask BResumerCompleted" + " #PrefTime2 $PrefText2 #Obj2 #Obj2Dest #Obj3 #Obj3Dest #Obj1 #Obj1Dest" + " #TaskAffected [5]Res" + }, + { + "NPC", + "$Name $Prefix V$Alias $Descr #StartRoom $AltText #Task VTopics" + " VWalks BShowEnterExit ?BShowEnterExit:$EnterText,$ExitText" + " $InRoomText #Gender [4]Res ?GBattleSystem:Battle" + }, + { + "NPC_BATTLE", + "iAttitude iStaminaLo iStaminaHi iStrengthLo iStrengthHi iAccuracyLo" + " iAccuracyHi iDefenseLo iDefenseHi iAgilityLo iAgilityHi iSpeed" + " iKilledTask iRecovery iStaminaTask" + }, + { + "TOPIC", + "$Subject $Reply #Task $AltReply" + }, + { + "WALK", + "#NumStops BLoop #StartTask #CharTask #MeetObject #ObjectTask #StoppingTask" + " #MeetChar $ChangedDesc {WALK:#Rooms_#Times}" + }, + { + "ROOM_GROUP", + "$Name {ROOM_GROUP:[]BList}" + }, + { + "SYNONYM", + "$Replacement $Original" + }, + { + "VARIABLE", + "$Name #Type $Value" + }, + { + "ALR", + "$Original $Replacement" + }, + {NULL, NULL} }; /* Version 3.9 TAF file properties descriptor table. */ static const sc_parse_schema_t V390_PARSE_SCHEMA[] = { - {"_GAME_", - "
Header Globals VRooms VObjects VTasks" - " VEvents VNPCs VRoomGroups VSynonyms" - " VVariables VALRs BCustomFont ?BCustomFont:$FontNameSize" - " $CompileDate sPassword"}, - {"HEADER", - "MStartupText #StartRoom MWinText"}, - {"GLOBAL", - "$GameName $GameAuthor $DontUnderstand #Perspective BShowExits #WaitTurns" - " BDispFirstRoom BBattleSystem #MaxScore $PlayerName BPromptName $PlayerDesc" - " #Task ?!#Task=0:$AltDesc #Position #ParentObject #PlayerGender" - " #MaxSize #MaxWt ?GBattleSystem:Battle BEightPointCompass bNoDebug" - " BNoScoreNotify BNoMap bNoAutoComplete bNoControlPanel bNoMouse" - " BSound BGraphics IntroRes WinRes FStatusBox" - " EStatusBoxText iUnk1 iUnk2 FEmbedded"}, - {"BATTLE", - "iStamina iStrength iDefense"}, - {"ROOM", - "$Short $Long $LastDesc ?GEightPointCompass:[12]Exits" - " ?!GEightPointCompass:[8]Exits $AddDesc1 #Task1 $AddDesc2 #Task2" - " #Obj $AltDesc #TypeHideObjects Res LastRes" - " Task1Res Task2Res AltRes" - " ?!GNoMap:bHideOnMap |V390_ROOM:_Alts_|"}, - {"ROOM_EXIT", - "{V390_V380_ROOM_EXIT:#Dest_#Var1_#Var2_ZVar3}"}, - {"RESOURCE", - "?GSound:$SoundFile,ZSoundLen,ZSoundOffset" - " ?GGraphics:$GraphicFile,ZGraphicLen,ZGraphicOffset"}, - {"OBJECT", - "$Prefix $Short" - " [1]$Alias BStatic $Description #InitialPosition #Task BTaskNotDone" - " $AltDesc ?BStatic:Where BContainer BSurface #Capacity" - " ?!BStatic:BWearable,#SizeWeight,#Parent ?BStatic:{OBJECT:#Parent}" - " #Openable |V390_OBJECT:_Openable_,Key| #SitLie ?!BStatic:BEdible BReadable" - " ?BReadable:$ReadText ?!BStatic:BWeapon ZCurrentState FListFlag" - " Res1 Res2 ?GBattleSystem:Battle" - " EInRoomDesc ZOnlyWhenNotMoved"}, - {"OBJ_BATTLE", - "iProtectionValue iHitValue iMethod"}, - {"ROOM_LIST1", - "#Type {ROOM_LIST1}"}, - {"TASK", - "W$Command $CompleteText $ReverseMessage $RepeatText $AdditionalMessage" - " #ShowRoomDesc BRepeatable BReversible W$ReverseCommand Where" - " $Question ?$Question:$Hint1,$Hint2 VRestrictions" - " VActions |V390_TASK:$RestrMask| Res"}, - {"TASK_RESTR", - "#Type ?#Type=0:#Var1,#Var2,#Var3 ?#Type=1:#Var1,#Var2 ?#Type=2:#Var1,#Var2" - " ?#Type=3:#Var1,#Var2,#Var3 ?#Type=4:#Var1,#Var2,#Var3,EVar4" - ",|V390_TASK_RESTR:Var1>0?#Var1++| $FailMessage"}, - {"TASK_ACTION", - "#Type |V390_TASK_ACTION:Type>4?#Type++| ?#Type=0:#Var1,#Var2,#Var3" - " ?#Type=1:#Var1,#Var2,#Var3 ?#Type=2:#Var1,#Var2" - " ?#Type=3:#Var1,#Var2,#Var3,|V390_TASK_ACTION:$Expr_#Var5|" - " ?#Type=4:#Var1 ?#Type=6:#Var1,ZVar2,ZVar3 ?#Type=7:iVar1,iVar2,iVar3"}, - {"ROOM_LIST0", - "#Type {ROOM_LIST0}"}, - {"EVENT", - "$Short #StarterType ?#StarterType=2:#StartTime,#EndTime" - " ?#StarterType=3:#TaskNum #RestartType BTaskFinished #Time1 #Time2" - " $StartText $LookText $FinishText Where #PauseTask" - " BPauserCompleted #PrefTime1 $PrefText1 #ResumeTask BResumerCompleted" - " #PrefTime2 $PrefText2 #Obj2 #Obj2Dest #Obj3 #Obj3Dest #Obj1 #Obj1Dest" - " #TaskAffected [5]Res"}, - {"NPC", - "$Name $Prefix [1]$Alias $Descr #StartRoom $AltText #Task VTopics" - " VWalks BShowEnterExit ?BShowEnterExit:$EnterText,$ExitText" - " $InRoomText #Gender [4]Res ?GBattleSystem:Battle"}, - {"NPC_BATTLE", - "iAttitude iStamina iStrength iDefense iSpeed iKilledTask"}, - {"TOPIC", - "$Subject $Reply #Task $AltReply"}, - {"WALK", - "#NumStops BLoop #StartTask #CharTask #MeetObject #ObjectTask #StoppingTask" - " ZMeetChar $ChangedDesc {WALK:#Rooms_#Times}"}, - {"ROOM_GROUP", - "$Name {ROOM_GROUP:[]BList}"}, - {"SYNONYM", - "$Replacement $Original"}, - {"VARIABLE", - "$Name ZType $Value"}, - {"ALR", - "$Original $Replacement"}, - {NULL, NULL} + { + "_GAME_", + "
Header Globals VRooms VObjects VTasks" + " VEvents VNPCs VRoomGroups VSynonyms" + " VVariables VALRs BCustomFont ?BCustomFont:$FontNameSize" + " $CompileDate sPassword" + }, + { + "HEADER", + "MStartupText #StartRoom MWinText" + }, + { + "GLOBAL", + "$GameName $GameAuthor $DontUnderstand #Perspective BShowExits #WaitTurns" + " BDispFirstRoom BBattleSystem #MaxScore $PlayerName BPromptName $PlayerDesc" + " #Task ?!#Task=0:$AltDesc #Position #ParentObject #PlayerGender" + " #MaxSize #MaxWt ?GBattleSystem:Battle BEightPointCompass bNoDebug" + " BNoScoreNotify BNoMap bNoAutoComplete bNoControlPanel bNoMouse" + " BSound BGraphics IntroRes WinRes FStatusBox" + " EStatusBoxText iUnk1 iUnk2 FEmbedded" + }, + { + "BATTLE", + "iStamina iStrength iDefense" + }, + { + "ROOM", + "$Short $Long $LastDesc ?GEightPointCompass:[12]Exits" + " ?!GEightPointCompass:[8]Exits $AddDesc1 #Task1 $AddDesc2 #Task2" + " #Obj $AltDesc #TypeHideObjects Res LastRes" + " Task1Res Task2Res AltRes" + " ?!GNoMap:bHideOnMap |V390_ROOM:_Alts_|" + }, + { + "ROOM_EXIT", + "{V390_V380_ROOM_EXIT:#Dest_#Var1_#Var2_ZVar3}" + }, + { + "RESOURCE", + "?GSound:$SoundFile,ZSoundLen,ZSoundOffset" + " ?GGraphics:$GraphicFile,ZGraphicLen,ZGraphicOffset" + }, + { + "OBJECT", + "$Prefix $Short" + " [1]$Alias BStatic $Description #InitialPosition #Task BTaskNotDone" + " $AltDesc ?BStatic:Where BContainer BSurface #Capacity" + " ?!BStatic:BWearable,#SizeWeight,#Parent ?BStatic:{OBJECT:#Parent}" + " #Openable |V390_OBJECT:_Openable_,Key| #SitLie ?!BStatic:BEdible BReadable" + " ?BReadable:$ReadText ?!BStatic:BWeapon ZCurrentState FListFlag" + " Res1 Res2 ?GBattleSystem:Battle" + " EInRoomDesc ZOnlyWhenNotMoved" + }, + { + "OBJ_BATTLE", + "iProtectionValue iHitValue iMethod" + }, + { + "ROOM_LIST1", + "#Type {ROOM_LIST1}" + }, + { + "TASK", + "W$Command $CompleteText $ReverseMessage $RepeatText $AdditionalMessage" + " #ShowRoomDesc BRepeatable BReversible W$ReverseCommand Where" + " $Question ?$Question:$Hint1,$Hint2 VRestrictions" + " VActions |V390_TASK:$RestrMask| Res" + }, + { + "TASK_RESTR", + "#Type ?#Type=0:#Var1,#Var2,#Var3 ?#Type=1:#Var1,#Var2 ?#Type=2:#Var1,#Var2" + " ?#Type=3:#Var1,#Var2,#Var3 ?#Type=4:#Var1,#Var2,#Var3,EVar4" + ",|V390_TASK_RESTR:Var1>0?#Var1++| $FailMessage" + }, + { + "TASK_ACTION", + "#Type |V390_TASK_ACTION:Type>4?#Type++| ?#Type=0:#Var1,#Var2,#Var3" + " ?#Type=1:#Var1,#Var2,#Var3 ?#Type=2:#Var1,#Var2" + " ?#Type=3:#Var1,#Var2,#Var3,|V390_TASK_ACTION:$Expr_#Var5|" + " ?#Type=4:#Var1 ?#Type=6:#Var1,ZVar2,ZVar3 ?#Type=7:iVar1,iVar2,iVar3" + }, + { + "ROOM_LIST0", + "#Type {ROOM_LIST0}" + }, + { + "EVENT", + "$Short #StarterType ?#StarterType=2:#StartTime,#EndTime" + " ?#StarterType=3:#TaskNum #RestartType BTaskFinished #Time1 #Time2" + " $StartText $LookText $FinishText Where #PauseTask" + " BPauserCompleted #PrefTime1 $PrefText1 #ResumeTask BResumerCompleted" + " #PrefTime2 $PrefText2 #Obj2 #Obj2Dest #Obj3 #Obj3Dest #Obj1 #Obj1Dest" + " #TaskAffected [5]Res" + }, + { + "NPC", + "$Name $Prefix [1]$Alias $Descr #StartRoom $AltText #Task VTopics" + " VWalks BShowEnterExit ?BShowEnterExit:$EnterText,$ExitText" + " $InRoomText #Gender [4]Res ?GBattleSystem:Battle" + }, + { + "NPC_BATTLE", + "iAttitude iStamina iStrength iDefense iSpeed iKilledTask" + }, + { + "TOPIC", + "$Subject $Reply #Task $AltReply" + }, + { + "WALK", + "#NumStops BLoop #StartTask #CharTask #MeetObject #ObjectTask #StoppingTask" + " ZMeetChar $ChangedDesc {WALK:#Rooms_#Times}" + }, + { + "ROOM_GROUP", + "$Name {ROOM_GROUP:[]BList}" + }, + { + "SYNONYM", + "$Replacement $Original" + }, + { + "VARIABLE", + "$Name ZType $Value" + }, + { + "ALR", + "$Original $Replacement" + }, + {NULL, NULL} }; /* Version 3.8 TAF file properties descriptor table. */ static const sc_parse_schema_t V380_PARSE_SCHEMA[] = { - {"_GAME_", - "
Header Globals VRooms VObjects VTasks" - " VEvents VNPCs VRoomGroups VSynonyms" - " FCustomFont $CompileDate sPassword |V380_GLOBAL:_MaxScore_|" - " |V380_OBJECT:_InitialPositions_|"}, - {"HEADER", - "MStartupText #StartRoom MWinText"}, - {"GLOBAL", - "$GameName $GameAuthor #MaxCarried |V380_MaxSize_MaxWt_| $DontUnderstand" - " #Perspective BShowExits #WaitTurns FDispFirstRoom FBattleSystem" - " EPlayerName FPromptName EPlayerDesc ZTask ZPosition ZParentObject" - " ZPlayerGender FEightPointCompass TNoScoreNotify FSound FGraphics" - " FStatusBox EStatusBoxText FEmbedded"}, - {"ROOM", - "$Short $Long $LastDesc [8]Exits $AddDesc1 #Task1 $AddDesc2" - " #Task2 #Obj $AltDesc #TypeHideObjects |V380_ROOM:_Alts_|"}, - {"ROOM_EXIT", - "{V390_V380_ROOM_EXIT:#Dest_#Var1_#Var2_ZVar3}"}, - {"OBJECT", - "$Prefix $Short [1]$Alias BStatic $Description #InitialPosition #Task" - " BTaskNotDone $AltDesc ?BStatic:Where #SurfaceContainer" - " FSurface ?#SurfaceContainer=2:TSurface FContainer" - " ?#SurfaceContainer=1:TContainer #Capacity |V380_OBJECT:#Capacity*10+2|" - " ?!BStatic:BWearable,#SizeWeight,#Parent ?BStatic:{OBJECT:#Parent}" - " #Openable |V380_OBJECT:_Openable_,Key| #SitLie ?!BStatic:BEdible BReadable" - " ?BReadable:$ReadText ?!BStatic:BWeapon ZCurrentState FListFlag" - " EInRoomDesc ZOnlyWhenNotMoved"}, - {"ROOM_LIST1", - "#Type {ROOM_LIST1}"}, - {"TASK", - "W$Command $CompleteText $ReverseMessage $RepeatText $AdditionalMessage" - " #ShowRoomDesc BRepeatable #Score BSingleScore [6]Movements" - " BReversible W$ReverseCommand #WearObj1 #WearObj2 #HoldObj1 #HoldObj2" - " #HoldObj3 #Obj1 #Task BTaskNotDone $TaskMsg $HoldMsg $WearMsg $CompanyMsg" - " BNotInSameRoom #NPC $Obj1Msg #Obj1Room Where BKillsPlayer" - " BHoldingSameRoom $Question ?$Question:$Hint1,$Hint2 #Obj2" - " ?!#Obj2=0:#Obj2Var1,#Obj2Var2,$Obj2Msg BWinGame |V380_TASK:_Actions_|" - " |V380_TASK:_Restrictions_|"}, - {"TASK_MOVE", - "#Var1 #Var2 #Var3"}, - {"ROOM_LIST0", - "#Type {ROOM_LIST0}"}, - {"EVENT", - "$Short #StarterType ?#StarterType=2:#StartTime,#EndTime" - " ?#StarterType=3:#TaskNum #RestartType BTaskFinished #Time1 #Time2" - " $StartText $LookText $FinishText Where #PauseTask" - " BPauserCompleted #PrefTime1 $PrefText1 #ResumeTask BResumerCompleted" - " #PrefTime2 $PrefText2 #Obj2 #Obj2Dest #Obj3 #Obj3Dest #Obj1 #Obj1Dest" - " #TaskAffected"}, - {"NPC", - "$Name $Prefix [1]$Alias $Descr #StartRoom $AltText #Task VTopics" - " VWalks BShowEnterExit ?BShowEnterExit:$EnterText,$ExitText" - " $InRoomText ZGender"}, - {"TOPIC", - "$Subject $Reply #Task $AltReply"}, - {"WALK", - "#NumStops BLoop #StartTask #CharTask #MeetObject" - " ?!#MeetObject=0:|V380_WALK:_MeetObject_| #ObjectTask ZMeetChar" - " {WALK:#Rooms_#Times} ZStoppingTask EChangedDesc"}, - {"ROOM_GROUP", - "$Name {ROOM_GROUP:[]BList}"}, - {"SYNONYM", - "$Replacement $Original"}, - {NULL, NULL} + { + "_GAME_", + "
Header Globals VRooms VObjects VTasks" + " VEvents VNPCs VRoomGroups VSynonyms" + " FCustomFont $CompileDate sPassword |V380_GLOBAL:_MaxScore_|" + " |V380_OBJECT:_InitialPositions_|" + }, + { + "HEADER", + "MStartupText #StartRoom MWinText" + }, + { + "GLOBAL", + "$GameName $GameAuthor #MaxCarried |V380_MaxSize_MaxWt_| $DontUnderstand" + " #Perspective BShowExits #WaitTurns FDispFirstRoom FBattleSystem" + " EPlayerName FPromptName EPlayerDesc ZTask ZPosition ZParentObject" + " ZPlayerGender FEightPointCompass TNoScoreNotify FSound FGraphics" + " FStatusBox EStatusBoxText FEmbedded" + }, + { + "ROOM", + "$Short $Long $LastDesc [8]Exits $AddDesc1 #Task1 $AddDesc2" + " #Task2 #Obj $AltDesc #TypeHideObjects |V380_ROOM:_Alts_|" + }, + { + "ROOM_EXIT", + "{V390_V380_ROOM_EXIT:#Dest_#Var1_#Var2_ZVar3}" + }, + { + "OBJECT", + "$Prefix $Short [1]$Alias BStatic $Description #InitialPosition #Task" + " BTaskNotDone $AltDesc ?BStatic:Where #SurfaceContainer" + " FSurface ?#SurfaceContainer=2:TSurface FContainer" + " ?#SurfaceContainer=1:TContainer #Capacity |V380_OBJECT:#Capacity*10+2|" + " ?!BStatic:BWearable,#SizeWeight,#Parent ?BStatic:{OBJECT:#Parent}" + " #Openable |V380_OBJECT:_Openable_,Key| #SitLie ?!BStatic:BEdible BReadable" + " ?BReadable:$ReadText ?!BStatic:BWeapon ZCurrentState FListFlag" + " EInRoomDesc ZOnlyWhenNotMoved" + }, + { + "ROOM_LIST1", + "#Type {ROOM_LIST1}" + }, + { + "TASK", + "W$Command $CompleteText $ReverseMessage $RepeatText $AdditionalMessage" + " #ShowRoomDesc BRepeatable #Score BSingleScore [6]Movements" + " BReversible W$ReverseCommand #WearObj1 #WearObj2 #HoldObj1 #HoldObj2" + " #HoldObj3 #Obj1 #Task BTaskNotDone $TaskMsg $HoldMsg $WearMsg $CompanyMsg" + " BNotInSameRoom #NPC $Obj1Msg #Obj1Room Where BKillsPlayer" + " BHoldingSameRoom $Question ?$Question:$Hint1,$Hint2 #Obj2" + " ?!#Obj2=0:#Obj2Var1,#Obj2Var2,$Obj2Msg BWinGame |V380_TASK:_Actions_|" + " |V380_TASK:_Restrictions_|" + }, + { + "TASK_MOVE", + "#Var1 #Var2 #Var3" + }, + { + "ROOM_LIST0", + "#Type {ROOM_LIST0}" + }, + { + "EVENT", + "$Short #StarterType ?#StarterType=2:#StartTime,#EndTime" + " ?#StarterType=3:#TaskNum #RestartType BTaskFinished #Time1 #Time2" + " $StartText $LookText $FinishText Where #PauseTask" + " BPauserCompleted #PrefTime1 $PrefText1 #ResumeTask BResumerCompleted" + " #PrefTime2 $PrefText2 #Obj2 #Obj2Dest #Obj3 #Obj3Dest #Obj1 #Obj1Dest" + " #TaskAffected" + }, + { + "NPC", + "$Name $Prefix [1]$Alias $Descr #StartRoom $AltText #Task VTopics" + " VWalks BShowEnterExit ?BShowEnterExit:$EnterText,$ExitText" + " $InRoomText ZGender" + }, + { + "TOPIC", + "$Subject $Reply #Task $AltReply" + }, + { + "WALK", + "#NumStops BLoop #StartTask #CharTask #MeetObject" + " ?!#MeetObject=0:|V380_WALK:_MeetObject_| #ObjectTask ZMeetChar" + " {WALK:#Rooms_#Times} ZStoppingTask EChangedDesc" + }, + { + "ROOM_GROUP", + "$Name {ROOM_GROUP:[]BList}" + }, + { + "SYNONYM", + "$Replacement $Original" + }, + {NULL, NULL} }; @@ -331,21 +456,19 @@ static const sc_parse_schema_t V380_PARSE_SCHEMA[] = { * Select one of the parse schemata based on a TAF file. */ static const sc_parse_schema_t * -parse_select_schema (sc_tafref_t taf) -{ - /* Switch based on the TAF file version. */ - switch (taf_get_version (taf)) - { - case TAF_VERSION_400: - return V400_PARSE_SCHEMA; - case TAF_VERSION_390: - return V390_PARSE_SCHEMA; - case TAF_VERSION_380: - return V380_PARSE_SCHEMA; - default: - sc_fatal ("parse_select_schema: invalid TAF file version\n"); - return NULL; - } +parse_select_schema(sc_tafref_t taf) { + /* Switch based on the TAF file version. */ + switch (taf_get_version(taf)) { + case TAF_VERSION_400: + return V400_PARSE_SCHEMA; + case TAF_VERSION_390: + return V390_PARSE_SCHEMA; + case TAF_VERSION_380: + return V380_PARSE_SCHEMA; + default: + sc_fatal("parse_select_schema: invalid TAF file version\n"); + return NULL; + } } @@ -377,24 +500,22 @@ static sc_int parse_depth = 0; * off on unwind. */ static void -parse_push_key (sc_vartype_t vt_key, sc_char type) -{ - if (parse_depth == PARSE_MAX_DEPTH) - sc_fatal ("parse_push_key: stack overrun\n"); - - /* Push the key, and its associated type. */ - parse_vt_key[parse_depth] = vt_key; - parse_format[parse_depth] = type; - parse_depth++; +parse_push_key(sc_vartype_t vt_key, sc_char type) { + if (parse_depth == PARSE_MAX_DEPTH) + sc_fatal("parse_push_key: stack overrun\n"); + + /* Push the key, and its associated type. */ + parse_vt_key[parse_depth] = vt_key; + parse_format[parse_depth] = type; + parse_depth++; } static void -parse_pop_key (void) -{ - /* Check the stack has something to pop, then pop it. */ - if (parse_depth == 0) - sc_fatal ("parse_pop_key: stack underrun\n"); - parse_depth--; +parse_pop_key(void) { + /* Check the stack has something to pop, then pop it. */ + if (parse_depth == 0) + sc_fatal("parse_pop_key: stack underrun\n"); + parse_depth--; } @@ -406,35 +527,30 @@ parse_pop_key (void) * value */ static void -parse_retrieve_stack (sc_char format[], sc_vartype_t vt_key[], sc_int *depth) -{ - sc_int index_; - - /* Switch index-string key pairs. */ - for (index_ = 0; index_ < parse_depth; index_++) - { - if (index_ < parse_depth - 1 - && parse_format[index_] == PROP_KEY_INTEGER - && parse_format[index_ + 1] == PROP_KEY_STRING) - { - /* Swap format and key elements. */ - format[index_] = parse_format[index_ + 1]; - format[index_ + 1] = parse_format[index_]; - vt_key[index_] = parse_vt_key[index_ + 1]; - vt_key[index_ + 1] = parse_vt_key[index_]; - - index_++; - } - else - { - /* Simple copy of format and key elements. */ - format[index_] = parse_format[index_]; - vt_key[index_] = parse_vt_key[index_]; - } - } - - /* Return the parse depth. */ - *depth = parse_depth; +parse_retrieve_stack(sc_char format[], sc_vartype_t vt_key[], sc_int *depth) { + sc_int index_; + + /* Switch index-string key pairs. */ + for (index_ = 0; index_ < parse_depth; index_++) { + if (index_ < parse_depth - 1 + && parse_format[index_] == PROP_KEY_INTEGER + && parse_format[index_ + 1] == PROP_KEY_STRING) { + /* Swap format and key elements. */ + format[index_] = parse_format[index_ + 1]; + format[index_ + 1] = parse_format[index_]; + vt_key[index_] = parse_vt_key[index_ + 1]; + vt_key[index_ + 1] = parse_vt_key[index_]; + + index_++; + } else { + /* Simple copy of format and key elements. */ + format[index_] = parse_format[index_]; + vt_key[index_] = parse_vt_key[index_]; + } + } + + /* Return the parse depth. */ + *depth = parse_depth; } @@ -445,33 +561,31 @@ parse_retrieve_stack (sc_char format[], sc_vartype_t vt_key[], sc_int *depth) * be a bad game. */ static void -parse_stack_backtrace (void) -{ - sc_vartype_t vt_key[PARSE_MAX_DEPTH]; - sc_char format[PARSE_MAX_DEPTH]; - sc_int depth, index_; - - parse_retrieve_stack (format, vt_key, &depth); - - sc_error ("parse_stack_backtrace: version %s schema parsed to depth %ld\n", - (parse_schema == V400_PARSE_SCHEMA) ? "4.00" : - (parse_schema == V390_PARSE_SCHEMA) ? "3.90" : - (parse_schema == V380_PARSE_SCHEMA) ? "3.80" : "[Invalid]", - depth); - - sc_error ("parse_stack_backtrace: parse stack backtrace follows...\n"); - for (index_ = 0; index_ < depth; index_++) - { - sc_char type; - - type = format[index_]; - if (type == PROP_KEY_INTEGER) - sc_error ("%2ld - [%c] %ld\n", index_, type, vt_key[index_].integer); - else if (type == PROP_KEY_STRING) - sc_error ("%2ld - [%c] \"%s\"\n", index_, type, vt_key[index_].string); - else - sc_error ("%2ld - [%c] %p\n", index_, type, vt_key[index_].voidp); - } +parse_stack_backtrace(void) { + sc_vartype_t vt_key[PARSE_MAX_DEPTH]; + sc_char format[PARSE_MAX_DEPTH]; + sc_int depth, index_; + + parse_retrieve_stack(format, vt_key, &depth); + + sc_error("parse_stack_backtrace: version %s schema parsed to depth %ld\n", + (parse_schema == V400_PARSE_SCHEMA) ? "4.00" : + (parse_schema == V390_PARSE_SCHEMA) ? "3.90" : + (parse_schema == V380_PARSE_SCHEMA) ? "3.80" : "[Invalid]", + depth); + + sc_error("parse_stack_backtrace: parse stack backtrace follows...\n"); + for (index_ = 0; index_ < depth; index_++) { + sc_char type; + + type = format[index_]; + if (type == PROP_KEY_INTEGER) + sc_error("%2ld - [%c] %ld\n", index_, type, vt_key[index_].integer); + else if (type == PROP_KEY_STRING) + sc_error("%2ld - [%c] \"%s\"\n", index_, type, vt_key[index_].string); + else + sc_error("%2ld - [%c] %p\n", index_, type, vt_key[index_].voidp); + } } @@ -482,48 +596,46 @@ parse_stack_backtrace (void) * Write or read a property based on the keys amassed so far. */ static void -parse_put_property (sc_vartype_t vt_value, sc_char type) -{ - sc_vartype_t vt_key[PARSE_MAX_DEPTH]; - sc_char format[PARSE_MAX_DEPTH + 4]; - sc_int depth; - - /* Retrieve the adjusted stack. */ - parse_retrieve_stack (format + 3, vt_key, &depth); - - /* Complete the format for the property put. */ - format[0] = type; - format[1] = '-'; - format[2] = '>'; - format[depth + 3] = NUL; - - /* Store the property under the stacked keys. */ - assert (parse_bundle); - prop_put (parse_bundle, format, vt_value, vt_key); +parse_put_property(sc_vartype_t vt_value, sc_char type) { + sc_vartype_t vt_key[PARSE_MAX_DEPTH]; + sc_char format[PARSE_MAX_DEPTH + 4]; + sc_int depth; + + /* Retrieve the adjusted stack. */ + parse_retrieve_stack(format + 3, vt_key, &depth); + + /* Complete the format for the property put. */ + format[0] = type; + format[1] = '-'; + format[2] = '>'; + format[depth + 3] = NUL; + + /* Store the property under the stacked keys. */ + assert(parse_bundle); + prop_put(parse_bundle, format, vt_value, vt_key); } static sc_bool -parse_get_property (sc_vartype_t *vt_rvalue, sc_char type) -{ - sc_vartype_t vt_key[PARSE_MAX_DEPTH]; - sc_char format[PARSE_MAX_DEPTH + 4]; - sc_int depth; - sc_bool status; - - /* Retrieve the adjusted stack. */ - parse_retrieve_stack (format + 3, vt_key, &depth); - - /* Complete the format for the property put. */ - format[0] = type; - format[1] = '<'; - format[2] = '-'; - format[depth + 3] = NUL; - - /* Retrieve the property using the stacked keys. */ - assert (parse_bundle); - status = prop_get (parse_bundle, format, vt_rvalue, vt_key); - - return status; +parse_get_property(sc_vartype_t *vt_rvalue, sc_char type) { + sc_vartype_t vt_key[PARSE_MAX_DEPTH]; + sc_char format[PARSE_MAX_DEPTH + 4]; + sc_int depth; + sc_bool status; + + /* Retrieve the adjusted stack. */ + parse_retrieve_stack(format + 3, vt_key, &depth); + + /* Complete the format for the property put. */ + format[0] = type; + format[1] = '<'; + format[2] = '-'; + format[depth + 3] = NUL; + + /* Retrieve the property using the stacked keys. */ + assert(parse_bundle); + status = prop_get(parse_bundle, format, vt_rvalue, vt_key); + + return status; } @@ -535,14 +647,13 @@ parse_get_property (sc_vartype_t *vt_rvalue, sc_char type) * no such node exists. */ static sc_int -parse_get_child_count (void) -{ - sc_vartype_t vt_rvalue; +parse_get_child_count(void) { + sc_vartype_t vt_rvalue; - if (!parse_get_property (&vt_rvalue, PROP_INTEGER)) - vt_rvalue.integer = 0; + if (!parse_get_property(&vt_rvalue, PROP_INTEGER)) + vt_rvalue.integer = 0; - return vt_rvalue.integer; + return vt_rvalue.integer; } @@ -555,36 +666,33 @@ parse_get_child_count (void) * a fatal error if the property does not exist. */ static sc_int -parse_get_integer_property (void) -{ - sc_vartype_t vt_rvalue; +parse_get_integer_property(void) { + sc_vartype_t vt_rvalue; - if (!parse_get_property (&vt_rvalue, PROP_INTEGER)) - sc_fatal ("parse_get_integer_property: missing property\n"); + if (!parse_get_property(&vt_rvalue, PROP_INTEGER)) + sc_fatal("parse_get_integer_property: missing property\n"); - return vt_rvalue.integer; + return vt_rvalue.integer; } static sc_bool -parse_get_boolean_property (void) -{ - sc_vartype_t vt_rvalue; +parse_get_boolean_property(void) { + sc_vartype_t vt_rvalue; - if (!parse_get_property (&vt_rvalue, PROP_BOOLEAN)) - sc_fatal ("parse_get_boolean_property: missing property\n"); + if (!parse_get_property(&vt_rvalue, PROP_BOOLEAN)) + sc_fatal("parse_get_boolean_property: missing property\n"); - return vt_rvalue.boolean; + return vt_rvalue.boolean; } static const sc_char * -parse_get_string_property (void) -{ - sc_vartype_t vt_rvalue; +parse_get_string_property(void) { + sc_vartype_t vt_rvalue; - if (!parse_get_property (&vt_rvalue, PROP_STRING)) - sc_fatal ("parse_get_string_property: missing property\n"); + if (!parse_get_property(&vt_rvalue, PROP_STRING)) + sc_fatal("parse_get_string_property: missing property\n"); - return vt_rvalue.string; + return vt_rvalue.string; } @@ -606,132 +714,121 @@ static sc_bool parse_use_pushback = FALSE; * TAF line pushback. */ static const sc_char * -parse_get_taf_string (void) -{ - const sc_char *line; - - /* If pushback requested, use that instead of reading. */ - if (parse_use_pushback) - { - /* Use the pushback line, and clear the request. */ - assert (parse_pushback_line); - line = parse_pushback_line; - parse_use_pushback = FALSE; - } - else - { - /* Get the next line, and complain if absent. */ - line = taf_next_line (parse_taf); - if (!line) - { - sc_error ("parse_get_taf_string:" - " out of TAF data at line %ld\n", parse_tafline); - parse_stack_backtrace (); - longjmp (parse_taf_error, 1); - } - - /* Note this line for possible pushback. */ - parse_pushback_line = line; - } - - /* Print out the line we're parsing if tracing. */ - if (parse_trace) - sc_trace ("Parse: read in line %ld : %s\n", parse_tafline, line); - - parse_tafline++; - return line; +parse_get_taf_string(void) { + const sc_char *line; + + /* If pushback requested, use that instead of reading. */ + if (parse_use_pushback) { + /* Use the pushback line, and clear the request. */ + assert(parse_pushback_line); + line = parse_pushback_line; + parse_use_pushback = FALSE; + } else { + /* Get the next line, and complain if absent. */ + line = taf_next_line(parse_taf); + if (!line) { + sc_error("parse_get_taf_string:" + " out of TAF data at line %ld\n", parse_tafline); + parse_stack_backtrace(); + longjmp(parse_taf_error, 1); + } + + /* Note this line for possible pushback. */ + parse_pushback_line = line; + } + + /* Print out the line we're parsing if tracing. */ + if (parse_trace) + sc_trace("Parse: read in line %ld : %s\n", parse_tafline, line); + + parse_tafline++; + return line; } static sc_int -parse_get_taf_integer (void) -{ - const sc_char *line; - sc_int integer; - - /* Get line, and scan for a single integer; return it. */ - line = parse_get_taf_string (); - if (sscanf (line, "%ld", &integer) != 1) - { - sc_error ("parse_get_taf_integer:" - " invalid integer at line %ld\n", parse_tafline - 1); - parse_stack_backtrace (); - longjmp (parse_taf_error, 1); - } - - return integer; +parse_get_taf_integer(void) { + const sc_char *line; + sc_int integer; + + /* Get line, and scan for a single integer; return it. */ + line = parse_get_taf_string(); + if (sscanf(line, "%ld", &integer) != 1) { + sc_error("parse_get_taf_integer:" + " invalid integer at line %ld\n", parse_tafline - 1); + parse_stack_backtrace(); + longjmp(parse_taf_error, 1); + } + + return integer; } static sc_bool -parse_get_taf_boolean (void) -{ - const sc_char *line; - sc_uint boolean; - - /* - * Get line, and scan for a single integer; check it's a valid-looking flag, - * and return it. - */ - line = parse_get_taf_string (); - if (sscanf (line, "%lu", &boolean) != 1) - { - sc_error ("parse_get_taf_boolean:" - " invalid boolean at line %ld\n", parse_tafline - 1); - parse_stack_backtrace (); - longjmp (parse_taf_error, 1); - } - if (boolean != 0 && boolean != 1) - { - sc_error ("parse_get_taf_boolean:" - " warning: suspect boolean at line %ld\n", parse_tafline - 1); - } - - return boolean != 0; +parse_get_taf_boolean(void) { + const sc_char *line; + sc_uint boolean; + + /* + * Get line, and scan for a single integer; check it's a valid-looking flag, + * and return it. + */ + line = parse_get_taf_string(); + if (sscanf(line, "%lu", &boolean) != 1) { + sc_error("parse_get_taf_boolean:" + " invalid boolean at line %ld\n", parse_tafline - 1); + parse_stack_backtrace(); + longjmp(parse_taf_error, 1); + } + if (boolean != 0 && boolean != 1) { + sc_error("parse_get_taf_boolean:" + " warning: suspect boolean at line %ld\n", parse_tafline - 1); + } + + return boolean != 0; } static void -parse_taf_pushback (void) -{ - if (parse_use_pushback || !parse_pushback_line) - sc_fatal ("parse_taf_pushback: too much pushback requested\n"); - - /* Set pushback request, and decrement line counter. */ - parse_use_pushback = TRUE; - parse_tafline--; - - /* Note pushback for tracing purposes. */ - if (parse_trace) - sc_trace ("Parse: push back at line %ld\n", parse_tafline); +parse_taf_pushback(void) { + if (parse_use_pushback || !parse_pushback_line) + sc_fatal("parse_taf_pushback: too much pushback requested\n"); + + /* Set pushback request, and decrement line counter. */ + parse_use_pushback = TRUE; + parse_tafline--; + + /* Note pushback for tracing purposes. */ + if (parse_trace) + sc_trace("Parse: push back at line %ld\n", parse_tafline); } /* Enumerations of parse types found in the parse schema. */ -enum -{ PARSE_INTEGER = '#', - PARSE_DEFAULT_ZERO = 'Z', - PARSE_BOOLEAN = 'B', - PARSE_DEFAULT_FALSE = 'F', - PARSE_DEFAULT_TRUE = 'T', - PARSE_STRING = '$', - PARSE_DEFAULT_EMPTY = 'E', - PARSE_MULTILINE = 'M', - PARSE_VECTOR = 'V', - PARSE_VECTOR_ALTERNATE = 'W', - PARSE_ARRAY = '[', - PARSE_EXPRESSION = '?', - PARSE_EXPRESSION_NOT = '!', - PARSE_GLOBAL_EXPRESSION = 'G', - PARSE_CLASS = '<', - PARSE_FIXUP = '|', - PARSE_SPECIAL = '{', - PARSE_IGNORE_INTEGER = 'i', - PARSE_IGNORE_BOOLEAN = 'b', - PARSE_IGNORE_STRING = 's' +enum { + PARSE_INTEGER = '#', + PARSE_DEFAULT_ZERO = 'Z', + PARSE_BOOLEAN = 'B', + PARSE_DEFAULT_FALSE = 'F', + PARSE_DEFAULT_TRUE = 'T', + PARSE_STRING = '$', + PARSE_DEFAULT_EMPTY = 'E', + PARSE_MULTILINE = 'M', + PARSE_VECTOR = 'V', + PARSE_VECTOR_ALTERNATE = 'W', + PARSE_ARRAY = '[', + PARSE_EXPRESSION = '?', + PARSE_EXPRESSION_NOT = '!', + PARSE_GLOBAL_EXPRESSION = 'G', + PARSE_CLASS = '<', + PARSE_FIXUP = '|', + PARSE_SPECIAL = '{', + PARSE_IGNORE_INTEGER = 'i', + PARSE_IGNORE_BOOLEAN = 'b', + PARSE_IGNORE_STRING = 's' }; /* Forward declarations of parse functions for recursion. */ -static void parse_element (const sc_char *element); -static void parse_class (const sc_char *class_); -static void parse_descriptor (const sc_char *descriptor); +static void parse_element(const sc_char *element); +static void parse_class(const sc_char *class_); +static void parse_descriptor(const sc_char *descriptor); /* * parse_array() @@ -739,33 +836,31 @@ static void parse_descriptor (const sc_char *descriptor); * Parse a descriptor [] array. */ static void -parse_array (const sc_char *array) -{ - sc_int count, index_; - sc_char element[PARSE_TEMP_LENGTH]; +parse_array(const sc_char *array) { + sc_int count, index_; + sc_char element[PARSE_TEMP_LENGTH]; - if (parse_trace) - sc_trace ("Parse: entering array %s\n", array); + if (parse_trace) + sc_trace("Parse: entering array %s\n", array); - /* Find the count of elements in the array, and the element itself. */ - if (sscanf (array, "[%ld]%[^ ]", &count, element) != 2) - sc_fatal ("parse_array: bad array, %s\n", array); + /* Find the count of elements in the array, and the element itself. */ + if (sscanf(array, "[%ld]%[^ ]", &count, element) != 2) + sc_fatal("parse_array: bad array, %s\n", array); - /* Parse the element for array count iterations, each a key. */ - for (index_ = 0; index_ < count; index_++) - { - sc_vartype_t vt_key; + /* Parse the element for array count iterations, each a key. */ + for (index_ = 0; index_ < count; index_++) { + sc_vartype_t vt_key; - vt_key.integer = index_; - parse_push_key (vt_key, PROP_KEY_INTEGER); + vt_key.integer = index_; + parse_push_key(vt_key, PROP_KEY_INTEGER); - parse_element (element); + parse_element(element); - parse_pop_key (); - } + parse_pop_key(); + } - if (parse_trace) - sc_trace ("Parse: leaving array %s\n", array); + if (parse_trace) + sc_trace("Parse: leaving array %s\n", array); } @@ -777,54 +872,50 @@ parse_array (const sc_char *array) * Parse a variable-length vector of properties. */ static void -parse_vector_common (const sc_char *vector, sc_int count) -{ - sc_int index_; +parse_vector_common(const sc_char *vector, sc_int count) { + sc_int index_; - /* Parse the vector property count times, pushing a key on each. */ - for (index_ = 0; index_ < count; index_++) - { - sc_vartype_t vt_key; + /* Parse the vector property count times, pushing a key on each. */ + for (index_ = 0; index_ < count; index_++) { + sc_vartype_t vt_key; - vt_key.integer = index_; - parse_push_key (vt_key, PROP_KEY_INTEGER); + vt_key.integer = index_; + parse_push_key(vt_key, PROP_KEY_INTEGER); - parse_element (vector + 1); + parse_element(vector + 1); - parse_pop_key (); - } + parse_pop_key(); + } } static void -parse_vector (const sc_char *vector) -{ - sc_int count; +parse_vector(const sc_char *vector) { + sc_int count; - if (parse_trace) - sc_trace ("Parse: entering vector %s\n", vector); + if (parse_trace) + sc_trace("Parse: entering vector %s\n", vector); - /* Find the count of elements in the vector, and parse. */ - count = parse_get_taf_integer (); - parse_vector_common (vector, count); + /* Find the count of elements in the vector, and parse. */ + count = parse_get_taf_integer(); + parse_vector_common(vector, count); - if (parse_trace) - sc_trace ("Parse: leaving vector %s\n", vector); + if (parse_trace) + sc_trace("Parse: leaving vector %s\n", vector); } static void -parse_vector_alternate (const sc_char *vector) -{ - sc_int count; +parse_vector_alternate(const sc_char *vector) { + sc_int count; - if (parse_trace) - sc_trace ("Parse: entering alternate vector %s\n", vector); + if (parse_trace) + sc_trace("Parse: entering alternate vector %s\n", vector); - /* Element count, this is a vector described by size - 1. */ - count = parse_get_taf_integer () + 1; - parse_vector_common (vector, count); + /* Element count, this is a vector described by size - 1. */ + count = parse_get_taf_integer() + 1; + parse_vector_common(vector, count); - if (parse_trace) - sc_trace ("Parse: leaving alternate vector %s\n", vector); + if (parse_trace) + sc_trace("Parse: leaving alternate vector %s\n", vector); } @@ -835,112 +926,105 @@ parse_vector_alternate (const sc_char *vector) * Parse a conditional field definition, with runtime test. */ static sc_bool -parse_test_expression (const sc_char *test_expression) -{ - sc_vartype_t vt_key; - sc_char plhs[PARSE_TEMP_LENGTH]; - sc_int rhs; - sc_bool retval = FALSE; - - /* Identify the type of expression to evaluate. */ - switch (test_expression[0]) - { - case PARSE_BOOLEAN: - /* Read boolean property and return its value. */ - vt_key.string = test_expression + 1; - parse_push_key (vt_key, PROP_KEY_STRING); - retval = parse_get_boolean_property (); - parse_pop_key (); - break; - - case PARSE_INTEGER: - /* Get the left and right sides of = comparison. */ - if (sscanf (test_expression, "#%[^=]=%ld", plhs, &rhs) != 2) - { - sc_fatal ("parse_test_expression: bad = compare, %s\n", - test_expression + 1); - } - - /* Read integer property and return comparison. */ - vt_key.string = plhs; - parse_push_key (vt_key, PROP_KEY_STRING); - retval = (parse_get_integer_property () == rhs); - parse_pop_key (); - break; - - case PARSE_STRING: - /* Read property and return TRUE if not an empty string. */ - vt_key.string = test_expression + 1; - parse_push_key (vt_key, PROP_KEY_STRING); - retval = !sc_strempty (parse_get_string_property ()); - parse_pop_key (); - break; - - case PARSE_GLOBAL_EXPRESSION: - { - sc_vartype_t vt_gkey[2]; - - /* Read the given Global boolean property and return it. */ - vt_gkey[0].string = "Globals"; - vt_gkey[1].string = test_expression + 1; - retval = prop_get_boolean (parse_bundle, "B<-ss", vt_gkey); - break; - } - - default: - sc_fatal ("parse_test_expression:" - " bad expression, %s\n", test_expression + 1); - } - - if (parse_trace) - sc_trace ("Parse: expression is %s\n", retval ? "true" : "false"); - - return retval; +parse_test_expression(const sc_char *test_expression) { + sc_vartype_t vt_key; + sc_char plhs[PARSE_TEMP_LENGTH]; + sc_int rhs; + sc_bool retval = FALSE; + + /* Identify the type of expression to evaluate. */ + switch (test_expression[0]) { + case PARSE_BOOLEAN: + /* Read boolean property and return its value. */ + vt_key.string = test_expression + 1; + parse_push_key(vt_key, PROP_KEY_STRING); + retval = parse_get_boolean_property(); + parse_pop_key(); + break; + + case PARSE_INTEGER: + /* Get the left and right sides of = comparison. */ + if (sscanf(test_expression, "#%[^=]=%ld", plhs, &rhs) != 2) { + sc_fatal("parse_test_expression: bad = compare, %s\n", + test_expression + 1); + } + + /* Read integer property and return comparison. */ + vt_key.string = plhs; + parse_push_key(vt_key, PROP_KEY_STRING); + retval = (parse_get_integer_property() == rhs); + parse_pop_key(); + break; + + case PARSE_STRING: + /* Read property and return TRUE if not an empty string. */ + vt_key.string = test_expression + 1; + parse_push_key(vt_key, PROP_KEY_STRING); + retval = !sc_strempty(parse_get_string_property()); + parse_pop_key(); + break; + + case PARSE_GLOBAL_EXPRESSION: { + sc_vartype_t vt_gkey[2]; + + /* Read the given Global boolean property and return it. */ + vt_gkey[0].string = "Globals"; + vt_gkey[1].string = test_expression + 1; + retval = prop_get_boolean(parse_bundle, "B<-ss", vt_gkey); + break; + } + + default: + sc_fatal("parse_test_expression:" + " bad expression, %s\n", test_expression + 1); + } + + if (parse_trace) + sc_trace("Parse: expression is %s\n", retval ? "true" : "false"); + + return retval; } static void -parse_expression (const sc_char *expression) -{ - sc_char test_expression[PARSE_TEMP_LENGTH]; - sc_bool is_present; - - if (parse_trace) - sc_trace ("Parse: entering expression %s\n", expression); - - /* Isolate the test part of the expression. */ - if (sscanf (expression, "?%[^:]", test_expression) != 1) - sc_fatal ("parse_expression: bad expression, %s\n", expression); - - /* Handle the remainder of the expression only if test passes. */ - is_present = (test_expression[0] == PARSE_EXPRESSION_NOT) - ? !parse_test_expression (test_expression + 1) - : parse_test_expression (test_expression); - if (is_present) - { - sc_int next; - - /* - * Following the ':' may be a single element, or a comma-separated list. - */ - for (next = strlen (test_expression) + 2; expression[next] != NUL; ) - { - sc_char element[PARSE_TEMP_LENGTH]; - - /* Get the next individual element to parse. */ - if (sscanf (expression + next, "%[^,]", element) != 1) - sc_fatal ("parse_expression: bad list, %s\n", expression + next); - - /* Parse this isolated element. */ - parse_element (element); - - /* Advance to the start of the next element. */ - next += strlen (element); - next += strspn (expression + next, ","); - } - } - - if (parse_trace) - sc_trace ("Parse: leaving expression %s\n", expression); +parse_expression(const sc_char *expression) { + sc_char test_expression[PARSE_TEMP_LENGTH]; + sc_bool is_present; + + if (parse_trace) + sc_trace("Parse: entering expression %s\n", expression); + + /* Isolate the test part of the expression. */ + if (sscanf(expression, "?%[^:]", test_expression) != 1) + sc_fatal("parse_expression: bad expression, %s\n", expression); + + /* Handle the remainder of the expression only if test passes. */ + is_present = (test_expression[0] == PARSE_EXPRESSION_NOT) + ? !parse_test_expression(test_expression + 1) + : parse_test_expression(test_expression); + if (is_present) { + sc_int next; + + /* + * Following the ':' may be a single element, or a comma-separated list. + */ + for (next = strlen(test_expression) + 2; expression[next] != NUL;) { + sc_char element[PARSE_TEMP_LENGTH]; + + /* Get the next individual element to parse. */ + if (sscanf(expression + next, "%[^,]", element) != 1) + sc_fatal("parse_expression: bad list, %s\n", expression + next); + + /* Parse this isolated element. */ + parse_element(element); + + /* Advance to the start of the next element. */ + next += strlen(element); + next += strspn(expression + next, ","); + } + } + + if (parse_trace) + sc_trace("Parse: leaving expression %s\n", expression); } @@ -951,46 +1035,43 @@ parse_expression (const sc_char *expression) * string is malloc'ed, and the caller needs to handle that. */ static sc_char * -parse_read_multiline (void) -{ - const sc_byte *separator = NULL; - const sc_char *line; - sc_char *multiline; - - /* Select the appropriate multiline separator. */ - switch (taf_get_version (parse_taf)) - { - case TAF_VERSION_400: - separator = V400_SEPARATOR; - break; - case TAF_VERSION_390: - separator = V390_SEPARATOR; - break; - case TAF_VERSION_380: - separator = V380_SEPARATOR; - break; - default: - sc_fatal ("parse_read_multiline: invalid TAF file version\n"); - break; - } - - /* Take a simple copy of the first line. */ - line = parse_get_taf_string (); - multiline = (sc_char *)sc_malloc (strlen (line) + 1); - strcpy (multiline, line); - - /* Now concatenate until separator found. */ - line = parse_get_taf_string (); - while (memcmp (line, separator, SEPARATOR_SIZE) != 0) - { - multiline = (sc_char *)sc_realloc (multiline, - strlen (multiline) + strlen (line) + 2); - strcat (multiline, "\n"); - strcat (multiline, line); - line = parse_get_taf_string (); - } - - return multiline; +parse_read_multiline(void) { + const sc_byte *separator = NULL; + const sc_char *line; + sc_char *multiline; + + /* Select the appropriate multiline separator. */ + switch (taf_get_version(parse_taf)) { + case TAF_VERSION_400: + separator = V400_SEPARATOR; + break; + case TAF_VERSION_390: + separator = V390_SEPARATOR; + break; + case TAF_VERSION_380: + separator = V380_SEPARATOR; + break; + default: + sc_fatal("parse_read_multiline: invalid TAF file version\n"); + break; + } + + /* Take a simple copy of the first line. */ + line = parse_get_taf_string(); + multiline = (sc_char *)sc_malloc(strlen(line) + 1); + strcpy(multiline, line); + + /* Now concatenate until separator found. */ + line = parse_get_taf_string(); + while (memcmp(line, separator, SEPARATOR_SIZE) != 0) { + multiline = (sc_char *)sc_realloc(multiline, + strlen(multiline) + strlen(line) + 2); + strcat(multiline, "\n"); + strcat(multiline, line); + line = parse_get_taf_string(); + } + + return multiline; } @@ -1000,76 +1081,74 @@ parse_read_multiline (void) * Common handler for string, integer, boolean, and multiline parse terminals. */ static void -parse_terminal (const sc_char *terminal) -{ - sc_vartype_t vt_key, vt_value; - - if (parse_trace) - sc_trace ("Parse: entering terminal %s\n", terminal); - - /* Push the key string. */ - vt_key.string = terminal + 1; - parse_push_key (vt_key, PROP_KEY_STRING); - - /* Retrieve, or invent, then store the value. */ - switch (terminal[0]) - { - case PARSE_INTEGER: - vt_value.integer = parse_get_taf_integer (); - parse_put_property (vt_value, PROP_INTEGER); - break; - case PARSE_DEFAULT_ZERO: - vt_value.integer = 0; - parse_put_property (vt_value, PROP_INTEGER); - break; - - case PARSE_BOOLEAN: - vt_value.boolean = parse_get_taf_boolean (); - parse_put_property (vt_value, PROP_BOOLEAN); - break; - case PARSE_DEFAULT_FALSE: - case PARSE_DEFAULT_TRUE: - vt_value.boolean = (terminal[0] == PARSE_DEFAULT_TRUE); - parse_put_property (vt_value, PROP_BOOLEAN); - break; - - case PARSE_STRING: - vt_value.string = parse_get_taf_string (); - parse_put_property (vt_value, PROP_STRING); - break; - case PARSE_DEFAULT_EMPTY: - vt_value.string = ""; - parse_put_property (vt_value, PROP_STRING); - break; - - case PARSE_MULTILINE: - /* Assign to and adopt mutable string rather than const string. */ - vt_value.mutable_string = parse_read_multiline (); - parse_put_property (vt_value, PROP_STRING); - - assert (parse_bundle); - prop_adopt (parse_bundle, vt_value.mutable_string); - break; - - case PARSE_IGNORE_INTEGER: - (void) parse_get_taf_integer (); - break; - case PARSE_IGNORE_BOOLEAN: - (void) parse_get_taf_boolean (); - break; - case PARSE_IGNORE_STRING: - (void) parse_get_taf_string (); - break; - - default: - sc_fatal ("parse_terminal: bad type, %c\n", terminal[0]); - } - - /* Pop terminal key. */ - parse_pop_key (); - - if (parse_trace) - sc_trace ("Parse: leaving terminal %s\n", terminal); +parse_terminal(const sc_char *terminal) { + sc_vartype_t vt_key, vt_value; + + if (parse_trace) + sc_trace("Parse: entering terminal %s\n", terminal); + + /* Push the key string. */ + vt_key.string = terminal + 1; + parse_push_key(vt_key, PROP_KEY_STRING); + + /* Retrieve, or invent, then store the value. */ + switch (terminal[0]) { + case PARSE_INTEGER: + vt_value.integer = parse_get_taf_integer(); + parse_put_property(vt_value, PROP_INTEGER); + break; + case PARSE_DEFAULT_ZERO: + vt_value.integer = 0; + parse_put_property(vt_value, PROP_INTEGER); + break; + + case PARSE_BOOLEAN: + vt_value.boolean = parse_get_taf_boolean(); + parse_put_property(vt_value, PROP_BOOLEAN); + break; + case PARSE_DEFAULT_FALSE: + case PARSE_DEFAULT_TRUE: + vt_value.boolean = (terminal[0] == PARSE_DEFAULT_TRUE); + parse_put_property(vt_value, PROP_BOOLEAN); + break; + + case PARSE_STRING: + vt_value.string = parse_get_taf_string(); + parse_put_property(vt_value, PROP_STRING); + break; + case PARSE_DEFAULT_EMPTY: + vt_value.string = ""; + parse_put_property(vt_value, PROP_STRING); + break; + + case PARSE_MULTILINE: + /* Assign to and adopt mutable string rather than const string. */ + vt_value.mutable_string = parse_read_multiline(); + parse_put_property(vt_value, PROP_STRING); + + assert(parse_bundle); + prop_adopt(parse_bundle, vt_value.mutable_string); + break; + + case PARSE_IGNORE_INTEGER: + (void) parse_get_taf_integer(); + break; + case PARSE_IGNORE_BOOLEAN: + (void) parse_get_taf_boolean(); + break; + case PARSE_IGNORE_STRING: + (void) parse_get_taf_string(); + break; + + default: + sc_fatal("parse_terminal: bad type, %c\n", terminal[0]); + } + + /* Pop terminal key. */ + parse_pop_key(); + + if (parse_trace) + sc_trace("Parse: leaving terminal %s\n", terminal); } @@ -1078,12 +1157,11 @@ parse_terminal (const sc_char *terminal) * for the various sound and graphic resources encountered on parsing * version 4.0 games. It's unused if the version is not 4.0. */ -typedef struct -{ - sc_char *name; - sc_uint hash; - sc_int length; - sc_int offset; +typedef struct { + sc_char *name; + sc_uint hash; + sc_int length; + sc_int offset; } sc_parse_resource_t; enum { RESOURCE_GROW_INCREMENT = 32 }; @@ -1098,21 +1176,19 @@ static sc_parse_resource_t *parse_resources = NULL; * Free and clear down the version 4.0 resources table. */ static void -parse_clear_v400_resources_table (void) -{ - /* Free allocated memory and return to initial values. */ - if (parse_resources) - { - sc_int index_; - - for (index_ = 0; index_ < parse_resources_length; index_++) - sc_free (parse_resources[index_].name); - - sc_free (parse_resources); - parse_resources = NULL; - } - parse_resources_length = 0; - parse_resources_size = 0; +parse_clear_v400_resources_table(void) { + /* Free allocated memory and return to initial values. */ + if (parse_resources) { + sc_int index_; + + for (index_ = 0; index_ < parse_resources_length; index_++) + sc_free(parse_resources[index_].name); + + sc_free(parse_resources); + parse_resources = NULL; + } + parse_resources_length = 0; + parse_resources_size = 0; } @@ -1130,77 +1206,71 @@ parse_clear_v400_resources_table (void) * length with real_length to see if that happened. */ static sc_int -parse_get_v400_resource_offset (const sc_char *name, - sc_int length, sc_int *real_length) -{ - sc_char *clean_name; - sc_uint hash; - sc_int index_, offset; - - /* - * Take a copy of the name, and remove any trailing "##" looping sound - * indicator flag. Who thinks this junk up? - */ - clean_name = (sc_char *)sc_malloc (strlen (name) + 1); - strcpy (clean_name, name); - if (strcmp (clean_name + strlen (clean_name) - 2, "##") == 0) - clean_name[strlen (clean_name) - 2] = NUL; - - /* - * Scan the current resources list for a matching name, and if the resource - * is already known, return its offset. The hash check is an attempt to - * improve the search times, relative to using only string comparisons -- - * the table's not fully hashed. If found, we need to also pass back the - * corrected length. - */ - offset = -1; - hash = sc_hash (clean_name); - for (index_ = 0; index_ < parse_resources_length; index_++) - { - if (parse_resources[index_].hash == hash - && strcmp (parse_resources[index_].name, clean_name) == 0) - { - offset = parse_resources[index_].offset; - break; - } - } - if (offset != -1) - { - *real_length = parse_resources[index_].length; - sc_free (clean_name); - return offset; - } - - /* Resize the resources table if required. */ - if (parse_resources_length == parse_resources_size) - { - parse_resources_size += RESOURCE_GROW_INCREMENT; - parse_resources = (sc_parse_resource_t *)sc_realloc (parse_resources, - parse_resources_size * - sizeof (parse_resources[0])); - } - - /* - * Calculate the offset. For the first resource, it's zero; for others, - * it's one after the prior entry's offset and length. - */ - if (parse_resources_length == 0) - offset = 0; - else - { - offset = parse_resources[parse_resources_length - 1].offset - + parse_resources[parse_resources_length - 1].length + 1; - } - - /* Add details to the table. */ - parse_resources[parse_resources_length].name = clean_name; - parse_resources[parse_resources_length].hash = hash; - parse_resources[parse_resources_length].offset = offset; - parse_resources[parse_resources_length].length = length; - parse_resources_length++; - - *real_length = length; - return offset; +parse_get_v400_resource_offset(const sc_char *name, + sc_int length, sc_int *real_length) { + sc_char *clean_name; + sc_uint hash; + sc_int index_, offset; + + /* + * Take a copy of the name, and remove any trailing "##" looping sound + * indicator flag. Who thinks this junk up? + */ + clean_name = (sc_char *)sc_malloc(strlen(name) + 1); + strcpy(clean_name, name); + if (strcmp(clean_name + strlen(clean_name) - 2, "##") == 0) + clean_name[strlen(clean_name) - 2] = NUL; + + /* + * Scan the current resources list for a matching name, and if the resource + * is already known, return its offset. The hash check is an attempt to + * improve the search times, relative to using only string comparisons -- + * the table's not fully hashed. If found, we need to also pass back the + * corrected length. + */ + offset = -1; + hash = sc_hash(clean_name); + for (index_ = 0; index_ < parse_resources_length; index_++) { + if (parse_resources[index_].hash == hash + && strcmp(parse_resources[index_].name, clean_name) == 0) { + offset = parse_resources[index_].offset; + break; + } + } + if (offset != -1) { + *real_length = parse_resources[index_].length; + sc_free(clean_name); + return offset; + } + + /* Resize the resources table if required. */ + if (parse_resources_length == parse_resources_size) { + parse_resources_size += RESOURCE_GROW_INCREMENT; + parse_resources = (sc_parse_resource_t *)sc_realloc(parse_resources, + parse_resources_size * + sizeof(parse_resources[0])); + } + + /* + * Calculate the offset. For the first resource, it's zero; for others, + * it's one after the prior entry's offset and length. + */ + if (parse_resources_length == 0) + offset = 0; + else { + offset = parse_resources[parse_resources_length - 1].offset + + parse_resources[parse_resources_length - 1].length + 1; + } + + /* Add details to the table. */ + parse_resources[parse_resources_length].name = clean_name; + parse_resources[parse_resources_length].hash = hash; + parse_resources[parse_resources_length].offset = offset; + parse_resources[parse_resources_length].length = length; + parse_resources_length++; + + *real_length = length; + return offset; } @@ -1221,104 +1291,97 @@ parse_get_v400_resource_offset (const sc_char *name, * our parse_resources table, but not always... */ static void -parse_handle_v400_resources (sc_bool has_sound, sc_bool has_graphics) -{ - sc_vartype_t vt_key, vt_value; - const sc_char *file; - sc_int length, offset; - - /* - * Retrieve the file and length for the sound just parsed. If there's a - * file of non-zero length, rewrite its offset. - */ - if (has_sound) - { - /* Retrieve the file and length information. */ - vt_key.string = "SoundFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - file = parse_get_string_property (); - parse_pop_key (); - - vt_key.string = "SoundLen"; - parse_push_key (vt_key, PROP_KEY_STRING); - length = parse_get_integer_property (); - parse_pop_key (); - - /* - * If defined and has a length, rewrite the offset, and also the length - * in case changed. - */ - if (!sc_strempty (file) && length != 0) - { - sc_int real_length; - - offset = parse_get_v400_resource_offset (file, length, &real_length); - vt_key.string = "SoundOffset"; - parse_push_key (vt_key, PROP_KEY_STRING); - - vt_value.integer = offset; - parse_put_property (vt_value, PROP_INTEGER); - - parse_pop_key (); - - /* Rewrite length if changed. */ - if (real_length != length) - { - vt_key.string = "SoundLen"; - parse_push_key (vt_key, PROP_KEY_STRING); - - vt_value.integer = real_length; - parse_put_property (vt_value, PROP_INTEGER); - - parse_pop_key (); - } - } - } - - /* Now do the same thing for graphics. */ - if (has_graphics) - { - /* Retrieve the file and length information. */ - vt_key.string = "GraphicFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - file = parse_get_string_property (); - parse_pop_key (); - - vt_key.string = "GraphicLen"; - parse_push_key (vt_key, PROP_KEY_STRING); - length = parse_get_integer_property (); - parse_pop_key (); - - /* - * If defined and has a length, rewrite the offset, and also the length - * in case changed. - */ - if (!sc_strempty (file) && length != 0) - { - sc_int real_length; - - offset = parse_get_v400_resource_offset (file, length, &real_length); - vt_key.string = "GraphicOffset"; - parse_push_key (vt_key, PROP_KEY_STRING); - - vt_value.integer = offset; - parse_put_property (vt_value, PROP_INTEGER); - - parse_pop_key (); - - /* Rewrite length if changed. */ - if (real_length != length) - { - vt_key.string = "GraphicLen"; - parse_push_key (vt_key, PROP_KEY_STRING); - - vt_value.integer = real_length; - parse_put_property (vt_value, PROP_INTEGER); - - parse_pop_key (); - } - } - } +parse_handle_v400_resources(sc_bool has_sound, sc_bool has_graphics) { + sc_vartype_t vt_key, vt_value; + const sc_char *file; + sc_int length, offset; + + /* + * Retrieve the file and length for the sound just parsed. If there's a + * file of non-zero length, rewrite its offset. + */ + if (has_sound) { + /* Retrieve the file and length information. */ + vt_key.string = "SoundFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + file = parse_get_string_property(); + parse_pop_key(); + + vt_key.string = "SoundLen"; + parse_push_key(vt_key, PROP_KEY_STRING); + length = parse_get_integer_property(); + parse_pop_key(); + + /* + * If defined and has a length, rewrite the offset, and also the length + * in case changed. + */ + if (!sc_strempty(file) && length != 0) { + sc_int real_length; + + offset = parse_get_v400_resource_offset(file, length, &real_length); + vt_key.string = "SoundOffset"; + parse_push_key(vt_key, PROP_KEY_STRING); + + vt_value.integer = offset; + parse_put_property(vt_value, PROP_INTEGER); + + parse_pop_key(); + + /* Rewrite length if changed. */ + if (real_length != length) { + vt_key.string = "SoundLen"; + parse_push_key(vt_key, PROP_KEY_STRING); + + vt_value.integer = real_length; + parse_put_property(vt_value, PROP_INTEGER); + + parse_pop_key(); + } + } + } + + /* Now do the same thing for graphics. */ + if (has_graphics) { + /* Retrieve the file and length information. */ + vt_key.string = "GraphicFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + file = parse_get_string_property(); + parse_pop_key(); + + vt_key.string = "GraphicLen"; + parse_push_key(vt_key, PROP_KEY_STRING); + length = parse_get_integer_property(); + parse_pop_key(); + + /* + * If defined and has a length, rewrite the offset, and also the length + * in case changed. + */ + if (!sc_strempty(file) && length != 0) { + sc_int real_length; + + offset = parse_get_v400_resource_offset(file, length, &real_length); + vt_key.string = "GraphicOffset"; + parse_push_key(vt_key, PROP_KEY_STRING); + + vt_value.integer = offset; + parse_put_property(vt_value, PROP_INTEGER); + + parse_pop_key(); + + /* Rewrite length if changed. */ + if (real_length != length) { + vt_key.string = "GraphicLen"; + parse_push_key(vt_key, PROP_KEY_STRING); + + vt_value.integer = real_length; + parse_put_property(vt_value, PROP_INTEGER); + + parse_pop_key(); + } + } + } } @@ -1329,238 +1392,222 @@ parse_handle_v400_resources (sc_bool has_sound, sc_bool has_graphics) * therefore need careful treatment. */ static void -parse_special (const sc_char *special) -{ - if (parse_trace) - sc_trace ("Parse: entering special %s\n", special); - - /* Special handling for version 4.0 resources. */ - if (strcmp (special, "{V400_RESOURCE}") == 0) - { - sc_vartype_t vt_key[2]; - sc_bool has_sound, has_graphics; - - /* Get sound and graphics global flags. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "Sound"; - has_sound = prop_get_boolean (parse_bundle, "B<-ss", vt_key); - - vt_key[1].string = "Graphics"; - has_graphics = prop_get_boolean (parse_bundle, "B<-ss", vt_key); - - /* Apply special handling to the resources. */ - parse_handle_v400_resources (has_sound, has_graphics); - } - - /* Parse a version 4.0 optional set of room exit information. */ - else if (strcmp (special, "{V400_ROOM_EXIT:#Dest_#Var1_#Var2_#Var3}") == 0) - { - sc_int flag; - - /* Get next flag, and if true, pushback and parse. */ - flag = parse_get_taf_integer (); - if (flag != 0) - { - parse_taf_pushback (); - parse_descriptor ("#Dest #Var1 #Var2 #Var3"); - } - } - - /* Parse version 3.9 and version 3.8 optional room exit information. */ - else if (strcmp (special, - "{V390_V380_ROOM_EXIT:#Dest_#Var1_#Var2_ZVar3}") == 0) - { - sc_int flag; - - /* Get next flag, and if true, pushback and parse. */ - flag = parse_get_taf_integer (); - if (flag != 0) - { - parse_taf_pushback (); - parse_descriptor ("#Dest #Var1 #Var2 ZVar3"); - } - } - - /* Parse room lists, with optional extra room. */ - else if (strcmp (special, "{ROOM_LIST0}") == 0 - || strcmp (special, "{ROOM_LIST1}") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int room_count, num_rooms, type, index_; - - /* Retrieve the room list type. */ - vt_key.string = "Type"; - parse_push_key (vt_key, PROP_KEY_STRING); - type = parse_get_integer_property (); - parse_pop_key (); - - /* Write remaining room list depending on the type. */ - switch (type) - { - case ROOMLIST_NO_ROOMS: - case ROOMLIST_ALL_ROOMS: - case ROOMLIST_NPC_PART: - break; - - case ROOMLIST_ONE_ROOM: - /* Store this room as the single list entry. */ - parse_element ("#Room"); - break; - - case ROOMLIST_SOME_ROOMS: - /* Get count of rooms defined, add one if necessary. */ - vt_key.string = "Rooms"; - room_count = prop_get_child_count (parse_bundle, "I<-s", &vt_key); - - if (strcmp (special, "{ROOM_LIST1}") == 0) - num_rooms = room_count + 1; - else - num_rooms = room_count; - - /* Store an array of rooms flags for each room. */ - vt_key.string = "Rooms"; - parse_push_key (vt_key, PROP_KEY_STRING); - for (index_ = 0; index_ < num_rooms; index_++) - { - sc_bool this_room; - - /* Get flag for this room. */ - this_room = parse_get_taf_boolean (); - - /* Store flag directly. */ - vt_key.integer = index_; - parse_push_key (vt_key, PROP_KEY_INTEGER); - vt_value.boolean = this_room; - parse_put_property (vt_value, PROP_BOOLEAN); - parse_pop_key (); - } - parse_pop_key (); - break; - - default: - sc_fatal ("parse_special: bad type, %ld\n", type); - } - } - - /* Parse Parent number iff this object is an NPC part. */ - else if (strcmp (special, "{OBJECT:#Parent}") == 0) - { - sc_vartype_t vt_key; - sc_int type; - - /* Check object's Where room list Type for NPC part. */ - vt_key.string = "Where"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_key.string = "Type"; - parse_push_key (vt_key, PROP_KEY_STRING); - type = parse_get_integer_property (); - parse_pop_key (); - parse_pop_key (); - - /* Get Parent if the object is part of an NPC. */ - if (type == ROOMLIST_NPC_PART) - parse_element ("#Parent"); - } - - /* Parse a list of rooms and times for a walk. */ - else if (strcmp (special, "{WALK:#Rooms_#Times}") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int num_stops, index_; - - /* Obtain the count of stops in this walk. */ - vt_key.string = "NumStops"; - parse_push_key (vt_key, PROP_KEY_STRING); - num_stops = parse_get_integer_property (); - parse_pop_key (); - - /* Look for a room and time for each stop. */ - for (index_ = 0; index_ < num_stops; index_++) - { - sc_int room, time; - - /* Parse and store Rooms[index_]. */ - vt_key.string = "Rooms"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_key.integer = index_; - parse_push_key (vt_key, PROP_KEY_INTEGER); - - room = parse_get_taf_integer (); - - vt_value.integer = room; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - parse_pop_key (); - - /* Parse and store Times[index_]. */ - vt_key.string = "Times"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_key.integer = index_; - parse_push_key (vt_key, PROP_KEY_INTEGER); - - time = parse_get_taf_integer (); - - vt_value.integer = time; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - parse_pop_key (); - } - } - - /* Parse a room group variable size boolean list. */ - else if (strcmp (special, "{ROOM_GROUP:[]BList}") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int num_rooms, index_, l2index_; - sc_bool in_group; - - /* Get the count of rooms defined. */ - vt_key.string = "Rooms"; - num_rooms = prop_get_integer (parse_bundle, "I<-s", &vt_key); - - /* Read a boolean for each room. */ - l2index_ = 0; - for (index_ = 0; index_ < num_rooms; index_++) - { - in_group = parse_get_taf_boolean (); - - /* Store raw flag as List[index_]. */ - vt_key.string = "List"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_key.integer = index_; - parse_push_key (vt_key, PROP_KEY_INTEGER); - vt_value.boolean = in_group; - parse_put_property (vt_value, PROP_BOOLEAN); - - parse_pop_key (); - parse_pop_key (); - - /* Store in-group index'es as List2[0..n]. */ - if (in_group) - { - vt_key.string = "List2"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_key.integer = l2index_; - parse_push_key (vt_key, PROP_KEY_INTEGER); - vt_value.integer = index_; - parse_put_property (vt_value, PROP_INTEGER); - - parse_pop_key (); - parse_pop_key (); - - l2index_++; - } - } - } - - /* Error if no special handler available. */ - else - { - sc_fatal ("parse_special: no handler for \"%s\"\n", special); - } - - if (parse_trace) - sc_trace ("Parse: leaving special %s\n", special); +parse_special(const sc_char *special) { + if (parse_trace) + sc_trace("Parse: entering special %s\n", special); + + /* Special handling for version 4.0 resources. */ + if (strcmp(special, "{V400_RESOURCE}") == 0) { + sc_vartype_t vt_key[2]; + sc_bool has_sound, has_graphics; + + /* Get sound and graphics global flags. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "Sound"; + has_sound = prop_get_boolean(parse_bundle, "B<-ss", vt_key); + + vt_key[1].string = "Graphics"; + has_graphics = prop_get_boolean(parse_bundle, "B<-ss", vt_key); + + /* Apply special handling to the resources. */ + parse_handle_v400_resources(has_sound, has_graphics); + } + + /* Parse a version 4.0 optional set of room exit information. */ + else if (strcmp(special, "{V400_ROOM_EXIT:#Dest_#Var1_#Var2_#Var3}") == 0) { + sc_int flag; + + /* Get next flag, and if true, pushback and parse. */ + flag = parse_get_taf_integer(); + if (flag != 0) { + parse_taf_pushback(); + parse_descriptor("#Dest #Var1 #Var2 #Var3"); + } + } + + /* Parse version 3.9 and version 3.8 optional room exit information. */ + else if (strcmp(special, + "{V390_V380_ROOM_EXIT:#Dest_#Var1_#Var2_ZVar3}") == 0) { + sc_int flag; + + /* Get next flag, and if true, pushback and parse. */ + flag = parse_get_taf_integer(); + if (flag != 0) { + parse_taf_pushback(); + parse_descriptor("#Dest #Var1 #Var2 ZVar3"); + } + } + + /* Parse room lists, with optional extra room. */ + else if (strcmp(special, "{ROOM_LIST0}") == 0 + || strcmp(special, "{ROOM_LIST1}") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int room_count, num_rooms, type, index_; + + /* Retrieve the room list type. */ + vt_key.string = "Type"; + parse_push_key(vt_key, PROP_KEY_STRING); + type = parse_get_integer_property(); + parse_pop_key(); + + /* Write remaining room list depending on the type. */ + switch (type) { + case ROOMLIST_NO_ROOMS: + case ROOMLIST_ALL_ROOMS: + case ROOMLIST_NPC_PART: + break; + + case ROOMLIST_ONE_ROOM: + /* Store this room as the single list entry. */ + parse_element("#Room"); + break; + + case ROOMLIST_SOME_ROOMS: + /* Get count of rooms defined, add one if necessary. */ + vt_key.string = "Rooms"; + room_count = prop_get_child_count(parse_bundle, "I<-s", &vt_key); + + if (strcmp(special, "{ROOM_LIST1}") == 0) + num_rooms = room_count + 1; + else + num_rooms = room_count; + + /* Store an array of rooms flags for each room. */ + vt_key.string = "Rooms"; + parse_push_key(vt_key, PROP_KEY_STRING); + for (index_ = 0; index_ < num_rooms; index_++) { + sc_bool this_room; + + /* Get flag for this room. */ + this_room = parse_get_taf_boolean(); + + /* Store flag directly. */ + vt_key.integer = index_; + parse_push_key(vt_key, PROP_KEY_INTEGER); + vt_value.boolean = this_room; + parse_put_property(vt_value, PROP_BOOLEAN); + parse_pop_key(); + } + parse_pop_key(); + break; + + default: + sc_fatal("parse_special: bad type, %ld\n", type); + } + } + + /* Parse Parent number iff this object is an NPC part. */ + else if (strcmp(special, "{OBJECT:#Parent}") == 0) { + sc_vartype_t vt_key; + sc_int type; + + /* Check object's Where room list Type for NPC part. */ + vt_key.string = "Where"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_key.string = "Type"; + parse_push_key(vt_key, PROP_KEY_STRING); + type = parse_get_integer_property(); + parse_pop_key(); + parse_pop_key(); + + /* Get Parent if the object is part of an NPC. */ + if (type == ROOMLIST_NPC_PART) + parse_element("#Parent"); + } + + /* Parse a list of rooms and times for a walk. */ + else if (strcmp(special, "{WALK:#Rooms_#Times}") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int num_stops, index_; + + /* Obtain the count of stops in this walk. */ + vt_key.string = "NumStops"; + parse_push_key(vt_key, PROP_KEY_STRING); + num_stops = parse_get_integer_property(); + parse_pop_key(); + + /* Look for a room and time for each stop. */ + for (index_ = 0; index_ < num_stops; index_++) { + sc_int room, time; + + /* Parse and store Rooms[index_]. */ + vt_key.string = "Rooms"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_key.integer = index_; + parse_push_key(vt_key, PROP_KEY_INTEGER); + + room = parse_get_taf_integer(); + + vt_value.integer = room; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + parse_pop_key(); + + /* Parse and store Times[index_]. */ + vt_key.string = "Times"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_key.integer = index_; + parse_push_key(vt_key, PROP_KEY_INTEGER); + + time = parse_get_taf_integer(); + + vt_value.integer = time; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + parse_pop_key(); + } + } + + /* Parse a room group variable size boolean list. */ + else if (strcmp(special, "{ROOM_GROUP:[]BList}") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int num_rooms, index_, l2index_; + sc_bool in_group; + + /* Get the count of rooms defined. */ + vt_key.string = "Rooms"; + num_rooms = prop_get_integer(parse_bundle, "I<-s", &vt_key); + + /* Read a boolean for each room. */ + l2index_ = 0; + for (index_ = 0; index_ < num_rooms; index_++) { + in_group = parse_get_taf_boolean(); + + /* Store raw flag as List[index_]. */ + vt_key.string = "List"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_key.integer = index_; + parse_push_key(vt_key, PROP_KEY_INTEGER); + vt_value.boolean = in_group; + parse_put_property(vt_value, PROP_BOOLEAN); + + parse_pop_key(); + parse_pop_key(); + + /* Store in-group index'es as List2[0..n]. */ + if (in_group) { + vt_key.string = "List2"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_key.integer = l2index_; + parse_push_key(vt_key, PROP_KEY_INTEGER); + vt_value.integer = index_; + parse_put_property(vt_value, PROP_INTEGER); + + parse_pop_key(); + parse_pop_key(); + + l2index_++; + } + } + } + + /* Error if no special handler available. */ + else { + sc_fatal("parse_special: no handler for \"%s\"\n", special); + } + + if (parse_trace) + sc_trace("Parse: leaving special %s\n", special); } @@ -1571,219 +1618,205 @@ parse_special (const sc_char *special) * version 4.0 room alts for version 3.9 and version 3.8 games. */ static void -parse_fixup_v390_v380_room_alt (const sc_char *m1, sc_int type, - const sc_char *resource1, - const sc_char *m2, sc_int var2, - const sc_char *resource2, - sc_int hide_objects, - const sc_char *changed, - sc_int var3, sc_int display_room) -{ - sc_vartype_t vt_key, vt_value, vt_gkey[2]; - sc_bool has_sound, has_graphics; - sc_int alt_count; - const sc_char *soundfile1, *graphicfile1; - const sc_char *soundfile2, *graphicfile2; - - /* - * Initialize resource files to empty, for cases where no resource is copied - * over from the main room (NULL resource1/2). - */ - soundfile1 = ""; - graphicfile1 = ""; - soundfile2 = ""; - graphicfile2 = ""; - - /* Get sound and graphics flags, always FALSE for version 3.8. */ - vt_gkey[0].string = "Globals"; - vt_gkey[1].string = "Sound"; - has_sound = prop_get_boolean (parse_bundle, "B<-ss", vt_gkey); - - vt_gkey[1].string = "Graphics"; - has_graphics = prop_get_boolean (parse_bundle, "B<-ss", vt_gkey); - - /* Get a count of alts so far defined for the room. */ - vt_key.string = "Alts"; - parse_push_key (vt_key, PROP_KEY_STRING); - alt_count = parse_get_child_count (); - parse_pop_key (); - - /* - * Lookup any resource details now, and save them. Because this is not - * version 4.0, we can ignore lengths, and set them to zero when needed. - */ - if (has_sound || has_graphics) - { - if (resource1) - { - vt_key.string = resource1; - parse_push_key (vt_key, PROP_KEY_STRING); - if (has_sound) - { - vt_key.string = "SoundFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - soundfile1 = parse_get_string_property (); - parse_pop_key (); - } - if (has_graphics) - { - vt_key.string = "GraphicFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - graphicfile1 = parse_get_string_property (); - parse_pop_key (); - } - parse_pop_key (); - } - - if (resource2) - { - vt_key.string = resource2; - parse_push_key (vt_key, PROP_KEY_STRING); - if (has_sound) - { - vt_key.string = "SoundFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - soundfile2 = parse_get_string_property (); - parse_pop_key (); - } - if (has_graphics) - { - vt_key.string = "GraphicFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - graphicfile2 = parse_get_string_property (); - parse_pop_key (); - } - parse_pop_key (); - } - } - - /* - * Create a room alt to match data passed in. Start with the Alts string - * and the index to the alt being written. To correctly emulate the parse, - * we also have to reverse the "Alts" and the index, as parse_put_property() - * will swap them. Madness. - */ - vt_key.integer = alt_count; - parse_push_key (vt_key, PROP_KEY_INTEGER); - vt_key.string = "Alts"; - parse_push_key (vt_key, PROP_KEY_STRING); - - /* Write M1 and Type. */ - vt_key.string = "M1"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = m1; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - vt_key.string = "Type"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = type; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - - /* If resources, add these as retrieved above. */ - if (has_sound || has_graphics) - { - vt_key.string = "Res1"; - parse_push_key (vt_key, PROP_KEY_STRING); - if (has_sound) - { - vt_key.string = "SoundFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = soundfile1; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - vt_key.string = "SoundLen"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = 0; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - if (has_graphics) - { - vt_key.string = "GraphicFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = graphicfile1; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - vt_key.string = "GraphicLen"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = 0; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - parse_pop_key (); - } - - /* Write M2 and Var2. */ - vt_key.string = "M2"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = m2; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - vt_key.string = "Var2"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = var2; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - - /* If resources, again add these as retrieved above. */ - if (has_sound || has_graphics) - { - vt_key.string = "Res2"; - parse_push_key (vt_key, PROP_KEY_STRING); - if (has_sound) - { - vt_key.string = "SoundFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = soundfile2; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - vt_key.string = "SoundLen"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = 0; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - if (has_graphics) - { - vt_key.string = "GraphicFile"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = graphicfile2; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - vt_key.string = "GraphicLen"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = 0; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - parse_pop_key (); - } - - /* Finish off with the last four alt properties. */ - vt_key.string = "HideObjects"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = hide_objects; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - vt_key.string = "Changed"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = changed; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - vt_key.string = "Var3"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = var3; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - vt_key.string = "DisplayRoom"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = display_room; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - - parse_pop_key (); - parse_pop_key (); +parse_fixup_v390_v380_room_alt(const sc_char *m1, sc_int type, + const sc_char *resource1, + const sc_char *m2, sc_int var2, + const sc_char *resource2, + sc_int hide_objects, + const sc_char *changed, + sc_int var3, sc_int display_room) { + sc_vartype_t vt_key, vt_value, vt_gkey[2]; + sc_bool has_sound, has_graphics; + sc_int alt_count; + const sc_char *soundfile1, *graphicfile1; + const sc_char *soundfile2, *graphicfile2; + + /* + * Initialize resource files to empty, for cases where no resource is copied + * over from the main room (NULL resource1/2). + */ + soundfile1 = ""; + graphicfile1 = ""; + soundfile2 = ""; + graphicfile2 = ""; + + /* Get sound and graphics flags, always FALSE for version 3.8. */ + vt_gkey[0].string = "Globals"; + vt_gkey[1].string = "Sound"; + has_sound = prop_get_boolean(parse_bundle, "B<-ss", vt_gkey); + + vt_gkey[1].string = "Graphics"; + has_graphics = prop_get_boolean(parse_bundle, "B<-ss", vt_gkey); + + /* Get a count of alts so far defined for the room. */ + vt_key.string = "Alts"; + parse_push_key(vt_key, PROP_KEY_STRING); + alt_count = parse_get_child_count(); + parse_pop_key(); + + /* + * Lookup any resource details now, and save them. Because this is not + * version 4.0, we can ignore lengths, and set them to zero when needed. + */ + if (has_sound || has_graphics) { + if (resource1) { + vt_key.string = resource1; + parse_push_key(vt_key, PROP_KEY_STRING); + if (has_sound) { + vt_key.string = "SoundFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + soundfile1 = parse_get_string_property(); + parse_pop_key(); + } + if (has_graphics) { + vt_key.string = "GraphicFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + graphicfile1 = parse_get_string_property(); + parse_pop_key(); + } + parse_pop_key(); + } + + if (resource2) { + vt_key.string = resource2; + parse_push_key(vt_key, PROP_KEY_STRING); + if (has_sound) { + vt_key.string = "SoundFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + soundfile2 = parse_get_string_property(); + parse_pop_key(); + } + if (has_graphics) { + vt_key.string = "GraphicFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + graphicfile2 = parse_get_string_property(); + parse_pop_key(); + } + parse_pop_key(); + } + } + + /* + * Create a room alt to match data passed in. Start with the Alts string + * and the index to the alt being written. To correctly emulate the parse, + * we also have to reverse the "Alts" and the index, as parse_put_property() + * will swap them. Madness. + */ + vt_key.integer = alt_count; + parse_push_key(vt_key, PROP_KEY_INTEGER); + vt_key.string = "Alts"; + parse_push_key(vt_key, PROP_KEY_STRING); + + /* Write M1 and Type. */ + vt_key.string = "M1"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = m1; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + vt_key.string = "Type"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = type; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + + /* If resources, add these as retrieved above. */ + if (has_sound || has_graphics) { + vt_key.string = "Res1"; + parse_push_key(vt_key, PROP_KEY_STRING); + if (has_sound) { + vt_key.string = "SoundFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = soundfile1; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + vt_key.string = "SoundLen"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = 0; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + if (has_graphics) { + vt_key.string = "GraphicFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = graphicfile1; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + vt_key.string = "GraphicLen"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = 0; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + parse_pop_key(); + } + + /* Write M2 and Var2. */ + vt_key.string = "M2"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = m2; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + vt_key.string = "Var2"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = var2; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + + /* If resources, again add these as retrieved above. */ + if (has_sound || has_graphics) { + vt_key.string = "Res2"; + parse_push_key(vt_key, PROP_KEY_STRING); + if (has_sound) { + vt_key.string = "SoundFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = soundfile2; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + vt_key.string = "SoundLen"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = 0; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + if (has_graphics) { + vt_key.string = "GraphicFile"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = graphicfile2; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + vt_key.string = "GraphicLen"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = 0; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + parse_pop_key(); + } + + /* Finish off with the last four alt properties. */ + vt_key.string = "HideObjects"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = hide_objects; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + vt_key.string = "Changed"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = changed; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + vt_key.string = "Var3"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = var3; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + vt_key.string = "DisplayRoom"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = display_room; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + + parse_pop_key(); + parse_pop_key(); } @@ -1798,127 +1831,122 @@ enum { V390_V380_ALT_TYPEHIDE_MULT = 10 }; * an equivalent array of version 4.0 style room alts. */ static void -parse_fixup_v390_v380_room_alts (void) -{ - sc_vartype_t vt_key; - const sc_char *m1, *m2, *changed; - sc_int type, var2, hide_objects, var3, display_room; - - /* Room alt invariants. */ - m2 = ""; /* No else text */ - changed = ""; /* No changed room name */ - - /* - * Create a room alt to override all others, controlled by an object - * condition and with optional object hiding. - */ - type = 2; /* Object condition */ - display_room = 0; /* Override all others */ - - vt_key.string = "Obj"; - parse_push_key (vt_key, PROP_KEY_STRING); - var3 = parse_get_integer_property (); - parse_pop_key (); - - if (var3 > 0) - { - sc_int typehideobjects; - - vt_key.string = "AltDesc"; - parse_push_key (vt_key, PROP_KEY_STRING); - m1 = parse_get_string_property (); - parse_pop_key (); - - vt_key.string = "TypeHideObjects"; - parse_push_key (vt_key, PROP_KEY_STRING); - typehideobjects = parse_get_integer_property (); - parse_pop_key (); - - var2 = typehideobjects / V390_V380_ALT_TYPEHIDE_MULT; - hide_objects = typehideobjects % V390_V380_ALT_TYPEHIDE_MULT; - - parse_fixup_v390_v380_room_alt (m1, type, "AltRes", - m2, var2, NULL, - hide_objects, changed, var3, - display_room); - } - - /* - * If a second task alternate description is defined, create a room alt to - * add after the main description, one that stops printing once done. - */ - type = 0; /* Task condition */ - display_room = 1; /* Print after main and stop */ - - vt_key.string = "Task2"; - parse_push_key (vt_key, PROP_KEY_STRING); - var2 = parse_get_integer_property (); - parse_pop_key (); - - if (var2 > 0) - { - vt_key.string = "AddDesc2"; - parse_push_key (vt_key, PROP_KEY_STRING); - m1 = parse_get_string_property (); - parse_pop_key (); - - var3 = 0; - hide_objects = 0; - - parse_fixup_v390_v380_room_alt (m1, type, "Task2Res", - m2, var2, NULL, - hide_objects, changed, var3, - display_room); - } - - /* Do the same for any first task additional description. */ - type = 0; /* Task condition */ - display_room = 1; /* Print after main and stop */ - - vt_key.string = "Task1"; - parse_push_key (vt_key, PROP_KEY_STRING); - var2 = parse_get_integer_property (); - parse_pop_key (); - - if (var2 > 0) - { - vt_key.string = "AddDesc1"; - parse_push_key (vt_key, PROP_KEY_STRING); - m1 = parse_get_string_property (); - parse_pop_key (); - - var3 = 0; - hide_objects = 0; - - parse_fixup_v390_v380_room_alt (m1, type, "Task1Res", - m2, var2, NULL, - hide_objects, changed, var3, - display_room); - } - - /* - * If still printing at this point, we need a catch-all room alt that will - * print. So create one with an always true condition. - */ - type = 0; /* Task condition */ - display_room = 2; /* Lowest priority output */ - - vt_key.string = "LastDesc"; - parse_push_key (vt_key, PROP_KEY_STRING); - m1 = parse_get_string_property (); - parse_pop_key (); - - if (!sc_strempty (m1)) - { - var2 = 0; /* No task - always TRUE */ - var3 = 0; - hide_objects = 0; - - parse_fixup_v390_v380_room_alt (m1, type, "LastRes", - m2, var2, NULL, - hide_objects, changed, var3, - display_room); - } +parse_fixup_v390_v380_room_alts(void) { + sc_vartype_t vt_key; + const sc_char *m1, *m2, *changed; + sc_int type, var2, hide_objects, var3, display_room; + + /* Room alt invariants. */ + m2 = ""; /* No else text */ + changed = ""; /* No changed room name */ + + /* + * Create a room alt to override all others, controlled by an object + * condition and with optional object hiding. + */ + type = 2; /* Object condition */ + display_room = 0; /* Override all others */ + + vt_key.string = "Obj"; + parse_push_key(vt_key, PROP_KEY_STRING); + var3 = parse_get_integer_property(); + parse_pop_key(); + + if (var3 > 0) { + sc_int typehideobjects; + + vt_key.string = "AltDesc"; + parse_push_key(vt_key, PROP_KEY_STRING); + m1 = parse_get_string_property(); + parse_pop_key(); + + vt_key.string = "TypeHideObjects"; + parse_push_key(vt_key, PROP_KEY_STRING); + typehideobjects = parse_get_integer_property(); + parse_pop_key(); + + var2 = typehideobjects / V390_V380_ALT_TYPEHIDE_MULT; + hide_objects = typehideobjects % V390_V380_ALT_TYPEHIDE_MULT; + + parse_fixup_v390_v380_room_alt(m1, type, "AltRes", + m2, var2, NULL, + hide_objects, changed, var3, + display_room); + } + + /* + * If a second task alternate description is defined, create a room alt to + * add after the main description, one that stops printing once done. + */ + type = 0; /* Task condition */ + display_room = 1; /* Print after main and stop */ + + vt_key.string = "Task2"; + parse_push_key(vt_key, PROP_KEY_STRING); + var2 = parse_get_integer_property(); + parse_pop_key(); + + if (var2 > 0) { + vt_key.string = "AddDesc2"; + parse_push_key(vt_key, PROP_KEY_STRING); + m1 = parse_get_string_property(); + parse_pop_key(); + + var3 = 0; + hide_objects = 0; + + parse_fixup_v390_v380_room_alt(m1, type, "Task2Res", + m2, var2, NULL, + hide_objects, changed, var3, + display_room); + } + + /* Do the same for any first task additional description. */ + type = 0; /* Task condition */ + display_room = 1; /* Print after main and stop */ + + vt_key.string = "Task1"; + parse_push_key(vt_key, PROP_KEY_STRING); + var2 = parse_get_integer_property(); + parse_pop_key(); + + if (var2 > 0) { + vt_key.string = "AddDesc1"; + parse_push_key(vt_key, PROP_KEY_STRING); + m1 = parse_get_string_property(); + parse_pop_key(); + + var3 = 0; + hide_objects = 0; + + parse_fixup_v390_v380_room_alt(m1, type, "Task1Res", + m2, var2, NULL, + hide_objects, changed, var3, + display_room); + } + + /* + * If still printing at this point, we need a catch-all room alt that will + * print. So create one with an always true condition. + */ + type = 0; /* Task condition */ + display_room = 2; /* Lowest priority output */ + + vt_key.string = "LastDesc"; + parse_push_key(vt_key, PROP_KEY_STRING); + m1 = parse_get_string_property(); + parse_pop_key(); + + if (!sc_strempty(m1)) { + var2 = 0; /* No task - always TRUE */ + var3 = 0; + hide_objects = 0; + + parse_fixup_v390_v380_room_alt(m1, type, "LastRes", + m2, var2, NULL, + hide_objects, changed, var3, + display_room); + } } @@ -1929,151 +1957,138 @@ parse_fixup_v390_v380_room_alts (void) * 3.9 format into version 4.0. */ static void -parse_fixup_v390 (const sc_char *fixup) -{ - if (parse_trace) - sc_trace ("Parse: entering version 3.9 fixup %s\n", fixup); - - /* Fixup a version 3.9 task action by incrementing Type > 4. */ - if (strcmp (fixup, "|V390_TASK_ACTION:Type>4?#Type++|") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int type; - - /* Retrieve Type, and if > 4, increment. */ - vt_key.string = "Type"; - parse_push_key (vt_key, PROP_KEY_STRING); - type = parse_get_integer_property (); - - if (type > 4) - { - vt_value.integer = type + 1; - parse_put_property (vt_value, PROP_INTEGER); - } - - parse_pop_key (); - } - - /* Handle either Expr or Var5 for version 3.9 task actions. */ - else if (strcmp (fixup, "|V390_TASK_ACTION:$Expr_#Var5|") == 0) - { - sc_vartype_t vt_key; - sc_int var2; - - /* Either Expr or Var5, depending on Var2. */ - vt_key.string = "Var2"; - parse_push_key (vt_key, PROP_KEY_STRING); - var2 = parse_get_integer_property (); - parse_pop_key (); - - if (var2 == 5) - parse_descriptor ("$Expr ZVar5"); - else - parse_descriptor ("EExpr #Var5"); - } - - /* - * Exchange openable values 5 and 6, and write -1 key for openable objects. - */ - else if (strcmp (fixup, "|V390_OBJECT:_Openable_,Key|") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int openable; - - /* Retrieve Openable, and if 5 or 6, exchange. */ - vt_key.string = "Openable"; - parse_push_key (vt_key, PROP_KEY_STRING); - openable = parse_get_integer_property (); - - if (openable == 5 || openable == 6) - { - vt_value.integer = (openable == 5) ? 6 : 5; - parse_put_property (vt_value, PROP_INTEGER); - } - - parse_pop_key (); - - /* For openable objects, store a Key of -1. */ - if (openable == 5 || openable == 6) - { - vt_key.string = "Key"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = -1; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - } - - /* Create a RestrMask that 'and's all the restrictions together. */ - else if (strcmp (fixup, "|V390_TASK:$RestrMask|") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int restriction_count; - - /* Get a count of restrictions. */ - vt_key.string = "Restrictions"; - parse_push_key (vt_key, PROP_KEY_STRING); - restriction_count = parse_get_child_count (); - parse_pop_key (); - - /* Allocate and fill a new mask for these restrictions. */ - if (restriction_count > 0) - { - sc_char *restrmask; - sc_int index_; - - restrmask = (sc_char *)sc_malloc (2 * restriction_count); - strcpy (restrmask, "#"); - for (index_ = 1; index_ < restriction_count; index_++) - strcat (restrmask, "A#"); - - vt_key.string = "RestrMask"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = restrmask; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - - prop_adopt (parse_bundle, restrmask); - } - } - - /* - * Increment var1 for variable restrictions to compensate for there being no - * referenced text comparison (no string variables). - */ - else if (strcmp (fixup, "|V390_TASK_RESTR:Var1>0?#Var1++|") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int var1; - - /* Retrieve Var1, and if greater than zero, increment. */ - vt_key.string = "Var1"; - parse_push_key (vt_key, PROP_KEY_STRING); - var1 = parse_get_integer_property (); - - if (var1 > 0) - { - vt_value.integer = var1 + 1; - parse_put_property (vt_value, PROP_INTEGER); - } - - parse_pop_key (); - } - - /* Convert version 3.9 fixed alts into a version 4.0 array. */ - else if (strcmp (fixup, "|V390_ROOM:_Alts_|") == 0) - { - parse_fixup_v390_v380_room_alts (); - } - - /* Error if no fixup special handler available. */ - else - { - sc_fatal ("parse_fixup_v390: no handler for \"%s\"\n", fixup); - } - - if (parse_trace) - sc_trace ("Parse: leaving version 3.9 fixup %s\n", fixup); +parse_fixup_v390(const sc_char *fixup) { + if (parse_trace) + sc_trace("Parse: entering version 3.9 fixup %s\n", fixup); + + /* Fixup a version 3.9 task action by incrementing Type > 4. */ + if (strcmp(fixup, "|V390_TASK_ACTION:Type>4?#Type++|") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int type; + + /* Retrieve Type, and if > 4, increment. */ + vt_key.string = "Type"; + parse_push_key(vt_key, PROP_KEY_STRING); + type = parse_get_integer_property(); + + if (type > 4) { + vt_value.integer = type + 1; + parse_put_property(vt_value, PROP_INTEGER); + } + + parse_pop_key(); + } + + /* Handle either Expr or Var5 for version 3.9 task actions. */ + else if (strcmp(fixup, "|V390_TASK_ACTION:$Expr_#Var5|") == 0) { + sc_vartype_t vt_key; + sc_int var2; + + /* Either Expr or Var5, depending on Var2. */ + vt_key.string = "Var2"; + parse_push_key(vt_key, PROP_KEY_STRING); + var2 = parse_get_integer_property(); + parse_pop_key(); + + if (var2 == 5) + parse_descriptor("$Expr ZVar5"); + else + parse_descriptor("EExpr #Var5"); + } + + /* + * Exchange openable values 5 and 6, and write -1 key for openable objects. + */ + else if (strcmp(fixup, "|V390_OBJECT:_Openable_,Key|") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int openable; + + /* Retrieve Openable, and if 5 or 6, exchange. */ + vt_key.string = "Openable"; + parse_push_key(vt_key, PROP_KEY_STRING); + openable = parse_get_integer_property(); + + if (openable == 5 || openable == 6) { + vt_value.integer = (openable == 5) ? 6 : 5; + parse_put_property(vt_value, PROP_INTEGER); + } + + parse_pop_key(); + + /* For openable objects, store a Key of -1. */ + if (openable == 5 || openable == 6) { + vt_key.string = "Key"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = -1; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + } + + /* Create a RestrMask that 'and's all the restrictions together. */ + else if (strcmp(fixup, "|V390_TASK:$RestrMask|") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int restriction_count; + + /* Get a count of restrictions. */ + vt_key.string = "Restrictions"; + parse_push_key(vt_key, PROP_KEY_STRING); + restriction_count = parse_get_child_count(); + parse_pop_key(); + + /* Allocate and fill a new mask for these restrictions. */ + if (restriction_count > 0) { + sc_char *restrmask; + sc_int index_; + + restrmask = (sc_char *)sc_malloc(2 * restriction_count); + strcpy(restrmask, "#"); + for (index_ = 1; index_ < restriction_count; index_++) + strcat(restrmask, "A#"); + + vt_key.string = "RestrMask"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = restrmask; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + + prop_adopt(parse_bundle, restrmask); + } + } + + /* + * Increment var1 for variable restrictions to compensate for there being no + * referenced text comparison (no string variables). + */ + else if (strcmp(fixup, "|V390_TASK_RESTR:Var1>0?#Var1++|") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int var1; + + /* Retrieve Var1, and if greater than zero, increment. */ + vt_key.string = "Var1"; + parse_push_key(vt_key, PROP_KEY_STRING); + var1 = parse_get_integer_property(); + + if (var1 > 0) { + vt_value.integer = var1 + 1; + parse_put_property(vt_value, PROP_INTEGER); + } + + parse_pop_key(); + } + + /* Convert version 3.9 fixed alts into a version 4.0 array. */ + else if (strcmp(fixup, "|V390_ROOM:_Alts_|") == 0) { + parse_fixup_v390_v380_room_alts(); + } + + /* Error if no fixup special handler available. */ + else { + sc_fatal("parse_fixup_v390: no handler for \"%s\"\n", fixup); + } + + if (parse_trace) + sc_trace("Parse: leaving version 3.9 fixup %s\n", fixup); } @@ -2092,57 +2107,54 @@ enum { V380_TASK_MOVEMENTS = 6 }; * Helper for parse_fixup_v380(), adds a task action. */ static void -parse_fixup_v380_action (sc_int type, sc_int var_count, - sc_int var1, sc_int var2, sc_int var3) -{ - sc_vartype_t vt_key, vt_value; - sc_int action_count; - - /* Get a count of actions so far defined for the task. */ - vt_key.string = "Actions"; - parse_push_key (vt_key, PROP_KEY_STRING); - action_count = parse_get_child_count (); - parse_pop_key (); - - /* Write actions key, reversed to emulate parse actions. */ - vt_key.integer = action_count; - parse_push_key (vt_key, PROP_KEY_INTEGER); - vt_key.string = "Actions"; - parse_push_key (vt_key, PROP_KEY_STRING); - - /* Write new action according to the given arguments. */ - vt_key.string = "Type"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = type; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - - vt_key.string = "Var1"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = var1; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - - if (var_count > 1) - { - vt_key.string = "Var2"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = var2; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - - if (var_count > 2) - { - vt_key.string = "Var3"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = var3; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - - parse_pop_key (); - parse_pop_key (); +parse_fixup_v380_action(sc_int type, sc_int var_count, + sc_int var1, sc_int var2, sc_int var3) { + sc_vartype_t vt_key, vt_value; + sc_int action_count; + + /* Get a count of actions so far defined for the task. */ + vt_key.string = "Actions"; + parse_push_key(vt_key, PROP_KEY_STRING); + action_count = parse_get_child_count(); + parse_pop_key(); + + /* Write actions key, reversed to emulate parse actions. */ + vt_key.integer = action_count; + parse_push_key(vt_key, PROP_KEY_INTEGER); + vt_key.string = "Actions"; + parse_push_key(vt_key, PROP_KEY_STRING); + + /* Write new action according to the given arguments. */ + vt_key.string = "Type"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = type; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + + vt_key.string = "Var1"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = var1; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + + if (var_count > 1) { + vt_key.string = "Var2"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = var2; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + + if (var_count > 2) { + vt_key.string = "Var3"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = var3; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + + parse_pop_key(); + parse_pop_key(); } @@ -2152,83 +2164,79 @@ parse_fixup_v380_action (sc_int type, sc_int var_count, * Helper for parse_fixup_v380(), converts a task movement into an action. */ static void -parse_fixup_v380_movement (sc_int mvar1, sc_int mvar2, sc_int mvar3) -{ - sc_int var1; - - /* If nothing was selected to move, ignore the call. */ - if (mvar1 == 0) - return; - - /* - * Accept only player moves into rooms. Other combinations, such as move - * player to worn by player, are unlikely. And move player to same room as - * player isn't useful. - */ - if (mvar1 == 1) - { - if (mvar3 == 0 && mvar2 >= 2) - parse_fixup_v380_action (1, 3, 0, 0, mvar2 - 2); - return; - } - - /* - * Convert movement var1 into action var1. Var1 is the dynamic object + 3, - * or 2 for referenced object, or 0 for all held. - */ - switch (mvar1) - { - case 2: - var1 = 2; - break; /* Referenced obj */ - case 3: - var1 = 0; - break; /* All held */ - default: - var1 = mvar1 - 1; - break; /* Dynamic obj */ - } - - /* Dissect the rest of the movement. */ - switch (mvar3) - { - case 0: /* To room */ - /* - * Convert movement var2 into action var2 and var3. Var2 is 0 for move - * to room, 6 for move to player room. Var3 is 0 for hidden, otherwise - * the room number plus one. - */ - if (mvar2 == 0) /* Hidden */ - parse_fixup_v380_action (0, 3, var1, 0, 0); - else if (mvar2 == 1) /* Player room */ - parse_fixup_v380_action (0, 3, var1, 6, 0); - else /* Specified room */ - parse_fixup_v380_action (0, 3, var1, 0, mvar2 - 1); - break; - - case 1: /* To inside */ - case 2: /* To onto */ - /* - * Convert movement var2 and var3 into action var3 and var2, a simple - * conversion, but check that var2 is not 'not selected' first. - */ - if (mvar2 > 0) - parse_fixup_v380_action (0, 3, var1, mvar3 + 1, mvar2 - 1); - break; - - case 3: /* To held by */ - case 4: /* To worn by */ - /* - * Convert movement var2 and var3 into action var3 and var2, in this - * case a simple conversion, since version 4.0 task actions are close - * here. - */ - parse_fixup_v380_action (0, 3, var1, mvar3 + 1, mvar2); - break; - - default: - sc_fatal ("parse_fixup_v380_movement: invalid mvar3, %ld\n", mvar3); - } +parse_fixup_v380_movement(sc_int mvar1, sc_int mvar2, sc_int mvar3) { + sc_int var1; + + /* If nothing was selected to move, ignore the call. */ + if (mvar1 == 0) + return; + + /* + * Accept only player moves into rooms. Other combinations, such as move + * player to worn by player, are unlikely. And move player to same room as + * player isn't useful. + */ + if (mvar1 == 1) { + if (mvar3 == 0 && mvar2 >= 2) + parse_fixup_v380_action(1, 3, 0, 0, mvar2 - 2); + return; + } + + /* + * Convert movement var1 into action var1. Var1 is the dynamic object + 3, + * or 2 for referenced object, or 0 for all held. + */ + switch (mvar1) { + case 2: + var1 = 2; + break; /* Referenced obj */ + case 3: + var1 = 0; + break; /* All held */ + default: + var1 = mvar1 - 1; + break; /* Dynamic obj */ + } + + /* Dissect the rest of the movement. */ + switch (mvar3) { + case 0: /* To room */ + /* + * Convert movement var2 into action var2 and var3. Var2 is 0 for move + * to room, 6 for move to player room. Var3 is 0 for hidden, otherwise + * the room number plus one. + */ + if (mvar2 == 0) /* Hidden */ + parse_fixup_v380_action(0, 3, var1, 0, 0); + else if (mvar2 == 1) /* Player room */ + parse_fixup_v380_action(0, 3, var1, 6, 0); + else /* Specified room */ + parse_fixup_v380_action(0, 3, var1, 0, mvar2 - 1); + break; + + case 1: /* To inside */ + case 2: /* To onto */ + /* + * Convert movement var2 and var3 into action var3 and var2, a simple + * conversion, but check that var2 is not 'not selected' first. + */ + if (mvar2 > 0) + parse_fixup_v380_action(0, 3, var1, mvar3 + 1, mvar2 - 1); + break; + + case 3: /* To held by */ + case 4: /* To worn by */ + /* + * Convert movement var2 and var3 into action var3 and var2, in this + * case a simple conversion, since version 4.0 task actions are close + * here. + */ + parse_fixup_v380_action(0, 3, var1, mvar3 + 1, mvar2); + break; + + default: + sc_fatal("parse_fixup_v380_movement: invalid mvar3, %ld\n", mvar3); + } } @@ -2238,64 +2246,61 @@ parse_fixup_v380_movement (sc_int mvar1, sc_int mvar2, sc_int mvar3) * Helper for parse_fixup_v380(), adds a task restriction. */ static void -parse_fixup_v380_restr (sc_int type, sc_int var_count, - sc_int var1, sc_int var2, sc_int var3, - const sc_char *failmessage) -{ - sc_vartype_t vt_key, vt_value; - sc_int restriction_count; - - /* Get a count of restrictions so far defined for the task. */ - vt_key.string = "Restrictions"; - parse_push_key (vt_key, PROP_KEY_STRING); - restriction_count = parse_get_child_count (); - parse_pop_key (); - - /* Write restrictions key, reversed to emulate parse actions. */ - vt_key.integer = restriction_count; - parse_push_key (vt_key, PROP_KEY_INTEGER); - vt_key.string = "Restrictions"; - parse_push_key (vt_key, PROP_KEY_STRING); - - /* Write new restriction according to the given arguments. */ - vt_key.string = "Type"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = type; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - - vt_key.string = "Var1"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = var1; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - - if (var_count > 1) - { - vt_key.string = "Var2"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = var2; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - - if (var_count > 2) - { - vt_key.string = "Var3"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = var3; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - - vt_key.string = "FailMessage"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = failmessage; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - - parse_pop_key (); - parse_pop_key (); +parse_fixup_v380_restr(sc_int type, sc_int var_count, + sc_int var1, sc_int var2, sc_int var3, + const sc_char *failmessage) { + sc_vartype_t vt_key, vt_value; + sc_int restriction_count; + + /* Get a count of restrictions so far defined for the task. */ + vt_key.string = "Restrictions"; + parse_push_key(vt_key, PROP_KEY_STRING); + restriction_count = parse_get_child_count(); + parse_pop_key(); + + /* Write restrictions key, reversed to emulate parse actions. */ + vt_key.integer = restriction_count; + parse_push_key(vt_key, PROP_KEY_INTEGER); + vt_key.string = "Restrictions"; + parse_push_key(vt_key, PROP_KEY_STRING); + + /* Write new restriction according to the given arguments. */ + vt_key.string = "Type"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = type; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + + vt_key.string = "Var1"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = var1; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + + if (var_count > 1) { + vt_key.string = "Var2"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = var2; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + + if (var_count > 2) { + vt_key.string = "Var3"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = var3; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + + vt_key.string = "FailMessage"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = failmessage; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + + parse_pop_key(); + parse_pop_key(); } @@ -2310,223 +2315,201 @@ parse_fixup_v380_restr (sc_int type, sc_int var_count, * Helper handlers for parse_fixup_v380(); create task restrictions. */ static void -parse_fixup_v380_obj_restr (sc_bool holding, - sc_int holdobj, const sc_char *failmessage) -{ - /* Ignore if no object selected. */ - if (holdobj > 0) - { - sc_int var1, var2; - - /* - * Create version 4.0 task restriction to check for either the - * referenced object or a dynamic object being either held or in the - * same room (visible to player). - */ - var1 = (holdobj == 1) ? 2 : holdobj + 1; - var2 = holding ? 1 : 3; - parse_fixup_v380_restr (0, 3, var1, var2, 0, failmessage); - } +parse_fixup_v380_obj_restr(sc_bool holding, + sc_int holdobj, const sc_char *failmessage) { + /* Ignore if no object selected. */ + if (holdobj > 0) { + sc_int var1, var2; + + /* + * Create version 4.0 task restriction to check for either the + * referenced object or a dynamic object being either held or in the + * same room (visible to player). + */ + var1 = (holdobj == 1) ? 2 : holdobj + 1; + var2 = holding ? 1 : 3; + parse_fixup_v380_restr(0, 3, var1, var2, 0, failmessage); + } } static void -parse_fixup_v380_task_restr (sc_bool tasknotdone, sc_int task, - const sc_char *failmessage) -{ - /* Ignore if no task selected. */ - if (task > 0) - { - sc_int var2; - - /* Create version 4.0 restriction to check task state. */ - var2 = tasknotdone ? 1 : 0; - parse_fixup_v380_restr (2, 2, task, var2, 0, failmessage); - } +parse_fixup_v380_task_restr(sc_bool tasknotdone, sc_int task, + const sc_char *failmessage) { + /* Ignore if no task selected. */ + if (task > 0) { + sc_int var2; + + /* Create version 4.0 restriction to check task state. */ + var2 = tasknotdone ? 1 : 0; + parse_fixup_v380_restr(2, 2, task, var2, 0, failmessage); + } } static void -parse_fixup_v380_wear_restr (sc_int wearobj, const sc_char *failmessage) -{ - /* Ignore if no object selected. */ - if (wearobj > 0) - { - sc_vartype_t vt_key[3]; - sc_int object_count, object, dynamic, obj_index; - - /* - * Create version 4.0 restrictions for something or nothing worn by - * player. - */ - if (wearobj == 1) - { - parse_fixup_v380_restr (0, 3, 1, 2, 0, failmessage); - return; - } - else if (wearobj == 2) - { - parse_fixup_v380_restr (0, 3, 0, 2, 0, failmessage); - return; - } - - /* Get the count of objects defined. */ - vt_key[0].string = "Objects"; - object_count = prop_get_child_count (parse_bundle, "I<-s", vt_key); - - /* Convert wearobj from worn index to object index. */ - wearobj -= 2; - for (object = 0; object < object_count && wearobj > 0; object++) - { - sc_bool bstatic, wearable; - - vt_key[1].integer = object; - vt_key[2].string = "Static"; - bstatic = prop_get_boolean (parse_bundle, "B<-sis", vt_key); - if (!bstatic) - { - vt_key[2].string = "Wearable"; - wearable = prop_get_boolean (parse_bundle, "B<-sis", vt_key); - if (wearable) - wearobj--; - } - } - obj_index = object - 1; - - /* Now convert wearobj from object index to dynamic index. */ - dynamic = 0; - for (object = 0; object <= obj_index; object++) - { - sc_bool bstatic; - - vt_key[1].integer = object; - vt_key[2].string = "Static"; - bstatic = prop_get_boolean (parse_bundle, "B<-sis", vt_key); - if (!bstatic) - dynamic++; - } - dynamic--; - - /* Create version 4.0 restriction for object worn by player. */ - parse_fixup_v380_restr (0, 3, dynamic + 3, 2, 0, failmessage); - } +parse_fixup_v380_wear_restr(sc_int wearobj, const sc_char *failmessage) { + /* Ignore if no object selected. */ + if (wearobj > 0) { + sc_vartype_t vt_key[3]; + sc_int object_count, object, dynamic, obj_index; + + /* + * Create version 4.0 restrictions for something or nothing worn by + * player. + */ + if (wearobj == 1) { + parse_fixup_v380_restr(0, 3, 1, 2, 0, failmessage); + return; + } else if (wearobj == 2) { + parse_fixup_v380_restr(0, 3, 0, 2, 0, failmessage); + return; + } + + /* Get the count of objects defined. */ + vt_key[0].string = "Objects"; + object_count = prop_get_child_count(parse_bundle, "I<-s", vt_key); + + /* Convert wearobj from worn index to object index. */ + wearobj -= 2; + for (object = 0; object < object_count && wearobj > 0; object++) { + sc_bool bstatic, wearable; + + vt_key[1].integer = object; + vt_key[2].string = "Static"; + bstatic = prop_get_boolean(parse_bundle, "B<-sis", vt_key); + if (!bstatic) { + vt_key[2].string = "Wearable"; + wearable = prop_get_boolean(parse_bundle, "B<-sis", vt_key); + if (wearable) + wearobj--; + } + } + obj_index = object - 1; + + /* Now convert wearobj from object index to dynamic index. */ + dynamic = 0; + for (object = 0; object <= obj_index; object++) { + sc_bool bstatic; + + vt_key[1].integer = object; + vt_key[2].string = "Static"; + bstatic = prop_get_boolean(parse_bundle, "B<-sis", vt_key); + if (!bstatic) + dynamic++; + } + dynamic--; + + /* Create version 4.0 restriction for object worn by player. */ + parse_fixup_v380_restr(0, 3, dynamic + 3, 2, 0, failmessage); + } } static void -parse_fixup_v380_npc_restr (sc_bool notinsameroom, sc_int npc, - const sc_char *failmessage) -{ - /* Ignore if no NPC selected. */ - if (npc > 0) - { - sc_int var2; - - if (npc == 1) - { - /* Create restriction to look for alone, or not. */ - var2 = notinsameroom ? 3 : 2; - parse_fixup_v380_restr (3, 3, 0, var2, 0, failmessage); - return; - } - - /* Create restriction to look for company. */ - var2 = notinsameroom ? 1 : 0; - parse_fixup_v380_restr (3, 3, 0, var2, npc, failmessage); - } +parse_fixup_v380_npc_restr(sc_bool notinsameroom, sc_int npc, + const sc_char *failmessage) { + /* Ignore if no NPC selected. */ + if (npc > 0) { + sc_int var2; + + if (npc == 1) { + /* Create restriction to look for alone, or not. */ + var2 = notinsameroom ? 3 : 2; + parse_fixup_v380_restr(3, 3, 0, var2, 0, failmessage); + return; + } + + /* Create restriction to look for company. */ + var2 = notinsameroom ? 1 : 0; + parse_fixup_v380_restr(3, 3, 0, var2, npc, failmessage); + } } static void -parse_fixup_v380_objroom_restr (sc_int obj, sc_int objroom, - const sc_char *failmessage) -{ - /* Ignore if no object selected. */ - if (obj > 0) - { - /* Create version 4.0 restriction to check object in room. */ - parse_fixup_v380_restr (0, 3, obj + 1, 0, objroom, failmessage); - } +parse_fixup_v380_objroom_restr(sc_int obj, sc_int objroom, + const sc_char *failmessage) { + /* Ignore if no object selected. */ + if (obj > 0) { + /* Create version 4.0 restriction to check object in room. */ + parse_fixup_v380_restr(0, 3, obj + 1, 0, objroom, failmessage); + } } static void -parse_fixup_v380_objstate_restr (sc_int obj, sc_int ivar1, sc_int ivar2, - const sc_char *failmessage) -{ - sc_vartype_t vt_key[3]; - sc_int object, dynamic, var2, var3; - - /* Initialize variables to avoid gcc warnings. */ - var2 = -1; - var3 = -1; - - /* Ignore restrictions with no "type". */ - if (ivar1 == 0) - return; - - /* Look for opened/closed restrictions, convert and return. */ - if (ivar1 == 3 || ivar1 == 4) - { - sc_int stateful; - - /* Convert obj from object to openable (stateful) index. */ - stateful = 0; - for (object = 0; object <= obj - 1; object++) - { - sc_int openable; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Openable"; - openable = prop_get_integer (parse_bundle, "I<-sis", vt_key); - if (openable > 0) - stateful++; - } - stateful--; - - /* - * Create a version 4.0 restriction that checks that an object's state - * is open (var2 = 0) or closed (var2 = 1). - */ - var2 = (ivar1 == 3) ? 0 : 1; - parse_fixup_v380_restr (1, 2, stateful + 1, var2, 0, failmessage); - return; - } - - /* Convert obj from object to dynamic index. */ - dynamic = 0; - for (object = 0; object <= obj - 1; object++) - { - sc_bool bstatic; - - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Static"; - bstatic = prop_get_boolean (parse_bundle, "B<-sis", vt_key); - if (!bstatic) - dynamic++; - } - dynamic--; - - /* Create version 4.0 object location restrictions for the rest. */ - switch (ivar1) - { - case 1: - var2 = 4; - var3 = ivar2; - break; /* Inside */ - case 2: - var2 = 5; - var3 = ivar2; - break; /* On */ - case 5: - var2 = 1; - var3 = ivar2 + 1; - break; /* Held by */ - case 6: - var2 = 2; - var3 = ivar2 + 1; - break; /* Worn by */ - default: - sc_fatal ("parse_fixup_v380_objstate_restr: invalid ivar1, %ld\n", ivar1); - } - parse_fixup_v380_restr (0, 3, dynamic + 3, var2, var3, failmessage); +parse_fixup_v380_objstate_restr(sc_int obj, sc_int ivar1, sc_int ivar2, + const sc_char *failmessage) { + sc_vartype_t vt_key[3]; + sc_int object, dynamic, var2, var3; + + /* Initialize variables to avoid gcc warnings. */ + var2 = -1; + var3 = -1; + + /* Ignore restrictions with no "type". */ + if (ivar1 == 0) + return; + + /* Look for opened/closed restrictions, convert and return. */ + if (ivar1 == 3 || ivar1 == 4) { + sc_int stateful; + + /* Convert obj from object to openable (stateful) index. */ + stateful = 0; + for (object = 0; object <= obj - 1; object++) { + sc_int openable; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Openable"; + openable = prop_get_integer(parse_bundle, "I<-sis", vt_key); + if (openable > 0) + stateful++; + } + stateful--; + + /* + * Create a version 4.0 restriction that checks that an object's state + * is open (var2 = 0) or closed (var2 = 1). + */ + var2 = (ivar1 == 3) ? 0 : 1; + parse_fixup_v380_restr(1, 2, stateful + 1, var2, 0, failmessage); + return; + } + + /* Convert obj from object to dynamic index. */ + dynamic = 0; + for (object = 0; object <= obj - 1; object++) { + sc_bool bstatic; + + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Static"; + bstatic = prop_get_boolean(parse_bundle, "B<-sis", vt_key); + if (!bstatic) + dynamic++; + } + dynamic--; + + /* Create version 4.0 object location restrictions for the rest. */ + switch (ivar1) { + case 1: + var2 = 4; + var3 = ivar2; + break; /* Inside */ + case 2: + var2 = 5; + var3 = ivar2; + break; /* On */ + case 5: + var2 = 1; + var3 = ivar2 + 1; + break; /* Held by */ + case 6: + var2 = 2; + var3 = ivar2 + 1; + break; /* Worn by */ + default: + sc_fatal("parse_fixup_v380_objstate_restr: invalid ivar1, %ld\n", ivar1); + } + parse_fixup_v380_restr(0, 3, dynamic + 3, var2, var3, failmessage); } @@ -2537,516 +2520,489 @@ parse_fixup_v380_objstate_restr (sc_int obj, sc_int ivar1, sc_int ivar2, * 3.8 format into version 4.0. */ static void -parse_fixup_v380 (const sc_char *fixup) -{ - if (parse_trace) - sc_trace ("Parse: entering version 3.8 fixup %s\n", fixup); - - /* Convert container capacity attributes to version 4.0 values. */ - if (strcmp (fixup, "|V380_OBJECT:#Capacity*10+2|") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int surfacecontainer; - - /* Get the object surface and container attributes. */ - vt_key.string = "SurfaceContainer"; - parse_push_key (vt_key, PROP_KEY_STRING); - surfacecontainer = parse_get_integer_property (); - parse_pop_key (); - - /* Convert capacity from version 3.8 format to version 4.0. */ - if (surfacecontainer == V380_OBJ_IS_CONTAINER) - { - sc_int capacity; - - vt_key.string = "Capacity"; - parse_push_key (vt_key, PROP_KEY_STRING); - capacity = parse_get_integer_property (); - - capacity = capacity * V380_OBJ_CAPACITY_MULT + V380_OBJ_DEFAULT_SIZE; - - vt_value.integer = capacity; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - } - - /* - * Exchange openable values 5 and 6, watch for a possible 1 from a 3.8 game - * (interpret as 0), and write -1 key for openable objects. - */ - else if (strcmp (fixup, "|V380_OBJECT:_Openable_,Key|") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int openable; - - /* Retrieve Openable, and if 5 or 6, exchange. */ - vt_key.string = "Openable"; - parse_push_key (vt_key, PROP_KEY_STRING); - openable = parse_get_integer_property (); - - if (openable == 5 || openable == 6) - { - vt_value.integer = (openable == 5) ? 6 : 5; - parse_put_property (vt_value, PROP_INTEGER); - } - - /* If the odd value of 1, rewrite as zero. */ - else if (openable == 1) - { - vt_value.integer = 0; - parse_put_property (vt_value, PROP_INTEGER); - } - - parse_pop_key (); - - /* For openable objects, store a Key of -1. */ - if (openable == 5 || openable == 6) - { - vt_key.string = "Key"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.integer = -1; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - } - - /* Create version 4.0 task actions from a version 3.8 task. */ - else if (strcmp (fixup, "|V380_TASK:_Actions_|") == 0) - { - sc_vartype_t vt_key; - sc_int score; - sc_bool killsplayer, wingame; - sc_int movement; - - /* Retrieve the score change for the task. */ - vt_key.string = "Score"; - parse_push_key (vt_key, PROP_KEY_STRING); - score = parse_get_integer_property (); - parse_pop_key (); - - /* Create any appropriate score change action. */ - if (score != 0) - parse_fixup_v380_action (4, 1, score, 0, 0); - - /* Get player death and game winning flags. */ - vt_key.string = "KillsPlayer"; - parse_push_key (vt_key, PROP_KEY_STRING); - killsplayer = parse_get_boolean_property (); - parse_pop_key (); - vt_key.string = "WinGame"; - parse_push_key (vt_key, PROP_KEY_STRING); - wingame = parse_get_boolean_property (); - parse_pop_key (); - - /* Create any appropriate game ending actions. */ - if (killsplayer) - parse_fixup_v380_action (6, 1, 2, 0, 0); - if (wingame) - parse_fixup_v380_action (6, 1, 0, 0, 0); - - /* Handle each defined movement for the task. */ - for (movement = 0; movement < V380_TASK_MOVEMENTS; movement++) - { - sc_int mvar1, mvar2, mvar3; - - vt_key.integer = movement; - parse_push_key (vt_key, PROP_KEY_INTEGER); - vt_key.string = "Movements"; - parse_push_key (vt_key, PROP_KEY_STRING); - - /* Retrieve the movement parameters. */ - vt_key.string = "Var1"; - parse_push_key (vt_key, PROP_KEY_STRING); - mvar1 = parse_get_integer_property (); - parse_pop_key (); - vt_key.string = "Var2"; - parse_push_key (vt_key, PROP_KEY_STRING); - mvar2 = parse_get_integer_property (); - parse_pop_key (); - vt_key.string = "Var3"; - parse_push_key (vt_key, PROP_KEY_STRING); - mvar3 = parse_get_integer_property (); - parse_pop_key (); - - parse_pop_key (); - parse_pop_key (); - - /* Create the corresponding task action. */ - parse_fixup_v380_movement (mvar1, mvar2, mvar3); - } - } - - /* Create version 4.0 task restrictions from a version 3.8 task. */ - else if (strcmp (fixup, "|V380_TASK:_Restrictions_|") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_bool holding, tasknotdone, notinsameroom; - sc_int holdobj1, holdobj2, holdobj3, task; - sc_int wearobj1, wearobj2, npc, obj1, obj1room, obj2; - const sc_char *holdmsg, *taskmsg, *wearmsg, *companymsg; - const sc_char *obj1msg; - sc_int restriction_count; - - /* Create restrictions for objects not held or absent. */ - vt_key.string = "HoldingSameRoom"; - parse_push_key (vt_key, PROP_KEY_STRING); - holding = parse_get_boolean_property (); - parse_pop_key (); - - vt_key.string = "HoldObj1"; - parse_push_key (vt_key, PROP_KEY_STRING); - holdobj1 = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "HoldObj2"; - parse_push_key (vt_key, PROP_KEY_STRING); - holdobj2 = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "HoldObj3"; - parse_push_key (vt_key, PROP_KEY_STRING); - holdobj3 = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "HoldMsg"; - parse_push_key (vt_key, PROP_KEY_STRING); - holdmsg = parse_get_string_property (); - parse_pop_key (); - - parse_fixup_v380_obj_restr (holding, holdobj1, holdmsg); - parse_fixup_v380_obj_restr (holding, holdobj2, holdmsg); - parse_fixup_v380_obj_restr (holding, holdobj3, holdmsg); - - /* Create any task state restriction. */ - vt_key.string = "TaskNotDone"; - parse_push_key (vt_key, PROP_KEY_STRING); - tasknotdone = parse_get_boolean_property (); - parse_pop_key (); - - vt_key.string = "Task"; - parse_push_key (vt_key, PROP_KEY_STRING); - task = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "TaskMsg"; - parse_push_key (vt_key, PROP_KEY_STRING); - taskmsg = parse_get_string_property (); - parse_pop_key (); - - parse_fixup_v380_task_restr (tasknotdone, task, taskmsg); - - /* Create any object not worn restrictions. */ - vt_key.string = "WearObj1"; - parse_push_key (vt_key, PROP_KEY_STRING); - wearobj1 = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "WearObj2"; - parse_push_key (vt_key, PROP_KEY_STRING); - wearobj2 = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "WearMsg"; - parse_push_key (vt_key, PROP_KEY_STRING); - wearmsg = parse_get_string_property (); - parse_pop_key (); - - parse_fixup_v380_wear_restr (wearobj1, wearmsg); - parse_fixup_v380_wear_restr (wearobj2, wearmsg); - - /* Check for presence/absence of NPCs restriction. */ - vt_key.string = "NotInSameRoom"; - parse_push_key (vt_key, PROP_KEY_STRING); - notinsameroom = parse_get_boolean_property (); - parse_pop_key (); - - vt_key.string = "NPC"; - parse_push_key (vt_key, PROP_KEY_STRING); - npc = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "CompanyMsg"; - parse_push_key (vt_key, PROP_KEY_STRING); - companymsg = parse_get_string_property (); - parse_pop_key (); - - parse_fixup_v380_npc_restr (notinsameroom, npc, companymsg); - - /* Create any object location restriction. */ - vt_key.string = "Obj1"; - parse_push_key (vt_key, PROP_KEY_STRING); - obj1 = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "Obj1Room"; - parse_push_key (vt_key, PROP_KEY_STRING); - obj1room = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "Obj1Msg"; - parse_push_key (vt_key, PROP_KEY_STRING); - obj1msg = parse_get_string_property (); - parse_pop_key (); - - parse_fixup_v380_objroom_restr (obj1, obj1room, obj1msg); - - /* And finally, any object state restriction. */ - vt_key.string = "Obj2"; - parse_push_key (vt_key, PROP_KEY_STRING); - obj2 = parse_get_integer_property (); - parse_pop_key (); - - if (obj2 > 0) - { - sc_int var1, var2; - const sc_char *obj2msg; - - vt_key.string = "Obj2Var1"; - parse_push_key (vt_key, PROP_KEY_STRING); - var1 = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "Obj2Var2"; - parse_push_key (vt_key, PROP_KEY_STRING); - var2 = parse_get_integer_property (); - parse_pop_key (); - - vt_key.string = "Obj2Msg"; - parse_push_key (vt_key, PROP_KEY_STRING); - obj2msg = parse_get_string_property (); - parse_pop_key (); - - parse_fixup_v380_objstate_restr (obj2, var1, var2, obj2msg); - } - - /* Get a count of restrictions created. */ - vt_key.string = "Restrictions"; - parse_push_key (vt_key, PROP_KEY_STRING); - restriction_count = parse_get_child_count (); - parse_pop_key (); - - /* Allocate and fill a new mask for these restrictions. */ - if (restriction_count > 0) - { - sc_char *restrmask; - sc_int index_; - - restrmask = (sc_char *)sc_malloc (2 * restriction_count); - strcpy (restrmask, "#"); - for (index_ = 1; index_ < restriction_count; index_++) - strcat (restrmask, "A#"); - - vt_key.string = "RestrMask"; - parse_push_key (vt_key, PROP_KEY_STRING); - vt_value.string = restrmask; - parse_put_property (vt_value, PROP_STRING); - parse_pop_key (); - - prop_adopt (parse_bundle, restrmask); - } - } - - /* - * Adjust dynamic object initial positions and parents (where contained - * or on surfaces) into version 4.0 range. - */ - else if (strcmp (fixup, "|V380_OBJECT:_InitialPositions_|") == 0) - { - sc_vartype_t vt_key[3]; - sc_int object_count, object, *object_type; - - /* Get a count of objects. */ - vt_key[0].string = "Objects"; - object_count = prop_get_child_count (parse_bundle, "I<-s", vt_key); - - /* Build an array of object container/surface types. */ - object_type = (sc_int *)sc_malloc (object_count * sizeof (*object_type)); - for (object = 0; object < object_count; object++) - { - vt_key[1].integer = object; - vt_key[2].string = "SurfaceContainer"; - object_type[object] = prop_get_integer (parse_bundle, - "I<-sis", vt_key); - } - - /* Adjust each object's initial position if necessary. */ - for (object = 0; object < object_count; object++) - { - sc_vartype_t vt_value; - sc_bool is_static; - sc_int initialposition; - - /* Ignore static objects; we only want dynamic ones. */ - vt_key[1].integer = object; - vt_key[2].string = "Static"; - is_static = prop_get_boolean (parse_bundle, "B<-sis", vt_key); - if (is_static) - continue; - - /* If initial position is above on/in, increment. */ - vt_key[1].integer = object; - vt_key[2].string = "InitialPosition"; - initialposition = prop_get_integer (parse_bundle, "I<-sis", vt_key); - if (initialposition > 2) - { - vt_value.integer = initialposition + 1; - prop_put (parse_bundle, "I->sis", vt_value, vt_key); - } - - /* - * If initial position is on or in, decide which, depending on the - * type of the parent. From this, expand initial position into a - * version 4.0 value. - */ - if (initialposition == 2) - { - sc_int count, parent, index_; - - /* Get parent container/surface index. */ - vt_key[1].integer = object; - vt_key[2].string = "Parent"; - count = prop_get_integer (parse_bundle, "I<-sis", vt_key); - - /* Convert container/surface index. */ - for (parent = 0; parent < object_count && count >= 0; parent++) - { - if (object_type[parent] == V380_OBJ_IS_CONTAINER - || object_type[parent] == V380_OBJ_IS_SURFACE) - count--; - } - parent--; - - /* If parent is a surface, adjust position. */ - if (object_type[parent] == V380_OBJ_IS_SURFACE) - { - vt_key[2].string = "InitialPosition"; - vt_value.integer = initialposition + 1; - prop_put (parse_bundle, "I->sis", vt_value, vt_key); - } - - /* - * For both, adjust parent to be an object index for that type - * of object only. - */ - count = 0; - for (index_ = 0; index_ < parent; index_++) - { - if (object_type[index_] == object_type[parent]) - count++; - } - vt_key[2].string = "Parent"; - vt_value.integer = count; - prop_put (parse_bundle, "I->sis", vt_value, vt_key); - } - } - - /* Done with temporary array. */ - sc_free (object_type); - } - - /* Convert carry limit into version 4.0-like size and weight limits. */ - else if (strcmp (fixup, "|V380_MaxSize_MaxWt_|") == 0) - { - sc_vartype_t vt_key, vt_value; - sc_int maxcarried; - - vt_key.string = "MaxCarried"; - parse_push_key (vt_key, PROP_KEY_STRING); - maxcarried = parse_get_integer_property (); - parse_pop_key (); - - vt_value.integer = maxcarried * V380_OBJ_CAPACITY_MULT - + V380_OBJ_DEFAULT_SIZE; - - vt_key.string = "MaxSize"; - parse_push_key (vt_key, PROP_KEY_STRING); - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - - vt_key.string = "MaxWt"; - parse_push_key (vt_key, PROP_KEY_STRING); - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - - /* Add up positive scoring tasks to arrive at max score. */ - else if (strcmp (fixup, "|V380_GLOBAL:_MaxScore_|") == 0) - { - sc_vartype_t vt_key[3], vt_value; - sc_int task_count, maxscore, task; - - /* Get a count of tasks. */ - vt_key[0].string = "Tasks"; - task_count = prop_get_child_count (parse_bundle, "I<-s", vt_key); - - /* Sum positive scoring tasks. */ - maxscore = 0; - for (task = 0; task < task_count; task++) - { - sc_int score; - - vt_key[1].integer = task; - vt_key[2].string = "Score"; - score = prop_get_integer (parse_bundle, "I<-sis", vt_key); - if (score > 0) - maxscore += score; - } - - /* Write MaxScore global property. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "MaxScore"; - vt_value.integer = maxscore; - prop_put (parse_bundle, "I->ss", vt_value, vt_key); - } - - /* Convert walk meetobject from dynamic index to object. */ - else if (strcmp (fixup, "|V380_WALK:_MeetObject_|") == 0) - { - sc_vartype_t vt_key, vt_value, vt_gkey[3]; - sc_int meetobject, count, object_count, object; - - vt_key.string = "MeetObject"; - parse_push_key (vt_key, PROP_KEY_STRING); - meetobject = parse_get_integer_property (); - - /* Get a count of objects. */ - vt_gkey[0].string = "Objects"; - object_count = prop_get_child_count (parse_bundle, "I<-s", vt_gkey); - - /* Convert dynamic index to object, and rewrite. */ - count = meetobject - 1; - for (object = 0; object < object_count && count >= 0; object++) - { - sc_bool bstatic; - - vt_gkey[1].integer = object; - vt_gkey[2].string = "Static"; - bstatic = prop_get_boolean (parse_bundle, "B<-sis", vt_gkey); - if (!bstatic) - count--; - } - object--; - - vt_value.integer = object; - parse_put_property (vt_value, PROP_INTEGER); - parse_pop_key (); - } - - /* Convert version 3.8 room data into a version 4.0 alts array. */ - else if (strcmp (fixup, "|V380_ROOM:_Alts_|") == 0) - { - parse_fixup_v390_v380_room_alts (); - } - - /* Error if no fixup special handler available. */ - else - { - sc_fatal ("parse_fixup_v380: no handler for \"%s\"\n", fixup); - } - - if (parse_trace) - sc_trace ("Parse: leaving version 3.8 fixup %s\n", fixup); +parse_fixup_v380(const sc_char *fixup) { + if (parse_trace) + sc_trace("Parse: entering version 3.8 fixup %s\n", fixup); + + /* Convert container capacity attributes to version 4.0 values. */ + if (strcmp(fixup, "|V380_OBJECT:#Capacity*10+2|") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int surfacecontainer; + + /* Get the object surface and container attributes. */ + vt_key.string = "SurfaceContainer"; + parse_push_key(vt_key, PROP_KEY_STRING); + surfacecontainer = parse_get_integer_property(); + parse_pop_key(); + + /* Convert capacity from version 3.8 format to version 4.0. */ + if (surfacecontainer == V380_OBJ_IS_CONTAINER) { + sc_int capacity; + + vt_key.string = "Capacity"; + parse_push_key(vt_key, PROP_KEY_STRING); + capacity = parse_get_integer_property(); + + capacity = capacity * V380_OBJ_CAPACITY_MULT + V380_OBJ_DEFAULT_SIZE; + + vt_value.integer = capacity; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + } + + /* + * Exchange openable values 5 and 6, watch for a possible 1 from a 3.8 game + * (interpret as 0), and write -1 key for openable objects. + */ + else if (strcmp(fixup, "|V380_OBJECT:_Openable_,Key|") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int openable; + + /* Retrieve Openable, and if 5 or 6, exchange. */ + vt_key.string = "Openable"; + parse_push_key(vt_key, PROP_KEY_STRING); + openable = parse_get_integer_property(); + + if (openable == 5 || openable == 6) { + vt_value.integer = (openable == 5) ? 6 : 5; + parse_put_property(vt_value, PROP_INTEGER); + } + + /* If the odd value of 1, rewrite as zero. */ + else if (openable == 1) { + vt_value.integer = 0; + parse_put_property(vt_value, PROP_INTEGER); + } + + parse_pop_key(); + + /* For openable objects, store a Key of -1. */ + if (openable == 5 || openable == 6) { + vt_key.string = "Key"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.integer = -1; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + } + + /* Create version 4.0 task actions from a version 3.8 task. */ + else if (strcmp(fixup, "|V380_TASK:_Actions_|") == 0) { + sc_vartype_t vt_key; + sc_int score; + sc_bool killsplayer, wingame; + sc_int movement; + + /* Retrieve the score change for the task. */ + vt_key.string = "Score"; + parse_push_key(vt_key, PROP_KEY_STRING); + score = parse_get_integer_property(); + parse_pop_key(); + + /* Create any appropriate score change action. */ + if (score != 0) + parse_fixup_v380_action(4, 1, score, 0, 0); + + /* Get player death and game winning flags. */ + vt_key.string = "KillsPlayer"; + parse_push_key(vt_key, PROP_KEY_STRING); + killsplayer = parse_get_boolean_property(); + parse_pop_key(); + vt_key.string = "WinGame"; + parse_push_key(vt_key, PROP_KEY_STRING); + wingame = parse_get_boolean_property(); + parse_pop_key(); + + /* Create any appropriate game ending actions. */ + if (killsplayer) + parse_fixup_v380_action(6, 1, 2, 0, 0); + if (wingame) + parse_fixup_v380_action(6, 1, 0, 0, 0); + + /* Handle each defined movement for the task. */ + for (movement = 0; movement < V380_TASK_MOVEMENTS; movement++) { + sc_int mvar1, mvar2, mvar3; + + vt_key.integer = movement; + parse_push_key(vt_key, PROP_KEY_INTEGER); + vt_key.string = "Movements"; + parse_push_key(vt_key, PROP_KEY_STRING); + + /* Retrieve the movement parameters. */ + vt_key.string = "Var1"; + parse_push_key(vt_key, PROP_KEY_STRING); + mvar1 = parse_get_integer_property(); + parse_pop_key(); + vt_key.string = "Var2"; + parse_push_key(vt_key, PROP_KEY_STRING); + mvar2 = parse_get_integer_property(); + parse_pop_key(); + vt_key.string = "Var3"; + parse_push_key(vt_key, PROP_KEY_STRING); + mvar3 = parse_get_integer_property(); + parse_pop_key(); + + parse_pop_key(); + parse_pop_key(); + + /* Create the corresponding task action. */ + parse_fixup_v380_movement(mvar1, mvar2, mvar3); + } + } + + /* Create version 4.0 task restrictions from a version 3.8 task. */ + else if (strcmp(fixup, "|V380_TASK:_Restrictions_|") == 0) { + sc_vartype_t vt_key, vt_value; + sc_bool holding, tasknotdone, notinsameroom; + sc_int holdobj1, holdobj2, holdobj3, task; + sc_int wearobj1, wearobj2, npc, obj1, obj1room, obj2; + const sc_char *holdmsg, *taskmsg, *wearmsg, *companymsg; + const sc_char *obj1msg; + sc_int restriction_count; + + /* Create restrictions for objects not held or absent. */ + vt_key.string = "HoldingSameRoom"; + parse_push_key(vt_key, PROP_KEY_STRING); + holding = parse_get_boolean_property(); + parse_pop_key(); + + vt_key.string = "HoldObj1"; + parse_push_key(vt_key, PROP_KEY_STRING); + holdobj1 = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "HoldObj2"; + parse_push_key(vt_key, PROP_KEY_STRING); + holdobj2 = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "HoldObj3"; + parse_push_key(vt_key, PROP_KEY_STRING); + holdobj3 = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "HoldMsg"; + parse_push_key(vt_key, PROP_KEY_STRING); + holdmsg = parse_get_string_property(); + parse_pop_key(); + + parse_fixup_v380_obj_restr(holding, holdobj1, holdmsg); + parse_fixup_v380_obj_restr(holding, holdobj2, holdmsg); + parse_fixup_v380_obj_restr(holding, holdobj3, holdmsg); + + /* Create any task state restriction. */ + vt_key.string = "TaskNotDone"; + parse_push_key(vt_key, PROP_KEY_STRING); + tasknotdone = parse_get_boolean_property(); + parse_pop_key(); + + vt_key.string = "Task"; + parse_push_key(vt_key, PROP_KEY_STRING); + task = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "TaskMsg"; + parse_push_key(vt_key, PROP_KEY_STRING); + taskmsg = parse_get_string_property(); + parse_pop_key(); + + parse_fixup_v380_task_restr(tasknotdone, task, taskmsg); + + /* Create any object not worn restrictions. */ + vt_key.string = "WearObj1"; + parse_push_key(vt_key, PROP_KEY_STRING); + wearobj1 = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "WearObj2"; + parse_push_key(vt_key, PROP_KEY_STRING); + wearobj2 = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "WearMsg"; + parse_push_key(vt_key, PROP_KEY_STRING); + wearmsg = parse_get_string_property(); + parse_pop_key(); + + parse_fixup_v380_wear_restr(wearobj1, wearmsg); + parse_fixup_v380_wear_restr(wearobj2, wearmsg); + + /* Check for presence/absence of NPCs restriction. */ + vt_key.string = "NotInSameRoom"; + parse_push_key(vt_key, PROP_KEY_STRING); + notinsameroom = parse_get_boolean_property(); + parse_pop_key(); + + vt_key.string = "NPC"; + parse_push_key(vt_key, PROP_KEY_STRING); + npc = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "CompanyMsg"; + parse_push_key(vt_key, PROP_KEY_STRING); + companymsg = parse_get_string_property(); + parse_pop_key(); + + parse_fixup_v380_npc_restr(notinsameroom, npc, companymsg); + + /* Create any object location restriction. */ + vt_key.string = "Obj1"; + parse_push_key(vt_key, PROP_KEY_STRING); + obj1 = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "Obj1Room"; + parse_push_key(vt_key, PROP_KEY_STRING); + obj1room = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "Obj1Msg"; + parse_push_key(vt_key, PROP_KEY_STRING); + obj1msg = parse_get_string_property(); + parse_pop_key(); + + parse_fixup_v380_objroom_restr(obj1, obj1room, obj1msg); + + /* And finally, any object state restriction. */ + vt_key.string = "Obj2"; + parse_push_key(vt_key, PROP_KEY_STRING); + obj2 = parse_get_integer_property(); + parse_pop_key(); + + if (obj2 > 0) { + sc_int var1, var2; + const sc_char *obj2msg; + + vt_key.string = "Obj2Var1"; + parse_push_key(vt_key, PROP_KEY_STRING); + var1 = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "Obj2Var2"; + parse_push_key(vt_key, PROP_KEY_STRING); + var2 = parse_get_integer_property(); + parse_pop_key(); + + vt_key.string = "Obj2Msg"; + parse_push_key(vt_key, PROP_KEY_STRING); + obj2msg = parse_get_string_property(); + parse_pop_key(); + + parse_fixup_v380_objstate_restr(obj2, var1, var2, obj2msg); + } + + /* Get a count of restrictions created. */ + vt_key.string = "Restrictions"; + parse_push_key(vt_key, PROP_KEY_STRING); + restriction_count = parse_get_child_count(); + parse_pop_key(); + + /* Allocate and fill a new mask for these restrictions. */ + if (restriction_count > 0) { + sc_char *restrmask; + sc_int index_; + + restrmask = (sc_char *)sc_malloc(2 * restriction_count); + strcpy(restrmask, "#"); + for (index_ = 1; index_ < restriction_count; index_++) + strcat(restrmask, "A#"); + + vt_key.string = "RestrMask"; + parse_push_key(vt_key, PROP_KEY_STRING); + vt_value.string = restrmask; + parse_put_property(vt_value, PROP_STRING); + parse_pop_key(); + + prop_adopt(parse_bundle, restrmask); + } + } + + /* + * Adjust dynamic object initial positions and parents (where contained + * or on surfaces) into version 4.0 range. + */ + else if (strcmp(fixup, "|V380_OBJECT:_InitialPositions_|") == 0) { + sc_vartype_t vt_key[3]; + sc_int object_count, object, *object_type; + + /* Get a count of objects. */ + vt_key[0].string = "Objects"; + object_count = prop_get_child_count(parse_bundle, "I<-s", vt_key); + + /* Build an array of object container/surface types. */ + object_type = (sc_int *)sc_malloc(object_count * sizeof(*object_type)); + for (object = 0; object < object_count; object++) { + vt_key[1].integer = object; + vt_key[2].string = "SurfaceContainer"; + object_type[object] = prop_get_integer(parse_bundle, + "I<-sis", vt_key); + } + + /* Adjust each object's initial position if necessary. */ + for (object = 0; object < object_count; object++) { + sc_vartype_t vt_value; + sc_bool is_static; + sc_int initialposition; + + /* Ignore static objects; we only want dynamic ones. */ + vt_key[1].integer = object; + vt_key[2].string = "Static"; + is_static = prop_get_boolean(parse_bundle, "B<-sis", vt_key); + if (is_static) + continue; + + /* If initial position is above on/in, increment. */ + vt_key[1].integer = object; + vt_key[2].string = "InitialPosition"; + initialposition = prop_get_integer(parse_bundle, "I<-sis", vt_key); + if (initialposition > 2) { + vt_value.integer = initialposition + 1; + prop_put(parse_bundle, "I->sis", vt_value, vt_key); + } + + /* + * If initial position is on or in, decide which, depending on the + * type of the parent. From this, expand initial position into a + * version 4.0 value. + */ + if (initialposition == 2) { + sc_int count, parent, index_; + + /* Get parent container/surface index. */ + vt_key[1].integer = object; + vt_key[2].string = "Parent"; + count = prop_get_integer(parse_bundle, "I<-sis", vt_key); + + /* Convert container/surface index. */ + for (parent = 0; parent < object_count && count >= 0; parent++) { + if (object_type[parent] == V380_OBJ_IS_CONTAINER + || object_type[parent] == V380_OBJ_IS_SURFACE) + count--; + } + parent--; + + /* If parent is a surface, adjust position. */ + if (object_type[parent] == V380_OBJ_IS_SURFACE) { + vt_key[2].string = "InitialPosition"; + vt_value.integer = initialposition + 1; + prop_put(parse_bundle, "I->sis", vt_value, vt_key); + } + + /* + * For both, adjust parent to be an object index for that type + * of object only. + */ + count = 0; + for (index_ = 0; index_ < parent; index_++) { + if (object_type[index_] == object_type[parent]) + count++; + } + vt_key[2].string = "Parent"; + vt_value.integer = count; + prop_put(parse_bundle, "I->sis", vt_value, vt_key); + } + } + + /* Done with temporary array. */ + sc_free(object_type); + } + + /* Convert carry limit into version 4.0-like size and weight limits. */ + else if (strcmp(fixup, "|V380_MaxSize_MaxWt_|") == 0) { + sc_vartype_t vt_key, vt_value; + sc_int maxcarried; + + vt_key.string = "MaxCarried"; + parse_push_key(vt_key, PROP_KEY_STRING); + maxcarried = parse_get_integer_property(); + parse_pop_key(); + + vt_value.integer = maxcarried * V380_OBJ_CAPACITY_MULT + + V380_OBJ_DEFAULT_SIZE; + + vt_key.string = "MaxSize"; + parse_push_key(vt_key, PROP_KEY_STRING); + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + + vt_key.string = "MaxWt"; + parse_push_key(vt_key, PROP_KEY_STRING); + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + + /* Add up positive scoring tasks to arrive at max score. */ + else if (strcmp(fixup, "|V380_GLOBAL:_MaxScore_|") == 0) { + sc_vartype_t vt_key[3], vt_value; + sc_int task_count, maxscore, task; + + /* Get a count of tasks. */ + vt_key[0].string = "Tasks"; + task_count = prop_get_child_count(parse_bundle, "I<-s", vt_key); + + /* Sum positive scoring tasks. */ + maxscore = 0; + for (task = 0; task < task_count; task++) { + sc_int score; + + vt_key[1].integer = task; + vt_key[2].string = "Score"; + score = prop_get_integer(parse_bundle, "I<-sis", vt_key); + if (score > 0) + maxscore += score; + } + + /* Write MaxScore global property. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "MaxScore"; + vt_value.integer = maxscore; + prop_put(parse_bundle, "I->ss", vt_value, vt_key); + } + + /* Convert walk meetobject from dynamic index to object. */ + else if (strcmp(fixup, "|V380_WALK:_MeetObject_|") == 0) { + sc_vartype_t vt_key, vt_value, vt_gkey[3]; + sc_int meetobject, count, object_count, object; + + vt_key.string = "MeetObject"; + parse_push_key(vt_key, PROP_KEY_STRING); + meetobject = parse_get_integer_property(); + + /* Get a count of objects. */ + vt_gkey[0].string = "Objects"; + object_count = prop_get_child_count(parse_bundle, "I<-s", vt_gkey); + + /* Convert dynamic index to object, and rewrite. */ + count = meetobject - 1; + for (object = 0; object < object_count && count >= 0; object++) { + sc_bool bstatic; + + vt_gkey[1].integer = object; + vt_gkey[2].string = "Static"; + bstatic = prop_get_boolean(parse_bundle, "B<-sis", vt_gkey); + if (!bstatic) + count--; + } + object--; + + vt_value.integer = object; + parse_put_property(vt_value, PROP_INTEGER); + parse_pop_key(); + } + + /* Convert version 3.8 room data into a version 4.0 alts array. */ + else if (strcmp(fixup, "|V380_ROOM:_Alts_|") == 0) { + parse_fixup_v390_v380_room_alts(); + } + + /* Error if no fixup special handler available. */ + else { + sc_fatal("parse_fixup_v380: no handler for \"%s\"\n", fixup); + } + + if (parse_trace) + sc_trace("Parse: leaving version 3.8 fixup %s\n", fixup); } @@ -3057,27 +3013,25 @@ parse_fixup_v380 (const sc_char *fixup) * 3.9 and version 3.8 formats into version 4.0. */ static void -parse_fixup (const sc_char *fixup) -{ - /* - * Pick a fixup handler specific to the TAF version. This helps keep - * fixup code separate, rather than glommed into one large function. - */ - switch (taf_get_version (parse_taf)) - { - case TAF_VERSION_400: - sc_fatal ("parse_fixup: unexpected call\n"); - break; - case TAF_VERSION_390: - parse_fixup_v390 (fixup); - break; - case TAF_VERSION_380: - parse_fixup_v380 (fixup); - break; - default: - sc_fatal ("parse_fixup: invalid TAF file version\n"); - break; - } +parse_fixup(const sc_char *fixup) { + /* + * Pick a fixup handler specific to the TAF version. This helps keep + * fixup code separate, rather than glommed into one large function. + */ + switch (taf_get_version(parse_taf)) { + case TAF_VERSION_400: + sc_fatal("parse_fixup: unexpected call\n"); + break; + case TAF_VERSION_390: + parse_fixup_v390(fixup); + break; + case TAF_VERSION_380: + parse_fixup_v380(fixup); + break; + default: + sc_fatal("parse_fixup: invalid TAF file version\n"); + break; + } } @@ -3087,55 +3041,53 @@ parse_fixup (const sc_char *fixup) * Parse a class descriptor element. */ static void -parse_element (const sc_char *element) -{ - if (parse_trace) - sc_trace ("Parse: entering element %s\n", element); - - /* Determine the element type from the first character. */ - switch (element[0]) - { - case PARSE_ARRAY: - parse_array (element); - break; - case PARSE_VECTOR: - parse_vector (element); - break; - case PARSE_VECTOR_ALTERNATE: - parse_vector_alternate (element); - break; - case PARSE_CLASS: - parse_class (element); - break; - case PARSE_EXPRESSION: - parse_expression (element); - break; - case PARSE_SPECIAL: - parse_special (element); - break; - case PARSE_FIXUP: - parse_fixup (element); - break; - - case PARSE_INTEGER: - case PARSE_DEFAULT_ZERO: - case PARSE_BOOLEAN: - case PARSE_DEFAULT_TRUE: - case PARSE_DEFAULT_FALSE: - case PARSE_STRING: - case PARSE_DEFAULT_EMPTY: - case PARSE_IGNORE_INTEGER: - case PARSE_IGNORE_BOOLEAN: - case PARSE_IGNORE_STRING: - case PARSE_MULTILINE: - parse_terminal (element); - break; - default: - sc_fatal ("parse_element: bad type, %c\n", element[0]); - } - - if (parse_trace) - sc_trace ("Parse: leaving element %s\n", element); +parse_element(const sc_char *element) { + if (parse_trace) + sc_trace("Parse: entering element %s\n", element); + + /* Determine the element type from the first character. */ + switch (element[0]) { + case PARSE_ARRAY: + parse_array(element); + break; + case PARSE_VECTOR: + parse_vector(element); + break; + case PARSE_VECTOR_ALTERNATE: + parse_vector_alternate(element); + break; + case PARSE_CLASS: + parse_class(element); + break; + case PARSE_EXPRESSION: + parse_expression(element); + break; + case PARSE_SPECIAL: + parse_special(element); + break; + case PARSE_FIXUP: + parse_fixup(element); + break; + + case PARSE_INTEGER: + case PARSE_DEFAULT_ZERO: + case PARSE_BOOLEAN: + case PARSE_DEFAULT_TRUE: + case PARSE_DEFAULT_FALSE: + case PARSE_STRING: + case PARSE_DEFAULT_EMPTY: + case PARSE_IGNORE_INTEGER: + case PARSE_IGNORE_BOOLEAN: + case PARSE_IGNORE_STRING: + case PARSE_MULTILINE: + parse_terminal(element); + break; + default: + sc_fatal("parse_element: bad type, %c\n", element[0]); + } + + if (parse_trace) + sc_trace("Parse: leaving element %s\n", element); } @@ -3145,26 +3097,24 @@ parse_element (const sc_char *element) * Parse a class's properties descriptor list. */ static void -parse_descriptor (const sc_char *descriptor) -{ - sc_int next; - - /* Find and parse each element in the descriptor. */ - for (next = 0; descriptor[next] != NUL; ) - { - sc_char element[PARSE_TEMP_LENGTH]; - - /* Isolate the next descriptor element. */ - if (sscanf (descriptor + next, "%[^ ]", element) != 1) - sc_fatal ("parse_element: no element, %s\n", descriptor + next); - - /* Parse this isolated element. */ - parse_element (element); - - /* Advance over the element and any trailing whitespace. */ - next += strlen (element); - next += strspn (descriptor + next, " "); - } +parse_descriptor(const sc_char *descriptor) { + sc_int next; + + /* Find and parse each element in the descriptor. */ + for (next = 0; descriptor[next] != NUL;) { + sc_char element[PARSE_TEMP_LENGTH]; + + /* Isolate the next descriptor element. */ + if (sscanf(descriptor + next, "%[^ ]", element) != 1) + sc_fatal("parse_element: no element, %s\n", descriptor + next); + + /* Parse this isolated element. */ + parse_element(element); + + /* Advance over the element and any trailing whitespace. */ + next += strlen(element); + next += strspn(descriptor + next, " "); + } } @@ -3174,47 +3124,44 @@ parse_descriptor (const sc_char *descriptor) * Parse a class of properties. */ static void -parse_class (const sc_char *class_) -{ - sc_char class_name[PARSE_TEMP_LENGTH]; - sc_int index_; - sc_vartype_t vt_key; - - /* Isolate the class name. */ - if (sscanf (class_, "<%[^>]", class_name) != 1) - sc_fatal ("parse_class: error in class, %s\n", class_); - if (parse_trace) - sc_trace ("Parse: entering class %s\n", class_name); - - /* Find the class in the parse schema, and fail if not found. */ - for (index_ = 0; parse_schema[index_].class_name; index_++) - { - if (strcmp (parse_schema[index_].class_name, class_name) == 0) - break; - } - if (!parse_schema[index_].class_name) - sc_fatal ("parse_class: class not described, %s\n", class_name); - - /* - * Unless we are at the top level of the parse schema, push the class tag - * as a key. The top level is "_GAME_", index_ 0, and isn't part of key - * formation. - */ - if (index_ > 0) - { - vt_key.string = class_ + strlen (class_name) + 2; - parse_push_key (vt_key, PROP_KEY_STRING); - } - - /* Parse each element in the descriptor. */ - parse_descriptor (parse_schema[index_].descriptor); - - /* Pop a key if the class tag was pushed above. */ - if (index_ > 0) - parse_pop_key (); - - if (parse_trace) - sc_trace ("Parse: leaving class %s\n", class_name); +parse_class(const sc_char *class_) { + sc_char class_name[PARSE_TEMP_LENGTH]; + sc_int index_; + sc_vartype_t vt_key; + + /* Isolate the class name. */ + if (sscanf(class_, "<%[^>]", class_name) != 1) + sc_fatal("parse_class: error in class, %s\n", class_); + if (parse_trace) + sc_trace("Parse: entering class %s\n", class_name); + + /* Find the class in the parse schema, and fail if not found. */ + for (index_ = 0; parse_schema[index_].class_name; index_++) { + if (strcmp(parse_schema[index_].class_name, class_name) == 0) + break; + } + if (!parse_schema[index_].class_name) + sc_fatal("parse_class: class not described, %s\n", class_name); + + /* + * Unless we are at the top level of the parse schema, push the class tag + * as a key. The top level is "_GAME_", index_ 0, and isn't part of key + * formation. + */ + if (index_ > 0) { + vt_key.string = class_ + strlen(class_name) + 2; + parse_push_key(vt_key, PROP_KEY_STRING); + } + + /* Parse each element in the descriptor. */ + parse_descriptor(parse_schema[index_].descriptor); + + /* Pop a key if the class tag was pushed above. */ + if (index_ > 0) + parse_pop_key(); + + if (parse_trace) + sc_trace("Parse: leaving class %s\n", class_name); } @@ -3225,54 +3172,50 @@ parse_class (const sc_char *class_) * that occurs after the TAF file has been successfully parsed. */ static void -parse_add_walkalerts (sc_prop_setref_t bundle) -{ - sc_vartype_t vt_key[5]; - sc_int npcs_count, npc; - - /* Get the count of NPCs. */ - vt_key[0].string = "NPCs"; - npcs_count = prop_get_child_count (bundle, "I<-s", vt_key); - - /* Set up each NPC. */ - for (npc = 0; npc < npcs_count; npc++) - { - sc_int walk_count, walk; - - /* Get NPC walk details. */ - vt_key[1].integer = npc; - vt_key[2].string = "Walks"; - walk_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - for (walk = 0; walk < walk_count; walk++) - { - sc_int starttask; - - /* Get start task of walk. */ - vt_key[3].integer = walk; - vt_key[4].string = "StartTask"; - starttask = prop_get_integer (bundle, "I<-sisis", vt_key) - 1; - if (starttask >= 0) - { - sc_vartype_t vt_key2[4], vt_value; - sc_int count; - - /* Count existing walkalerts for the task. */ - vt_key2[0].string = "Tasks"; - vt_key2[1].integer = starttask; - vt_key2[2].string = "NPCWalkAlert"; - count = prop_get_child_count (bundle, "I<-sis", vt_key2); - - /* Add two more -- NPC and walk. */ - vt_key2[3].integer = count; - vt_value.integer = npc; - prop_put (bundle, "I->sisi", vt_value, vt_key2); - vt_key2[3].integer = count + 1; - vt_value.integer = walk; - prop_put (bundle, "I->sisi", vt_value, vt_key2); - } - } - } +parse_add_walkalerts(sc_prop_setref_t bundle) { + sc_vartype_t vt_key[5]; + sc_int npcs_count, npc; + + /* Get the count of NPCs. */ + vt_key[0].string = "NPCs"; + npcs_count = prop_get_child_count(bundle, "I<-s", vt_key); + + /* Set up each NPC. */ + for (npc = 0; npc < npcs_count; npc++) { + sc_int walk_count, walk; + + /* Get NPC walk details. */ + vt_key[1].integer = npc; + vt_key[2].string = "Walks"; + walk_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + for (walk = 0; walk < walk_count; walk++) { + sc_int starttask; + + /* Get start task of walk. */ + vt_key[3].integer = walk; + vt_key[4].string = "StartTask"; + starttask = prop_get_integer(bundle, "I<-sisis", vt_key) - 1; + if (starttask >= 0) { + sc_vartype_t vt_key2[4], vt_value; + sc_int count; + + /* Count existing walkalerts for the task. */ + vt_key2[0].string = "Tasks"; + vt_key2[1].integer = starttask; + vt_key2[2].string = "NPCWalkAlert"; + count = prop_get_child_count(bundle, "I<-sis", vt_key2); + + /* Add two more -- NPC and walk. */ + vt_key2[3].integer = count; + vt_value.integer = npc; + prop_put(bundle, "I->sisi", vt_value, vt_key2); + vt_key2[3].integer = count + 1; + vt_value.integer = walk; + prop_put(bundle, "I->sisi", vt_value, vt_key2); + } + } + } } @@ -3283,56 +3226,51 @@ parse_add_walkalerts (sc_prop_setref_t bundle) * occurs after the TAF file has been successfully parsed. */ static void -parse_add_movetimes (sc_prop_setref_t bundle) -{ - sc_vartype_t vt_key[6]; - sc_int npcs_count, npc; - - /* Get the count of NPCs. */ - vt_key[0].string = "NPCs"; - npcs_count = prop_get_child_count (bundle, "I<-s", vt_key); - - /* Set up each NPC. */ - for (npc = 0; npc < npcs_count; npc++) - { - sc_int walk_count, walk; - - /* Get NPC walk details. */ - vt_key[1].integer = npc; - vt_key[2].string = "Walks"; - walk_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - for (walk = 0; walk < walk_count; walk++) - { - sc_int waittimes; - sc_int *movetimes, index_; - sc_vartype_t vt_value; - - vt_key[3].integer = walk; - vt_key[4].string = "Times"; - waittimes = prop_get_child_count (bundle, "I<-sisis", vt_key); - - movetimes = (sc_int *)sc_malloc ((waittimes + 1) * sizeof (*movetimes)); - memset (movetimes, 0, (waittimes + 1) * sizeof (*movetimes)); - for (index_ = waittimes - 1; index_ >= 0; index_--) - { - vt_key[4].string = "Times"; - vt_key[5].integer = index_; - movetimes[index_] = prop_get_integer (bundle, "I<-sisisi", vt_key) - + movetimes[index_ + 1]; - } - movetimes[waittimes] = -2; - - for (index_ = 0; index_ <= waittimes; index_++) - { - vt_key[4].string = "MoveTimes"; - vt_key[5].integer = index_; - vt_value.integer = movetimes[index_]; - prop_put (bundle, "I->sisisi", vt_value, vt_key); - } - sc_free (movetimes); - } - } +parse_add_movetimes(sc_prop_setref_t bundle) { + sc_vartype_t vt_key[6]; + sc_int npcs_count, npc; + + /* Get the count of NPCs. */ + vt_key[0].string = "NPCs"; + npcs_count = prop_get_child_count(bundle, "I<-s", vt_key); + + /* Set up each NPC. */ + for (npc = 0; npc < npcs_count; npc++) { + sc_int walk_count, walk; + + /* Get NPC walk details. */ + vt_key[1].integer = npc; + vt_key[2].string = "Walks"; + walk_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + for (walk = 0; walk < walk_count; walk++) { + sc_int waittimes; + sc_int *movetimes, index_; + sc_vartype_t vt_value; + + vt_key[3].integer = walk; + vt_key[4].string = "Times"; + waittimes = prop_get_child_count(bundle, "I<-sisis", vt_key); + + movetimes = (sc_int *)sc_malloc((waittimes + 1) * sizeof(*movetimes)); + memset(movetimes, 0, (waittimes + 1) * sizeof(*movetimes)); + for (index_ = waittimes - 1; index_ >= 0; index_--) { + vt_key[4].string = "Times"; + vt_key[5].integer = index_; + movetimes[index_] = prop_get_integer(bundle, "I<-sisisi", vt_key) + + movetimes[index_ + 1]; + } + movetimes[waittimes] = -2; + + for (index_ = 0; index_ <= waittimes; index_++) { + vt_key[4].string = "MoveTimes"; + vt_key[5].integer = index_; + vt_value.integer = movetimes[index_]; + prop_put(bundle, "I->sisisi", vt_value, vt_key); + } + sc_free(movetimes); + } + } } @@ -3343,65 +3281,60 @@ parse_add_movetimes (sc_prop_setref_t bundle) * that ALR replacements look at longer strings before shorter ones. */ static void -parse_add_alrs_index (sc_prop_setref_t bundle) -{ - sc_vartype_t vt_key[3]; - sc_int alr_count, index_, alr; - sc_int *alr_lengths, longest, shortest, length; - - /* Count ALRs, and set invariant part of properties key. */ - vt_key[0].string = "ALRs"; - alr_count = prop_get_child_count (bundle, "I<-s", vt_key); - - /* - * Set up an array of the lengths of ALR original strings, and while at it, - * get the shortest and longest defined. - */ - alr_lengths = (sc_int *)sc_malloc(alr_count * sizeof (*alr_lengths)); - shortest = INT_MAX; - longest = 0; - for (index_ = 0; index_ < alr_count; index_++) - { - const sc_char *original; - - vt_key[1].integer = index_; - vt_key[2].string = "Original"; - original = prop_get_string (bundle, "S<-sis", vt_key); - length = strlen (original); - - alr_lengths[index_] = length; - shortest = (length < shortest) ? length : shortest; - longest = (length > longest) ? length : longest; - } - - /* - * Now write a set of secondary properties that define the order of handling - * for ALRs. Our friend qsort() can't help here as it doesn't define the - * final ordering of equal members, and we need here to retain file ordering - * for ALR originals of the same length. - */ - vt_key[0].string = "ALRs2"; - alr = 0; - for (length = longest; length >= shortest; length--) - { - /* Find and add each ALR of this length. */ - for (index_ = 0; index_ < alr_count; index_++) - { - if (alr_lengths[index_] == length) - { - sc_vartype_t vt_value; - - vt_key[1].integer = alr++; - vt_key[2].string = "ALRIndex"; - vt_value.integer = index_; - prop_put (bundle, "I->sis", vt_value, vt_key); - } - } - } - assert (alr == alr_count); - - /* Done with ALR lengths array. */ - sc_free (alr_lengths); +parse_add_alrs_index(sc_prop_setref_t bundle) { + sc_vartype_t vt_key[3]; + sc_int alr_count, index_, alr; + sc_int *alr_lengths, longest, shortest, length; + + /* Count ALRs, and set invariant part of properties key. */ + vt_key[0].string = "ALRs"; + alr_count = prop_get_child_count(bundle, "I<-s", vt_key); + + /* + * Set up an array of the lengths of ALR original strings, and while at it, + * get the shortest and longest defined. + */ + alr_lengths = (sc_int *)sc_malloc(alr_count * sizeof(*alr_lengths)); + shortest = INT_MAX; + longest = 0; + for (index_ = 0; index_ < alr_count; index_++) { + const sc_char *original; + + vt_key[1].integer = index_; + vt_key[2].string = "Original"; + original = prop_get_string(bundle, "S<-sis", vt_key); + length = strlen(original); + + alr_lengths[index_] = length; + shortest = (length < shortest) ? length : shortest; + longest = (length > longest) ? length : longest; + } + + /* + * Now write a set of secondary properties that define the order of handling + * for ALRs. Our friend qsort() can't help here as it doesn't define the + * final ordering of equal members, and we need here to retain file ordering + * for ALR originals of the same length. + */ + vt_key[0].string = "ALRs2"; + alr = 0; + for (length = longest; length >= shortest; length--) { + /* Find and add each ALR of this length. */ + for (index_ = 0; index_ < alr_count; index_++) { + if (alr_lengths[index_] == length) { + sc_vartype_t vt_value; + + vt_key[1].integer = alr++; + vt_key[2].string = "ALRIndex"; + vt_value.integer = index_; + prop_put(bundle, "I->sis", vt_value, vt_key); + } + } + } + assert(alr == alr_count); + + /* Done with ALR lengths array. */ + sc_free(alr_lengths); } @@ -3413,25 +3346,24 @@ parse_add_alrs_index (sc_prop_setref_t bundle) * zero; only version 4.0 games can embed their resources into the TAF file. */ static void -parse_add_resources_offset (sc_prop_setref_t bundle, sc_tafref_t taf) -{ - sc_vartype_t vt_key[2], vt_value; - sc_bool embedded; - sc_int offset; - - /* - * Get the resources offset from the TAF, or default to zero. The resources - * offset is one byte after the end of game data. - */ - vt_key[0].string = "Globals"; - vt_key[1].string = "Embedded"; - embedded = prop_get_boolean (bundle, "B<-ss", vt_key); - offset = embedded ? taf_get_game_data_length (taf) + 1 : 0; - - /* Add this offset to the properties. */ - vt_key[0].string = "ResourceOffset"; - vt_value.integer = offset; - prop_put (bundle, "I->s", vt_value, vt_key); +parse_add_resources_offset(sc_prop_setref_t bundle, sc_tafref_t taf) { + sc_vartype_t vt_key[2], vt_value; + sc_bool embedded; + sc_int offset; + + /* + * Get the resources offset from the TAF, or default to zero. The resources + * offset is one byte after the end of game data. + */ + vt_key[0].string = "Globals"; + vt_key[1].string = "Embedded"; + embedded = prop_get_boolean(bundle, "B<-ss", vt_key); + offset = embedded ? taf_get_game_data_length(taf) + 1 : 0; + + /* Add this offset to the properties. */ + vt_key[0].string = "ResourceOffset"; + vt_value.integer = offset; + prop_put(bundle, "I->s", vt_value, vt_key); } @@ -3442,34 +3374,32 @@ parse_add_resources_offset (sc_prop_setref_t bundle, sc_tafref_t taf) * for convenience. */ static void -parse_add_version (sc_prop_setref_t bundle, sc_tafref_t taf) -{ - sc_vartype_t vt_key, vt_value; - - /* Add the version integer to the properties. */ - vt_key.string = "Version"; - vt_value.integer = taf_get_version (taf); - prop_put (bundle, "I->s", vt_value, &vt_key); - - /* Add the version string to the properties. */ - switch (taf_get_version (taf)) - { - case TAF_VERSION_400: - vt_value.string = "4.00"; - break; - case TAF_VERSION_390: - vt_value.string = "3.90"; - break; - case TAF_VERSION_380: - vt_value.string = "3.80"; - break; - default: - sc_error ("parse_add_version_string: invalid TAF file version\n"); - vt_value.string = "[Unknown version]"; - break; - } - vt_key.string = "VersionString"; - prop_put (bundle, "S->s", vt_value, &vt_key); +parse_add_version(sc_prop_setref_t bundle, sc_tafref_t taf) { + sc_vartype_t vt_key, vt_value; + + /* Add the version integer to the properties. */ + vt_key.string = "Version"; + vt_value.integer = taf_get_version(taf); + prop_put(bundle, "I->s", vt_value, &vt_key); + + /* Add the version string to the properties. */ + switch (taf_get_version(taf)) { + case TAF_VERSION_400: + vt_value.string = "4.00"; + break; + case TAF_VERSION_390: + vt_value.string = "3.90"; + break; + case TAF_VERSION_380: + vt_value.string = "3.80"; + break; + default: + sc_error("parse_add_version_string: invalid TAF file version\n"); + vt_value.string = "[Unknown version]"; + break; + } + vt_key.string = "VersionString"; + prop_put(bundle, "S->s", vt_value, &vt_key); } @@ -3480,60 +3410,57 @@ parse_add_version (sc_prop_setref_t bundle, sc_tafref_t taf) * it encountered an error reading the TAF file. */ sc_bool parse_game(sc_tafref_t taf, sc_prop_setref_t bundle) { - assert (taf && bundle); - - /* Store the TAF to read from, and the bundle to store into. */ - parse_taf = taf; - parse_bundle = bundle; - parse_schema = parse_select_schema (parse_taf); - parse_depth = 0; - - /* Try parsing, and catch errors from longjmp. */ - if (setjmp (parse_taf_error) == 0) - { - /* Parse a complete game. */ - taf_first_line (parse_taf); - parse_tafline = 0; - parse_class ("<_GAME_>"); - } - else - { - /* Error with one of the TAF file lines. */ - parse_clear_v400_resources_table (); - parse_taf = NULL; - parse_bundle = NULL; - parse_schema = NULL; - parse_depth = 0; - return FALSE; - } - - /* Free the accumulated version 4.0 resources details. */ - parse_clear_v400_resources_table (); - - /* See if we reached the end of the TAF. */ - if (taf_more_lines (parse_taf)) - sc_error ("parse_game: unexpected trailing data\n"); - - /* Append post-processing walkalerts and move times. */ - parse_add_walkalerts (parse_bundle); - parse_add_movetimes (parse_bundle); - - /* Append sorted ALR list and resources offset. */ - parse_add_alrs_index (parse_bundle); - parse_add_resources_offset (parse_bundle, parse_taf); - - /* Add a note of the TAF file version. */ - parse_add_version (parse_bundle, parse_taf); - - /* Trim excess allocations from properties. */ - prop_solidify (parse_bundle); - - /* Return successfully. */ - parse_taf = NULL; - parse_bundle = NULL; - parse_schema = NULL; - parse_depth = 0; - return TRUE; + assert(taf && bundle); + + /* Store the TAF to read from, and the bundle to store into. */ + parse_taf = taf; + parse_bundle = bundle; + parse_schema = parse_select_schema(parse_taf); + parse_depth = 0; + + /* Try parsing, and catch errors from longjmp. */ + if (setjmp(parse_taf_error) == 0) { + /* Parse a complete game. */ + taf_first_line(parse_taf); + parse_tafline = 0; + parse_class("<_GAME_>"); + } else { + /* Error with one of the TAF file lines. */ + parse_clear_v400_resources_table(); + parse_taf = NULL; + parse_bundle = NULL; + parse_schema = NULL; + parse_depth = 0; + return FALSE; + } + + /* Free the accumulated version 4.0 resources details. */ + parse_clear_v400_resources_table(); + + /* See if we reached the end of the TAF. */ + if (taf_more_lines(parse_taf)) + sc_error("parse_game: unexpected trailing data\n"); + + /* Append post-processing walkalerts and move times. */ + parse_add_walkalerts(parse_bundle); + parse_add_movetimes(parse_bundle); + + /* Append sorted ALR list and resources offset. */ + parse_add_alrs_index(parse_bundle); + parse_add_resources_offset(parse_bundle, parse_taf); + + /* Add a note of the TAF file version. */ + parse_add_version(parse_bundle, parse_taf); + + /* Trim excess allocations from properties. */ + prop_solidify(parse_bundle); + + /* Return successfully. */ + parse_taf = NULL; + parse_bundle = NULL; + parse_schema = NULL; + parse_depth = 0; + return TRUE; } @@ -3543,9 +3470,8 @@ sc_bool parse_game(sc_tafref_t taf, sc_prop_setref_t bundle) { * Set parse tracing on/off. */ void -parse_debug_trace (sc_bool flag) -{ - parse_trace = flag; +parse_debug_trace(sc_bool flag) { + parse_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sctasks.cpp b/engines/glk/adrift/sctasks.cpp index 4ced0c5099..8273affef6 100644 --- a/engines/glk/adrift/sctasks.cpp +++ b/engines/glk/adrift/sctasks.cpp @@ -57,43 +57,38 @@ static sc_bool task_trace = FALSE; * hints. */ static const sc_char * -task_get_hint_common (sc_gameref_t game, sc_int task, const sc_char *hint) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *retval; - - /* Look up and return the requested hint string. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = hint; - retval = prop_get_string (bundle, "S<-sis", vt_key); - return retval; +task_get_hint_common(sc_gameref_t game, sc_int task, const sc_char *hint) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *retval; + + /* Look up and return the requested hint string. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = hint; + retval = prop_get_string(bundle, "S<-sis", vt_key); + return retval; } const sc_char * -task_get_hint_question (sc_gameref_t game, sc_int task) -{ - return task_get_hint_common (game, task, "Question"); +task_get_hint_question(sc_gameref_t game, sc_int task) { + return task_get_hint_common(game, task, "Question"); } const sc_char * -task_get_hint_subtle (sc_gameref_t game, sc_int task) -{ - return task_get_hint_common (game, task, "Hint1"); +task_get_hint_subtle(sc_gameref_t game, sc_int task) { + return task_get_hint_common(game, task, "Hint1"); } const sc_char * -task_get_hint_unsubtle (sc_gameref_t game, sc_int task) -{ - return task_get_hint_common (game, task, "Hint2"); +task_get_hint_unsubtle(sc_gameref_t game, sc_int task) { + return task_get_hint_common(game, task, "Hint2"); } sc_bool -task_has_hints (sc_gameref_t game, sc_int task) -{ - /* A non-empty question implies hints available. */ - return !sc_strempty (task_get_hint_question (game, task)); +task_has_hints(sc_gameref_t game, sc_int task) { + /* A non-empty question implies hints available. */ + return !sc_strempty(task_get_hint_question(game, task)); } @@ -104,72 +99,68 @@ task_has_hints (sc_gameref_t game, sc_int task) * is runnable in the given direction. */ sc_bool -task_can_run_task_directional (sc_gameref_t game, - sc_int task, sc_bool forwards) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int type; - - /* If already run, non-repeatable tasks are not re-runnable forwards. */ - if (forwards && gs_task_done (game, task)) - { - sc_bool repeatable; - const sc_char *repeattext; - - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Repeatable"; - repeatable = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!repeatable) - return FALSE; - - vt_key[2].string = "RepeatText"; - repeattext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (repeattext)) - return FALSE; - } - - /* If checking for reverse, test the reversibility flag. */ - if (!forwards) - { - sc_bool reversible; - - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Reversible"; - reversible = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!reversible) - return FALSE; - } - - /* Check room list for the task and return it. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Where"; - vt_key[3].string = "Type"; - type = prop_get_integer (bundle, "I<-siss", vt_key); - switch (type) - { - case ROOMLIST_NO_ROOMS: - return FALSE; - case ROOMLIST_ALL_ROOMS: - return TRUE; - - case ROOMLIST_ONE_ROOM: - vt_key[3].string = "Room"; - return prop_get_integer (bundle, - "I<-siss", vt_key) == gs_playerroom (game); - - case ROOMLIST_SOME_ROOMS: - vt_key[3].string = "Rooms"; - vt_key[4].integer = gs_playerroom (game); - return prop_get_boolean (bundle, "B<-sissi", vt_key); - - default: - sc_fatal ("task_can_run_task_directional: invalid type, %ld\n", type); - return FALSE; - } +task_can_run_task_directional(sc_gameref_t game, + sc_int task, sc_bool forwards) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int type; + + /* If already run, non-repeatable tasks are not re-runnable forwards. */ + if (forwards && gs_task_done(game, task)) { + sc_bool repeatable; + const sc_char *repeattext; + + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Repeatable"; + repeatable = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!repeatable) + return FALSE; + + vt_key[2].string = "RepeatText"; + repeattext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(repeattext)) + return FALSE; + } + + /* If checking for reverse, test the reversibility flag. */ + if (!forwards) { + sc_bool reversible; + + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Reversible"; + reversible = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!reversible) + return FALSE; + } + + /* Check room list for the task and return it. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Where"; + vt_key[3].string = "Type"; + type = prop_get_integer(bundle, "I<-siss", vt_key); + switch (type) { + case ROOMLIST_NO_ROOMS: + return FALSE; + case ROOMLIST_ALL_ROOMS: + return TRUE; + + case ROOMLIST_ONE_ROOM: + vt_key[3].string = "Room"; + return prop_get_integer(bundle, + "I<-siss", vt_key) == gs_playerroom(game); + + case ROOMLIST_SOME_ROOMS: + vt_key[3].string = "Rooms"; + vt_key[4].integer = gs_playerroom(game); + return prop_get_boolean(bundle, "B<-sissi", vt_key); + + default: + sc_fatal("task_can_run_task_directional: invalid type, %ld\n", type); + return FALSE; + } } @@ -179,15 +170,14 @@ task_can_run_task_directional (sc_gameref_t game, * Returns TRUE if the task can be run in either direction. */ sc_bool -task_can_run_task (sc_gameref_t game, sc_int task) -{ - /* - * Testing reversible tasks first may be a little more efficient if they - * aren't common in games. There is, though, probably a little bit of - * redundant work going on here. - */ - return task_can_run_task_directional (game, task, FALSE) - || task_can_run_task_directional (game, task, TRUE); +task_can_run_task(sc_gameref_t game, sc_int task) { + /* + * Testing reversible tasks first may be a little more efficient if they + * aren't common in games. There is, though, probably a little bit of + * redundant work going on here. + */ + return task_can_run_task_directional(game, task, FALSE) + || task_can_run_task_directional(game, task, TRUE); } @@ -197,114 +187,102 @@ task_can_run_task (sc_gameref_t game, sc_int task) * Move an object to a place. */ static void -task_move_object (sc_gameref_t game, sc_int object, sc_int var2, sc_int var3) -{ - const sc_var_setref_t vars = gs_get_vars (game); - - /* Select action depending on var2. */ - switch (var2) - { - case 0: /* To room */ - if (var3 == 0) - { - if (task_trace) - sc_trace ("Task: moving object %ld to hidden\n", object); - - gs_object_make_hidden (game, object); - } - else - { - if (task_trace) - { - sc_trace ("Task: moving object %ld to room %ld\n", - object, var3 - 1); - } - - if (var3 == 0) - gs_object_player_get (game, object); - else - gs_object_to_room (game, object, var3 - 1); - } - break; - - case 1: /* To roomgroup part */ - if (task_trace) - { - sc_trace ("Task: moving object %ld to random room in group %ld\n", - object, var3); - } - - gs_object_to_room (game, object, - lib_random_roomgroup_member (game, var3)); - break; - - case 2: /* Into object */ - if (task_trace) - sc_trace ("Task: moving object %ld into %ld\n", object, var3); - - gs_object_move_into (game, object, obj_container_object (game, var3)); - break; - - case 3: /* Onto object */ - if (task_trace) - sc_trace ("Task: moving object %ld onto %ld\n", object, var3); - - gs_object_move_onto (game, object, obj_surface_object (game, var3)); - break; - - case 4: /* Held by */ - if (task_trace) - sc_trace ("Task: moving object %ld to held by %ld\n", object, var3); - - if (var3 == 0) /* Player */ - gs_object_player_get (game, object); - else if (var3 == 1) /* Ref character */ - gs_object_npc_get (game, object, var_get_ref_character (vars)); - else /* NPC id */ - gs_object_npc_get (game, object, var3 - 2); - break; - - case 5: /* Worn by */ - if (task_trace) - sc_trace ("Task: moving object %ld to worn by %ld\n", object, var3); - - if (var3 == 0) /* Player */ - gs_object_player_wear (game, object); - else if (var3 == 1) /* Ref character */ - gs_object_npc_wear (game, object, var_get_ref_character (vars)); - else /* NPC id */ - gs_object_npc_wear (game, object, var3 - 2); - break; - - case 6: /* Same room as */ - { - sc_int room, npc; - - if (task_trace) - { - sc_trace ("Task: moving object %ld to same room as %ld\n", - object, var3); - } - - if (var3 == 0) /* Player */ - room = gs_playerroom (game); - else if (var3 == 1) /* Ref character */ - { - npc = var_get_ref_character (vars); - room = gs_npc_location (game, npc) - 1; - } - else /* NPC id */ - { - npc = var3 - 2; - room = gs_npc_location (game, npc) - 1; - } - gs_object_to_room (game, object, room); - break; - } - - default: - sc_fatal ("task_move_object: unknown move type, %ld\n", var2); - } +task_move_object(sc_gameref_t game, sc_int object, sc_int var2, sc_int var3) { + const sc_var_setref_t vars = gs_get_vars(game); + + /* Select action depending on var2. */ + switch (var2) { + case 0: /* To room */ + if (var3 == 0) { + if (task_trace) + sc_trace("Task: moving object %ld to hidden\n", object); + + gs_object_make_hidden(game, object); + } else { + if (task_trace) { + sc_trace("Task: moving object %ld to room %ld\n", + object, var3 - 1); + } + + if (var3 == 0) + gs_object_player_get(game, object); + else + gs_object_to_room(game, object, var3 - 1); + } + break; + + case 1: /* To roomgroup part */ + if (task_trace) { + sc_trace("Task: moving object %ld to random room in group %ld\n", + object, var3); + } + + gs_object_to_room(game, object, + lib_random_roomgroup_member(game, var3)); + break; + + case 2: /* Into object */ + if (task_trace) + sc_trace("Task: moving object %ld into %ld\n", object, var3); + + gs_object_move_into(game, object, obj_container_object(game, var3)); + break; + + case 3: /* Onto object */ + if (task_trace) + sc_trace("Task: moving object %ld onto %ld\n", object, var3); + + gs_object_move_onto(game, object, obj_surface_object(game, var3)); + break; + + case 4: /* Held by */ + if (task_trace) + sc_trace("Task: moving object %ld to held by %ld\n", object, var3); + + if (var3 == 0) /* Player */ + gs_object_player_get(game, object); + else if (var3 == 1) /* Ref character */ + gs_object_npc_get(game, object, var_get_ref_character(vars)); + else /* NPC id */ + gs_object_npc_get(game, object, var3 - 2); + break; + + case 5: /* Worn by */ + if (task_trace) + sc_trace("Task: moving object %ld to worn by %ld\n", object, var3); + + if (var3 == 0) /* Player */ + gs_object_player_wear(game, object); + else if (var3 == 1) /* Ref character */ + gs_object_npc_wear(game, object, var_get_ref_character(vars)); + else /* NPC id */ + gs_object_npc_wear(game, object, var3 - 2); + break; + + case 6: { /* Same room as */ + sc_int room, npc; + + if (task_trace) { + sc_trace("Task: moving object %ld to same room as %ld\n", + object, var3); + } + + if (var3 == 0) /* Player */ + room = gs_playerroom(game); + else if (var3 == 1) { /* Ref character */ + npc = var_get_ref_character(vars); + room = gs_npc_location(game, npc) - 1; + } else { /* NPC id */ + npc = var3 - 2; + room = gs_npc_location(game, npc) - 1; + } + gs_object_to_room(game, object, room); + break; + } + + default: + sc_fatal("task_move_object: unknown move type, %ld\n", var2); + } } @@ -314,41 +292,37 @@ task_move_object (sc_gameref_t game, sc_int object, sc_int var2, sc_int var3) * Demultiplex an object move action and execute it. */ static void -task_run_move_object_action (sc_gameref_t game, - sc_int var1, sc_int var2, sc_int var3) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int object; - - /* Select depending on value in var1. */ - switch (var1) - { - case 0: /* All held */ - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_HELD_PLAYER) - task_move_object (game, object, var2, var3); - } - break; - - case 1: /* All worn */ - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_WORN_PLAYER) - task_move_object (game, object, var2, var3); - } - break; - - case 2: /* Ref object */ - object = var_get_ref_object (vars); - task_move_object (game, object, var2, var3); - break; - - default: /* Dynamic object */ - object = obj_dynamic_object (game, var1 - 3); - task_move_object (game, object, var2, var3); - break; - } +task_run_move_object_action(sc_gameref_t game, + sc_int var1, sc_int var2, sc_int var3) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int object; + + /* Select depending on value in var1. */ + switch (var1) { + case 0: /* All held */ + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_HELD_PLAYER) + task_move_object(game, object, var2, var3); + } + break; + + case 1: /* All worn */ + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_WORN_PLAYER) + task_move_object(game, object, var2, var3); + } + break; + + case 2: /* Ref object */ + object = var_get_ref_object(vars); + task_move_object(game, object, var2, var3); + break; + + default: /* Dynamic object */ + object = obj_dynamic_object(game, var1 - 3); + task_move_object(game, object, var2, var3); + break; + } } @@ -358,21 +332,20 @@ task_run_move_object_action (sc_gameref_t game, * Move an NPC to a given room. */ static void -task_move_npc_to_room (sc_gameref_t game, sc_int npc, sc_int room) -{ - if (task_trace) - sc_trace ("Task: moving NPC %ld to room %ld\n", npc, room); - - /* Update the NPC's state. */ - if (room < gs_room_count (game)) - gs_set_npc_location (game, npc, room + 1); - else - gs_set_npc_location (game, npc, - lib_random_roomgroup_member (game, - room - gs_room_count (game)) + 1); - - gs_set_npc_parent (game, npc, -1); - gs_set_npc_position (game, npc, 0); +task_move_npc_to_room(sc_gameref_t game, sc_int npc, sc_int room) { + if (task_trace) + sc_trace("Task: moving NPC %ld to room %ld\n", npc, room); + + /* Update the NPC's state. */ + if (room < gs_room_count(game)) + gs_set_npc_location(game, npc, room + 1); + else + gs_set_npc_location(game, npc, + lib_random_roomgroup_member(game, + room - gs_room_count(game)) + 1); + + gs_set_npc_parent(game, npc, -1); + gs_set_npc_position(game, npc, 0); } @@ -382,164 +355,149 @@ task_move_npc_to_room (sc_gameref_t game, sc_int npc, sc_int room) * Move player or NPC. */ static void -task_run_move_npc_action (sc_gameref_t game, - sc_int var1, sc_int var2, sc_int var3) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int npc, room, ref_npc = -1; - - /* Player or NPC? */ - if (var1 == 0) - { - /* Player -- decide where to move player to. */ - switch (var2) - { - case 0: /* To room */ - gs_move_player_to_room (game, var3); - return; - - case 1: /* To roomgroup part */ - if (task_trace) - { - sc_trace ("Task: moving player to random room in group %ld\n", - var3); - } - - gs_move_player_to_room (game, - lib_random_roomgroup_member (game, var3)); - return; - - case 2: /* To same room as... */ - switch (var3) - { - case 0: /* ...player! */ - return; - case 1: /* ...referenced NPC */ - npc = var_get_ref_character (vars); - break; - default: /* ...specified NPC */ - npc = var3 - 2; - break; - } - - if (task_trace) - sc_trace ("Task: moving player to same room as NPC %ld\n", npc); - - room = gs_npc_location (game, npc) - 1; - if (room < 0) - { - if (task_trace) - sc_trace ("Task: silently suppressed player move to hidden\n"); - } - else - gs_move_player_to_room (game, room); - return; - - case 3: /* To standing on */ - gs_set_playerposition (game, 0); - gs_set_playerparent (game, obj_standable_object (game, var3 - 1)); - return; - - case 4: /* To sitting on */ - gs_set_playerposition (game, 1); - gs_set_playerparent (game, obj_standable_object (game, var3 - 1)); - return; - - case 5: /* To lying on */ - gs_set_playerposition (game, 2); - gs_set_playerparent (game, obj_lieable_object (game, var3 - 1)); - return; - - default: - sc_fatal ("task_run_move_npc_action:" - " unknown player move type, %ld\n", var2); - return; - } - } - else - { - /* NPC -- first find which NPC to move about. */ - if (var1 == 1) - npc = var_get_ref_character (vars); - else - npc = var1 - 2; - - /* Decide where to move the NPC to. */ - switch (var2) - { - case 0: /* To room */ - task_move_npc_to_room (game, npc, var3 - 1); - return; - - case 1: /* To roomgroup part */ - if (task_trace) - { - sc_trace ("Task: moving NPC %ld to random room in group %ld\n", - npc, var3); - } - - task_move_npc_to_room (game, npc, - lib_random_roomgroup_member (game, var3)); - return; - - case 2: /* To same room as... */ - switch (var3) - { - case 0: /* ...player */ - if (task_trace) - { - sc_trace ("Task: moving NPC %ld to same room as player\n", - npc); - } - - task_move_npc_to_room (game, npc, gs_playerroom (game)); - break; - case 1: /* ...referenced NPC */ - ref_npc = var_get_ref_character (vars); - if (task_trace) - { - sc_trace ("Task: moving NPC %ld to" - " same room as referenced NPC %ld\n", npc, ref_npc); - } - - room = gs_npc_location (game, ref_npc) - 1; - task_move_npc_to_room (game, npc, room); - break; - default: /* ...specified NPC */ - ref_npc = var3 - 2; - if (task_trace) - { - sc_trace ("Task: moving NPC %ld to" - " same room as NPC %ld\n", npc, ref_npc); - } - - room = gs_npc_location (game, ref_npc) - 1; - task_move_npc_to_room (game, npc, room); - break; - } - return; - - case 3: /* To standing on */ - gs_set_npc_position (game, npc, 0); - gs_set_npc_parent (game, npc, obj_standable_object (game, var3)); - return; - - case 4: /* To sitting on */ - gs_set_npc_position (game, npc, 1); - gs_set_npc_parent (game, npc, obj_standable_object (game, var3)); - return; - - case 5: /* To lying on */ - gs_set_npc_position (game, npc, 2); - gs_set_npc_parent (game, npc, obj_lieable_object (game, var3)); - return; - - default: - sc_fatal ("task_run_move_npc_action:" - " unknown NPC move type, %ld\n", var2); - return; - } - } +task_run_move_npc_action(sc_gameref_t game, + sc_int var1, sc_int var2, sc_int var3) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int npc, room, ref_npc = -1; + + /* Player or NPC? */ + if (var1 == 0) { + /* Player -- decide where to move player to. */ + switch (var2) { + case 0: /* To room */ + gs_move_player_to_room(game, var3); + return; + + case 1: /* To roomgroup part */ + if (task_trace) { + sc_trace("Task: moving player to random room in group %ld\n", + var3); + } + + gs_move_player_to_room(game, + lib_random_roomgroup_member(game, var3)); + return; + + case 2: /* To same room as... */ + switch (var3) { + case 0: /* ...player! */ + return; + case 1: /* ...referenced NPC */ + npc = var_get_ref_character(vars); + break; + default: /* ...specified NPC */ + npc = var3 - 2; + break; + } + + if (task_trace) + sc_trace("Task: moving player to same room as NPC %ld\n", npc); + + room = gs_npc_location(game, npc) - 1; + if (room < 0) { + if (task_trace) + sc_trace("Task: silently suppressed player move to hidden\n"); + } else + gs_move_player_to_room(game, room); + return; + + case 3: /* To standing on */ + gs_set_playerposition(game, 0); + gs_set_playerparent(game, obj_standable_object(game, var3 - 1)); + return; + + case 4: /* To sitting on */ + gs_set_playerposition(game, 1); + gs_set_playerparent(game, obj_standable_object(game, var3 - 1)); + return; + + case 5: /* To lying on */ + gs_set_playerposition(game, 2); + gs_set_playerparent(game, obj_lieable_object(game, var3 - 1)); + return; + + default: + sc_fatal("task_run_move_npc_action:" + " unknown player move type, %ld\n", var2); + return; + } + } else { + /* NPC -- first find which NPC to move about. */ + if (var1 == 1) + npc = var_get_ref_character(vars); + else + npc = var1 - 2; + + /* Decide where to move the NPC to. */ + switch (var2) { + case 0: /* To room */ + task_move_npc_to_room(game, npc, var3 - 1); + return; + + case 1: /* To roomgroup part */ + if (task_trace) { + sc_trace("Task: moving NPC %ld to random room in group %ld\n", + npc, var3); + } + + task_move_npc_to_room(game, npc, + lib_random_roomgroup_member(game, var3)); + return; + + case 2: /* To same room as... */ + switch (var3) { + case 0: /* ...player */ + if (task_trace) { + sc_trace("Task: moving NPC %ld to same room as player\n", + npc); + } + + task_move_npc_to_room(game, npc, gs_playerroom(game)); + break; + case 1: /* ...referenced NPC */ + ref_npc = var_get_ref_character(vars); + if (task_trace) { + sc_trace("Task: moving NPC %ld to" + " same room as referenced NPC %ld\n", npc, ref_npc); + } + + room = gs_npc_location(game, ref_npc) - 1; + task_move_npc_to_room(game, npc, room); + break; + default: /* ...specified NPC */ + ref_npc = var3 - 2; + if (task_trace) { + sc_trace("Task: moving NPC %ld to" + " same room as NPC %ld\n", npc, ref_npc); + } + + room = gs_npc_location(game, ref_npc) - 1; + task_move_npc_to_room(game, npc, room); + break; + } + return; + + case 3: /* To standing on */ + gs_set_npc_position(game, npc, 0); + gs_set_npc_parent(game, npc, obj_standable_object(game, var3)); + return; + + case 4: /* To sitting on */ + gs_set_npc_position(game, npc, 1); + gs_set_npc_parent(game, npc, obj_standable_object(game, var3)); + return; + + case 5: /* To lying on */ + gs_set_npc_position(game, npc, 2); + gs_set_npc_parent(game, npc, obj_lieable_object(game, var3)); + return; + + default: + sc_fatal("task_run_move_npc_action:" + " unknown NPC move type, %ld\n", var2); + return; + } + } } @@ -549,59 +507,51 @@ task_run_move_npc_action (sc_gameref_t game, * Change the status of an object. */ static void -task_run_change_object_status (sc_gameref_t game, sc_int var1, sc_int var2) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int object, openable, lockable; - - if (task_trace) - { - sc_trace ("Task: setting status of stateful object %ld to %ld\n", - var1, var2); - } - - /* Identify the target object. */ - object = obj_stateful_object (game, var1); - - /* See if openable. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Openable"; - openable = prop_get_integer (bundle, "I<-sis", vt_key); - if (openable > 0) - { - /* See if lockable. */ - vt_key[2].string = "Key"; - lockable = prop_get_integer (bundle, "I<-sis", vt_key); - if (lockable >= 0) - { - /* Lockable. */ - if (var2 <= 2) - gs_set_object_openness (game, object, var2 + 5); - else - gs_set_object_state (game, object, var2 - 2); - } - else - { - /* Not lockable, though openable. */ - if (var2 <= 1) - gs_set_object_openness (game, object, var2 + 5); - else - gs_set_object_state (game, object, var2 - 1); - } - } - else - /* Not openable. */ - gs_set_object_state (game, object, var2 + 1); - - if (task_trace) - { - sc_trace ("Task: openness of object %ld is now %ld\n", - object, gs_object_openness (game, object)); - sc_trace ("Task: state of object %ld is now %ld\n", - object, gs_object_state (game, object)); - } +task_run_change_object_status(sc_gameref_t game, sc_int var1, sc_int var2) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int object, openable, lockable; + + if (task_trace) { + sc_trace("Task: setting status of stateful object %ld to %ld\n", + var1, var2); + } + + /* Identify the target object. */ + object = obj_stateful_object(game, var1); + + /* See if openable. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Openable"; + openable = prop_get_integer(bundle, "I<-sis", vt_key); + if (openable > 0) { + /* See if lockable. */ + vt_key[2].string = "Key"; + lockable = prop_get_integer(bundle, "I<-sis", vt_key); + if (lockable >= 0) { + /* Lockable. */ + if (var2 <= 2) + gs_set_object_openness(game, object, var2 + 5); + else + gs_set_object_state(game, object, var2 - 2); + } else { + /* Not lockable, though openable. */ + if (var2 <= 1) + gs_set_object_openness(game, object, var2 + 5); + else + gs_set_object_state(game, object, var2 - 1); + } + } else + /* Not openable. */ + gs_set_object_state(game, object, var2 + 1); + + if (task_trace) { + sc_trace("Task: openness of object %ld is now %ld\n", + object, gs_object_openness(game, object)); + sc_trace("Task: state of object %ld is now %ld\n", + object, gs_object_state(game, object)); + } } @@ -611,164 +561,151 @@ task_run_change_object_status (sc_gameref_t game, sc_int var1, sc_int var2) * Change a variable's value in inscrutable ways. */ static void -task_run_change_variable_action (sc_gameref_t game, - sc_int var1, sc_int var2, sc_int var3, - const sc_char *expr, sc_int var5) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[3]; - const sc_char *name, *string; - sc_char *mutable_string; - sc_int type, value; - - /* - * At this point, we need to checkpoint the filter. We're about to change - * a variable value, so interpolating here before doing that ensures that - * any currently buffered text gets the values that were set when the text - * was buffered. - */ - pf_checkpoint (filter, vars, bundle); - - /* Get the name and type of the variable being addressed. */ - vt_key[0].string = "Variables"; - vt_key[1].integer = var1; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Type"; - type = prop_get_integer (bundle, "I<-sis", vt_key); - - /* Select first based on variable type. */ - switch (type) - { - case TAFVAR_NUMERIC: /* Integer */ - - /* Select again based on action type. */ - switch (var2) - { - case 0: /* Var = */ - if (task_trace) - sc_trace ("Task: variable %ld (%s) = %ld\n", var1, name, var3); - - var_put_integer (vars, name, var3); - return; - - case 1: /* Var += */ - if (task_trace) - sc_trace ("Task: variable %ld (%s) += %ld\n", var1, name, var3); - - value = var_get_integer (vars, name) + var3; - var_put_integer (vars, name, value); - return; - - case 2: /* Var = rnd(range) */ - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = random(%ld,%ld)\n", - var1, name, var3, var5); - } - - value = sc_randomint (var3, var5); - var_put_integer (vars, name, value); - return; - - case 3: /* Var += rnd(range) */ - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) += random(%ld,%ld)\n", - var1, name, var3, var5); - } - - value = var_get_integer (vars, name) + sc_randomint (var3, var5); - var_put_integer (vars, name, value); - return; - - case 4: /* Var = ref */ - value = var_get_ref_number (vars); - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = ref, %ld\n", - var1, name, value); - } - - var_put_integer (vars, name, value); - return; - - case 5: /* Var = expr */ - if (!expr_eval_numeric_expression (expr, vars, &value)) - { - sc_error ("task_run_change_variable_action:" - " invalid expression, %s\n", expr); - value = 0; - } - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = %s, %ld\n", - var1, name, expr, value); - } - - var_put_integer (vars, name, value); - return; - - default: - sc_fatal ("task_run_change_variable_action:" - " unknown integer change type, %ld\n", var2); - } - - case TAFVAR_STRING: /* String */ - - /* Select again based on action type. */ - switch (var2) - { - case 0: /* Var = text literal */ - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = \"%s\"\n", - var1, name, expr); - } - - var_put_string (vars, name, expr); - return; - - case 1: /* Var = ref */ - string = var_get_ref_text (vars); - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = ref, \"%s\"\n", - var1, name, string); - } - - var_put_string (vars, name, string); - return; - - case 2: /* Var = expr */ - if (!expr_eval_string_expression (expr, vars, &mutable_string)) - { - sc_error ("task_run_change_variable_action:" - " invalid string expression, %s\n", expr); - mutable_string = (sc_char *)sc_malloc (strlen ("[expr error]") + 1); - strcpy (mutable_string, "[expr error]"); - } - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = %s, %s\n", - var1, name, expr, mutable_string); - } - - var_put_string (vars, name, mutable_string); - sc_free (mutable_string); - return; - - default: - sc_fatal ("task_run_change_variable_action:" - " unknown string change type, %ld\n", var2); - } - - default: - sc_fatal ("task_run_change_variable_action:" - " invalid variable type, %ld\n", type); - } +task_run_change_variable_action(sc_gameref_t game, + sc_int var1, sc_int var2, sc_int var3, + const sc_char *expr, sc_int var5) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[3]; + const sc_char *name, *string; + sc_char *mutable_string; + sc_int type, value; + + /* + * At this point, we need to checkpoint the filter. We're about to change + * a variable value, so interpolating here before doing that ensures that + * any currently buffered text gets the values that were set when the text + * was buffered. + */ + pf_checkpoint(filter, vars, bundle); + + /* Get the name and type of the variable being addressed. */ + vt_key[0].string = "Variables"; + vt_key[1].integer = var1; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Type"; + type = prop_get_integer(bundle, "I<-sis", vt_key); + + /* Select first based on variable type. */ + switch (type) { + case TAFVAR_NUMERIC: /* Integer */ + + /* Select again based on action type. */ + switch (var2) { + case 0: /* Var = */ + if (task_trace) + sc_trace("Task: variable %ld (%s) = %ld\n", var1, name, var3); + + var_put_integer(vars, name, var3); + return; + + case 1: /* Var += */ + if (task_trace) + sc_trace("Task: variable %ld (%s) += %ld\n", var1, name, var3); + + value = var_get_integer(vars, name) + var3; + var_put_integer(vars, name, value); + return; + + case 2: /* Var = rnd(range) */ + if (task_trace) { + sc_trace("Task: variable %ld (%s) = random(%ld,%ld)\n", + var1, name, var3, var5); + } + + value = sc_randomint(var3, var5); + var_put_integer(vars, name, value); + return; + + case 3: /* Var += rnd(range) */ + if (task_trace) { + sc_trace("Task: variable %ld (%s) += random(%ld,%ld)\n", + var1, name, var3, var5); + } + + value = var_get_integer(vars, name) + sc_randomint(var3, var5); + var_put_integer(vars, name, value); + return; + + case 4: /* Var = ref */ + value = var_get_ref_number(vars); + if (task_trace) { + sc_trace("Task: variable %ld (%s) = ref, %ld\n", + var1, name, value); + } + + var_put_integer(vars, name, value); + return; + + case 5: /* Var = expr */ + if (!expr_eval_numeric_expression(expr, vars, &value)) { + sc_error("task_run_change_variable_action:" + " invalid expression, %s\n", expr); + value = 0; + } + if (task_trace) { + sc_trace("Task: variable %ld (%s) = %s, %ld\n", + var1, name, expr, value); + } + + var_put_integer(vars, name, value); + return; + + default: + sc_fatal("task_run_change_variable_action:" + " unknown integer change type, %ld\n", var2); + } + + case TAFVAR_STRING: /* String */ + + /* Select again based on action type. */ + switch (var2) { + case 0: /* Var = text literal */ + if (task_trace) { + sc_trace("Task: variable %ld (%s) = \"%s\"\n", + var1, name, expr); + } + + var_put_string(vars, name, expr); + return; + + case 1: /* Var = ref */ + string = var_get_ref_text(vars); + if (task_trace) { + sc_trace("Task: variable %ld (%s) = ref, \"%s\"\n", + var1, name, string); + } + + var_put_string(vars, name, string); + return; + + case 2: /* Var = expr */ + if (!expr_eval_string_expression(expr, vars, &mutable_string)) { + sc_error("task_run_change_variable_action:" + " invalid string expression, %s\n", expr); + mutable_string = (sc_char *)sc_malloc(strlen("[expr error]") + 1); + strcpy(mutable_string, "[expr error]"); + } + if (task_trace) { + sc_trace("Task: variable %ld (%s) = %s, %s\n", + var1, name, expr, mutable_string); + } + + var_put_string(vars, name, mutable_string); + sc_free(mutable_string); + return; + + default: + sc_fatal("task_run_change_variable_action:" + " unknown string change type, %ld\n", var2); + } + + default: + sc_fatal("task_run_change_variable_action:" + " invalid variable type, %ld\n", type); + } } @@ -778,64 +715,56 @@ task_run_change_variable_action (sc_gameref_t game, * Change game score. */ static void -task_run_change_score_action (sc_gameref_t game, sc_int task, sc_int var1) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - - /* Increasing or decreasing the score? */ - if (var1 > 0) - { - sc_bool increase_score; - - /* See if this task is already scored. */ - increase_score = !gs_task_scored (game, task); - if (!increase_score) - { - sc_vartype_t vt_key[3]; - sc_int version; - - if (task_trace) - sc_trace ("Task: already scored task %ld\n", var1); - - /* Version 3.8 games permit tasks to rescore. */ - vt_key[0].string = "Version"; - version = prop_get_integer (bundle, "I<-s", vt_key); - if (version == TAF_VERSION_380) - { - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "SingleScore"; - increase_score = !prop_get_boolean (bundle, "B<-sis", vt_key); - - if (increase_score) - { - if (task_trace) - sc_trace ("Task: rescoring version 3.8 task anyway\n"); - } - } - } - - /* - * Increase the score if not yet scored or a version 3.8 multiple - * scoring task, and note as a scored task. - */ - if (increase_score) - { - if (task_trace) - sc_trace ("Task: increased score by %ld\n", var1); - - game->score += var1; - gs_set_task_scored (game, task, TRUE); - } - } - else if (var1 < 0) - { - /* Decrease the score. */ - if (task_trace) - sc_trace ("Task: decreased score by %ld\n", -(var1)); - - game->score += var1; - } +task_run_change_score_action(sc_gameref_t game, sc_int task, sc_int var1) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + + /* Increasing or decreasing the score? */ + if (var1 > 0) { + sc_bool increase_score; + + /* See if this task is already scored. */ + increase_score = !gs_task_scored(game, task); + if (!increase_score) { + sc_vartype_t vt_key[3]; + sc_int version; + + if (task_trace) + sc_trace("Task: already scored task %ld\n", var1); + + /* Version 3.8 games permit tasks to rescore. */ + vt_key[0].string = "Version"; + version = prop_get_integer(bundle, "I<-s", vt_key); + if (version == TAF_VERSION_380) { + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "SingleScore"; + increase_score = !prop_get_boolean(bundle, "B<-sis", vt_key); + + if (increase_score) { + if (task_trace) + sc_trace("Task: rescoring version 3.8 task anyway\n"); + } + } + } + + /* + * Increase the score if not yet scored or a version 3.8 multiple + * scoring task, and note as a scored task. + */ + if (increase_score) { + if (task_trace) + sc_trace("Task: increased score by %ld\n", var1); + + game->score += var1; + gs_set_task_scored(game, task, TRUE); + } + } else if (var1 < 0) { + /* Decrease the score. */ + if (task_trace) + sc_trace("Task: decreased score by %ld\n", -(var1)); + + game->score += var1; + } } @@ -845,36 +774,29 @@ task_run_change_score_action (sc_gameref_t game, sc_int task, sc_int var1) * Redirect to another task. */ static sc_bool -task_run_set_task_action (sc_gameref_t game, sc_int var1, sc_int var2) -{ - sc_bool status = FALSE; - - /* Select based on var1. */ - if (var1 == 0) - { - /* Redirect forwards. */ - if (task_can_run_task_directional (game, var2, TRUE)) - { - if (task_trace) - sc_trace ("Task: redirecting to task %ld\n", var2); - - status = task_run_task (game, var2, TRUE); - } - else - { - if (task_trace) - sc_trace ("Task: can't redirect to task %ld\n", var2); - } - } - else - { - /* Undo task. */ - gs_set_task_done (game, var2, FALSE); - if (task_trace) - sc_trace ("Task: reversing task %ld\n", var2); - } - - return status; +task_run_set_task_action(sc_gameref_t game, sc_int var1, sc_int var2) { + sc_bool status = FALSE; + + /* Select based on var1. */ + if (var1 == 0) { + /* Redirect forwards. */ + if (task_can_run_task_directional(game, var2, TRUE)) { + if (task_trace) + sc_trace("Task: redirecting to task %ld\n", var2); + + status = task_run_task(game, var2, TRUE); + } else { + if (task_trace) + sc_trace("Task: can't redirect to task %ld\n", var2); + } + } else { + /* Undo task. */ + gs_set_task_done(game, var2, FALSE); + if (task_trace) + sc_trace("Task: reversing task %ld\n", var2); + } + + return status; } @@ -884,65 +806,60 @@ task_run_set_task_action (sc_gameref_t game, sc_int var1, sc_int var2) * End of game task action. */ static sc_bool -task_run_end_game_action (sc_gameref_t game, sc_int var1) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_bool status = FALSE; - - /* Print a message based on var1. */ - switch (var1) - { - case 0: - { - sc_vartype_t vt_key[2]; - const sc_char *wintext; - - /* Get game WinText. */ - vt_key[0].string = "Header"; - vt_key[1].string = "WinText"; - wintext = prop_get_string (bundle, "S<-ss", vt_key); - - /* Print WinText, if any defined, otherwise a default. */ - if (!sc_strempty (wintext)) - { - pf_buffer_string (filter, wintext); - pf_buffer_character (filter, '\n'); - } - else - pf_buffer_string (filter, "Congratulations!\n"); - - /* Handle any associated WinRes resource. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "WinRes"; - res_handle_resource (game, "ss", vt_key); - - status = TRUE; - break; - } - - case 1: - pf_buffer_string (filter, "Better luck next time.\n"); - status = TRUE; - break; - - case 2: - pf_buffer_string (filter, "I'm afraid you are dead!\n"); - status = TRUE; - break; - - case 3: - break; - - default: - sc_fatal ("task_run_end_game_action: invalid type, %ld\n", var1); - } - - /* Stop the game, and note that it's not resumeable. */ - game->is_running = FALSE; - game->has_completed = TRUE; - - return status; +task_run_end_game_action(sc_gameref_t game, sc_int var1) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_bool status = FALSE; + + /* Print a message based on var1. */ + switch (var1) { + case 0: { + sc_vartype_t vt_key[2]; + const sc_char *wintext; + + /* Get game WinText. */ + vt_key[0].string = "Header"; + vt_key[1].string = "WinText"; + wintext = prop_get_string(bundle, "S<-ss", vt_key); + + /* Print WinText, if any defined, otherwise a default. */ + if (!sc_strempty(wintext)) { + pf_buffer_string(filter, wintext); + pf_buffer_character(filter, '\n'); + } else + pf_buffer_string(filter, "Congratulations!\n"); + + /* Handle any associated WinRes resource. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "WinRes"; + res_handle_resource(game, "ss", vt_key); + + status = TRUE; + break; + } + + case 1: + pf_buffer_string(filter, "Better luck next time.\n"); + status = TRUE; + break; + + case 2: + pf_buffer_string(filter, "I'm afraid you are dead!\n"); + status = TRUE; + break; + + case 3: + break; + + default: + sc_fatal("task_run_end_game_action: invalid type, %ld\n", var1); + } + + /* Stop the game, and note that it's not resumeable. */ + game->is_running = FALSE; + game->has_completed = TRUE; + + return status; } @@ -952,95 +869,93 @@ task_run_end_game_action (sc_gameref_t game, sc_int var1) * Demultiplexer for task actions. */ static sc_bool -task_run_task_action (sc_gameref_t game, sc_int task, sc_int action) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int type, var1, var2, var3, var5; - const sc_char *expr; - sc_bool status = FALSE; - - /* Get the task action type. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Actions"; - vt_key[3].integer = action; - vt_key[4].string = "Type"; - type = prop_get_integer (bundle, "I<-sisis", vt_key); - - /* Demultiplex depending on type. */ - switch (type) - { - case 0: /* Move object. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_move_object_action (game, var1, var2, var3); - break; - - case 1: /* Move player/NPC. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_move_npc_action (game, var1, var2, var3); - break; - - case 2: /* Change object status. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_change_object_status (game, var1, var2); - break; - - case 3: /* Change variable. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Expr"; - expr = prop_get_string (bundle, "S<-sisis", vt_key); - vt_key[4].string = "Var5"; - var5 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_change_variable_action (game, var1, var2, var3, expr, var5); - break; - - case 4: /* Change score. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_change_score_action (game, task, var1); - break; - - case 5: /* Execute/unset task. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - status = task_run_set_task_action (game, var1, var2); - break; - - case 6: /* End game. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - status = task_run_end_game_action (game, var1); - break; - - case 7: /* Battle options, ignored for now... */ - break; - - default: - sc_fatal ("task_run_task_action: unknown action type %ld\n", type); - } - - return status; +task_run_task_action(sc_gameref_t game, sc_int task, sc_int action) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int type, var1, var2, var3, var5; + const sc_char *expr; + sc_bool status = FALSE; + + /* Get the task action type. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Actions"; + vt_key[3].integer = action; + vt_key[4].string = "Type"; + type = prop_get_integer(bundle, "I<-sisis", vt_key); + + /* Demultiplex depending on type. */ + switch (type) { + case 0: /* Move object. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_move_object_action(game, var1, var2, var3); + break; + + case 1: /* Move player/NPC. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_move_npc_action(game, var1, var2, var3); + break; + + case 2: /* Change object status. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_change_object_status(game, var1, var2); + break; + + case 3: /* Change variable. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Expr"; + expr = prop_get_string(bundle, "S<-sisis", vt_key); + vt_key[4].string = "Var5"; + var5 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_change_variable_action(game, var1, var2, var3, expr, var5); + break; + + case 4: /* Change score. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_change_score_action(game, task, var1); + break; + + case 5: /* Execute/unset task. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + status = task_run_set_task_action(game, var1, var2); + break; + + case 6: /* End game. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + status = task_run_end_game_action(game, var1); + break; + + case 7: /* Battle options, ignored for now... */ + break; + + default: + sc_fatal("task_run_task_action: unknown action type %ld\n", type); + } + + return status; } @@ -1052,68 +967,62 @@ task_run_task_action (sc_gameref_t game, sc_int task, sc_int action) * returned TRUE. */ static sc_bool -task_run_task_actions (sc_gameref_t game, sc_int task) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int action_count, action; - sc_bool status, muted; - - /* Get the count of task actions. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Actions"; - action_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - if (action_count > 0) - { - if (task_trace) - { - sc_trace ("Task: task %ld running %ld action%s\n", - task, action_count, action_count == 1 ? "" : "s"); - } - } - - /* - * Run all task actions, capturing any TRUE status returned. If any task - * ends the game, run the remaining tasks silently. - * - * This seems a little counterintuitive; a more conventional thing would be - * to just exit the actions loop early. However, Adrift appears to plough - * on, and there may be an action that changes the score in here somewhere, - * so we'll do the same. - */ - status = FALSE; - muted = FALSE; - for (action = 0; action < action_count; action++) - { - sc_bool was_running; - - was_running = game->is_running; - status |= task_run_task_action (game, task, action); - - /* Did this action end the game? */ - if (was_running && !game->is_running) - { - if (task_trace) - { - sc_trace ("Task: task %ld action %ld ended game\n", - task, action); - } - - /* Mute the filter, and note that we did it, but continue. */ - pf_mute (filter); - muted = TRUE; - } - } - - /* If this stack frame muted the filter, un-mute it now. */ - if (muted) - pf_clear_mute (filter); - - /* Return TRUE if any task action returned TRUE. */ - return status; +task_run_task_actions(sc_gameref_t game, sc_int task) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int action_count, action; + sc_bool status, muted; + + /* Get the count of task actions. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Actions"; + action_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + if (action_count > 0) { + if (task_trace) { + sc_trace("Task: task %ld running %ld action%s\n", + task, action_count, action_count == 1 ? "" : "s"); + } + } + + /* + * Run all task actions, capturing any TRUE status returned. If any task + * ends the game, run the remaining tasks silently. + * + * This seems a little counterintuitive; a more conventional thing would be + * to just exit the actions loop early. However, Adrift appears to plough + * on, and there may be an action that changes the score in here somewhere, + * so we'll do the same. + */ + status = FALSE; + muted = FALSE; + for (action = 0; action < action_count; action++) { + sc_bool was_running; + + was_running = game->is_running; + status |= task_run_task_action(game, task, action); + + /* Did this action end the game? */ + if (was_running && !game->is_running) { + if (task_trace) { + sc_trace("Task: task %ld action %ld ended game\n", + task, action); + } + + /* Mute the filter, and note that we did it, but continue. */ + pf_mute(filter); + muted = TRUE; + } + } + + /* If this stack frame muted the filter, un-mute it now. */ + if (muted) + pf_clear_mute(filter); + + /* Return TRUE if any task action returned TRUE. */ + return status; } @@ -1123,29 +1032,27 @@ task_run_task_actions (sc_gameref_t game, sc_int task) * Start NPC walks based on alerts. */ static void -task_start_npc_walks (sc_gameref_t game, sc_int task) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int alert_count, alert; - - /* Get a count of NPC walk alerts. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "NPCWalkAlert"; - alert_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - /* Check alerts, and start any walks that need starting. */ - for (alert = 0; alert < alert_count; alert += 2) - { - sc_int npc, walk; - - vt_key[3].integer = alert; - npc = prop_get_integer (bundle, "I<-sisi", vt_key); - vt_key[3].integer = alert + 1; - walk = prop_get_integer (bundle, "I<-sisi", vt_key); - npc_start_npc_walk (game, npc, walk); - } +task_start_npc_walks(sc_gameref_t game, sc_int task) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int alert_count, alert; + + /* Get a count of NPC walk alerts. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "NPCWalkAlert"; + alert_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + /* Check alerts, and start any walks that need starting. */ + for (alert = 0; alert < alert_count; alert += 2) { + sc_int npc, walk; + + vt_key[3].integer = alert; + npc = prop_get_integer(bundle, "I<-sisi", vt_key); + vt_key[3].integer = alert + 1; + walk = prop_get_integer(bundle, "I<-sisi", vt_key); + npc_start_npc_walk(game, npc, walk); + } } @@ -1158,166 +1065,151 @@ task_start_npc_walks (sc_gameref_t game, sc_int task) * done. */ static sc_bool -task_run_task_unrestricted (sc_gameref_t game, sc_int task, sc_bool forwards) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *completetext, *additionalmessage; - sc_int action_count, showroomdesc; - sc_bool status; - - /* Start considering task output tracking. */ - status = FALSE; - - /* - * If reversing, print any reverse message for the task, and undo the task, - * then return. - */ - if (!forwards) - { - const sc_char *reversemessage; - - /* If not yet done, we can hardly reverse it. */ - if (gs_task_done (game, task)) - { - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "ReverseMessage"; - reversemessage = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (reversemessage)) - { - pf_buffer_string (filter, reversemessage); - pf_buffer_character (filter, '\n'); - status |= TRUE; - } - - /* Undo the task. */ - gs_set_task_done (game, task, FALSE); - } - - /* Return status of undo. */ - return status; - } - - /* See if we are trying to repeat a task that's not repeatable. */ - if (gs_task_done (game, task)) - { - sc_bool repeatable; - - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Repeatable"; - repeatable = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!repeatable) - { - const sc_char *repeattext; - - vt_key[2].string = "RepeatText"; - repeattext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (repeattext)) - { - if (task_trace) - { - sc_trace ("Task:" - " trying to repeat completed action, aborting\n"); - } - - pf_buffer_string (filter, repeattext); - pf_buffer_character (filter, '\n'); - status |= TRUE; - return status; - } - - /* - * Task done, yet not repeatable, so don't consider this case - * handled. - */ - return status; - } - } - - /* Mark the task as done. */ - gs_set_task_done (game, task, TRUE); - - /* Print any task completion text. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "CompleteText"; - completetext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (completetext)) - { - pf_buffer_string (filter, completetext); - pf_buffer_character (filter, '\n'); - status |= TRUE; - } - - /* Handle any task completion resource. */ - vt_key[2].string = "Res"; - res_handle_resource (game, "sis", vt_key); - - /* - * Things get slightly tricky here. We need to filter the completion text - * for the task using any final variable values generated or modified by - * task actions, but other task text, run by actions, according to the - * variable value in effect when it runs. - * - * To do this, we take a local copy of the filter's current buffer at this - * point, remove it from the filter, run task actions with checkpointing, - * then prepend it back into the filter after all the actions are done. - * - * As an optimization, we can avoid doing this if there are no task actions. - */ - vt_key[2].string = "Actions"; - action_count = prop_get_child_count (bundle, "I<-sis", vt_key); - if (action_count > 0) - { - sc_char *buffer; - - /* - * Take ownership of the current filter buffer text, then start NPC - * walks based on alerts, and run any and all task actions. Note that - * the buffer transferred out of the filter may be NULL if there is no - * text currently in the filter. - */ - buffer = pf_transfer_buffer (filter); - task_start_npc_walks (game, task); - status |= task_run_task_actions (game, task); - - /* Prepend the saved buffer data back onto the front of the filter. */ - if (buffer) - { - pf_prepend_string (filter, buffer); - sc_free (buffer); - } - } - else - { - /* Start NPC walks only; there are no task actions. */ - task_start_npc_walks (game, task); - } - - /* Append any room description and additional message for the task. */ - vt_key[2].string = "ShowRoomDesc"; - showroomdesc = prop_get_integer (bundle, "I<-sis", vt_key); - if (showroomdesc != 0) - { - lib_print_room_name (game, showroomdesc - 1); - lib_print_room_description (game, showroomdesc - 1); - status |= TRUE; - } - - vt_key[2].string = "AdditionalMessage"; - additionalmessage = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (additionalmessage)) - { - pf_buffer_string (filter, additionalmessage); - pf_buffer_character (filter, '\n'); - status |= TRUE; - } - - /* Return status -- TRUE if matched and we output something. */ - return status; +task_run_task_unrestricted(sc_gameref_t game, sc_int task, sc_bool forwards) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *completetext, *additionalmessage; + sc_int action_count, showroomdesc; + sc_bool status; + + /* Start considering task output tracking. */ + status = FALSE; + + /* + * If reversing, print any reverse message for the task, and undo the task, + * then return. + */ + if (!forwards) { + const sc_char *reversemessage; + + /* If not yet done, we can hardly reverse it. */ + if (gs_task_done(game, task)) { + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "ReverseMessage"; + reversemessage = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(reversemessage)) { + pf_buffer_string(filter, reversemessage); + pf_buffer_character(filter, '\n'); + status |= TRUE; + } + + /* Undo the task. */ + gs_set_task_done(game, task, FALSE); + } + + /* Return status of undo. */ + return status; + } + + /* See if we are trying to repeat a task that's not repeatable. */ + if (gs_task_done(game, task)) { + sc_bool repeatable; + + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Repeatable"; + repeatable = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!repeatable) { + const sc_char *repeattext; + + vt_key[2].string = "RepeatText"; + repeattext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(repeattext)) { + if (task_trace) { + sc_trace("Task:" + " trying to repeat completed action, aborting\n"); + } + + pf_buffer_string(filter, repeattext); + pf_buffer_character(filter, '\n'); + status |= TRUE; + return status; + } + + /* + * Task done, yet not repeatable, so don't consider this case + * handled. + */ + return status; + } + } + + /* Mark the task as done. */ + gs_set_task_done(game, task, TRUE); + + /* Print any task completion text. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "CompleteText"; + completetext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(completetext)) { + pf_buffer_string(filter, completetext); + pf_buffer_character(filter, '\n'); + status |= TRUE; + } + + /* Handle any task completion resource. */ + vt_key[2].string = "Res"; + res_handle_resource(game, "sis", vt_key); + + /* + * Things get slightly tricky here. We need to filter the completion text + * for the task using any final variable values generated or modified by + * task actions, but other task text, run by actions, according to the + * variable value in effect when it runs. + * + * To do this, we take a local copy of the filter's current buffer at this + * point, remove it from the filter, run task actions with checkpointing, + * then prepend it back into the filter after all the actions are done. + * + * As an optimization, we can avoid doing this if there are no task actions. + */ + vt_key[2].string = "Actions"; + action_count = prop_get_child_count(bundle, "I<-sis", vt_key); + if (action_count > 0) { + sc_char *buffer; + + /* + * Take ownership of the current filter buffer text, then start NPC + * walks based on alerts, and run any and all task actions. Note that + * the buffer transferred out of the filter may be NULL if there is no + * text currently in the filter. + */ + buffer = pf_transfer_buffer(filter); + task_start_npc_walks(game, task); + status |= task_run_task_actions(game, task); + + /* Prepend the saved buffer data back onto the front of the filter. */ + if (buffer) { + pf_prepend_string(filter, buffer); + sc_free(buffer); + } + } else { + /* Start NPC walks only; there are no task actions. */ + task_start_npc_walks(game, task); + } + + /* Append any room description and additional message for the task. */ + vt_key[2].string = "ShowRoomDesc"; + showroomdesc = prop_get_integer(bundle, "I<-sis", vt_key); + if (showroomdesc != 0) { + lib_print_room_name(game, showroomdesc - 1); + lib_print_room_description(game, showroomdesc - 1); + status |= TRUE; + } + + vt_key[2].string = "AdditionalMessage"; + additionalmessage = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(additionalmessage)) { + pf_buffer_string(filter, additionalmessage); + pf_buffer_character(filter, '\n'); + status |= TRUE; + } + + /* Return status -- TRUE if matched and we output something. */ + return status; } @@ -1330,72 +1222,64 @@ task_run_task_unrestricted (sc_gameref_t game, sc_int task, sc_bool forwards) * the call depth. */ sc_bool -task_run_task (sc_gameref_t game, sc_int task, sc_bool forwards) -{ - static sc_int recursion_depth = 0; - - const sc_filterref_t filter = gs_get_filter (game); - const sc_char *fail_message; - sc_bool restrictions_passed, status; - - if (task_trace) - { - sc_trace ("Task: running task %ld %s, depth %ld\n", - task, forwards ? "forwards" : "backwards", recursion_depth); - } - - /* Check restrictions. */ - if (!restr_eval_task_restrictions (game, task, - &restrictions_passed, &fail_message)) - { - sc_error ("task_run_task: restrictions error, %ld\n", task); - return FALSE; - } - if (!restrictions_passed) - { - if (task_trace) - { - sc_trace ("Task: restrictions failed, task %s\n", - fail_message ? "failed" : "aborted"); - } - - if (fail_message) - { - /* - * Print a message, and return TRUE since we can consider this task - * "done" (more accurately, we've output text, so the task command - * searching in the main run loop can exit...). - */ - pf_buffer_string (filter, fail_message); - pf_buffer_character (filter, '\n'); - return TRUE; - } - - /* Task not done; look for more possibilities. */ - return FALSE; - } - - /* Check for infinite recursion. */ - if (recursion_depth > TASK_MAXIMUM_RECURSION) - { - sc_error ("task_run_task: maximum recursion depth exceeded --" - " game task loop?\n"); - return FALSE; - } - - /* Increment depth, run the task, then decrement depth. */ - recursion_depth++; - status = task_run_task_unrestricted (game, task, forwards); - recursion_depth--; - - if (task_trace) - { - sc_trace ("Task: task %ld finished, return %s, depth %ld\n", - task, status ? "true" : "false", recursion_depth); - } - - /* Return the task's status. */ - return status; +task_run_task(sc_gameref_t game, sc_int task, sc_bool forwards) { + static sc_int recursion_depth = 0; + + const sc_filterref_t filter = gs_get_filter(game); + const sc_char *fail_message; + sc_bool restrictions_passed, status; + + if (task_trace) { + sc_trace("Task: running task %ld %s, depth %ld\n", + task, forwards ? "forwards" : "backwards", recursion_depth); + } + + /* Check restrictions. */ + if (!restr_eval_task_restrictions(game, task, + &restrictions_passed, &fail_message)) { + sc_error("task_run_task: restrictions error, %ld\n", task); + return FALSE; + } + if (!restrictions_passed) { + if (task_trace) { + sc_trace("Task: restrictions failed, task %s\n", + fail_message ? "failed" : "aborted"); + } + + if (fail_message) { + /* + * Print a message, and return TRUE since we can consider this task + * "done" (more accurately, we've output text, so the task command + * searching in the main run loop can exit...). + */ + pf_buffer_string(filter, fail_message); + pf_buffer_character(filter, '\n'); + return TRUE; + } + + /* Task not done; look for more possibilities. */ + return FALSE; + } + + /* Check for infinite recursion. */ + if (recursion_depth > TASK_MAXIMUM_RECURSION) { + sc_error("task_run_task: maximum recursion depth exceeded --" + " game task loop?\n"); + return FALSE; + } + + /* Increment depth, run the task, then decrement depth. */ + recursion_depth++; + status = task_run_task_unrestricted(game, task, forwards); + recursion_depth--; + + if (task_trace) { + sc_trace("Task: task %ld finished, return %s, depth %ld\n", + task, status ? "true" : "false", recursion_depth); + } + + /* Return the task's status. */ + return status; } @@ -1405,9 +1289,8 @@ task_run_task (sc_gameref_t game, sc_int task, sc_bool forwards) * Set task tracing on/off. */ void -task_debug_trace (sc_bool flag) -{ - task_trace = flag; +task_debug_trace(sc_bool flag) { + task_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scutils.cpp b/engines/glk/adrift/scutils.cpp index 98e10651e7..97db91dbb8 100644 --- a/engines/glk/adrift/scutils.cpp +++ b/engines/glk/adrift/scutils.cpp @@ -42,14 +42,14 @@ namespace Adrift { * * Debugging trace function; printf wrapper that writes to stderr. */ -void sc_trace (const sc_char *format, ...) { - va_list ap; - assert(format); - - va_start (ap, format); - Common::String s = Common::String::format(format, ap); - va_end (ap); - debug("%s", s.c_str()); +void sc_trace(const sc_char *format, ...) { + va_list ap; + assert(format); + + va_start(ap, format); + Common::String s = Common::String::format(format, ap); + va_end(ap); + debug("%s", s.c_str()); } @@ -60,7 +60,7 @@ void sc_trace (const sc_char *format, ...) { * Error reporting functions. sc_error() prints a message and continues. * sc_fatal() prints a message, then calls abort(). */ -void sc_error (const sc_char *format, ...) { +void sc_error(const sc_char *format, ...) { va_list ap; assert(format); @@ -70,7 +70,7 @@ void sc_error (const sc_char *format, ...) { warning("%s", s.c_str()); } -void sc_fatal (const sc_char *format, ...) { +void sc_fatal(const sc_char *format, ...) { va_list ap; assert(format); @@ -83,7 +83,7 @@ void sc_fatal (const sc_char *format, ...) { /* Unique non-heap address for zero size malloc() and realloc() requests. */ static void *sc_zero_allocation = &sc_zero_allocation; - + /* * sc_malloc() * sc_realloc() @@ -94,56 +94,52 @@ static void *sc_zero_allocation = &sc_zero_allocation; * defined, so we have to take special care to get predictable behavior. */ void * -sc_malloc (size_t size) -{ - void *allocated; +sc_malloc(size_t size) { + void *allocated; - if (size == 0) - return sc_zero_allocation; + if (size == 0) + return sc_zero_allocation; - allocated = malloc (size); - if (!allocated) - sc_fatal ("sc_malloc: requested %lu bytes\n", (sc_uint) size); - else if (allocated == sc_zero_allocation) - sc_fatal ("sc_malloc: zero-byte allocation address returned\n"); + allocated = malloc(size); + if (!allocated) + sc_fatal("sc_malloc: requested %lu bytes\n", (sc_uint) size); + else if (allocated == sc_zero_allocation) + sc_fatal("sc_malloc: zero-byte allocation address returned\n"); - memset (allocated, 0, size); - return allocated; + memset(allocated, 0, size); + return allocated; } void * -sc_realloc (void *pointer, size_t size) -{ - void *allocated; - - if (size == 0) - { - sc_free (pointer); - return sc_zero_allocation; - } - - if (pointer == sc_zero_allocation) - pointer = NULL; - - allocated = realloc (pointer, size); - if (!allocated) - sc_fatal ("sc_realloc: requested %lu bytes\n", (sc_uint) size); - else if (allocated == sc_zero_allocation) - sc_fatal ("sc_realloc: zero-byte allocation address returned\n"); - - if (!pointer) - memset (allocated, 0, size); - return allocated; +sc_realloc(void *pointer, size_t size) { + void *allocated; + + if (size == 0) { + sc_free(pointer); + return sc_zero_allocation; + } + + if (pointer == sc_zero_allocation) + pointer = NULL; + + allocated = realloc(pointer, size); + if (!allocated) + sc_fatal("sc_realloc: requested %lu bytes\n", (sc_uint) size); + else if (allocated == sc_zero_allocation) + sc_fatal("sc_realloc: zero-byte allocation address returned\n"); + + if (!pointer) + memset(allocated, 0, size); + return allocated; } void -sc_free (void *pointer) -{ - if (sc_zero_allocation != &sc_zero_allocation) - sc_fatal ("sc_free: write to zero-byte allocation address detected\n"); +sc_free(void *pointer) { + if (sc_zero_allocation != &sc_zero_allocation) + sc_fatal("sc_free: write to zero-byte allocation address detected\n"); - if (pointer && pointer != sc_zero_allocation) - free (pointer); + if (pointer && pointer != sc_zero_allocation) + free(pointer); } @@ -155,37 +151,34 @@ sc_free (void *pointer) * definitions to do the same jobs. */ sc_int -sc_strncasecmp (const sc_char *s1, const sc_char *s2, sc_int n) -{ - sc_int index_; - assert (s1 && s2); +sc_strncasecmp(const sc_char *s1, const sc_char *s2, sc_int n) { + sc_int index_; + assert(s1 && s2); - for (index_ = 0; index_ < n; index_++) - { - sc_int diff; + for (index_ = 0; index_ < n; index_++) { + sc_int diff; - diff = sc_tolower (s1[index_]) - sc_tolower (s2[index_]); - if (diff < 0 || diff > 0) - return diff < 0 ? -1 : 1; - } + diff = sc_tolower(s1[index_]) - sc_tolower(s2[index_]); + if (diff < 0 || diff > 0) + return diff < 0 ? -1 : 1; + } - return 0; + return 0; } sc_int -sc_strcasecmp (const sc_char *s1, const sc_char *s2) -{ - sc_int s1len, s2len, result; - assert (s1 && s2); - - s1len = strlen (s1); - s2len = strlen (s2); - - result = sc_strncasecmp (s1, s2, s1len < s2len ? s1len : s2len); - if (result < 0 || result > 0) - return result; - else - return s1len < s2len ? -1 : s1len > s2len ? 1 : 0; +sc_strcasecmp(const sc_char *s1, const sc_char *s2) { + sc_int s1len, s2len, result; + assert(s1 && s2); + + s1len = strlen(s1); + s2len = strlen(s2); + + result = sc_strncasecmp(s1, s2, s1len < s2len ? s1len : s2len); + if (result < 0 || result > 0) + return result; + else + return s1len < s2len ? -1 : s1len > s2len ? 1 : 0; } @@ -202,70 +195,61 @@ sc_strcasecmp (const sc_char *s1, const sc_char *s2) * with the latter intended for predictability of game actions. */ static sc_int -sc_platform_rand (sc_uint new_seed) -{ - static sc_bool is_seeded = FALSE; - - /* If reseeding, seed with the value supplied, note seeded, and return 0. */ - if (new_seed > 0) { - g_vm->setRandomNumberSeed(new_seed); - is_seeded = TRUE; - return 0; - } - else - { - /* If not explicitly seeded yet, generate a seed from time(). */ - if (!is_seeded) - { - //srand ((sc_uint) time (NULL)); - is_seeded = TRUE; - } - - /* Return the next rand() number in the sequence. */ - return g_vm->getRandomNumber(0xffffff); - } +sc_platform_rand(sc_uint new_seed) { + static sc_bool is_seeded = FALSE; + + /* If reseeding, seed with the value supplied, note seeded, and return 0. */ + if (new_seed > 0) { + g_vm->setRandomNumberSeed(new_seed); + is_seeded = TRUE; + return 0; + } else { + /* If not explicitly seeded yet, generate a seed from time(). */ + if (!is_seeded) { + //srand ((sc_uint) time (NULL)); + is_seeded = TRUE; + } + + /* Return the next rand() number in the sequence. */ + return g_vm->getRandomNumber(0xffffff); + } } static sc_int -sc_congruential_rand (sc_uint new_seed) -{ - static sc_bool is_seeded = FALSE; - static sc_uint rand_state = 1; - - /* If reseeding, seed with the value supplied, and note seeded. */ - if (new_seed > 0) - { - rand_state = new_seed; - is_seeded = TRUE; - return 0; - } - else - { - /* If not explicitly seeded yet, generate a seed from time(). */ - if (!is_seeded) - { - rand_state = (sc_uint)g_vm->_events->getTotalPlayTicks(); - is_seeded = TRUE; - } - - /* - * Advance random state, using constants from Park & Miller (1988). - * To keep the values the same for both 32 and 64 bit longs, mask out - * any bits above the bottom 32. - */ - rand_state = (rand_state * 16807 + 2147483647) & 0xffffffff; - - /* - * Discard the lowest bit as a way to map 32-bits unsigned to a 32-bit - * positive signed. - */ - return rand_state >> 1; - } +sc_congruential_rand(sc_uint new_seed) { + static sc_bool is_seeded = FALSE; + static sc_uint rand_state = 1; + + /* If reseeding, seed with the value supplied, and note seeded. */ + if (new_seed > 0) { + rand_state = new_seed; + is_seeded = TRUE; + return 0; + } else { + /* If not explicitly seeded yet, generate a seed from time(). */ + if (!is_seeded) { + rand_state = (sc_uint)g_vm->_events->getTotalPlayTicks(); + is_seeded = TRUE; + } + + /* + * Advance random state, using constants from Park & Miller (1988). + * To keep the values the same for both 32 and 64 bit longs, mask out + * any bits above the bottom 32. + */ + rand_state = (rand_state * 16807 + 2147483647) & 0xffffffff; + + /* + * Discard the lowest bit as a way to map 32-bits unsigned to a 32-bit + * positive signed. + */ + return rand_state >> 1; + } } /* Function pointer for the actual random number generator in use. */ -static sc_int (*sc_rand_function) (sc_uint) = sc_platform_rand; +static sc_int(*sc_rand_function)(sc_uint) = sc_platform_rand; /* * sc_set_congruential_random() @@ -280,49 +264,43 @@ static sc_int (*sc_rand_function) (sc_uint) = sc_platform_rand; * generate a random value within a given range. */ void -sc_set_congruential_random (void) -{ - sc_rand_function = sc_congruential_rand; +sc_set_congruential_random(void) { + sc_rand_function = sc_congruential_rand; } void -sc_set_platform_random (void) -{ - sc_rand_function = sc_platform_rand; +sc_set_platform_random(void) { + sc_rand_function = sc_platform_rand; } sc_bool -sc_is_congruential_random (void) -{ - return sc_rand_function == sc_congruential_rand; +sc_is_congruential_random(void) { + return sc_rand_function == sc_congruential_rand; } void -sc_seed_random (sc_uint new_seed) -{ - /* Ignore zero values of new_seed by simply using 1 instead. */ - sc_rand_function (new_seed > 0 ? new_seed : 1); +sc_seed_random(sc_uint new_seed) { + /* Ignore zero values of new_seed by simply using 1 instead. */ + sc_rand_function(new_seed > 0 ? new_seed : 1); } sc_int -sc_rand (void) -{ - sc_int retval; +sc_rand(void) { + sc_int retval; - /* Passing zero indicates this is not a seed operation. */ - retval = sc_rand_function (0); - return retval; + /* Passing zero indicates this is not a seed operation. */ + retval = sc_rand_function(0); + return retval; } sc_int -sc_randomint (sc_int low, sc_int high) -{ - /* - * If the range is invalid, just return the low value given. This mimics - * Adrift under the same conditions, and also guards against division by - * zero in the mod operation. - */ - return (high < low) ? low : low + sc_rand () % (high - low + 1); +sc_randomint(sc_int low, sc_int high) { + /* + * If the range is invalid, just return the low value given. This mimics + * Adrift under the same conditions, and also guards against division by + * zero in the mod operation. + */ + return (high < low) ? low : low + sc_rand() % (high - low + 1); } @@ -336,20 +314,18 @@ static const sc_char SPACE = ' '; * Return TRUE if a string is either zero-length or contains only whitespace. */ sc_bool -sc_strempty (const sc_char *string) -{ - sc_int index_; - assert (string); - - /* Scan for any non-space character. */ - for (index_ = 0; string[index_] != NUL; index_++) - { - if (!sc_isspace (string[index_])) - return FALSE; - } - - /* None found, so string is empty. */ - return TRUE; +sc_strempty(const sc_char *string) { + sc_int index_; + assert(string); + + /* Scan for any non-space character. */ + for (index_ = 0; string[index_] != NUL; index_++) { + if (!sc_isspace(string[index_])) + return FALSE; + } + + /* None found, so string is empty. */ + return TRUE; } @@ -360,20 +336,19 @@ sc_strempty (const sc_char *string) * in place, and returns the string address for convenience. */ sc_char * -sc_trim_string (sc_char *string) -{ - sc_int index_; - assert (string); +sc_trim_string(sc_char *string) { + sc_int index_; + assert(string); - for (index_ = strlen (string) - 1; - index_ >= 0 && sc_isspace (string[index_]); index_--) - string[index_] = NUL; + for (index_ = strlen(string) - 1; + index_ >= 0 && sc_isspace(string[index_]); index_--) + string[index_] = NUL; - for (index_ = 0; sc_isspace (string[index_]);) - index_++; - memmove (string, string + index_, strlen (string) - index_ + 1); + for (index_ = 0; sc_isspace(string[index_]);) + index_++; + memmove(string, string + index_, strlen(string) - index_ + 1); - return string; + return string; } @@ -385,30 +360,27 @@ sc_trim_string (sc_char *string) * convenience. */ sc_char * -sc_normalize_string (sc_char *string) -{ - sc_int index_; - assert (string); - - /* Trim all leading and trailing spaces. */ - string = sc_trim_string (string); - - /* Compress multiple whitespace runs into a single space character. */ - for (index_ = 0; string[index_] != NUL; index_++) - { - if (sc_isspace (string[index_])) - { - sc_int cursor; - - string[index_] = SPACE; - for (cursor = index_ + 1; sc_isspace (string[cursor]);) - cursor++; - memmove (string + index_ + 1, - string + cursor, strlen (string + cursor) + 1); - } - } - - return string; +sc_normalize_string(sc_char *string) { + sc_int index_; + assert(string); + + /* Trim all leading and trailing spaces. */ + string = sc_trim_string(string); + + /* Compress multiple whitespace runs into a single space character. */ + for (index_ = 0; string[index_] != NUL; index_++) { + if (sc_isspace(string[index_])) { + sc_int cursor; + + string[index_] = SPACE; + for (cursor = index_ + 1; sc_isspace(string[cursor]);) + cursor++; + memmove(string + index_ + 1, + string + cursor, strlen(string + cursor) + 1); + } + } + + return string; } @@ -418,13 +390,12 @@ sc_normalize_string (sc_char *string) * Return TRUE if the first word in the string is word, case insensitive. */ sc_bool -sc_compare_word (const sc_char *string, const sc_char *word, sc_int length) -{ - assert (string && word); +sc_compare_word(const sc_char *string, const sc_char *word, sc_int length) { + assert(string && word); - /* Return TRUE if string starts with word, then space or string end. */ - return sc_strncasecmp (string, word, length) == 0 - && (string[length] == NUL || sc_isspace (string[length])); + /* Return TRUE if string starts with word, then space or string end. */ + return sc_strncasecmp(string, word, length) == 0 + && (string[length] == NUL || sc_isspace(string[length])); } @@ -435,27 +406,24 @@ sc_compare_word (const sc_char *string, const sc_char *word, sc_int length) * and tools', page 436, unmodulo'ed and somewhat restyled. */ sc_uint -sc_hash (const sc_char *string) -{ - sc_int index_; - sc_uint hash; - assert (string); - - hash = 0; - for (index_ = 0; string[index_] != NUL; index_++) - { - sc_uint temp; - - hash = (hash << 4) + string[index_]; - temp = hash & 0xf0000000; - if (temp != 0) - { - hash = hash ^ (temp >> 24); - hash = hash ^ temp; - } - } - - return hash; +sc_hash(const sc_char *string) { + sc_int index_; + sc_uint hash; + assert(string); + + hash = 0; + for (index_ = 0; string[index_] != NUL; index_++) { + sc_uint temp; + + hash = (hash << 4) + string[index_]; + temp = hash & 0xf0000000; + if (temp != 0) { + hash = hash ^ (temp >> 24); + hash = hash ^ temp; + } + } + + return hash; } } // End of namespace Adrift diff --git a/engines/glk/adrift/scvars.cpp b/engines/glk/adrift/scvars.cpp index 0ed62446c1..65957e1c6e 100644 --- a/engines/glk/adrift/scvars.cpp +++ b/engines/glk/adrift/scvars.cpp @@ -51,19 +51,18 @@ static sc_bool var_trace = FALSE; /* Table of numbers zero to twenty spelled out. */ enum { VAR_NUMBERS_SIZE = 21 }; static const sc_char *const VAR_NUMBERS[VAR_NUMBERS_SIZE] = { - "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", - "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", - "sixteen", "seventeen", "eighteen", "nineteen", "twenty" + "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", + "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", + "sixteen", "seventeen", "eighteen", "nineteen", "twenty" }; /* Variable entry, held on a list hashed by variable name. */ -typedef struct sc_var_s -{ - struct sc_var_s *next; +typedef struct sc_var_s { + struct sc_var_s *next; - const sc_char *name; - sc_int type; - sc_vartype_t value; + const sc_char *name; + sc_int type; + sc_vartype_t value; } sc_var_t; typedef sc_var_t *sc_varref_t; @@ -74,20 +73,19 @@ typedef sc_var_t *sc_varref_t; * exceed a fill factor of two (~422 variables). */ enum { VAR_HASH_TABLE_SIZE = 211 }; -typedef struct sc_var_set_s -{ - sc_uint magic; - sc_prop_setref_t bundle; - sc_int referenced_character; - sc_int referenced_object; - sc_int referenced_number; - sc_bool is_number_referenced; - sc_char *referenced_text; - sc_char *temporary; - uint32 timestamp; - sc_uint time_offset; - sc_gameref_t game; - sc_varref_t variable[VAR_HASH_TABLE_SIZE]; +typedef struct sc_var_set_s { + sc_uint magic; + sc_prop_setref_t bundle; + sc_int referenced_character; + sc_int referenced_object; + sc_int referenced_number; + sc_bool is_number_referenced; + sc_char *referenced_text; + sc_char *temporary; + uint32 timestamp; + sc_uint time_offset; + sc_gameref_t game; + sc_varref_t variable[VAR_HASH_TABLE_SIZE]; } sc_var_set_t; @@ -97,9 +95,8 @@ typedef struct sc_var_set_s * Return TRUE if pointer is a valid variables set, FALSE otherwise. */ static sc_bool -var_is_valid (sc_var_setref_t vars) -{ - return vars && vars->magic == VARS_MAGIC; +var_is_valid(sc_var_setref_t vars) { + return vars && vars->magic == VARS_MAGIC; } @@ -109,9 +106,8 @@ var_is_valid (sc_var_setref_t vars) * Hash a variable name, modulo'ed to the number of buckets. */ static sc_uint -var_hash_name (const sc_char *name) -{ - return sc_hash (name) % VAR_HASH_TABLE_SIZE; +var_hash_name(const sc_char *name) { + return sc_hash(name) % VAR_HASH_TABLE_SIZE; } @@ -121,30 +117,29 @@ var_hash_name (const sc_char *name) * Create and return a new empty set of variables. */ static sc_var_setref_t -var_create_empty (void) -{ - sc_var_setref_t vars; - sc_int index_; - - /* Create a clean set of variables. */ - vars = (sc_var_setref_t)sc_malloc(sizeof (*vars)); - vars->magic = VARS_MAGIC; - vars->bundle = nullptr; - vars->referenced_character = -1; - vars->referenced_object = -1; - vars->referenced_number = 0; - vars->is_number_referenced = FALSE; - vars->referenced_text = nullptr; - vars->temporary = nullptr; - vars->timestamp = g_vm->_events->getTotalPlayTicks() / 1000; - vars->time_offset = 0; - vars->game = nullptr; - - /* Clear all variable hash lists. */ - for (index_ = 0; index_ < VAR_HASH_TABLE_SIZE; index_++) - vars->variable[index_] = nullptr; - - return vars; +var_create_empty(void) { + sc_var_setref_t vars; + sc_int index_; + + /* Create a clean set of variables. */ + vars = (sc_var_setref_t)sc_malloc(sizeof(*vars)); + vars->magic = VARS_MAGIC; + vars->bundle = nullptr; + vars->referenced_character = -1; + vars->referenced_object = -1; + vars->referenced_number = 0; + vars->is_number_referenced = FALSE; + vars->referenced_text = nullptr; + vars->temporary = nullptr; + vars->timestamp = g_vm->_events->getTotalPlayTicks() / 1000; + vars->time_offset = 0; + vars->game = nullptr; + + /* Clear all variable hash lists. */ + for (index_ = 0; index_ < VAR_HASH_TABLE_SIZE; index_++) + vars->variable[index_] = nullptr; + + return vars; } @@ -154,35 +149,32 @@ var_create_empty (void) * Destroy a variable set, and free its heap memory. */ void -var_destroy (sc_var_setref_t vars) -{ - sc_int index_; - assert (var_is_valid (vars)); - - /* - * Free the content of each string variable, and variable entry. String - * variable content needs to use mutable string instead of const string. - */ - for (index_ = 0; index_ < VAR_HASH_TABLE_SIZE; index_++) - { - sc_varref_t var, next; - - for (var = vars->variable[index_]; var; var = next) - { - next = var->next; - if (var->type == VAR_STRING) - sc_free (var->value.mutable_string); - sc_free (var); - } - } - - /* Free any temporary and reference text storage area. */ - sc_free (vars->temporary); - sc_free (vars->referenced_text); - - /* Poison and free the variable set itself. */ - memset (vars, 0xaa, sizeof (*vars)); - sc_free (vars); +var_destroy(sc_var_setref_t vars) { + sc_int index_; + assert(var_is_valid(vars)); + + /* + * Free the content of each string variable, and variable entry. String + * variable content needs to use mutable string instead of const string. + */ + for (index_ = 0; index_ < VAR_HASH_TABLE_SIZE; index_++) { + sc_varref_t var, next; + + for (var = vars->variable[index_]; var; var = next) { + next = var->next; + if (var->type == VAR_STRING) + sc_free(var->value.mutable_string); + sc_free(var); + } + } + + /* Free any temporary and reference text storage area. */ + sc_free(vars->temporary); + sc_free(vars->referenced_text); + + /* Poison and free the variable set itself. */ + memset(vars, 0xaa, sizeof(*vars)); + sc_free(vars); } @@ -194,41 +186,38 @@ var_destroy (sc_var_setref_t vars) * variable exists, and add a new variable structure to the lists. */ static sc_varref_t -var_find (sc_var_setref_t vars, const sc_char *name) -{ - sc_uint hash; - sc_varref_t var; - - /* Hash name, search list and return if name match found. */ - hash = var_hash_name (name); - for (var = vars->variable[hash]; var; var = var->next) - { - if (strcmp (name, var->name) == 0) - break; - } - - /* Return variable, or nullptr if no such variable. */ - return var; +var_find(sc_var_setref_t vars, const sc_char *name) { + sc_uint hash; + sc_varref_t var; + + /* Hash name, search list and return if name match found. */ + hash = var_hash_name(name); + for (var = vars->variable[hash]; var; var = var->next) { + if (strcmp(name, var->name) == 0) + break; + } + + /* Return variable, or nullptr if no such variable. */ + return var; } static sc_varref_t -var_add (sc_var_setref_t vars, const sc_char *name, sc_int type) -{ - sc_varref_t var; - sc_uint hash; - - /* Create a new variable entry. */ - var = (sc_varref_t)sc_malloc (sizeof (*var)); - var->name = name; - var->type = type; - var->value.voidp = nullptr; - - /* Hash its name, and insert it at start of the relevant list. */ - hash = var_hash_name (name); - var->next = vars->variable[hash]; - vars->variable[hash] = var; - - return var; +var_add(sc_var_setref_t vars, const sc_char *name, sc_int type) { + sc_varref_t var; + sc_uint hash; + + /* Create a new variable entry. */ + var = (sc_varref_t)sc_malloc(sizeof(*var)); + var->name = name; + var->type = type; + var->value.voidp = nullptr; + + /* Hash its name, and insert it at start of the relevant list. */ + hash = var_hash_name(name); + var->next = vars->variable[hash]; + vars->variable[hash] = var; + + return var; } @@ -239,18 +228,16 @@ var_add (sc_var_setref_t vars, const sc_char *name, sc_int type) * of this variable, and to re-initialize user versions initialized to zero. */ static sc_int -var_get_scare_version (void) -{ - sc_int major, minor, point, version; - - if (sscanf (SCARE_VERSION, "%ld.%ld.%ld", &major, &minor, &point) != 3) - { - sc_error ("var_get_scare_version: unable to generate scare_version\n"); - return 0; - } - - version = major * 10000 + minor * 100 + point; - return version; +var_get_scare_version(void) { + sc_int major, minor, point, version; + + if (sscanf(SCARE_VERSION, "%ld.%ld.%ld", &major, &minor, &point) != 3) { + sc_error("var_get_scare_version: unable to generate scare_version\n"); + return 0; + } + + version = major * 10000 + minor * 100 + point; + return version; } @@ -261,109 +248,99 @@ var_get_scare_version (void) * is created. Type is one of 'I' or 'S' for integer or string. */ void -var_put (sc_var_setref_t vars, - const sc_char *name, sc_int type, sc_vartype_t vt_value) -{ - sc_varref_t var; - sc_bool is_modification; - assert (var_is_valid (vars)); - assert (name); - - /* Check type is either integer or string. */ - switch (type) - { - case VAR_INTEGER: - case VAR_STRING: - break; - - default: - sc_fatal ("var_put: invalid variable type, %ld\n", type); - } - - /* See if the user variable already exists. */ - var = var_find (vars, name); - if (var) - { - /* Verify that nothing is trying to change the variable's type. */ - if (var->type != type) - sc_fatal ("var_put: variable type changed, %s\n", name); - - /* - * Special case %scare_version%. If a game changes its value, it may - * compromise version checking, so warn here, but continue. - */ - if (strcmp (name, "scare_version") == 0) - { - if (var->value.integer != vt_value.integer) - sc_error ("var_put: warning: %%%s%% value changed\n", name); - } - - is_modification = TRUE; - } - else - { - /* - * Special case %scare_version%. If a game defines this and initializes - * it to zero, re-initialize it to SCARE's version number. Games that - * define %scare_version%, initially zero, can use this to test if - * running under SCARE or Runner. - */ - if (strcmp (name, "scare_version") == 0 && vt_value.integer == 0) - { - vt_value.integer = var_get_scare_version (); - - if (var_trace) - sc_trace ("Variable: %%%s%% [new] caught and mapped\n", name); - } - - /* - * Create a new and empty variable entry. The mutable string needs to - * be set to nullptr here so that realloc works correctly on assigning - * the value below. - */ - var = var_add (vars, name, type); - var->value.mutable_string = nullptr; - - is_modification = FALSE; - } - - /* Update the existing variable, or populate the new one fully. */ - switch (var->type) - { - case VAR_INTEGER: - var->value.integer = vt_value.integer; - break; - - case VAR_STRING: - /* Use mutable string instead of const string. */ - var->value.mutable_string = (sc_char *)sc_realloc(var->value.mutable_string, - strlen (vt_value.string) + 1); - strcpy (var->value.mutable_string, vt_value.string); - break; - - default: - sc_fatal ("var_put: invalid variable type, %ld\n", var->type); - } - - if (var_trace) - { - sc_trace ("Variable: %%%s%%%s = ", - name, is_modification ? "" : " [new]"); - switch (var->type) - { - case VAR_INTEGER: - sc_trace ("%ld", var->value.integer); - break; - case VAR_STRING: - sc_trace ("\"%s\"", var->value.string); - break; - - default: - sc_trace ("[invalid variable type, %ld]", var->type); - break; - } - sc_trace ("\n"); - } +var_put(sc_var_setref_t vars, + const sc_char *name, sc_int type, sc_vartype_t vt_value) { + sc_varref_t var; + sc_bool is_modification; + assert(var_is_valid(vars)); + assert(name); + + /* Check type is either integer or string. */ + switch (type) { + case VAR_INTEGER: + case VAR_STRING: + break; + + default: + sc_fatal("var_put: invalid variable type, %ld\n", type); + } + + /* See if the user variable already exists. */ + var = var_find(vars, name); + if (var) { + /* Verify that nothing is trying to change the variable's type. */ + if (var->type != type) + sc_fatal("var_put: variable type changed, %s\n", name); + + /* + * Special case %scare_version%. If a game changes its value, it may + * compromise version checking, so warn here, but continue. + */ + if (strcmp(name, "scare_version") == 0) { + if (var->value.integer != vt_value.integer) + sc_error("var_put: warning: %%%s%% value changed\n", name); + } + + is_modification = TRUE; + } else { + /* + * Special case %scare_version%. If a game defines this and initializes + * it to zero, re-initialize it to SCARE's version number. Games that + * define %scare_version%, initially zero, can use this to test if + * running under SCARE or Runner. + */ + if (strcmp(name, "scare_version") == 0 && vt_value.integer == 0) { + vt_value.integer = var_get_scare_version(); + + if (var_trace) + sc_trace("Variable: %%%s%% [new] caught and mapped\n", name); + } + + /* + * Create a new and empty variable entry. The mutable string needs to + * be set to nullptr here so that realloc works correctly on assigning + * the value below. + */ + var = var_add(vars, name, type); + var->value.mutable_string = nullptr; + + is_modification = FALSE; + } + + /* Update the existing variable, or populate the new one fully. */ + switch (var->type) { + case VAR_INTEGER: + var->value.integer = vt_value.integer; + break; + + case VAR_STRING: + /* Use mutable string instead of const string. */ + var->value.mutable_string = (sc_char *)sc_realloc(var->value.mutable_string, + strlen(vt_value.string) + 1); + strcpy(var->value.mutable_string, vt_value.string); + break; + + default: + sc_fatal("var_put: invalid variable type, %ld\n", var->type); + } + + if (var_trace) { + sc_trace("Variable: %%%s%%%s = ", + name, is_modification ? "" : " [new]"); + switch (var->type) { + case VAR_INTEGER: + sc_trace("%ld", var->value.integer); + break; + case VAR_STRING: + sc_trace("\"%s\"", var->value.string); + break; + + default: + sc_trace("[invalid variable type, %ld]", var->type); + break; + } + sc_trace("\n"); + } } @@ -374,32 +351,28 @@ var_put (sc_var_setref_t vars, * to the string. */ static void -var_append_temp (sc_var_setref_t vars, const sc_char *string) -{ - sc_bool new_sentence; - sc_int noted; - - if (!vars->temporary) - { - /* Create a new temporary area and copy string. */ - new_sentence = TRUE; - noted = 0; - vars->temporary = (sc_char *)sc_malloc (strlen (string) + 1); - strcpy (vars->temporary, string); - } - else - { - /* Append string to existing temporary. */ - new_sentence = (vars->temporary[0] == NUL); - noted = strlen (vars->temporary); - vars->temporary = (sc_char *)sc_realloc (vars->temporary, - strlen (vars->temporary) + - strlen (string) + 1); - strcat (vars->temporary, string); - } - - if (new_sentence) - vars->temporary[noted] = sc_toupper (vars->temporary[noted]); +var_append_temp(sc_var_setref_t vars, const sc_char *string) { + sc_bool new_sentence; + sc_int noted; + + if (!vars->temporary) { + /* Create a new temporary area and copy string. */ + new_sentence = TRUE; + noted = 0; + vars->temporary = (sc_char *)sc_malloc(strlen(string) + 1); + strcpy(vars->temporary, string); + } else { + /* Append string to existing temporary. */ + new_sentence = (vars->temporary[0] == NUL); + noted = strlen(vars->temporary); + vars->temporary = (sc_char *)sc_realloc(vars->temporary, + strlen(vars->temporary) + + strlen(string) + 1); + strcat(vars->temporary, string); + } + + if (new_sentence) + vars->temporary[noted] = sc_toupper(vars->temporary[noted]); } @@ -411,101 +384,87 @@ var_append_temp (sc_var_setref_t vars, const sc_char *string) * prefix, to variables temporary. */ static void -var_print_object_np (sc_gameref_t game, sc_int object) -{ - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *prefix, *normalized, *name; - - /* Get the object's prefix. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - - /* - * Try the same shenanigans as done by the equivalent function in the - * library. - */ - normalized = prefix; - if (sc_compare_word (prefix, "a", 1)) - { - normalized = prefix + 1; - var_append_temp (vars, "the"); - } - else if (sc_compare_word (prefix, "an", 2)) - { - normalized = prefix + 2; - var_append_temp (vars, "the"); - } - else if (sc_compare_word (prefix, "the", 3)) - { - normalized = prefix + 3; - var_append_temp (vars, "the"); - } - else if (sc_compare_word (prefix, "some", 4)) - { - normalized = prefix + 4; - var_append_temp (vars, "the"); - } - else if (sc_strempty (prefix)) - var_append_temp (vars, "the "); - - /* As with the library, handle the remaining prefix. */ - if (!sc_strempty (normalized)) - { - var_append_temp (vars, normalized); - var_append_temp (vars, " "); - } - else if (normalized > prefix) - var_append_temp (vars, " "); - - /* - * Print the object's name, again, as with the library, stripping any - * leading article - */ - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - if (sc_compare_word (name, "a", 1)) - name += 1; - else if (sc_compare_word (name, "an", 2)) - name += 2; - else if (sc_compare_word (name, "the", 3)) - name += 3; - else if (sc_compare_word (name, "some", 4)) - name += 4; - var_append_temp (vars, name); +var_print_object_np(sc_gameref_t game, sc_int object) { + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *prefix, *normalized, *name; + + /* Get the object's prefix. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + + /* + * Try the same shenanigans as done by the equivalent function in the + * library. + */ + normalized = prefix; + if (sc_compare_word(prefix, "a", 1)) { + normalized = prefix + 1; + var_append_temp(vars, "the"); + } else if (sc_compare_word(prefix, "an", 2)) { + normalized = prefix + 2; + var_append_temp(vars, "the"); + } else if (sc_compare_word(prefix, "the", 3)) { + normalized = prefix + 3; + var_append_temp(vars, "the"); + } else if (sc_compare_word(prefix, "some", 4)) { + normalized = prefix + 4; + var_append_temp(vars, "the"); + } else if (sc_strempty(prefix)) + var_append_temp(vars, "the "); + + /* As with the library, handle the remaining prefix. */ + if (!sc_strempty(normalized)) { + var_append_temp(vars, normalized); + var_append_temp(vars, " "); + } else if (normalized > prefix) + var_append_temp(vars, " "); + + /* + * Print the object's name, again, as with the library, stripping any + * leading article + */ + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + if (sc_compare_word(name, "a", 1)) + name += 1; + else if (sc_compare_word(name, "an", 2)) + name += 2; + else if (sc_compare_word(name, "the", 3)) + name += 3; + else if (sc_compare_word(name, "some", 4)) + name += 4; + var_append_temp(vars, name); } static void -var_print_object (sc_gameref_t game, sc_int object) -{ - const sc_var_setref_t vars = gs_get_vars (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *prefix, *name; - - /* - * Get the object's prefix. As with the library, if the prefix is empty, - * put in an "a ". - */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (prefix)) - { - var_append_temp (vars, prefix); - var_append_temp (vars, " "); - } - else - var_append_temp (vars, "a "); - - /* Print the object's name. */ - vt_key[2].string = "Short"; - name = prop_get_string (bundle, "S<-sis", vt_key); - var_append_temp (vars, name); +var_print_object(sc_gameref_t game, sc_int object) { + const sc_var_setref_t vars = gs_get_vars(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *prefix, *name; + + /* + * Get the object's prefix. As with the library, if the prefix is empty, + * put in an "a ". + */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(prefix)) { + var_append_temp(vars, prefix); + var_append_temp(vars, " "); + } else + var_append_temp(vars, "a "); + + /* Print the object's name. */ + vt_key[2].string = "Short"; + name = prop_get_string(bundle, "S<-sis", vt_key); + var_append_temp(vars, name); } @@ -516,10 +475,9 @@ var_print_object (sc_gameref_t game, sc_int object) * on whether an object appears singular or plural. */ static const sc_char * -var_select_plurality (sc_gameref_t game, sc_int object, - const sc_char *singular, const sc_char *plural) -{ - return obj_appears_plural (game, object) ? plural : singular; +var_select_plurality(sc_gameref_t game, sc_int object, + const sc_char *singular, const sc_char *plural) { + return obj_appears_plural(game, object) ? plural : singular; } @@ -529,54 +487,46 @@ var_select_plurality (sc_gameref_t game, sc_int object, * List the objects in a given container object. */ static void -var_list_in_object (sc_gameref_t game, sc_int container) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int object, count, trail; - - /* List out the objects contained in this object. */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - /* Contained? */ - if (gs_object_position (game, object) == OBJ_IN_OBJECT - && gs_object_parent (game, object) == container) - { - if (count > 0) - { - if (count > 1) - var_append_temp (vars, ", "); - - /* Print out the current list object. */ - var_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - var_print_object (game, trail); - var_append_temp (vars, - var_select_plurality (game, trail, - " is inside ", - " are inside ")); - } - else - { - var_append_temp (vars, " and "); - var_print_object (game, trail); - var_append_temp (vars, " are inside "); - } - - /* Print out the container. */ - var_print_object_np (game, container); - var_append_temp (vars, "."); - } +var_list_in_object(sc_gameref_t game, sc_int container) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int object, count, trail; + + /* List out the objects contained in this object. */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + /* Contained? */ + if (gs_object_position(game, object) == OBJ_IN_OBJECT + && gs_object_parent(game, object) == container) { + if (count > 0) { + if (count > 1) + var_append_temp(vars, ", "); + + /* Print out the current list object. */ + var_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + var_print_object(game, trail); + var_append_temp(vars, + var_select_plurality(game, trail, + " is inside ", + " are inside ")); + } else { + var_append_temp(vars, " and "); + var_print_object(game, trail); + var_append_temp(vars, " are inside "); + } + + /* Print out the container. */ + var_print_object_np(game, container); + var_append_temp(vars, "."); + } } @@ -586,53 +536,45 @@ var_list_in_object (sc_gameref_t game, sc_int container) * List the objects on a given surface object. */ static void -var_list_on_object (sc_gameref_t game, sc_int supporter) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int object, count, trail; - - /* List out the objects standing on this object. */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - /* Standing on? */ - if (gs_object_position (game, object) == OBJ_ON_OBJECT - && gs_object_parent (game, object) == supporter) - { - if (count > 0) - { - if (count > 1) - var_append_temp (vars, ", "); - - /* Print out the current list object. */ - var_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - var_print_object (game, trail); - var_append_temp (vars, - var_select_plurality (game, trail, - " is on ", " are on ")); - } - else - { - var_append_temp (vars, " and "); - var_print_object (game, trail); - var_append_temp (vars, " are on "); - } - - /* Print out the surface. */ - var_print_object_np (game, supporter); - var_append_temp (vars, "."); - } +var_list_on_object(sc_gameref_t game, sc_int supporter) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int object, count, trail; + + /* List out the objects standing on this object. */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + /* Standing on? */ + if (gs_object_position(game, object) == OBJ_ON_OBJECT + && gs_object_parent(game, object) == supporter) { + if (count > 0) { + if (count > 1) + var_append_temp(vars, ", "); + + /* Print out the current list object. */ + var_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + var_print_object(game, trail); + var_append_temp(vars, + var_select_plurality(game, trail, + " is on ", " are on ")); + } else { + var_append_temp(vars, " and "); + var_print_object(game, trail); + var_append_temp(vars, " are on "); + } + + /* Print out the surface. */ + var_print_object_np(game, supporter); + var_append_temp(vars, "."); + } } @@ -642,115 +584,95 @@ var_list_on_object (sc_gameref_t game, sc_int supporter) * List the objects on and in a given associate object. */ static void -var_list_onin_object (sc_gameref_t game, sc_int associate) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int object, count, trail; - sc_bool supporting; - - /* List out the objects standing on this object. */ - count = 0; - trail = -1; - supporting = FALSE; - for (object = 0; object < gs_object_count (game); object++) - { - /* Standing on? */ - if (gs_object_position (game, object) == OBJ_ON_OBJECT - && gs_object_parent (game, object) == associate) - { - if (count > 0) - { - if (count > 1) - var_append_temp (vars, ", "); - - /* Print out the current list object. */ - var_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - var_print_object (game, trail); - var_append_temp (vars, - var_select_plurality (game, trail, - " is on ", " are on ")); - } - else - { - var_append_temp (vars, " and "); - var_print_object (game, trail); - var_append_temp (vars, " are on "); - } - - /* Print out the surface. */ - var_print_object_np (game, associate); - supporting = TRUE; - } - - /* List out the objects contained in this object. */ - count = 0; - trail = -1; - for (object = 0; object < gs_object_count (game); object++) - { - /* Contained? */ - if (gs_object_position (game, object) == OBJ_IN_OBJECT - && gs_object_parent (game, object) == associate) - { - if (count > 0) - { - if (count == 1) - { - if (supporting) - var_append_temp (vars, ", and "); - } - else - var_append_temp (vars, ", "); - - /* Print out the current list object. */ - var_print_object (game, trail); - } - trail = object; - count++; - } - } - if (count >= 1) - { - /* Print out final listed object. */ - if (count == 1) - { - if (supporting) - var_append_temp (vars, ", and "); - var_print_object (game, trail); - var_append_temp (vars, - var_select_plurality (game, trail, - " is inside ", - " are inside ")); - } - else - { - var_append_temp (vars, " and "); - var_print_object (game, trail); - var_append_temp (vars, " are inside"); - } - - /* Print out the container. */ - if (!supporting) - { - var_append_temp (vars, " "); - var_print_object_np (game, associate); - } - var_append_temp (vars, "."); - } - else - { - if (supporting) - var_append_temp (vars, "."); - } +var_list_onin_object(sc_gameref_t game, sc_int associate) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int object, count, trail; + sc_bool supporting; + + /* List out the objects standing on this object. */ + count = 0; + trail = -1; + supporting = FALSE; + for (object = 0; object < gs_object_count(game); object++) { + /* Standing on? */ + if (gs_object_position(game, object) == OBJ_ON_OBJECT + && gs_object_parent(game, object) == associate) { + if (count > 0) { + if (count > 1) + var_append_temp(vars, ", "); + + /* Print out the current list object. */ + var_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + var_print_object(game, trail); + var_append_temp(vars, + var_select_plurality(game, trail, + " is on ", " are on ")); + } else { + var_append_temp(vars, " and "); + var_print_object(game, trail); + var_append_temp(vars, " are on "); + } + + /* Print out the surface. */ + var_print_object_np(game, associate); + supporting = TRUE; + } + + /* List out the objects contained in this object. */ + count = 0; + trail = -1; + for (object = 0; object < gs_object_count(game); object++) { + /* Contained? */ + if (gs_object_position(game, object) == OBJ_IN_OBJECT + && gs_object_parent(game, object) == associate) { + if (count > 0) { + if (count == 1) { + if (supporting) + var_append_temp(vars, ", and "); + } else + var_append_temp(vars, ", "); + + /* Print out the current list object. */ + var_print_object(game, trail); + } + trail = object; + count++; + } + } + if (count >= 1) { + /* Print out final listed object. */ + if (count == 1) { + if (supporting) + var_append_temp(vars, ", and "); + var_print_object(game, trail); + var_append_temp(vars, + var_select_plurality(game, trail, + " is inside ", + " are inside ")); + } else { + var_append_temp(vars, " and "); + var_print_object(game, trail); + var_append_temp(vars, " are inside"); + } + + /* Print out the container. */ + if (!supporting) { + var_append_temp(vars, " "); + var_print_object_np(game, associate); + } + var_append_temp(vars, "."); + } else { + if (supporting) + var_append_temp(vars, "."); + } } @@ -764,19 +686,17 @@ var_list_onin_object (sc_gameref_t game, sc_int associate) * return value field, and always return TRUE. A macro was tempting here... */ static sc_bool -var_return_integer (sc_int value, sc_int *type, sc_vartype_t *vt_rvalue) -{ - *type = VAR_INTEGER; - vt_rvalue->integer = value; - return TRUE; +var_return_integer(sc_int value, sc_int *type, sc_vartype_t *vt_rvalue) { + *type = VAR_INTEGER; + vt_rvalue->integer = value; + return TRUE; } static sc_bool -var_return_string (const sc_char *value, sc_int *type, sc_vartype_t *vt_rvalue) -{ - *type = VAR_STRING; - vt_rvalue->string = value; - return TRUE; +var_return_string(const sc_char *value, sc_int *type, sc_vartype_t *vt_rvalue) { + *type = VAR_STRING; + vt_rvalue->string = value; + return TRUE; } @@ -787,698 +707,614 @@ var_return_string (const sc_char *value, sc_int *type, sc_vartype_t *vt_rvalue) * if invalid name passed in. Uses var_return_*() to reduce code untidiness. */ static sc_bool -var_get_system (sc_var_setref_t vars, - const sc_char *name, sc_int *type, sc_vartype_t *vt_rvalue) -{ - const sc_prop_setref_t bundle = vars->bundle; - const sc_gameref_t game = vars->game; - - /* Check name for known system variables. */ - if (strcmp (name, "author") == 0) - { - sc_vartype_t vt_key[2]; - const sc_char *author; - - /* Get and return the global gameauthor string. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "GameAuthor"; - author = prop_get_string (bundle, "S<-ss", vt_key); - if (sc_strempty (author)) - author = "[Author unknown]"; - - return var_return_string (author, type, vt_rvalue); - } - - else if (strcmp (name, "character") == 0) - { - /* See if there is a referenced character. */ - if (vars->referenced_character != -1) - { - sc_vartype_t vt_key[3]; - const sc_char *npc_name; - - /* Return the character name string. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = vars->referenced_character; - vt_key[2].string = "Name"; - npc_name = prop_get_string (bundle, "S<-sis", vt_key); - if (sc_strempty (npc_name)) - npc_name = "[Character unknown]"; - - return var_return_string (npc_name, type, vt_rvalue); - } - else - { - sc_error ("var_get_system: no referenced character yet\n"); - return var_return_string ("[Character unknown]", type, vt_rvalue); - } - } - - else if (strcmp (name, "heshe") == 0 || strcmp (name, "himher") == 0) - { - /* See if there is a referenced character. */ - if (vars->referenced_character != -1) - { - sc_vartype_t vt_key[3]; - sc_int gender; - const sc_char *retval; - - /* Return the appropriate character gender string. */ - vt_key[0].string = "NPCs"; - vt_key[1].integer = vars->referenced_character; - vt_key[2].string = "Gender"; - gender = prop_get_integer (bundle, "I<-sis", vt_key); - switch (gender) - { - case NPC_MALE: - retval = (strcmp (name, "heshe") == 0) ? "he" : "him"; - break; - case NPC_FEMALE: - retval = (strcmp (name, "heshe") == 0) ? "she" : "her"; - break; - case NPC_NEUTER: - retval = "it"; - break; - - default: - sc_error ("var_get_system: unknown gender, %ld\n", gender); - retval = "[Gender unknown]"; - break; - } - return var_return_string (retval, type, vt_rvalue); - } - else - { - sc_error ("var_get_system: no referenced character yet\n"); - return var_return_string ("[Gender unknown]", type, vt_rvalue); - } - } - - else if (strncmp (name, "in_", 3) == 0) - { - sc_int saved_ref_object = vars->referenced_object; - - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for in_\n"); - return var_return_string ("[In_ unavailable]", type, vt_rvalue); - } - if (!uip_match ("%object%", name + 3, game)) - { - sc_error ("var_get_system: invalid object for in_\n"); - return var_return_string ("[In_ unavailable]", type, vt_rvalue); - } - - /* Clear any current temporary for appends. */ - vars->temporary = (sc_char *)sc_realloc (vars->temporary, 1); - strcpy (vars->temporary, ""); - - /* Write what's in the object into temporary. */ - var_list_in_object (game, vars->referenced_object); - - /* Restore saved referenced object and return. */ - vars->referenced_object = saved_ref_object; - return var_return_string (vars->temporary, type, vt_rvalue); - } - - else if (strcmp (name, "maxscore") == 0) - { - sc_vartype_t vt_key[2]; - sc_int maxscore; - - /* Return the maximum score. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "MaxScore"; - maxscore = prop_get_integer (bundle, "I<-ss", vt_key); - - return var_return_integer (maxscore, type, vt_rvalue); - } - - else if (strcmp (name, "modified") == 0) - { - sc_vartype_t vt_key; - const sc_char *compiledate; - - /* Return the game compilation date. */ - vt_key.string = "CompileDate"; - compiledate = prop_get_string (bundle, "S<-s", &vt_key); - if (sc_strempty (compiledate)) - compiledate = "[Modified unknown]"; - - return var_return_string (compiledate, type, vt_rvalue); - } - - else if (strcmp (name, "number") == 0) - { - /* Return the referenced number, or 0 if none yet. */ - if (!vars->is_number_referenced) - sc_error ("var_get_system: no referenced number yet\n"); - - return var_return_integer (vars->referenced_number, type, vt_rvalue); - } - - else if (strcmp (name, "object") == 0) - { - /* See if we have a referenced object yet. */ - if (vars->referenced_object != -1) - { - /* Return object name with its prefix. */ - sc_vartype_t vt_key[3]; - const sc_char *prefix, *objname; - - vt_key[0].string = "Objects"; - vt_key[1].integer = vars->referenced_object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - - vars->temporary = (sc_char *)sc_realloc (vars->temporary, strlen (prefix) + 1); - strcpy (vars->temporary, prefix); - - vt_key[2].string = "Short"; - objname = prop_get_string (bundle, "S<-sis", vt_key); - - vars->temporary = (sc_char *)sc_realloc (vars->temporary, - strlen (vars->temporary) - + strlen (objname) + 2); - strcat (vars->temporary, " "); - strcat (vars->temporary, objname); - - return var_return_string (vars->temporary, type, vt_rvalue); - } - else - { - sc_error ("var_get_system: no referenced object yet\n"); - return var_return_string ("[Object unknown]", type, vt_rvalue); - } - } - - else if (strcmp (name, "obstate") == 0) - { - sc_vartype_t vt_key[3]; - sc_bool is_statussed; - sc_char *state; - - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for obstate\n"); - return var_return_string ("[Obstate unavailable]", type, vt_rvalue); - } - if (vars->referenced_object == -1) - { - sc_error ("var_get_system: no object for obstate\n"); - return var_return_string ("[Obstate unavailable]", type, vt_rvalue); - } - - /* - * If not a stateful object, Runner 4.0.45 crashes; we'll do something - * different here. - */ - vt_key[0].string = "Objects"; - vt_key[1].integer = vars->referenced_object; - vt_key[2].string = "CurrentState"; - is_statussed = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - if (!is_statussed) - return var_return_string ("stateless", type, vt_rvalue); - - /* Get state, and copy to temporary. */ - state = obj_state_name (game, vars->referenced_object); - if (!state) - { - sc_error ("var_get_system: invalid state for obstate\n"); - return var_return_string ("[Obstate unknown]", type, vt_rvalue); - } - vars->temporary = (sc_char *)sc_realloc (vars->temporary, strlen (state) + 1); - strcpy (vars->temporary, state); - sc_free (state); - - /* Return temporary. */ - return var_return_string (vars->temporary, type, vt_rvalue); - } - - else if (strcmp (name, "obstatus") == 0) - { - sc_vartype_t vt_key[3]; - sc_bool is_openable; - sc_int openness; - const sc_char *retval; - - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for obstatus\n"); - return var_return_string ("[Obstatus unavailable]", type, vt_rvalue); - } - if (vars->referenced_object == -1) - { - sc_error ("var_get_system: no object for obstatus\n"); - return var_return_string ("[Obstatus unavailable]", type, vt_rvalue); - } - - /* If not an openable object, return unopenable to match Adrift. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = vars->referenced_object; - vt_key[2].string = "Openable"; - is_openable = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - if (!is_openable) - return var_return_string ("unopenable", type, vt_rvalue); - - /* Return one of open, closed, or locked. */ - openness = gs_object_openness (game, vars->referenced_object); - switch (openness) - { - case OBJ_OPEN: - retval = "open"; - break; - case OBJ_CLOSED: - retval = "closed"; - break; - case OBJ_LOCKED: - retval = "locked"; - break; - default: - retval = "[Obstatus unknown]"; - break; - } - return var_return_string (retval, type, vt_rvalue); - } - - else if (strncmp (name, "on_", 3) == 0) - { - sc_int saved_ref_object = vars->referenced_object; - - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for on_\n"); - return var_return_string ("[On_ unavailable]", type, vt_rvalue); - } - if (!uip_match ("%object%", name + 3, game)) - { - sc_error ("var_get_system: invalid object for on_\n"); - return var_return_string ("[On_ unavailable]", type, vt_rvalue); - } - - /* Clear any current temporary for appends. */ - vars->temporary = (sc_char *)sc_realloc (vars->temporary, 1); - strcpy (vars->temporary, ""); - - /* Write what's on the object into temporary. */ - var_list_on_object (game, vars->referenced_object); - - /* Restore saved referenced object and return. */ - vars->referenced_object = saved_ref_object; - return var_return_string (vars->temporary, type, vt_rvalue); - } - - else if (strncmp (name, "onin_", 5) == 0) - { - sc_int saved_ref_object = vars->referenced_object; - - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for onin_\n"); - return var_return_string ("[Onin_ unavailable]", type, vt_rvalue); - } - if (!uip_match ("%object%", name + 5, game)) - { - sc_error ("var_get_system: invalid object for onin_\n"); - return var_return_string ("[Onin_ unavailable]", type, vt_rvalue); - } - - /* Clear any current temporary for appends. */ - vars->temporary = (sc_char *)sc_realloc (vars->temporary, 1); - strcpy (vars->temporary, ""); - - /* Write what's on/in the object into temporary. */ - var_list_onin_object (game, vars->referenced_object); - - /* Restore saved referenced object and return. */ - vars->referenced_object = saved_ref_object; - return var_return_string (vars->temporary, type, vt_rvalue); - } - - else if (strcmp (name, "player") == 0) - { - sc_vartype_t vt_key[2]; - const sc_char *playername; - - /* - * Return player's name from properties, or just "Player" if not set - * in the properties. - */ - vt_key[0].string = "Globals"; - vt_key[1].string = "PlayerName"; - playername = prop_get_string (bundle, "S<-ss", vt_key); - if (sc_strempty (playername)) - playername = "Player"; - - return var_return_string (playername, type, vt_rvalue); - } - - else if (strcmp (name, "room") == 0) - { - const sc_char *roomname; - - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for room\n"); - return var_return_string ("[Room unavailable]", type, vt_rvalue); - } - - /* Return the current player room. */ - roomname = lib_get_room_name (game, gs_playerroom (game)); - return var_return_string (roomname, type, vt_rvalue); - } - - else if (strcmp (name, "score") == 0) - { - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for score\n"); - return var_return_integer (0, type, vt_rvalue); - } - - /* Return the current game score. */ - return var_return_integer (game->score, type, vt_rvalue); - } - - else if (strncmp (name, "state_", 6) == 0) - { - sc_int saved_ref_object = vars->referenced_object; - sc_vartype_t vt_key[3]; - sc_bool is_statussed; - sc_char *state; - - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for state_\n"); - return var_return_string ("[State_ unavailable]", type, vt_rvalue); - } - if (!uip_match ("%object%", name + 6, game)) - { - sc_error ("var_get_system: invalid object for state_\n"); - return var_return_string ("[State_ unavailable]", type, vt_rvalue); - } - - /* Verify this is a stateful object. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = vars->referenced_object; - vt_key[2].string = "CurrentState"; - is_statussed = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - if (!is_statussed) - { - vars->referenced_object = saved_ref_object; - sc_error ("var_get_system: stateless object for state_\n"); - return var_return_string ("[State_ unavailable]", type, vt_rvalue); - } - - /* Get state, and copy to temporary. */ - state = obj_state_name (game, vars->referenced_object); - if (!state) - { - vars->referenced_object = saved_ref_object; - sc_error ("var_get_system: invalid state for state_\n"); - return var_return_string ("[State_ unknown]", type, vt_rvalue); - } - vars->temporary = (sc_char *)sc_realloc (vars->temporary, strlen (state) + 1); - strcpy (vars->temporary, state); - sc_free (state); - - /* Restore saved referenced object and return. */ - vars->referenced_object = saved_ref_object; - return var_return_string (vars->temporary, type, vt_rvalue); - } - - else if (strncmp (name, "status_", 7) == 0) - { - sc_int saved_ref_object = vars->referenced_object; - sc_vartype_t vt_key[3]; - sc_bool is_openable; - sc_int openness; - const sc_char *retval; - - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for status_\n"); - return var_return_string ("[Status_ unavailable]", type, vt_rvalue); - } - if (!uip_match ("%object%", name + 7, game)) - { - sc_error ("var_get_system: invalid object for status_\n"); - return var_return_string ("[Status_ unavailable]", type, vt_rvalue); - } - - /* Verify this is an openable object. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = vars->referenced_object; - vt_key[2].string = "Openable"; - is_openable = prop_get_integer (bundle, "I<-sis", vt_key) != 0; - if (!is_openable) - { - vars->referenced_object = saved_ref_object; - sc_error ("var_get_system: stateless object for status_\n"); - return var_return_string ("[Status_ unavailable]", type, vt_rvalue); - } - - /* Return one of open, closed, or locked. */ - openness = gs_object_openness (game, vars->referenced_object); - switch (openness) - { - case OBJ_OPEN: - retval = "open"; - break; - case OBJ_CLOSED: - retval = "closed"; - break; - case OBJ_LOCKED: - retval = "locked"; - break; - default: - retval = "[Status_ unknown]"; - break; - } - - /* Restore saved referenced object and return. */ - vars->referenced_object = saved_ref_object; - return var_return_string (retval, type, vt_rvalue); - } - - else if (strcmp (name, "t_number") == 0) - { - /* See if we have a referenced number yet. */ - if (vars->is_number_referenced) - { - sc_int number; - const sc_char *retval; - - /* Return the referenced number as a string. */ - number = vars->referenced_number; - if (number >= 0 && number < VAR_NUMBERS_SIZE) - retval = VAR_NUMBERS[number]; - else - { - vars->temporary = (sc_char *)sc_realloc (vars->temporary, 32); - sprintf (vars->temporary, "%ld", number); - retval = vars->temporary; - } - - return var_return_string (retval, type, vt_rvalue); - } - else - { - sc_error ("var_get_system: no referenced number yet\n"); - return var_return_string ("[Number unknown]", type, vt_rvalue); - } - } - - else if (strncmp (name, "t_", 2) == 0) - { - sc_varref_t var; - - /* Find the variable; must be a user, not a system, one. */ - var = var_find (vars, name + 2); - if (!var) - { - sc_error ("var_get_system:" - " no such variable, %s\n", name + 2); - return var_return_string ("[Unknown variable]", type, vt_rvalue); - } - else if (var->type != VAR_INTEGER) - { - sc_error ("var_get_system:" - " not an integer variable, %s\n", name + 2); - return var_return_string (var->value.string, type, vt_rvalue); - } - else - { - sc_int number; - const sc_char *retval; - - /* Return the variable value as a string. */ - number = var->value.integer; - if (number >= 0 && number < VAR_NUMBERS_SIZE) - retval = VAR_NUMBERS[number]; - else - { - vars->temporary = (sc_char *)sc_realloc (vars->temporary, 32); - sprintf (vars->temporary, "%ld", number); - retval = vars->temporary; - } - - return var_return_string (retval, type, vt_rvalue); - } - } - - else if (strcmp (name, "text") == 0) - { - const sc_char *retval; - - /* Return any referenced text, otherwise a neutral string. */ - if (vars->referenced_text) - retval = vars->referenced_text; - else - { - sc_error ("var_get_system: no text yet to reference\n"); - retval = "[Text unknown]"; - } - - return var_return_string (retval, type, vt_rvalue); - } - - else if (strcmp (name, "theobject") == 0) - { - /* See if we have a referenced object yet. */ - if (vars->referenced_object != -1) - { - /* Return object name prefixed with "the"... */ - sc_vartype_t vt_key[3]; - const sc_char *prefix, *normalized, *objname; - - vt_key[0].string = "Objects"; - vt_key[1].integer = vars->referenced_object; - vt_key[2].string = "Prefix"; - prefix = prop_get_string (bundle, "S<-sis", vt_key); - - vars->temporary = (sc_char *)sc_realloc (vars->temporary, strlen (prefix) + 5); - strcpy (vars->temporary, ""); - - normalized = prefix; - if (sc_compare_word (prefix, "a", 1)) - { - strcat (vars->temporary, "the"); - normalized = prefix + 1; - } - else if (sc_compare_word (prefix, "an", 2)) - { - strcat (vars->temporary, "the"); - normalized = prefix + 2; - } - else if (sc_compare_word (prefix, "the", 3)) - { - strcat (vars->temporary, "the"); - normalized = prefix + 3; - } - else if (sc_compare_word (prefix, "some", 4)) - { - strcat (vars->temporary, "the"); - normalized = prefix + 4; - } - else if (sc_strempty (prefix)) - strcat (vars->temporary, "the "); - - if (!sc_strempty (normalized)) - { - strcat (vars->temporary, normalized); - strcat (vars->temporary, " "); - } - else if (normalized > prefix) - strcat (vars->temporary, " "); - - vt_key[2].string = "Short"; - objname = prop_get_string (bundle, "S<-sis", vt_key); - if (sc_compare_word (objname, "a", 1)) - objname += 1; - else if (sc_compare_word (objname, "an", 2)) - objname += 2; - else if (sc_compare_word (objname, "the", 3)) - objname += 3; - else if (sc_compare_word (objname, "some", 4)) - objname += 4; - - vars->temporary = (sc_char *)sc_realloc (vars->temporary, - strlen (vars->temporary) - + strlen (objname) + 1); - strcat (vars->temporary, objname); - - return var_return_string (vars->temporary, type, vt_rvalue); - } - else - { - sc_error ("var_get_system: no referenced object yet\n"); - return var_return_string ("[Object unknown]", type, vt_rvalue); - } - } - - else if (strcmp (name, "time") == 0) - { - double delta; - sc_int retval; - - /* Return the elapsed game time in seconds. */ - delta = vars->timestamp - (g_vm->_events->getTotalPlayTicks() / 1000); - retval = (sc_int) delta + vars->time_offset; - - return var_return_integer (retval, type, vt_rvalue); - } - - else if (strcmp (name, "title") == 0) - { - sc_vartype_t vt_key[2]; - const sc_char *gamename; - - /* Return the game's title. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "GameName"; - gamename = prop_get_string (bundle, "S<-ss", vt_key); - if (sc_strempty (gamename)) - gamename = "[Title unknown]"; - - return var_return_string (gamename, type, vt_rvalue); - } - - else if (strcmp (name, "turns") == 0) - { - /* Check there's enough information to return a value. */ - if (!game) - { - sc_error ("var_get_system: no game for turns\n"); - return var_return_integer (0, type, vt_rvalue); - } - - /* Return the count of game turns. */ - return var_return_integer (game->turns, type, vt_rvalue); - } - - else if (strcmp (name, "version") == 0) - { - /* Return the Adrift emulation level of SCARE. */ - return var_return_integer (SCARE_EMULATION, type, vt_rvalue); - } - - else if (strcmp (name, "scare_version") == 0) - { - /* Private system variable, return SCARE's version number. */ - return var_return_integer (var_get_scare_version (), type, vt_rvalue); - } - - return FALSE; +var_get_system(sc_var_setref_t vars, + const sc_char *name, sc_int *type, sc_vartype_t *vt_rvalue) { + const sc_prop_setref_t bundle = vars->bundle; + const sc_gameref_t game = vars->game; + + /* Check name for known system variables. */ + if (strcmp(name, "author") == 0) { + sc_vartype_t vt_key[2]; + const sc_char *author; + + /* Get and return the global gameauthor string. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "GameAuthor"; + author = prop_get_string(bundle, "S<-ss", vt_key); + if (sc_strempty(author)) + author = "[Author unknown]"; + + return var_return_string(author, type, vt_rvalue); + } + + else if (strcmp(name, "character") == 0) { + /* See if there is a referenced character. */ + if (vars->referenced_character != -1) { + sc_vartype_t vt_key[3]; + const sc_char *npc_name; + + /* Return the character name string. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = vars->referenced_character; + vt_key[2].string = "Name"; + npc_name = prop_get_string(bundle, "S<-sis", vt_key); + if (sc_strempty(npc_name)) + npc_name = "[Character unknown]"; + + return var_return_string(npc_name, type, vt_rvalue); + } else { + sc_error("var_get_system: no referenced character yet\n"); + return var_return_string("[Character unknown]", type, vt_rvalue); + } + } + + else if (strcmp(name, "heshe") == 0 || strcmp(name, "himher") == 0) { + /* See if there is a referenced character. */ + if (vars->referenced_character != -1) { + sc_vartype_t vt_key[3]; + sc_int gender; + const sc_char *retval; + + /* Return the appropriate character gender string. */ + vt_key[0].string = "NPCs"; + vt_key[1].integer = vars->referenced_character; + vt_key[2].string = "Gender"; + gender = prop_get_integer(bundle, "I<-sis", vt_key); + switch (gender) { + case NPC_MALE: + retval = (strcmp(name, "heshe") == 0) ? "he" : "him"; + break; + case NPC_FEMALE: + retval = (strcmp(name, "heshe") == 0) ? "she" : "her"; + break; + case NPC_NEUTER: + retval = "it"; + break; + + default: + sc_error("var_get_system: unknown gender, %ld\n", gender); + retval = "[Gender unknown]"; + break; + } + return var_return_string(retval, type, vt_rvalue); + } else { + sc_error("var_get_system: no referenced character yet\n"); + return var_return_string("[Gender unknown]", type, vt_rvalue); + } + } + + else if (strncmp(name, "in_", 3) == 0) { + sc_int saved_ref_object = vars->referenced_object; + + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for in_\n"); + return var_return_string("[In_ unavailable]", type, vt_rvalue); + } + if (!uip_match("%object%", name + 3, game)) { + sc_error("var_get_system: invalid object for in_\n"); + return var_return_string("[In_ unavailable]", type, vt_rvalue); + } + + /* Clear any current temporary for appends. */ + vars->temporary = (sc_char *)sc_realloc(vars->temporary, 1); + strcpy(vars->temporary, ""); + + /* Write what's in the object into temporary. */ + var_list_in_object(game, vars->referenced_object); + + /* Restore saved referenced object and return. */ + vars->referenced_object = saved_ref_object; + return var_return_string(vars->temporary, type, vt_rvalue); + } + + else if (strcmp(name, "maxscore") == 0) { + sc_vartype_t vt_key[2]; + sc_int maxscore; + + /* Return the maximum score. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "MaxScore"; + maxscore = prop_get_integer(bundle, "I<-ss", vt_key); + + return var_return_integer(maxscore, type, vt_rvalue); + } + + else if (strcmp(name, "modified") == 0) { + sc_vartype_t vt_key; + const sc_char *compiledate; + + /* Return the game compilation date. */ + vt_key.string = "CompileDate"; + compiledate = prop_get_string(bundle, "S<-s", &vt_key); + if (sc_strempty(compiledate)) + compiledate = "[Modified unknown]"; + + return var_return_string(compiledate, type, vt_rvalue); + } + + else if (strcmp(name, "number") == 0) { + /* Return the referenced number, or 0 if none yet. */ + if (!vars->is_number_referenced) + sc_error("var_get_system: no referenced number yet\n"); + + return var_return_integer(vars->referenced_number, type, vt_rvalue); + } + + else if (strcmp(name, "object") == 0) { + /* See if we have a referenced object yet. */ + if (vars->referenced_object != -1) { + /* Return object name with its prefix. */ + sc_vartype_t vt_key[3]; + const sc_char *prefix, *objname; + + vt_key[0].string = "Objects"; + vt_key[1].integer = vars->referenced_object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + + vars->temporary = (sc_char *)sc_realloc(vars->temporary, strlen(prefix) + 1); + strcpy(vars->temporary, prefix); + + vt_key[2].string = "Short"; + objname = prop_get_string(bundle, "S<-sis", vt_key); + + vars->temporary = (sc_char *)sc_realloc(vars->temporary, + strlen(vars->temporary) + + strlen(objname) + 2); + strcat(vars->temporary, " "); + strcat(vars->temporary, objname); + + return var_return_string(vars->temporary, type, vt_rvalue); + } else { + sc_error("var_get_system: no referenced object yet\n"); + return var_return_string("[Object unknown]", type, vt_rvalue); + } + } + + else if (strcmp(name, "obstate") == 0) { + sc_vartype_t vt_key[3]; + sc_bool is_statussed; + sc_char *state; + + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for obstate\n"); + return var_return_string("[Obstate unavailable]", type, vt_rvalue); + } + if (vars->referenced_object == -1) { + sc_error("var_get_system: no object for obstate\n"); + return var_return_string("[Obstate unavailable]", type, vt_rvalue); + } + + /* + * If not a stateful object, Runner 4.0.45 crashes; we'll do something + * different here. + */ + vt_key[0].string = "Objects"; + vt_key[1].integer = vars->referenced_object; + vt_key[2].string = "CurrentState"; + is_statussed = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + if (!is_statussed) + return var_return_string("stateless", type, vt_rvalue); + + /* Get state, and copy to temporary. */ + state = obj_state_name(game, vars->referenced_object); + if (!state) { + sc_error("var_get_system: invalid state for obstate\n"); + return var_return_string("[Obstate unknown]", type, vt_rvalue); + } + vars->temporary = (sc_char *)sc_realloc(vars->temporary, strlen(state) + 1); + strcpy(vars->temporary, state); + sc_free(state); + + /* Return temporary. */ + return var_return_string(vars->temporary, type, vt_rvalue); + } + + else if (strcmp(name, "obstatus") == 0) { + sc_vartype_t vt_key[3]; + sc_bool is_openable; + sc_int openness; + const sc_char *retval; + + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for obstatus\n"); + return var_return_string("[Obstatus unavailable]", type, vt_rvalue); + } + if (vars->referenced_object == -1) { + sc_error("var_get_system: no object for obstatus\n"); + return var_return_string("[Obstatus unavailable]", type, vt_rvalue); + } + + /* If not an openable object, return unopenable to match Adrift. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = vars->referenced_object; + vt_key[2].string = "Openable"; + is_openable = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + if (!is_openable) + return var_return_string("unopenable", type, vt_rvalue); + + /* Return one of open, closed, or locked. */ + openness = gs_object_openness(game, vars->referenced_object); + switch (openness) { + case OBJ_OPEN: + retval = "open"; + break; + case OBJ_CLOSED: + retval = "closed"; + break; + case OBJ_LOCKED: + retval = "locked"; + break; + default: + retval = "[Obstatus unknown]"; + break; + } + return var_return_string(retval, type, vt_rvalue); + } + + else if (strncmp(name, "on_", 3) == 0) { + sc_int saved_ref_object = vars->referenced_object; + + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for on_\n"); + return var_return_string("[On_ unavailable]", type, vt_rvalue); + } + if (!uip_match("%object%", name + 3, game)) { + sc_error("var_get_system: invalid object for on_\n"); + return var_return_string("[On_ unavailable]", type, vt_rvalue); + } + + /* Clear any current temporary for appends. */ + vars->temporary = (sc_char *)sc_realloc(vars->temporary, 1); + strcpy(vars->temporary, ""); + + /* Write what's on the object into temporary. */ + var_list_on_object(game, vars->referenced_object); + + /* Restore saved referenced object and return. */ + vars->referenced_object = saved_ref_object; + return var_return_string(vars->temporary, type, vt_rvalue); + } + + else if (strncmp(name, "onin_", 5) == 0) { + sc_int saved_ref_object = vars->referenced_object; + + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for onin_\n"); + return var_return_string("[Onin_ unavailable]", type, vt_rvalue); + } + if (!uip_match("%object%", name + 5, game)) { + sc_error("var_get_system: invalid object for onin_\n"); + return var_return_string("[Onin_ unavailable]", type, vt_rvalue); + } + + /* Clear any current temporary for appends. */ + vars->temporary = (sc_char *)sc_realloc(vars->temporary, 1); + strcpy(vars->temporary, ""); + + /* Write what's on/in the object into temporary. */ + var_list_onin_object(game, vars->referenced_object); + + /* Restore saved referenced object and return. */ + vars->referenced_object = saved_ref_object; + return var_return_string(vars->temporary, type, vt_rvalue); + } + + else if (strcmp(name, "player") == 0) { + sc_vartype_t vt_key[2]; + const sc_char *playername; + + /* + * Return player's name from properties, or just "Player" if not set + * in the properties. + */ + vt_key[0].string = "Globals"; + vt_key[1].string = "PlayerName"; + playername = prop_get_string(bundle, "S<-ss", vt_key); + if (sc_strempty(playername)) + playername = "Player"; + + return var_return_string(playername, type, vt_rvalue); + } + + else if (strcmp(name, "room") == 0) { + const sc_char *roomname; + + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for room\n"); + return var_return_string("[Room unavailable]", type, vt_rvalue); + } + + /* Return the current player room. */ + roomname = lib_get_room_name(game, gs_playerroom(game)); + return var_return_string(roomname, type, vt_rvalue); + } + + else if (strcmp(name, "score") == 0) { + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for score\n"); + return var_return_integer(0, type, vt_rvalue); + } + + /* Return the current game score. */ + return var_return_integer(game->score, type, vt_rvalue); + } + + else if (strncmp(name, "state_", 6) == 0) { + sc_int saved_ref_object = vars->referenced_object; + sc_vartype_t vt_key[3]; + sc_bool is_statussed; + sc_char *state; + + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for state_\n"); + return var_return_string("[State_ unavailable]", type, vt_rvalue); + } + if (!uip_match("%object%", name + 6, game)) { + sc_error("var_get_system: invalid object for state_\n"); + return var_return_string("[State_ unavailable]", type, vt_rvalue); + } + + /* Verify this is a stateful object. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = vars->referenced_object; + vt_key[2].string = "CurrentState"; + is_statussed = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + if (!is_statussed) { + vars->referenced_object = saved_ref_object; + sc_error("var_get_system: stateless object for state_\n"); + return var_return_string("[State_ unavailable]", type, vt_rvalue); + } + + /* Get state, and copy to temporary. */ + state = obj_state_name(game, vars->referenced_object); + if (!state) { + vars->referenced_object = saved_ref_object; + sc_error("var_get_system: invalid state for state_\n"); + return var_return_string("[State_ unknown]", type, vt_rvalue); + } + vars->temporary = (sc_char *)sc_realloc(vars->temporary, strlen(state) + 1); + strcpy(vars->temporary, state); + sc_free(state); + + /* Restore saved referenced object and return. */ + vars->referenced_object = saved_ref_object; + return var_return_string(vars->temporary, type, vt_rvalue); + } + + else if (strncmp(name, "status_", 7) == 0) { + sc_int saved_ref_object = vars->referenced_object; + sc_vartype_t vt_key[3]; + sc_bool is_openable; + sc_int openness; + const sc_char *retval; + + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for status_\n"); + return var_return_string("[Status_ unavailable]", type, vt_rvalue); + } + if (!uip_match("%object%", name + 7, game)) { + sc_error("var_get_system: invalid object for status_\n"); + return var_return_string("[Status_ unavailable]", type, vt_rvalue); + } + + /* Verify this is an openable object. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = vars->referenced_object; + vt_key[2].string = "Openable"; + is_openable = prop_get_integer(bundle, "I<-sis", vt_key) != 0; + if (!is_openable) { + vars->referenced_object = saved_ref_object; + sc_error("var_get_system: stateless object for status_\n"); + return var_return_string("[Status_ unavailable]", type, vt_rvalue); + } + + /* Return one of open, closed, or locked. */ + openness = gs_object_openness(game, vars->referenced_object); + switch (openness) { + case OBJ_OPEN: + retval = "open"; + break; + case OBJ_CLOSED: + retval = "closed"; + break; + case OBJ_LOCKED: + retval = "locked"; + break; + default: + retval = "[Status_ unknown]"; + break; + } + + /* Restore saved referenced object and return. */ + vars->referenced_object = saved_ref_object; + return var_return_string(retval, type, vt_rvalue); + } + + else if (strcmp(name, "t_number") == 0) { + /* See if we have a referenced number yet. */ + if (vars->is_number_referenced) { + sc_int number; + const sc_char *retval; + + /* Return the referenced number as a string. */ + number = vars->referenced_number; + if (number >= 0 && number < VAR_NUMBERS_SIZE) + retval = VAR_NUMBERS[number]; + else { + vars->temporary = (sc_char *)sc_realloc(vars->temporary, 32); + sprintf(vars->temporary, "%ld", number); + retval = vars->temporary; + } + + return var_return_string(retval, type, vt_rvalue); + } else { + sc_error("var_get_system: no referenced number yet\n"); + return var_return_string("[Number unknown]", type, vt_rvalue); + } + } + + else if (strncmp(name, "t_", 2) == 0) { + sc_varref_t var; + + /* Find the variable; must be a user, not a system, one. */ + var = var_find(vars, name + 2); + if (!var) { + sc_error("var_get_system:" + " no such variable, %s\n", name + 2); + return var_return_string("[Unknown variable]", type, vt_rvalue); + } else if (var->type != VAR_INTEGER) { + sc_error("var_get_system:" + " not an integer variable, %s\n", name + 2); + return var_return_string(var->value.string, type, vt_rvalue); + } else { + sc_int number; + const sc_char *retval; + + /* Return the variable value as a string. */ + number = var->value.integer; + if (number >= 0 && number < VAR_NUMBERS_SIZE) + retval = VAR_NUMBERS[number]; + else { + vars->temporary = (sc_char *)sc_realloc(vars->temporary, 32); + sprintf(vars->temporary, "%ld", number); + retval = vars->temporary; + } + + return var_return_string(retval, type, vt_rvalue); + } + } + + else if (strcmp(name, "text") == 0) { + const sc_char *retval; + + /* Return any referenced text, otherwise a neutral string. */ + if (vars->referenced_text) + retval = vars->referenced_text; + else { + sc_error("var_get_system: no text yet to reference\n"); + retval = "[Text unknown]"; + } + + return var_return_string(retval, type, vt_rvalue); + } + + else if (strcmp(name, "theobject") == 0) { + /* See if we have a referenced object yet. */ + if (vars->referenced_object != -1) { + /* Return object name prefixed with "the"... */ + sc_vartype_t vt_key[3]; + const sc_char *prefix, *normalized, *objname; + + vt_key[0].string = "Objects"; + vt_key[1].integer = vars->referenced_object; + vt_key[2].string = "Prefix"; + prefix = prop_get_string(bundle, "S<-sis", vt_key); + + vars->temporary = (sc_char *)sc_realloc(vars->temporary, strlen(prefix) + 5); + strcpy(vars->temporary, ""); + + normalized = prefix; + if (sc_compare_word(prefix, "a", 1)) { + strcat(vars->temporary, "the"); + normalized = prefix + 1; + } else if (sc_compare_word(prefix, "an", 2)) { + strcat(vars->temporary, "the"); + normalized = prefix + 2; + } else if (sc_compare_word(prefix, "the", 3)) { + strcat(vars->temporary, "the"); + normalized = prefix + 3; + } else if (sc_compare_word(prefix, "some", 4)) { + strcat(vars->temporary, "the"); + normalized = prefix + 4; + } else if (sc_strempty(prefix)) + strcat(vars->temporary, "the "); + + if (!sc_strempty(normalized)) { + strcat(vars->temporary, normalized); + strcat(vars->temporary, " "); + } else if (normalized > prefix) + strcat(vars->temporary, " "); + + vt_key[2].string = "Short"; + objname = prop_get_string(bundle, "S<-sis", vt_key); + if (sc_compare_word(objname, "a", 1)) + objname += 1; + else if (sc_compare_word(objname, "an", 2)) + objname += 2; + else if (sc_compare_word(objname, "the", 3)) + objname += 3; + else if (sc_compare_word(objname, "some", 4)) + objname += 4; + + vars->temporary = (sc_char *)sc_realloc(vars->temporary, + strlen(vars->temporary) + + strlen(objname) + 1); + strcat(vars->temporary, objname); + + return var_return_string(vars->temporary, type, vt_rvalue); + } else { + sc_error("var_get_system: no referenced object yet\n"); + return var_return_string("[Object unknown]", type, vt_rvalue); + } + } + + else if (strcmp(name, "time") == 0) { + double delta; + sc_int retval; + + /* Return the elapsed game time in seconds. */ + delta = vars->timestamp - (g_vm->_events->getTotalPlayTicks() / 1000); + retval = (sc_int) delta + vars->time_offset; + + return var_return_integer(retval, type, vt_rvalue); + } + + else if (strcmp(name, "title") == 0) { + sc_vartype_t vt_key[2]; + const sc_char *gamename; + + /* Return the game's title. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "GameName"; + gamename = prop_get_string(bundle, "S<-ss", vt_key); + if (sc_strempty(gamename)) + gamename = "[Title unknown]"; + + return var_return_string(gamename, type, vt_rvalue); + } + + else if (strcmp(name, "turns") == 0) { + /* Check there's enough information to return a value. */ + if (!game) { + sc_error("var_get_system: no game for turns\n"); + return var_return_integer(0, type, vt_rvalue); + } + + /* Return the count of game turns. */ + return var_return_integer(game->turns, type, vt_rvalue); + } + + else if (strcmp(name, "version") == 0) { + /* Return the Adrift emulation level of SCARE. */ + return var_return_integer(SCARE_EMULATION, type, vt_rvalue); + } + + else if (strcmp(name, "scare_version") == 0) { + /* Private system variable, return SCARE's version number. */ + return var_return_integer(var_get_scare_version(), type, vt_rvalue); + } + + return FALSE; } @@ -1489,35 +1325,32 @@ var_get_system (sc_var_setref_t vars, * name passed in is not a defined user variable. */ static sc_bool -var_get_user (sc_var_setref_t vars, - const sc_char *name, sc_int *type, sc_vartype_t *vt_rvalue) -{ - sc_varref_t var; - - /* Check user variables for a reference to the named variable. */ - var = var_find (vars, name); - if (var) - { - /* Copy out variable details. */ - *type = var->type; - switch (var->type) - { - case VAR_INTEGER: - vt_rvalue->integer = var->value.integer; - break; - case VAR_STRING: - vt_rvalue->string = var->value.string; - break; - - default: - sc_fatal ("var_get_user: invalid variable type, %ld\n", var->type); - } - - /* Return success. */ - return TRUE; - } - - return FALSE; +var_get_user(sc_var_setref_t vars, + const sc_char *name, sc_int *type, sc_vartype_t *vt_rvalue) { + sc_varref_t var; + + /* Check user variables for a reference to the named variable. */ + var = var_find(vars, name); + if (var) { + /* Copy out variable details. */ + *type = var->type; + switch (var->type) { + case VAR_INTEGER: + vt_rvalue->integer = var->value.integer; + break; + case VAR_STRING: + vt_rvalue->string = var->value.string; + break; + + default: + sc_fatal("var_get_user: invalid variable type, %ld\n", var->type); + } + + /* Return success. */ + return TRUE; + } + + return FALSE; } @@ -1528,47 +1361,42 @@ var_get_user (sc_var_setref_t vars, * named variable does not exist. */ sc_bool -var_get (sc_var_setref_t vars, - const sc_char *name, sc_int *type, sc_vartype_t *vt_rvalue) -{ - sc_bool status; - assert (var_is_valid (vars)); - assert (name && type && vt_rvalue); - - /* - * Check user and system variables for a reference to the name. User - * variables take precedence over system ones; that is, they may override - * them in a game. - */ - status = var_get_user (vars, name, type, vt_rvalue); - if (!status) - status = var_get_system (vars, name, type, vt_rvalue); - - if (var_trace) - { - if (status) - { - sc_trace ("Variable: %%%s%% retrieved, ", name); - switch (*type) - { - case VAR_INTEGER: - sc_trace ("%ld", vt_rvalue->integer); - break; - case VAR_STRING: - sc_trace ("\"%s\"", vt_rvalue->string); - break; - - default: - sc_trace ("Variable: invalid variable type, %ld\n", *type); - break; - } - sc_trace ("\n"); - } - else - sc_trace ("Variable: \"%s\", no such variable\n", name); - } - - return status; +var_get(sc_var_setref_t vars, + const sc_char *name, sc_int *type, sc_vartype_t *vt_rvalue) { + sc_bool status; + assert(var_is_valid(vars)); + assert(name && type && vt_rvalue); + + /* + * Check user and system variables for a reference to the name. User + * variables take precedence over system ones; that is, they may override + * them in a game. + */ + status = var_get_user(vars, name, type, vt_rvalue); + if (!status) + status = var_get_system(vars, name, type, vt_rvalue); + + if (var_trace) { + if (status) { + sc_trace("Variable: %%%s%% retrieved, ", name); + switch (*type) { + case VAR_INTEGER: + sc_trace("%ld", vt_rvalue->integer); + break; + case VAR_STRING: + sc_trace("\"%s\"", vt_rvalue->string); + break; + + default: + sc_trace("Variable: invalid variable type, %ld\n", *type); + break; + } + sc_trace("\n"); + } else + sc_trace("Variable: \"%s\", no such variable\n", name); + } + + return status; } @@ -1580,28 +1408,26 @@ var_get (sc_var_setref_t vars, * an error for the variable not to exist or to have the wrong type. */ void -var_put_integer (sc_var_setref_t vars, const sc_char *name, sc_int value) -{ - sc_vartype_t vt_value; - assert (var_is_valid (vars)); +var_put_integer(sc_var_setref_t vars, const sc_char *name, sc_int value) { + sc_vartype_t vt_value; + assert(var_is_valid(vars)); - vt_value.integer = value; - var_put (vars, name, VAR_INTEGER, vt_value); + vt_value.integer = value; + var_put(vars, name, VAR_INTEGER, vt_value); } sc_int -var_get_integer (sc_var_setref_t vars, const sc_char *name) -{ - sc_vartype_t vt_rvalue; - sc_int type; - assert (var_is_valid (vars)); - - if (!var_get (vars, name, &type, &vt_rvalue)) - sc_fatal ("var_get_integer: no such variable, %s\n", name); - else if (type != VAR_INTEGER) - sc_fatal ("var_get_integer: not an integer, %s\n", name); - - return vt_rvalue.integer; +var_get_integer(sc_var_setref_t vars, const sc_char *name) { + sc_vartype_t vt_rvalue; + sc_int type; + assert(var_is_valid(vars)); + + if (!var_get(vars, name, &type, &vt_rvalue)) + sc_fatal("var_get_integer: no such variable, %s\n", name); + else if (type != VAR_INTEGER) + sc_fatal("var_get_integer: not an integer, %s\n", name); + + return vt_rvalue.integer; } @@ -1613,29 +1439,27 @@ var_get_integer (sc_var_setref_t vars, const sc_char *name) * an error for the variable not to exist or to have the wrong type. */ void -var_put_string (sc_var_setref_t vars, - const sc_char *name, const sc_char *string) -{ - sc_vartype_t vt_value; - assert (var_is_valid (vars)); - - vt_value.string = string; - var_put (vars, name, VAR_STRING, vt_value); +var_put_string(sc_var_setref_t vars, + const sc_char *name, const sc_char *string) { + sc_vartype_t vt_value; + assert(var_is_valid(vars)); + + vt_value.string = string; + var_put(vars, name, VAR_STRING, vt_value); } const sc_char * -var_get_string (sc_var_setref_t vars, const sc_char *name) -{ - sc_vartype_t vt_rvalue; - sc_int type; - assert (var_is_valid (vars)); - - if (!var_get (vars, name, &type, &vt_rvalue)) - sc_fatal ("var_get_string: no such variable, %s\n", name); - else if (type != VAR_STRING) - sc_fatal ("var_get_string: not a string, %s\n", name); - - return vt_rvalue.string; +var_get_string(sc_var_setref_t vars, const sc_char *name) { + sc_vartype_t vt_rvalue; + sc_int type; + assert(var_is_valid(vars)); + + if (!var_get(vars, name, &type, &vt_rvalue)) + sc_fatal("var_get_string: no such variable, %s\n", name); + else if (type != VAR_STRING) + sc_fatal("var_get_string: not a string, %s\n", name); + + return vt_rvalue.string; } @@ -1646,65 +1470,60 @@ var_get_string (sc_var_setref_t vars, const sc_char *name) * properties bundle passed in. */ sc_var_setref_t -var_create (sc_prop_setref_t bundle) -{ - sc_var_setref_t vars; - sc_int var_count, index_; - sc_vartype_t vt_key[3]; - assert (bundle); - - /* Create a clean set of variables to fill from the bundle. */ - vars = var_create_empty (); - vars->bundle = bundle; - - /* Retrieve the count of variables. */ - vt_key[0].string = "Variables"; - var_count = prop_get_child_count (bundle, "I<-s", vt_key); - - /* Create a variable for each variable property held. */ - for (index_ = 0; index_ < var_count; index_++) - { - const sc_char *name; - sc_int var_type; - const sc_char *value; - - /* Retrieve variable name, type, and string initial value. */ - vt_key[1].integer = index_; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - - vt_key[2].string = "Type"; - var_type = prop_get_integer (bundle, "I<-sis", vt_key); - - vt_key[2].string = "Value"; - value = prop_get_string (bundle, "S<-sis", vt_key); - - /* Handle numerics and strings differently. */ - switch (var_type) - { - case TAFVAR_NUMERIC: - { - sc_int integer_value; - if (sscanf (value, "%ld", &integer_value) != 1) - { - sc_error ("var_create:" - " invalid numeric variable %s, %s\n", name, value); - integer_value = 0; - } - var_put_integer (vars, name, integer_value); - break; - } - - case TAFVAR_STRING: - var_put_string (vars, name, value); - break; - - default: - sc_fatal ("var_create: invalid variable type, %ld\n", var_type); - } - } - - return vars; +var_create(sc_prop_setref_t bundle) { + sc_var_setref_t vars; + sc_int var_count, index_; + sc_vartype_t vt_key[3]; + assert(bundle); + + /* Create a clean set of variables to fill from the bundle. */ + vars = var_create_empty(); + vars->bundle = bundle; + + /* Retrieve the count of variables. */ + vt_key[0].string = "Variables"; + var_count = prop_get_child_count(bundle, "I<-s", vt_key); + + /* Create a variable for each variable property held. */ + for (index_ = 0; index_ < var_count; index_++) { + const sc_char *name; + sc_int var_type; + const sc_char *value; + + /* Retrieve variable name, type, and string initial value. */ + vt_key[1].integer = index_; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + + vt_key[2].string = "Type"; + var_type = prop_get_integer(bundle, "I<-sis", vt_key); + + vt_key[2].string = "Value"; + value = prop_get_string(bundle, "S<-sis", vt_key); + + /* Handle numerics and strings differently. */ + switch (var_type) { + case TAFVAR_NUMERIC: { + sc_int integer_value; + if (sscanf(value, "%ld", &integer_value) != 1) { + sc_error("var_create:" + " invalid numeric variable %s, %s\n", name, value); + integer_value = 0; + } + var_put_integer(vars, name, integer_value); + break; + } + + case TAFVAR_STRING: + var_put_string(vars, name, value); + break; + + default: + sc_fatal("var_create: invalid variable type, %ld\n", var_type); + } + } + + return vars; } @@ -1716,15 +1535,14 @@ var_create (sc_prop_setref_t bundle) * reference this variable set. */ void -var_register_game (sc_var_setref_t vars, sc_gameref_t game) -{ - assert (var_is_valid (vars)); - assert (gs_is_game_valid (game)); +var_register_game(sc_var_setref_t vars, sc_gameref_t game) { + assert(var_is_valid(vars)); + assert(gs_is_game_valid(game)); - if (vars != gs_get_vars (game)) - sc_fatal ("var_register_game: game binding error\n"); + if (vars != gs_get_vars(game)) + sc_fatal("var_register_game: game binding error\n"); - vars->game = game; + vars->game = game; } @@ -1737,35 +1555,31 @@ var_register_game (sc_var_setref_t vars, sc_gameref_t game) * Set the "referenced" character, object, number, and text. */ void -var_set_ref_character (sc_var_setref_t vars, sc_int character) -{ - assert (var_is_valid (vars)); - vars->referenced_character = character; +var_set_ref_character(sc_var_setref_t vars, sc_int character) { + assert(var_is_valid(vars)); + vars->referenced_character = character; } void -var_set_ref_object (sc_var_setref_t vars, sc_int object) -{ - assert (var_is_valid (vars)); - vars->referenced_object = object; +var_set_ref_object(sc_var_setref_t vars, sc_int object) { + assert(var_is_valid(vars)); + vars->referenced_object = object; } void -var_set_ref_number (sc_var_setref_t vars, sc_int number) -{ - assert (var_is_valid (vars)); - vars->referenced_number = number; - vars->is_number_referenced = TRUE; +var_set_ref_number(sc_var_setref_t vars, sc_int number) { + assert(var_is_valid(vars)); + vars->referenced_number = number; + vars->is_number_referenced = TRUE; } void -var_set_ref_text (sc_var_setref_t vars, const sc_char *text) -{ - assert (var_is_valid (vars)); +var_set_ref_text(sc_var_setref_t vars, const sc_char *text) { + assert(var_is_valid(vars)); - /* Take a copy of the string, and retain it. */ - vars->referenced_text = (sc_char *)sc_realloc (vars->referenced_text, strlen (text) + 1); - strcpy (vars->referenced_text, text); + /* Take a copy of the string, and retain it. */ + vars->referenced_text = (sc_char *)sc_realloc(vars->referenced_text, strlen(text) + 1); + strcpy(vars->referenced_text, text); } @@ -1778,37 +1592,33 @@ var_set_ref_text (sc_var_setref_t vars, const sc_char *text) * Get the "referenced" character, object, number, and text. */ sc_int -var_get_ref_character (sc_var_setref_t vars) -{ - assert (var_is_valid (vars)); - return vars->referenced_character; +var_get_ref_character(sc_var_setref_t vars) { + assert(var_is_valid(vars)); + return vars->referenced_character; } sc_int -var_get_ref_object (sc_var_setref_t vars) -{ - assert (var_is_valid (vars)); - return vars->referenced_object; +var_get_ref_object(sc_var_setref_t vars) { + assert(var_is_valid(vars)); + return vars->referenced_object; } sc_int -var_get_ref_number (sc_var_setref_t vars) -{ - assert (var_is_valid (vars)); - return vars->referenced_number; +var_get_ref_number(sc_var_setref_t vars) { + assert(var_is_valid(vars)); + return vars->referenced_number; } const sc_char * -var_get_ref_text (sc_var_setref_t vars) -{ - assert (var_is_valid (vars)); - - /* - * If currently nullptr, return "". A game may check restrictions involving - * referenced text before any value has been set; returning "" here for - * this case prevents problems later (strcmp (nullptr, ...), for example). - */ - return vars->referenced_text ? vars->referenced_text : ""; +var_get_ref_text(sc_var_setref_t vars) { + assert(var_is_valid(vars)); + + /* + * If currently nullptr, return "". A game may check restrictions involving + * referenced text before any value has been set; returning "" here for + * this case prevents problems later (strcmp (nullptr, ...), for example). + */ + return vars->referenced_text ? vars->referenced_text : ""; } @@ -1820,27 +1630,25 @@ var_get_ref_text (sc_var_setref_t vars) * of game), and set the count to a given value (game restore). */ sc_uint -var_get_elapsed_seconds (sc_var_setref_t vars) -{ - double delta; - assert (var_is_valid (vars)); +var_get_elapsed_seconds(sc_var_setref_t vars) { + double delta; + assert(var_is_valid(vars)); - delta = vars->timestamp - g_vm->_events->getTotalPlayTicks(); - return (sc_uint) delta + vars->time_offset; + delta = vars->timestamp - g_vm->_events->getTotalPlayTicks(); + return (sc_uint) delta + vars->time_offset; } void -var_set_elapsed_seconds (sc_var_setref_t vars, sc_uint seconds) -{ - assert (var_is_valid (vars)); - - /* - * Reset the timestamp to now, and store seconds in offset. This is sort-of - * forced by the fact that ANSI offers difftime but no 'settime' -- here, - * we'd really want to set the timestamp to now less seconds. - */ - vars->timestamp = g_vm->_events->getTotalPlayTicks() / 1000; - vars->time_offset = seconds; +var_set_elapsed_seconds(sc_var_setref_t vars, sc_uint seconds) { + assert(var_is_valid(vars)); + + /* + * Reset the timestamp to now, and store seconds in offset. This is sort-of + * forced by the fact that ANSI offers difftime but no 'settime' -- here, + * we'd really want to set the timestamp to now less seconds. + */ + vars->timestamp = g_vm->_events->getTotalPlayTicks() / 1000; + vars->time_offset = seconds; } @@ -1850,9 +1658,8 @@ var_set_elapsed_seconds (sc_var_setref_t vars, sc_uint seconds) * Set variable tracing on/off. */ void -var_debug_trace (sc_bool flag) -{ - var_trace = flag; +var_debug_trace(sc_bool flag) { + var_trace = flag; } @@ -1862,56 +1669,52 @@ var_debug_trace (sc_bool flag) * Print out a complete variables set. */ void -var_debug_dump (sc_var_setref_t vars) -{ - sc_int index_; - sc_varref_t var; - assert (var_is_valid (vars)); - - /* Dump complete structure. */ - sc_trace ("Variable: debug dump follows...\n"); - sc_trace ("vars->bundle = %p\n", (void *) vars->bundle); - sc_trace ("vars->referenced_character = %ld\n", vars->referenced_character); - sc_trace ("vars->referenced_object = %ld\n", vars->referenced_object); - sc_trace ("vars->referenced_number = %ld\n", vars->referenced_number); - sc_trace ("vars->is_number_referenced = %s\n", - vars->is_number_referenced ? "true" : "false"); - - sc_trace ("vars->referenced_text = "); - if (vars->referenced_text) - sc_trace ("\"%s\"\n", vars->referenced_text); - else - sc_trace ("(nil)\n"); - - sc_trace ("vars->temporary = %p\n", (void *) vars->temporary); - sc_trace("vars->timestamp = %lu\n", (sc_uint) vars->timestamp); - sc_trace ("vars->game = %p\n", (void *) vars->game); - - sc_trace ("vars->variables =\n"); - for (index_ = 0; index_ < VAR_HASH_TABLE_SIZE; index_++) - { - for (var = vars->variable[index_]; var; var = var->next) - { - if (var == vars->variable[index_]) - sc_trace ("%3ld : ", index_); - else - sc_trace (" : "); - switch (var->type) - { - case VAR_STRING: - sc_trace ("[String ] %s = \"%s\"", var->name, var->value.string); - break; - case VAR_INTEGER: - sc_trace ("[Integer] %s = %ld", var->name, var->value.integer); - break; - - default: - sc_trace ("[Invalid] %s = %p", var->name, var->value.voidp); - break; - } - sc_trace ("\n"); - } - } +var_debug_dump(sc_var_setref_t vars) { + sc_int index_; + sc_varref_t var; + assert(var_is_valid(vars)); + + /* Dump complete structure. */ + sc_trace("Variable: debug dump follows...\n"); + sc_trace("vars->bundle = %p\n", (void *) vars->bundle); + sc_trace("vars->referenced_character = %ld\n", vars->referenced_character); + sc_trace("vars->referenced_object = %ld\n", vars->referenced_object); + sc_trace("vars->referenced_number = %ld\n", vars->referenced_number); + sc_trace("vars->is_number_referenced = %s\n", + vars->is_number_referenced ? "true" : "false"); + + sc_trace("vars->referenced_text = "); + if (vars->referenced_text) + sc_trace("\"%s\"\n", vars->referenced_text); + else + sc_trace("(nil)\n"); + + sc_trace("vars->temporary = %p\n", (void *) vars->temporary); + sc_trace("vars->timestamp = %lu\n", (sc_uint) vars->timestamp); + sc_trace("vars->game = %p\n", (void *) vars->game); + + sc_trace("vars->variables =\n"); + for (index_ = 0; index_ < VAR_HASH_TABLE_SIZE; index_++) { + for (var = vars->variable[index_]; var; var = var->next) { + if (var == vars->variable[index_]) + sc_trace("%3ld : ", index_); + else + sc_trace(" : "); + switch (var->type) { + case VAR_STRING: + sc_trace("[String ] %s = \"%s\"", var->name, var->value.string); + break; + case VAR_INTEGER: + sc_trace("[Integer] %s = %ld", var->name, var->value.integer); + break; + + default: + sc_trace("[Invalid] %s = %p", var->name, var->value.voidp); + break; + } + sc_trace("\n"); + } + } } } // End of namespace Adrift diff --git a/engines/glk/adrift/sxfile.cpp b/engines/glk/adrift/sxfile.cpp index 41cfcc485e..4b91db9687 100644 --- a/engines/glk/adrift/sxfile.cpp +++ b/engines/glk/adrift/sxfile.cpp @@ -32,10 +32,10 @@ namespace Adrift { * only one of these to exist. */ struct sx_scr_stream_t { - sc_byte *data; - sc_int length; - sc_bool is_open; - sc_bool is_writable; + sc_byte *data; + sc_int length; + sc_bool is_open; + sc_bool is_writable; }; static sx_scr_stream_t scr_serialization_stream = {NULL, 0, FALSE, FALSE}; @@ -51,132 +51,109 @@ static sx_scr_stream_t scr_serialization_stream = {NULL, 0, FALSE, FALSE}; * exist, meaning that a script must restore a saved game before trying to * save another. */ -void *file_open_file_callback (sc_bool is_save) -{ - sx_scr_stream_t *const stream = &scr_serialization_stream; - - /* Detect any problems due to scripting limitations. */ - if (stream->is_open) - { - scr_test_failed ("File open error: %s", - "stream is in use (script limitation)"); - return NULL; - } - else if (is_save && stream->data) - { - scr_test_failed ("File open error: %s", - "stream has not been read (script limitation)"); - return NULL; - } - - /* - * Set up the stream for the requested mode. Act as if no such file if - * no data available for a read-only open. - */ - if (is_save) - { - stream->data = NULL; - stream->length = 0; - } - else if (!stream->data) - return NULL; - - stream->is_open = TRUE; - stream->is_writable = is_save; - return stream; +void *file_open_file_callback(sc_bool is_save) { + sx_scr_stream_t *const stream = &scr_serialization_stream; + + /* Detect any problems due to scripting limitations. */ + if (stream->is_open) { + scr_test_failed("File open error: %s", + "stream is in use (script limitation)"); + return NULL; + } else if (is_save && stream->data) { + scr_test_failed("File open error: %s", + "stream has not been read (script limitation)"); + return NULL; + } + + /* + * Set up the stream for the requested mode. Act as if no such file if + * no data available for a read-only open. + */ + if (is_save) { + stream->data = NULL; + stream->length = 0; + } else if (!stream->data) + return NULL; + + stream->is_open = TRUE; + stream->is_writable = is_save; + return stream; } sc_int -file_read_file_callback (void *opaque, sc_byte *buffer, sc_int length) -{ - sx_scr_stream_t *const stream = (sx_scr_stream_t *)opaque; - sc_int bytes; - assert (opaque && buffer && length > 0); - - /* Detect any problems with the callback parameters. */ - if (stream != &scr_serialization_stream) - { - scr_test_failed ("File read error: %s", "stream is invalid"); - return 0; - } - else if (!stream->is_open) - { - scr_test_failed ("File read error: %s", "stream is not open"); - return 0; - } - else if (stream->is_writable) - { - scr_test_failed ("File read error: %s", "stream is not open for read"); - return 0; - } - - /* Read and remove the first block of data (or all if less than length). */ - bytes = (stream->length < length) ? stream->length : length; - memcpy (buffer, stream->data, bytes); - memmove (stream->data, stream->data + bytes, stream->length - bytes); - stream->length -= bytes; - return bytes; +file_read_file_callback(void *opaque, sc_byte *buffer, sc_int length) { + sx_scr_stream_t *const stream = (sx_scr_stream_t *)opaque; + sc_int bytes; + assert(opaque && buffer && length > 0); + + /* Detect any problems with the callback parameters. */ + if (stream != &scr_serialization_stream) { + scr_test_failed("File read error: %s", "stream is invalid"); + return 0; + } else if (!stream->is_open) { + scr_test_failed("File read error: %s", "stream is not open"); + return 0; + } else if (stream->is_writable) { + scr_test_failed("File read error: %s", "stream is not open for read"); + return 0; + } + + /* Read and remove the first block of data (or all if less than length). */ + bytes = (stream->length < length) ? stream->length : length; + memcpy(buffer, stream->data, bytes); + memmove(stream->data, stream->data + bytes, stream->length - bytes); + stream->length -= bytes; + return bytes; } void -file_write_file_callback (void *opaque, const sc_byte *buffer, sc_int length) -{ - sx_scr_stream_t *const stream = (sx_scr_stream_t *)opaque; - assert (opaque && buffer && length > 0); - - /* Detect any problems with the callback parameters. */ - if (stream != &scr_serialization_stream) - { - scr_test_failed ("File write error: %s", "stream is invalid"); - return; - } - else if (!stream->is_open) - { - scr_test_failed ("File write error: %s", "stream is not open"); - return; - } - else if (!stream->is_writable) - { - scr_test_failed ("File write error: %s", "stream is not open for write"); - return; - } - - /* Reallocate, then add this block of data to the buffer. */ - stream->data = (sc_byte *)sx_realloc(stream->data, stream->length + length); - memcpy (stream->data + stream->length, buffer, length); - stream->length += length; +file_write_file_callback(void *opaque, const sc_byte *buffer, sc_int length) { + sx_scr_stream_t *const stream = (sx_scr_stream_t *)opaque; + assert(opaque && buffer && length > 0); + + /* Detect any problems with the callback parameters. */ + if (stream != &scr_serialization_stream) { + scr_test_failed("File write error: %s", "stream is invalid"); + return; + } else if (!stream->is_open) { + scr_test_failed("File write error: %s", "stream is not open"); + return; + } else if (!stream->is_writable) { + scr_test_failed("File write error: %s", "stream is not open for write"); + return; + } + + /* Reallocate, then add this block of data to the buffer. */ + stream->data = (sc_byte *)sx_realloc(stream->data, stream->length + length); + memcpy(stream->data + stream->length, buffer, length); + stream->length += length; } void -file_close_file_callback (void *opaque) -{ - sx_scr_stream_t *const stream = (sx_scr_stream_t *)opaque; - assert (opaque); - - /* Detect any problems with the callback parameters. */ - if (stream != &scr_serialization_stream) - { - scr_test_failed ("File close error: %s", "stream is invalid"); - return; - } - else if (!stream->is_open) - { - scr_test_failed ("File close error: %s", "stream is not open"); - return; - } - - /* - * If closing after a read, free allocations, and return the stream to - * its empty state; if after write, leave the data for the later read. - */ - if (!stream->is_writable) - { - sx_free (stream->data); - stream->data = NULL; - stream->length = 0; - } - stream->is_writable = FALSE; - stream->is_open = FALSE; +file_close_file_callback(void *opaque) { + sx_scr_stream_t *const stream = (sx_scr_stream_t *)opaque; + assert(opaque); + + /* Detect any problems with the callback parameters. */ + if (stream != &scr_serialization_stream) { + scr_test_failed("File close error: %s", "stream is invalid"); + return; + } else if (!stream->is_open) { + scr_test_failed("File close error: %s", "stream is not open"); + return; + } + + /* + * If closing after a read, free allocations, and return the stream to + * its empty state; if after write, leave the data for the later read. + */ + if (!stream->is_writable) { + sx_free(stream->data); + stream->data = NULL; + stream->length = 0; + } + stream->is_writable = FALSE; + stream->is_open = FALSE; } @@ -186,15 +163,14 @@ file_close_file_callback (void *opaque) * Free any pending allocations and clean up on completion of a script. */ void -file_cleanup (void) -{ - sx_scr_stream_t *const stream = &scr_serialization_stream; - - sx_free (stream->data); - stream->data = NULL; - stream->length = 0; - stream->is_writable = FALSE; - stream->is_open = FALSE; +file_cleanup(void) { + sx_scr_stream_t *const stream = &scr_serialization_stream; + + sx_free(stream->data); + stream->data = NULL; + stream->length = 0; + stream->is_writable = FALSE; + stream->is_open = FALSE; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sxglob.cpp b/engines/glk/adrift/sxglob.cpp index 3a4a0c6cc4..c6133aa458 100644 --- a/engines/glk/adrift/sxglob.cpp +++ b/engines/glk/adrift/sxglob.cpp @@ -67,170 +67,157 @@ namespace Adrift { * above for notes on where these functions came from originally. */ static int -glob_inrange_unsigned (const unsigned char **const pattern, - unsigned char ch) -{ - const unsigned char *const pattern_ = *pattern; - int in_range = FALSE; - unsigned int l = 256, r = 0, index_; - - /* Skip the leading '[' on entry to a range check. */ - index_ = 1; - - /* Special-case a range that has ']' as its first character. */ - if (pattern_[index_] == ']') - { - r = pattern_[index_++]; - if (ch == r) - in_range = TRUE; - } - - /* - * Check at the loop top, rather than the bottom, to avoid problems with - * invalid or uncompleted ranges. - */ - while (pattern_[index_] && pattern_[index_] != ']') - { - r = pattern_[index_++]; - if (r == '-') - { - /* Special-case a range that has '-' as its last character. */ - if (pattern_[index_] == ']' || !pattern_[index_]) - { - if (ch == r) - in_range = TRUE; - break; - } - - /* Break the loop on unterminated range ending with '-'. */ - if (!pattern_[index_]) - break; - - r = pattern_[index_++]; - if (l <= ch && ch <= r) - in_range = TRUE; - } - else - { - l = r; - if (ch == r) - in_range = TRUE; - } - } - - /* Update pattern with characters consumed, return result. */ - *pattern += index_; - return in_range; +glob_inrange_unsigned(const unsigned char **const pattern, + unsigned char ch) { + const unsigned char *const pattern_ = *pattern; + int in_range = FALSE; + unsigned int l = 256, r = 0, index_; + + /* Skip the leading '[' on entry to a range check. */ + index_ = 1; + + /* Special-case a range that has ']' as its first character. */ + if (pattern_[index_] == ']') { + r = pattern_[index_++]; + if (ch == r) + in_range = TRUE; + } + + /* + * Check at the loop top, rather than the bottom, to avoid problems with + * invalid or uncompleted ranges. + */ + while (pattern_[index_] && pattern_[index_] != ']') { + r = pattern_[index_++]; + if (r == '-') { + /* Special-case a range that has '-' as its last character. */ + if (pattern_[index_] == ']' || !pattern_[index_]) { + if (ch == r) + in_range = TRUE; + break; + } + + /* Break the loop on unterminated range ending with '-'. */ + if (!pattern_[index_]) + break; + + r = pattern_[index_++]; + if (l <= ch && ch <= r) + in_range = TRUE; + } else { + l = r; + if (ch == r) + in_range = TRUE; + } + } + + /* Update pattern with characters consumed, return result. */ + *pattern += index_; + return in_range; } static int -glob_match_unsigned (const unsigned char *pattern, - const unsigned char *string) -{ - int is_match = FALSE; - - if (!*string) - { - if (*pattern == '*') - is_match = glob_match_unsigned (pattern + 1, string); - else - is_match = !*pattern; - } - else - { - switch (*pattern) - { - case '\0': - is_match = !*string; - break; - case '*': - if (glob_match_unsigned (pattern + 1, string)) - is_match = TRUE; - else - is_match = glob_match_unsigned (pattern, string + 1); - break; - case '?': - is_match = glob_match_unsigned (pattern + 1, string + 1); - break; - case '[': - /* - * After a range check, we need to see if we hit the end of the - * pattern before recursively matching pattern + 1. - */ - is_match = glob_inrange_unsigned (&pattern, *string) - && (!*pattern - || glob_match_unsigned (pattern + 1, string + 1)); - break; - default: - is_match = *pattern == *string - && glob_match_unsigned (pattern + 1, string + 1); - break; - } - } - - return is_match; +glob_match_unsigned(const unsigned char *pattern, + const unsigned char *string) { + int is_match = FALSE; + + if (!*string) { + if (*pattern == '*') + is_match = glob_match_unsigned(pattern + 1, string); + else + is_match = !*pattern; + } else { + switch (*pattern) { + case '\0': + is_match = !*string; + break; + case '*': + if (glob_match_unsigned(pattern + 1, string)) + is_match = TRUE; + else + is_match = glob_match_unsigned(pattern, string + 1); + break; + case '?': + is_match = glob_match_unsigned(pattern + 1, string + 1); + break; + case '[': + /* + * After a range check, we need to see if we hit the end of the + * pattern before recursively matching pattern + 1. + */ + is_match = glob_inrange_unsigned(&pattern, *string) + && (!*pattern + || glob_match_unsigned(pattern + 1, string + 1)); + break; + default: + is_match = *pattern == *string + && glob_match_unsigned(pattern + 1, string + 1); + break; + } + } + + return is_match; } /* Structures and data for the self test function. */ -typedef struct -{ - const sc_char *const pattern; - const sc_char *const string; +typedef struct { + const sc_char *const pattern; + const sc_char *const string; } sx_test_data_t; static const sx_test_data_t SHOULD_MATCH[] = { - {"a", "a"}, {"abc", "abc"}, {"", ""}, - {"*", ""}, {"*", "abc"}, {"*", "cba"}, - {"*c", "c"}, {"*c", "abc"}, {"*c", "cbac"}, - {"a*", "a"}, {"a*", "abc"}, {"a*", "abca"}, - {"a*c", "ac"}, {"a*c", "abc"}, {"a*c", "abcbcbc"}, - {"a**c", "ac"}, {"a**c", "abc"}, {"a**c", "abcbcbc"}, - {"*b*", "b"}, {"*b*", "abc"}, {"*b*", "ab"}, {"*b*", "bc"}, - {"?", "a"}, {"?", "z"}, {"?", "?"}, {"[?]", "?"}, - {"a?", "aa"}, {"a?", "az"}, {"a?", "a?"}, - {"?c", "ac"}, {"?c", "zc"}, {"?c", "?c"}, - {"[abz]", "a"}, {"[abz]", "b"}, {"[abz]", "z"}, - {"[a-c]", "a"}, {"[a-c]", "b"}, {"[a-c]", "c"}, - {"[ac]b[ac]", "abc"}, {"[ac]b[ac]", "cba"}, - - {"[]]", "]"}, {"[]a-c]", "a"}, {"[]a-c]", "b"}, {"[]a-c]", "c"}, - {"[?]", "?" }, {"[-]", "-"}, {"[z-]", "z"}, {"[z-]", "-"}, - {"[][-]", "]"}, {"[][-]", "["}, {"[][-]", "-"}, - {"[a-c-]", "a"}, {"[a-c-]", "b"}, {"[a-c-]", "c"}, {"[a-c-]", "-"}, - - {"*[a-z]*abc?xyz", "aabcQxyz"}, {"*[a-z]*abc?xyz", "aabcQxyz"}, - {"*[a-z]*abc?xyz", "aabcQxyz"}, {"*[a-z]*abc?xyz", "aabcQxyz"}, - - {"???]", "abc]"}, {"[z-a]", "z"}, - {"[a-z", "a"}, {"[a-", "a"}, {"[a", "a"}, {"[[", "["}, - {NULL, NULL} + {"a", "a"}, {"abc", "abc"}, {"", ""}, + {"*", ""}, {"*", "abc"}, {"*", "cba"}, + {"*c", "c"}, {"*c", "abc"}, {"*c", "cbac"}, + {"a*", "a"}, {"a*", "abc"}, {"a*", "abca"}, + {"a*c", "ac"}, {"a*c", "abc"}, {"a*c", "abcbcbc"}, + {"a**c", "ac"}, {"a**c", "abc"}, {"a**c", "abcbcbc"}, + {"*b*", "b"}, {"*b*", "abc"}, {"*b*", "ab"}, {"*b*", "bc"}, + {"?", "a"}, {"?", "z"}, {"?", "?"}, {"[?]", "?"}, + {"a?", "aa"}, {"a?", "az"}, {"a?", "a?"}, + {"?c", "ac"}, {"?c", "zc"}, {"?c", "?c"}, + {"[abz]", "a"}, {"[abz]", "b"}, {"[abz]", "z"}, + {"[a-c]", "a"}, {"[a-c]", "b"}, {"[a-c]", "c"}, + {"[ac]b[ac]", "abc"}, {"[ac]b[ac]", "cba"}, + + {"[]]", "]"}, {"[]a-c]", "a"}, {"[]a-c]", "b"}, {"[]a-c]", "c"}, + {"[?]", "?" }, {"[-]", "-"}, {"[z-]", "z"}, {"[z-]", "-"}, + {"[][-]", "]"}, {"[][-]", "["}, {"[][-]", "-"}, + {"[a-c-]", "a"}, {"[a-c-]", "b"}, {"[a-c-]", "c"}, {"[a-c-]", "-"}, + + {"*[a-z]*abc?xyz", "aabcQxyz"}, {"*[a-z]*abc?xyz", "aabcQxyz"}, + {"*[a-z]*abc?xyz", "aabcQxyz"}, {"*[a-z]*abc?xyz", "aabcQxyz"}, + + {"???]", "abc]"}, {"[z-a]", "z"}, + {"[a-z", "a"}, {"[a-", "a"}, {"[a", "a"}, {"[[", "["}, + {NULL, NULL} }; static const sx_test_data_t SHOULD_NOT_MATCH[] = { - {"a", "b"}, {"abc", "abd"}, {"a", ""}, {"", "a"}, - {"*c", "a"}, {"*c", "ab"}, {"*c", "abca"}, - {"a*", "c"}, {"a*", "cba"}, {"a*", "cbac"}, - {"a*c", "ca"}, {"a*c", "cba"}, {"a*c", "cbababa"}, - {"a**c", "ca"}, {"a**c", "cba"}, {"a**c", "cbababa"}, - {"*b*", ""}, {"*b*", "z"}, {"*b*", "ac"}, {"*b*", "azc"}, - {"?", ""}, {"?", "ab"}, {"?", "abc"}, {"[?]", "a"}, - {"a?", "ca"}, {"a?", "cz"}, {"a?", "??"}, - {"?c", "ab"}, {"?c", "zb"}, {"?c", "??"}, - {"[bcy]", "a"}, {"[bcy]", "d"}, {"[bcy]", "z"}, - {"[b-d]", "a"}, {"[b-d]", "e"}, {"[b-d]", ""}, {"[b-d]", "bc"}, - {"[ac]b[ac]", "aaa"}, {"[ac]b[ac]", "bbb"}, {"[ac]b[ac]", "ccc"}, - - {"[]]", "["}, {"[]]", "a"}, {"[]a-c]", "z"}, - {"[?]", "a" }, {"[-]", "a"}, {"[z-]", "a"}, - {"[][-]", "a"}, {"[][-]", "z"}, - {"[a-c-]", "z"}, - - {"*[a-z]*abc?xyz", "AabcQxyz"}, {"*[a-z]*abc?xyz", "AabcQxyz"}, - {"*[a-z]*abc?xyz", "AabcQxyz"}, {"*[a-z]*abc?xyz", "aabcxyz"}, - - {"[z-a]", "a"}, {"[z-a]", "b"}, {"[", "a"}, {"[[", "a"}, - {NULL, NULL} + {"a", "b"}, {"abc", "abd"}, {"a", ""}, {"", "a"}, + {"*c", "a"}, {"*c", "ab"}, {"*c", "abca"}, + {"a*", "c"}, {"a*", "cba"}, {"a*", "cbac"}, + {"a*c", "ca"}, {"a*c", "cba"}, {"a*c", "cbababa"}, + {"a**c", "ca"}, {"a**c", "cba"}, {"a**c", "cbababa"}, + {"*b*", ""}, {"*b*", "z"}, {"*b*", "ac"}, {"*b*", "azc"}, + {"?", ""}, {"?", "ab"}, {"?", "abc"}, {"[?]", "a"}, + {"a?", "ca"}, {"a?", "cz"}, {"a?", "??"}, + {"?c", "ab"}, {"?c", "zb"}, {"?c", "??"}, + {"[bcy]", "a"}, {"[bcy]", "d"}, {"[bcy]", "z"}, + {"[b-d]", "a"}, {"[b-d]", "e"}, {"[b-d]", ""}, {"[b-d]", "bc"}, + {"[ac]b[ac]", "aaa"}, {"[ac]b[ac]", "bbb"}, {"[ac]b[ac]", "ccc"}, + + {"[]]", "["}, {"[]]", "a"}, {"[]a-c]", "z"}, + {"[?]", "a" }, {"[-]", "a"}, {"[z-]", "a"}, + {"[][-]", "a"}, {"[][-]", "z"}, + {"[a-c-]", "z"}, + + {"*[a-z]*abc?xyz", "AabcQxyz"}, {"*[a-z]*abc?xyz", "AabcQxyz"}, + {"*[a-z]*abc?xyz", "AabcQxyz"}, {"*[a-z]*abc?xyz", "aabcxyz"}, + + {"[z-a]", "a"}, {"[z-a]", "b"}, {"[", "a"}, {"[[", "a"}, + {NULL, NULL} }; @@ -240,47 +227,41 @@ static const sx_test_data_t SHOULD_NOT_MATCH[] = { * Sed quis custodiet ipsos custodes? */ static void -glob_self_test (void) -{ - const sx_test_data_t *test; - sc_int errors; - - /* - * Run each test case and compare against expected result. To avoid a lot - * of ugly casting, we use the main public glob_match() function. - */ - errors = 0; - for (test = SHOULD_MATCH; test->pattern; test++) - { - if (!glob_match (test->pattern, test->string)) - { - sx_error ("glob_self_test: \"%s\", \"%s\"" - " did not match, and should have matched\n", - test->pattern, test->string); - errors++; - } - } - - for (test = SHOULD_NOT_MATCH; test->pattern; test++) - { - if (glob_match (test->pattern, test->string)) - { - sx_error ("glob_self_test: \"%s\", \"%s\"" - " matched, and should not have matched\n", - test->pattern, test->string); - errors++; - } - } - - /* - * Abort if any error. As befits our distrustful nature, we won't even - * trust that sx_fatal() calls abort() (though it should). - */ - if (errors > 0) - { - sx_fatal("glob_self_test: %ld self-test error%s found, aborting\n", - errors, (errors == 1) ? "" : "s"); - } +glob_self_test(void) { + const sx_test_data_t *test; + sc_int errors; + + /* + * Run each test case and compare against expected result. To avoid a lot + * of ugly casting, we use the main public glob_match() function. + */ + errors = 0; + for (test = SHOULD_MATCH; test->pattern; test++) { + if (!glob_match(test->pattern, test->string)) { + sx_error("glob_self_test: \"%s\", \"%s\"" + " did not match, and should have matched\n", + test->pattern, test->string); + errors++; + } + } + + for (test = SHOULD_NOT_MATCH; test->pattern; test++) { + if (glob_match(test->pattern, test->string)) { + sx_error("glob_self_test: \"%s\", \"%s\"" + " matched, and should not have matched\n", + test->pattern, test->string); + errors++; + } + } + + /* + * Abort if any error. As befits our distrustful nature, we won't even + * trust that sx_fatal() calls abort() (though it should). + */ + if (errors > 0) { + sx_fatal("glob_self_test: %ld self-test error%s found, aborting\n", + errors, (errors == 1) ? "" : "s"); + } } @@ -291,29 +272,27 @@ glob_self_test (void) * based interface. Here is where all the evil casting lives. */ sc_bool -glob_match (const sc_char *pattern, const sc_char *string) -{ - static sc_bool initialized = FALSE; - - const unsigned char *pattern_ = (const unsigned char *) pattern; - const unsigned char *string_ = (const unsigned char *) string; - sc_bool retval; - assert (pattern && string); - - /* On the first call, run a self-test to verify basic glob matching. */ - if (!initialized) - { - /* - * To avoid lots of icky casting, the self-test uses the core public - * glob_match() that we're in right here to run its tests. So set - * initialized _before_ the test, to avoid infinite recursion. - */ - initialized = TRUE; - glob_self_test (); - } - - retval = glob_match_unsigned (pattern_, string_) != 0; - return retval; +glob_match(const sc_char *pattern, const sc_char *string) { + static sc_bool initialized = FALSE; + + const unsigned char *pattern_ = (const unsigned char *) pattern; + const unsigned char *string_ = (const unsigned char *) string; + sc_bool retval; + assert(pattern && string); + + /* On the first call, run a self-test to verify basic glob matching. */ + if (!initialized) { + /* + * To avoid lots of icky casting, the self-test uses the core public + * glob_match() that we're in right here to run its tests. So set + * initialized _before_ the test, to avoid infinite recursion. + */ + initialized = TRUE; + glob_self_test(); + } + + retval = glob_match_unsigned(pattern_, string_) != 0; + return retval; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sxmain.cpp b/engines/glk/adrift/sxmain.cpp index 2644a5d53e..d01e226716 100644 --- a/engines/glk/adrift/sxmain.cpp +++ b/engines/glk/adrift/sxmain.cpp @@ -51,124 +51,113 @@ namespace Adrift { * Validate the command line, and each argument as a game to be run. * Execute scripts for each, and return with an error code if any test fails. */ -int glk_main (int argc, const char *argv[]) -{ - const sc_char *const program = argv[0]; - sc_bool is_verbose = FALSE, is_tracing = FALSE; - const sc_char *trace_flags; - sx_test_descriptor_t *tests; - sc_int count, index_, errors; - assert (argc > 0 && argv); - - /* Get options and validate the command line. */ - if (argc > 1 - && (strcmp (argv[1], "-v") == 0 || strcmp (argv[1], "-vv") == 0)) - { - is_verbose = TRUE; - is_tracing = (strcmp (argv[1], "-vv") == 0); - argc--; - argv++; - } - - if (is_verbose) - { - sx_trace ("--- %s Test Suite [Adrift %ld compatible]\n", - sc_scare_version (), sc_scare_emulation ()); - if (argc < 2) - return EXIT_SUCCESS; - } - else if (argc < 2) - { - error("Usage: %s [-v | -vv] test [test...]\n", program); - return EXIT_FAILURE; - } - - /* Ensure that the interpreter is in the Latin1 locale, and stays there. */ - if (!sc_set_locale ("Latin1")) - { - error("%s: failed to set locale\n", program); - return EXIT_FAILURE; - } - - /* - * Force test reproducibility. Because game construction may use random - * numbers, we also need to remember to reseed this before constructing - * each game, and then again before running each. - */ - sc_set_portable_random (TRUE); - - /* Set verbosity and tracing for other modules. */ - scr_set_verbose (is_verbose); - stub_debug_trace (is_tracing); - trace_flags = 0; // getenv("SC_TRACE_FLAGS"); - if (trace_flags) - sc_set_trace_flags (strtoul (trace_flags, NULL, 0)); - - /* Create an array of test descriptors large enough for all tests. */ - tests = (sx_test_descriptor_t *)sx_malloc ((argc - 1) * sizeof (*tests)); - - /* Validate each test argument by opening a game and script for it. */ - count = 0; - for (index_ = 1; index_ < argc; index_++) - { - const sc_char *name; - Common::SeekableReadStream *stream; - sx_script script; - sc_game game; - - name = argv[index_]; - - script = sx_fopen(name, "scr", "r"); - if (!script) - { - error("%s: %s.scr: %s\n", program, name, strerror (errno)); - continue; - } - - stream = sx_fopen (name, "taf", "rb"); - if (!stream) - { - error("%s: %s.taf: %s\n", program, name, strerror (errno)); - delete script; - continue; - } - - sc_reseed_random_sequence (1); - game = sc_game_from_stream(stream); - delete stream; - if (!game) - { - error("%s: %s.taf: Unable to decode Adrift game\n", program, name); - delete script; - continue; - } - - tests[count].name = name; - tests[count].script = script; - tests[count].game = game; - count++; - } - - /* Run the available tests and report results. */ - if (count > 0) - errors = test_run_game_tests (tests, count, is_verbose); - else - errors = 1; - - /* Clean up allocations and opened files. */ - for (index_ = 0; index_ < count; index_++) - { - delete tests[index_].script; - sc_free_game (tests[index_].game); - } - sx_free (tests); - - /* Report results overall. */ - warning("%s [%ld test%s, %ld error%s]\n", - errors > 0 ? "FAIL" : "PASS", - count, count == 1 ? "" : "s", errors, errors == 1 ? "" : "s"); - - return errors > 0 ? EXIT_FAILURE : EXIT_SUCCESS; +int glk_main(int argc, const char *argv[]) { + const sc_char *const program = argv[0]; + sc_bool is_verbose = FALSE, is_tracing = FALSE; + const sc_char *trace_flags; + sx_test_descriptor_t *tests; + sc_int count, index_, errors; + assert(argc > 0 && argv); + + /* Get options and validate the command line. */ + if (argc > 1 + && (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "-vv") == 0)) { + is_verbose = TRUE; + is_tracing = (strcmp(argv[1], "-vv") == 0); + argc--; + argv++; + } + + if (is_verbose) { + sx_trace("--- %s Test Suite [Adrift %ld compatible]\n", + sc_scare_version(), sc_scare_emulation()); + if (argc < 2) + return EXIT_SUCCESS; + } else if (argc < 2) { + error("Usage: %s [-v | -vv] test [test...]\n", program); + return EXIT_FAILURE; + } + + /* Ensure that the interpreter is in the Latin1 locale, and stays there. */ + if (!sc_set_locale("Latin1")) { + error("%s: failed to set locale\n", program); + return EXIT_FAILURE; + } + + /* + * Force test reproducibility. Because game construction may use random + * numbers, we also need to remember to reseed this before constructing + * each game, and then again before running each. + */ + sc_set_portable_random(TRUE); + + /* Set verbosity and tracing for other modules. */ + scr_set_verbose(is_verbose); + stub_debug_trace(is_tracing); + trace_flags = 0; // getenv("SC_TRACE_FLAGS"); + if (trace_flags) + sc_set_trace_flags(strtoul(trace_flags, NULL, 0)); + + /* Create an array of test descriptors large enough for all tests. */ + tests = (sx_test_descriptor_t *)sx_malloc((argc - 1) * sizeof(*tests)); + + /* Validate each test argument by opening a game and script for it. */ + count = 0; + for (index_ = 1; index_ < argc; index_++) { + const sc_char *name; + Common::SeekableReadStream *stream; + sx_script script; + sc_game game; + + name = argv[index_]; + + script = sx_fopen(name, "scr", "r"); + if (!script) { + error("%s: %s.scr: %s\n", program, name, strerror(errno)); + continue; + } + + stream = sx_fopen(name, "taf", "rb"); + if (!stream) { + error("%s: %s.taf: %s\n", program, name, strerror(errno)); + delete script; + continue; + } + + sc_reseed_random_sequence(1); + game = sc_game_from_stream(stream); + delete stream; + if (!game) { + error("%s: %s.taf: Unable to decode Adrift game\n", program, name); + delete script; + continue; + } + + tests[count].name = name; + tests[count].script = script; + tests[count].game = game; + count++; + } + + /* Run the available tests and report results. */ + if (count > 0) + errors = test_run_game_tests(tests, count, is_verbose); + else + errors = 1; + + /* Clean up allocations and opened files. */ + for (index_ = 0; index_ < count; index_++) { + delete tests[index_].script; + sc_free_game(tests[index_].game); + } + sx_free(tests); + + /* Report results overall. */ + warning("%s [%ld test%s, %ld error%s]\n", + errors > 0 ? "FAIL" : "PASS", + count, count == 1 ? "" : "s", errors, errors == 1 ? "" : "s"); + + return errors > 0 ? EXIT_FAILURE : EXIT_SUCCESS; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sxprotos.h b/engines/glk/adrift/sxprotos.h index 6591b5d820..57ce5f392f 100644 --- a/engines/glk/adrift/sxprotos.h +++ b/engines/glk/adrift/sxprotos.h @@ -41,11 +41,10 @@ namespace Adrift { typedef Common::SeekableReadStream *sx_script; /* Typedef representing a test descriptor. */ -typedef struct sx_test_descriptor_s -{ - const sc_char *name; - sc_game game; - sx_script script; +typedef struct sx_test_descriptor_s { + const sc_char *name; + sc_game game; + sx_script script; } sx_test_descriptor_t; /* @@ -54,58 +53,58 @@ typedef struct sx_test_descriptor_s * checks. */ #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) -extern void sx_trace (const sc_char *format, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); -extern void sx_error (const sc_char *format, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); -extern void sx_fatal (const sc_char *format, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); +extern void sx_trace(const sc_char *format, ...) +__attribute__((__format__(__printf__, 1, 2))); +extern void sx_error(const sc_char *format, ...) +__attribute__((__format__(__printf__, 1, 2))); +extern void sx_fatal(const sc_char *format, ...) +__attribute__((__format__(__printf__, 1, 2))); #else -extern void sx_trace (const sc_char *format, ...); -extern void sx_error (const sc_char *format, ...); -extern void sx_fatal (const sc_char *format, ...); +extern void sx_trace(const sc_char *format, ...); +extern void sx_error(const sc_char *format, ...); +extern void sx_fatal(const sc_char *format, ...); #endif -extern void *sx_malloc (size_t size); -extern void *sx_realloc (void *pointer, size_t size); -extern void sx_free (void *pointer); +extern void *sx_malloc(size_t size); +extern void *sx_realloc(void *pointer, size_t size); +extern void sx_free(void *pointer); extern Common::SeekableReadStream *sx_fopen(const sc_char *name, - const sc_char *extension, const sc_char *mode); -extern sc_char *sx_trim_string (sc_char *string); -extern sc_char *sx_normalize_string (sc_char *string); + const sc_char *extension, const sc_char *mode); +extern sc_char *sx_trim_string(sc_char *string); +extern sc_char *sx_normalize_string(sc_char *string); /* OS stub hooks controller functions. */ -extern void stub_attach_handlers (sc_bool (*read_line) (sc_char *, sc_int), - void (*print_string) (const sc_char *), - void *(*open_file) (sc_bool), - sc_int (*read_file) - (void*, sc_byte*, sc_int), - void (*write_file) - (void*, const sc_byte*, sc_int), - void (*close_file) (void*)); -extern void stub_detach_handlers (void); -extern void stub_debug_trace (sc_bool flag); +extern void stub_attach_handlers(sc_bool(*read_line)(sc_char *, sc_int), + void (*print_string)(const sc_char *), + void *(*open_file)(sc_bool), + sc_int(*read_file) + (void *, sc_byte *, sc_int), + void (*write_file) + (void *, const sc_byte *, sc_int), + void (*close_file)(void *)); +extern void stub_detach_handlers(void); +extern void stub_debug_trace(sc_bool flag); /* Test controller function. */ -extern sc_int test_run_game_tests (const sx_test_descriptor_t tests[], - sc_int count, sc_bool is_verbose); +extern sc_int test_run_game_tests(const sx_test_descriptor_t tests[], + sc_int count, sc_bool is_verbose); /* Globbing function. */ -extern sc_bool glob_match (const sc_char *pattern, const sc_char *string); +extern sc_bool glob_match(const sc_char *pattern, const sc_char *string); /* Script running and checking functions. */ -extern void scr_test_failed (const sc_char *format, const sc_char *string); -extern void scr_set_verbose (sc_bool flag); -extern void scr_start_script (sc_game game, Common::SeekableReadStream *script); -extern sc_int scr_finalize_script (void); +extern void scr_test_failed(const sc_char *format, const sc_char *string); +extern void scr_set_verbose(sc_bool flag); +extern void scr_start_script(sc_game game, Common::SeekableReadStream *script); +extern sc_int scr_finalize_script(void); /* Serialization helper for script running and checking. */ -extern void *file_open_file_callback (sc_bool is_save); -extern sc_int file_read_file_callback (void *opaque, - sc_byte *buffer, sc_int length); -extern void file_write_file_callback (void *opaque, - const sc_byte *buffer, sc_int length); -extern void file_close_file_callback (void *opaque); -extern void file_cleanup (void); +extern void *file_open_file_callback(sc_bool is_save); +extern sc_int file_read_file_callback(void *opaque, + sc_byte *buffer, sc_int length); +extern void file_write_file_callback(void *opaque, + const sc_byte *buffer, sc_int length); +extern void file_close_file_callback(void *opaque); +extern void file_cleanup(void); } // End of namespace Adrift } // End of namespace Glk diff --git a/engines/glk/adrift/sxscript.cpp b/engines/glk/adrift/sxscript.cpp index 41be4c2b77..33c0501a3c 100644 --- a/engines/glk/adrift/sxscript.cpp +++ b/engines/glk/adrift/sxscript.cpp @@ -76,9 +76,8 @@ static sc_char *scr_game_output = NULL; * Set error reporting for expectation errors detected in the script. */ void -scr_set_verbose (sc_bool flag) -{ - scr_is_verbose = flag; +scr_set_verbose(sc_bool flag) { + scr_is_verbose = flag; } @@ -90,31 +89,27 @@ scr_set_verbose (sc_bool flag) * is used by the serialization helper, so is not static. */ static void -scr_test_message (const sc_char *format, const sc_char *string) -{ - if (scr_is_verbose) - { - sx_trace ("--- "); - sx_trace (format, string); - sx_trace ("\n"); - } +scr_test_message(const sc_char *format, const sc_char *string) { + if (scr_is_verbose) { + sx_trace("--- "); + sx_trace(format, string); + sx_trace("\n"); + } } void -scr_test_failed (const sc_char *format, const sc_char *string) -{ - assert (format && string); - - if (scr_is_verbose) - { - if (scr_line_number > 0) - sx_trace ("--- Near line %ld: ", scr_line_number); - else - sx_trace ("--- "); - sx_trace (format, string); - sx_trace ("\n"); - } - scr_errors++; +scr_test_failed(const sc_char *format, const sc_char *string) { + assert(format && string); + + if (scr_is_verbose) { + if (scr_line_number > 0) + sx_trace("--- Near line %ld: ", scr_line_number); + else + sx_trace("--- "); + sx_trace(format, string); + sx_trace("\n"); + } + scr_errors++; } @@ -129,47 +124,41 @@ scr_test_failed (const sc_char *format, const sc_char *string) * Line classifiers, return TRUE if line has the given type. */ static sc_bool -scr_is_line_type (const sc_char *line, sc_char type) -{ - return line[0] == type; +scr_is_line_type(const sc_char *line, sc_char type) { + return line[0] == type; } static sc_bool -scr_is_line_comment_or_empty (const sc_char *line) -{ - return scr_is_line_type (line, SCRIPT_COMMENT) - || strspn (line, "\t\n\v\f\r ") == strlen (line); +scr_is_line_comment_or_empty(const sc_char *line) { + return scr_is_line_type(line, SCRIPT_COMMENT) + || strspn(line, "\t\n\v\f\r ") == strlen(line); } static sc_bool -scr_is_line_game_command (const sc_char *line) -{ - return scr_is_line_type (line, GAME_COMMAND); +scr_is_line_game_command(const sc_char *line) { + return scr_is_line_type(line, GAME_COMMAND); } static sc_bool -scr_is_line_debug_command (const sc_char *line) -{ - return scr_is_line_type (line, DEBUG_COMMAND); +scr_is_line_debug_command(const sc_char *line) { + return scr_is_line_type(line, DEBUG_COMMAND); } static sc_bool -scr_is_line_command (const sc_char *line) -{ - return scr_is_line_game_command (line) || scr_is_line_debug_command (line); +scr_is_line_command(const sc_char *line) { + return scr_is_line_game_command(line) || scr_is_line_debug_command(line); } static sc_bool -scr_is_line_empty_debug_command (const sc_char *line) -{ - return scr_is_line_type (line, DEBUG_COMMAND) && line[1] == NUL; +scr_is_line_empty_debug_command(const sc_char *line) { + return scr_is_line_type(line, DEBUG_COMMAND) && line[1] == NUL; } /* Script location, a pair holding the file location and the line number. */ struct sx_scr_location_t { - size_t position; - sc_int line_number; + size_t position; + sc_int line_number; }; typedef sx_scr_location_t *sx_scr_locationref_t; @@ -180,12 +169,12 @@ typedef sx_scr_location_t *sx_scr_locationref_t; * Save and restore the script location in the given structure. */ static void -scr_save_location (sx_script script, sx_scr_locationref_t location) { +scr_save_location(sx_script script, sx_scr_locationref_t location) { location->position = script->pos(); location->line_number = scr_line_number; } -static void scr_restore_location (sx_script script, sx_scr_locationref_t location) { +static void scr_restore_location(sx_script script, sx_scr_locationref_t location) { script->seek(location->position); scr_line_number = location->line_number; } @@ -198,28 +187,26 @@ static void scr_restore_location (sx_script script, sx_scr_locationref_t locatio * line from the script. Returns NULL if no more lines, or on file error. The * return string is allocated, and it's the caller's responsibility to free it. */ -static sc_char *scr_get_next_line (sx_script script) { - sc_char *buffer, *line = NULL; - - /* Allocate a buffer for line reads. */ - buffer = (sc_char *)sx_malloc(LINE_BUFFER_SIZE); - - /* Read until a significant line is found, or end of file or error. */ - while (adrift_fgets(buffer, LINE_BUFFER_SIZE, script)) - { - scr_line_number++; - if (!scr_is_line_comment_or_empty (buffer)) - { - line = buffer; - break; - } - } - - /* If no significant line read, free the read buffer. */ - if (!line) - sx_free (buffer); - - return line; +static sc_char *scr_get_next_line(sx_script script) { + sc_char *buffer, *line = NULL; + + /* Allocate a buffer for line reads. */ + buffer = (sc_char *)sx_malloc(LINE_BUFFER_SIZE); + + /* Read until a significant line is found, or end of file or error. */ + while (adrift_fgets(buffer, LINE_BUFFER_SIZE, script)) { + scr_line_number++; + if (!scr_is_line_comment_or_empty(buffer)) { + line = buffer; + break; + } + } + + /* If no significant line read, free the read buffer. */ + if (!line) + sx_free(buffer); + + return line; } @@ -231,23 +218,19 @@ static sc_char *scr_get_next_line (sx_script script) { * instead. */ static sc_char * -scr_concatenate (sc_char *string, const sc_char *buffer) -{ - /* If string is not null, concatenate buffer, otherwise duplicate. */ - if (string) - { - string = (sc_char *)sx_realloc(string, - strlen (string) + 1 + strlen (buffer) + 1); - strcat (string, " "); - strcat (string, buffer); - } - else - { - string = (sc_char *)sx_malloc(strlen (buffer) + 1); - strcpy (string, buffer); - } - - return string; +scr_concatenate(sc_char *string, const sc_char *buffer) { + /* If string is not null, concatenate buffer, otherwise duplicate. */ + if (string) { + string = (sc_char *)sx_realloc(string, + strlen(string) + 1 + strlen(buffer) + 1); + strcat(string, " "); + strcat(string, buffer); + } else { + string = (sc_char *)sx_malloc(strlen(buffer) + 1); + strcpy(string, buffer); + } + + return string; } @@ -261,65 +244,57 @@ scr_concatenate (sc_char *string, const sc_char *buffer) * free them. */ static sc_bool -scr_get_next_section (sx_script script, - sc_char **command, sc_char **expectation) -{ - sc_char *line, *first_line, *other_lines; - sx_scr_location_t location; - - /* Clear initial line accumulation. */ - first_line = other_lines = NULL; - - /* Read the next significant line from the script. */ - scr_save_location (script, &location); - line = scr_get_next_line (script); - while (line) - { - /* If already a first line, this is other lines or section end. */ - if (first_line) - { - /* - * If we found the start of the next section, reset the script - * location that saved on the line read, and we're done. - */ - if (scr_is_line_command (line)) - { - scr_restore_location (script, &location); - sx_free (line); - break; - } - else - other_lines = scr_concatenate (other_lines, line); - } - else - first_line = scr_concatenate (first_line, line); - - sx_free (line); - - /* Read the next significant line from the script. */ - scr_save_location (script, &location); - line = scr_get_next_line (script); - } - - /* Clean up and return nothing on file error. */ - if (script->err()) - { - scr_test_failed ("Script error: Failed reading script input file", ""); - sx_free (first_line); - sx_free (other_lines); - return FALSE; - } - - /* Return the command and the matching expectation string, if any. */ - if (first_line) - { - *command = sx_normalize_string (first_line); - *expectation = other_lines ? sx_normalize_string (other_lines) : NULL; - return TRUE; - } - - /* End of file, no command section read. */ - return FALSE; +scr_get_next_section(sx_script script, + sc_char **command, sc_char **expectation) { + sc_char *line, *first_line, *other_lines; + sx_scr_location_t location; + + /* Clear initial line accumulation. */ + first_line = other_lines = NULL; + + /* Read the next significant line from the script. */ + scr_save_location(script, &location); + line = scr_get_next_line(script); + while (line) { + /* If already a first line, this is other lines or section end. */ + if (first_line) { + /* + * If we found the start of the next section, reset the script + * location that saved on the line read, and we're done. + */ + if (scr_is_line_command(line)) { + scr_restore_location(script, &location); + sx_free(line); + break; + } else + other_lines = scr_concatenate(other_lines, line); + } else + first_line = scr_concatenate(first_line, line); + + sx_free(line); + + /* Read the next significant line from the script. */ + scr_save_location(script, &location); + line = scr_get_next_line(script); + } + + /* Clean up and return nothing on file error. */ + if (script->err()) { + scr_test_failed("Script error: Failed reading script input file", ""); + sx_free(first_line); + sx_free(other_lines); + return FALSE; + } + + /* Return the command and the matching expectation string, if any. */ + if (first_line) { + *command = sx_normalize_string(first_line); + *expectation = other_lines ? sx_normalize_string(other_lines) : NULL; + return TRUE; + } + + /* End of file, no command section read. */ + return FALSE; } @@ -334,48 +309,41 @@ scr_get_next_section (sx_script script, * input. */ static void -scr_expect (sc_char *expectation) -{ - /* - * Save the expectation, and set up collection of game output if needed. - * And if not needed, ensure expectation and game output are cleared. - */ - if (expectation) - { - scr_expectation = (sc_char *)sx_malloc(strlen (expectation) + 1); - strcpy (scr_expectation, expectation); - scr_game_output = (sc_char *)sx_malloc (1); - strcpy (scr_game_output, ""); - } - else - { - sx_free(scr_expectation); - scr_expectation = NULL; - sx_free(scr_game_output); - scr_game_output = NULL; - } +scr_expect(sc_char *expectation) { + /* + * Save the expectation, and set up collection of game output if needed. + * And if not needed, ensure expectation and game output are cleared. + */ + if (expectation) { + scr_expectation = (sc_char *)sx_malloc(strlen(expectation) + 1); + strcpy(scr_expectation, expectation); + scr_game_output = (sc_char *)sx_malloc(1); + strcpy(scr_game_output, ""); + } else { + sx_free(scr_expectation); + scr_expectation = NULL; + sx_free(scr_game_output); + scr_game_output = NULL; + } } static void -scr_verify_expectation (void) -{ - /* Compare expected with actual, and handle any error detected. */ - if (scr_expectation && scr_game_output) - { - scr_game_output = sx_normalize_string (scr_game_output); - if (!glob_match (scr_expectation, scr_game_output)) - { - scr_test_failed ("Expectation error:", ""); - scr_test_message (" Expected: \"%s\"", scr_expectation); - scr_test_message (" Received: \"%s\"", scr_game_output); - } - } - - /* Dispose of the expectation and accumulated game output. */ - sx_free (scr_expectation); - scr_expectation = NULL; - sx_free (scr_game_output); - scr_game_output = NULL; +scr_verify_expectation(void) { + /* Compare expected with actual, and handle any error detected. */ + if (scr_expectation && scr_game_output) { + scr_game_output = sx_normalize_string(scr_game_output); + if (!glob_match(scr_expectation, scr_game_output)) { + scr_test_failed("Expectation error:", ""); + scr_test_message(" Expected: \"%s\"", scr_expectation); + scr_test_message(" Received: \"%s\"", scr_game_output); + } + } + + /* Dispose of the expectation and accumulated game output. */ + sx_free(scr_expectation); + scr_expectation = NULL; + sx_free(scr_game_output); + scr_game_output = NULL; } @@ -390,28 +358,26 @@ scr_verify_expectation (void) * to turn it off when it's no longer needed. */ static void -scr_execute_debugger_command (const sc_char *command, sc_char *expectation) -{ - sc_bool status; - - /* Set up the expectation. */ - scr_expect (expectation); - - /* - * Execute the command via the debugger interface. The "+1" on command - * skips the leading '~' read in from the game script. - */ - sc_set_game_debugger_enabled (scr_game, TRUE); - status = sc_run_game_debugger_command (scr_game, command + 1); - - if (!status) - { - scr_test_failed ("Script error:" - " Debug command \"%s\" is not valid", command); - } - - /* Check expectations immediately. */ - scr_verify_expectation (); +scr_execute_debugger_command(const sc_char *command, sc_char *expectation) { + sc_bool status; + + /* Set up the expectation. */ + scr_expect(expectation); + + /* + * Execute the command via the debugger interface. The "+1" on command + * skips the leading '~' read in from the game script. + */ + sc_set_game_debugger_enabled(scr_game, TRUE); + status = sc_run_game_debugger_command(scr_game, command + 1); + + if (!status) { + scr_test_failed("Script error:" + " Debug command \"%s\" is not valid", command); + } + + /* Check expectations immediately. */ + scr_verify_expectation(); } @@ -425,65 +391,60 @@ scr_execute_debugger_command (const sc_char *command, sc_char *expectation) * to the game. */ static sc_bool -scr_read_line_callback (sc_char *buffer, sc_int length) -{ - sc_char *command, *expectation; - assert (buffer && length > 0); - - /* Check pending expectation, and clear settings for the next line. */ - scr_verify_expectation (); - - /* Get the next line-expectation pair from the script stream. */ - if (scr_get_next_section (scr_script, &command, &expectation)) - { - if (scr_is_line_debug_command (command)) - { - /* The debugger persists where debug commands are adjacent. */ - scr_execute_debugger_command (command, expectation); - sx_free (command); - sx_free (expectation); - - /* - * Returning FALSE here causes the game to re-prompt. We could - * loop (or tail recurse) ourselves, but returning is simpler. - */ - return FALSE; - } - else - sc_set_game_debugger_enabled (scr_game, FALSE); - - if (scr_is_line_game_command (command)) - { - /* Set up the expectation. */ - scr_expect (expectation); - - /* Copy out the line to the return buffer, and free the line. */ - strncpy (buffer, command + 1, length); - buffer[length - 1] = NUL; - sx_free (command); - sx_free (expectation); - return TRUE; - } - - /* Neither a '~' nor a '>' command. */ - scr_test_failed ("Script error:" - " Command \"%s\" is not valid, ignored", command); - sx_free (command); - sx_free (expectation); - return FALSE; - } - - /* Ensure the game debugger is off after this section. */ - sc_set_game_debugger_enabled (scr_game, FALSE); - - /* - * We reached the end of the script without finding a "quit" command. - * Supply one here, then. In the unlikely even that this does not quit - * the game, we'll iterate on this. - */ - assert (length > 4); - strcpy (buffer, "quit"); - return TRUE; +scr_read_line_callback(sc_char *buffer, sc_int length) { + sc_char *command, *expectation; + assert(buffer && length > 0); + + /* Check pending expectation, and clear settings for the next line. */ + scr_verify_expectation(); + + /* Get the next line-expectation pair from the script stream. */ + if (scr_get_next_section(scr_script, &command, &expectation)) { + if (scr_is_line_debug_command(command)) { + /* The debugger persists where debug commands are adjacent. */ + scr_execute_debugger_command(command, expectation); + sx_free(command); + sx_free(expectation); + + /* + * Returning FALSE here causes the game to re-prompt. We could + * loop (or tail recurse) ourselves, but returning is simpler. + */ + return FALSE; + } else + sc_set_game_debugger_enabled(scr_game, FALSE); + + if (scr_is_line_game_command(command)) { + /* Set up the expectation. */ + scr_expect(expectation); + + /* Copy out the line to the return buffer, and free the line. */ + strncpy(buffer, command + 1, length); + buffer[length - 1] = NUL; + sx_free(command); + sx_free(expectation); + return TRUE; + } + + /* Neither a '~' nor a '>' command. */ + scr_test_failed("Script error:" + " Command \"%s\" is not valid, ignored", command); + sx_free(command); + sx_free(expectation); + return FALSE; + } + + /* Ensure the game debugger is off after this section. */ + sc_set_game_debugger_enabled(scr_game, FALSE); + + /* + * We reached the end of the script without finding a "quit" command. + * Supply one here, then. In the unlikely even that this does not quit + * the game, we'll iterate on this. + */ + assert(length > 4); + strcpy(buffer, "quit"); + return TRUE; } @@ -495,17 +456,15 @@ scr_read_line_callback (sc_char *buffer, sc_int length) * the current game output will be NULL, and we can simply save the effort. */ static void -scr_print_string_callback (const sc_char *string) -{ - assert (string); - - if (scr_game_output) - { - scr_game_output = (sc_char *)sx_realloc (scr_game_output, - strlen (scr_game_output) - + strlen (string) + 1); - strcat (scr_game_output, string); - } +scr_print_string_callback(const sc_char *string) { + assert(string); + + if (scr_game_output) { + scr_game_output = (sc_char *)sx_realloc(scr_game_output, + strlen(scr_game_output) + + strlen(string) + 1); + strcat(scr_game_output, string); + } } @@ -518,68 +477,60 @@ scr_print_string_callback (const sc_char *string) * and match against the expectations on next request or on finalization. */ void -scr_start_script (sc_game game, sx_script script) -{ - sc_char *command, *expectation; - sx_scr_location_t location; - assert (game && script); - - /* Save the game and stream, and clear the line number and errors count. */ - assert (!scr_game && !scr_script); - scr_game = game; - scr_script = script; - scr_line_number = 0; - scr_errors = 0; - - /* Set up our callback functions to catch game i/o. */ - stub_attach_handlers (scr_read_line_callback, scr_print_string_callback, - file_open_file_callback, file_read_file_callback, - file_write_file_callback, file_close_file_callback); - - /* - * Handle any initial debugging commands, terminating on either a non- - * debugging one or an expectation for the game intro. - */ - scr_script->seek(0); - scr_save_location (scr_script, &location); - while (scr_get_next_section (scr_script, &command, &expectation)) - { - if (scr_is_line_debug_command (command)) - { - if (scr_is_line_empty_debug_command (command)) - { - /* It's an intro expectation - set and break loop. */ - scr_expect (expectation); - sx_free (command); - sx_free (expectation); - break; - } - else - { - /* It's a full debug command - execute it as one. */ - scr_execute_debugger_command (command, expectation); - sx_free (command); - sx_free (expectation); - } - } - else - { - /* - * It's an ordinary section - rewind so that it's the first one - * handled in the callback, and break loop. - */ - scr_restore_location (scr_script, &location); - sx_free (command); - sx_free (expectation); - break; - } - - /* Note script position before reading the next section. */ - scr_save_location (scr_script, &location); - } - - /* Ensure the game debugger is off after this section. */ - sc_set_game_debugger_enabled (scr_game, FALSE); +scr_start_script(sc_game game, sx_script script) { + sc_char *command, *expectation; + sx_scr_location_t location; + assert(game && script); + + /* Save the game and stream, and clear the line number and errors count. */ + assert(!scr_game && !scr_script); + scr_game = game; + scr_script = script; + scr_line_number = 0; + scr_errors = 0; + + /* Set up our callback functions to catch game i/o. */ + stub_attach_handlers(scr_read_line_callback, scr_print_string_callback, + file_open_file_callback, file_read_file_callback, + file_write_file_callback, file_close_file_callback); + + /* + * Handle any initial debugging commands, terminating on either a non- + * debugging one or an expectation for the game intro. + */ + scr_script->seek(0); + scr_save_location(scr_script, &location); + while (scr_get_next_section(scr_script, &command, &expectation)) { + if (scr_is_line_debug_command(command)) { + if (scr_is_line_empty_debug_command(command)) { + /* It's an intro expectation - set and break loop. */ + scr_expect(expectation); + sx_free(command); + sx_free(expectation); + break; + } else { + /* It's a full debug command - execute it as one. */ + scr_execute_debugger_command(command, expectation); + sx_free(command); + sx_free(expectation); + } + } else { + /* + * It's an ordinary section - rewind so that it's the first one + * handled in the callback, and break loop. + */ + scr_restore_location(scr_script, &location); + sx_free(command); + sx_free(expectation); + break; + } + + /* Note script position before reading the next section. */ + scr_save_location(scr_script, &location); + } + + /* Ensure the game debugger is off after this section. */ + sc_set_game_debugger_enabled(scr_game, FALSE); } @@ -591,51 +542,46 @@ scr_start_script (sc_game game, sx_script script) * count of errors detected during the script. */ sc_int -scr_finalize_script (void) -{ - sc_char *command, *expectation; - sc_int errors; - - /* Check pending expectation, and clear settings. */ - scr_verify_expectation (); - - /* Drain the remainder of the script, ignoring non-debugging commands. */ - while (scr_get_next_section (scr_script, &command, &expectation)) - { - if (scr_is_line_debug_command (command)) - { - scr_execute_debugger_command (command, expectation); - sx_free (command); - sx_free (expectation); - } - else - { - /* Complain about script entries ignored because the game ended. */ - scr_test_failed ("Script error:" - " Game completed, command \"%s\" ignored", command); - sx_free (command); - sx_free (expectation); - } - } - - /* Ensure the game debugger is off after this section. */ - sc_set_game_debugger_enabled (scr_game, FALSE); - - /* - * Remove our callback functions from the stubs, and "close" any retained - * stream data from game save/load tests. - */ - stub_detach_handlers (); - file_cleanup (); - - /* Clear local records of game stream, line number, and errors count. */ - errors = scr_errors; - scr_game = NULL; - scr_script = NULL; - scr_line_number = 0; - scr_errors = 0; - - return errors; +scr_finalize_script(void) { + sc_char *command, *expectation; + sc_int errors; + + /* Check pending expectation, and clear settings. */ + scr_verify_expectation(); + + /* Drain the remainder of the script, ignoring non-debugging commands. */ + while (scr_get_next_section(scr_script, &command, &expectation)) { + if (scr_is_line_debug_command(command)) { + scr_execute_debugger_command(command, expectation); + sx_free(command); + sx_free(expectation); + } else { + /* Complain about script entries ignored because the game ended. */ + scr_test_failed("Script error:" + " Game completed, command \"%s\" ignored", command); + sx_free(command); + sx_free(expectation); + } + } + + /* Ensure the game debugger is off after this section. */ + sc_set_game_debugger_enabled(scr_game, FALSE); + + /* + * Remove our callback functions from the stubs, and "close" any retained + * stream data from game save/load tests. + */ + stub_detach_handlers(); + file_cleanup(); + + /* Clear local records of game stream, line number, and errors count. */ + errors = scr_errors; + scr_game = NULL; + scr_script = NULL; + scr_line_number = 0; + scr_errors = 0; + + return errors; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sxstubs.cpp b/engines/glk/adrift/sxstubs.cpp index d55b4037a9..32d1fddd4e 100644 --- a/engines/glk/adrift/sxstubs.cpp +++ b/engines/glk/adrift/sxstubs.cpp @@ -41,12 +41,12 @@ static sc_bool stub_trace = FALSE; * Input/output handler functions. If assigned, calls to os_* functions are * routed here to allow the script runner to catch interpeter i/o. */ -static sc_bool (*stub_read_line) (sc_char*, sc_int) = NULL; -static void (*stub_print_string) (const sc_char*) = NULL; -static void *(*stub_open_file) (sc_bool) = NULL; -static sc_int (*stub_read_file) (void*, sc_byte*, sc_int) = NULL; -static void (*stub_write_file) (void*, const sc_byte*, sc_int) = NULL; -static void (*stub_close_file) (void*) = NULL; +static sc_bool(*stub_read_line)(sc_char *, sc_int) = NULL; +static void (*stub_print_string)(const sc_char *) = NULL; +static void *(*stub_open_file)(sc_bool) = NULL; +static sc_int(*stub_read_file)(void *, sc_byte *, sc_int) = NULL; +static void (*stub_write_file)(void *, const sc_byte *, sc_int) = NULL; +static void (*stub_close_file)(void *) = NULL; /* Flags for whether to report tags and resources via stub_print_string(). */ static sc_int stub_show_resources = 0; @@ -60,36 +60,34 @@ static sc_int stub_show_tags = 0; * Attach input/output handler functions, and reset to NULLs. */ void -stub_attach_handlers (sc_bool (*read_line) (sc_char*, sc_int), - void (*print_string) (const sc_char*), - void *(*open_file) (sc_bool), - sc_int (*read_file) (void*, sc_byte*, sc_int), - void (*write_file) (void*, const sc_byte*, sc_int), - void (*close_file) (void*)) -{ - stub_read_line = read_line; - stub_print_string = print_string; - stub_open_file = open_file; - stub_read_file = read_file; - stub_write_file = write_file; - stub_close_file = close_file; - - stub_show_resources = 0; - stub_show_tags = 0; +stub_attach_handlers(sc_bool(*read_line)(sc_char *, sc_int), + void (*print_string)(const sc_char *), + void *(*open_file)(sc_bool), + sc_int(*read_file)(void *, sc_byte *, sc_int), + void (*write_file)(void *, const sc_byte *, sc_int), + void (*close_file)(void *)) { + stub_read_line = read_line; + stub_print_string = print_string; + stub_open_file = open_file; + stub_read_file = read_file; + stub_write_file = write_file; + stub_close_file = close_file; + + stub_show_resources = 0; + stub_show_tags = 0; } void -stub_detach_handlers (void) -{ - stub_read_line = NULL; - stub_print_string = NULL; - stub_open_file = NULL; - stub_read_file = NULL; - stub_write_file = NULL; - stub_close_file = NULL; - - stub_show_resources = 0; - stub_show_tags = 0; +stub_detach_handlers(void) { + stub_read_line = NULL; + stub_print_string = NULL; + stub_open_file = NULL; + stub_read_file = NULL; + stub_write_file = NULL; + stub_close_file = NULL; + + stub_show_resources = 0; + stub_show_tags = 0; } @@ -102,35 +100,29 @@ stub_detach_handlers (void) * Returns TRUE if the tag trapped was one of our testing ones. */ static void -stub_adjust_test_control (sc_int *control, sc_bool is_begin) -{ - *control += is_begin ? 1 : (*control > 0 ? -1 : 0); +stub_adjust_test_control(sc_int *control, sc_bool is_begin) { + *control += is_begin ? 1 : (*control > 0 ? -1 : 0); } static sc_bool -stub_catch_test_control (sc_int tag, const sc_char *argument) -{ - if (tag == SC_TAG_UNKNOWN && argument) - { - sc_bool is_begin; - const sc_char *name; - - is_begin = !(argument[0] == '/'); - name = is_begin ? argument : argument + 1; - - if (sc_strcasecmp (name, "sxshowresources") == 0) - { - stub_adjust_test_control (&stub_show_resources, is_begin); - return TRUE; - } - else if (sc_strcasecmp (name, "sxshowtags") == 0) - { - stub_adjust_test_control (&stub_show_tags, is_begin); - return TRUE; - } - } - - return FALSE; +stub_catch_test_control(sc_int tag, const sc_char *argument) { + if (tag == SC_TAG_UNKNOWN && argument) { + sc_bool is_begin; + const sc_char *name; + + is_begin = !(argument[0] == '/'); + name = is_begin ? argument : argument + 1; + + if (sc_strcasecmp(name, "sxshowresources") == 0) { + stub_adjust_test_control(&stub_show_resources, is_begin); + return TRUE; + } else if (sc_strcasecmp(name, "sxshowtags") == 0) { + stub_adjust_test_control(&stub_show_tags, is_begin); + return TRUE; + } + } + + return FALSE; } @@ -141,9 +133,8 @@ stub_catch_test_control (sc_int tag, const sc_char *argument) * safety. Most libc's handle this themselves, but it's not defined by ANSI. */ static const sc_char * -stub_notnull (const sc_char *string) -{ - return string ? string : "(nil)"; +stub_notnull(const sc_char *string) { + return string ? string : "(nil)"; } @@ -153,245 +144,219 @@ stub_notnull (const sc_char *string) * Stub functions called by the interpreter core. */ void -os_print_tag (sc_int tag, const sc_char *argument) -{ - if (stub_trace) - sx_trace ("os_print_tag (%ld, \"%s\")\n", tag, stub_notnull (argument)); - - if (!stub_catch_test_control (tag, argument)) - { - if (stub_print_string) - { - if (stub_show_tags > 0) { - stub_print_string ("<>"); - } - else if (tag == SC_TAG_WAITKEY || tag == SC_TAG_CLS) - stub_print_string (" "); - } - } +os_print_tag(sc_int tag, const sc_char *argument) { + if (stub_trace) + sx_trace("os_print_tag (%ld, \"%s\")\n", tag, stub_notnull(argument)); + + if (!stub_catch_test_control(tag, argument)) { + if (stub_print_string) { + if (stub_show_tags > 0) { + stub_print_string("<>"); + } else if (tag == SC_TAG_WAITKEY || tag == SC_TAG_CLS) + stub_print_string(" "); + } + } } void -os_print_string (const sc_char *string) -{ - if (stub_trace) - sx_trace ("os_print_string (\"%s\")\n", stub_notnull (string)); +os_print_string(const sc_char *string) { + if (stub_trace) + sx_trace("os_print_string (\"%s\")\n", stub_notnull(string)); - if (stub_print_string) - stub_print_string (string); + if (stub_print_string) + stub_print_string(string); } void -os_print_string_debug (const sc_char *string) -{ - if (stub_trace) - sx_trace ("os_print_string_debug (\"%s\")\n", stub_notnull (string)); +os_print_string_debug(const sc_char *string) { + if (stub_trace) + sx_trace("os_print_string_debug (\"%s\")\n", stub_notnull(string)); - if (stub_print_string) - stub_print_string (string); + if (stub_print_string) + stub_print_string(string); } void -os_play_sound (const sc_char *filepath, - sc_int offset, sc_int length, sc_bool is_looping) -{ - if (stub_trace) - sx_trace ("os_play_sound (\"%s\", %ld, %ld, %s)\n", - stub_notnull (filepath), offset, length, - is_looping ? "true" : "false"); - - if (stub_print_string && stub_show_resources > 0) - { - sc_char buffer[32]; - - stub_print_string ("<>"); - } +os_play_sound(const sc_char *filepath, + sc_int offset, sc_int length, sc_bool is_looping) { + if (stub_trace) + sx_trace("os_play_sound (\"%s\", %ld, %ld, %s)\n", + stub_notnull(filepath), offset, length, + is_looping ? "true" : "false"); + + if (stub_print_string && stub_show_resources > 0) { + sc_char buffer[32]; + + stub_print_string("<>"); + } } void -os_stop_sound (void) -{ - if (stub_trace) - sx_trace ("os_stop_sound ()\n"); +os_stop_sound(void) { + if (stub_trace) + sx_trace("os_stop_sound ()\n"); - if (stub_print_string && stub_show_resources > 0) - stub_print_string ("<>"); + if (stub_print_string && stub_show_resources > 0) + stub_print_string("<>"); } void -os_show_graphic (const sc_char *filepath, sc_int offset, sc_int length) -{ - if (stub_trace) - sx_trace ("os_show_graphic (\"%s\", %ld, %ld)\n", - stub_notnull (filepath), offset, length); - - if (stub_print_string && stub_show_resources > 0) - { - sc_char buffer[32]; - - stub_print_string ("<>"); - } +os_show_graphic(const sc_char *filepath, sc_int offset, sc_int length) { + if (stub_trace) + sx_trace("os_show_graphic (\"%s\", %ld, %ld)\n", + stub_notnull(filepath), offset, length); + + if (stub_print_string && stub_show_resources > 0) { + sc_char buffer[32]; + + stub_print_string("<>"); + } } sc_bool -os_read_line (sc_char *buffer, sc_int length) -{ - sc_bool status; - - if (stub_read_line) - status = stub_read_line (buffer, length); - else - { - assert (buffer && length > 4); - sprintf (buffer, "%s", "quit"); - status = TRUE; - } - - if (stub_trace) - { - if (status) - sx_trace ("os_read_line (\"%s\", %ld) -> true\n", - stub_notnull (buffer), length); - else - sx_trace ("os_read_line (\"...\", %ld) -> false\n", length); - } - return status; +os_read_line(sc_char *buffer, sc_int length) { + sc_bool status; + + if (stub_read_line) + status = stub_read_line(buffer, length); + else { + assert(buffer && length > 4); + sprintf(buffer, "%s", "quit"); + status = TRUE; + } + + if (stub_trace) { + if (status) + sx_trace("os_read_line (\"%s\", %ld) -> true\n", + stub_notnull(buffer), length); + else + sx_trace("os_read_line (\"...\", %ld) -> false\n", length); + } + return status; } sc_bool -os_read_line_debug (sc_char *buffer, sc_int length) -{ - assert (buffer && length > 8); - sprintf (buffer, "%s", "continue"); - - if (stub_trace) - sx_trace ("os_read_line_debug (\"%s\", %ld) -> true\n", buffer, length); - return TRUE; +os_read_line_debug(sc_char *buffer, sc_int length) { + assert(buffer && length > 8); + sprintf(buffer, "%s", "continue"); + + if (stub_trace) + sx_trace("os_read_line_debug (\"%s\", %ld) -> true\n", buffer, length); + return TRUE; } sc_bool -os_confirm (sc_int type) -{ - if (stub_trace) - sx_trace ("os_confirm (%ld) -> true\n", type); - return TRUE; +os_confirm(sc_int type) { + if (stub_trace) + sx_trace("os_confirm (%ld) -> true\n", type); + return TRUE; } void * -os_open_file (sc_bool is_save) -{ - void *opaque; - - if (stub_open_file) - opaque = stub_open_file (is_save); - else - opaque = NULL; - - if (stub_trace) - { - if (opaque) - sx_trace ("os_open_file (%s) -> %p\n", - is_save ? "true" : "false", opaque); - else - sx_trace ("os_open_file (%s) -> null\n", is_save ? "true" : "false"); - } - return opaque; +os_open_file(sc_bool is_save) { + void *opaque; + + if (stub_open_file) + opaque = stub_open_file(is_save); + else + opaque = NULL; + + if (stub_trace) { + if (opaque) + sx_trace("os_open_file (%s) -> %p\n", + is_save ? "true" : "false", opaque); + else + sx_trace("os_open_file (%s) -> null\n", is_save ? "true" : "false"); + } + return opaque; } sc_int -os_read_file (void *opaque, sc_byte *buffer, sc_int length) -{ - sc_int bytes; - - if (stub_read_file) - bytes = stub_read_file (opaque, buffer, length); - else - bytes = 0; - - if (stub_trace) - sx_trace ("os_read_file (%p, %p, %ld) -> %ld\n", - opaque, buffer, length, bytes); - return bytes; +os_read_file(void *opaque, sc_byte *buffer, sc_int length) { + sc_int bytes; + + if (stub_read_file) + bytes = stub_read_file(opaque, buffer, length); + else + bytes = 0; + + if (stub_trace) + sx_trace("os_read_file (%p, %p, %ld) -> %ld\n", + opaque, buffer, length, bytes); + return bytes; } void -os_write_file (void *opaque, const sc_byte *buffer, sc_int length) -{ - if (stub_write_file) - stub_write_file (opaque, buffer, length); +os_write_file(void *opaque, const sc_byte *buffer, sc_int length) { + if (stub_write_file) + stub_write_file(opaque, buffer, length); - if (stub_trace) - sx_trace ("os_write_file (%p, %p, %ld)\n", opaque, buffer, length); + if (stub_trace) + sx_trace("os_write_file (%p, %p, %ld)\n", opaque, buffer, length); } void -os_close_file (void *opaque) -{ - if (stub_close_file) - stub_close_file (opaque); +os_close_file(void *opaque) { + if (stub_close_file) + stub_close_file(opaque); - if (stub_trace) - sx_trace ("os_close_file (%p)\n", opaque); + if (stub_trace) + sx_trace("os_close_file (%p)\n", opaque); } void -os_display_hints (sc_game game) -{ - if (stub_trace) - sx_trace ("os_display_hints (%p)\n", game); - - if (stub_print_string) - { - sc_game_hint hint; - - for (hint = sc_get_first_game_hint (game); - hint; hint = sc_get_next_game_hint (game, hint)) - { - const sc_char *hint_text; - - stub_print_string (sc_get_game_hint_question (game, hint)); - stub_print_string ("\n"); - - hint_text = sc_get_game_subtle_hint (game, hint); - if (hint_text) - { - stub_print_string ("- "); - stub_print_string (hint_text); - stub_print_string ("\n"); - } - - hint_text = sc_get_game_unsubtle_hint (game, hint); - if (hint_text) - { - stub_print_string ("- "); - stub_print_string (hint_text); - stub_print_string ("\n"); - } - } - } +os_display_hints(sc_game game) { + if (stub_trace) + sx_trace("os_display_hints (%p)\n", game); + + if (stub_print_string) { + sc_game_hint hint; + + for (hint = sc_get_first_game_hint(game); + hint; hint = sc_get_next_game_hint(game, hint)) { + const sc_char *hint_text; + + stub_print_string(sc_get_game_hint_question(game, hint)); + stub_print_string("\n"); + + hint_text = sc_get_game_subtle_hint(game, hint); + if (hint_text) { + stub_print_string("- "); + stub_print_string(hint_text); + stub_print_string("\n"); + } + + hint_text = sc_get_game_unsubtle_hint(game, hint); + if (hint_text) { + stub_print_string("- "); + stub_print_string(hint_text); + stub_print_string("\n"); + } + } + } } @@ -401,9 +366,8 @@ os_display_hints (sc_game game) * Set stubs tracing on/off. */ void -stub_debug_trace (sc_bool flag) -{ - stub_trace = flag; +stub_debug_trace(sc_bool flag) { + stub_trace = flag; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sxtester.cpp b/engines/glk/adrift/sxtester.cpp index 483d8df202..f82ca275ad 100644 --- a/engines/glk/adrift/sxtester.cpp +++ b/engines/glk/adrift/sxtester.cpp @@ -33,18 +33,18 @@ namespace Adrift { * the script's monitoring. */ static sc_int test_run_game_script(sc_game game, sx_script script) { - sc_int errors; + sc_int errors; - /* Ensure completely repeatable random number sequences. */ - sc_reseed_random_sequence (1); + /* Ensure completely repeatable random number sequences. */ + sc_reseed_random_sequence(1); - /* Start interpreting the script stream. */ - scr_start_script (game, script); - sc_interpret_game (game); + /* Start interpreting the script stream. */ + scr_start_script(game, script); + sc_interpret_game(game); - /* Wrap up the script interpreter and capture error count. */ - errors = scr_finalize_script (); - return errors; + /* Wrap up the script interpreter and capture error count. */ + errors = scr_finalize_script(); + return errors; } @@ -54,47 +54,43 @@ static sc_int test_run_game_script(sc_game game, sx_script script) { * Run each test in the given descriptor array, reporting the results and * accumulating an error count overall. Return the total error count. */ -sc_int test_run_game_tests (const sx_test_descriptor_t tests[], - sc_int count, sc_bool is_verbose) { - const sx_test_descriptor_t *test; - sc_int errors; - assert(tests); +sc_int test_run_game_tests(const sx_test_descriptor_t tests[], + sc_int count, sc_bool is_verbose) { + const sx_test_descriptor_t *test; + sc_int errors; + assert(tests); - errors = 0; + errors = 0; - /* Execute each game in turn. */ - for (test = tests; test < tests + count; test++) - { - sc_int test_errors; + /* Execute each game in turn. */ + for (test = tests; test < tests + count; test++) { + sc_int test_errors; - if (is_verbose) - { - sx_trace ("--- Running Test \"%s\" [\"%s\", by %s]...\n", - test->name, - sc_get_game_name (test->game), - sc_get_game_author (test->game)); - } + if (is_verbose) { + sx_trace("--- Running Test \"%s\" [\"%s\", by %s]...\n", + test->name, + sc_get_game_name(test->game), + sc_get_game_author(test->game)); + } - test_errors = test_run_game_script (test->game, test->script); - errors += test_errors; + test_errors = test_run_game_script(test->game, test->script); + errors += test_errors; - if (is_verbose) - { - sx_trace ("--- Test \"%s\": ", test->name); - if (test_errors > 0) - sx_trace ("%s [%ld error%s]\n", - "FAIL", test_errors, test_errors == 1 ? "" : "s"); - else - sx_trace ("%s\n", "PASS"); - } - else - sx_trace ("%s", test_errors > 0 ? "F" : "."); - //fflush (stdout); - //fflush (stderr); - } - sx_trace ("%s", is_verbose ? "" : "\n"); + if (is_verbose) { + sx_trace("--- Test \"%s\": ", test->name); + if (test_errors > 0) + sx_trace("%s [%ld error%s]\n", + "FAIL", test_errors, test_errors == 1 ? "" : "s"); + else + sx_trace("%s\n", "PASS"); + } else + sx_trace("%s", test_errors > 0 ? "F" : "."); + //fflush (stdout); + //fflush (stderr); + } + sx_trace("%s", is_verbose ? "" : "\n"); - return errors; + return errors; } } // End of namespace Adrift diff --git a/engines/glk/adrift/sxutils.cpp b/engines/glk/adrift/sxutils.cpp index d52670db31..90c7385131 100644 --- a/engines/glk/adrift/sxutils.cpp +++ b/engines/glk/adrift/sxutils.cpp @@ -38,14 +38,14 @@ namespace Adrift { * that trace output is synchronized to test expectation failure messages. */ void sx_trace(const sc_char *format, ...) { - va_list ap; - assert (format); + va_list ap; + assert(format); - va_start(ap, format); - Common::String line = Common::String::vformat(format, ap); - va_end(ap); + va_start(ap, format); + Common::String line = Common::String::vformat(format, ap); + va_end(ap); - debug("%s", line.c_str()); + debug("%s", line.c_str()); } /* @@ -79,7 +79,7 @@ void sx_fatal(const sc_char *format, ...) { /* Unique non-heap address for zero size malloc() and realloc() requests. */ static void *sx_zero_allocation = &sx_zero_allocation; - + /* * sx_malloc() * sx_realloc() @@ -90,54 +90,51 @@ static void *sx_zero_allocation = &sx_zero_allocation; * defined, so we have to take special care to get predictable behavior. */ void * -sx_malloc (size_t size) -{ - void *allocated; +sx_malloc(size_t size) { + void *allocated; - if (size == 0) - return sx_zero_allocation; + if (size == 0) + return sx_zero_allocation; - allocated = malloc (size); - if (!allocated) - sx_fatal ("sx_malloc: requested %lu bytes\n", (sc_uint) size); - else if (allocated == sx_zero_allocation) - sx_fatal ("sx_malloc: zero-byte allocation address returned\n"); + allocated = malloc(size); + if (!allocated) + sx_fatal("sx_malloc: requested %lu bytes\n", (sc_uint) size); + else if (allocated == sx_zero_allocation) + sx_fatal("sx_malloc: zero-byte allocation address returned\n"); - memset (allocated, 0, size); - return allocated; + memset(allocated, 0, size); + return allocated; } void * -sx_realloc (void *pointer, size_t size) -{ - void *allocated; - - if (size == 0) - { - sx_free (pointer); - return sx_zero_allocation; - } - - if (pointer == sx_zero_allocation) - pointer = NULL; - - allocated = realloc (pointer, size); - if (!allocated) - sx_fatal ("sx_realloc: requested %lu bytes\n", (sc_uint) size); - else if (allocated == sx_zero_allocation) - sx_fatal ("sx_realloc: zero-byte allocation address returned\n"); - - if (!pointer) - memset (allocated, 0, size); - return allocated; +sx_realloc(void *pointer, size_t size) { + void *allocated; + + if (size == 0) { + sx_free(pointer); + return sx_zero_allocation; + } + + if (pointer == sx_zero_allocation) + pointer = NULL; + + allocated = realloc(pointer, size); + if (!allocated) + sx_fatal("sx_realloc: requested %lu bytes\n", (sc_uint) size); + else if (allocated == sx_zero_allocation) + sx_fatal("sx_realloc: zero-byte allocation address returned\n"); + + if (!pointer) + memset(allocated, 0, size); + return allocated; } -void sx_free (void *pointer) { - if (sx_zero_allocation != &sx_zero_allocation) - sx_fatal ("sx_free: write to zero-byte allocation address detected\n"); +void sx_free(void *pointer) { + if (sx_zero_allocation != &sx_zero_allocation) + sx_fatal("sx_free: write to zero-byte allocation address detected\n"); - if (pointer && pointer != sx_zero_allocation) - free (pointer); + if (pointer && pointer != sx_zero_allocation) + free(pointer); } @@ -148,16 +145,16 @@ void sx_free (void *pointer) { * Returns NULL if unsuccessful. */ Common::SeekableReadStream *sx_fopen(const sc_char *name, const sc_char *extension, const sc_char *mode) { - assert (name && extension && mode); + assert(name && extension && mode); - Common::String filename = Common::String::format("%s.%s", name, extension); - Common::File *f = new Common::File(); + Common::String filename = Common::String::format("%s.%s", name, extension); + Common::File *f = new Common::File(); - if (f->open(filename)) - return f; + if (f->open(filename)) + return f; - delete f; - return nullptr; + delete f; + return nullptr; } @@ -171,19 +168,17 @@ static const sc_char NUL = '\0'; * Built in replacements for locale-sensitive libc ctype.h functions. */ static sc_bool -sx_isspace (sc_char character) -{ - static const sc_char *const WHITESPACE = "\t\n\v\f\r "; +sx_isspace(sc_char character) { + static const sc_char *const WHITESPACE = "\t\n\v\f\r "; - return character != NUL && strchr (WHITESPACE, character) != NULL; + return character != NUL && strchr(WHITESPACE, character) != NULL; } static sc_bool -sx_isprint (sc_char character) -{ - static const sc_int MIN_PRINTABLE = ' ', MAX_PRINTABLE = '~'; +sx_isprint(sc_char character) { + static const sc_int MIN_PRINTABLE = ' ', MAX_PRINTABLE = '~'; - return character >= MIN_PRINTABLE && character <= MAX_PRINTABLE; + return character >= MIN_PRINTABLE && character <= MAX_PRINTABLE; } @@ -194,20 +189,19 @@ sx_isprint (sc_char character) * in place, and returns the string address for convenience. */ sc_char * -sx_trim_string (sc_char *string) -{ - sc_int index_; - assert (string); +sx_trim_string(sc_char *string) { + sc_int index_; + assert(string); - for (index_ = strlen (string) - 1; - index_ >= 0 && sx_isspace (string[index_]); index_--) - string[index_] = NUL; + for (index_ = strlen(string) - 1; + index_ >= 0 && sx_isspace(string[index_]); index_--) + string[index_] = NUL; - for (index_ = 0; sx_isspace (string[index_]);) - index_++; - memmove (string, string + index_, strlen (string) - index_ + 1); + for (index_ = 0; sx_isspace(string[index_]);) + index_++; + memmove(string, string + index_, strlen(string) - index_ + 1); - return string; + return string; } @@ -219,30 +213,26 @@ sx_trim_string (sc_char *string) * place, and returns the string address for convenience. */ sc_char * -sx_normalize_string (sc_char *string) -{ - sc_int index_; - assert (string); - - string = sx_trim_string (string); - - for (index_ = 0; string[index_] != NUL; index_++) - { - if (sx_isspace (string[index_])) - { - sc_int cursor; - - string[index_] = ' '; - for (cursor = index_ + 1; sx_isspace (string[cursor]);) - cursor++; - memmove (string + index_ + 1, - string + cursor, strlen (string + cursor) + 1); - } - else if (!sx_isprint (string[index_])) - string[index_] = '?'; - } - - return string; +sx_normalize_string(sc_char *string) { + sc_int index_; + assert(string); + + string = sx_trim_string(string); + + for (index_ = 0; string[index_] != NUL; index_++) { + if (sx_isspace(string[index_])) { + sc_int cursor; + + string[index_] = ' '; + for (cursor = index_ + 1; sx_isspace(string[cursor]);) + cursor++; + memmove(string + index_ + 1, + string + cursor, strlen(string + cursor) + 1); + } else if (!sx_isprint(string[index_])) + string[index_] = '?'; + } + + return string; } char *adrift_fgets(char *buf, int max, Common::SeekableReadStream *s) { -- cgit v1.2.3