home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / Epoc / Palmtime / files / FrotzS5_src.ZIP / FASTMEM.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-23  |  20.7 KB  |  932 lines

  1. /*
  2.  * fastmem.c
  3.  *
  4.  * Memory related functions (fast version without virtual memory)
  5.  *
  6.  */
  7.  
  8. #include "frotz.h"
  9. #include "S5api.h"
  10.  
  11. #ifndef SEEK_SET
  12. #define SEEK_SET 0
  13. #define SEEK_CUR 1
  14. #define SEEK_END 2
  15. #endif
  16.  
  17. extern void restart_screen (struct sg *g);
  18. extern void refresh_text_style (struct sg *g);
  19. extern void call (struct sg *g,zword, short, zword *, short);
  20. extern void split_window (struct sg *g,zword);
  21. extern void script_open (struct sg *g);
  22. extern void script_close (struct sg *g);
  23.  
  24. /*extern void (*op0_opcodes[]) (void);
  25. extern void (*op1_opcodes[]) (void);
  26. extern void (*op2_opcodes[]) (void);
  27. extern void (*var_opcodes[]) (void);*/
  28.  
  29.  
  30.  
  31. /*
  32.  * get_header_extension
  33.  *
  34.  * Read a value from the header extension (former mouse table).
  35.  *
  36.  */
  37.  
  38. zword get_header_extension (struct sg *g, short entry)
  39. {
  40.     zword addr;
  41.     zword val;
  42.  
  43.     if (g->h_extension_table == 0 || entry > g->hx_table_size)
  44.     return 0;
  45.  
  46.     addr = g->h_extension_table + 2 * entry;
  47.     LOW_WORD (addr, val)
  48.  
  49.     return val;
  50.  
  51. }/* get_header_extension */
  52.  
  53. /*
  54.  * set_header_extension
  55.  *
  56.  * Set an entry in the header extension (former mouse table).
  57.  *
  58.  */
  59.  
  60. void set_header_extension (struct sg *g, short entry, zword val)
  61. {
  62.     zword addr;
  63.  
  64.     if (g->h_extension_table == 0 || entry > g->hx_table_size)
  65.     return;
  66.  
  67.     addr = g->h_extension_table + 2 * entry;
  68.     SET_WORD (addr, val)
  69.  
  70. }/* set_header_extension */
  71.  
  72. /*
  73.  * restart_header
  74.  *
  75.  * Set all header fields which hold information about the interpreter.
  76.  *
  77.  */
  78.  
  79. void restart_header (struct sg *g)
  80. {
  81.     zword screen_x_size;
  82.     zword screen_y_size;
  83.     zbyte font_x_size;
  84.     zbyte font_y_size;
  85.  
  86.     short i;
  87.  
  88.     SET_BYTE (H_CONFIG, g->h_config)
  89.     SET_WORD (H_FLAGS, g->h_flags)
  90.  
  91.     if (g->h_version >= V4) {
  92.     SET_BYTE (H_INTERPRETER_NUMBER, g->h_interpreter_number)
  93.     SET_BYTE (H_INTERPRETER_VERSION, g->h_interpreter_version)
  94.     SET_BYTE (H_SCREEN_ROWS, g->h_screen_rows)
  95.     SET_BYTE (H_SCREEN_COLS, g->h_screen_cols)
  96.     }
  97.  
  98.     /* It's less trouble to use font size 1x1 for V5 games, especially
  99.        because of a bug in the unreleased German version of "Zork 1" */
  100.  
  101.     if (g->h_version != V6) {
  102.     screen_x_size = (zword) g->h_screen_cols;
  103.     screen_y_size = (zword) g->h_screen_rows;
  104.     font_x_size = 1;
  105.     font_y_size = 1;
  106.     } else {
  107.     screen_x_size = g->h_screen_width;
  108.     screen_y_size = g->h_screen_height;
  109.     font_x_size = g->h_font_width;
  110.     font_y_size = g->h_font_height;
  111.     }
  112.  
  113.     if (g->h_version >= V5) {
  114.     SET_WORD (H_SCREEN_WIDTH, screen_x_size)
  115.     SET_WORD (H_SCREEN_HEIGHT, screen_y_size)
  116.     SET_BYTE (H_FONT_HEIGHT, font_y_size)
  117.     SET_BYTE (H_FONT_WIDTH, font_x_size)
  118.     SET_BYTE (H_DEFAULT_BACKGROUND, g->h_default_background)
  119.     SET_BYTE (H_DEFAULT_FOREGROUND, g->h_default_foreground)
  120.     }
  121.  
  122.     if (g->h_version == V6)
  123.     for (i = 0; i < 8; i++)
  124.         storeb (g, (zword) (H_USER_NAME + i), g->h_user_name[i]);
  125.  
  126.     SET_BYTE (H_STANDARD_HIGH, g->h_standard_high)
  127.     SET_BYTE (H_STANDARD_LOW, g->h_standard_low)
  128.  
  129. }/* restart_header */
  130.  
  131. /*
  132.  * init_memory
  133.  *
  134.  * Allocate memory and load the story file.
  135.  *
  136.  */
  137.  
  138. void init_memory (struct sg *g)
  139. {
  140.     zword addr;
  141.     int i, j;
  142.  
  143.     /* Open story file */
  144.  
  145.     if ((g->story_fp = SrvOpenRead(g, g->story_name)) == NULL)
  146.     os_fatal (g, "Cannot open story file");
  147.  
  148.     /* Load header into memory */
  149.     g->zmp = g->Header;
  150.  
  151.     if (SrvRead (g, g->zmp, 1, 64, g->story_fp) != 64)
  152.     os_fatal (g, "Story file read error");
  153.  
  154.     /* Copy header fields to global variables */
  155.     LOW_BYTE (H_VERSION, g->h_version)
  156.  
  157.     if (g->h_version < V1 || g->h_version > V8)
  158.     os_fatal (g, "Unknown Z-code version");
  159.  
  160.     LOW_BYTE (H_CONFIG, g->h_config)
  161.  
  162.     if (g->h_version == V3 && (g->h_config & CONFIG_BYTE_SWAPPED))
  163.     os_fatal (g, "Byte swapped story file");
  164.  
  165.     LOW_WORD (H_RELEASE, g->h_release)
  166.     LOW_WORD (H_RESIDENT_SIZE, g->h_resident_size)
  167.     LOW_WORD (H_START_PC, g->h_start_pc)
  168.     LOW_WORD (H_DICTIONARY, g->h_dictionary)
  169.     LOW_WORD (H_OBJECTS, g->h_objects)
  170.     LOW_WORD (H_GLOBALS, g->h_globals)
  171.     LOW_WORD (H_DYNAMIC_SIZE, g->h_dynamic_size)
  172.     LOW_WORD (H_FLAGS, g->h_flags)
  173.  
  174.  
  175.     for (i = 0, addr = H_SERIAL; i < 6; i++, addr++)
  176.       LOW_BYTE (addr, g->h_serial[i])
  177.  
  178.     /* Auto-detect buggy story files that need special fixes */
  179.  
  180.     for (i = 0; g->records[i].story_id != UNKNOWN; i++) {
  181.  
  182.     if (g->h_release == g->records[i].release) {
  183.  
  184.         for (j = 0; j < 6; j++)
  185.         if (g->h_serial[j] != g->records[i].serial[j])
  186.             goto no_match;
  187.  
  188.         g->story_id = g->records[i].story_id;
  189.  
  190.     }
  191.  
  192.     no_match:
  193.     g->story_id = g->story_id;
  194.  
  195.     }
  196.  
  197.     LOW_WORD (H_ABBREVIATIONS, g->h_abbreviations)
  198.     LOW_WORD (H_FILE_SIZE, g->h_file_size)
  199.  
  200.     /* Calculate story file size in bytes */
  201.  
  202.     if (g->h_file_size != 0) {
  203.  
  204.     g->story_size = (long) 2 * g->h_file_size;
  205.  
  206.     if (g->h_version >= V4)
  207.         g->story_size *= 2;
  208.     if (g->h_version >= V6)
  209.         g->story_size *= 2;
  210.  
  211.     } else {        /* some old games lack the file size entry */
  212.  
  213.     SrvSeek(g, g->story_fp, 0, SEEK_END);
  214.     g->story_size = SrvTell(g, g->story_fp);
  215.     SrvSeek(g, g->story_fp, 64, SEEK_SET);
  216.  
  217.     }
  218.  
  219.     LOW_WORD (H_CHECKSUM, g->h_checksum)
  220.     LOW_WORD (H_ALPHABET, g->h_alphabet)
  221.     LOW_WORD (H_FUNCTIONS_OFFSET, g->h_functions_offset)
  222.     LOW_WORD (H_STRINGS_OFFSET, g->h_strings_offset)
  223.     LOW_WORD (H_TERMINATING_KEYS, g->h_terminating_keys)
  224.     LOW_WORD (H_EXTENSION_TABLE, g->h_extension_table)
  225.  
  226.     /* Zork Zero Macintosh doesn't have the graphics flag set */
  227.  
  228.     if (g->story_id == ZORK_ZERO && g->h_release == 296)
  229.     g->h_flags |= GRAPHICS_FLAG;
  230.  
  231.     /* Adjust opcode tables */
  232.  
  233.     if (g->h_version <= V4) {
  234.     g->op0_opcodes[0x09] = z_pop;
  235.     g->op1_opcodes[0x0f] = z_not;
  236.     } else {
  237.     g->op0_opcodes[0x09] = z_catch;
  238.     g->op1_opcodes[0x0f] = z_call_n;
  239.     }
  240.  
  241.     SrvClose(g, g->story_fp);
  242.     
  243.     if ((g->story_fp = SrvOpenRead(g,g->story_name)) == NULL)
  244.         os_fatal (g, "Cannot open story file");
  245.     /* Allocate memory for story data */
  246.  
  247.     if ((g->zmp = (zbyte far *) SrvMalloc (g,0, g->story_size)) == NULL)
  248.     os_fatal (g, "Out of memory");
  249.  
  250.     if (SrvRead (g, g->zmp, 1, 64, g->story_fp) != 64)
  251.         os_fatal (g, "Story file read error");
  252.     SET_PC (64)
  253.     if (SrvRead (g, g->pcp, 1, g->story_size-64, g->story_fp) != g->story_size-64)
  254.         os_fatal (g, "Story file read error");
  255.  
  256.     SET_PC (g->story_size)
  257.  
  258.  
  259.     /* Read header extension table */
  260.  
  261.     g->hx_table_size = get_header_extension (g, HX_TABLE_SIZE);
  262.     g->hx_unicode_table = get_header_extension (g, HX_UNICODE_TABLE);
  263. }
  264. /* init_memory */
  265.  
  266. /*
  267.  * init_undo
  268.  *
  269.  * Allocate memory for multiple undo. It is important not to occupy
  270.  * all the memory available, since the IO interface may need memory
  271.  * during the game, e.g. for loading sounds or pictures.
  272.  *
  273.  */
  274.  
  275. void init_undo (struct sg *g)
  276. {
  277.     void *reserved;
  278.  
  279.     if (g->reserve_mem != 0)
  280.     if ((reserved = SrvMalloc (g, 1, g->reserve_mem)) == NULL)
  281.         return;
  282.  
  283.     while (g->undo_slots < g->option_undo_slots && g->undo_slots < MAX_UNDO_SLOTS) {
  284.  
  285.     void *mem = SrvMalloc (g,2 + g->undo_slots, (long) sizeof (g->stack) + g->h_dynamic_size);
  286.  
  287.     if (mem == NULL)
  288.         break;
  289.  
  290.     g->undo[g->undo_slots++] = (unsigned char *)mem;
  291.  
  292.     }
  293.  
  294.     if (g->reserve_mem != 0)
  295.     SrvFree (g,1, reserved);
  296.  
  297. }/* init_undo */
  298.  
  299. /*
  300.  * reset_memory
  301.  *
  302.  * Close the story file and deallocate memory.
  303.  *
  304.  */
  305.  
  306. void reset_memory (struct sg *g)
  307. {
  308.  
  309.     SrvClose(g,g->story_fp);
  310.  
  311.     while (g->undo_slots--)
  312.     SrvFree (g, 2 + g->undo_slots, g->undo[g->undo_slots]);
  313.  
  314.     SrvFree (g, 0, g->zmp);
  315.  
  316. }/* reset_memory */
  317.  
  318. /*
  319.  * storeb
  320.  *
  321.  * Write a byte value to the dynamic Z-machine memory.
  322.  *
  323.  */
  324.  
  325. void storeb (struct sg *g, zword addr, zbyte value)
  326. {
  327.  
  328.     if (addr >= g->h_dynamic_size)
  329.     runtime_error (g, "Store out of dynamic memory");
  330.  
  331.     if (addr == H_FLAGS + 1) {    /* flags register is modified */
  332.  
  333.     g->h_flags &= ~(SCRIPTING_FLAG | FIXED_FONT_FLAG);
  334.     g->h_flags |= value & (SCRIPTING_FLAG | FIXED_FONT_FLAG);
  335.  
  336.     if (value & SCRIPTING_FLAG) {
  337.         if (!g->ostream_script)
  338.         script_open (g);
  339.     } else {
  340.         if (g->ostream_script)
  341.         script_close (g);
  342.     }
  343.  
  344.     refresh_text_style (g);
  345.  
  346.     }
  347.  
  348.     SET_BYTE (addr, value)
  349.  
  350. }/* storeb */
  351.  
  352. /*
  353.  * storew
  354.  *
  355.  * Write a word value to the dynamic Z-machine memory.
  356.  *
  357.  */
  358.  
  359. void storew (struct sg *g, zword addr, zword value)
  360. {
  361.  
  362.     storeb (g, (zword) (addr + 0), hi (value));
  363.     storeb (g, (zword) (addr + 1), lo (value));
  364.  
  365. }/* storew */
  366.  
  367. /*
  368.  * z_restart, re-load dynamic area, clear the stack and set the PC.
  369.  *
  370.  *     no zargs used
  371.  *
  372.  */
  373.  
  374. void z_restart (struct sg *g)
  375. {
  376.  
  377.     flush_buffer (g);
  378.  
  379.     os_restart_game (g, RESTART_BEGIN);
  380.  
  381.     if (!g->first_restart) {
  382.  
  383.     SrvSeek (g, g->story_fp, 0, SEEK_SET);
  384.  
  385.     if (SrvRead (g, g->zmp, 1, g->h_dynamic_size, g->story_fp) != g->h_dynamic_size)
  386.         os_fatal (g, "Story file read error");
  387.  
  388.     } else g->first_restart = FALSE;
  389.  
  390.     restart_header (g);
  391.     restart_screen (g);
  392.  
  393.     g->sp = g->fp = g->stack + STACK_SIZE;
  394.  
  395.     if (g->h_version != V6) {
  396.  
  397.     long pc = (long) g->h_start_pc;
  398.     SET_PC (pc)
  399.  
  400.     } else call (g, g->h_start_pc, 0, NULL, 0);
  401.  
  402.     os_restart_game (g, RESTART_END);
  403.  
  404. }/* z_restart */
  405.  
  406. /*
  407.  * get_default_name
  408.  *
  409.  * Read a default file name from the memory of the Z-machine and
  410.  * copy it to a string.
  411.  *
  412.  */
  413.  
  414. void get_default_name (struct sg *g, char *default_name, zword addr)
  415. {
  416.  
  417.     if (addr != 0) {
  418.  
  419.     zbyte len;
  420.     short i;
  421.  
  422.     LOW_BYTE (addr, len)
  423.     addr++;
  424.  
  425.     for (i = 0; i < len; i++) {
  426.  
  427.         zbyte c;
  428.  
  429.         LOW_BYTE (addr, c)
  430.         addr++;
  431.  
  432.         if (c >= 'A' && c <= 'Z')
  433.         c += 'a' - 'A';
  434.  
  435.         default_name[i] = c;
  436.  
  437.     }
  438.  
  439.     default_name[i] = 0;
  440.  
  441.     if (Srvstrchr (default_name, '.') == NULL)
  442.         Srvstrcpy (default_name + i, ".AUX");
  443.  
  444.     } else Srvstrcpy (default_name, g->auxilary_name);
  445.  
  446. }/* get_default_name */
  447.  
  448. /*
  449.  * z_restore, restore [a part of] a Z-machine state from disk
  450.  *
  451.  *    zargs[0] = address of area to restore (optional)
  452.  *    zargs[1] = number of bytes to restore
  453.  *    zargs[2] = address of suggested file name
  454.  *
  455.  */
  456.  
  457. void z_restore (struct sg *g)
  458. {
  459.     char new_name[MAX_FILE_NAME + 1];
  460.     char default_name[MAX_FILE_NAME + 1];
  461.     FILE *gfp;
  462.     short pfbuffin = 0;
  463.     int lbuffin;
  464.     unsigned char *fbuffin = g->filebuffin;
  465.     short maxfbuffin = sizeof(g->filebuffin) -4;
  466.     short pfbuffins = 0;
  467.     int lbuffins;
  468.     unsigned char *fbuffins = g->filebuffout;
  469.     short maxfbuffins = sizeof(g->filebuffout) -4;
  470.     int frotzs5fmt = 0;
  471.     zword s5fp, *parsefp;
  472.  
  473.     zword success = 0;
  474.  
  475.     if (g->zargc != 0) {
  476.  
  477.     /* Get the file name */
  478.  
  479.     get_default_name (g, default_name, (short)((g->zargc >= 3) ? g->zargs[2] : 0));
  480.  
  481.     if (os_read_file_name (g, new_name, default_name, FILE_LOAD_AUX) == 0)
  482.         goto finished;
  483.  
  484.     Srvstrcpy (g->auxilary_name, default_name);
  485.  
  486.     /* Open auxilary file */
  487.  
  488.     if ((gfp = SrvOpenRead (g, new_name)) == NULL)
  489.         goto finished;
  490.  
  491.     /* Load auxilary file */
  492.  
  493.     success = SrvRead (g, g->zmp + g->zargs[0], 1, g->zargs[1], gfp);
  494.  
  495.     /* Close auxilary file */
  496.  
  497.     SrvClose(g, gfp);
  498.  
  499.     } else {
  500.  
  501.     long pc;
  502.     zword release;
  503.     zword addr;
  504.     short i;
  505.  
  506.     /* Get the file name */
  507.  
  508.     if (os_read_file_name (g, new_name, g->save_name, FILE_RESTORE) == 0)
  509.         goto finished;
  510.  
  511.     Srvstrcpy (g->save_name, new_name);
  512.  
  513.     /* Open game file */
  514.  
  515.     if ((gfp = SrvOpenRead(g, new_name)) == NULL)
  516.         goto finished;
  517.  
  518.     /* Load game file */
  519.  
  520.         lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
  521.     release = (unsigned) fbuffin[pfbuffin++] << 8;
  522.     release |= fbuffin[pfbuffin++];
  523.  
  524.     pfbuffin++;
  525.     pfbuffin++;
  526.  
  527.     /* Check the release number */
  528.  
  529.     if (release == g->h_release) {
  530.  
  531.         pc = (long) fbuffin[pfbuffin++] << 16;
  532.         pc |= (unsigned) fbuffin[pfbuffin++] << 8;
  533.         pc |= fbuffin[pfbuffin++];
  534.  
  535.         SET_PC (pc)
  536.  
  537.         g->sp = g->stack + (fbuffin[pfbuffin++] << 8);
  538.         g->sp += fbuffin[pfbuffin++];
  539.         g->fp = g->stack + (fbuffin[pfbuffin++] << 8);
  540.         g->fp += fbuffin[pfbuffin++];
  541.         if((g->sp - g->stack) > 3000)
  542.           {
  543.           frotzs5fmt = 1;
  544.           g->sp -= 3072;
  545.           g->fp -= 3072;
  546.           }
  547.  
  548.         lbuffin -= pfbuffin;
  549.  
  550.          for (i = (short) (g->sp - g->stack); i < STACK_SIZE; i++) {
  551.         g->stack[i] = (unsigned) fbuffin[pfbuffin++] << 8;
  552.         if(--lbuffin == 0)
  553.           {
  554.           pfbuffin = 0;
  555.           lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
  556.           }
  557.         g->stack[i] |= fbuffin[pfbuffin++];
  558.         if(--lbuffin == 0)
  559.           {
  560.           pfbuffin = 0;
  561.           lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
  562.           }
  563.         }
  564.  
  565.         SrvSeek (g, g->story_fp, 0, SEEK_SET);
  566.         lbuffins = SrvRead (g, fbuffins, 1, maxfbuffins, g->story_fp);
  567.  
  568.         for (addr = 0; addr < g->h_dynamic_size; addr++) {
  569.         short skip = fbuffin[pfbuffin++];
  570.         if(--lbuffin == 0)
  571.           {
  572.           pfbuffin = 0;
  573.           lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
  574.           }
  575.         for (i = 0; i < skip; i++)
  576.             {
  577.             g->zmp[addr++] = fbuffins[pfbuffins++];
  578.             if(--lbuffins == 0)
  579.               {
  580.               pfbuffins = 0;
  581.               lbuffins = SrvRead (g, fbuffins, 1, maxfbuffins, g->story_fp);
  582.               }
  583.             }
  584.         g->zmp[addr] = fbuffin[pfbuffin++];
  585.         if(--lbuffin <= 0)
  586.           {
  587.           pfbuffin = 0;
  588.           lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, gfp);
  589.           }
  590.         pfbuffins++;
  591.         if(--lbuffins <= 0)
  592.           {
  593.           pfbuffins = 0;
  594.           lbuffins = SrvRead (g, fbuffins, 1, maxfbuffins, g->story_fp);
  595.           }
  596.         }
  597.  
  598.         SrvSeek (g, g->story_fp, g->h_dynamic_size, SEEK_SET);
  599.         /* Check for errors */
  600.  
  601.         if (SrvError (g, gfp) || SrvError (g, g->story_fp) || addr != g->h_dynamic_size)
  602.         os_fatal (g, "Error reading save file");
  603.  
  604.         /* Reset upper window (V3 only) */
  605.  
  606.         if (g->h_version == V3)
  607.         split_window (g,0);
  608.  
  609.         /* Initialise story header */
  610.  
  611.         restart_header (g);
  612.  
  613.         /* Success */
  614.  
  615.         success = 2;
  616.  
  617.     } else print_string (g,"Invalid save file\n");
  618.  
  619.     /* Close game file */
  620.     SrvClose (g, gfp);
  621.  
  622.     if(frotzs5fmt)
  623.       {
  624.       parsefp = g->fp;
  625.       while((parsefp - g->stack) <= 1020)
  626.         {
  627.         s5fp = *++parsefp;
  628.         *parsefp = s5fp - 3072;
  629.         parsefp = g->stack + s5fp - 3071;
  630.         }
  631.       }
  632.  
  633.     }
  634.  
  635. finished:
  636.  
  637.     if (g->h_version <= V3)
  638.     branch (g, success);
  639.     else
  640.     store (g, success);
  641.  
  642. }/* z_restore */
  643.  
  644. /*
  645.  * restore_undo
  646.  *
  647.  * This function does the dirty work for z_restore_undo.
  648.  *
  649.  */
  650.  
  651. short restore_undo (struct sg *g)
  652. {
  653.  
  654.     if (g->undo_slots == 0)    /* undo feature unavailable */
  655.  
  656.     return -1;
  657.  
  658.     else if (g->undo_valid == 0)    /* no saved game state */
  659.  
  660.     return 0;
  661.  
  662.     else {            /* undo possible */
  663.  
  664.     long pc;
  665.  
  666.     if (g->undo_count == 0)
  667.         g->undo_count = g->undo_slots;
  668.  
  669.     Srvmemcpy (g->stack, g->undo[g->undo_count - 1], sizeof (g->stack));
  670.     Srvmemcpy (g->zmp, g->undo[g->undo_count - 1] + sizeof (g->stack), g->h_dynamic_size);
  671.  
  672.     pc = ((long) g->stack[0] << 16) | g->stack[1];
  673.     g->sp = g->stack + g->stack[2];
  674.     g->fp = g->stack + g->stack[3];
  675.  
  676.     SET_PC (pc)
  677.  
  678.     restart_header (g);
  679.  
  680.     g->undo_count--;
  681.     g->undo_valid--;
  682.  
  683.     return 2;
  684.  
  685.     }
  686.  
  687. }/* restore_undo */
  688.  
  689. /*
  690.  * z_restore_undo, restore a Z-machine state from memory.
  691.  *
  692.  *    no zargs used
  693.  *
  694.  */
  695.  
  696. void z_restore_undo (struct sg *g)
  697. {
  698.  
  699.     store (g, (zword) restore_undo (g));
  700.  
  701. }/* restore_undo */
  702.  
  703. /*
  704.  * z_save, save [a part of] the Z-machine state to disk.
  705.  *
  706.  *    zargs[0] = address of memory area to save (optional)
  707.  *    zargs[1] = number of bytes to save
  708.  *    zargs[2] = address of suggested file name
  709.  *
  710.  */
  711.  
  712. void z_save (struct sg *g)
  713. {
  714.     char new_name[MAX_FILE_NAME + 1];
  715.     char default_name[MAX_FILE_NAME + 1];
  716.     FILE *gfp;
  717.     short pfbuffout = 0;
  718.     unsigned char *fbuffout = g->filebuffout;
  719.     short maxfbuffout = sizeof(g->filebuffout) -4;
  720.     short pfbuffin = 0;
  721.     int lbuffin;
  722.     unsigned char *fbuffin = g->filebuffin;
  723.     short maxfbuffin = sizeof(g->filebuffin) -4;
  724.  
  725.     zword success = 0;
  726.  
  727.     if (g->zargc != 0) {
  728.  
  729.     /* Get the file name */
  730.  
  731.     get_default_name (g, default_name, (short)((g->zargc >= 3) ? g->zargs[2] : 0));
  732.  
  733.     if (os_read_file_name (g, new_name, default_name, FILE_SAVE_AUX) == 0)
  734.         goto finished;
  735.  
  736.     Srvstrcpy (g->auxilary_name, default_name);
  737.  
  738.     /* Open auxilary file */
  739.  
  740.     if ((gfp = SrvOpenWrite (g, new_name)) == NULL)
  741.         goto finished;
  742.  
  743.     /* Write auxilary file */
  744.  
  745.     success = SrvWrite (g, g->zmp + g->zargs[0], g->zargs[1], 1, gfp);
  746.  
  747.     /* Close auxilary file */
  748.  
  749.     SrvClose (g, gfp);
  750.  
  751.     } else {
  752.  
  753.     long pc;
  754.     zword addr;
  755.     zword nsp, nfp;
  756.     short skip;
  757.     short i;
  758.  
  759.     /* Get the file name */
  760.  
  761.     if (os_read_file_name (g, new_name, g->save_name, FILE_SAVE) == 0)
  762.         goto finished;
  763.  
  764.     Srvstrcpy (g->save_name, new_name);
  765.  
  766.     /* Open game file */
  767.  
  768.     if ((gfp = SrvOpenWrite(g, new_name)) == NULL)
  769.         goto finished;
  770.  
  771.     /* Write game file */
  772.     fbuffout[pfbuffout++] = (unsigned char) hi (g->h_release);
  773.     fbuffout[pfbuffout++] = (unsigned char) lo (g->h_release);
  774.     fbuffout[pfbuffout++] = (unsigned char) hi (g->h_checksum);
  775.     fbuffout[pfbuffout++] = (unsigned char) lo (g->h_checksum);
  776.  
  777.     GET_PC (pc)
  778.  
  779.     fbuffout[pfbuffout++] = (unsigned char) (pc >> 16) & 0xff;
  780.     fbuffout[pfbuffout++] = (unsigned char) (pc >> 8) & 0xff;
  781.     fbuffout[pfbuffout++] = (unsigned char) (pc) & 0xff;
  782.  
  783.     nsp = (short) (g->sp - g->stack);
  784.     nfp = (short) (g->fp - g->stack);
  785.  
  786.     fbuffout[pfbuffout++] = (unsigned char) hi (nsp);
  787.     fbuffout[pfbuffout++] = (unsigned char) lo (nsp);
  788.     fbuffout[pfbuffout++] = (unsigned char) hi (nfp);
  789.     fbuffout[pfbuffout++] = (unsigned char) lo (nfp);
  790.  
  791.     for (i = nsp; i < STACK_SIZE; i++) {
  792.         fbuffout[pfbuffout++] = (unsigned char) hi (g->stack[i]);
  793.         fbuffout[pfbuffout++] = (unsigned char) lo (g->stack[i]);
  794.         if(pfbuffout >= maxfbuffout)
  795.           {
  796.           SrvWrite(g, fbuffout, pfbuffout, 1, gfp);
  797.           pfbuffout = 0;
  798.           }
  799.     }
  800.  
  801.     SrvSeek (g, g->story_fp, 0, SEEK_SET);
  802.     lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, g->story_fp);
  803.  
  804.     for (addr = 0, skip = 0; addr < g->h_dynamic_size; addr++)
  805.         {
  806.         if (g->zmp[addr] != fbuffin[pfbuffin++] || skip == 255 || addr + 1 == g->h_dynamic_size) {
  807.         fbuffout[pfbuffout++] = (unsigned char) skip;
  808.         fbuffout[pfbuffout++] = (unsigned char) g->zmp[addr];
  809.         if(pfbuffout >= maxfbuffout)
  810.           {
  811.           SrvWrite(g, fbuffout, pfbuffout, 1, gfp);
  812.           pfbuffout = 0;
  813.           }
  814.         skip = 0;
  815.         } else skip++;
  816.         if(--lbuffin == 0)
  817.           {
  818.           pfbuffin = 0;
  819.           lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, g->story_fp);
  820.           }
  821.         }
  822.  
  823.     /* Close game file and check for errors */
  824.     if(pfbuffout > 0)
  825.       SrvWrite(g, fbuffout, pfbuffout, 1, gfp);
  826.     SrvClose(g, gfp);
  827.     SrvSeek (g, g->story_fp, g->h_dynamic_size, SEEK_SET);
  828.     success = 1;
  829.     }
  830.  
  831. finished:
  832.  
  833.     if (g->h_version <= V3)
  834.     branch (g,success);
  835.     else
  836.     store (g,success);
  837.  
  838. }/* z_save */
  839.  
  840. /*
  841.  * save_undo
  842.  *
  843.  * This function does the dirty work for z_save_undo.
  844.  *
  845.  */
  846.  
  847. short save_undo (struct sg *g)
  848. {
  849.     long pc;
  850.  
  851.     if (g->undo_slots == 0)    /* undo feature unavailable */
  852.  
  853.     return -1;
  854.  
  855.     else {            /* save undo possible */
  856.  
  857.     if (g->undo_count == g->undo_slots)
  858.         g->undo_count = 0;
  859.  
  860.     GET_PC (pc)
  861.  
  862.     g->stack[0] = (zword) (pc >> 16);
  863.     g->stack[1] = (zword) (pc & 0xffff);
  864.     g->stack[2] = (zword) (g->sp - g->stack);
  865.     g->stack[3] = (zword) (g->fp - g->stack);
  866.  
  867.     Srvmemcpy (g->undo[g->undo_count], g->stack, sizeof (g->stack));
  868.     Srvmemcpy (g->undo[g->undo_count] + sizeof (g->stack), g->zmp, g->h_dynamic_size);
  869.  
  870.     if (++(g->undo_count) == g->undo_slots)
  871.         g->undo_count = 0;
  872.     if (++(g->undo_valid) > g->undo_slots)
  873.         g->undo_valid = g->undo_slots;
  874.  
  875.     return 1;
  876.  
  877.     }
  878.  
  879. }/* save_undo */
  880.  
  881. /*
  882.  * z_save_undo, save the current Z-machine state for a future undo.
  883.  *
  884.  *    no zargs used
  885.  *
  886.  */
  887.  
  888. void z_save_undo (struct sg *g)
  889. {
  890.  
  891.     store (g, (zword) save_undo (g));
  892.  
  893. }/* z_save_undo */
  894.  
  895. /*
  896.  * z_verify, check the story file integrity.
  897.  *
  898.  *    no zargs used
  899.  *
  900.  */
  901.  
  902. void z_verify (struct sg *g)
  903. {
  904.     zword checksum = 0;
  905.     long i;
  906.     short pfbuffin = 0;
  907.     int lbuffin;
  908.     unsigned char *fbuffin = g->filebuffin;
  909.     short maxfbuffin = sizeof(g->filebuffin) -4;
  910.  
  911.     /* Sum all bytes in story file except header bytes */
  912.  
  913.     SrvSeek (g, g->story_fp, 64, SEEK_SET);
  914.     lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, g->story_fp);
  915.  
  916.     for (i = 64; i < g->story_size; i++)
  917.     {
  918.     checksum += fbuffin[pfbuffin++];
  919.     if(--lbuffin == 0)
  920.        {
  921.        pfbuffin = 0;
  922.        lbuffin = SrvRead (g, fbuffin, 1, maxfbuffin, g->story_fp);
  923.        }
  924.     }
  925.     SrvSeek (g, g->story_fp, g->story_size, SEEK_SET);
  926.  
  927.     /* Branch if the checksums are equal */
  928.  
  929.     branch (g, checksum == g->h_checksum);
  930.  
  931. }/* z_verify */
  932.