home *** CD-ROM | disk | FTP | other *** search
- /*
- * fastmem.c
- *
- * Memory related functions (fast version without virtual memory)
- *
- */
-
- #include "frotz.h"
- #include "S5api.h"
-
- #ifndef SEEK_SET
- #define SEEK_SET 0
- #define SEEK_CUR 1
- #define SEEK_END 2
- #endif
-
- extern void restart_screen (struct sg *g);
- extern void refresh_text_style (struct sg *g);
- extern void call (struct sg *g,zword, short, zword *, short);
- extern void split_window (struct sg *g,zword);
- extern void script_open (struct sg *g);
- extern void script_close (struct sg *g);
-
- /*extern void (*op0_opcodes[]) (void);
- extern void (*op1_opcodes[]) (void);
- extern void (*op2_opcodes[]) (void);
- extern void (*var_opcodes[]) (void);*/
-
-
-
- /*
- * get_header_extension
- *
- * Read a value from the header extension (former mouse table).
- *
- */
-
- zword get_header_extension (struct sg *g, short entry)
- {
- zword addr;
- zword val;
-
- if (g->h_extension_table == 0 || entry > g->hx_table_size)
- return 0;
-
- addr = g->h_extension_table + 2 * entry;
- LOW_WORD (addr, val)
-
- return val;
-
- }/* get_header_extension */
-
- /*
- * set_header_extension
- *
- * Set an entry in the header extension (former mouse table).
- *
- */
-
- void set_header_extension (struct sg *g, short entry, zword val)
- {
- zword addr;
-
- if (g->h_extension_table == 0 || entry > g->hx_table_size)
- return;
-
- addr = g->h_extension_table + 2 * entry;
- SET_WORD (addr, val)
-
- }/* set_header_extension */
-
- /*
- * restart_header
- *
- * Set all header fields which hold information about the interpreter.
- *
- */
-
- void restart_header (struct sg *g)
- {
- zword screen_x_size;
- zword screen_y_size;
- zbyte font_x_size;
- zbyte font_y_size;
-
- short i;
-
- SET_BYTE (H_CONFIG, g->h_config)
- SET_WORD (H_FLAGS, g->h_flags)
-
- if (g->h_version >= V4) {
- SET_BYTE (H_INTERPRETER_NUMBER, g->h_interpreter_number)
- SET_BYTE (H_INTERPRETER_VERSION, g->h_interpreter_version)
- SET_BYTE (H_SCREEN_ROWS, g->h_screen_rows)
- SET_BYTE (H_SCREEN_COLS, g->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 (g->h_version != V6) {
- screen_x_size = (zword) g->h_screen_cols;
- screen_y_size = (zword) g->h_screen_rows;
- font_x_size = 1;
- font_y_size = 1;
- } else {
- screen_x_size = g->h_screen_width;
- screen_y_size = g->h_screen_height;
- font_x_size = g->h_font_width;
- font_y_size = g->h_font_height;
- }
-
- if (g->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, g->h_default_background)
- SET_BYTE (H_DEFAULT_FOREGROUND, g->h_default_foreground)
- }
-
- if (g->h_version == V6)
- for (i = 0; i < 8; i++)
- storeb (g, (zword) (H_USER_NAME + i), g->h_user_name[i]);
-
- SET_BYTE (H_STANDARD_HIGH, g->h_standard_high)
- SET_BYTE (H_STANDARD_LOW, g->h_standard_low)
-
- }/* restart_header */
-
- /*
- * init_memory
- *
- * Allocate memory and load the story file.
- *
- */
-
- void init_memory (struct sg *g)
- {
- zword addr;
- int i, j;
-
- /* Open story file */
-
- if ((g->story_fp = SrvOpenRead(g, g->story_name)) == NULL)
- os_fatal (g, "Cannot open story file");
-
- /* Load header into memory */
- g->zmp = g->Header;
-
- if (SrvRead (g, g->zmp, 1, 64, g->story_fp) != 64)
- os_fatal (g, "Story file read error");
-
- /* Copy header fields to global variables */
- LOW_BYTE (H_VERSION, g->h_version)
-
- if (g->h_version < V1 || g->h_version > V8)
- os_fatal (g, "Unknown Z-code version");
-
- LOW_BYTE (H_CONFIG, g->h_config)
-
- if (g->h_version == V3 && (g->h_config & CONFIG_BYTE_SWAPPED))
- os_fatal (g, "Byte swapped story file");
-
- LOW_WORD (H_RELEASE, g->h_release)
- LOW_WORD (H_RESIDENT_SIZE, g->h_resident_size)
- LOW_WORD (H_START_PC, g->h_start_pc)
- LOW_WORD (H_DICTIONARY, g->h_dictionary)
- LOW_WORD (H_OBJECTS, g->h_objects)
- LOW_WORD (H_GLOBALS, g->h_globals)
- LOW_WORD (H_DYNAMIC_SIZE, g->h_dynamic_size)
- LOW_WORD (H_FLAGS, g->h_flags)
-
-
- for (i = 0, addr = H_SERIAL; i < 6; i++, addr++)
- LOW_BYTE (addr, g->h_serial[i])
-
- /* Auto-detect buggy story files that need special fixes */
-
- for (i = 0; g->records[i].story_id != UNKNOWN; i++) {
-
- if (g->h_release == g->records[i].release) {
-
- for (j = 0; j < 6; j++)
- if (g->h_serial[j] != g->records[i].serial[j])
- goto no_match;
-
- g->story_id = g->records[i].story_id;
-
- }
-
- no_match:
- g->story_id = g->story_id;
-
- }
-
- LOW_WORD (H_ABBREVIATIONS, g->h_abbreviations)
- LOW_WORD (H_FILE_SIZE, g->h_file_size)
-
- /* Calculate story file size in bytes */
-
- if (g->h_file_size != 0) {
-
- g->story_size = (long) 2 * g->h_file_size;
-
- if (g->h_version >= V4)
- g->story_size *= 2;
- if (g->h_version >= V6)
- g->story_size *= 2;
-
- } else { /* some old games lack the file size entry */
-
- SrvSeek(g, g->story_fp, 0, SEEK_END);
- g->story_size = SrvTell(g, g->story_fp);
- SrvSeek(g, g->story_fp, 64, SEEK_SET);
-
- }
-
- LOW_WORD (H_CHECKSUM, g->h_checksum)
- LOW_WORD (H_ALPHABET, g->h_alphabet)
- LOW_WORD (H_FUNCTIONS_OFFSET, g->h_functions_offset)
- LOW_WORD (H_STRINGS_OFFSET, g->h_strings_offset)
- LOW_WORD (H_TERMINATING_KEYS, g->h_terminating_keys)
- LOW_WORD (H_EXTENSION_TABLE, g->h_extension_table)
-
- /* Zork Zero Macintosh doesn't have the graphics flag set */
-
- if (g->story_id == ZORK_ZERO && g->h_release == 296)
- g->h_flags |= GRAPHICS_FLAG;
-
- /* Adjust opcode tables */
-
- if (g->h_version <= V4) {
- g->op0_opcodes[0x09] = z_pop;
- g->op1_opcodes[0x0f] = z_not;
- } else {
- g->op0_opcodes[0x09] = z_catch;
- g->op1_opcodes[0x0f] = z_call_n;
- }
-
- SrvClose(g, g->story_fp);
-
- if ((g->story_fp = SrvOpenRead(g,g->story_name)) == NULL)
- os_fatal (g, "Cannot open story file");
- /* Allocate memory for story data */
-
- if ((g->zmp = (zbyte far *) SrvMalloc (g,0, g->story_size)) == NULL)
- os_fatal (g, "Out of memory");
-
- if (SrvRead (g, g->zmp, 1, 64, g->story_fp) != 64)
- os_fatal (g, "Story file read error");
- SET_PC (64)
- if (SrvRead (g, g->pcp, 1, g->story_size-64, g->story_fp) != g->story_size-64)
- os_fatal (g, "Story file read error");
-
- SET_PC (g->story_size)
-
-
- /* Read header extension table */
-
- g->hx_table_size = get_header_extension (g, HX_TABLE_SIZE);
- g->hx_unicode_table = get_header_extension (g, HX_UNICODE_TABLE);
- }
- /* 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 (struct sg *g)
- {
- void *reserved;
-
- if (g->reserve_mem != 0)
- if ((reserved = SrvMalloc (g, 1, g->reserve_mem)) == NULL)
- return;
-
- while (g->undo_slots < g->option_undo_slots && g->undo_slots < MAX_UNDO_SLOTS) {
-
- void *mem = SrvMalloc (g,2 + g->undo_slots, (long) sizeof (g->stack) + g->h_dynamic_size);
-
- if (mem == NULL)
- break;
-
- g->undo[g->undo_slots++] = (unsigned char *)mem;
-
- }
-
- if (g->reserve_mem != 0)
- SrvFree (g,1, reserved);
-
- }/* init_undo */
-
- /*
- * reset_memory
- *
- * Close the story file and deallocate memory.
- *
- */
-
- void reset_memory (struct sg *g)
- {
-
- SrvClose(g,g->story_fp);
-
- while (g->undo_slots--)
- SrvFree (g, 2 + g->undo_slots, g->undo[g->undo_slots]);
-
- SrvFree (g, 0, g->zmp);
-
- }/* reset_memory */
-
- /*
- * storeb
- *
- * Write a byte value to the dynamic Z-machine memory.
- *
- */
-
- void storeb (struct sg *g, zword addr, zbyte value)
- {
-
- if (addr >= g->h_dynamic_size)
- runtime_error (g, "Store out of dynamic memory");
-
- if (addr == H_FLAGS + 1) { /* flags register is modified */
-
- g->h_flags &= ~(SCRIPTING_FLAG | FIXED_FONT_FLAG);
- g->h_flags |= value & (SCRIPTING_FLAG | FIXED_FONT_FLAG);
-
- if (value & SCRIPTING_FLAG) {
- if (!g->ostream_script)
- script_open (g);
- } else {
- if (g->ostream_script)
- script_close (g);
- }
-
- refresh_text_style (g);
-
- }
-
- SET_BYTE (addr, value)
-
- }/* storeb */
-
- /*
- * storew
- *
- * Write a word value to the dynamic Z-machine memory.
- *
- */
-
- void storew (struct sg *g, zword addr, zword value)
- {
-
- storeb (g, (zword) (addr + 0), hi (value));
- storeb (g, (zword) (addr + 1), lo (value));
-
- }/* storew */
-
- /*
- * z_restart, re-load dynamic area, clear the stack and set the PC.
- *
- * no zargs used
- *
- */
-
- void z_restart (struct sg *g)
- {
-
- flush_buffer (g);
-
- os_restart_game (g, RESTART_BEGIN);
-
- if (!g->first_restart) {
-
- SrvSeek (g, g->story_fp, 0, SEEK_SET);
-
- if (SrvRead (g, g->zmp, 1, g->h_dynamic_size, g->story_fp) != g->h_dynamic_size)
- os_fatal (g, "Story file read error");
-
- } else g->first_restart = FALSE;
-
- restart_header (g);
- restart_screen (g);
-
- g->sp = g->fp = g->stack + STACK_SIZE;
-
- if (g->h_version != V6) {
-
- long pc = (long) g->h_start_pc;
- SET_PC (pc)
-
- } else call (g, g->h_start_pc, 0, NULL, 0);
-
- os_restart_game (g, RESTART_END);
-
- }/* z_restart */
-
- /*
- * get_default_name
- *
- * Read a default file name from the memory of the Z-machine and
- * copy it to a string.
- *
- */
-
- void get_default_name (struct sg *g, char *default_name, zword addr)
- {
-
- if (addr != 0) {
-
- zbyte len;
- short i;
-
- LOW_BYTE (addr, len)
- addr++;
-
- for (i = 0; i < len; i++) {
-
- zbyte c;
-
- LOW_BYTE (addr, c)
- addr++;
-
- if (c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
-
- default_name[i] = c;
-
- }
-
- default_name[i] = 0;
-
- if (Srvstrchr (default_name, '.') == NULL)
- Srvstrcpy (default_name + i, ".AUX");
-
- } else Srvstrcpy (default_name, g->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 (struct sg *g)
- {
- char new_name[MAX_FILE_NAME + 1];
- char default_name[MAX_FILE_NAME + 1];
- FILE *gfp;
- short pfbuffin = 0;
- int lbuffin;
- unsigned char *fbuffin = g->filebuffin;
- short maxfbuffin = sizeof(g->filebuffin) -4;
- short pfbuffins = 0;
- int lbuffins;
- unsigned char *fbuffins = g->filebuffout;
- short maxfbuffins = sizeof(g->filebuffout) -4;
- int frotzs5fmt = 0;
- zword s5fp, *parsefp;
-
- zword success = 0;
-
- if (g->zargc != 0) {
-
- /* Get the file name */
-
- get_default_name (g, default_name, (short)((g->zargc >= 3) ? g->zargs[2] : 0));
-
- if (os_read_file_name (g, new_name, default_name, FILE_LOAD_AUX) == 0)
- goto finished;
-
- Srvstrcpy (g->auxilary_name, default_name);
-
- /* Open auxilary file */
-
- if ((gfp = SrvOpenRead (g, new_name)) == NULL)
- goto finished;
-
- /* Load auxilary file */
-
- success = SrvRead (g, g->zmp + g->zargs[0], 1, g->zargs[1], gfp);
-
- /* Close auxilary file */
-
- SrvClose(g, gfp);
-
- } else {
-
- long pc;
- zword release;
- zword addr;
- short i;
-
- /* Get the file name */
-
- if (os_read_file_name (g, new_name, g->save_name, FILE_RESTORE) == 0)
- goto finished;
-
- Srvstrcpy (g->save_name, new_name);
-
- /* Open game file */
-
- if ((gfp = SrvOpenRead(g, new_name)) == NULL)
- goto finished;
-
- /* Load game file */
-
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
- release = (unsigned) fbuffin[pfbuffin++] << 8;
- release |= fbuffin[pfbuffin++];
-
- pfbuffin++;
- pfbuffin++;
-
- /* Check the release number */
-
- if (release == g->h_release) {
-
- pc = (long) fbuffin[pfbuffin++] << 16;
- pc |= (unsigned) fbuffin[pfbuffin++] << 8;
- pc |= fbuffin[pfbuffin++];
-
- SET_PC (pc)
-
- g->sp = g->stack + (fbuffin[pfbuffin++] << 8);
- g->sp += fbuffin[pfbuffin++];
- g->fp = g->stack + (fbuffin[pfbuffin++] << 8);
- g->fp += fbuffin[pfbuffin++];
- if((g->sp - g->stack) > 3000)
- {
- frotzs5fmt = 1;
- g->sp -= 3072;
- g->fp -= 3072;
- }
-
- lbuffin -= pfbuffin;
-
- for (i = (short) (g->sp - g->stack); i < STACK_SIZE; i++) {
- g->stack[i] = (unsigned) fbuffin[pfbuffin++] << 8;
- if(--lbuffin == 0)
- {
- pfbuffin = 0;
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
- }
- g->stack[i] |= fbuffin[pfbuffin++];
- if(--lbuffin == 0)
- {
- pfbuffin = 0;
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
- }
- }
-
- SrvSeek (g, g->story_fp, 0, SEEK_SET);
- lbuffins = SrvRead (g, fbuffins, 1, maxfbuffins, g->story_fp);
-
- for (addr = 0; addr < g->h_dynamic_size; addr++) {
- short skip = fbuffin[pfbuffin++];
- if(--lbuffin == 0)
- {
- pfbuffin = 0;
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
- }
- for (i = 0; i < skip; i++)
- {
- g->zmp[addr++] = fbuffins[pfbuffins++];
- if(--lbuffins == 0)
- {
- pfbuffins = 0;
- lbuffins = SrvRead (g, fbuffins, 1, maxfbuffins, g->story_fp);
- }
- }
- g->zmp[addr] = fbuffin[pfbuffin++];
- if(--lbuffin <= 0)
- {
- pfbuffin = 0;
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
- }
- pfbuffins++;
- if(--lbuffins <= 0)
- {
- pfbuffins = 0;
- lbuffins = SrvRead (g, fbuffins, 1, maxfbuffins, g->story_fp);
- }
- }
-
- SrvSeek (g, g->story_fp, g->h_dynamic_size, SEEK_SET);
- /* Check for errors */
-
- if (SrvError (g, gfp) || SrvError (g, g->story_fp) || addr != g->h_dynamic_size)
- os_fatal (g, "Error reading save file");
-
- /* Reset upper window (V3 only) */
-
- if (g->h_version == V3)
- split_window (g,0);
-
- /* Initialise story header */
-
- restart_header (g);
-
- /* Success */
-
- success = 2;
-
- } else print_string (g,"Invalid save file\n");
-
- /* Close game file */
- SrvClose (g, gfp);
-
- if(frotzs5fmt)
- {
- parsefp = g->fp;
- while((parsefp - g->stack) <= 1020)
- {
- s5fp = *++parsefp;
- *parsefp = s5fp - 3072;
- parsefp = g->stack + s5fp - 3071;
- }
- }
-
- }
-
- finished:
-
- if (g->h_version <= V3)
- branch (g, success);
- else
- store (g, success);
-
- }/* z_restore */
-
- /*
- * restore_undo
- *
- * This function does the dirty work for z_restore_undo.
- *
- */
-
- short restore_undo (struct sg *g)
- {
-
- if (g->undo_slots == 0) /* undo feature unavailable */
-
- return -1;
-
- else if (g->undo_valid == 0) /* no saved game state */
-
- return 0;
-
- else { /* undo possible */
-
- long pc;
-
- if (g->undo_count == 0)
- g->undo_count = g->undo_slots;
-
- Srvmemcpy (g->stack, g->undo[g->undo_count - 1], sizeof (g->stack));
- Srvmemcpy (g->zmp, g->undo[g->undo_count - 1] + sizeof (g->stack), g->h_dynamic_size);
-
- pc = ((long) g->stack[0] << 16) | g->stack[1];
- g->sp = g->stack + g->stack[2];
- g->fp = g->stack + g->stack[3];
-
- SET_PC (pc)
-
- restart_header (g);
-
- g->undo_count--;
- g->undo_valid--;
-
- return 2;
-
- }
-
- }/* restore_undo */
-
- /*
- * z_restore_undo, restore a Z-machine state from memory.
- *
- * no zargs used
- *
- */
-
- void z_restore_undo (struct sg *g)
- {
-
- store (g, (zword) restore_undo (g));
-
- }/* 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 (struct sg *g)
- {
- char new_name[MAX_FILE_NAME + 1];
- char default_name[MAX_FILE_NAME + 1];
- FILE *gfp;
- short pfbuffout = 0;
- unsigned char *fbuffout = g->filebuffout;
- short maxfbuffout = sizeof(g->filebuffout) -4;
- short pfbuffin = 0;
- int lbuffin;
- unsigned char *fbuffin = g->filebuffin;
- short maxfbuffin = sizeof(g->filebuffin) -4;
-
- zword success = 0;
-
- if (g->zargc != 0) {
-
- /* Get the file name */
-
- get_default_name (g, default_name, (short)((g->zargc >= 3) ? g->zargs[2] : 0));
-
- if (os_read_file_name (g, new_name, default_name, FILE_SAVE_AUX) == 0)
- goto finished;
-
- Srvstrcpy (g->auxilary_name, default_name);
-
- /* Open auxilary file */
-
- if ((gfp = SrvOpenWrite (g, new_name)) == NULL)
- goto finished;
-
- /* Write auxilary file */
-
- success = SrvWrite (g, g->zmp + g->zargs[0], g->zargs[1], 1, gfp);
-
- /* Close auxilary file */
-
- SrvClose (g, gfp);
-
- } else {
-
- long pc;
- zword addr;
- zword nsp, nfp;
- short skip;
- short i;
-
- /* Get the file name */
-
- if (os_read_file_name (g, new_name, g->save_name, FILE_SAVE) == 0)
- goto finished;
-
- Srvstrcpy (g->save_name, new_name);
-
- /* Open game file */
-
- if ((gfp = SrvOpenWrite(g, new_name)) == NULL)
- goto finished;
-
- /* Write game file */
- fbuffout[pfbuffout++] = (unsigned char) hi (g->h_release);
- fbuffout[pfbuffout++] = (unsigned char) lo (g->h_release);
- fbuffout[pfbuffout++] = (unsigned char) hi (g->h_checksum);
- fbuffout[pfbuffout++] = (unsigned char) lo (g->h_checksum);
-
- GET_PC (pc)
-
- fbuffout[pfbuffout++] = (unsigned char) (pc >> 16) & 0xff;
- fbuffout[pfbuffout++] = (unsigned char) (pc >> 8) & 0xff;
- fbuffout[pfbuffout++] = (unsigned char) (pc) & 0xff;
-
- nsp = (short) (g->sp - g->stack);
- nfp = (short) (g->fp - g->stack);
-
- fbuffout[pfbuffout++] = (unsigned char) hi (nsp);
- fbuffout[pfbuffout++] = (unsigned char) lo (nsp);
- fbuffout[pfbuffout++] = (unsigned char) hi (nfp);
- fbuffout[pfbuffout++] = (unsigned char) lo (nfp);
-
- for (i = nsp; i < STACK_SIZE; i++) {
- fbuffout[pfbuffout++] = (unsigned char) hi (g->stack[i]);
- fbuffout[pfbuffout++] = (unsigned char) lo (g->stack[i]);
- if(pfbuffout >= maxfbuffout)
- {
- SrvWrite(g, fbuffout, pfbuffout, 1, gfp);
- pfbuffout = 0;
- }
- }
-
- SrvSeek (g, g->story_fp, 0, SEEK_SET);
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, g->story_fp);
-
- for (addr = 0, skip = 0; addr < g->h_dynamic_size; addr++)
- {
- if (g->zmp[addr] != fbuffin[pfbuffin++] || skip == 255 || addr + 1 == g->h_dynamic_size) {
- fbuffout[pfbuffout++] = (unsigned char) skip;
- fbuffout[pfbuffout++] = (unsigned char) g->zmp[addr];
- if(pfbuffout >= maxfbuffout)
- {
- SrvWrite(g, fbuffout, pfbuffout, 1, gfp);
- pfbuffout = 0;
- }
- skip = 0;
- } else skip++;
- if(--lbuffin == 0)
- {
- pfbuffin = 0;
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, g->story_fp);
- }
- }
-
- /* Close game file and check for errors */
- if(pfbuffout > 0)
- SrvWrite(g, fbuffout, pfbuffout, 1, gfp);
- SrvClose(g, gfp);
- SrvSeek (g, g->story_fp, g->h_dynamic_size, SEEK_SET);
- success = 1;
- }
-
- finished:
-
- if (g->h_version <= V3)
- branch (g,success);
- else
- store (g,success);
-
- }/* z_save */
-
- /*
- * save_undo
- *
- * This function does the dirty work for z_save_undo.
- *
- */
-
- short save_undo (struct sg *g)
- {
- long pc;
-
- if (g->undo_slots == 0) /* undo feature unavailable */
-
- return -1;
-
- else { /* save undo possible */
-
- if (g->undo_count == g->undo_slots)
- g->undo_count = 0;
-
- GET_PC (pc)
-
- g->stack[0] = (zword) (pc >> 16);
- g->stack[1] = (zword) (pc & 0xffff);
- g->stack[2] = (zword) (g->sp - g->stack);
- g->stack[3] = (zword) (g->fp - g->stack);
-
- Srvmemcpy (g->undo[g->undo_count], g->stack, sizeof (g->stack));
- Srvmemcpy (g->undo[g->undo_count] + sizeof (g->stack), g->zmp, g->h_dynamic_size);
-
- if (++(g->undo_count) == g->undo_slots)
- g->undo_count = 0;
- if (++(g->undo_valid) > g->undo_slots)
- g->undo_valid = g->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 (struct sg *g)
- {
-
- store (g, (zword) save_undo (g));
-
- }/* z_save_undo */
-
- /*
- * z_verify, check the story file integrity.
- *
- * no zargs used
- *
- */
-
- void z_verify (struct sg *g)
- {
- zword checksum = 0;
- long i;
- short pfbuffin = 0;
- int lbuffin;
- unsigned char *fbuffin = g->filebuffin;
- short maxfbuffin = sizeof(g->filebuffin) -4;
-
- /* Sum all bytes in story file except header bytes */
-
- SrvSeek (g, g->story_fp, 64, SEEK_SET);
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, g->story_fp);
-
- for (i = 64; i < g->story_size; i++)
- {
- checksum += fbuffin[pfbuffin++];
- if(--lbuffin == 0)
- {
- pfbuffin = 0;
- lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, g->story_fp);
- }
- }
- SrvSeek (g, g->story_fp, g->story_size, SEEK_SET);
-
- /* Branch if the checksums are equal */
-
- branch (g, checksum == g->h_checksum);
-
- }/* z_verify */
-