home *** CD-ROM | disk | FTP | other *** search
- /*
- * fastmem.c
- *
- * Memory related functions (fast version without virtual memory)
- *
- */
-
- #ifndef _WIN32_WCE
- #include <stdio.h>
- #else
- #include "FrotzCEIO.h"
- #endif
-
- #include <string.h>
-
- #ifndef _WIN32_WCE
- #include "frotz.h"
- #else
- #include "Frotz\Frotz.h"
- #endif
-
- #ifdef __MSDOS__
-
- #include <alloc.h>
-
- #define malloc(size) farmalloc (size)
- #define realloc(size,p) farrealloc (size,p)
- #define free(size) farfree (size)
- #define memcpy(d,s,n) _fmemcpy (d,s,n)
-
- #else
-
- #ifdef _WIN32_WCE
-
- #include <windows.h>
-
- #define malloc( size ) LocalAlloc( LPTR, (UINT) size )
- #define realloc( size, p ) LocalReAlloc( (HLOCAL) p, (UINT) size, 0 )
- #define free( p ) LocalFree( (HLOCAL) p )
-
- #ifndef SEEK_SET
- #define SEEK_SET 0
- #define SEEK_CUR 1
- #define SEEK_END 2
- #endif
-
- #define far
-
- #endif
-
- #endif
-
- extern void (*op0_opcodes[]) (void);
- extern void (*op1_opcodes[]) (void);
- extern void (*op2_opcodes[]) (void);
- extern void (*var_opcodes[]) (void);
-
- char save_name[MAX_FILE_NAME + 1] = DEFAULT_SAVE_NAME;
- char auxilary_name[MAX_FILE_NAME + 1] = DEFAULT_AUXILARY_NAME;
-
- zbyte far *zmp = NULL;
- zbyte far *pcp = NULL;
-
- FILE *story_fp = NULL;
-
- zbyte far *undo[MAX_UNDO_SLOTS];
-
- int undo_slots = 0;
- int undo_count = 0;
- int undo_valid = 0;
-
- /*
- * restart_header
- *
- * Set all header fields which hold information about the interpreter.
- *
- */
-
- void restart_header (void)
- {
- zword screen_x_size;
- zword screen_y_size;
- zbyte font_x_size;
- zbyte font_y_size;
-
- int i;
-
- SET_BYTE (H_CONFIG, h_config)
- SET_WORD (H_FLAGS, h_flags)
-
- if (h_version >= V4) {
- SET_BYTE (H_INTERPRETER_NUMBER, h_interpreter_number)
- SET_BYTE (H_INTERPRETER_VERSION, h_interpreter_version)
- SET_BYTE (H_SCREEN_ROWS, h_screen_rows)
- SET_BYTE (H_SCREEN_COLS, h_screen_cols)
- }
-
- /* It's less trouble to use font size 1x1 for V5 games, especially
- because of a bug in the unreleased German version of "Zork 1" */
-
- if (h_version != V6) {
- screen_x_size = ZWORD (h_screen_cols);
- screen_y_size = ZWORD (h_screen_rows);
- font_x_size = 1;
- font_y_size = 1;
- } else {
- screen_x_size = h_screen_width;
- screen_y_size = h_screen_height;
- font_x_size = h_font_width;
- font_y_size = h_font_height;
- }
-
- if (h_version >= V5) {
- SET_WORD (H_SCREEN_WIDTH, screen_x_size)
- SET_WORD (H_SCREEN_HEIGHT, screen_y_size)
- SET_BYTE (H_FONT_HEIGHT, font_y_size)
- SET_BYTE (H_FONT_WIDTH, font_x_size)
- SET_BYTE (H_DEFAULT_BACKGROUND, h_default_background)
- SET_BYTE (H_DEFAULT_FOREGROUND, h_default_foreground)
- }
-
- if (h_version == V6)
- for (i = 0; i < 8; i++)
- storeb (ZWORD (H_USER_NAME + i), h_user_name[i]);
-
- SET_BYTE (H_STANDARD_HIGH, h_standard_high)
- SET_BYTE (H_STANDARD_LOW, h_standard_low)
-
- }/* restart_header */
-
- /*
- * init_memory
- *
- * Allocate memory and load the story file.
- *
- */
-
- void init_memory (void)
- {
- long size;
- zword addr;
- unsigned n;
- int i, j;
-
- #ifndef AMIGA
-
- /* Amiga interface has its own game detection routines */
-
- static struct {
- zword release;
- zbyte serial[6];
- int id;
- } records[] = {
- { 21, "871214", SHERLOCK },
- { 26, "880127", SHERLOCK },
- { 47, "870915", BEYOND_ZORK },
- { 49, "870917", BEYOND_ZORK },
- { 51, "870923", BEYOND_ZORK },
- { 57, "871221", BEYOND_ZORK }
- };
-
- #endif
-
- /* Open story file */
-
- if ((story_fp = fopen (story_name, "rb")) == NULL)
- os_fatal ("Cannot open story file");
-
- /* Allocate memory for story header */
-
- if ((zmp = (zbyte far *) malloc (64)) == NULL)
- os_fatal ("Out of memory");
-
- /* Load header into memory */
-
- if (fread (zmp, 1, 64, story_fp) != 64)
- os_fatal ("Story file read error");
-
- /* Copy header fields to global variables */
-
- LOW_BYTE (H_VERSION, h_version)
-
- if (h_version < V1 || h_version > V8)
- os_fatal ("Unknown Z-code version");
-
- LOW_BYTE (H_CONFIG, h_config)
-
- if (h_version == V3 && (h_config & CONFIG_BYTE_SWAPPED))
- os_fatal ("Byte swapped story file");
-
- LOW_WORD (H_RELEASE, h_release)
- LOW_WORD (H_RESIDENT_SIZE, h_resident_size)
- LOW_WORD (H_START_PC, h_start_pc)
- LOW_WORD (H_DICTIONARY, h_dictionary)
- LOW_WORD (H_OBJECTS, h_objects)
- LOW_WORD (H_GLOBALS, h_globals)
- LOW_WORD (H_DYNAMIC_SIZE, h_dynamic_size)
- LOW_WORD (H_FLAGS, h_flags)
-
- for (i = 0, addr = H_SERIAL; i < 6; i++, addr++)
- LOW_BYTE (addr, h_serial[i])
-
- #ifndef AMIGA
-
- /* Auto-detect buggy story files that need special fixes */
-
- for (i = 0; i < 6; i++) {
-
- if (h_release == records[i].release) {
-
- for (j = 0; j < 6; j++)
- if (h_serial[j] != records[i].serial[j])
- goto no_match;
-
- story_id = records[i].id;
-
- }
-
- }
-
- no_match:
-
- #endif
-
- LOW_WORD (H_ABBREVIATIONS, h_abbreviations)
- LOW_WORD (H_FILE_SIZE, h_file_size)
-
- /* Calculate story file size in bytes */
-
- if (h_file_size) {
-
- story_size = (long) 2 * h_file_size;
-
- if (h_version >= V4)
- story_size *= 2;
- if (h_version >= V6)
- story_size *= 2;
-
- } else { /* some old games lack the file size entry */
-
- fseek (story_fp, 0, SEEK_END);
- story_size = ftell (story_fp);
- fseek (story_fp, 64, SEEK_SET);
-
- }
-
- LOW_WORD (H_CHECKSUM, h_checksum)
- LOW_WORD (H_ALPHABET, h_alphabet)
- LOW_WORD (H_FUNCTIONS_OFFSET, h_functions_offset)
- LOW_WORD (H_STRINGS_OFFSET, h_strings_offset)
- LOW_WORD (H_TERMINATING_KEYS, h_terminating_keys)
- LOW_WORD (H_MOUSE_TABLE, h_mouse_table)
-
- /* Adjust opcode tables for pre-V5 games */
-
- if (h_version <= V4)
- {
- op0_opcodes[0x09] = z_pop;
- op1_opcodes[0x0f] = z_not;
- }
- else
- {
- op0_opcodes[0x09] = z_catch;
- op1_opcodes[0x0f] = z_call_n;
- }
- /* Allocate memory for story data */
-
- free( zmp );
- zmp = NULL;
-
- if ((zmp = (zbyte far *) malloc ( story_size)) == NULL)
- os_fatal ("Out of memory");
-
- fseek( story_fp, 0, SEEK_SET );
-
- if (fread (zmp, 1, 64, story_fp) != 64)
- os_fatal ("Story file read error");
-
- /* Load story file in chunks of 32KB */
-
- n = 0x8000;
-
- for (size = 64; size < story_size; size += n) {
-
- if (story_size - size < 0x8000)
- n = (unsigned) (story_size - size);
-
- SET_PC (size)
-
- if (fread (pcp, 1, n, story_fp) != n)
- os_fatal ("Story file read error");
-
- }
-
- }/* init_memory */
-
- /*
- * init_undo
- *
- * Allocate memory for multiple undo. It is important not to occupy
- * all the memory available, since the IO interface may need memory
- * during the game, e.g. for loading sounds or pictures.
- *
- */
-
- void init_undo (void)
- {
- void far *reserved;
-
- undo_slots = 0;
- undo_count = 0;
- undo_valid = 0;
-
- if (reserve_mem)
- if ((reserved = malloc (reserve_mem)) == NULL)
- return;
-
- while (undo_slots < MAX_UNDO_SLOTS) {
-
- void far *mem = malloc ((long) sizeof (stack) + h_dynamic_size);
-
- if (mem == NULL)
- break;
-
- undo[undo_slots++] = mem;
-
- }
-
- if (reserve_mem)
- free (reserved);
-
- }/* init_undo */
-
- /*
- * reset_memory
- *
- * Close the story file and deallocate memory.
- *
- */
-
- void reset_memory (void)
- {
- int nSlot;
-
- fclose (story_fp);
-
- for (nSlot = 0; nSlot < MAX_UNDO_SLOTS; nSlot++)
- free (undo[nSlot]);
-
- undo_slots = 0;
- undo_count = 0;
- undo_valid = 0;
-
- free (zmp);
-
- }/* reset_memory */
-
- /*
- * storeb
- *
- * Write a byte value to the dynamic Z-machine memory.
- *
- */
-
- void storeb (zword addr, zbyte value)
- {
-
- if (addr >= h_dynamic_size)
- runtime_error ("Store out of dynamic memory");
-
- if (addr == H_FLAGS + 1) { /* flags register is modified */
-
- h_flags &= ~(SCRIPTING_FLAG | FIXED_FONT_FLAG);
- h_flags |= value & (SCRIPTING_FLAG | FIXED_FONT_FLAG);
-
- if (value & SCRIPTING_FLAG) {
- if (!ostream_script)
- script_open ();
- } else {
- if (ostream_script)
- script_close ();
- }
-
- refresh_text_style ();
-
- }
-
- SET_BYTE (addr, value)
-
- }/* storeb */
-
- /*
- * storew
- *
- * Write a word value to the dynamic Z-machine memory.
- *
- */
-
- void storew (zword addr, zword value)
- {
-
- storeb (ZWORD (addr + 0), (zbyte) hi (value));
- storeb (ZWORD (addr + 1), (zbyte) lo (value));
-
- }/* storew */
-
- /*
- * z_restart, re-load dynamic area, clear the stack and set the PC.
- *
- * no zargs used
- *
- */
-
- void z_restart (void)
- {
- static first_restart = 1;
-
- restart_screen ();
-
- seed_random (0);
-
- if (!first_restart) {
-
- fseek (story_fp, 0, SEEK_SET);
-
- if (fread (zmp, 1, h_dynamic_size, story_fp) != h_dynamic_size)
- os_fatal ("Story file read error");
-
- } else first_restart = 0;
-
- restart_header ();
-
- sp = fp = stack + STACK_SIZE;
-
- if (h_version != V6) {
-
- long pc = (long) h_start_pc;
- SET_PC (pc)
-
- } else call (h_start_pc, 0, NULL, 0);
-
- }/* z_restart */
-
- /*
- * get_default_name
- *
- * Read a default file name from the memory of the Z-machine and
- * copy it to a string.
- *
- */
-
- static void get_default_name (char *default_name, zword addr)
- {
-
- if (addr) {
-
- zbyte len;
- int i;
-
- LOW_BYTE (addr, len)
- addr++;
-
- for (i = 0; i < len; i++) {
-
- zbyte c;
-
- LOW_BYTE (addr, c)
- addr++;
-
- default_name[i] = c;
-
- }
-
- default_name[i] = 0;
-
- if (strchr (default_name, '.') == NULL)
- strcpy (default_name + i, ".AUX");
-
- } else strcpy (default_name, auxilary_name);
-
- }/* get_default_name */
-
- /*
- * z_restore, restore [a part of] a Z-machine state from disk
- *
- * zargs[0] = address of area to restore (optional)
- * zargs[1] = number of bytes to restore
- * zargs[2] = address of suggested file name
- *
- */
-
- void z_restore (void)
- {
- char new_name[MAX_FILE_NAME + 1];
- char default_name[MAX_FILE_NAME + 1];
- FILE *gfp;
-
- int success = 0;
-
- if (zargc != 0) {
-
- /* Get the file name */
-
- get_default_name (default_name, ZWORD ((zargc >= 3) ? zargs[2] : 0));
-
- if (os_read_file_name (new_name, default_name, FILE_LOAD_AUX) == 0)
- goto finished;
-
- strcpy (auxilary_name, default_name);
-
- /* Open auxilary file */
-
- if ((gfp = fopen (new_name, "rb")) == NULL)
- goto finished;
-
- /* Load auxilary file */
-
- success = fread (zmp + zargs[1], 1, zargs[2], gfp);
-
- /* Close auxilary file */
-
- fclose (gfp);
-
- } else {
-
- long pc;
- zword release;
- zword addr;
- int i;
-
- /* Get the file name */
-
- if (os_read_file_name (new_name, save_name, FILE_RESTORE) == 0)
- goto finished;
-
- strcpy (save_name, new_name);
-
- /* Open game file */
-
- if ((gfp = fopen (new_name, "rb")) == NULL)
- goto finished;
-
- /* Load game file */
-
- release = (unsigned) fgetc (gfp) << 8;
- release |= fgetc (gfp);
-
- (void) fgetc (gfp);
- (void) fgetc (gfp);
-
- /* Check the release number */
-
- if (release == h_release) {
-
- pc = (long) fgetc (gfp) << 16;
- pc |= (unsigned) fgetc (gfp) << 8;
- pc |= fgetc (gfp);
-
- SET_PC (pc)
-
- sp = stack + (fgetc (gfp) << 8);
- sp += fgetc (gfp);
- fp = stack + (fgetc (gfp) << 8);
- fp += fgetc (gfp);
-
- for (i = (int) (sp - stack); i < STACK_SIZE; i++) {
- stack[i] = (unsigned) fgetc (gfp) << 8;
- stack[i] |= fgetc (gfp);
- }
-
- fseek (story_fp, 0, SEEK_SET);
-
- for (addr = 0; addr < h_dynamic_size; addr++) {
- int skip = fgetc (gfp);
- for (i = 0; i < skip; i++)
- zmp[addr++] = ZBYTE (fgetc (story_fp));
- zmp[addr] = ZBYTE (fgetc (gfp));
- (void) fgetc (story_fp);
- }
-
- /* Check for errors */
-
- if (ferror (gfp) || ferror (story_fp))
- os_fatal ("Error reading save file");
-
- /* Reset upper window (V3 only) */
-
- if (h_version == V3)
- split_window (0);
-
- /* Initialise story header */
-
- restart_header ();
-
- /* Success */
-
- success = 2;
-
- } else print_string ("Invalid save file\n");
-
- /* Close game file */
-
- fclose (gfp);
-
- }
-
- finished:
-
- if (h_version <= V3)
- branch (success);
- else
- store (ZWORD (success));
-
- }/* z_restore */
-
- /*
- * restore_undo
- *
- * This function does the dirty work for z_restore_undo.
- *
- */
-
- int restore_undo (void)
- {
-
- if (undo_slots == 0) /* undo feature unavailable */
-
- return -1;
-
- else if (undo_valid == 0) /* no saved game state */
-
- return 0;
-
- else { /* undo possible */
-
- long pc;
-
- if (undo_count == 0)
- undo_count = undo_slots;
-
- memcpy (stack, undo[undo_count - 1], sizeof (stack));
- memcpy (zmp, undo[undo_count - 1] + sizeof (stack), h_dynamic_size);
-
- pc = ((long) stack[0] << 16) | stack[1];
- sp = stack + stack[2];
- fp = stack + stack[3];
-
- SET_PC (pc)
-
- restart_header ();
-
- undo_count--;
- undo_valid--;
-
- return 2;
-
- }
-
- }/* restore_undo */
-
- /*
- * z_restore_undo, restore a Z-machine state from memory.
- *
- * no zargs used
- *
- */
-
- void z_restore_undo (void)
- {
-
- store (ZWORD (restore_undo ()));
-
- }/* restore_undo */
-
- /*
- * z_save, save [a part of] the Z-machine state to disk.
- *
- * zargs[0] = address of memory area to save (optional)
- * zargs[1] = number of bytes to save
- * zargs[2] = address of suggested file name
- *
- */
-
- void z_save (void)
- {
- char new_name[MAX_FILE_NAME + 1];
- char default_name[MAX_FILE_NAME + 1];
- FILE *gfp;
-
- int success = 0;
-
- if (zargc != 0) {
-
- /* Get the file name */
-
- get_default_name (default_name, ZWORD ((zargc >= 3) ? zargs[2] : 0));
-
- if (os_read_file_name (new_name, default_name, FILE_SAVE_AUX) == 0)
- goto finished;
-
- strcpy (auxilary_name, default_name);
-
- /* Open auxilary file */
-
- if ((gfp = fopen (new_name, "wb")) == NULL)
- goto finished;
-
- /* Write auxilary file */
-
- success = fwrite (zmp + zargs[0], zargs[1], 1, gfp);
-
- /* Close auxilary file */
-
- fclose (gfp);
-
- } else {
-
- long pc;
- zword addr;
- int nsp, nfp;
- int skip;
- int i;
-
- /* Get the file name */
-
- if (os_read_file_name (new_name, save_name, FILE_SAVE) == 0)
- goto finished;
-
- strcpy (save_name, new_name);
-
- /* Open game file */
-
- if ((gfp = fopen (new_name, "wb")) == NULL)
- goto finished;
-
- /* Write game file */
-
- fputc ((int) hi (h_release), gfp);
- fputc ((int) lo (h_release), gfp);
- fputc ((int) hi (h_checksum), gfp);
- fputc ((int) lo (h_checksum), gfp);
-
- GET_PC (pc)
-
- fputc ((int) (pc >> 16) & 0xff, gfp);
- fputc ((int) (pc >> 8) & 0xff, gfp);
- fputc ((int) (pc) & 0xff, gfp);
-
- nsp = (int) (sp - stack);
- nfp = (int) (fp - stack);
-
- fputc ((int) hi (nsp), gfp);
- fputc ((int) lo (nsp), gfp);
- fputc ((int) hi (nfp), gfp);
- fputc ((int) lo (nfp), gfp);
-
- for (i = nsp; i < STACK_SIZE; i++) {
- fputc ((int) hi (stack[i]), gfp);
- fputc ((int) lo (stack[i]), gfp);
- }
-
- fseek (story_fp, 0, SEEK_SET);
-
- for (addr = 0, skip = 0; addr < h_dynamic_size; addr++)
- if (zmp[addr] != fgetc (story_fp) || skip == 255 || addr + 1 == h_dynamic_size) {
- fputc (skip, gfp);
- fputc (zmp[addr], gfp);
- skip = 0;
- } else skip++;
-
- /* Close game file and check for errors */
-
- if (fclose (gfp) == EOF || ferror (story_fp)) {
- print_string ("Error writing save file\n");
- goto finished;
- }
-
- /* Success */
-
- success = 1;
-
- }
-
- finished:
-
- if (h_version <= V3)
- branch (success);
- else
- store (ZWORD (success));
-
- }/* z_save */
-
- /*
- * save_undo
- *
- * This function does the dirty work for z_save_undo.
- *
- */
-
- int save_undo (void)
- {
- long pc;
-
- if (undo_slots == 0) /* undo feature unavailable */
-
- return -1;
-
- else { /* save undo possible */
-
- if (undo_count == undo_slots)
- undo_count = 0;
-
- GET_PC (pc)
-
- stack[0] = ZWORD (pc >> 16);
- stack[1] = ZWORD (pc & 0xffff);
- stack[2] = ZWORD (sp - stack);
- stack[3] = ZWORD (fp - stack);
-
- memcpy (undo[undo_count], stack, sizeof (stack));
- memcpy (undo[undo_count] + sizeof (stack), zmp, h_dynamic_size);
-
- if (++undo_count == undo_slots)
- undo_count = 0;
- if (++undo_valid > undo_slots)
- undo_valid = undo_slots;
-
- return 1;
-
- }
-
- }/* save_undo */
-
- /*
- * z_save_undo, save the current Z-machine state for a future undo.
- *
- * no zargs used
- *
- */
-
- void z_save_undo (void)
- {
-
- store (ZWORD (save_undo ()));
-
- }/* z_save_undo */
-
- /*
- * z_verify, verify the story file integrity.
- *
- * no zargs used
- *
- */
-
- void z_verify (void)
- {
- zword checksum = 0;
- long i;
-
- /* Sum all bytes in story file except header bytes */
-
- fseek (story_fp, 64, SEEK_SET);
-
- for (i = 64; i < story_size; i++)
- checksum += fgetc (story_fp);
-
- /* Branch if the checksums are equal */
-
- branch (checksum == h_checksum);
-
- }/* z_verify */
-