aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/game.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/game.cpp')
-rw-r--r--engines/sci/engine/game.cpp773
1 files changed, 773 insertions, 0 deletions
diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp
new file mode 100644
index 0000000000..63d3fb9e94
--- /dev/null
+++ b/engines/sci/engine/game.cpp
@@ -0,0 +1,773 @@
+/***************************************************************************
+ game.c Copyright (C) 1999 Christoph Reichenbach
+
+
+ This program may be modified and copied freely according to the terms of
+ the GNU general public license (GPL), as long as the above copyright
+ notice and the licensing information contained herein are preserved.
+
+ Please refer to www.gnu.org for licensing details.
+
+ This work is provided AS IS, without warranty of any kind, expressed or
+ implied, including but not limited to the warranties of merchantibility,
+ noninfringement, and fitness for a specific purpose. The author will not
+ be held liable for any damage caused by this work or derivatives of it.
+
+ By using this source code, you agree to the licensing terms as stated
+ above.
+
+
+ Please contact the maintainer for bug reports or inquiries.
+
+ Current Maintainer:
+
+ Christoph Reichenbach (CJR) [jameson@linuxgames.com]
+
+***************************************************************************/
+
+#include "sci/include/sciresource.h"
+#include "sci/include/engine.h"
+#include "sci/include/versions.h"
+#include "sci/include/kernel.h"
+#include "sci/engine/kernel_types.h"
+
+/* Structures and data from vm.c: */
+extern calls_struct_t *send_calls;
+extern int send_calls_allocated;
+extern int bp_flag;
+
+
+
+static int
+_init_vocabulary(state_t *s) /* initialize vocabulary and related resources */
+{
+ s->parser_lastmatch_word = SAID_NO_MATCH;
+ s->parser_rules = NULL;
+
+ sciprintf("Initializing vocabulary\n");
+
+ if ((s->resmgr->sci_version < SCI_VERSION_01_VGA)&&(s->parser_words = vocab_get_words(s->resmgr, &(s->parser_words_nr)))) {
+ s->parser_suffices = vocab_get_suffices(s->resmgr, &(s->parser_suffices_nr));
+ if ((s->parser_branches = vocab_get_branches(s->resmgr, &(s->parser_branches_nr))))
+ /* Now build a GNF grammar out of this */
+ s->parser_rules = vocab_build_gnf(s->parser_branches, s->parser_branches_nr);
+
+ } else {
+ sciprintf("Assuming that this game does not use a parser.\n");
+ s->parser_rules = NULL;
+ }
+
+
+ s->opcodes = vocabulary_get_opcodes(s->resmgr);
+
+ if (!(s->selector_names = vocabulary_get_snames(s->resmgr, NULL, s->version))) {
+ sciprintf("_init_vocabulary(): Could not retreive selector names (vocab.997)!\n");
+ return 1;
+ }
+
+ for (s->selector_names_nr = 0; s->selector_names[s->selector_names_nr]; s->selector_names_nr++);
+ /* Counts the number of selector names */
+
+ script_map_selectors(s, &(s->selector_map));
+ /* Maps a few special selectors for later use */
+
+ return 0;
+}
+
+extern int _allocd_rules;
+static void
+_free_vocabulary(state_t *s)
+{
+ sciprintf("Freeing vocabulary\n");
+
+ if (s->parser_words) {
+ vocab_free_words(s->parser_words, s->parser_words_nr);
+ vocab_free_suffices(s->resmgr, s->parser_suffices, s->parser_suffices_nr);
+ vocab_free_branches(s->parser_branches);
+ vocab_free_rule_list(s->parser_rules);
+ }
+
+ vocabulary_free_snames(s->selector_names);
+ vocabulary_free_knames(s->kernel_names);
+ vocabulary_free_opcodes(s->opcodes);
+ s->opcodes = NULL;
+
+ s->selector_names = NULL;
+ s->kernel_names = NULL;
+ s->opcodes = NULL;
+}
+
+
+static int
+_init_graphics_input(state_t *s)
+{
+ s->pic_priority_table = NULL;
+ s->pics = NULL;
+ s->pics_nr = 0;
+ return 0;
+}
+
+static void
+_sci1_alloc_system_colors(state_t *s)
+{
+ gfx_color_t white;
+ gfx_color_t black;
+
+ white.visual.global_index = 255;
+ white.visual.r = white.visual.g = white.visual.b = 255;
+ white.alpha = 0;
+ white.priority = white.control = 0;
+ white.mask = GFX_MASK_VISUAL;
+ gfxop_set_system_color(s->gfx_state, &white);
+
+ black.visual.global_index = 0;
+ black.visual.r = black.visual.g = black.visual.b = 0;
+ black.alpha = 0;
+ black.priority = black.control = 0;
+ black.mask = GFX_MASK_VISUAL;
+ gfxop_set_system_color(s->gfx_state, &black);
+}
+
+int
+_reset_graphics_input(state_t *s)
+{
+ resource_t *resource;
+ int font_nr;
+ gfx_color_t transparent;
+ sciprintf("Initializing graphics\n");
+
+ if (s->resmgr->sci_version <= SCI_VERSION_01) {
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ if (gfxop_set_color(s->gfx_state, &(s->ega_colors[i]),
+ gfx_sci0_image_colors[sci0_palette][i].r,
+ gfx_sci0_image_colors[sci0_palette][i].g,
+ gfx_sci0_image_colors[sci0_palette][i].b,
+ 0, -1, -1))
+ return 1;
+ gfxop_set_system_color(s->gfx_state, &(s->ega_colors[i]));
+ }
+ } else
+ {
+ /* Check for Amiga palette file. */
+ FILE *f = sci_fopen("spal", "rb");
+ if (f) {
+ s->gfx_state->resstate->static_palette =
+ gfxr_read_pal1_amiga(&s->gfx_state->resstate->static_palette_entries, f);
+ fclose(f);
+ _sci1_alloc_system_colors(s);
+ } else {
+ resource = scir_find_resource(s->resmgr, sci_palette, 999, 1);
+ if (resource) {
+ if (s->version < SCI_VERSION(1,001,000))
+ s->gfx_state->resstate->static_palette =
+ gfxr_read_pal1(999, &s->gfx_state->resstate->static_palette_entries,
+ resource->data, resource->size);
+ else
+ s->gfx_state->resstate->static_palette =
+ gfxr_read_pal11(999, &s->gfx_state->resstate->static_palette_entries,
+ resource->data, resource->size);
+ _sci1_alloc_system_colors(s);
+ scir_unlock_resource(s->resmgr, resource, sci_palette, 999);
+ } else
+ sciprintf("Couldn't find the default palette!\n");
+ }
+ }
+ transparent.mask = 0;
+
+ gfxop_fill_box(s->gfx_state, gfx_rect(0, 0, 320, 200), s->ega_colors[0]); /* Fill screen black */
+ gfxop_update(s->gfx_state);
+
+ s->mouse_pointer_view = s->mouse_pointer_loop = s->mouse_pointer_cel = -1; /* No mouse pointer resource */
+ s->save_mouse_pointer_view = s->save_mouse_pointer_loop = s->save_mouse_pointer_cel = -1; /* No mouse pointer resource */
+ gfxop_set_pointer_position(s->gfx_state, gfx_point(160, 150));
+
+ s->mouse_pointer_view = s->mouse_pointer_loop = s->mouse_pointer_cel = -1; /* No mouse pointer resource */
+ s->save_mouse_pointer_view = s->save_mouse_pointer_loop = s->save_mouse_pointer_cel = -1; /* No mouse pointer resource */
+
+
+ s->pic_is_new = 0;
+ s->pic_visible_map = GFX_MASK_NONE; /* Other values only make sense for debugging */
+ s->dyn_views = NULL; /* no DynViews */
+ s->drop_views = NULL; /* And, consequently, no list for dropped views */
+
+ s->priority_first = 42; /* Priority zone 0 ends here */
+
+ if (s->version < SCI_VERSION_FTU_PRIORITY_14_ZONES)
+ s->priority_last = 200; else
+ s->priority_last = 190;
+
+ font_nr = -1;
+ do {
+ resource = scir_test_resource(s->resmgr, sci_font, ++font_nr);
+ } while ((!resource) && (font_nr < sci_max_resource_nr[s->resmgr->sci_version]));
+
+ if (!resource) {
+ sciprintf("No text font was found.\n");
+ return 1;
+ }
+
+ s->visual = gfxw_new_visual(s->gfx_state, font_nr);
+
+ s->wm_port = gfxw_new_port(s->visual, NULL, s->gfx_state->options->pic_port_bounds, s->ega_colors[0], transparent);
+ s->iconbar_port = gfxw_new_port(s->visual, NULL, gfx_rect(0, 0, 320, 200), s->ega_colors[0], transparent);
+ s->iconbar_port->flags |= GFXW_FLAG_NO_IMPLICIT_SWITCH;
+
+ if (s->resmgr->sci_version >= SCI_VERSION_01_VGA)
+ {
+ gfx_color_t fgcolor;
+ gfx_color_t bgcolor;
+
+#if 0
+ fgcolor.visual = s->gfx_state->resstate->static_palette[0];
+ fgcolor.mask = GFX_MASK_VISUAL;
+ bgcolor.visual = s->gfx_state->resstate->static_palette[255];
+ bgcolor.mask = GFX_MASK_VISUAL;
+#endif
+ s->titlebar_port = gfxw_new_port(s->visual, NULL, gfx_rect(0, 0, 320, 10),
+ fgcolor, bgcolor);
+ } else
+ s->titlebar_port = gfxw_new_port(s->visual, NULL, gfx_rect(0, 0, 320, 10),
+ s->ega_colors[0], s->ega_colors[15]);
+ s->titlebar_port->color.mask |= GFX_MASK_PRIORITY;
+ s->titlebar_port->color.priority = 11;
+ s->titlebar_port->bgcolor.mask |= GFX_MASK_PRIORITY;
+ s->titlebar_port->bgcolor.priority = 11;
+ s->titlebar_port->flags |= GFXW_FLAG_NO_IMPLICIT_SWITCH;
+
+ /* but this is correct */
+ s->picture_port = gfxw_new_port(s->visual, NULL, s->gfx_state->options->pic_port_bounds, s->ega_colors[0], transparent);
+
+ s->pics_drawn_nr = 0;
+
+ s->visual->add(GFXWC(s->visual), GFXW(s->wm_port));
+ s->visual->add(GFXWC(s->visual), GFXW(s->titlebar_port));
+ s->visual->add(GFXWC(s->visual), GFXW(s->picture_port));
+ s->visual->add(GFXWC(s->visual), GFXW(s->iconbar_port));
+ /* Add ports to visual */
+
+ s->port = s->picture_port; /* Currently using the picture port */
+
+#if 0
+ s->titlebar_port->bgcolor.mask |= GFX_MASK_PRIORITY;
+ s->titlebar_port->bgcolor.priority = 11; /* Standard priority for the titlebar port */
+#endif
+
+ return 0;
+}
+
+int
+game_init_graphics(state_t *s)
+{
+#ifndef WITH_PIC_SCALING
+ if (s->gfx_state->options->pic0_unscaled == 0)
+ sciprintf("WARNING: Pic scaling was disabled; your version of FreeSCI has no support for scaled pic drawing built in.\n");
+
+ s->gfx_state->options->pic0_unscaled = 1;
+#endif
+ return _reset_graphics_input(s);
+}
+
+
+static void
+_free_graphics_input(state_t *s)
+{
+ sciprintf("Freeing graphics\n");
+
+ s->visual->widfree(GFXW(s->visual));
+
+ s->wm_port = s->titlebar_port = s->picture_port = NULL;
+ s->visual = NULL;
+ s->dyn_views = NULL;
+ s->port = NULL;
+
+ if (s->pics)
+ sci_free(s->pics);
+ s->pics = NULL;
+}
+
+/*------------------------------------------------------------*/
+
+int
+game_init_sound(state_t *s, int sound_flags)
+{
+ if (s->resmgr->sci_version >= SCI_VERSION_01)
+ sound_flags |= SFX_STATE_FLAG_MULTIPLAY;
+
+ s->sfx_init_flags = sound_flags;
+ sfx_init(&s->sound, s->resmgr, sound_flags);
+ return 0;
+}
+
+
+/* Maps a class ID to the script the corresponding class is contained in */
+/* Returns the script number suggested by vocab.996, or -1 if there's none */
+static int
+suggested_script(resource_t *res, unsigned int class)
+{
+ int offset;
+ if (!res || class >= res->size >> 2)
+ return -1;
+
+ offset = 2 + (class << 2);
+
+ return getInt16(res->data + offset);
+}
+
+
+int
+test_cursor_style(state_t *s)
+{
+ int resource_nr = 0;
+ int ok = 0;
+
+ do {
+ ok |= scir_test_resource(s->resmgr, sci_cursor, resource_nr++) != NULL;
+ } while (resource_nr < 1000 && !ok);
+
+ return ok;
+}
+
+int
+create_class_table_sci11(state_t *s)
+{
+ int scriptnr;
+ unsigned int seeker_offset;
+ char *seeker_ptr;
+ int classnr;
+
+ resource_t *vocab996 = scir_find_resource(s->resmgr, sci_vocab, 996, 1);
+
+ if (!vocab996)
+ s->classtable_size = 20;
+ else
+ s->classtable_size = vocab996->size >> 2;
+
+ s->classtable = (class_t*)sci_calloc(sizeof(class_t), s->classtable_size);
+
+ for (scriptnr = 0; scriptnr < 1000; scriptnr++) {
+ resource_t *heap = scir_find_resource(s->resmgr, sci_heap,
+ scriptnr, 0);
+
+ if (heap) {
+ int global_vars = getUInt16(heap->data + 2);
+
+ seeker_ptr = (char*)heap->data + 4 + global_vars*2;
+ seeker_offset = 4 + global_vars*2;
+
+ while (getUInt16((byte*)seeker_ptr) == SCRIPT_OBJECT_MAGIC_NUMBER)
+ {
+ if (getUInt16((byte*)seeker_ptr + 14) & SCRIPT_INFO_CLASS)
+ {
+ classnr = getUInt16((byte*)seeker_ptr + 10);
+ if (classnr >= s->classtable_size) {
+
+ if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) {
+ fprintf(stderr,"Invalid class number 0x%x in script.%d(0x%x), offset %04x\n",
+ classnr, scriptnr, scriptnr, seeker_offset);
+ return 1;
+ }
+
+ s->classtable = (class_t*)sci_realloc(s->classtable, sizeof(class_t) * (classnr + 1));
+ memset(&(s->classtable[s->classtable_size]), 0,
+ sizeof(class_t) * (1 + classnr - s->classtable_size)); /* Clear after resize */
+
+ s->classtable_size = classnr + 1; /* Adjust maximum number of entries */
+ }
+
+ s->classtable[classnr].reg.offset = seeker_offset;
+ s->classtable[classnr].reg.segment = 0;
+ s->classtable[classnr].script = scriptnr;
+ }
+
+ seeker_ptr += getUInt16((byte*)seeker_ptr + 2) * 2;
+ seeker_offset += getUInt16((byte*)seeker_ptr + 2) * 2;
+ }
+ }
+ }
+
+ return 0;
+}
+static int
+create_class_table_sci0(state_t *s)
+{
+ int scriptnr;
+ unsigned int seeker;
+ int classnr;
+ int magic_offset; /* For strange scripts in older SCI versions */
+
+ resource_t *vocab996 = scir_find_resource(s->resmgr, sci_vocab, 996, 1);
+
+ if (!vocab996)
+ s->classtable_size = 20;
+ else
+ s->classtable_size = vocab996->size >> 2;
+
+ s->classtable = (class_t*)sci_calloc(sizeof(class_t), s->classtable_size);
+
+ for (scriptnr = 0; scriptnr < 1000; scriptnr++) {
+ int objtype = 0;
+ resource_t *script = scir_find_resource(s->resmgr, sci_script,
+ scriptnr, 0);
+
+ if (script) {
+ if (s->version < SCI_VERSION_FTU_NEW_SCRIPT_HEADER)
+ magic_offset = seeker = 2;
+ else
+ magic_offset = seeker = 0;
+
+ do {
+
+ while (seeker < script->size) {
+ unsigned int lastseeker = seeker;
+ objtype = getInt16(script->data + seeker);
+ if (objtype == sci_obj_class || objtype == sci_obj_terminator)
+ break;
+ seeker += getInt16(script->data + seeker + 2);
+ if (seeker <= lastseeker) {
+ sciprintf("Warning: Script version is invalid.\n");
+ sci_free(s->classtable);
+ return SCI_ERROR_INVALID_SCRIPT_VERSION;
+ }
+ }
+
+ if (objtype == sci_obj_class) {
+ int sugg_script;
+
+ seeker -= SCRIPT_OBJECT_MAGIC_OFFSET; /* Adjust position; script home is base +8 bytes */
+
+ classnr = getInt16(script->data + seeker + 4 + SCRIPT_SPECIES_OFFSET);
+ if (classnr >= s->classtable_size) {
+
+ if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) {
+ fprintf(stderr,"Invalid class number 0x%x in script.%d(0x%x), offset %04x\n",
+ classnr, scriptnr, scriptnr, seeker);
+ return 1;
+ }
+
+ s->classtable = (class_t*)sci_realloc(s->classtable, sizeof(class_t) * (classnr + 1));
+ memset(&(s->classtable[s->classtable_size]), 0,
+ sizeof(class_t) * (1 + classnr - s->classtable_size)); /* Clear after resize */
+
+ s->classtable_size = classnr + 1; /* Adjust maximum number of entries */
+ }
+
+ sugg_script = suggested_script(vocab996, classnr);
+
+ /* First, test whether the script hasn't been claimed, or if it's been claimed by the wrong script */
+
+ if (sugg_script == -1 || scriptnr == sugg_script /*|| !s->classtable[classnr].reg.segment*/) {
+ /* Now set the home script of the class */
+ s->classtable[classnr].reg.offset = seeker + 4 - magic_offset;
+ s->classtable[classnr].reg.segment = 0;
+ s->classtable[classnr].script = scriptnr;
+ }
+
+ seeker += SCRIPT_OBJECT_MAGIC_OFFSET; /* Re-adjust position */
+
+ seeker += getInt16(script->data + seeker + 2); /* Move to next */
+ }
+
+ } while (objtype != sci_obj_terminator && seeker <= script->size);
+
+ }
+ }
+ scir_unlock_resource(s->resmgr, vocab996, sci_vocab, 996);
+ vocab996 = NULL;
+ return 0;
+}
+
+/* Architectural stuff: Init/Unintialize engine */
+int
+script_init_engine(state_t *s, sci_version_t version)
+{
+ int result;
+
+ s->max_version = SCI_VERSION(9,999,999); /* :-) */
+ s->min_version = 0; /* Set no real limits */
+ s->version = SCI_VERSION_DEFAULT_SCI0;
+ s->kernel_opt_flags = 0;
+
+ if (!version) {
+ s->version_lock_flag = 0;
+ } else {
+ s->version = version;
+ s->version_lock_flag = 1; /* Lock version */
+ }
+
+ script_detect_versions(s);
+
+ if (s->version >= SCI_VERSION(1,001,000))
+ result = create_class_table_sci11(s);
+ else
+ result = create_class_table_sci0(s);
+
+ sm_init(&s->seg_manager, s->version >= SCI_VERSION(1,001,000));
+ s->gc_countdown = GC_INTERVAL - 1;
+
+ if (result)
+ {
+ sciprintf("Failed to initialize class table\n");
+ return 1;
+ }
+
+ s->script_000_segment = script_get_segment(s, 0, SCRIPT_GET_LOCK);
+
+ if (s->script_000_segment <= 0) {
+ sciprintf("Failed to instantiate script.000\n");
+ return 1;
+ }
+
+ s->script_000 = &(s->seg_manager.heap[s->script_000_segment]->data.script);
+
+
+ s->sys_strings = sm_allocate_sys_strings(&s->seg_manager,
+ &s->sys_strings_segment);
+ /* Allocate static buffer for savegame and CWD directories */
+ sys_string_acquire(s->sys_strings, SYS_STRING_SAVEDIR, "savedir", MAX_SAVE_DIR_SIZE);
+
+ s->save_dir_copy = make_reg(s->sys_strings_segment, SYS_STRING_SAVEDIR);
+ s->save_dir_edit_offset = 0;
+
+ s->r_acc = s->r_prev = NULL_REG;
+ s->r_amp_rest = 0;
+
+ s->execution_stack = NULL; /* Start without any execution stack */
+ s->execution_stack_base = -1; /* No vm is running yet */
+ s->execution_stack_pos = -1; /* Start at execution stack position 0 */
+
+
+ s->kernel_names = vocabulary_get_knames(s->resmgr, &s->kernel_names_nr);
+ script_map_kernel(s);
+ /* Maps the kernel functions */
+
+ if (_init_vocabulary(s)) return 1;
+ if (s->selector_map.cantBeHere != -1)
+ version_require_later_than(s, SCI_VERSION_FTU_INVERSE_CANBEHERE);
+
+ s->restarting_flags = SCI_GAME_IS_NOT_RESTARTING;
+
+ s->bp_list = NULL; /* No breakpoints defined */
+ s->have_bp = 0;
+
+ s->file_handles_nr = 5;
+ s->file_handles = (FILE**)sci_calloc(sizeof(FILE *), s->file_handles_nr);
+ /* Allocate memory for file handles */
+
+ sci_init_dir(&(s->dirseeker));
+ s->dirseeker_outbuffer = NULL_REG;
+ /* Those two are used by FileIO for FIND_FIRST, FIND_NEXT */
+
+ if (s->version >= SCI_VERSION_FTU_LOFS_ABSOLUTE &&
+ s->version < SCI_VERSION(1,001,000))
+ sm_set_export_width(&s->seg_manager, 1);
+ else
+ sm_set_export_width(&s->seg_manager, 0);
+
+ sciprintf("Engine initialized\n");
+
+ if (_init_graphics_input(s))
+ return 1;
+
+ return 0;
+}
+
+
+void
+script_set_gamestate_save_dir(state_t *s, const char* path)
+{
+ sys_string_set(s->sys_strings, SYS_STRING_SAVEDIR, path);
+}
+
+void
+script_free_vm_memory(state_t *s)
+{
+ int i;
+
+ sciprintf("Freeing VM memory\n");
+ s->save_dir_copy_buf = NULL;
+
+ sci_free(s->classtable);
+ s->classtable = NULL;
+
+ /* Close all opened file handles */
+#ifndef _DOS
+ for (i = 1; i < s->file_handles_nr; i++)
+ if (s->file_handles[i])
+ fclose(s->file_handles[i]);
+#endif
+
+ sci_free(s->file_handles);
+ s->file_handles = NULL;
+
+ /* FIXME: file handles will NOT be closed under DOS. DJGPP generates an
+ exception fault whenever you try to close a never-opened file */
+}
+
+extern void
+free_kfunct_tables(state_t *s);
+/* From kernel.c */
+
+void
+script_free_engine(state_t *s)
+{
+ script_free_vm_memory(s);
+
+ sciprintf("Freeing state-dependant data\n");
+
+ free_kfunct_tables(s);
+
+ _free_vocabulary(s);
+
+}
+
+void
+script_free_breakpoints(state_t *s)
+{
+ breakpoint_t *bp, *bp_next;
+
+ /* Free breakpoint list */
+ bp = s->bp_list;
+ while (bp) {
+ bp_next = bp->next;
+ if (bp->type == BREAK_SELECTOR) sci_free (bp->data.name);
+ free (bp);
+ bp = bp_next;
+ }
+
+ s->bp_list = NULL;
+}
+
+/*************************************************************/
+/* Game instance stuff: Init/Unitialize state-dependant data */
+/*************************************************************/
+
+
+int
+game_init(state_t *s)
+{
+#ifdef __GNUC__
+# warning "Fixme: Use new VM instantiation code all over the place"
+#endif
+ reg_t game_obj; /* Address of the game object */
+ dstack_t *stack;
+
+ stack = sm_allocate_stack(&s->seg_manager, VM_STACK_SIZE,
+ &s->stack_segment);
+ s->stack_base = stack->entries;
+ s->stack_top = s->stack_base + VM_STACK_SIZE;
+
+ if (!script_instantiate(s, 0)) {
+ sciprintf("game_init(): Could not instantiate script 0\n");
+ return 1;
+ }
+
+ s->parser_valid = 0; /* Invalidate parser */
+ s->parser_event = NULL_REG; /* Invalidate parser event */
+
+ s->synonyms = NULL;
+ s->synonyms_nr = 0; /* No synonyms */
+
+ /* Initialize send_calls buffer */
+
+ if (!send_calls_allocated)
+ send_calls = (calls_struct_t*)sci_calloc(sizeof(calls_struct_t), send_calls_allocated = 16);
+
+ if (s->gfx_state && _reset_graphics_input(s))
+ return 1;
+
+ s->successor = NULL; /* No successor */
+ s->status_bar_text = NULL; /* Status bar is blank */
+ s->status_bar_foreground = 0;
+ s->status_bar_background = s->resmgr->sci_version >= SCI_VERSION_01_VGA ? 255 : 15;
+
+ sys_string_acquire(s->sys_strings, SYS_STRING_PARSER_BASE, "parser-base", MAX_PARSER_BASE);
+ s->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
+
+ sci_get_current_time(&(s->game_start_time)); /* Get start time */
+ memcpy(&(s->last_wait_time), &(s->game_start_time), sizeof(GTimeVal));
+ /* Use start time as last_wait_time */
+
+ s->debug_mode = 0x0; /* Disable all debugging */
+ s->onscreen_console = 0; /* No onscreen console unless explicitly requested */
+
+ srand(time(NULL)); /* Initialize random number generator */
+
+ /* script_dissect(0, s->selector_names, s->selector_names_nr); */
+ game_obj = script_lookup_export(s, 0, 0);
+ /* The first entry in the export table of script 0 points to the game object */
+
+ s->game_name = sci_strdup(obj_get_name(s, game_obj));
+
+ if (!s->game_name) {
+ sciprintf("Error: script.000, export 0 ("PREG") does not\n"
+ " yield an object with a name -> sanity check failed\n",
+ PRINT_REG(game_obj));
+ return 1;
+ }
+
+ sciprintf(" \"%s\" at "PREG"\n", s->game_name, PRINT_REG(game_obj));
+
+ if (strlen((char *) s->game_name) >= MAX_GAMEDIR_SIZE) {
+
+ s->game_name[MAX_GAMEDIR_SIZE - 1] = 0; /* Fix length with brute force */
+ sciprintf(" Designation too long; was truncated to \"%s\"\n", s->game_name);
+ }
+
+ s->game_obj = game_obj;
+
+ /* Mark parse tree as unused */
+ s->parser_nodes[0].type = PARSE_TREE_NODE_LEAF;
+ s->parser_nodes[0].content.value = 0;
+
+ s->menubar = menubar_new(); /* Create menu bar */
+
+ return 0;
+}
+
+int
+game_exit(state_t *s)
+{
+ if (s->execution_stack) {
+ sci_free(s->execution_stack);
+ }
+
+#if 0
+ sfx_exit(&s->sound);
+/* Reinit because some other code depends on having a valid state */
+ game_init_sound(s, SFX_STATE_FLAG_NOSOUND);
+#else
+#endif
+
+ sm_destroy(&s->seg_manager);
+
+ if (s->synonyms_nr) {
+ sci_free(s->synonyms);
+ s->synonyms = NULL;
+ s->synonyms_nr = 0;
+ }
+
+ sciprintf("Freeing miscellaneous data...\n");
+
+#ifdef __GNUC__
+#warning "Free parser segment here"
+#endif
+ if (send_calls_allocated) {
+ sci_free(send_calls);
+ send_calls_allocated = 0;
+ }
+
+#ifdef __GNUC__
+#warning "Free scripts here"
+#endif
+
+ menubar_free(s->menubar);
+
+ _free_graphics_input(s);
+
+ sci_free(s->game_name);
+
+ return 0;
+}
+