save/restore changes - part 2

This is the second of a series of changes related to save/restore.

    No EDITLEVEL bump has been included, because although the code
    is changed extensively by this, the content of the savefiles have
    not been changed.

    Push the use of the structlevel bwrite() and mread() function use
    out of the core and into sfstruct.c. This is groundwork for upcoming
    changes.

    In the core, replace the bwrite() and mread() calls with the
    use of type-specific savefile output (Sfo) and savefile
    input (Sfi) macros.  The macros are defined in a new header file
    savefile.h, which also contains the prototypes for the sfo_* and
    sfi_* functions that the macros ultimately expand to. The functions
    themselves are in src/sfbase.c.

    On C99, each Sfo or Sfi macro expansion refers directly to the
    corresponding  type-specific sfo_* or sfi_* function.

    If C23 or later is is use, the majority (all but 3 types) of the
    macros refer to a single _Generic output routine sfo(nhfp, dt, tag),
    and a single _Generic input routine sfi(nhfp, dt, tag), which handles
    the dispatch of the type-specific underlying functions. This was
    somewhat experimental, but turned out to be practical because the
    compiler would gripe if the type for a variable was not included in
    the _Generic when passed as an argument, so it could be fixed.

    This alters the savefile verication process by having a common set
    return values for the related functions such as uptodate(),
    check_version(), etc. The new return values return more information
    about savefile incompatibilities, beyond failure/sucess. The
    additional information will be useful for an upcoming addition.
    The expanded return values are:
     SF_UPTODATE                     (0) everything matched and looks good
     SF_OUTDATED                     (1) savefile is outdated
     SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch
     SF_DM_IL32LLP64_ON_ILP32LL64    (3) Windows x64 savefile on x86
     SF_DM_I32LP64_ON_ILP32LL64      (4) Unix 64 savefile on x86
     SF_DM_ILP32LL64_ON_I32LP64      (5) x86 savefile on Unix 64
     SF_DM_ILP32LL64_ON_IL32LLP64    (6) x86 savefile on Windows x64
     SF_DM_I32LP64_ON_IL32LLP64      (7) Unix 64 savefile on Windows x64
     SF_DM_IL32LLP64_ON_I32LP64      (8) Windows x64 savefile on Unix 64
     SF_DM_MISMATCH                  (9) some other mismatch
    The callers in the core have been adjusted to deal with the expanded
    return values.

    Other miscellaneous inclusions:

       - go.oracle_loc -> svo.oracle_loc.
       - add a bit (1UL << 30) to  called SFCTOOL_BIT as groundwork
         for changes to follow.
This commit is contained in:
nhmall
2025-05-25 15:03:13 -04:00
parent 15ced6f1ff
commit f4a6da2e52
50 changed files with 2551 additions and 1287 deletions

View File

