Update interpreters to latest Garglk codebase
[projects/chimara/chimara.git] / interpreters / nitfol / op_save.c
1 /*  Nitfol - z-machine interpreter using Glk for output.
2     Copyright (C) 1999  Evin Robertson
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18     The author can be reached at nitfol@deja.com
19 */
20 #include "nitfol.h"
21
22 BOOL savegame(void)
23 {
24   BOOL result;
25   strid_t file;
26
27   if(automap_unexplore())
28     return FALSE;
29
30   file = n_file_prompt(fileusage_SavedGame | fileusage_BinaryMode,
31                        filemode_Write);
32   if(!file)
33     return FALSE;
34
35   result = savequetzal(file);
36
37   glk_stream_close(file, NULL);
38
39   return result;
40 }
41
42
43 void op_save1(void)
44 {
45   if(!savegame()) {
46     mop_skip_branch();
47   } else {
48     mop_take_branch();
49   }
50 }
51
52
53 void op_save4(void)
54 {
55   if(!savegame()) {
56     mop_store_result(0);
57   } else {
58     mop_store_result(1);
59   }
60 }
61
62
63 void op_save5(void)
64 {
65   unsigned i;
66   char filename[256];
67   unsigned length;
68   strid_t file = NULL;
69   offset end;
70   switch(numoperands) {
71   case 0:
72     op_save4();
73     return;
74   case 1: 
75     n_show_error(E_INSTR, "call save with bad number of operands", numoperands);
76     mop_store_result(0);
77     return;
78   case 2:
79     file = n_file_prompt(fileusage_Data | fileusage_BinaryMode,
80                          filemode_Write);
81     break;
82   default:
83     length = LOBYTE(operand[2]);
84     if(length > 13)
85       n_show_port(E_INSTR, "save with filename > 13 characters", length);
86     for(i = 0; i < length; i++)
87       filename[i] = glk_char_to_upper(LOBYTE(operand[2] + 1 + i));
88     filename[length] = 0;
89     file = n_file_name(fileusage_Data | fileusage_BinaryMode,
90                        filemode_Write, filename);
91     break;
92   }
93   if(!file) {
94     mop_store_result(0);
95     return;
96   }
97   end = ((offset) operand[0]) + operand[1];
98   if(end > 65535 || end > total_size) {
99     n_show_error(E_MEMORY, "attempt to save data out of range", end);
100     mop_store_result(0);
101     return;
102   }
103
104   w_glk_put_buffer_stream(file, (char *) z_memory + operand[0], operand[1]);
105   glk_stream_close(file, NULL);
106
107   mop_store_result(1);
108 }
109
110
111 BOOL restoregame(void)
112 {
113   BOOL result;
114   strid_t file;
115
116   if(automap_unexplore())
117     return FALSE;
118
119   file = n_file_prompt(fileusage_SavedGame | fileusage_BinaryMode,
120                        filemode_Read);
121   if(!file)
122     return FALSE;
123
124   result = restorequetzal(file);
125
126   glk_stream_close(file, NULL);
127
128   if(result) {
129     glui32 wid, hei;
130     z_find_size(&wid, &hei);
131     set_header(wid, hei);
132   }
133
134   return result;
135 }
136
137
138 void op_restore1(void)
139 {
140   if(!restoregame())
141     mop_skip_branch();
142   else
143     mop_take_branch();
144 }
145
146 void op_restore4(void)
147 {
148   if(!restoregame())
149     mop_store_result(0);
150   else
151     mop_store_result(2);
152 }
153
154
155 void op_restore5(void)
156 {
157   int i;
158   char filename[256];
159   int length;
160   strid_t file;
161   offset end;
162   switch(numoperands) {
163   case 0:
164     op_restore4();
165     return;
166   case 1: 
167     n_show_error(E_INSTR, "call restore with bad number of operands", numoperands);
168     mop_store_result(0);
169     return;
170   case 2:
171     file = n_file_prompt(fileusage_Data | fileusage_BinaryMode,
172                          filemode_Read);
173     break;
174   default:
175     length = LOBYTE(operand[2]);
176     if(length > 13)
177       n_show_port(E_INSTR, "save with filename > 13 characters", length);
178     for(i = 0; i < length; i++)
179       filename[i] = glk_char_to_upper(LOBYTE(operand[2] + 1 + i));
180     filename[length] = 0;
181     file = n_file_name(fileusage_Data | fileusage_BinaryMode,
182                        filemode_Read, filename);
183   }
184   if(!file) {
185     mop_store_result(0);
186     return;
187   }
188   end = ((offset) operand[0]) + operand[1];
189   if(end > 65535 || end > dynamic_size) {
190     n_show_error(E_MEMORY, "attempt to restore data out of range", end);
191     mop_store_result(0);
192     return;
193   }
194
195   length = glk_get_buffer_stream(file, (char *) z_memory + operand[0],
196                                  operand[1]);
197   glk_stream_close(file, NULL);
198   mop_store_result(length);
199 }
200
201
202 void op_restart(void)
203 {
204   if(automap_unexplore())
205     return;
206   z_init(current_zfile);
207 }
208
209
210 void op_save_undo(void)
211 {
212   if(saveundo(TRUE)) {
213     mop_store_result(1);
214   } else {
215     mop_store_result(0);
216   }
217 }
218
219
220 void op_restore_undo(void)
221 {
222   if(!restoreundo())
223     mop_store_result(0);
224 }
225
226
227 void op_quit(void)
228 {
229   if(automap_unexplore())
230     return;
231   z_close();
232   /* puts("@quit\n"); */
233   glk_exit();
234 }
235
236
237 BOOL check_game_for_save(strid_t gamefile, zword release, const char serial[6],
238                          zword checksum)
239 {
240   int i;
241   unsigned char header[64];
242   glk_stream_set_position(gamefile, 0, seekmode_Start);
243   if(glk_get_buffer_stream(gamefile, (char *) header, 64) != 64)
244     return FALSE;
245   if(header[HD_ZVERSION] == 0 || header[HD_ZVERSION] > 8)
246     return FALSE;
247   if(MSBdecodeZ(header + HD_RELNUM) != release)
248     return FALSE;
249   if(MSBdecodeZ(header + HD_CHECKSUM) != checksum)
250     return FALSE;
251   for(i = 0; i < 6; i++) {
252     if(header[HD_SERNUM + i] != serial[i])
253       return FALSE;
254   }
255   return TRUE;
256 }