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