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 /*Various functions for doing game saves and restores */
12 /*The game remembers various player information, the city level,
13 the country level, and the last or current dungeon level */
14 
15 #if defined(MSDOS_SUPPORTED_ANTIQUE) || defined(AMIGA)
16 void do_compression(int, char *);
17 #endif
18 
19 /**************** SAVE FUNCTIONS */
20 
21 /* Checks to see if save file already exists.
22    Checks to see if save file can be opened for write.
23    The player, the city level, and the current dungeon level are saved.
24 */
25 
save_game(compress,savestr)26 int save_game(compress,savestr)
27 int compress;
28 char *savestr;
29 {
30   FILE *fd;
31   int slashpos;
32 #ifdef SAVE_LEVELS
33   int tmpdepth;
34 #endif
35   int i,writeok=TRUE;
36   plv current, save;
37   char temp[200];
38 
39 #ifndef MSDOS_SUPPORTED_ANTIQUE
40   if (access(savestr, R_OK) == 0)
41     if (access(savestr, W_OK) == 0)
42     {
43 	mprint(" Overwrite old file?");
44 	writeok = (ynq() == 'y');
45     }
46     else
47     {
48 	mprint(" File already exists.");
49 	writeok = FALSE;
50     }
51   else
52   {
53     for (slashpos = strlen(savestr); slashpos > 0 && savestr[slashpos] != '/';
54 	slashpos--)
55 	;
56     if (slashpos > 0)
57     {
58 	savestr[slashpos] = '\0';
59 	if (access(savestr, W_OK) == -1)
60 	{
61 	    mprint(" Unable to save to that directory.");
62 	    writeok = FALSE;
63 	}
64 	savestr[slashpos] = '/';
65     }
66   }
67 #endif
68   change_to_user_perms();
69   if (writeok) {
70     fd = fopen(savestr,"wb");
71     if (fd == NULL) {
72       writeok = FALSE;
73       mprint(" Error opening file.");
74     }
75   }
76   if (! writeok)
77   {
78     morewait();
79     print2("Save aborted.");
80   }
81   else {
82 
83     print1("Saving Game....");
84 
85     /* write the version number */
86     i = VERSION;
87     fwrite((char *)&i,sizeof(int),1,fd);
88     /* write game id to save file */
89 
90     writeok &= save_player(fd);
91     writeok &= save_country(fd);
92 #ifdef SAVE_LEVELS
93     tmpdepth = Level->depth;
94     City = msdos_changelevel(Level,E_CITY,0);
95 #endif
96     writeok &= save_level(fd,City);
97 
98     if (Current_Environment == E_CITY || Current_Environment == E_COUNTRYSIDE)
99       save = Dungeon;
100     else if (Current_Environment == Current_Dungeon)
101       save = Dungeon;
102     else
103       save = Level;
104     for (i = 0, current = save; current; current = current->next, i++)
105       ;
106     if (!fwrite((char *)&i,sizeof(int),1,fd))
107       writeok = FALSE;
108 #ifdef SAVE_LEVELS
109     Level = msdos_changelevel(NULL,Current_Environment,tmpdepth);
110 #endif
111     for (current = save; current; current = current->next)
112       if (current != Level)
113 	writeok &= save_level(fd,current);
114     if (save)
115       writeok &= save_level(fd,Level);	/* put current level last */
116     fclose(fd);
117     if (writeok)
118 	print1("Game Saved.");
119     else
120 	print1("Something didn't work... save aborted.");
121 #ifdef COMPRESS_SAVE_FILES
122     if (writeok && compress) {
123       print2("Compressing Save File....");
124 # if defined(MSDOS) || defined(AMIGA)
125       do_compression(0, savestr);
126       strcpy(temp, savestr);
127       strcat(temp, "Z");
128       rename(temp, savestr);
129 # else
130       strcpy(temp,COMPRESSOR);
131       strcat(temp," ");
132       strcat(temp,savestr);
133       system(temp);
134       sprintf(temp, "%s.%s", savestr, COMPRESS_EXT);
135       unlink(savestr);
136       link(temp, savestr);
137       unlink(temp);	/* renames, but sys-V doesn't have rename()... */
138 # endif
139     }
140 #endif
141     morewait();
142     clearmsg();
143   }
144   change_to_game_perms();
145   return(writeok);
146 }
147 
148 
149 
150 
151 /* saves game on SIGHUP */
152 /* no longer tries to compress, which hangs */
signalsave()153 void signalsave()
154 {
155   change_to_user_perms();
156   save_game(FALSE, "Omega.Sav");
157 #ifdef COMPRESS_SAVE_FILES
158   print1("Signal - Saving uncompressed file 'Omega.Sav'.");
159   print2("You can compress it yourself, if you like.");
160 #else
161   print1("Signal - Saving file 'Omega.Sav'.");
162 #endif
163   morewait();
164   endgraf();
165   exit(0);
166 }
167 
168 
169 /* also saves some globals like Level->depth... */
170 
save_player(fd)171 int save_player(fd)
172 FILE *fd;
173 {
174   int i;
175   int ok = 1;
176 
177   /* Save random global state information */
178 
179   Player.click = (Tick + 1)%60;
180   ok &= (fwrite((char *)&Player,sizeof(Player),1,fd) > 0);
181   ok &= (fprintf(fd,"%s\n",Password) >= 0);
182   ok &= (fprintf(fd,"%s\n",Player.name) >= 0);
183   ok &= (fwrite((char *)CitySiteList,sizeof(CitySiteList),1,fd) > 0);
184   ok &= (fwrite((char *)&GameStatus,sizeof(long),1,fd) > 0);
185   ok &= (fwrite((char *)&Current_Environment,sizeof(int),1,fd) > 0);
186   ok &= (fwrite((char *)&Last_Environment,sizeof(int),1,fd) > 0);
187   ok &= (fwrite((char *)&Current_Dungeon,sizeof(int),1,fd) > 0);
188   ok &= (fwrite((char *)&Villagenum,sizeof(int),1,fd) > 0);
189   ok &= (fwrite((char *)&Verbosity,sizeof(char),1,fd) > 0);
190   ok &= (fwrite((char *)&Time,sizeof(long),1,fd) > 0);
191   ok &= (fwrite((char *)&Tick,sizeof(int),1,fd) > 0);
192   ok &= (fwrite((char *)&Searchnum,sizeof(int),1,fd) > 0);
193   ok &= (fwrite((char *)&Behavior,sizeof(int),1,fd) > 0);
194   ok &= (fwrite((char *)&Phase,sizeof(int),1,fd) > 0);
195   ok &= (fwrite((char *)&Date,sizeof(int),1,fd) > 0);
196   ok &= (fwrite((char *)&Spellsleft,sizeof(int),1,fd) > 0);
197   ok &= (fwrite((char *)&SymbolUseHour,sizeof(int),1,fd) > 0);
198   ok &= (fwrite((char *)&ViewHour,sizeof(int),1,fd) > 0);
199   ok &= (fwrite((char *)&HelmHour,sizeof(int),1,fd) > 0);
200   ok &= (fwrite((char *)&Constriction,sizeof(int),1,fd) > 0);
201   ok &= (fwrite((char *)&Blessing,sizeof(int),1,fd) > 0);
202   ok &= (fwrite((char *)&LastDay,sizeof(int),1,fd) > 0);
203   ok &= (fwrite((char *)&RitualHour,sizeof(int),1,fd) > 0);
204   ok &= (fwrite((char *)&Lawstone,sizeof(int),1,fd) > 0);
205   ok &= (fwrite((char *)&Chaostone,sizeof(int),1,fd) > 0);
206   ok &= (fwrite((char *)&Mindstone,sizeof(int),1,fd) > 0);
207   ok &= (fwrite((char *)&Arena_Opponent,sizeof(int),1,fd) > 0);
208   ok &= (fwrite((char *)&Imprisonment,sizeof(int),1,fd) > 0);
209   ok &= (fwrite((char *)&Gymcredit,sizeof(long),1,fd) > 0);
210   ok &= (fwrite((char *)&Balance,sizeof(long),1,fd) > 0);
211   ok &= (fwrite((char *)&StarGemUse,sizeof(int),1,fd) > 0);
212   ok &= (fwrite((char *)&HiMagicUse,sizeof(int),1,fd) > 0);
213   ok &= (fwrite((char *)&HiMagic,sizeof(int),1,fd) > 0);
214   ok &= (fwrite((char *)&FixedPoints,sizeof(long),1,fd) > 0);
215   ok &= (fwrite((char *)&LastCountryLocX,sizeof(int),1,fd) > 0);
216   ok &= (fwrite((char *)&LastCountryLocY,sizeof(int),1,fd) > 0);
217   ok &= (fwrite((char *)&LastTownLocX,sizeof(int),1,fd) > 0);
218   ok &= (fwrite((char *)&LastTownLocY,sizeof(int),1,fd) > 0);
219   ok &= (fwrite((char *)&Pawndate,sizeof(int),1,fd) > 0);
220 
221   ok &= (fwrite((char *)Spells,sizeof(Spells),1,fd) > 0);
222 
223   ok &= (fwrite((char *)&Command_Duration,sizeof(Command_Duration),1,fd) > 0);
224   ok &= (fwrite((char *)&Precipitation,sizeof(Precipitation),1,fd) > 0);
225   ok &= (fwrite((char *)&Lunarity,sizeof(Lunarity),1,fd) > 0);
226   ok &= (fwrite((char *)&ZapHour,sizeof(ZapHour),1,fd) > 0);
227   ok &= (fwrite((char *)&RitualRoom,sizeof(RitualRoom),1,fd) > 0);
228 
229   /* stuff which used to be statics */
230   ok &= (fwrite((char *)&twiddle,sizeof(twiddle),1,fd) > 0);
231   ok &= (fwrite((char *)&saved,sizeof(saved),1,fd) > 0);
232   ok &= (fwrite((char *)&onewithchaos,sizeof(onewithchaos),1,fd) > 0);
233   ok &= (fwrite((char *)&club_hinthour,sizeof(club_hinthour),1,fd) > 0);
234   ok &= (fwrite((char *)&winnings,sizeof(winnings),1,fd) > 0);
235   ok &= (fwrite((char *)&tavern_hinthour,sizeof(tavern_hinthour),1,fd) > 0);
236   ok &= (fwrite((char *)scroll_ids,sizeof(scroll_ids),1,fd) > 0);
237   ok &= (fwrite((char *)potion_ids,sizeof(potion_ids),1,fd) > 0);
238   ok &= (fwrite((char *)stick_ids,sizeof(stick_ids),1,fd) > 0);
239   ok &= (fwrite((char *)ring_ids,sizeof(ring_ids),1,fd) > 0);
240   ok &= (fwrite((char *)cloak_ids,sizeof(cloak_ids),1,fd) > 0);
241   ok &= (fwrite((char *)boot_ids,sizeof(boot_ids),1,fd) > 0);
242   ok &= (fwrite((char *)deepest,sizeof(int),E_MAX + 1,fd) > 0);
243   ok &= (fwrite((char *)level_seed,sizeof(int),E_MAX + 1,fd) > 0);
244 
245   /* Save player possessions */
246 
247   if (Player.possessions[O_READY_HAND] == Player.possessions[O_WEAPON_HAND])
248     Player.possessions[O_READY_HAND] = NULL;
249   for(i=0;i<MAXITEMS;i++) ok &= save_item(fd,Player.possessions[i]);
250   for(i=0;i<MAXPACK;i++) ok &= save_item(fd,Player.pack[i]);
251   for(i=0;i<PAWNITEMS;i++) ok &= save_item(fd,Pawnitems[i]);
252 
253   /* Save items in condo vault */
254   ok &= save_itemlist(fd,Condoitems);
255 
256   /* Save player item knowledge */
257   for (i=0;i<TOTALITEMS;i++)
258   {
259     ok &= (fwrite((char *)&(Objects[i].known),sizeof(Objects[i].known),1,fd) > 0);
260     ok &= (fwrite((char *)&(Objects[i].uniqueness),sizeof(Objects[i].uniqueness),1,fd) > 0);
261   }
262   return ok;
263 }
264 
265 
266 /* Save whatever is pointed to by level */
save_level(fd,level)267 int save_level(fd,level)
268 FILE *fd;
269 plv level;
270 {
271   int i, j, run;
272   unsigned long int mask;
273   int ok = 1;
274 
275   ok &= (fwrite((char *)&level->depth,sizeof(char),1,fd) > 0);
276   ok &= (fwrite((char *)&level->numrooms,sizeof(char),1,fd) > 0);
277   ok &= (fwrite((char *)&level->tunnelled,sizeof(char),1,fd) > 0);
278   ok &= (fwrite((char *)&level->environment,sizeof(int),1,fd) > 0);
279   for (j = 0; j < MAXLENGTH; j++)
280     for (i = 0; i < MAXWIDTH; i++)
281       if (level->site[i][j].lstatus&CHANGED) {	/* this loc has been changed */
282 	for (run = i + 1; run < MAXWIDTH &&	/* find how many in a row */
283 	  level->site[run][j].lstatus&CHANGED; run++)
284 	  ;
285 	ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
286 	ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
287 	ok &= (fwrite((char *)&run,sizeof(int),1,fd) > 0);
288 	for (; i < run; i++)
289 	  ok &= (fwrite((char *)&level->site[i][j],sizeof(struct location),1,fd) > 0);
290       }
291   ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
292   ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);	/* signify end */
293   /* since we don't mark the 'seen' bits as CHANGED, need to save a bitmask */
294   run = 8*sizeof(long int);
295   mask = 0;
296   for (j = 0; j < MAXLENGTH; j++)
297     for (i = 0; i < MAXWIDTH; i++) {
298       if (run == 0) {
299 	run = 8*sizeof(long int);
300 	ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
301 	mask = 0;
302       }
303       mask >>= 1;
304       if (level->site[i][j].lstatus&SEEN)
305 	mask |= (1<<(sizeof(long int)*8 - 1));
306       run--;
307     }
308   if (run < 8*sizeof(long int))
309     ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
310   ok &= save_monsters(fd,level->mlist);
311   for(i=0;i<MAXWIDTH;i++)
312     for(j=0;j<MAXLENGTH;j++)
313       if (level->site[i][j].things) {
314 	ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
315 	ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
316 	ok &= save_itemlist(fd,level->site[i][j].things);
317       }
318   ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
319   ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);	/* signify end */
320   return ok;
321 }
322 
323 
save_monsters(fd,ml)324 int save_monsters(fd,ml)
325 FILE *fd;
326 pml ml;
327 {
328   pml tml;
329   int nummonsters=0;
330   int ok = 1;
331   unsigned char type;
332 
333   /* First count monsters */
334   for(tml=ml;tml!=NULL;tml=tml->next)
335     if (tml->m->hp > 0) nummonsters++;
336 
337   ok &= (fwrite((char *)&nummonsters,sizeof(int),1,fd) > 0);
338 
339   /* Now save monsters */
340   for(tml=ml;tml!=NULL;tml=tml->next) {
341     if (tml->m->hp > 0) {
342       ok &= (fwrite((char *)tml->m,sizeof(montype),1,fd) > 0);
343       if (tml->m->id != HISCORE_NPC) {
344 	type = 0x0;
345 	if (strcmp(tml->m->monstring, Monsters[tml->m->id].monstring))
346 	  type |= 0x1;
347 	if (strcmp(tml->m->corpsestr, Monsters[tml->m->id].corpsestr))
348 	  type |= 0x2;
349 	ok &= (fwrite((char *)&type,sizeof(unsigned char),1,fd) > 0);
350 	if (type&1)
351 	  ok &= (fprintf(fd,"%s\n",tml->m->monstring) >= 0);
352 	if (type&2)
353 	  ok &= (fprintf(fd,"%s\n",tml->m->corpsestr) >= 0);
354         /* WDT: line moved from here... */
355       }	/* else it'll be reloaded from the hiscore file on restore */
356       /* WDT: to here.  This bug fix is Sheldon Simm's suggestion
357        * to fix the well-known 'Star Gem' bug; it should allow the
358        * possessions of hiscore NPCs to be restored from the savefile.
359        * See also the complementary change in restore_monsters. */
360       ok &= save_itemlist(fd,tml->m->possessions);
361     }
362   }
363   return ok;
364 }
365 
366 
367 /* Save o unless it's null, then save a special flag byte instead */
368 /* Use other values of flag byte to indicate what strings are saved */
save_item(fd,o)369 int save_item(fd,o)
370 FILE *fd;
371 pob o;
372 {
373   int ok = 1;
374   unsigned char type;
375 
376   if (o == NULL) {
377     type = 0xff;
378     ok &= (fwrite((char *)&type,sizeof(type),1,fd) > 0);
379   }
380   else {
381     type = 0;
382     if (strcmp(o->objstr, Objects[o->id].objstr))
383       type |= 1;
384     if (strcmp(o->truename, Objects[o->id].truename))
385       type |= 2;
386     if (strcmp(o->cursestr, Objects[o->id].cursestr))
387       type |= 4;
388     ok &= (fwrite((char *)&type,sizeof(type),1,fd) > 0);
389     ok &= (fwrite((char *)o,sizeof(objtype),1,fd) > 0);
390     if (type&1)
391       ok &= (fprintf(fd,"%s\n",o->objstr) >= 0);
392     if (type&2)
393       ok &= (fprintf(fd,"%s\n",o->truename) >= 0);
394     if (type&4)
395       ok &= (fprintf(fd,"%s\n",o->cursestr) >= 0);
396   }
397   return ok;
398 }
399 
save_itemlist(fd,ol)400 int save_itemlist(fd,ol)
401 FILE *fd;
402 pol ol;
403 {
404   int numitems = 0;
405   pol tol;
406   int ok = 1;
407 
408   for(tol=ol;tol!=NULL;tol=tol->next) numitems++;
409   ok &= (fwrite((char *)&numitems,sizeof(int),1,fd) > 0);
410   for(tol=ol;tol!=NULL;tol=tol->next)
411     ok &= save_item(fd,tol->thing);
412   return ok;
413 }
414 
415 
save_country(fd)416 int save_country(fd)
417 FILE *fd;
418 {
419   int i, j;
420   int ok = 1;
421   int run;
422   unsigned long int mask;
423 
424   for (i = 0; i < MAXWIDTH; i++)
425     for (j = 0; j < MAXLENGTH; j++)
426       if (c_statusp(i, j, CHANGED)) {
427 	ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
428 	ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
429 	ok &= (fwrite((char *)&Country[i][j],sizeof(struct terrain),1,fd) > 0);
430       }
431   ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
432   ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
433   /* since we don't mark the 'seen' bits as CHANGED, need to save a bitmask */
434   run = 8*sizeof(long int);
435   mask = 0;
436   for (i = 0; i < MAXWIDTH; i++)
437     for (j = 0; j < MAXLENGTH; j++) {
438       if (run == 0) {
439 	run = 8*sizeof(long int);
440 	ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
441 	mask = 0;
442       }
443       mask >>= 1;
444       if (c_statusp(i, j, SEEN))
445 	mask |= (1<<(sizeof(long int)*8 - 1));
446       run--;
447     }
448   if (run < 8*sizeof(long int))
449     ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
450   return ok;
451 }
452 
453 
454 /* returns TRUE if the given version can be restored by this version */
ok_outdated(version)455 int ok_outdated(version)
456 int version;
457 {
458   switch (version) {
459     case 80:
460       print1("Converting version 0.80 savefile to current.");
461       morewait();
462       return TRUE;
463       break;
464     case 81:
465       print1("Loading version 0.81 savefile.");
466       morewait();
467       return TRUE;
468       break;
469     default:
470       return FALSE;
471       break;
472   }
473 }
474 
475 
476 /* read player data, city level, dungeon level,
477    check on validity of save file, etc.
478    return TRUE if game restored, FALSE otherwise */
479 
restore_game(savestr)480 int restore_game(savestr)
481 char *savestr;
482 {
483   int i,version;
484   char temp[200];
485   FILE *fd;
486 
487 #ifndef MSDOS_SUPPORTED_ANTIQUE
488   if (access(savestr, F_OK|R_OK|W_OK) == -1) /* access uses real uid */
489   {
490     print1("Unable to access save file: ");
491     nprint1(savestr);
492     morewait();
493     return FALSE;
494   }
495 #endif
496   change_to_user_perms();
497 #ifdef COMPRESS_SAVE_FILES
498   fd = fopen(savestr,"rb");
499   if (fd == NULL) {
500     print1("Error restoring game -- aborted.");
501     print2("File name was: ");
502     nprint2(savestr);
503     morewait();
504     change_to_game_perms();
505     return(FALSE);
506   }
507   fread((char *)&version,sizeof(int),1,fd);
508   fclose(fd);
509   if (VERSION != version && !ok_outdated(version)) {
510     print1("Uncompressing Save File....");
511 #if defined(MSDOS) || defined(AMIGA)
512     strcpy(temp, savestr);
513     strcat(temp, "Z");
514     rename(savestr, temp);
515     do_compression(1, savestr);
516 #else
517     sprintf(temp, "%s.%s", savestr, COMPRESS_EXT);
518     unlink(temp);
519     link(savestr, temp);
520     unlink(savestr);	/* renames, but sys-V doesn't have rename()... */
521     strcpy(temp,UNCOMPRESSOR);
522     strcat(temp," ");
523     strcat(temp,savestr);
524     system(temp);
525 #endif
526     print2("Save file uncompressed.");
527     morewait();
528   }
529 #endif
530 
531   fd = fopen(savestr,"rb");
532 
533   if (fd == NULL) {
534     print1("Error restoring game -- aborted.");
535     print2("File name was: ");
536     nprint2(savestr);
537     morewait();
538     change_to_game_perms();
539     return(FALSE);
540   }
541   else {
542     print1("Restoring...");
543 
544     fread((char *)&version,sizeof(int),1,fd);
545 
546     if (VERSION != version && !ok_outdated(version)) {
547       change_to_game_perms();
548       fclose(fd);
549       clearmsg();
550       mprint(" Sorry, I can't restore an outdated save file!");
551       mprint(" savefile is version ");
552       mnumprint(version/100);
553       nprint2(".");
554       mnumprint(version%100);
555       morewait();
556       return(FALSE);
557     }
558     restore_player(fd, version);
559     restore_country(fd, version);
560     restore_level(fd, version); /* the city level */
561     fread((char *)&i,sizeof(int),1,fd);
562     for (; i > 0; i--) {
563 #ifdef SAVE_LEVELS
564       msdos_changelevel(Level,0,-1);
565 #endif
566       restore_level(fd, version);
567       if (Level->environment == Current_Dungeon) {
568 	Level->next = Dungeon;
569 	Dungeon = Level;
570       }
571       if (Current_Environment == E_CITY)
572 	Level = City;
573     }
574     /* this disgusting kludge because LENGTH and WIDTH are globals... */
575     WIDTH = 64;
576     switch (Current_Environment) {
577       case E_COURT:
578 	LENGTH = 24; break;
579       case E_ARENA: case E_ABYSS: case E_CIRCLE: case E_MANSION:
580       case E_HOUSE: case E_HOVEL: case E_DLAIR: case E_STARPEAK:
581       case E_MAGIC_ISLE: case E_TEMPLE: case E_VILLAGE:
582 	LENGTH = 16; break;
583       default:
584 	LENGTH = 64; break;
585     }
586     fclose(fd);
587     print3("Restoration complete.");
588     ScreenOffset = -1000;	/* to force a redraw */
589     setgamestatus(SKIP_MONSTERS);
590     change_to_game_perms();
591     return(TRUE);
592   }
593 }
594 
restore_player(fd,version)595 void restore_player(fd, version)
596 FILE *fd;
597 int version;
598 {
599   int i;
600   fread((char *)&Player,sizeof(Player),1,fd);
601   filescanstring(fd,Password);
602   filescanstring(fd,Player.name);
603   fread((char *)CitySiteList,sizeof(CitySiteList),1,fd);
604   fread((char *)&GameStatus,sizeof(long),1,fd);
605   fread((char *)&Current_Environment,sizeof(int),1,fd);
606   fread((char *)&Last_Environment,sizeof(int),1,fd);
607   fread((char *)&Current_Dungeon,sizeof(int),1,fd);
608   fread((char *)&Villagenum,sizeof(int),1,fd);
609   switch(Current_Dungeon) {
610     case E_ASTRAL: MaxDungeonLevels = ASTRALLEVELS; break;
611     case E_SEWERS: MaxDungeonLevels = SEWERLEVELS; break;
612     case E_CASTLE: MaxDungeonLevels = CASTLELEVELS; break;
613     case E_CAVES: MaxDungeonLevels = CAVELEVELS; break;
614     case E_VOLCANO: MaxDungeonLevels = VOLCANOLEVELS; break;
615   }
616   fread((char *)&Verbosity,sizeof(char),1,fd);
617   fread((char *)&Time,sizeof(long),1,fd);
618   fread((char *)&Tick,sizeof(int),1,fd);
619   fread((char *)&Searchnum,sizeof(int),1,fd);
620   fread((char *)&Behavior,sizeof(int),1,fd);
621   fread((char *)&Phase,sizeof(int),1,fd);
622   fread((char *)&Date,sizeof(int),1,fd);
623   fread((char *)&Spellsleft,sizeof(int),1,fd);
624   fread((char *)&SymbolUseHour,sizeof(int),1,fd);
625   fread((char *)&ViewHour,sizeof(int),1,fd);
626   fread((char *)&HelmHour,sizeof(int),1,fd);
627   fread((char *)&Constriction,sizeof(int),1,fd);
628   fread((char *)&Blessing,sizeof(int),1,fd);
629   fread((char *)&LastDay,sizeof(int),1,fd);
630   fread((char *)&RitualHour,sizeof(int),1,fd);
631   fread((char *)&Lawstone,sizeof(int),1,fd);
632   fread((char *)&Chaostone,sizeof(int),1,fd);
633   fread((char *)&Mindstone,sizeof(int),1,fd);
634   fread((char *)&Arena_Opponent,sizeof(int),1,fd);
635   fread((char *)&Imprisonment,sizeof(int),1,fd);
636   fread((char *)&Gymcredit,sizeof(long),1,fd);
637   fread((char *)&Balance,sizeof(long),1,fd);
638   fread((char *)&StarGemUse,sizeof(int),1,fd);
639   fread((char *)&HiMagicUse,sizeof(int),1,fd);
640   fread((char *)&HiMagic,sizeof(int),1,fd);
641   fread((char *)&FixedPoints,sizeof(long),1,fd);
642   fread((char *)&LastCountryLocX,sizeof(int),1,fd);
643   fread((char *)&LastCountryLocY,sizeof(int),1,fd);
644   fread((char *)&LastTownLocX,sizeof(int),1,fd);
645   fread((char *)&LastTownLocY,sizeof(int),1,fd);
646   fread((char *)&Pawndate,sizeof(int),1,fd);
647 
648   fread((char *)Spells,sizeof(Spells),1,fd);
649 
650   fread((char *)&Command_Duration,sizeof(Command_Duration),1,fd);
651   fread((char *)&Precipitation,sizeof(Precipitation),1,fd);
652   fread((char *)&Lunarity,sizeof(Lunarity),1,fd);
653   fread((char *)&ZapHour,sizeof(ZapHour),1,fd);
654   fread((char *)&RitualRoom,sizeof(RitualRoom),1,fd);
655 
656   /* stuff which used to be statics */
657   fread((char *)&twiddle,sizeof(twiddle),1,fd);
658   fread((char *)&saved,sizeof(saved),1,fd);
659   fread((char *)&onewithchaos,sizeof(onewithchaos),1,fd);
660   fread((char *)&club_hinthour,sizeof(club_hinthour),1,fd);
661   fread((char *)&winnings,sizeof(winnings),1,fd);
662   fread((char *)&tavern_hinthour,sizeof(tavern_hinthour),1,fd);
663   fread((char *)scroll_ids,sizeof(scroll_ids),1,fd);
664   fread((char *)potion_ids,sizeof(potion_ids),1,fd);
665   fread((char *)stick_ids,sizeof(stick_ids),1,fd);
666   fread((char *)ring_ids,sizeof(ring_ids),1,fd);
667   fread((char *)cloak_ids,sizeof(cloak_ids),1,fd);
668   fread((char *)boot_ids,sizeof(boot_ids),1,fd);
669   fread((char *)deepest,sizeof(int),E_MAX + 1,fd);
670   fread((char *)level_seed,sizeof(int),E_MAX + 1,fd);
671 
672   /* Set up the strings for the id's */
673   inititem(FALSE);
674 
675   for(i=0;i<MAXITEMS;i++)
676     Player.possessions[i] = restore_item(fd, version);
677 
678   if (!Player.possessions[O_READY_HAND] && Player.possessions[O_WEAPON_HAND] &&
679     twohandedp(Player.possessions[O_WEAPON_HAND]->id))
680     Player.possessions[O_READY_HAND] = Player.possessions[O_WEAPON_HAND];
681 
682   for(i=0;i<MAXPACK;i++)
683     Player.pack[i] = restore_item(fd, version);
684   for(i=0;i<PAWNITEMS;i++)
685     Pawnitems[i] = restore_item(fd, version);
686   Condoitems = restore_itemlist(fd, version);
687   for (i=0;i<TOTALITEMS;i++)
688   {
689     fread((char *)&(Objects[i].known),sizeof(Objects[i].known),1,fd);
690     if (version != 80)
691       fread((char *)&(Objects[i].uniqueness),sizeof(Objects[i].uniqueness),1,fd);
692   }
693 }
694 
695 
696 
697 /* Restore an item, the first byte tells us if it's NULL, and what strings */
698 /* have been saved as different from the typical */
restore_item(fd,version)699 pob restore_item(fd, version)
700 FILE *fd;
701 int version;
702 {
703   char tempstr[80];
704   unsigned char type;
705   pob obj = NULL;
706 
707   fread((char *)&type,sizeof(type),1,fd);
708   if (type != 0xff) {
709     obj = ((pob) checkmalloc(sizeof(objtype)));
710     fread((char *)obj,sizeof(objtype),1,fd);
711     if (type&1) {
712       filescanstring(fd,tempstr);
713       obj->objstr = salloc(tempstr);
714     }
715     else
716       obj->objstr = Objects[obj->id].objstr;
717     if (type&2) {
718       filescanstring(fd,tempstr);
719       obj->truename = salloc(tempstr);
720     }
721     else
722       obj->truename = Objects[obj->id].truename;
723     if (type&4) {
724       filescanstring(fd,tempstr);
725       obj->cursestr = salloc(tempstr);
726     }
727     else
728       obj->cursestr = Objects[obj->id].cursestr;
729   }
730   return obj;
731 }
732 
restore_itemlist(fd,version)733 pol restore_itemlist(fd, version)
734 FILE *fd;
735 int version;
736 {
737   pol ol=NULL,cur=NULL,new=NULL;
738   int i,numitems,firsttime=TRUE;
739   fread((char *)&numitems,sizeof(int),1,fd);
740   for(i=0;i<numitems;i++) {
741     new = ((pol) checkmalloc(sizeof(oltype)));
742     new->thing = restore_item(fd, version);
743     new->next = NULL;
744     if (firsttime==TRUE) {
745       ol = cur = new;
746       firsttime = FALSE;
747     }
748     else {
749       cur->next = new;
750       cur = new;
751     }
752   }
753   return(ol);
754 }
755 
756 
restore_level(fd,version)757 void restore_level(fd, version)
758 FILE *fd;
759 int version;
760 {
761   int i, j, run;
762   unsigned long int mask;
763   int temp_env;
764 
765   Level = (plv) checkmalloc(sizeof(levtype));
766   clear_level(Level);
767   fread((char *)&Level->depth,sizeof(char),1,fd);
768   fread((char *)&Level->numrooms,sizeof(char),1,fd);
769   fread((char *)&Level->tunnelled,sizeof(char),1,fd);
770   fread((char *)&Level->environment,sizeof(int),1,fd);
771   Level->generated = TRUE;
772   temp_env = Current_Environment;
773   Current_Environment = Level->environment;
774   switch(Level->environment) {
775     case E_COUNTRYSIDE:
776       load_country();
777       break;
778     case E_CITY:
779       load_city(FALSE);
780       break;
781     case E_VILLAGE:
782       load_village(Country[LastCountryLocX][LastCountryLocY].aux, FALSE);
783       break;
784     case E_CAVES:
785       initrand(Current_Environment, Level->depth);
786       if ((random_range(4)==0) && (Level->depth < MaxDungeonLevels))
787 	room_level();
788       else cavern_level();
789       break;
790     case E_SEWERS:
791       initrand(Current_Environment, Level->depth);
792       if ((random_range(4)==0) && (Level->depth < MaxDungeonLevels))
793 	room_level();
794       else sewer_level();
795       break;
796     case E_CASTLE:
797       initrand(Current_Environment, Level->depth);
798       room_level();
799       break;
800     case E_ASTRAL:
801       initrand(Current_Environment, Level->depth);
802       maze_level();
803       break;
804     case E_VOLCANO:
805       initrand(Current_Environment, Level->depth);
806       switch(random_range(3)) {
807       case 0: cavern_level(); break;
808       case 1: room_level(); break;
809       case 2: maze_level(); break;
810       }
811       break;
812     case E_HOVEL:
813     case E_MANSION:
814     case E_HOUSE:
815       load_house(Level->environment, FALSE);
816       break;
817     case E_DLAIR:
818       load_dlair(gamestatusp(KILLED_DRAGONLORD), FALSE);
819       break;
820     case E_STARPEAK:
821       load_speak(gamestatusp(KILLED_LAWBRINGER), FALSE);
822       break;
823     case E_MAGIC_ISLE:
824       load_misle(gamestatusp(KILLED_EATER), FALSE);
825       break;
826     case E_TEMPLE:
827       load_temple(Country[LastCountryLocX][LastCountryLocY].aux, FALSE);
828       break;
829     case E_CIRCLE:
830       load_circle(FALSE);
831       break;
832     case E_COURT:
833       load_court(FALSE);
834       break;
835     default: print3("This dungeon not implemented!"); break;
836   }
837   if (Level->depth > 0) {	/* dungeon... */
838     install_traps();
839     install_specials();
840     make_stairs(-1);
841     make_stairs(-1);
842     initrand(E_RESTORE, 0);
843   }
844   Current_Environment = temp_env;
845   fread((char *)&i,sizeof(int),1,fd);
846   fread((char *)&j,sizeof(int),1,fd);
847   while (j < MAXLENGTH && i < MAXWIDTH) {
848     fread((char *)&run,sizeof(int),1,fd);
849     for (; i < run; i++) {
850       fread((char *)&Level->site[i][j],sizeof(struct location),1,fd);
851       Level->site[i][j].creature = NULL;
852       Level->site[i][j].things = NULL;
853     }
854     fread((char *)&i,sizeof(int),1,fd);
855     fread((char *)&j,sizeof(int),1,fd);
856   }
857   run = 0;
858   for (j = 0; j < MAXLENGTH; j++)
859     for (i = 0; i < MAXWIDTH; i++) {
860       if (run == 0) {
861 	run = 8*sizeof(long int);
862 	fread((char *)&mask,sizeof(long int),1,fd);
863       }
864       if (mask&1)
865 	lset(i, j, SEEN);
866       mask >>= 1;
867       run--;
868     }
869   restore_monsters(fd,Level, version);
870   fread((char *)&i,sizeof(int),1,fd);
871   fread((char *)&j,sizeof(int),1,fd);
872   while (j < MAXLENGTH && i < MAXWIDTH) {
873     Level->site[i][j].things = restore_itemlist(fd, version);
874     fread((char *)&i,sizeof(int),1,fd);
875     fread((char *)&j,sizeof(int),1,fd);
876   }
877 }
878 
879 
restore_hiscore_npc(npc,npcid)880 void restore_hiscore_npc(npc, npcid)
881 pmt npc;
882 int npcid;
883 {
884   pob ob;
885   int level, behavior;
886   long status;
887 
888   switch(npcid) {
889   case 0:
890     strcpy(Str2,Hiscorer);
891     level = Hilevel;
892     behavior = Hibehavior;
893     break;
894   case 1: case 2: case 3: case 4: case 5: case 6:
895     strcpy(Str2,Priest[npcid]);
896     level = Priestlevel[npcid];
897     behavior = Priestbehavior[npcid];
898     break;
899   case 7:
900     strcpy(Str2,Shadowlord);
901     level = Shadowlordlevel;
902     behavior = Shadowlordbehavior;
903     break;
904   case 8:
905     strcpy(Str2,Commandant);
906     level = Commandantlevel;
907     behavior = Commandantbehavior;
908     break;
909   case 9:
910     strcpy(Str2,Archmage);
911     level = Archmagelevel;
912     behavior = Archmagebehavior;
913     break;
914   case 10:
915     strcpy(Str2,Prime);
916     level = Primelevel;
917     behavior = Primebehavior;
918     break;
919   case 11:
920     strcpy(Str2,Champion);
921     level = Championlevel;
922     behavior = Championbehavior;
923     break;
924   case 12:
925     strcpy(Str2,Duke);
926     level = Dukelevel;
927     behavior = Dukebehavior;
928     break;
929   case 13:
930     strcpy(Str2,Chaoslord);
931     level = Chaoslordlevel;
932     behavior = Chaoslordbehavior;
933     break;
934   case 14:
935     strcpy(Str2,Lawlord);
936     level = Lawlordlevel;
937     behavior = Lawlordbehavior;
938     break;
939   case 15:
940     strcpy(Str2,Justiciar);
941     level = Justiciarlevel;
942     behavior = Justiciarbehavior;
943     break;
944   }
945   npc->monstring = salloc(Str2);
946   strcpy(Str1,"The body of ");
947   strcat(Str1,Str2);
948   npc->corpsestr = salloc(Str1);
949   if (!m_statusp(npc, HOSTILE)) {
950     status = npc->status;
951     determine_npc_behavior(npc,level,behavior);
952     npc->status = status;
953   }
954 }
955 
956 
restore_monsters(fd,level,version)957 void restore_monsters(fd,level, version)
958 FILE *fd;
959 plv level;
960 int version;
961 {
962   pml ml=NULL;
963   int i,nummonsters;
964   char tempstr[80];
965   int temp_x, temp_y;
966   unsigned char type;
967 
968   level->mlist = NULL;
969 
970   fread((char *)&nummonsters,sizeof(int),1,fd);
971 
972   for(i=0;i<nummonsters;i++) {
973     ml = ((pml) checkmalloc(sizeof(mltype)));
974     ml->m = ((pmt) checkmalloc(sizeof(montype)));
975     ml->next = NULL;
976     fread((char *)ml->m,sizeof(montype),1,fd);
977     if (ml->m->id == HISCORE_NPC)
978       if (version == 80) {
979         temp_x = ml->m->x;
980         temp_y = ml->m->y;
981         make_hiscore_npc(ml->m, ml->m->aux2);
982         ml->m->x = temp_x;
983         ml->m->y = temp_y;
984       }
985       else
986 	restore_hiscore_npc(ml->m, ml->m->aux2);
987     else {
988       fread((char *)&type,sizeof(unsigned char),1,fd);
989       if (type&1) {
990 	filescanstring(fd,tempstr);
991 	ml->m->monstring = salloc(tempstr);
992       }
993       else
994 	ml->m->monstring = Monsters[ml->m->id].monstring;
995       if (type&2) {
996 	filescanstring(fd,tempstr);
997 	ml->m->corpsestr = salloc(tempstr);
998       }
999       else
1000 	ml->m->corpsestr = Monsters[ml->m->id].corpsestr;
1001       /* WDT: As suggested by Sheldon Simms, I'm moving this line... */
1002       if ( version <= 80 )
1003         ml->m->possessions = restore_itemlist(fd,version);
1004       ml->m->meleestr = Monsters[ml->m->id].meleestr;
1005     }
1006     /* WDT: ...to here, so that all creatures will have their stuff
1007      * restored to them.  Savefile versioning added by David Given. */
1008     if ( version > 80 )
1009       ml->m->possessions = restore_itemlist(fd,version);
1010     level->site[ml->m->x][ml->m->y].creature = ml->m;
1011     ml->next = level->mlist;
1012     level->mlist = ml;
1013   }
1014 }
1015 
1016 
1017 
restore_country(fd,version)1018 void restore_country(fd, version)
1019 FILE *fd;
1020 int version;
1021 {
1022   int i, j;
1023   int run;
1024   unsigned long int mask;
1025 
1026   load_country();
1027   fread((char *)&i,sizeof(int),1,fd);
1028   fread((char *)&j,sizeof(int),1,fd);
1029   while (i < MAXWIDTH && j < MAXLENGTH) {
1030     fread((char *)&Country[i][j],sizeof(struct terrain),1,fd);
1031     fread((char *)&i,sizeof(int),1,fd);
1032     fread((char *)&j,sizeof(int),1,fd);
1033   }
1034   run = 0;
1035   for (i = 0; i < MAXWIDTH; i++)
1036     for (j = 0; j < MAXLENGTH; j++) {
1037       if (run == 0) {
1038 	run = 8*sizeof(long int);
1039 	fread((char *)&mask,sizeof(long int),1,fd);
1040       }
1041       if (mask&1)
1042 	c_set(i, j, SEEN);
1043       mask >>= 1;
1044       run--;
1045     }
1046 }
1047