Paweł Kołodziejski 2a7d22702c initialize palette buffers (compiler warning)
svn-id: r38351
2009-02-16 07:17:36 +00:00

749 lines
21 KiB
C++

/***************************************************************************
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 retrieve 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) {
// This bit sets the foreground and background colors in VGA SCI games
gfx_color_t fgcolor;
gfx_color_t bgcolor;
memset(&fgcolor, 0, sizeof(gfx_color_t));
memset(&bgcolor, 0, sizeof(gfx_color_t));
#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 classId) {
int offset;
if (!res || classId >= res->size >> 2)
return -1;
offset = 2 + (classId << 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 */
for (i = 1; i < s->file_handles_nr; i++)
if (s->file_handles[i])
fclose(s->file_handles[i]);
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__XX
# 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);
}
sfx_exit(&s->sound);
/* Reinit because some other code depends on having a valid state */
game_init_sound(s, SFX_STATE_FLAG_NOSOUND);
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__XX
#warning "Free parser segment here"
#endif
if (send_calls_allocated) {
sci_free(send_calls);
send_calls_allocated = 0;
}
#ifdef __GNUC__XX
#warning "Free scripts here"
#endif
menubar_free(s->menubar);
_free_graphics_input(s);
sci_free(s->game_name);
return 0;
}