Branch data Line data Source code
1 : : /* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */
2 : : /* save.c */
3 : :
4 : : #ifndef MSDOS_SUPPORTED_ANTIQUE
5 : : #include <unistd.h>
6 : : #include <stdlib.h>
7 : : #endif
8 : :
9 : : #include "glob.h"
10 : :
11 : : #ifdef ALLOWING_OLD_SAVEFILES
12 : : /* holds the OLD_ definitions */
13 : : # include "oldsave.h"
14 : : #endif
15 : :
16 : : /*Various functions for doing game saves and restores */
17 : : /*The game remembers various player information, the city level,
18 : : the country level, and the last or current dungeon level */
19 : :
20 : : #if defined(MSDOS_SUPPORTED_ANTIQUE) || defined(AMIGA)
21 : : void do_compression(int, char *);
22 : : #endif
23 : :
24 : : /**************** SAVE FUNCTIONS */
25 : :
26 : : /* Checks to see if save file already exists.
27 : : Checks to see if save file can be opened for write.
28 : : The player, the city level, and the current dungeon level are saved.
29 : : */
30 : :
31 : 5 : int save_game(int compress, char *savestr)
32 : : {
33 : : FILE *fd;
34 : : int slashpos;
35 : : #ifdef SAVE_LEVELS
36 : : int tmpdepth;
37 : : #endif
38 : 5 : int i,writeok=TRUE;
39 : : plv current, save;
40 : : #ifdef COMPRESS_SAVE_FILES
41 : : char temp[200];
42 : : #endif
43 : :
44 : : #ifndef MSDOS_SUPPORTED_ANTIQUE
45 [ - + ]: 5 : if (access(savestr, R_OK) == 0)
46 [ # # ]: 0 : if (access(savestr, W_OK) == 0)
47 : : {
48 : 0 : mprint(" Overwrite old file?");
49 : 0 : writeok = (ynq() == 'y');
50 : : }
51 : : else
52 : : {
53 : 0 : mprint(" File already exists.");
54 : 0 : writeok = FALSE;
55 : : }
56 : : else
57 : : {
58 [ + + ][ + - ]: 35 : for (slashpos = strlen(savestr); slashpos > 0 && savestr[slashpos] != '/';
59 : 30 : slashpos--)
60 : : ;
61 [ - + ]: 5 : if (slashpos > 0)
62 : : {
63 : 0 : savestr[slashpos] = '\0';
64 [ # # ]: 0 : if (access(savestr, W_OK) == -1)
65 : : {
66 : 0 : mprint(" Unable to save to that directory.");
67 : 0 : writeok = FALSE;
68 : : }
69 : 0 : savestr[slashpos] = '/';
70 : : }
71 : : }
72 : : #endif
73 : 5 : change_to_user_perms();
74 [ + - ]: 5 : if (writeok) {
75 : 5 : fd = fopen(savestr,"wb");
76 [ - + ]: 5 : if (fd == NULL) {
77 : 0 : writeok = FALSE;
78 : 0 : mprint(" Error opening file.");
79 : : }
80 : : }
81 [ - + ]: 5 : if (! writeok)
82 : : {
83 : 0 : morewait();
84 : 0 : print2("Save aborted.");
85 : : }
86 : : else {
87 : :
88 : 5 : print1("Saving Game....");
89 : :
90 : : /* write the version number */
91 : 5 : i = VERSION;
92 : 5 : fwrite((char *)&i,sizeof(int),1,fd);
93 : : /* write game id to save file */
94 : :
95 : 5 : writeok &= save_player(fd);
96 : 5 : writeok &= save_country(fd);
97 : : #ifdef SAVE_LEVELS
98 : : tmpdepth = Level->depth;
99 : : City = msdos_changelevel(Level,E_CITY,0);
100 : : #endif
101 : 5 : writeok &= save_level(fd,City);
102 : :
103 [ + - ][ + + ]: 5 : if (Current_Environment == E_CITY || Current_Environment == E_COUNTRYSIDE)
104 : 3 : save = Dungeon;
105 [ - + ]: 2 : else if (Current_Environment == Current_Dungeon)
106 : 0 : save = Dungeon;
107 : : else
108 : 2 : save = Level;
109 [ + + ]: 7 : for (i = 0, current = save; current; current = current->next, i++)
110 : : ;
111 [ - + ]: 5 : if (!fwrite((char *)&i,sizeof(int),1,fd))
112 : 0 : writeok = FALSE;
113 : : #ifdef SAVE_LEVELS
114 : : Level = msdos_changelevel(NULL,Current_Environment,tmpdepth);
115 : : #endif
116 [ + + ]: 7 : for (current = save; current; current = current->next)
117 [ - + ]: 2 : if (current != Level)
118 : 0 : writeok &= save_level(fd,current);
119 [ + + ]: 5 : if (save)
120 : 2 : writeok &= save_level(fd,Level); /* put current level last */
121 : 5 : fclose(fd);
122 [ + - ]: 5 : if (writeok)
123 : 5 : print1("Game Saved.");
124 : : else
125 : 0 : print1("Something didn't work... save aborted.");
126 : : #ifdef COMPRESS_SAVE_FILES
127 : : if (writeok && compress) {
128 : : print2("Compressing Save File....");
129 : : # if defined(MSDOS) || defined(AMIGA)
130 : : do_compression(0, savestr);
131 : : strcpy(temp, savestr);
132 : : strcat(temp, "Z");
133 : : rename(temp, savestr);
134 : : # else
135 : : strcpy(temp,COMPRESSOR);
136 : : strcat(temp," ");
137 : : strcat(temp,savestr);
138 : : system(temp);
139 : : sprintf(temp, "%s.%s", savestr, COMPRESS_EXT);
140 : : unlink(savestr);
141 : : link(temp, savestr);
142 : : unlink(temp); /* renames, but sys-V doesn't have rename()... */
143 : : # endif
144 : : }
145 : : #endif
146 : 5 : morewait();
147 : 5 : clearmsg();
148 : : }
149 : 5 : change_to_game_perms();
150 : 5 : return(writeok);
151 : : }
152 : :
153 : :
154 : :
155 : :
156 : : /* saves game on SIGHUP */
157 : : /* no longer tries to compress, which hangs */
158 : 0 : void signalsave(int ignore)
159 : : {
160 : 0 : change_to_user_perms();
161 : 0 : save_game(FALSE, "Omega.Sav");
162 : : #ifdef COMPRESS_SAVE_FILES
163 : : print1("Signal - Saving uncompressed file 'Omega.Sav'.");
164 : : print2("You can compress it yourself, if you like.");
165 : : #else
166 : 0 : print1("Signal - Saving file 'Omega.Sav'.");
167 : : #endif
168 : 0 : morewait();
169 : 0 : endgraf();
170 : 0 : exit(0);
171 : : }
172 : :
173 : :
174 : : /* also saves some globals like Level->depth... */
175 : :
176 : 5 : int save_player(FILE *fd)
177 : : {
178 : : int i;
179 : 5 : int ok = 1;
180 : : #ifdef NEW_BANK
181 : : bank_account *account;
182 : : #endif
183 : :
184 : : /* Save random global state information */
185 : :
186 : 5 : Player.click = (Tick + 1)%60;
187 : 5 : ok &= (fwrite((char *)&Player,sizeof(Player),1,fd) > 0);
188 : : #ifndef NEW_BANK
189 : : ok &= (fprintf(fd,"%s\n",Password) >= 0);
190 : : #endif
191 : 5 : ok &= (fprintf(fd,"%s\n",Player.name) >= 0);
192 : 5 : ok &= (fwrite((char *)CitySiteList,sizeof(CitySiteList),1,fd) > 0);
193 : 5 : ok &= (fwrite((char *)&GameStatus,sizeof(long),1,fd) > 0);
194 : 5 : ok &= (fwrite((char *)&Current_Environment,sizeof(int),1,fd) > 0);
195 : 5 : ok &= (fwrite((char *)&Last_Environment,sizeof(int),1,fd) > 0);
196 : 5 : ok &= (fwrite((char *)&Current_Dungeon,sizeof(int),1,fd) > 0);
197 : 5 : ok &= (fwrite((char *)&Villagenum,sizeof(int),1,fd) > 0);
198 : 5 : ok &= (fwrite((char *)&Verbosity,sizeof(char),1,fd) > 0);
199 : 5 : ok &= (fwrite((char *)&Time,sizeof(long),1,fd) > 0);
200 : 5 : ok &= (fwrite((char *)&Tick,sizeof(int),1,fd) > 0);
201 : 5 : ok &= (fwrite((char *)&Searchnum,sizeof(int),1,fd) > 0);
202 : 5 : ok &= (fwrite((char *)&Behavior,sizeof(int),1,fd) > 0);
203 : 5 : ok &= (fwrite((char *)&Phase,sizeof(int),1,fd) > 0);
204 : 5 : ok &= (fwrite((char *)&Date,sizeof(int),1,fd) > 0);
205 : 5 : ok &= (fwrite((char *)&Spellsleft,sizeof(int),1,fd) > 0);
206 : 5 : ok &= (fwrite((char *)&SalaryAmount,sizeof(int),1,fd) > 0);
207 : 5 : ok &= (fwrite((char *)&SalaryAccount,sizeof(int),1,fd) > 0);
208 : 5 : ok &= (fwrite((char *)&Studiesleft,sizeof(int),1,fd) > 0);
209 : 5 : ok &= (fwrite((char *)&SymbolUseHour,sizeof(int),1,fd) > 0);
210 : 5 : ok &= (fwrite((char *)&SymbolUseDay,sizeof(int),1,fd) > 0);
211 : 5 : ok &= (fwrite((char *)&ViewHour,sizeof(int),1,fd) > 0);
212 : 5 : ok &= (fwrite((char *)&ViewDay,sizeof(int),1,fd) > 0);
213 : 5 : ok &= (fwrite((char *)&HelmHour,sizeof(int),1,fd) > 0);
214 : 5 : ok &= (fwrite((char *)&HelmDay,sizeof(int),1,fd) > 0);
215 : 5 : ok &= (fwrite((char *)&Constriction,sizeof(int),1,fd) > 0);
216 : 5 : ok &= (fwrite((char *)&Blessing,sizeof(int),1,fd) > 0);
217 : 5 : ok &= (fwrite((char *)&LastDay,sizeof(int),1,fd) > 0);
218 : 5 : ok &= (fwrite((char *)&RitualHour,sizeof(int),1,fd) > 0);
219 : 5 : ok &= (fwrite((char *)&Lawstone,sizeof(int),1,fd) > 0);
220 : 5 : ok &= (fwrite((char *)&Chaostone,sizeof(int),1,fd) > 0);
221 : 5 : ok &= (fwrite((char *)&Mindstone,sizeof(int),1,fd) > 0);
222 : 5 : ok &= (fwrite((char *)&Arena_Opponent,sizeof(int),1,fd) > 0);
223 : 5 : ok &= (fwrite((char *)&Imprisonment,sizeof(int),1,fd) > 0);
224 : 5 : ok &= (fwrite((char *)&Gymcredit,sizeof(long),1,fd) > 0);
225 : :
226 : : #ifdef NEW_BANK
227 : 5 : i = 0;
228 [ + + ]: 45 : for( account = bank; account; account = account->next_account ) i++;
229 : 5 : ok &= ( fwrite( (char *)&i, sizeof( int ), 1, fd ) > 0 );
230 [ + + ]: 45 : for( account = bank; account; account = account->next_account )
231 : : {
232 : 40 : ok &= ( fwrite( (char *)(&(account->player)), sizeof(short), 1, fd ) > 0 );
233 : 40 : ok &= ( fwrite( (char *)(&(account->balance)), sizeof(long), 1, fd ) > 0 );
234 : 40 : ok &= ( fwrite( (char *)(&(account->number)), sizeof(long), 1, fd ) > 0 );
235 : 40 : ok &= ( fprintf( fd, "%s\n", account->password ) >= 0 );
236 : : }
237 : : #else
238 : : ok &= (fwrite((char *)&Balance,sizeof(long),1,fd) > 0);
239 : : #endif
240 : :
241 : 5 : ok &= (fwrite((char *)&StarGemUse,sizeof(int),1,fd) > 0);
242 : 5 : ok &= (fwrite((char *)&HiMagicUse,sizeof(int),1,fd) > 0);
243 : 5 : ok &= (fwrite((char *)&HiMagic,sizeof(int),1,fd) > 0);
244 : 5 : ok &= (fwrite((char *)&FixedPoints,sizeof(long),1,fd) > 0);
245 : 5 : ok &= (fwrite((char *)&LastCountryLocX,sizeof(int),1,fd) > 0);
246 : 5 : ok &= (fwrite((char *)&LastCountryLocY,sizeof(int),1,fd) > 0);
247 : 5 : ok &= (fwrite((char *)&LastTownLocX,sizeof(int),1,fd) > 0);
248 : 5 : ok &= (fwrite((char *)&LastTownLocY,sizeof(int),1,fd) > 0);
249 : 5 : ok &= (fwrite((char *)&Pawndate,sizeof(int),1,fd) > 0);
250 : :
251 : 5 : ok &= (fwrite((char *)Spells,sizeof(Spells),1,fd) > 0);
252 : :
253 : 5 : ok &= (fwrite((char *)&Command_Duration,sizeof(Command_Duration),1,fd) > 0);
254 : 5 : ok &= (fwrite((char *)&Precipitation,sizeof(Precipitation),1,fd) > 0);
255 : 5 : ok &= (fwrite((char *)&Lunarity,sizeof(Lunarity),1,fd) > 0);
256 : 5 : ok &= (fwrite((char *)&ZapHour,sizeof(ZapHour),1,fd) > 0);
257 : 5 : ok &= (fwrite((char *)&RitualRoom,sizeof(RitualRoom),1,fd) > 0);
258 : :
259 : : /* stuff which used to be statics */
260 : 5 : ok &= (fwrite((char *)&twiddle,sizeof(twiddle),1,fd) > 0);
261 : 5 : ok &= (fwrite((char *)&saved,sizeof(saved),1,fd) > 0);
262 : 5 : ok &= (fwrite((char *)&onewithchaos,sizeof(onewithchaos),1,fd) > 0);
263 : 5 : ok &= (fwrite((char *)&club_hinthour,sizeof(club_hinthour),1,fd) > 0);
264 : 5 : ok &= (fwrite((char *)&winnings,sizeof(winnings),1,fd) > 0);
265 : 5 : ok &= (fwrite((char *)&tavern_hinthour,sizeof(tavern_hinthour),1,fd) > 0);
266 : 5 : ok &= (fwrite((char *)scroll_ids,sizeof(scroll_ids),1,fd) > 0);
267 : 5 : ok &= (fwrite((char *)potion_ids,sizeof(potion_ids),1,fd) > 0);
268 : 5 : ok &= (fwrite((char *)stick_ids,sizeof(stick_ids),1,fd) > 0);
269 : 5 : ok &= (fwrite((char *)ring_ids,sizeof(ring_ids),1,fd) > 0);
270 : 5 : ok &= (fwrite((char *)cloak_ids,sizeof(cloak_ids),1,fd) > 0);
271 : 5 : ok &= (fwrite((char *)boot_ids,sizeof(boot_ids),1,fd) > 0);
272 : 5 : ok &= (fwrite((char *)deepest,sizeof(int),E_MAX + 1,fd) > 0);
273 : 5 : ok &= (fwrite((char *)level_seed,sizeof(int),E_MAX + 1,fd) > 0);
274 : :
275 : : /* Save player possessions */
276 : :
277 [ - + ]: 5 : if (Player.possessions[O_READY_HAND] == Player.possessions[O_WEAPON_HAND])
278 : 0 : Player.possessions[O_READY_HAND] = NULL;
279 [ + + ]: 85 : for(i=0;i<MAXITEMS;i++) ok &= save_item(fd,Player.possessions[i]);
280 [ + + ]: 135 : for(i=0;i<MAXPACK;i++) ok &= save_item(fd,Player.pack[i]);
281 [ + + ]: 105 : for(i=0;i<PAWNITEMS;i++) ok &= save_item(fd,Pawnitems[i]);
282 : :
283 : : /* Save items in condo vault */
284 : 5 : ok &= save_itemlist(fd,Condoitems);
285 : : /* Save items in bag of holding */
286 : 5 : ok &= save_itemlist(fd,Bagitems);
287 : :
288 : : /* Save player item knowledge */
289 [ + + ]: 1120 : for (i=0;i<TOTALITEMS;i++)
290 : : {
291 : 1115 : ok &= (fwrite((char *)&(Objects[i].known),sizeof(Objects[i].known),1,fd) > 0);
292 : 1115 : ok &= (fwrite((char *)&(Objects[i].uniqueness),sizeof(Objects[i].uniqueness),1,fd) > 0);
293 : : }
294 : 5 : return ok;
295 : : }
296 : :
297 : :
298 : : /* Save whatever is pointed to by level */
299 : 7 : int save_level(FILE *fd, plv level)
300 : : {
301 : : int i, j, run;
302 : : unsigned long int mask;
303 : 7 : int ok = 1;
304 : 7 : int width = level->level_width;
305 : 7 : int length = level->level_length;
306 : :
307 : 7 : ok &= (fwrite((char *)&level->depth,sizeof(char),1,fd) > 0);
308 : 7 : ok &= (fwrite((char *)&level->numrooms,sizeof(char),1,fd) > 0);
309 : 7 : ok &= (fwrite((char *)&level->tunnelled,sizeof(char),1,fd) > 0);
310 : 7 : ok &= (fwrite((char *)&level->environment,sizeof(int),1,fd) > 0);
311 : 7 : ok &= (fwrite((char *)&level->level_width,sizeof(int),1,fd) > 0);
312 : 7 : ok &= (fwrite((char *)&level->level_length,sizeof(int),1,fd) > 0);
313 [ + + ]: 359 : for (j = 0; j < length; j++)
314 [ + + ]: 22880 : for (i = 0; i < width; i++)
315 [ - + ]: 22528 : if (level->site[i][j].lstatus&CHANGED) { /* this loc has been changed */
316 [ # # ][ # # ]: 0 : for (run = i + 1; run < width && /* find how many in a row */
317 : 0 : level->site[run][j].lstatus&CHANGED; run++)
318 : : ;
319 : 0 : ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
320 : 0 : ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
321 : 0 : ok &= (fwrite((char *)&run,sizeof(int),1,fd) > 0);
322 [ # # ]: 0 : for (; i < run; i++)
323 : 0 : ok &= (fwrite((char *)&level->site[i][j],sizeof(struct location),1,fd) > 0);
324 : : }
325 : 7 : ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
326 : 7 : ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0); /* signify end */
327 : : /* since we don't mark the 'seen' bits as CHANGED, need to save a bitmask */
328 : 7 : run = 8*sizeof(long int);
329 : 7 : mask = 0;
330 [ + + ]: 359 : for (j = 0; j < length; j++)
331 [ + + ]: 22880 : for (i = 0; i < width; i++) {
332 [ + + ]: 22528 : if (run == 0) {
333 : 345 : run = 8*sizeof(long int);
334 : 345 : ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
335 : 345 : mask = 0;
336 : : }
337 : 22528 : mask >>= 1;
338 [ + + ]: 22528 : if (level->site[i][j].lstatus&SEEN)
339 : 21098 : mask |= (1UL<<(sizeof(long int)*8 - 1));
340 : 22528 : run--;
341 : : }
342 [ + - ]: 7 : if (run < 8*sizeof(long int))
343 : 7 : ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
344 : 7 : ok &= save_monsters(fd,level->mlist);
345 [ + + ]: 455 : for(i=0;i<width;i++)
346 [ + + ]: 22976 : for(j=0;j<length;j++)
347 [ + + ]: 22528 : if (level->site[i][j].things) {
348 : 183 : ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
349 : 183 : ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
350 : 183 : ok &= save_itemlist(fd,level->site[i][j].things);
351 : : }
352 : 7 : ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
353 : 7 : ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0); /* signify end */
354 : 7 : return ok;
355 : : }
356 : :
357 : :
358 : 7 : int save_monsters(FILE *fd, pml ml)
359 : : {
360 : : pml tml;
361 : 7 : int nummonsters=0;
362 : 7 : int ok = 1;
363 : : unsigned char type;
364 : :
365 : : /* First count monsters */
366 [ + + ]: 144 : for(tml=ml;tml!=NULL;tml=tml->next)
367 [ + - ]: 137 : if (tml->m->hp > 0) nummonsters++;
368 : :
369 : 7 : ok &= (fwrite((char *)&nummonsters,sizeof(int),1,fd) > 0);
370 : :
371 : : /* Now save monsters */
372 [ + + ]: 144 : for(tml=ml;tml!=NULL;tml=tml->next) {
373 [ + - ]: 137 : if (tml->m->hp > 0) {
374 : 137 : ok &= (fwrite((char *)tml->m,sizeof(montype),1,fd) > 0);
375 [ + + ]: 137 : if (tml->m->id != HISCORE_NPC) {
376 : 132 : type = 0x0;
377 : : /* DAG use pointer compare rather than strcmp; a bit more effecient */
378 [ - + ]: 132 : if (tml->m->monstring != Monsters[tml->m->id].monstring)
379 : 0 : type |= 0x1;
380 [ - + ]: 132 : if (tml->m->corpsestr != Monsters[tml->m->id].corpsestr)
381 : 0 : type |= 0x2;
382 : : /* DAG expect from now (version 9000) on that type will always be */
383 : : /* 0x3 (both) saved, but leave this way as it may not, and this */
384 : : /* preserves save-file compatibility without requiring code changes */
385 : 132 : ok &= (fwrite((char *)&type,sizeof(unsigned char),1,fd) > 0);
386 [ - + ]: 132 : if (type&1)
387 : 0 : ok &= (fprintf(fd,"%s\n",tml->m->monstring) >= 0);
388 [ - + ]: 132 : if (type&2)
389 : 0 : ok &= (fprintf(fd,"%s\n",tml->m->corpsestr) >= 0);
390 : : /* WDT: line moved from here... */
391 : : } /* else it'll be reloaded from the hiscore file on restore */
392 : : /* WDT: to here. This bug fix is Sheldon Simm's suggestion
393 : : * to fix the well-known 'Star Gem' bug; it should allow the
394 : : * possessions of hiscore NPCs to be restored from the savefile.
395 : : * See also the complementary change in restore_monsters. */
396 : 137 : ok &= save_itemlist(fd,tml->m->possessions);
397 : : }
398 : : }
399 : 7 : return ok;
400 : : }
401 : :
402 : :
403 : : /* Save o unless it's null, then save a special flag byte instead */
404 : : /* Use other values of flag byte to indicate what strings are saved */
405 : 674 : int save_item(FILE *fd, pob o)
406 : : {
407 : 674 : int ok = 1;
408 : : unsigned char type;
409 : :
410 [ + + ]: 674 : if (o == NULL) {
411 : 182 : type = 0xff;
412 : 182 : ok &= (fwrite((char *)&type,sizeof(type),1,fd) > 0);
413 : : }
414 : : else {
415 : 492 : type = 0;
416 : : /* DAG these strcmp could be just pointer comparisons, more efficient. */
417 [ + + ]: 492 : if (strcmp(o->objstr, Objects[o->id].objstr))
418 : 7 : type |= 1;
419 [ + + ]: 492 : if (strcmp(o->truename, Objects[o->id].truename))
420 : 7 : type |= 2;
421 [ + + ]: 492 : if (strcmp(o->cursestr, Objects[o->id].cursestr))
422 : 7 : type |= 4;
423 : : /* DAG following is true for corpses */
424 [ + + ][ + - ]: 492 : if ( (type && o->cursestr == o->objstr) && (o->cursestr == o->truename) )
[ + - ]
425 : 7 : type |=8;
426 : 492 : ok &= (fwrite((char *)&type,sizeof(type),1,fd) > 0);
427 : 492 : ok &= (fwrite((char *)o,sizeof(objtype),1,fd) > 0);
428 [ + + ]: 492 : if (type&1)
429 : 7 : ok &= (fprintf(fd,"%s\n",o->objstr) >= 0);
430 [ + + ]: 492 : if (type&2)
431 : 7 : ok &= (fprintf(fd,"%s\n",o->truename) >= 0);
432 [ + + ]: 492 : if (type&4)
433 : 7 : ok &= (fprintf(fd,"%s\n",o->cursestr) >= 0);
434 : : }
435 : 674 : return ok;
436 : : }
437 : :
438 : 330 : int save_itemlist(FILE *fd, pol ol)
439 : : {
440 : 330 : int numitems = 0;
441 : : pol tol;
442 : 330 : int ok = 1;
443 : :
444 [ + + ]: 694 : for(tol=ol;tol!=NULL;tol=tol->next) numitems++;
445 : 330 : ok &= (fwrite((char *)&numitems,sizeof(int),1,fd) > 0);
446 [ + + ]: 694 : for(tol=ol;tol!=NULL;tol=tol->next)
447 : 364 : ok &= save_item(fd,tol->thing);
448 : 330 : return ok;
449 : : }
450 : :
451 : :
452 : 5 : int save_country(FILE *fd)
453 : : {
454 : : int i, j;
455 : 5 : int ok = 1;
456 : : int run;
457 : : unsigned long int mask;
458 : :
459 [ + + ]: 325 : for (i = 0; i < COUNTRY_WIDTH; i++)
460 [ + + ]: 20800 : for (j = 0; j < COUNTRY_LENGTH; j++)
461 [ - + ]: 20480 : if (c_statusp(i, j, CHANGED)) {
462 : 0 : ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
463 : 0 : ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
464 : 0 : ok &= (fwrite((char *)&Country[i][j],sizeof(struct terrain),1,fd) > 0);
465 : : }
466 : 5 : ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
467 : 5 : ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
468 : : /* since we don't mark the 'seen' bits as CHANGED, need to save a bitmask */
469 : 5 : run = 8*sizeof(long int);
470 : 5 : mask = 0;
471 [ + + ]: 325 : for (i = 0; i < COUNTRY_WIDTH; i++)
472 [ + + ]: 20800 : for (j = 0; j < COUNTRY_LENGTH; j++) {
473 [ + + ]: 20480 : if (run == 0) {
474 : 315 : run = 8*sizeof(long int);
475 : 315 : ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
476 : 315 : mask = 0;
477 : : }
478 : 20480 : mask >>= 1;
479 [ + + ]: 20480 : if (c_statusp(i, j, SEEN))
480 : 420 : mask |= (1UL<<(sizeof(long int)*8 - 1));
481 : 20480 : run--;
482 : : }
483 [ + - ]: 5 : if (run < 8*sizeof(long int))
484 : 5 : ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
485 : 5 : return ok;
486 : : }
487 : :
488 : :
489 : : /* returns TRUE if the given version can be restored by this version */
490 : 0 : int ok_outdated(int version)
491 : : {
492 : : /* currently all backwards compatibility is broken, so fail ok_outdated()
493 : : until we actually re-install some type of backwards compatibility. DAG */
494 : :
495 : 0 : return FALSE;
496 : :
497 : : #if 0
498 : : switch (version) {
499 : : case 80:
500 : : print1("Converting version 0.80 savefile to current.");
501 : : morewait();
502 : : return TRUE;
503 : : break;
504 : : case 81:
505 : : print1("Converting version 0.81 savefile to current.");
506 : : morewait();
507 : : return TRUE;
508 : : break;
509 : : case 90:
510 : : print1("Converting version 0.90 savefile to current.");
511 : : morewait();
512 : : return TRUE;
513 : : break;
514 : : case 91:
515 : : /* version 91 is same as version 9000 right now */
516 : : return TRUE;
517 : : break;
518 : : case 9000:
519 : : /* DAG - 9000 is the re-numbered 90, for the new version numbering system. */
520 : : print1("Converting version 0.90 savefile to current.");
521 : : morewait();
522 : : return TRUE;
523 : : break;
524 : : default:
525 : : return FALSE;
526 : : break;
527 : : }
528 : : #endif /* #if 0 */
529 : : }
530 : :
531 : :
532 : : /* read player data, city level, dungeon level,
533 : : check on validity of save file, etc.
534 : : return TRUE if game restored, FALSE otherwise */
535 : :
536 : 10 : int restore_game(char *savestr)
537 : : {
538 : : int i,version;
539 : : #ifdef COMPRESS_SAVE_FILES
540 : : char temp[200];
541 : : #endif
542 : : FILE *fd;
543 : :
544 : : #ifndef MSDOS_SUPPORTED_ANTIQUE
545 [ + + ]: 10 : if (access(savestr, F_OK|R_OK|W_OK) == -1) /* access uses real uid */
546 : : {
547 : 2 : print1("Unable to access save file: ");
548 : 2 : nprint1(savestr);
549 : 2 : morewait();
550 : 2 : return FALSE;
551 : : }
552 : : #endif
553 : 8 : change_to_user_perms();
554 : : #ifdef COMPRESS_SAVE_FILES
555 : : fd = fopen(savestr,"rb");
556 : : if (fd == NULL) {
557 : : print1("Error restoring game -- aborted.");
558 : : print2("File name was: ");
559 : : nprint2(savestr);
560 : : morewait();
561 : : change_to_game_perms();
562 : : return(FALSE);
563 : : }
564 : : fread((char *)&version,sizeof(int),1,fd);
565 : : fclose(fd);
566 : : if (VERSION != version && !ok_outdated(version)) {
567 : : print1("Uncompressing Save File....");
568 : : #if defined(MSDOS) || defined(AMIGA)
569 : : strcpy(temp, savestr);
570 : : strcat(temp, "Z");
571 : : rename(savestr, temp);
572 : : do_compression(1, savestr);
573 : : #else
574 : : sprintf(temp, "%s.%s", savestr, COMPRESS_EXT);
575 : : unlink(temp);
576 : : link(savestr, temp);
577 : : unlink(savestr); /* renames, but sys-V doesn't have rename()... */
578 : : strcpy(temp,UNCOMPRESSOR);
579 : : strcat(temp," ");
580 : : strcat(temp,savestr);
581 : : system(temp);
582 : : #endif
583 : : print2("Save file uncompressed.");
584 : : morewait();
585 : : }
586 : : #endif
587 : :
588 : 8 : fd = fopen(savestr,"rb");
589 : :
590 [ - + ]: 8 : if (fd == NULL) {
591 : 0 : print1("Error restoring game -- aborted.");
592 : 0 : print2("File name was: ");
593 : 0 : nprint2(savestr);
594 : 0 : morewait();
595 : 0 : change_to_game_perms();
596 : 0 : return(FALSE);
597 : : }
598 : : else {
599 : 8 : print1("Restoring...");
600 : :
601 : 8 : fread((char *)&version,sizeof(int),1,fd);
602 : :
603 [ - + ][ # # ]: 8 : if (VERSION != version && !ok_outdated(version)) {
604 : 0 : change_to_game_perms();
605 : 0 : fclose(fd);
606 : 0 : clearmsg();
607 : 0 : mprint(" Sorry, I can't restore an outdated save file!");
608 : 0 : mprint(" savefile is version ");
609 : 0 : mnumprint(version/10000);
610 : 0 : nprint2(".");
611 : 0 : mnumprint( (version/100)%100);
612 : 0 : morewait();
613 : 0 : return(FALSE);
614 : : }
615 : 8 : restore_player(fd, version);
616 : 8 : restore_country(fd, version);
617 : 8 : restore_level(fd, version); /* the city level */
618 : 8 : fread((char *)&i,sizeof(int),1,fd);
619 [ + + ]: 14 : for (; i > 0; i--) {
620 : : #ifdef SAVE_LEVELS
621 : : msdos_changelevel(Level,0,-1);
622 : : #endif
623 : 6 : restore_level(fd, version);
624 [ - + ]: 6 : if (Level->environment == Current_Dungeon) {
625 : 0 : Level->next = Dungeon;
626 : 0 : Dungeon = Level;
627 : : }
628 [ - + ]: 6 : if (Current_Environment == E_CITY)
629 : 0 : Level = City;
630 : : }
631 : :
632 : 8 : fclose(fd);
633 : 8 : print3("Restoration complete.");
634 : 8 : ScreenOffset = -1000; /* to force a redraw */
635 : 8 : setgamestatus(SKIP_MONSTERS);
636 : 8 : change_to_game_perms();
637 : 10 : return(TRUE);
638 : : }
639 : : }
640 : :
641 : 8 : void restore_player(FILE *fd, int version)
642 : : {
643 : : int i;
644 : : #ifdef NEW_BANK
645 : : int num_accounts;
646 : : bank_account *account;
647 : : char pw_buf[ 64 ];
648 : : #endif
649 : :
650 : 8 : fread((char *)&Player,sizeof(Player),1,fd);
651 : : #ifndef NEW_BANK
652 : : filescanstring(fd,Password);
653 : : #endif
654 : 8 : filescanstring(fd,Player.name);
655 : : #ifdef ALLOWING_OLD_SAVEFILES
656 : : if( version < 91 ) /* DAG */
657 : : fread((char *)CitySiteList,(3*OLD_NUMCITYSITES*sizeof(int)),1,fd);
658 : : else
659 : : #endif
660 : 8 : fread((char *)CitySiteList,sizeof(CitySiteList),1,fd);
661 : 8 : fread((char *)&GameStatus,sizeof(long),1,fd);
662 : 8 : fread((char *)&Current_Environment,sizeof(int),1,fd);
663 : 8 : fread((char *)&Last_Environment,sizeof(int),1,fd);
664 : 8 : fread((char *)&Current_Dungeon,sizeof(int),1,fd);
665 : 8 : fread((char *)&Villagenum,sizeof(int),1,fd);
666 [ - - - - : 8 : switch(Current_Dungeon) {
- - + ]
667 : 0 : case E_ASTRAL: MaxDungeonLevels = ASTRALLEVELS; break;
668 : 0 : case E_SEWERS: MaxDungeonLevels = SEWERLEVELS; break;
669 : 0 : case E_CASTLE: MaxDungeonLevels = CASTLELEVELS; break;
670 : 0 : case E_CAVES: MaxDungeonLevels = CAVELEVELS; break;
671 : 0 : case E_VOLCANO: MaxDungeonLevels = VOLCANOLEVELS; break;
672 : 0 : case E_PALACE: MaxDungeonLevels = PALACELEVELS; break;
673 : : }
674 : 8 : fread((char *)&Verbosity,sizeof(char),1,fd);
675 : 8 : fread((char *)&Time,sizeof(long),1,fd);
676 : 8 : fread((char *)&Tick,sizeof(int),1,fd);
677 : 8 : fread((char *)&Searchnum,sizeof(int),1,fd);
678 : 8 : fread((char *)&Behavior,sizeof(int),1,fd);
679 : 8 : fread((char *)&Phase,sizeof(int),1,fd);
680 : 8 : fread((char *)&Date,sizeof(int),1,fd);
681 : 8 : fread((char *)&Spellsleft,sizeof(int),1,fd);
682 : 8 : fread((char *)&SalaryAmount,sizeof(int),1,fd);
683 : 8 : fread((char *)&SalaryAccount,sizeof(int),1,fd);
684 : 8 : fread((char *)&Studiesleft,sizeof(int),1,fd);
685 : 8 : fread((char *)&SymbolUseHour,sizeof(int),1,fd);
686 : 8 : fread((char *)&SymbolUseDay,sizeof(int),1,fd);
687 : 8 : fread((char *)&ViewHour,sizeof(int),1,fd);
688 : 8 : fread((char *)&ViewDay,sizeof(int),1,fd);
689 : 8 : fread((char *)&HelmHour,sizeof(int),1,fd);
690 : 8 : fread((char *)&HelmDay,sizeof(int),1,fd);
691 : 8 : fread((char *)&Constriction,sizeof(int),1,fd);
692 : 8 : fread((char *)&Blessing,sizeof(int),1,fd);
693 : 8 : fread((char *)&LastDay,sizeof(int),1,fd);
694 : 8 : fread((char *)&RitualHour,sizeof(int),1,fd);
695 : 8 : fread((char *)&Lawstone,sizeof(int),1,fd);
696 : 8 : fread((char *)&Chaostone,sizeof(int),1,fd);
697 : 8 : fread((char *)&Mindstone,sizeof(int),1,fd);
698 : 8 : fread((char *)&Arena_Opponent,sizeof(int),1,fd);
699 : 8 : fread((char *)&Imprisonment,sizeof(int),1,fd);
700 : 8 : fread((char *)&Gymcredit,sizeof(long),1,fd);
701 : :
702 : : #ifdef NEW_BANK
703 : 8 : fread( (char *)&num_accounts, sizeof( int ), 1, fd );
704 [ + + ]: 72 : for( i = 0; i < num_accounts; i++ )
705 : : {
706 : 64 : account = (bank_account *)checkmalloc( sizeof( bank_account ));
707 : 64 : fread( (char *)(&(account->player)), sizeof(short), 1, fd );
708 : 64 : fread( (char *)(&(account->balance)), sizeof(long), 1, fd );
709 : 64 : fread( (char *)(&(account->number)), sizeof(long), 1, fd );
710 : 64 : filescanstring( fd, pw_buf );
711 : 64 : account->password = salloc( pw_buf );
712 : 64 : account->next_account = bank;
713 : 64 : bank = account;
714 : : }
715 : : #else
716 : : fread((char *)&Balance,sizeof(long),1,fd);
717 : : #endif
718 : :
719 : 8 : fread((char *)&StarGemUse,sizeof(int),1,fd);
720 : 8 : fread((char *)&HiMagicUse,sizeof(int),1,fd);
721 : 8 : fread((char *)&HiMagic,sizeof(int),1,fd);
722 : 8 : fread((char *)&FixedPoints,sizeof(long),1,fd);
723 : 8 : fread((char *)&LastCountryLocX,sizeof(int),1,fd);
724 : 8 : fread((char *)&LastCountryLocY,sizeof(int),1,fd);
725 : 8 : fread((char *)&LastTownLocX,sizeof(int),1,fd);
726 : 8 : fread((char *)&LastTownLocY,sizeof(int),1,fd);
727 : 8 : fread((char *)&Pawndate,sizeof(int),1,fd);
728 : :
729 : 8 : fread((char *)Spells,sizeof(Spells),1,fd);
730 : :
731 : 8 : fread((char *)&Command_Duration,sizeof(Command_Duration),1,fd);
732 : 8 : fread((char *)&Precipitation,sizeof(Precipitation),1,fd);
733 : 8 : fread((char *)&Lunarity,sizeof(Lunarity),1,fd);
734 : 8 : fread((char *)&ZapHour,sizeof(ZapHour),1,fd);
735 : 8 : fread((char *)&RitualRoom,sizeof(RitualRoom),1,fd);
736 : :
737 : : /* stuff which used to be statics */
738 : 8 : fread((char *)&twiddle,sizeof(twiddle),1,fd);
739 : 8 : fread((char *)&saved,sizeof(saved),1,fd);
740 : 8 : fread((char *)&onewithchaos,sizeof(onewithchaos),1,fd);
741 : 8 : fread((char *)&club_hinthour,sizeof(club_hinthour),1,fd);
742 : 8 : fread((char *)&winnings,sizeof(winnings),1,fd);
743 : 8 : fread((char *)&tavern_hinthour,sizeof(tavern_hinthour),1,fd);
744 : 8 : fread((char *)scroll_ids,sizeof(scroll_ids),1,fd);
745 : 8 : fread((char *)potion_ids,sizeof(potion_ids),1,fd);
746 : 8 : fread((char *)stick_ids,sizeof(stick_ids),1,fd);
747 : 8 : fread((char *)ring_ids,sizeof(ring_ids),1,fd);
748 : 8 : fread((char *)cloak_ids,sizeof(cloak_ids),1,fd);
749 : 8 : fread((char *)boot_ids,sizeof(boot_ids),1,fd);
750 : 8 : fread((char *)deepest,sizeof(int),E_MAX + 1,fd);
751 : 8 : fread((char *)level_seed,sizeof(int),E_MAX + 1,fd);
752 : :
753 : : /* Set up the strings for the id's */
754 : 8 : inititem(FALSE);
755 : :
756 [ + + ]: 136 : for(i=0;i<MAXITEMS;i++)
757 : 128 : Player.possessions[i] = restore_item(fd, version);
758 : :
759 [ + - ]: 16 : if (!Player.possessions[O_READY_HAND] && Player.possessions[O_WEAPON_HAND] &&
[ + - - + ]
760 : 8 : twohandedp(Player.possessions[O_WEAPON_HAND]->id))
761 : 0 : Player.possessions[O_READY_HAND] = Player.possessions[O_WEAPON_HAND];
762 : :
763 [ + + ]: 216 : for(i=0;i<MAXPACK;i++)
764 : 208 : Player.pack[i] = restore_item(fd, version);
765 [ + + ]: 168 : for(i=0;i<PAWNITEMS;i++)
766 : 160 : Pawnitems[i] = restore_item(fd, version);
767 : 8 : Condoitems = restore_itemlist(fd, version);
768 : : /* Added bag of holding in 9001, so need to restore list. */
769 [ - + ]: 8 : if (version < 9001)
770 : 0 : Bagitems = NULL;
771 : : else
772 : 8 : Bagitems = restore_itemlist(fd, version);
773 : :
774 [ + + ]: 1792 : for (i=0;i<TOTALITEMS;i++)
775 : : {
776 : : /* Add bag of holding, skip its position in the 2 arrays */
777 [ - + ][ # # ]: 1784 : if ( (version < 9001) && (i == 215) )
778 : 0 : i = 216;
779 : 1784 : fread((char *)&(Objects[i].known),sizeof(Objects[i].known),1,fd);
780 [ + - ]: 1784 : if (version != 80)
781 : 1784 : fread((char *)&(Objects[i].uniqueness),sizeof(Objects[i].uniqueness),1,fd);
782 : : }
783 : 8 : }
784 : :
785 : :
786 : :
787 : : /* Restore an item, the first byte tells us if it's NULL, and what strings */
788 : : /* have been saved as different from the typical */
789 : 1210 : pob restore_item(FILE *fd, int version)
790 : : {
791 : : char tempstr[80];
792 : : unsigned char type;
793 : 1210 : pob obj = NULL;
794 : :
795 : 1210 : fread((char *)&type,sizeof(type),1,fd);
796 [ + + ]: 1210 : if (type != 0xff) {
797 : 913 : obj = ((pob) checkmalloc(sizeof(objtype)));
798 : 913 : fread((char *)obj,sizeof(objtype),1,fd);
799 : :
800 : : /* DAG -- added object 215 (bag of holding) in 9001; have to renumber */
801 [ - + ]: 913 : if (version < 9001 )
802 [ # # ]: 0 : if (obj->id >= 215)
803 : 0 : obj->id++;
804 : :
805 [ + + ]: 913 : if (type&8)
806 : : {
807 : : /* DAG case to handle corpses */
808 [ + - ]: 9 : if (type&1)
809 : 9 : filescanstring(fd,tempstr);
810 [ + - ]: 9 : if (type&2)
811 : 9 : filescanstring(fd,tempstr);
812 [ + - ]: 9 : if (type&4)
813 : 9 : filescanstring(fd,tempstr);
814 : 9 : obj->objstr = obj->truename = obj->cursestr = salloc(tempstr);
815 : : }
816 : : else
817 : : {
818 [ - + ]: 904 : if (type&1) {
819 : 0 : filescanstring(fd,tempstr);
820 : 0 : obj->objstr = salloc(tempstr);
821 : : }
822 : : else
823 : 904 : obj->objstr = Objects[obj->id].objstr;
824 [ - + ]: 904 : if (type&2) {
825 : 0 : filescanstring(fd,tempstr);
826 : 0 : obj->truename = salloc(tempstr);
827 : : }
828 : : else
829 : 904 : obj->truename = Objects[obj->id].truename;
830 [ - + ]: 904 : if (type&4) {
831 : 0 : filescanstring(fd,tempstr);
832 : 0 : obj->cursestr = salloc(tempstr);
833 : : }
834 : : else
835 : 904 : obj->cursestr = Objects[obj->id].cursestr;
836 : : }
837 : : }
838 : 1210 : return obj;
839 : : }
840 : :
841 : 584 : pol restore_itemlist(FILE *fd, int version)
842 : : {
843 : 584 : pol ol=NULL,cur=NULL,new=NULL;
844 : 584 : int i,numitems,firsttime=TRUE;
845 : 584 : fread((char *)&numitems,sizeof(int),1,fd);
846 [ + + ]: 1298 : for(i=0;i<numitems;i++) {
847 : 714 : new = ((pol) checkmalloc(sizeof(oltype)));
848 : 714 : new->thing = restore_item(fd, version);
849 : 714 : new->next = NULL;
850 [ + + ]: 714 : if (firsttime==TRUE) {
851 : 466 : ol = cur = new;
852 : 466 : firsttime = FALSE;
853 : : }
854 : : else {
855 : 248 : cur->next = new;
856 : 248 : cur = new;
857 : : }
858 : : }
859 : 584 : return(ol);
860 : : }
861 : :
862 : : /* converts old location function ids to current ones. DAG */
863 : 0 : void fix_p_locf( unsigned char *p_locf, int version )
864 : : /* char *p_locf is pointer to single char, not a string */
865 : : {
866 : : #ifdef ALLOWING_OLD_SAVEFILES
867 : : if( version < 91 )
868 : : {
869 : : switch( *p_locf )
870 : : {
871 : : case OLD_L_NO_OP : *p_locf = L_NO_OP; break;
872 : : case OLD_L_LIFT : *p_locf = L_LIFT; break;
873 : : case OLD_L_BALANCESTONE : *p_locf = L_BALANCESTONE; break;
874 : : case OLD_L_FIRE : *p_locf = L_FIRE; break;
875 : : case OLD_L_WHIRLWIND : *p_locf = L_WHIRLWIND; break;
876 : : case OLD_L_VOIDSTONE : *p_locf = L_VOIDSTONE; break;
877 : : case OLD_L_WARNING : *p_locf = L_WARNING; break;
878 : : case OLD_L_ARENA_EXIT : *p_locf = L_ARENA_EXIT; break;
879 : : case OLD_L_HOUSE_EXIT : *p_locf = L_HOUSE_EXIT; break;
880 : : case OLD_L_SAFE : *p_locf = L_SAFE; break;
881 : : case OLD_L_CHARITY : *p_locf = L_CHARITY; break;
882 : : case OLD_L_ARMORER : *p_locf = L_ARMORER; break;
883 : : case OLD_L_CLUB : *p_locf = L_CLUB; break;
884 : : case OLD_L_GYM : *p_locf = L_GYM; break;
885 : : case OLD_L_THIEVES_GUILD : *p_locf = L_THIEVES_GUILD; break;
886 : : case OLD_L_COLLEGE : *p_locf = L_COLLEGE; break;
887 : : case OLD_L_HEALER : *p_locf = L_HEALER; break;
888 : : case OLD_L_CASINO : *p_locf = L_CASINO; break;
889 : : case OLD_L_TAVERN : *p_locf = L_TAVERN; break;
890 : : case OLD_L_MERC_GUILD : *p_locf = L_MERC_GUILD; break;
891 : : case OLD_L_ALCHEMIST : *p_locf = L_ALCHEMIST; break;
892 : : case OLD_L_SORCERORS : *p_locf = L_SORCERORS; break;
893 : : case OLD_L_CASTLE : *p_locf = L_CASTLE; break;
894 : : case OLD_L_ARENA : *p_locf = L_ARENA; break;
895 : : case OLD_L_DPW : *p_locf = L_DPW; break;
896 : : case OLD_L_LIBRARY : *p_locf = L_LIBRARY; break;
897 : : case OLD_L_PAWN_SHOP : *p_locf = L_PAWN_SHOP; break;
898 : : case OLD_L_BANK : *p_locf = L_BANK; break;
899 : : case OLD_L_CONDO : *p_locf = L_CONDO; break;
900 : : case OLD_L_ORACLE : *p_locf = L_ORACLE; break;
901 : : case OLD_L_ORDER : *p_locf = L_ORDER; break;
902 : : case OLD_L_DINER : *p_locf = L_DINER; break;
903 : : case OLD_L_COMMANDANT : *p_locf = L_COMMANDANT; break;
904 : : case OLD_L_CRAP : *p_locf = L_CRAP; break;
905 : : case OLD_L_TEMPLE : *p_locf = L_TEMPLE; break;
906 : : case OLD_L_COUNTRYSIDE : *p_locf = L_COUNTRYSIDE; break;
907 : : case OLD_L_BROTHEL : *p_locf = L_BROTHEL; break;
908 : : case OLD_L_JAIL : *p_locf = L_JAIL; break;
909 : : case OLD_L_TEMPLE_WARNING : *p_locf = L_TEMPLE_WARNING; break;
910 : : case OLD_L_LAWSTONE : *p_locf = L_LAWSTONE; break;
911 : : case OLD_L_CHAOSTONE : *p_locf = L_CHAOSTONE; break;
912 : : case OLD_L_EARTH_STATION : *p_locf = L_EARTH_STATION; break;
913 : : case OLD_L_FIRE_STATION : *p_locf = L_FIRE_STATION; break;
914 : : case OLD_L_WATER_STATION : *p_locf = L_WATER_STATION; break;
915 : : case OLD_L_AIR_STATION : *p_locf = L_AIR_STATION; break;
916 : : case OLD_L_VOID_STATION : *p_locf = L_VOID_STATION; break;
917 : : case OLD_L_VOID : *p_locf = L_VOID; break;
918 : : case OLD_L_VOICE1 : *p_locf = L_VOICE1; break;
919 : : case OLD_L_VOICE2 : *p_locf = L_VOICE2; break;
920 : : case OLD_L_VOICE3 : *p_locf = L_VOICE3; break;
921 : : case OLD_L_SACRIFICESTONE : *p_locf = L_SACRIFICESTONE; break;
922 : : case OLD_L_TOME1 : *p_locf = L_TOME1; break;
923 : : case OLD_L_TOME2 : *p_locf = L_TOME2; break;
924 : : case OLD_L_ENTER_CIRCLE : *p_locf = L_ENTER_CIRCLE; break;
925 : : case OLD_L_CIRCLE_LIBRARY : *p_locf = L_CIRCLE_LIBRARY; break;
926 : : case OLD_L_DRUID : *p_locf = L_DRUID; break;
927 : : case OLD_L_ALTAR : *p_locf = L_ALTAR; break;
928 : : case OLD_L_GARDEN : *p_locf = L_GARDEN; break;
929 : : case OLD_L_ADEPT : *p_locf = L_ADEPT; break;
930 : : case OLD_L_SEWER : *p_locf = L_SEWER; break;
931 : : case OLD_L_OMEGA : *p_locf = L_OMEGA; break;
932 : : case OLD_L_CARTOGRAPHER : *p_locf = L_CARTOGRAPHER; break;
933 : : case OLD_L_STABLES : *p_locf = L_STABLES; break;
934 : : case OLD_L_COMMONS : *p_locf = L_COMMONS; break;
935 : : case OLD_L_GRANARY : *p_locf = L_GRANARY; break;
936 : : case OLD_L_MAZE : *p_locf = L_MAZE; break;
937 : : case OLD_L_HOVEL : *p_locf = L_HOVEL; break;
938 : : case OLD_L_HOUSE : *p_locf = L_HOUSE; break;
939 : : case OLD_L_MANSION : *p_locf = L_MANSION; break;
940 : : case OLD_L_OCCUPIED_HOUSE : *p_locf = L_OCCUPIED_HOUSE; break;
941 : : case OLD_L_TACTICAL_EXIT : *p_locf = L_TACTICAL_EXIT; break;
942 : : case OLD_L_VAULT : *p_locf = L_VAULT; break;
943 : : case OLD_L_CEMETARY : *p_locf = L_CEMETARY; break;
944 : : case OLD_L_THRONE : *p_locf = L_THRONE; break;
945 : : case OLD_L_ESCALATOR : *p_locf = L_ESCALATOR; break;
946 : : case OLD_L_ENTER_COURT : *p_locf = L_ENTER_COURT; break;
947 : : case OLD_L_TRIFID : *p_locf = L_TRIFID; break;
948 : : case OLD_L_FINAL_ABYSS : *p_locf = L_FINAL_ABYSS; break;
949 : : case OLD_L_RAISE_PORTCULLIS : *p_locf = L_RAISE_PORTCULLIS; break;
950 : : case OLD_L_MINDSTONE : *p_locf = L_MINDSTONE; break;
951 : : case OLD_L_CHAOS : *p_locf = L_CHAOS; break;
952 : : case OLD_L_WATER : *p_locf = L_WATER; break;
953 : : case OLD_L_LAVA : *p_locf = L_LAVA; break;
954 : : case OLD_L_MAGIC_POOL : *p_locf = L_MAGIC_POOL; break;
955 : : case OLD_L_PORTCULLIS_TRAP : *p_locf = L_PORTCULLIS_TRAP; break;
956 : : case OLD_L_DROP_EVERY_PORTCULLIS : *p_locf = L_DROP_EVERY_PORTCULLIS; break;
957 : : case OLD_L_PORTCULLIS : *p_locf = L_PORTCULLIS; break;
958 : : case OLD_L_TRAP_DART : *p_locf = L_TRAP_DART; break;
959 : : case OLD_L_TRAP_PIT : *p_locf = L_TRAP_PIT; break;
960 : : case OLD_L_TRAP_DOOR : *p_locf = L_TRAP_DOOR; break;
961 : : case OLD_L_TRAP_SNARE : *p_locf = L_TRAP_SNARE; break;
962 : : case OLD_L_TRAP_BLADE : *p_locf = L_TRAP_BLADE; break;
963 : : case OLD_L_TRAP_FIRE : *p_locf = L_TRAP_FIRE; break;
964 : : case OLD_L_TRAP_TELEPORT : *p_locf = L_TRAP_TELEPORT; break;
965 : : case OLD_L_TRAP_DISINTEGRATE : *p_locf = L_TRAP_DISINTEGRATE; break;
966 : : case OLD_L_TRAP_SLEEP_GAS : *p_locf = L_TRAP_SLEEP_GAS; break;
967 : : case OLD_L_TRAP_ACID : *p_locf = L_TRAP_ACID; break;
968 : : case OLD_L_TRAP_MANADRAIN : *p_locf = L_TRAP_MANADRAIN; break;
969 : : case OLD_L_TRAP_ABYSS : *p_locf = L_TRAP_ABYSS; break;
970 : : case OLD_L_TRAP_SIREN : *p_locf = L_TRAP_SIREN; break;
971 : : case OLD_L_STATUE_WAKE : *p_locf = L_STATUE_WAKE; break;
972 : : case OLD_L_STATUE_RANDOM : *p_locf = L_STATUE_RANDOM; break;
973 : : case OLD_L_HEDGE : *p_locf = L_HEDGE; break;
974 : : case OLD_L_RUBBLE : *p_locf = L_RUBBLE; break;
975 : : case OLD_L_ABYSS : *p_locf = L_ABYSS; break;
976 : : default: *p_locf = L_NO_OP; break; /* shouldn't happen */
977 : : }
978 : : }
979 : : #endif
980 : 0 : }
981 : :
982 : 14 : void restore_level(FILE *fd, int version)
983 : : {
984 : : int i, j, run;
985 : : unsigned long int mask;
986 : : int temp_env;
987 : : int length, width;
988 : :
989 : 14 : Level = (plv) checkmalloc(sizeof(levtype));
990 : 14 : clear_level(Level);
991 : 14 : fread((char *)&Level->depth,sizeof(char),1,fd);
992 : 14 : fread((char *)&Level->numrooms,sizeof(char),1,fd);
993 : 14 : fread((char *)&Level->tunnelled,sizeof(char),1,fd);
994 : 14 : fread((char *)&Level->environment,sizeof(int),1,fd);
995 : 14 : fread((char *)&Level->level_width,sizeof(int),1,fd);
996 : 14 : fread((char *)&Level->level_length,sizeof(int),1,fd);
997 : :
998 : 14 : width = Level->level_width;
999 : 14 : length = Level->level_length;
1000 : 14 : Level->generated = TRUE;
1001 : 14 : temp_env = Current_Environment;
1002 : 14 : Current_Environment = Level->environment;
1003 [ - + + - : 14 : switch(Level->environment) {
- - - - -
- - - - -
- - - ]
1004 : : case E_COUNTRYSIDE:
1005 : 0 : load_country();
1006 : 0 : break;
1007 : : case E_CITY:
1008 : 8 : load_city(FALSE);
1009 : 8 : break;
1010 : : case E_VILLAGE:
1011 : 6 : load_village(Country[LastCountryLocX][LastCountryLocY].aux, FALSE);
1012 : 6 : break;
1013 : : case E_CAVES:
1014 : 0 : initrand(Current_Environment, Level->depth);
1015 [ # # ][ # # ]: 0 : if ((random_range(4)==0) && (Level->depth < MaxDungeonLevels))
1016 : 0 : room_level();
1017 : 0 : else cavern_level();
1018 : 0 : break;
1019 : : case E_SEWERS:
1020 : 0 : initrand(Current_Environment, Level->depth);
1021 [ # # ][ # # ]: 0 : if ((random_range(4)==0) && (Level->depth < MaxDungeonLevels))
1022 : 0 : room_level();
1023 : 0 : else sewer_level();
1024 : 0 : break;
1025 : : case E_CASTLE:
1026 : 0 : initrand(Current_Environment, Level->depth);
1027 : 0 : room_level();
1028 : 0 : break;
1029 : : case E_PALACE:
1030 : 0 : initrand(Current_Environment, Level->depth);
1031 : 0 : room_level(); /* TODO PGM */
1032 : 0 : break;
1033 : : case E_ASTRAL:
1034 : 0 : initrand(Current_Environment, Level->depth);
1035 : 0 : maze_level();
1036 : 0 : break;
1037 : : case E_VOLCANO:
1038 : 0 : initrand(Current_Environment, Level->depth);
1039 [ # # # # ]: 0 : switch(random_range(3)) {
1040 : 0 : case 0: cavern_level(); break;
1041 : 0 : case 1: room_level(); break;
1042 : 0 : case 2: maze_level(); break;
1043 : : }
1044 : 0 : break;
1045 : : case E_HOVEL:
1046 : : case E_MANSION:
1047 : : case E_HOUSE:
1048 : 0 : load_house(Level->environment, FALSE);
1049 : 0 : break;
1050 : : case E_DLAIR:
1051 : 0 : load_dlair(gamestatusp(KILLED_DRAGONLORD), FALSE);
1052 : 0 : break;
1053 : : case E_STARPEAK:
1054 : 0 : load_speak(gamestatusp(KILLED_LAWBRINGER), FALSE);
1055 : 0 : break;
1056 : : case E_MAGIC_ISLE:
1057 : 0 : load_misle(gamestatusp(KILLED_EATER), FALSE);
1058 : 0 : break;
1059 : : case E_TEMPLE:
1060 : 0 : load_temple(Country[LastCountryLocX][LastCountryLocY].aux, FALSE);
1061 : 0 : break;
1062 : : case E_CIRCLE:
1063 : 0 : load_circle(FALSE);
1064 : 0 : break;
1065 : : case E_COURT:
1066 : 0 : load_court(FALSE);
1067 : 0 : break;
1068 : 0 : default: print3("This dungeon not implemented!"); break;
1069 : : }
1070 [ - + ]: 14 : if (Level->depth > 0) { /* dungeon... */
1071 : 0 : install_traps();
1072 : 0 : install_specials();
1073 : 0 : make_stairs(-1);
1074 : 0 : make_stairs(-1);
1075 : 0 : initrand(E_RESTORE, 0);
1076 : : }
1077 : 14 : Current_Environment = temp_env;
1078 : 14 : fread((char *)&i,sizeof(int),1,fd);
1079 : 14 : fread((char *)&j,sizeof(int),1,fd);
1080 [ - + ][ # # ]: 14 : while ((j < length) && (i < width)) {
1081 : 0 : fread((char *)&run,sizeof(int),1,fd);
1082 [ # # ]: 0 : for (; i < run; i++) {
1083 : 0 : fread((char *)&Level->site[i][j],sizeof(struct location),1,fd);
1084 : 0 : fix_p_locf( &(Level->site[i][j].p_locf), version ); /* DAG */
1085 : 0 : Level->site[i][j].creature = NULL;
1086 : 0 : Level->site[i][j].things = NULL;
1087 : : }
1088 : 0 : fread((char *)&i,sizeof(int),1,fd);
1089 : 0 : fread((char *)&j,sizeof(int),1,fd);
1090 : : }
1091 : 14 : run = 0;
1092 [ + + ]: 622 : for (j = 0; j < length; j++)
1093 [ + + ]: 39520 : for (i = 0; i < width; i++) {
1094 [ + + ]: 38912 : if (run == 0) {
1095 : 608 : run = 8*sizeof(long int);
1096 : 608 : fread((char *)&mask,sizeof(long int),1,fd);
1097 : : }
1098 [ + + ]: 38912 : if (mask&1)
1099 : 36624 : lset(i, j, SEEN);
1100 : 38912 : mask >>= 1;
1101 : 38912 : run--;
1102 : : }
1103 : 14 : restore_monsters(fd,Level, version);
1104 : 14 : fread((char *)&i,sizeof(int),1,fd);
1105 : 14 : fread((char *)&j,sizeof(int),1,fd);
1106 [ + + ][ + - ]: 318 : while (j < length && i < width) {
1107 : 304 : Level->site[i][j].things = restore_itemlist(fd, version);
1108 : 304 : fread((char *)&i,sizeof(int),1,fd);
1109 : 304 : fread((char *)&j,sizeof(int),1,fd);
1110 : : }
1111 : 14 : }
1112 : :
1113 : :
1114 : 8 : void restore_hiscore_npc(pmt npc, int npcid)
1115 : : {
1116 : : int level, behavior;
1117 : : long status;
1118 : :
1119 [ - - - - : 8 : switch(npcid) {
- - - - -
- + - - ]
1120 : : case 0:
1121 : 0 : strcpy(Str2,Hiscorer);
1122 : 0 : level = Hilevel;
1123 : 0 : behavior = Hibehavior;
1124 : 0 : break;
1125 : : case 1: case 2: case 3: case 4: case 5: case 6:
1126 : 0 : strcpy(Str2,Priest[npcid]);
1127 : 0 : level = Priestlevel[npcid];
1128 : 0 : behavior = Priestbehavior[npcid];
1129 : 0 : break;
1130 : : case 7:
1131 : 0 : strcpy(Str2,Shadowlord);
1132 : 0 : level = Shadowlordlevel;
1133 : 0 : behavior = Shadowlordbehavior;
1134 : 0 : break;
1135 : : case 8:
1136 : 0 : strcpy(Str2,Commandant);
1137 : 0 : level = Commandantlevel;
1138 : 0 : behavior = Commandantbehavior;
1139 : 0 : break;
1140 : : case 9:
1141 : 0 : strcpy(Str2,Archmage);
1142 : 0 : level = Archmagelevel;
1143 : 0 : behavior = Archmagebehavior;
1144 : 0 : break;
1145 : : case 10:
1146 : 0 : strcpy(Str2,Prime);
1147 : 0 : level = Primelevel;
1148 : 0 : behavior = Primebehavior;
1149 : 0 : break;
1150 : : case 11:
1151 : 0 : strcpy(Str2,Champion);
1152 : 0 : level = Championlevel;
1153 : 0 : behavior = Championbehavior;
1154 : 0 : break;
1155 : : case 12:
1156 : 0 : strcpy(Str2,Duke);
1157 : 0 : level = Dukelevel;
1158 : 0 : behavior = Dukebehavior;
1159 : 0 : break;
1160 : : case 13:
1161 : 0 : strcpy(Str2,Chaoslord);
1162 : 0 : level = Chaoslordlevel;
1163 : 0 : behavior = Chaoslordbehavior;
1164 : 0 : break;
1165 : : case 14:
1166 : 0 : strcpy(Str2,Lawlord);
1167 : 0 : level = Lawlordlevel;
1168 : 0 : behavior = Lawlordbehavior;
1169 : 0 : break;
1170 : : case 15:
1171 : 8 : strcpy(Str2,Justiciar);
1172 : 8 : level = Justiciarlevel;
1173 : 8 : behavior = Justiciarbehavior;
1174 : 8 : break;
1175 : : case 16:
1176 : 0 : strcpy(Str2,Grandmaster);
1177 : 0 : level = Grandmasterlevel;
1178 : 0 : behavior = Grandmasterbehavior;
1179 : 0 : break;
1180 : : default:
1181 : : /* bomb on error */
1182 : 0 : level = behavior = 0;
1183 : 0 : assert(FALSE);
1184 : : }
1185 : 8 : npc->monstring = salloc(Str2);
1186 : 8 : strcpy(Str1,"The body of ");
1187 : 8 : strcat(Str1,Str2);
1188 : 8 : npc->corpsestr = salloc(Str1);
1189 : 8 : m_status_set( npc, ALLOC );
1190 [ + - ]: 8 : if (!m_statusp(npc, HOSTILE)) {
1191 : 8 : status = npc->status;
1192 : 8 : determine_npc_behavior(npc,level,behavior);
1193 : 8 : npc->status = status;
1194 : : }
1195 : 8 : }
1196 : :
1197 : :
1198 : 14 : void restore_monsters(FILE *fd, plv level, int version)
1199 : : {
1200 : 14 : pml ml=NULL;
1201 : : int i,nummonsters;
1202 : : char tempstr[80];
1203 : : int temp_x, temp_y;
1204 : : unsigned char type;
1205 : :
1206 : 14 : level->mlist = NULL;
1207 : :
1208 : 14 : fread((char *)&nummonsters,sizeof(int),1,fd);
1209 : :
1210 [ + + ]: 278 : for(i=0;i<nummonsters;i++) {
1211 : 264 : ml = ((pml) checkmalloc(sizeof(mltype)));
1212 : 264 : ml->m = ((pmt) checkmalloc(sizeof(montype)));
1213 : 264 : ml->next = NULL;
1214 : 264 : fread((char *)ml->m,sizeof(montype),1,fd);
1215 [ + + ]: 264 : if (ml->m->id == HISCORE_NPC)
1216 [ - + ]: 8 : if (version == 80) {
1217 : 0 : temp_x = ml->m->x;
1218 : 0 : temp_y = ml->m->y;
1219 : 0 : make_hiscore_npc(ml->m, ml->m->aux2);
1220 : 0 : ml->m->x = temp_x;
1221 : 0 : ml->m->y = temp_y;
1222 : : }
1223 : : else
1224 : 8 : restore_hiscore_npc(ml->m, ml->m->aux2);
1225 : : else {
1226 : 256 : fread((char *)&type,sizeof(unsigned char),1,fd);
1227 [ - + ]: 256 : if ( type )
1228 : : {
1229 : : /* DAG enforce that if either one of monstring or corpsestr are */
1230 : : /* alloced, both are */
1231 : 0 : m_status_set( ml->m, ALLOC );
1232 [ # # ]: 0 : if (type&1) {
1233 : 0 : filescanstring(fd,tempstr);
1234 : 0 : ml->m->monstring = salloc(tempstr);
1235 : : }
1236 : : else
1237 : 0 : ml->m->monstring = salloc( Monsters[ml->m->id].monstring );
1238 : :
1239 [ # # ]: 0 : if (type&2) {
1240 : 0 : filescanstring(fd,tempstr);
1241 : 0 : ml->m->corpsestr = salloc(tempstr);
1242 : : }
1243 : : else
1244 : 0 : ml->m->corpsestr = salloc( Monsters[ml->m->id].corpsestr );
1245 : : }
1246 : : else
1247 : : {
1248 : 256 : ml->m->corpsestr = Monsters[ml->m->id].corpsestr;
1249 : 256 : ml->m->monstring = Monsters[ml->m->id].monstring;
1250 : : }
1251 : : /* WDT: As suggested by Sheldon Simms, I'm moving this line... */
1252 [ - + ]: 256 : if ( version <= 80 )
1253 : 0 : ml->m->possessions = restore_itemlist(fd,version);
1254 : 256 : ml->m->meleestr = Monsters[ml->m->id].meleestr;
1255 : : }
1256 : : /* WDT: ...to here, so that all creatures will have their stuff
1257 : : * restored to them. Savefile versioning added by David Given. */
1258 [ + - ]: 264 : if ( version > 80 )
1259 : 264 : ml->m->possessions = restore_itemlist(fd,version);
1260 : 264 : level->site[ml->m->x][ml->m->y].creature = ml->m;
1261 : 264 : ml->next = level->mlist;
1262 : 264 : level->mlist = ml;
1263 : : }
1264 : 14 : }
1265 : :
1266 : :
1267 : 8 : void restore_country(FILE *fd, int version)
1268 : : {
1269 : : int i, j;
1270 : : int run;
1271 : : unsigned long int mask;
1272 : :
1273 : 8 : load_country();
1274 : 8 : fread((char *)&i,sizeof(int),1,fd);
1275 : 8 : fread((char *)&j,sizeof(int),1,fd);
1276 [ - + ][ # # ]: 8 : while (i < COUNTRY_WIDTH && j < COUNTRY_LENGTH) {
1277 : 0 : fread((char *)&Country[i][j],sizeof(struct terrain),1,fd);
1278 : 0 : fread((char *)&i,sizeof(int),1,fd);
1279 : 0 : fread((char *)&j,sizeof(int),1,fd);
1280 : : }
1281 : 8 : run = 0;
1282 [ + + ]: 520 : for (i = 0; i < COUNTRY_WIDTH; i++)
1283 [ + + ]: 33280 : for (j = 0; j < COUNTRY_LENGTH; j++) {
1284 [ + + ]: 32768 : if (run == 0) {
1285 : 512 : run = 8*sizeof(long int);
1286 : 512 : fread((char *)&mask,sizeof(long int),1,fd);
1287 : : }
1288 [ + + ]: 32768 : if (mask&1)
1289 : 433 : c_set(i, j, SEEN);
1290 : 32768 : mask >>= 1;
1291 : 32768 : run--;
1292 : : }
1293 : 8 : }
|