@@ -59,12 +59,8 @@ extern int amii_numcolors;
#define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE)
/* third arg passed to mread() should be 'unsigned' but most calls use
sizeof so are attempting to pass 'size_t'; mread()'s prototype results
in an implicit conversion; this macro does it explicitly */
#define Mread(fd,adr,siz) mread((fd), (genericptr_t) (adr), (unsigned) (siz))
/* Recalculate svl.level.objects[x][y], since this info was not saved. */
staticfn void
find_lev_obj(void)
{
@@ -129,14 +125,10 @@ restlevchn(NHFILE *nhfp)
s_level *tmplev, *x;
svs.sp_levchn = (s_level *) 0;
if (nhfp->structlevel) {
Mread(nhfp->fd, &cnt, sizeof cnt);
}
Sfi_int(nhfp, &cnt, "levchn-lev_count");
for (; cnt > 0; cnt--) {
tmplev = (s_level *) alloc(sizeof(s_level));
if (nhfp->structlevel) {
Mread(nhfp->fd, tmplev, sizeof *tmplev);
}
Sfi_s_level(nhfp, tmplev, "levchn-s_level");
if (!svs.sp_levchn)
svs.sp_levchn = tmplev;
@@ -157,19 +149,15 @@ restdamage(NHFILE *nhfp)
struct damage *tmp_dam;
boolean ghostly = (nhfp->ftype == NHF_BONESFILE);
if (nhfp->structlevel) {
Mread(nhfp->fd, &dmgcount, sizeof dmgcount);
}
Sfi_unsigned(nhfp, &dmgcount, "damage-damage_count");
counter = (int) dmgcount;
if (!counter)
return;
do {
tmp_dam = (struct damage *) alloc(sizeof *tmp_dam);
if (nhfp->structlevel) {
Mread(nhfp->fd, tmp_dam, sizeof *tmp_dam);
}
Sfi_damage(nhfp, tmp_dam, "damage");
if (ghostly)
tmp_dam->when += (svm.moves - svo.omoves);
@@ -183,11 +171,9 @@ staticfn void
restobj(NHFILE *nhfp, struct obj *otmp)
{
int buflen = 0;
unsigned omid = 0;
if (nhfp->structlevel) {
Mread(nhfp->fd, otmp, sizeof *otmp);
}
Sfi_obj(nhfp, otmp, "obj");
otmp->lua_ref_cnt = 0;
/* next object pointers are invalid; otmp->cobj needs to be left
as is--being non-null is key to restoring container contents */
@@ -197,20 +183,14 @@ restobj(NHFILE *nhfp, struct obj *otmp)
otmp->oextra = newoextra();
/* oname - object's name */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "obj-oname_length");
if (buflen > 0) { /* includes terminating '\0' */
new_oname(otmp, buflen);
if (nhfp->structlevel) {
Mread(nhfp->fd, ONAME(otmp), buflen);
}
Sfi_char(nhfp, ONAME(otmp), "obj-oname", buflen);
}
/* omonst - corpse or statue might retain full monster details */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "obj-omonst_length");
if (buflen > 0) {
newomonst(otmp);
/* this is actually a monst struct, so we
@@ -219,24 +199,19 @@ restobj(NHFILE *nhfp, struct obj *otmp)
}
/* omailcmd - feedback mechanism for scroll of mail */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "obj-omail_length");
if (buflen > 0) {
char *omailcmd = (char *) alloc(buflen);
if (nhfp->structlevel) {
Mread(nhfp->fd, omailcmd, buflen);
}
Sfi_char(nhfp, omailcmd, "obj-omailcmd", buflen);
new_omailcmd(otmp, omailcmd);
free((genericptr_t) omailcmd);
}
/* omid - monster id number, connecting corpse to ghost */
newomid(otmp); /* superfluous; we're already allocated otmp->oextra */
if (nhfp->structlevel) {
Mread(nhfp->fd, &OMID(otmp), sizeof OMID(otmp));
}
Sfi_unsigned(nhfp, &omid, "obj-omid_length");
OMID(otmp) = omid;
}
}
@@ -249,9 +224,7 @@ restobjchn(NHFILE *nhfp, boolean frozen)
boolean ghostly = (nhfp->ftype == NHF_BONESFILE);
while (1) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "obj-obj_length");
if (buflen == -1)
break;
@@ -287,6 +260,7 @@ restobjchn(NHFILE *nhfp, boolean frozen)
for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
otmp3->ocontainer = otmp;
}
if (otmp->bypass)
otmp->bypass = 0;
if (!ghostly) {
@@ -304,7 +278,6 @@ restobjchn(NHFILE *nhfp, boolean frozen)
impossible("Restobjchn: error reading objchn.");
otmp2->nobj = 0;
}
return first;
}
@@ -314,9 +287,7 @@ restmon(NHFILE *nhfp, struct monst *mtmp)
{
int buflen = 0, mc = 0;
if (nhfp->structlevel) {
Mread(nhfp->fd, mtmp, sizeof *mtmp);
}
Sfi_monst(nhfp, mtmp, "monst");
/* next monster pointer is invalid */
mtmp->nmon = (struct monst *) 0;
@@ -325,84 +296,54 @@ restmon(NHFILE *nhfp, struct monst *mtmp)
mtmp->mextra = newmextra();
/* mgivenname - monster's name */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "monst-mgivenname_length");
if (buflen > 0) { /* includes terminating '\0' */
new_mgivenname(mtmp, buflen);
if (nhfp->structlevel) {
Mread(nhfp->fd, MGIVENNAME(mtmp), buflen);
}
Sfi_char(nhfp, MGIVENNAME(mtmp), "monst-mgivenname", (int) buflen);
}
/* egd - vault guard */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "monst-egd_length");
if (buflen > 0) {
newegd(mtmp);
if (nhfp->structlevel) {
Mread(nhfp->fd, EGD(mtmp), sizeof(struct egd));
}
Sfi_egd(nhfp, EGD(mtmp), "monst-egd");
}
/* epri - temple priest */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "monst-epri_length");
if (buflen > 0) {
newepri(mtmp);
if (nhfp->structlevel) {
Mread(nhfp->fd, EPRI(mtmp), sizeof(struct epri));
}
Sfi_epri(nhfp, EPRI(mtmp), "monst-epri");
}
/* eshk - shopkeeper */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "monst-eshk_length");
if (buflen > 0) {
neweshk(mtmp);
if (nhfp->structlevel) {
Mread(nhfp->fd, ESHK(mtmp), sizeof(struct eshk));
}
Sfi_eshk(nhfp, ESHK(mtmp), "monst-eshk");
}
/* emin - minion */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "monst-emin_length");
if (buflen > 0) {
newemin(mtmp);
if (nhfp->structlevel) {
Mread(nhfp->fd, EMIN(mtmp), sizeof(struct emin));
}
Sfi_emin(nhfp, EMIN(mtmp), "monst-emin");
}
/* edog - pet */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "monst-edog_length");
if (buflen > 0) {
newedog(mtmp);
if (nhfp->structlevel) {
Mread(nhfp->fd, EDOG(mtmp), sizeof(struct edog));
}
Sfi_edog(nhfp, EDOG(mtmp), "monst-edog");
/* sanity check to prevent rn2(0) */
if (EDOG(mtmp)->apport <= 0) {
EDOG(mtmp)->apport = 1;
}
}
/* ebones */
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "monst-ebones_length");
if (buflen > 0) {
newebones(mtmp);
if (nhfp->structlevel) {
Mread(nhfp->fd, EBONES(mtmp), sizeof(struct ebones));
}
Sfi_ebones(nhfp, EBONES(mtmp), "monst-ebones");
}
/* mcorpsenm - obj->corpsenm for mimic posing as corpse or
statue (inline int rather than pointer to something) */
if (nhfp->structlevel) {
Mread(nhfp->fd, &mc, sizeof mc);
}
Sfi_int(nhfp, &mc, "monst-mcorpsenm");
MCORPSENM(mtmp) = mc;
} /* mextra */
}
@@ -416,9 +357,7 @@ restmonchn(NHFILE *nhfp)
boolean ghostly = (nhfp->ftype == NHF_BONESFILE);
while (1) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "monst-monst_length");
if (buflen == -1)
break;
@@ -494,9 +433,7 @@ loadfruitchn(NHFILE *nhfp)
flist = 0;
for (;;) {
fnext = newfruit();
if (nhfp->structlevel) {
Mread(nhfp->fd, fnext, sizeof *fnext);
}
Sfi_fruit(nhfp, fnext, "fruit");
if (fnext->fid != 0) {
fnext->nextf = flist;
flist = fnext;
@@ -546,29 +483,29 @@ restgamestate(NHFILE *nhfp)
int i;
struct flag newgameflags;
struct context_info newgamecontext; /* all 0, but has some pointers */
struct obj *otmp;
struct obj *bc_obj;
char timebuf[15];
unsigned long uid = 0;
boolean defer_perm_invent, restoring_special;
struct obj *otmp;
if (nhfp->structlevel) {
Mread(nhfp->fd, &uid, sizeof uid);
}
Sfi_ulong(nhfp, &uid, "gamestate-uid");
if (SYSOPT_CHECK_SAVE_UID
&& uid != (unsigned long) getuid()) { /* strange ... */
/* for wizard mode, issue a reminder; for others, treat it
as an attempt to cheat and refuse to restore this file */
pline("Saved game was not yours.");
if (!wizard)
if (!gc.converted_savefile_loaded)
/* for wizard mode, issue a reminder; for others, treat it
as an attempt to cheat and refuse to restore this file */
pline("Saved game was not yours.");
if (wizard || gc.converted_savefile_loaded) {
if (gc.converted_savefile_loaded)
gc.converted_savefile_loaded = FALSE;
} else {
return FALSE;
}
}
newgamecontext = svc.context; /* copy statically init'd context */
if (nhfp->structlevel) {
Mread(nhfp->fd, &svc.context, sizeof svc.context);
}
Sfi_context_info(nhfp, &svc.context, "gamestate-context");
svc.context.warntype.species = (ismnum(svc.context.warntype.speciesidx))
? &mons[svc.context.warntype.speciesidx]
: (struct permonst *) 0;
@@ -580,9 +517,7 @@ restgamestate(NHFILE *nhfp)
file option values instead of keeping old save file option values
if partial restore fails and we resort to starting a new game */
newgameflags = flags;
if (nhfp->structlevel) {
Mread(nhfp->fd, &flags, sizeof flags);
}
Sfi_flag(nhfp, &flags, "gamestate-flags");
/* avoid keeping permanent inventory window up to date during restore
(setworn() calls update_inventory); attempting to include the cost
@@ -610,9 +545,8 @@ restgamestate(NHFILE *nhfp)
#ifdef AMII_GRAPHICS
amii_setpens(amii_numcolors); /* use colors from save file */
#endif
if (nhfp->structlevel) {
Mread(nhfp->fd, &u, sizeof u);
}
Sfi_you(nhfp, &u, "gamestate-you");
gy.youmonst.cham = u.mcham;
if (restoring_special && iflags.explore_error_flag) {
@@ -622,17 +556,11 @@ restgamestate(NHFILE *nhfp)
u.uhp = 0;
}
if (nhfp->structlevel) {
Mread(nhfp->fd, timebuf, 14);
}
Sfi_char(nhfp, timebuf, "gamestate-ubirthday", 14);
timebuf[14] = '\0';
ubirthday = time_from_yyyymmddhhmmss(timebuf);
if (nhfp->structlevel) {
Mread(nhfp->fd, &urealtime.realtime, sizeof urealtime.realtime);
}
if (nhfp->structlevel) {
Mread(nhfp->fd, timebuf, 14);
}
Sfi_long(nhfp, &urealtime.realtime, "gamestate-realtime");
Sfi_char(nhfp, timebuf, "gamestate-start_timing", 14);
timebuf[14] = '\0';
urealtime.start_timing = time_from_yyyymmddhhmmss(timebuf);
@@ -672,6 +600,7 @@ restgamestate(NHFILE *nhfp)
/* restore dangling (not on floor or in inventory) ball and/or chain */
bc_obj = restobjchn(nhfp, FALSE);
while (bc_obj) {
struct obj *nobj = bc_obj->nobj;
@@ -680,13 +609,12 @@ restgamestate(NHFILE *nhfp)
setworn(bc_obj, bc_obj->owornmask);
bc_obj = nobj;
}
gm.migrating_objs = restobjchn(nhfp, FALSE);
gm.migrating_mons = restmonchn(nhfp);
for (i = 0; i < NUMMONS; ++i) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &svm.mvitals[i], sizeof (struct mvitals));
}
Sfi_mvitals(nhfp, &svm.mvitals[i], "gamestate-mvitals");
}
/*
* There are some things after this that can have unintended display
@@ -712,26 +640,19 @@ restgamestate(NHFILE *nhfp)
restore_dungeon(nhfp);
restlevchn(nhfp);
if (nhfp->structlevel) {
Mread(nhfp->fd, &svm.moves, sizeof svm.moves);
}
Sfi_long(nhfp, &svm.moves, "gamestate-moves");
/* hero_seq isn't saved and restored because it can be recalculated */
gh.hero_seq = svm.moves << 3; /* normally handled in moveloop() */
if (nhfp->structlevel) {
Mread(nhfp->fd, &svq.quest_status, sizeof svq.quest_status);
}
Sfi_q_score(nhfp, &svq.quest_status, "gamestate-quest_status");
for (i = 0; i < (MAXSPELL + 1); ++i) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &svs.spl_book[i],
sizeof (struct spell));
}
Sfi_spell(nhfp, &svs.spl_book[i], "gamestate-spl_book");
}
restore_artifacts(nhfp);
restore_oracles(nhfp);
if (nhfp->structlevel) {
Mread(nhfp->fd, svp.pl_character, sizeof svp.pl_character);
Mread(nhfp->fd, svp.pl_fruit, sizeof svp.pl_fruit);
}
Sfi_char(nhfp, svp.pl_character,
"gamestate-pl_character", sizeof svp.pl_character);
Sfi_char(nhfp, svp.pl_fruit, "gamestate-pl_fruit", sizeof svp.pl_fruit);
freefruitchn(gf.ffruit); /* clean up fruit(s) made by initoptions() */
gf.ffruit = loadfruitchn(nhfp);
@@ -782,6 +703,21 @@ restlevelfile(xint8 ltmp)
return 2;
}
/*
* restore_saved_game() prior to this left us at this position in
* the savefile for dorecover():
*
* format indicator (1 byte)
* n = count of critical size list (1 byte)
* n bytes of critical sizes (n bytes)
* version info
* --> plnametmp = player name size (int, 2 bytes)
* player name (PL_NSIZ_PLUS)
* current level (including pets)
* (non-level-based) game state
* other levels
*/
int
dorecover(NHFILE *nhfp)
{
@@ -792,6 +728,19 @@ dorecover(NHFILE *nhfp)
program_state.restoring = REST_GSTATE;
get_plname_from_file(nhfp, svp.plname, TRUE);
/*
* The position in the save file is now here:
*
* format indicator (1 byte)
* n = count of critical size list (1 byte)
* n bytes of critical sizes (n bytes)
* version info
* plnametmp = player name size (int, 2 bytes)
* player name (PL_NSIZ_PLUS)
* --> current level (including pets)
* (non-level-based) game state
* other levels
*/
getlev(nhfp, 0, (xint8) 0);
if (!restgamestate(nhfp)) {
NHFILE tnhfp;
@@ -855,10 +804,8 @@ dorecover(NHFILE *nhfp)
#endif
restoreinfo.mread_flags = 1; /* return despite error */
while (1) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &ltmp, sizeof ltmp);
}
if (restoreinfo.mread_flags == -1)
Sfi_xint8(nhfp, &ltmp, "gamestate-level_number");
if (nhfp->eof)
break;
getlev(nhfp, 0, ltmp);
#ifdef MICRO
@@ -949,16 +896,11 @@ rest_stairs(NHFILE *nhfp)
stairway_free_all();
while (1) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &buflen, sizeof buflen);
}
Sfi_int(nhfp, &buflen, "stairs-staircount");
if (buflen == -1)
break;
if (nhfp->structlevel) {
Mread(nhfp->fd, &stway, sizeof stway);
}
Sfi_stairway(nhfp, &stway, "stairs-stairway");
if (program_state.restoring != REST_GSTATE
&& stway.tolev.dnum == u.uz.dnum) {
/* stairway dlevel is relative, make it absolute */
@@ -978,22 +920,29 @@ restcemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr)
struct cemetery *bonesinfo, **bonesaddr;
int cflag = 0;
if (nhfp->structlevel) {
Mread(nhfp->fd, &cflag, sizeof cflag);
}
Sfi_int(nhfp, &cflag, "cemetery-cemetery_flag");
if (cflag == 0) {
bonesaddr = cemeteryaddr;
do {
bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo);
if (nhfp->structlevel) {
Mread(nhfp->fd, bonesinfo, sizeof *bonesinfo);
}
Sfi_cemetery(nhfp, bonesinfo, "cemetery-bonesinfo");
*bonesaddr = bonesinfo;
bonesaddr = &(*bonesaddr)->next;
} while (*bonesaddr);
} else {
*cemeteryaddr = 0;
}
if ((nhfp->mode & CONVERTING) != 0) {
struct cemetery *thisbones, *nextbones;
/* free the memory */
nextbones = *cemeteryaddr;
while ((thisbones = nextbones) != 0) {
nextbones = thisbones->next;
free((genericptr_t)thisbones);
}
*cemeteryaddr = 0;
}
}
/*ARGSUSED*/
@@ -1004,9 +953,7 @@ rest_levl(NHFILE *nhfp)
for (c = 0; c < COLNO; ++c) {
for (r = 0; r < ROWNO; ++r) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &levl[c][r], sizeof (struct rm));
}
Sfi_rm(nhfp, &levl[c][r], "location-rm");
}
}
}
@@ -1043,10 +990,13 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
if (ghostly)
clear_id_mapping();
#if 0
#if defined(MSDOS) || defined(OS2)
if (nhfp->structlevel)
setmode(nhfp->fd, O_BINARY);
#endif
#endif
/* Load the old fruit info. We have to do it first, so the
* information is available when restoring the objects.
*/
@@ -1054,13 +1004,9 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
go.oldfruit = loadfruitchn(nhfp);
/* First some sanity checks */
if (nhfp->structlevel) {
Mread(nhfp->fd, &hpid, sizeof hpid);
}
if (nhfp->structlevel) {
Mread(nhfp->fd, &dlvl, sizeof dlvl);
}
Sfi_int(nhfp, &hpid, "gamestate-hackpid");
/* CHECK: This may prevent restoration */
Sfi_xint8(nhfp, &dlvl, "gamestate-dlvl");
if ((pid && pid != hpid) || (lev && dlvl != lev)) {
char trickbuf[BUFSZ];
@@ -1075,42 +1021,38 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
}
restcemetery(nhfp, &svl.level.bonesinfo);
rest_levl(nhfp);
for (c = 0; c < COLNO; ++c)
for (c = 0; c < COLNO; ++c) {
for (r = 0; r < ROWNO; ++r) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &svl.lastseentyp[c][r], sizeof (schar));
}
}
Mread(nhfp->fd, &svo.omoves, sizeof svo.omoves);
elapsed = svm.moves - svo.omoves;
Sfi_schar(nhfp, &svl.lastseentyp[c][r], "lastseentyp");
}
}
Sfi_long(nhfp, &svo.omoves, "lev-timestmp");
elapsed = (svm.moves - svo.omoves);
rest_stairs(nhfp);
if (nhfp->structlevel) {
Mread(nhfp->fd, &svu.updest, sizeof svu.updest);
Mread(nhfp->fd, &svd.dndest, sizeof svd.dndest);
Mread(nhfp->fd, &svl.level.flags, sizeof svl.level.flags);
}
Sfi_dest_area(nhfp, &svu.updest, "lev-updest");
Sfi_dest_area(nhfp, &svd.dndest, "lev-dndest");
Sfi_levelflags(nhfp, &svl.level.flags, "lev-level_flags");
if (svd.doors) {
free(svd.doors);
svd.doors = 0;
}
if (nhfp->structlevel) {
Mread(nhfp->fd, &svd.doors_alloc, sizeof svd.doors_alloc);
}
Sfi_int(nhfp, &svd.doors_alloc, "lev-doors_alloc");
if (svd.doors_alloc) { /* avoid pointless alloc(0) */
svd.doors = (coord *) alloc(svd.doors_alloc * sizeof(coord));
svd.doors = (coord *) alloc(svd.doors_alloc * sizeof (coord));
tmpc = svd.doors;
for (i = 0; i < svd.doors_alloc; ++i) {
if (nhfp->structlevel) {
Mread(nhfp->fd, tmpc, sizeof (coord));
}
Sfi_nhcoord(nhfp, tmpc, "lev-doors");
tmpc++;
}
}
rest_rooms(nhfp); /* No joke :-) */
if (svn.nroom) {
gd.doorindex = svr.rooms[svn.nroom - 1].fdoor
+ svr.rooms[svn.nroom - 1].doorct;
+ svr.rooms[svn.nroom - 1].doorct;
} else {
gd.doorindex = 0;
}
@@ -1123,9 +1065,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
gf.ftrap = 0;
for (;;) {
trap = newtrap();
if (nhfp->structlevel) {
Mread(nhfp->fd, trap, sizeof *trap);
}
Sfi_trap(nhfp, trap, "trap");
if (trap->tx != 0) {
if (program_state.restoring != REST_GSTATE
&& trap->dst.dnum == u.uz.dnum) {
@@ -1147,6 +1087,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
gb.billobjs = restobjchn(nhfp, FALSE);
rest_engravings(nhfp);
/* reset level.monsters for new level */
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
@@ -1192,6 +1133,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
if (ghostly || (elapsed > 00 && elapsed > (long) rnd(10)))
hide_monst(mtmp);
}
restdamage(nhfp);
rest_regions(nhfp);
rest_bubbles(nhfp); /* for water and air; empty marker on other levels */
@@ -1265,7 +1207,6 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
}
}
}
/* must come after all mons & objs are restored */
relink_timers(ghostly);
relink_light_sources(ghostly);
@@ -1288,13 +1229,12 @@ get_plname_from_file(
int pltmpsiz = 0;
plbuf[0] = '\0';
if (nhfp->structlevel) {
(void) read(nhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz);
/* pltmpsiz should now be PL_NSIZ_PLUS */
(void) read(nhfp->fd, (genericptr_t) plbuf, pltmpsiz);
/* plbuf[PL_NSIZ_PLUS-2] should be '\0';
plbuf[PL_NSIZ_PLUS-1] should be '-' or 'X' or 'D' */
}
Sfi_int(nhfp, &pltmpsiz, "plname-size");
/* pltmpsiz should now be PL_NSIZ_PLUS */
Sfi_char(nhfp, plbuf, "plname", pltmpsiz);
/* plbuf[PL_NSIZ_PLUS-2] should be '\0';
plbuf[PL_NSIZ_PLUS-1] should be '-' or 'X' or 'D' */
/* "-race-role-gend-algn" is already present except that it has been
hidden by replacing the initial dash with NUL; if we want that
information, replace the NUL with a dash */
@@ -1316,10 +1256,11 @@ rest_bubbles(NHFILE *nhfp)
clouds are present is recorded during save so that we don't have to
know what level is being restored */
bbubbly = 0;
if (nhfp->structlevel) {
Mread(nhfp->fd, &bbubbly, sizeof bbubbly);
}
Sfi_xint8(nhfp, &bbubbly, "bubbles-bbubbly");
#if 0
if (nhfp->structlevel)
xxread(nhfp->fd, &bbubbly, sizeof bbubbly);
#endif
if (bbubbly)
restore_waterlevel(nhfp);
}
@@ -1332,20 +1273,14 @@ restore_gamelog(NHFILE *nhfp)
struct gamelog_line tmp = { 0 };
while (1) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &slen, sizeof slen);
}
Sfi_int(nhfp, &slen, "gamelog-length");
if (slen == -1)
break;
if (slen > ((BUFSZ*2) - 1))
panic("restore_gamelog: msg too big (%d)", slen);
if (nhfp->structlevel) {
Mread(nhfp->fd, msg, slen);
}
Sfi_char(nhfp, msg, "gamelog-gamelog_text", slen);
msg[slen] = '\0';
if (nhfp->structlevel) {
Mread(nhfp->fd, &tmp, sizeof tmp);
}
Sfi_gamelog_line(nhfp, &tmp, "gamelog-gamelog_line");
gamelog_add(tmp.flags, tmp.turn, msg);
}
}
@@ -1353,20 +1288,17 @@ restore_gamelog(NHFILE *nhfp)
staticfn void
restore_msghistory(NHFILE *nhfp)
{
int msgsize = 0, msgcount = 0;
int msgsize = 0;
int msgcount = 0;
char msg[BUFSZ];
while (1) {
if (nhfp->structlevel) {
Mread(nhfp->fd, &msgsize, sizeof msgsize);
}
Sfi_int(nhfp, &msgsize, "msghistory-length");
if (msgsize == -1)
break;
if (msgsize > BUFSZ - 1)
panic("restore_msghistory: msg too big (%d)", msgsize);
if (nhfp->structlevel) {
Mread(nhfp->fd, msg, msgsize);
}
Sfi_char(nhfp, msg, "msghistory-msg", msgsize);
msg[msgsize] = '\0';
putmsghistory(msg, TRUE);
++msgcount;
@@ -1552,22 +1484,4 @@ restore_menu(
}
#endif /* SELECTSAVED */
int
validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile)
{
unsigned long utdflags = 0L;
boolean reslt = FALSE;
if (nhfp->structlevel)
utdflags |= UTD_CHECKSIZES;
if (without_waitsynch_perfile)
utdflags |= UTD_WITHOUT_WAITSYNCH_PERFILE;
if (!(reslt = uptodate(nhfp, name, utdflags)))
return 1;
return 0;
}
#undef Mread
/*restore.c*/