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

@@ -71,6 +71,7 @@ static xint16 artidisco[NROFARTIFACTS];
* bulk re-init if game restart ever gets implemented. They are saved
* and restored but that is done through this file so they can be local.
*/
static const struct arti_info zero_artiexist = {0}; /* all bits zero */
staticfn void hack_artifacts(void);
@@ -113,16 +114,11 @@ save_artifacts(NHFILE *nhfp)
{
int i;
for (i = 0; i < (NROFARTIFACTS + 1); ++i) {
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &artiexist[i],
sizeof (struct arti_info));
}
for (i = 0; i < (NROFARTIFACTS); ++i) {
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &artidisco[i],
sizeof (xint16));
}
for (i = 0; i < (NROFARTIFACTS + 1); ++i)
Sfo_arti_info(nhfp, &artiexist[i], "artiexist");
for (i = 0; i < NROFARTIFACTS; ++i)
Sfo_xint16(nhfp, &artidisco[i], "artidisco");
}
void
@@ -130,16 +126,10 @@ restore_artifacts(NHFILE *nhfp)
{
int i;
for (i = 0; i < (NROFARTIFACTS + 1); ++i) {
if (nhfp->structlevel)
mread(nhfp->fd, (genericptr_t) &artiexist[i],
sizeof (struct arti_info));
}
for (i = 0; i < (NROFARTIFACTS); ++i) {
if (nhfp->structlevel)
mread(nhfp->fd, (genericptr_t) &artidisco[i],
sizeof (xint16));
}
for (i = 0; i < (NROFARTIFACTS + 1); ++i)
Sfi_arti_info(nhfp, &artiexist[i], "artiexist");
for (i = 0; i < NROFARTIFACTS; ++i)
Sfi_short(nhfp, &artidisco[i], "artidisco");
hack_artifacts(); /* redo non-saved special cases */
}
@@ -2799,4 +2789,5 @@ permapoisoned(struct obj *obj)
{
return (obj && is_art(obj, ART_GRIMTOOTH));
}
/*artifact.c*/

View File

@@ -610,13 +610,10 @@ savebones(int how, time_t when, struct obj *corpse)
nhfp->mode = WRITING;
store_version(nhfp);
/* if a bones pool digit is in use, it precedes the bonesid
string and isn't recorded in the file */
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &c, sizeof c);
bwrite(nhfp->fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nn */
}
string and isn't recorded in the file */
Sfo_char(nhfp, &c, "bones_count", 1);
Sfo_char(nhfp, bonesid, "bonesid", (int) c); /* DD.nnn */
savefruitchn(nhfp);
update_mlstmv(); /* update monsters for eventual restoration */
savelev(nhfp, ledger_no(&u.uz));
@@ -655,7 +652,7 @@ getbones(void)
return 0;
}
if (validate(nhfp, gb.bones, FALSE) != 0) {
if (validate(nhfp, gb.bones, FALSE) != SF_UPTODATE) {
if (!wizard)
pline("Discarding unusable bones; no need to panic...");
ok = FALSE;
@@ -668,26 +665,18 @@ getbones(void)
return 0;
}
}
/* if a bones pool digit is in use, it precedes the bonesid
string and wasn't recorded in the file */
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &c,
sizeof c); /* length including terminating '\0' */
}
if ((unsigned) c <= sizeof oldbonesid) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) oldbonesid,
(unsigned) c); /* DD.nn or Qrrr.n for role rrr */
Sfi_char(nhfp, &c, "bones_count", 1); /* length incl. '\0' */
if ((unsigned) c <= sizeof oldbonesid) {
Sfi_char(nhfp, oldbonesid, "bonesid", (int) c);
} else {
if (wizard)
debugpline2("Abandoning bones , %u > %u.",
(unsigned) c, (unsigned) sizeof oldbonesid);
close_nhfile(nhfp);
compress_bonesfile();
/* ToDo: maybe unlink these problematic bones? */
return 0;
}
} else {
if (wizard)
debugpline2("Abandoning bones , %u > %u.", (unsigned) c,
(unsigned) sizeof oldbonesid);
close_nhfile(nhfp);
compress_bonesfile();
/* ToDo: maybe unlink these problematic bones? */
return 0;
}
if (strcmp(bonesid, oldbonesid) != 0) {
char errbuf[BUFSZ];

View File

@@ -1133,7 +1133,6 @@ cnf_line_PORTABLE_DEVICE_PATHS(char *bufp)
#endif
return TRUE;
}
#endif /* SYSCF */
staticfn boolean
@@ -1863,9 +1862,9 @@ vconfig_error_add(const char *str, va_list the_args)
staticfn void
parseformat(int *arr, char *str)
{
const char *legal[] = { "historical", "lendian", "ascii" };
const char *legal[] = { "historical", "cnv" };
int i, kwi = 0, words = 0;
char *p = str, *keywords[2];
char *p = str, *keywords[2] = { NULL };
while (*p) {
while (*p && isspace((uchar) *p)) {
@@ -1937,3 +1936,4 @@ assure_syscf_file(void)
/* ---------- END CONFIG FILE HANDLING ----------- */
/*cfgfiles.c*/

View File

@@ -282,6 +282,7 @@ static const struct instance_globals_c g_init_c = {
UNDEFINED_PTR, /* coder */
/* uhitm.c */
NON_PM, /* corpsenm_digested */
FALSE, /* converted_savefile_loaded */
TRUE, /* havestate*/
};
@@ -602,7 +603,6 @@ static const struct instance_globals_o g_init_o = {
UNDEFINED_PTR, /* oldfruit */
/* rumors.c */
0, /* oracle_flag */
UNDEFINED_PTR, /* oracle_loc */
/* uhitm.c */
FALSE, /* override_confirmation */
/* zap.c */
@@ -930,6 +930,8 @@ static const struct instance_globals_saved_n init_svn = {
static const struct instance_globals_saved_o init_svo = {
/* rumors.c */
0U, /* oracle_cnt */
UNDEFINED_PTR, /* oracle_loc */
/* other */
0L /* omoves */
};

View File

@@ -32,6 +32,8 @@ struct lchoice {
char menuletter;
};
static mapseen *load_mapseen(NHFILE *);
#if 0
staticfn void Fread(genericptr_t, int, int, dlb *);
#endif
@@ -152,49 +154,31 @@ save_dungeon(
mapseen *curr_ms, *next_ms;
if (perform_write) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns);
}
Sfo_int(nhfp, &svn.n_dgns, "dungeon_count");
for (i = 0; i < svn.n_dgns; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svd.dungeons[i],
sizeof (dungeon));
}
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svd.dungeon_topology,
sizeof svd.dungeon_topology);
bwrite(nhfp->fd, (genericptr_t) svt.tune, sizeof tune);
Sfo_dungeon(nhfp, &svd.dungeons[i], "dungeon");
}
Sfo_dgn_topology(nhfp, &svd.dungeon_topology, "svd.dungeon_topology");
Sfo_char(nhfp, svt.tune, "tune", (int) sizeof tune);
for (count = 0, curr = svb.branches; curr; curr = curr->next)
count++;
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
Sfo_int(nhfp, &count, "branch_count");
for (curr = svb.branches; curr; curr = curr->next) {
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) curr, sizeof *curr);
Sfo_branch(nhfp, curr, "branch");
}
count = maxledgerno();
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfo_int(nhfp, &count, "level_info_count");
for (i = 0; i < count; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svl.level_info[i],
sizeof (struct linfo));
}
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos);
Sfo_linfo(nhfp, &svl.level_info[i], "svl.level_info");
}
Sfo_nhcoord(nhfp, &svi.inv_pos, "svi.inv_pos");
for (count = 0, curr_ms = svm.mapseenchn; curr_ms;
curr_ms = curr_ms->next)
count++;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfo_int(nhfp, &count, "mapseen_count");
for (curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) {
save_mapseen(nhfp, curr_ms);
@@ -224,35 +208,24 @@ void
restore_dungeon(NHFILE *nhfp)
{
branch *curr, *last;
int count = 0, i;
int count = 0;
int i;
mapseen *curr_ms, *last_ms;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns);
}
Sfi_int(nhfp, &svn.n_dgns, "dungeon_count");
for (i = 0; i < svn.n_dgns; ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svd.dungeons[i], sizeof(dungeon));
}
}
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svd.dungeon_topology,
sizeof svd.dungeon_topology);
}
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) svt.tune, sizeof tune);
Sfi_dungeon(nhfp, &svd.dungeons[i], "dungeon");
}
Sfi_dgn_topology(nhfp, &svd.dungeon_topology, "svd.dungeon_topology");
Sfi_char(nhfp, svt.tune, "tune", (int) sizeof tune);
last = svb.branches = (branch *) 0;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfi_int(nhfp, &count, "branch_count");
for (i = 0; i < count; i++) {
curr = (branch *) alloc(sizeof *curr);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) curr, sizeof *curr);
}
Sfi_branch(nhfp, curr, "branch");
curr->next = (branch *) 0;
if (last)
last->next = curr;
@@ -261,23 +234,19 @@ restore_dungeon(NHFILE *nhfp)
last = curr;
}
if (nhfp->structlevel)
mread(nhfp->fd, (genericptr_t) &count, sizeof count);
Sfi_int(nhfp, &count, "level_info_count");
if (count >= MAXLINFO)
panic("level information count larger (%d) than allocated size",
count);
for (i = 0; i < count; ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svl.level_info[i],
sizeof (struct linfo));
}
}
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos);
mread(nhfp->fd, (genericptr_t) &count, sizeof count);
Sfi_linfo(nhfp, &svl.level_info[i], "svl.level_info");
}
Sfi_nhcoord(nhfp, &svi.inv_pos, "svi.inv_pos");
Sfi_int(nhfp, &count, "mapseen_count");
last_ms = (mapseen *) 0;
for (i = 0; i < count; i++) {
curr_ms = load_mapseen(nhfp);
@@ -2592,19 +2561,14 @@ save_exclusions(NHFILE *nhfp)
for (nez = 0, ez = sve.exclusion_zones; ez; ez = ez->next, ++nez)
;
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &nez, sizeof nez);
if (update_file(nhfp)) {
Sfo_int(nhfp, &nez, "exclusion-count");
for (ez = sve.exclusion_zones; ez; ez = ez->next) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &ez->zonetype,
sizeof ez->zonetype);
bwrite(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx);
bwrite(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly);
bwrite(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx);
bwrite(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy);
}
Sfo_xint16(nhfp, &ez->zonetype, "exclusion-zonetype");
Sfo_coordxy(nhfp, &ez->lx, "exclusion-lx");
Sfo_coordxy(nhfp, &ez->ly, "exclusion-ly");
Sfo_coordxy(nhfp, &ez->hx, "exclusion-hx");
Sfo_coordxy(nhfp, &ez->hy, "exclusion-hy");
}
}
}
@@ -2615,20 +2579,15 @@ load_exclusions(NHFILE *nhfp)
struct exclusion_zone *ez;
int nez = 0;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &nez, sizeof nez);
}
Sfi_int(nhfp, &nez, "exclusion_count");
while (nez-- > 0) {
ez = (struct exclusion_zone *) alloc(sizeof *ez);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &ez->zonetype,
sizeof ez->zonetype);
mread(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx);
mread(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly);
mread(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx);
mread(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy);
}
Sfi_xint16(nhfp, &ez->zonetype, "exclusion-zonetype");
Sfi_coordxy(nhfp, &ez->lx, "exclusion-lx");
Sfi_coordxy(nhfp, &ez->ly, "exclusion-ly");
Sfi_coordxy(nhfp, &ez->hx, "exclusion-hx");
Sfi_coordxy(nhfp, &ez->hy, "exclusion-hy");
ez->next = sve.exclusion_zones;
sve.exclusion_zones = ez;
}
@@ -2699,27 +2658,18 @@ save_mapseen(NHFILE *nhfp, mapseen *mptr)
for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx)
if (curr == mptr->br)
break;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &brindx, sizeof brindx);
bwrite(nhfp->fd, (genericptr_t) &mptr->lev, sizeof mptr->lev);
bwrite(nhfp->fd, (genericptr_t) &mptr->feat, sizeof mptr->feat);
bwrite(nhfp->fd, (genericptr_t) &mptr->flags, sizeof mptr->flags);
bwrite(nhfp->fd, (genericptr_t) &mptr->custom_lth,
sizeof mptr->custom_lth);
}
Sfo_int(nhfp, &brindx, "mapseen-branch_index");
Sfo_d_level(nhfp, &mptr->lev, "mapseen-d_level");
Sfo_mapseen_feat(nhfp, &mptr->feat, "mapseen-feat");
Sfo_mapseen_flags(nhfp, &mptr->flags, "mapseen-flags");
Sfo_unsigned(nhfp, &mptr->custom_lth, "mapseen-custom_lth");
if (mptr->custom_lth) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) mptr->custom,
mptr->custom_lth);
}
Sfo_char(nhfp, mptr->custom, "mapseen-custom",
(int) mptr->custom_lth);
}
for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &mptr->msrooms[i],
sizeof (struct mapseen_rooms));
}
Sfo_mapseen_rooms(nhfp, &mptr->msrooms[i], "mapseen-msrooms");
}
savecemetery(nhfp, &mptr->final_resting_place);
}
@@ -2733,38 +2683,28 @@ load_mapseen(NHFILE *nhfp)
load = (mapseen *) alloc(sizeof *load);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &branchnum, sizeof branchnum);
}
Sfi_int(nhfp, &branchnum, "mapseen-branch_index");
for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx)
if (brindx == branchnum)
break;
load->br = curr;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &load->lev, sizeof load->lev);
mread(nhfp->fd, (genericptr_t) &load->feat, sizeof load->feat);
mread(nhfp->fd, (genericptr_t) &load->flags, sizeof load->flags);
mread(nhfp->fd, (genericptr_t) &load->custom_lth,
sizeof load->custom_lth);
}
Sfi_d_level(nhfp, &load->lev, "mapseen-d_level");
Sfi_mapseen_feat(nhfp, &load->feat, "mapseen-feat");
Sfi_mapseen_flags(nhfp, &load->flags, "mapseen-flags");
Sfi_unsigned(nhfp, &load->custom_lth, "mapseen-custom_lth");
if (load->custom_lth) {
/* length doesn't include terminator (which isn't saved & restored) */
load->custom = (char *) alloc(load->custom_lth + 1);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) load->custom,
load->custom_lth);
}
Sfi_char(nhfp, load->custom, "mapseen-custom",
(int) load->custom_lth);
load->custom[load->custom_lth] = '\0';
} else {
load->custom = 0;
}
for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &load->msrooms[i],
sizeof (struct mapseen_rooms));
}
Sfi_mapseen_rooms(nhfp, &load->msrooms[i], "mapseen-msrooms");
}
restcemetery(nhfp, &load->final_resting_place);
return load;
@@ -3742,7 +3682,6 @@ print_mapseen(
}
}
}
#undef OF_INTEREST
#undef ADDNTOBUF
#undef ADDTOBUF

View File

@@ -1754,11 +1754,9 @@ save_killers(NHFILE *nhfp)
{
struct kinfo *kptr;
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
for (kptr = &svk.killer; kptr; kptr = kptr->next) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo));
}
Sfo_kinfo(nhfp, kptr, "kinfo");
}
}
if (release_data(nhfp)) {
@@ -1776,9 +1774,7 @@ restore_killers(NHFILE *nhfp)
struct kinfo *kptr;
for (kptr = &svk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo));
}
Sfi_kinfo(nhfp, kptr, "kinfo");
if (kptr->next) {
kptr->next = (struct kinfo *) alloc(sizeof (struct kinfo));
}
@@ -1933,12 +1929,12 @@ NH_abort(char *why USED_FOR_CRASHREPORT)
panictrace_setsignals(FALSE);
#endif
#endif /* PANICTRACE */
#ifdef WIN32
#if defined(WIN32)
win32_abort();
#else
abort();
#endif
}
#undef USED_FOR_CRASHREPORT
#undef USED_FOR_CRASHREPORT
/*end.c*/

View File

@@ -1515,27 +1515,29 @@ void
save_engravings(NHFILE *nhfp)
{
struct engr *ep, *ep2;
unsigned no_more_engr = 0;
unsigned no_more_engr = 0, engr_alloc;
unsigned szeach;
for (ep = head_engr; ep; ep = ep2) {
ep2 = ep->nxt_engr;
if (ep->engr_alloc
&& ep->engr_txt[actual_text][0] && perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &(ep->engr_alloc),
sizeof ep->engr_alloc);
bwrite(nhfp->fd, (genericptr_t) ep,
sizeof (struct engr) + ep->engr_alloc);
}
&& ep->engr_txt[actual_text][0] && update_file(nhfp)) {
engr_alloc = (unsigned) ep->engr_alloc;
szeach = ep->engr_szeach;
Sfo_unsigned(nhfp, &engr_alloc, "engraving-engr_alloc");
Sfo_engr(nhfp, ep, "engraving");
ep->engr_txt[actual_text] = (char *)(ep + 1);
ep->engr_txt[remembered_text] = ep->engr_txt[actual_text] + szeach;
ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] + szeach;
Sfo_char(nhfp, ep->engr_txt[actual_text], "engraving-actual_text", szeach);
Sfo_char(nhfp, ep->engr_txt[remembered_text], "engraving-remembered_text", szeach);
Sfo_char(nhfp, ep->engr_txt[pristine_text], "engraving-pristine_text", szeach);
}
if (release_data(nhfp))
dealloc_engr(ep);
}
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &no_more_engr,
sizeof no_more_engr);
}
if (update_file(nhfp)) {
Sfo_unsigned(nhfp, &no_more_engr, "engraving-engr_alloc");
}
if (release_data(nhfp))
head_engr = 0;
@@ -1546,25 +1548,28 @@ rest_engravings(NHFILE *nhfp)
{
struct engr *ep;
unsigned lth = 0;
unsigned szeach;
head_engr = 0;
while (1) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &lth, sizeof(unsigned));
}
Sfi_unsigned(nhfp, &lth, "engraving-engr_alloc");
if (lth == 0)
return;
ep = newengr(lth);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) ep, sizeof (struct engr) + lth);
}
Sfi_engr(nhfp, ep, "engraving");
szeach = ep->engr_szeach;
ep->nxt_engr = head_engr;
head_engr = ep;
ep->engr_txt[actual_text] = (char *) (ep + 1); /* Andreas Bormann */
ep->engr_txt[remembered_text] = ep->engr_txt[actual_text]
+ ep->engr_szeach;
ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text]
+ ep->engr_szeach;
ep->engr_txt[remembered_text] = ep->engr_txt[actual_text] + szeach;
ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] + szeach;
Sfi_char(nhfp, ep->engr_txt[actual_text],
"engraving-actual_text", (int) szeach);
Sfi_char(nhfp, ep->engr_txt[remembered_text],
"engraving-remembered_text", (int) szeach);
Sfi_char(nhfp, ep->engr_txt[pristine_text],
"engraving-pristine_text", (int) szeach);
while (ep->engr_txt[actual_text][0] == ' ')
ep->engr_txt[actual_text]++;
while (ep->engr_txt[remembered_text][0] == ' ')

View File

@@ -5,6 +5,10 @@
#define NEED_VARARGS
#if defined(WIN32)
#include "win32api.h"
#endif
#include "hack.h"
#include "dlb.h"
@@ -77,6 +81,9 @@ static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME];
#if defined(WIN32)
#include <share.h>
#include <io.h>
#define F_OK 0
#define access _access
#endif
#ifdef AMIGA
@@ -96,11 +103,15 @@ extern void amii_set_text_font(char *, int);
#endif
#define Close close
#ifndef WIN_CE
#ifdef DeleteFile
#undef DeleteFile
#endif
#define DeleteFile unlink
#endif
#ifdef WIN32
/*from windmain.c */
/*from windsys.c */
extern char *translate_path_variables(const char *, char *);
extern boolean get_user_home_folder(char *, size_t);
#endif
#endif
@@ -116,6 +127,7 @@ extern char *translate_path_variables(const char *, char *);
staticfn NHFILE *new_nhfile(void);
staticfn void free_nhfile(NHFILE *);
#ifdef SELECTSAVED
staticfn int QSORTCALLBACK strcmp_wrap(const void *, const void *);
#endif
@@ -130,10 +142,17 @@ staticfn void docompress_file(const char *, boolean);
#if defined(ZLIB_COMP)
staticfn boolean make_compressed_name(const char *, char *);
#endif
staticfn NHFILE *problematic_savefile(int, const char *);
staticfn NHFILE *viable_nhfile(NHFILE *);
#ifdef SELECTSAVED
staticfn int QSORTCALLBACK strcmp_wrap(const void *, const void *);
#endif
staticfn char *set_bonesfile_name(char *, d_level *);
staticfn char *set_bonestemp_name(void);
#ifndef USE_FCNTL
staticfn char *make_lockname(const char *, char *);
#endif
staticfn FILE *fopen_wizkit_file(void);
staticfn void wizkit_addinv(struct obj *);
boolean proc_wizkit_line(char *buf);
@@ -407,7 +426,7 @@ zero_nhfile(NHFILE *nhfp)
{
nhfp->fd = -1;
nhfp->mode = COUNTING;
nhfp->structlevel = FALSE;
nhfp->structlevel = TRUE;
nhfp->fieldlevel = FALSE;
nhfp->addinfo = FALSE;
nhfp->bendian = IS_BIGENDIAN();
@@ -417,6 +436,9 @@ zero_nhfile(NHFILE *nhfp)
nhfp->count = 0;
nhfp->eof = FALSE;
nhfp->fnidx = 0;
nhfp->style.deflt = FALSE;
nhfp->style.binary = TRUE;
nhfp->nhfpconvert = 0;
}
staticfn NHFILE *
@@ -442,6 +464,12 @@ close_nhfile(NHFILE *nhfp)
{
if (nhfp->structlevel && nhfp->fd != -1)
(void) nhclose(nhfp->fd), nhfp->fd = -1;
if (nhfp->fplog)
(void) fprintf(nhfp->fplog, "# closing\n");
if (nhfp->fplog)
(void) fclose(nhfp->fplog);
if (nhfp->fpdebug)
(void) fclose(nhfp->fpdebug);
zero_nhfile(nhfp);
free_nhfile(nhfp);
}
@@ -449,13 +477,11 @@ close_nhfile(NHFILE *nhfp)
void
rewind_nhfile(NHFILE *nhfp)
{
if (nhfp->structlevel) {
#ifdef BSD
(void) lseek(nhfp->fd, 0L, 0);
(void) lseek(nhfp->fd, 0L, 0);
#else
(void) lseek(nhfp->fd, (off_t) 0, 0);
(void) lseek(nhfp->fd, (off_t) 0, 0);
#endif
}
}
staticfn NHFILE *
@@ -465,10 +491,25 @@ viable_nhfile(NHFILE *nhfp)
the pointer to the nethack file descriptor */
if (nhfp) {
/* check for no open file at all,
* not a structlevel legacy file
* not a structlevel legacy file,
* nor a fieldlevel file.
*/
if (nhfp->structlevel && nhfp->fd < 0) {
if (((nhfp->fd == -1) && !nhfp->fpdef)
|| (nhfp->structlevel && nhfp->fd < 0)
|| (nhfp->fieldlevel && !nhfp->fpdef)) {
/* not viable, start the cleanup */
if (nhfp->fieldlevel) {
if (nhfp->fpdef) {
(void) fclose(nhfp->fpdef);
nhfp->fpdef = (FILE *) 0;
}
if (nhfp->fplog) {
(void) fprintf(nhfp->fplog, "# closing, not viable\n");
(void) fclose(nhfp->fplog);
}
if (nhfp->fpdebug)
(void) fclose(nhfp->fpdebug);
}
zero_nhfile(nhfp);
free_nhfile(nhfp);
nhfp = (NHFILE *) 0;
@@ -477,6 +518,20 @@ viable_nhfile(NHFILE *nhfp)
return nhfp;
}
int
nhclose(int fd)
{
int retval = 0;
if (fd >= 0) {
if (close_check(fd))
bclose(fd);
else
retval = close(fd);
}
return retval;
}
/* ---------- BEGIN LEVEL FILE HANDLING ----------- */
/* Construct a file name for a level-type file, which is of the form
@@ -520,6 +575,7 @@ create_levelfile(int lev, char errbuf[])
nhfp->addinfo = FALSE;
nhfp->style.deflt = FALSE;
nhfp->style.binary = TRUE;
nhfp->fnidx = historical;
nhfp->fd = -1;
nhfp->fpdef = (FILE *) 0;
#if defined(MICRO) || defined(WIN32)
@@ -542,6 +598,9 @@ create_levelfile(int lev, char errbuf[])
Sprintf(errbuf,
"Cannot create file \"%s\" for level %d (errno %d).",
gl.lock, lev, errno);
#if defined(MSDOS)
setmode(nhfp->fd, O_BINARY);
#endif
}
nhfp = viable_nhfile(nhfp);
return nhfp;
@@ -566,6 +625,7 @@ open_levelfile(int lev, char errbuf[])
nhfp->style.deflt = FALSE;
nhfp->style.binary = TRUE;
nhfp->ftype = NHF_LEVELFILE;
nhfp->fnidx = historical;
nhfp->fd = -1;
nhfp->fpdef = (FILE *) 0;
}
@@ -583,6 +643,9 @@ open_levelfile(int lev, char errbuf[])
Sprintf(errbuf,
"Cannot open file \"%s\" for level %d (errno %d).",
gl.lock, lev, errno);
#if defined(MSDOS)
setmode(nhfp->fd, O_BINARY);
#endif
}
nhfp = viable_nhfile(nhfp);
return nhfp;
@@ -631,20 +694,6 @@ strcmp_wrap(const void *p, const void *q)
}
#endif
int
nhclose(int fd)
{
int retval = 0;
if (fd >= 0) {
if (close_check(fd))
bclose(fd);
else
retval = close(fd);
}
return retval;
}
/* ---------- END LEVEL FILE HANDLING ----------- */
/* ---------- BEGIN BONES FILE HANDLING ----------- */
@@ -731,10 +780,23 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[])
nhfp = new_nhfile();
if (nhfp) {
nhfp->structlevel = TRUE;
nhfp->fieldlevel = FALSE;
nhfp->ftype = NHF_BONESFILE;
nhfp->mode = WRITING;
nhfp->structlevel = TRUE;
nhfp->fieldlevel = FALSE;
nhfp->addinfo = TRUE;
nhfp->style.deflt = TRUE;
nhfp->style.binary = TRUE;
nhfp->fnidx = historical;
nhfp->fd = -1;
nhfp->fpdef = fopen(file, nhfp->style.binary ? WRBMODE : WRTMODE);
if (nhfp->fpdef) {
#ifdef SAVEFILE_DEBUGGING
nhfp->fpdebug = fopen("create_bonesfile-debug.log", "a");
#endif
} else {
failed = errno;
}
if (nhfp->structlevel) {
#if defined(MICRO) || defined(WIN32)
/* Use O_TRUNC to force the file to be shortened if it already
@@ -751,6 +813,9 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[])
#endif
if (nhfp->fd < 0)
failed = errno;
#if defined(MSDOS)
setmode(nhfp->fd, O_BINARY);
#endif
}
if (failed && errbuf) /* failure explanation */
Sprintf(errbuf, "Cannot create bones \"%s\", id %s (errno %d).",
@@ -814,11 +879,25 @@ open_bonesfile(d_level *lev, char **bonesid)
nhfp->fieldlevel = FALSE;
nhfp->ftype = NHF_BONESFILE;
nhfp->mode = READING;
nhfp->addinfo = TRUE;
nhfp->style.deflt = TRUE;
nhfp->style.binary = (sysopt.bonesformat[0] != cnvascii);
nhfp->fnidx = sysopt.bonesformat[0];
nhfp->fd = -1;
nhfp->fpdef = fopen(fq_bones, nhfp->style.binary ? RDBMODE : RDTMODE);
if (nhfp->fpdef) {
#ifdef SAVEFILE_DEBUGGING
nhfp->fpdebug = fopen("open_bonesfile-debug.log", "a");
#endif
}
if (nhfp->structlevel) {
#ifdef MAC
nhfp->fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE);
#else
nhfp->fd = open(fq_bones, O_RDONLY | O_BINARY, 0);
#endif
#if defined(MSDOS)
setmode(nhfp->fd, O_BINARY);
#endif
}
}
@@ -829,8 +908,11 @@ open_bonesfile(d_level *lev, char **bonesid)
int
delete_bonesfile(d_level *lev)
{
int reslt;
(void) set_bonesfile_name(gb.bones, lev);
return !(unlink(fqname(gb.bones, BONESPREFIX, 0)) < 0);
reslt = unlink(fqname(gb.bones, BONESPREFIX, 0));
return !(reslt < 0);
}
/* assume we're compressing the recently read or created bonesfile, so the
@@ -929,9 +1011,6 @@ set_savefile_name(boolean regularize_it)
if (strlen(SAVE_EXTENSION) > (0) && !overflow) {
if (strlen(gs.SAVEF) + strlen(SAVE_EXTENSION) < (SAVESIZE - 1)) {
Strcat(gs.SAVEF, SAVE_EXTENSION);
#ifdef MSDOS
sfindicator = "";
#endif
} else
overflow = 3;
}
@@ -960,8 +1039,7 @@ set_savefile_name(boolean regularize_it)
void
save_savefile_name(NHFILE *nhfp)
{
if (nhfp->structlevel)
(void) write(nhfp->fd, (genericptr_t) gs.SAVEF, sizeof(gs.SAVEF));
Sfo_char(nhfp, gs.SAVEF, "savefile_name", sizeof(gs.SAVEF));
}
#endif
@@ -999,12 +1077,9 @@ create_savefile(void)
fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0);
nhfp = new_nhfile();
if (nhfp) {
nhfp->structlevel = TRUE;
nhfp->fieldlevel = FALSE;
nhfp->ftype = NHF_SAVEFILE;
nhfp->mode = WRITING;
if (program_state.in_self_recover || do_historical) {
do_historical = TRUE; /* force it */
nhUse(do_historical);
nhfp->structlevel = TRUE;
nhfp->fieldlevel = FALSE;
@@ -1014,19 +1089,24 @@ create_savefile(void)
nhfp->fnidx = historical;
nhfp->fd = -1;
nhfp->fpdef = (FILE *) 0;
}
if (nhfp->structlevel) {
#ifdef SAVEFILE_DEBUGGING
nhfp->fplog = fopen("create-savefile.log", "w");
#endif
}
#if defined(MICRO) || defined(WIN32)
nhfp->fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC,
FCMASK);
#else
#ifdef MAC
nhfp->fd = maccreat(fq_save, SAVE_TYPE);
nhfp->fd = maccreat(fq_save, SAVE_TYPE);
#else
nhfp->fd = creat(fq_save, FCMASK);
nhfp->fd = creat(fq_save, FCMASK);
#endif
#endif /* MICRO || WIN32 */
}
#if defined(MSDOS) || defined(WIN32)
if (nhfp->fd >= 0)
(void) setmode(nhfp->fd, O_BINARY);
#endif
}
#if defined(VMS) && !defined(SECURE)
/*
@@ -1054,8 +1134,6 @@ open_savefile(void)
fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0);
nhfp = new_nhfile();
if (nhfp) {
nhfp->structlevel = TRUE;
nhfp->fieldlevel = FALSE;
nhfp->ftype = NHF_SAVEFILE;
nhfp->mode = READING;
if (program_state.in_self_recover || do_historical) {
@@ -1069,14 +1147,19 @@ open_savefile(void)
nhfp->fnidx = historical;
nhfp->fd = -1;
nhfp->fpdef = (FILE *) 0;
}
if (nhfp->structlevel) {
#ifdef MAC
nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE);
#else
nhfp->fd = open(fq_save, O_RDONLY | O_BINARY, 0);
#ifdef SAVEFILE_DEBUGGING
nhfp->fplog = fopen("open-savefile.log", "w");
#endif
}
#ifdef MAC
nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE);
#else
nhfp->fd = open(fq_save, O_RDONLY | O_BINARY, 0);
#endif
#if defined(MSDOS) || defined(WIN32)
if (nhfp->fd >= 0)
(void) setmode(nhfp->fd, O_BINARY);
#endif
}
}
nhfp = viable_nhfile(nhfp);
return nhfp;
@@ -1086,7 +1169,9 @@ open_savefile(void)
int
delete_savefile(void)
{
(void) unlink(fqname(gs.SAVEF, SAVEPREFIX, 0));
const char *sfname = fqname(gs.SAVEF, SAVEPREFIX, 0);
(void) unlink(sfname);
return 0; /* for restore_saved_game() (ex-xxxmain.c) test */
}
@@ -1096,16 +1181,16 @@ restore_saved_game(void)
{
const char *fq_save;
NHFILE *nhfp = (NHFILE *) 0;
int sfstatus = 0;
set_savefile_name(TRUE);
fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0);
nh_uncompress(fq_save);
if ((nhfp = open_savefile()) != 0) {
if (validate(nhfp, fq_save, FALSE) != 0) {
if ((sfstatus = validate(nhfp, fq_save, FALSE)) != SF_UPTODATE) {
close_nhfile(nhfp);
nhfp = (NHFILE *) 0;
(void) delete_savefile();
nhfp = problematic_savefile(sfstatus, fq_save);
}
}
return nhfp;
@@ -1165,6 +1250,7 @@ plname_from_file(
NHFILE *nhfp;
unsigned ln;
char *result = 0;
int sfstatus = 0;
Strcpy(gs.SAVEF, filename);
#ifdef COMPRESS_EXTENSION
@@ -1179,7 +1265,8 @@ plname_from_file(
#endif
nh_uncompress(gs.SAVEF);
if ((nhfp = open_savefile()) != 0) {
if (validate(nhfp, filename, without_wait_synch_per_file) == 0) {
if ((sfstatus = validate(nhfp, filename,
without_wait_synch_per_file)) == SF_UPTODATE) {
/* room for "name+role+race+gend+algn X" where the space before
X is actually NUL and X is playmode: one of '-', 'X', or 'D' */
ln = (unsigned) PL_NSIZ_PLUS;
@@ -1403,7 +1490,6 @@ docompress_file(const char *filename, boolean uncomp)
#ifdef TTY_GRAPHICS
boolean istty = WINDOWPORT(tty);
#endif
#ifdef COMPRESS_EXTENSION
xtra = COMPRESS_EXTENSION;
#else
@@ -1752,6 +1838,60 @@ docompress_file(const char *filename, boolean uncomp)
/* ---------- END FILE COMPRESSION HANDLING ----------- */
/* ---------- BEGIN PROBLEMATIC SAVEFILE HANDLING ----------- */
static struct sfstatus_to_msg {
int sfstatus;
const char *msg;
} sf2msg[] = {
{ SF_UPTODATE, "everything matches" },
{ SF_OUTDATED, "outdated savefile" },
{ SF_CRITICAL_BYTE_COUNT_MISMATCH,
"savefile critical byte-count mismatch" },
{ SF_DM_IL32LLP64_ON_ILP32LL64, "Windows x64 savefile on x86" },
{ SF_DM_I32LP64_ON_ILP32LL64, "Unix 64 savefile on x86" },
{ SF_DM_ILP32LL64_ON_I32LP64, "x86 savefile on Unix 64" },
{ SF_DM_ILP32LL64_ON_IL32LLP64, "x86 savefile on Windows x64" },
{ SF_DM_I32LP64_ON_IL32LLP64, "Unix 64 savefile on Windows x64" },
{ SF_DM_IL32LLP64_ON_I32LP64, "Windows x64 savefile on Unix 64" },
{ SF_DM_MISMATCH, "generic savefile mismatch" },
};
staticfn NHFILE *
problematic_savefile(int sfstatus, const char *savefilenm)
{
int i;
NHFILE *nhfp = (NHFILE *) 0;
switch (sfstatus) {
case SF_UPTODATE:
break;
case SF_DM_IL32LLP64_ON_ILP32LL64:
case SF_DM_I32LP64_ON_ILP32LL64:
case SF_DM_ILP32LL64_ON_I32LP64:
case SF_DM_ILP32LL64_ON_IL32LLP64:
case SF_DM_I32LP64_ON_IL32LLP64:
case SF_DM_IL32LLP64_ON_I32LP64:
case SF_DM_MISMATCH:
case SF_OUTDATED:
case SF_CRITICAL_BYTE_COUNT_MISMATCH:
default:
for (i = 0; i < SIZE(sf2msg); ++i) {
if (sf2msg[i].sfstatus == sfstatus) {
raw_printf("\n%s is %s %s\n",
savefilenm,
(sfstatus == SF_OUTDATED) ? "an" : "a",
sf2msg[i].msg);
break;
}
}
}
return nhfp;
}
/* ---------- END PROBLEMATIC SAVEFILE HANDLING ----------- */
/* ---------- BEGIN FILE LOCKING HANDLING ----------- */
#if defined(NO_FILE_LINKS) || defined(USE_FCNTL) /* implies UNIX */
@@ -2413,18 +2553,22 @@ testinglog(const char *filenm, /* ad hoc file name */
#ifdef SELF_RECOVER
/* ---------- BEGIN INTERNAL RECOVER ----------- */
extern uchar critical_sizes[], cscbuf[]; /* version.c */
boolean
recover_savefile(void)
{
NHFILE *gnhfp, *lnhfp, *snhfp;
int lev, savelev, hpid, pltmpsiz;
int lev, savelev, hpid,
pltmpsiz, cscount = get_critical_size_count();
xint8 levc;
struct version_info version_data;
int processed[256];
char savename[SAVESIZE], errbuf[BUFSZ], indicator;
char savename[SAVESIZE], errbuf[BUFSZ], indicator, file_cscount;
char tmpplbuf[PL_NSIZ_PLUS];
const char *savewrite_failure = (const char *) 0;
int ccbresult = 0;
off_t filesz = 0;
for (lev = 0; lev < 256; lev++)
processed[lev] = 0;
@@ -2442,6 +2586,30 @@ recover_savefile(void)
raw_printf("%s\n", errbuf);
return FALSE;
}
filesz = lseek(gnhfp->fd, 0L, SEEK_END);
(void) lseek(gnhfp->fd, 0L, SEEK_SET);
if ((size_t) filesz < (sizeof hpid
+ sizeof lev
+ sizeof savename
+ sizeof indicator
+ sizeof file_cscount
+ sizeof version_data + sizeof pltmpsiz)) {
const char *fq_save;
/* this indicates a .0 file that was created as part of
* recover that did not complete. There could be an intact
* savefile already there. Check for that and return TRUE
* if there is. */
set_savefile_name(TRUE);
fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0);
if (access(fq_save, F_OK) == 0) {
close_nhfile(gnhfp);
delete_levelfile(0);
return TRUE;
} else {
/* savefile doesn't exist, so fall through */
}
}
if (read(gnhfp->fd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
raw_printf("\n%s\n%s\n",
"Checkpoint data incompletely written"
@@ -2463,7 +2631,11 @@ recover_savefile(void)
!= sizeof savename)
|| (read(gnhfp->fd, (genericptr_t) &indicator, sizeof indicator)
!= sizeof indicator)
|| ((ccbresult = compare_critical_bytes(gnhfp)) != 0)
|| (read(gnhfp->fd, (genericptr_t) &file_cscount, sizeof file_cscount)
!= sizeof file_cscount)
|| (file_cscount <= cscount
&& read(gnhfp->fd, (genericptr_t) &cscbuf, file_cscount)
!= file_cscount)
|| (read(gnhfp->fd, (genericptr_t) &version_data, sizeof version_data)
!= sizeof version_data)
|| (read(gnhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
@@ -2476,7 +2648,9 @@ recover_savefile(void)
}
/* save file should contain:
* format indicator and critical_bytes
* 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)
@@ -2486,6 +2660,7 @@ recover_savefile(void)
*/
/*
*
* Set a flag for the savefile routines to know the
* circumstances and act accordingly:
* program_state.in_self_recover
@@ -2509,21 +2684,19 @@ recover_savefile(void)
}
store_version(snhfp);
if (savewrite_failure)
goto cleanup;
if (snhfp->structlevel) {
if (write(snhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
!= sizeof pltmpsiz)
savewrite_failure = "player name size";
}
/* TODO: this is not a single byte, so a big-endian byte swap
* might be necessary here, if anyone is concerned about big-endian */
Sfo_int(snhfp, &pltmpsiz, "plname-size");
savewrite_failure = (const char *) 0;
if (savewrite_failure)
goto cleanup;
if (snhfp->structlevel) {
if (write(snhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz)
savewrite_failure = "player name";
}
Sfo_char(snhfp, tmpplbuf, "plname", pltmpsiz);
savewrite_failure = (const char *) 0;
if (savewrite_failure)
goto cleanup;
@@ -3173,7 +3346,6 @@ Death_quote(char *buf, int bufsz)
}
/* ---------- END TRIBUTE ----------- */
#ifdef LIVELOG
#define LLOG_SEP "\t" /* livelog field separator, as a string literal */
#define LLOG_EOL "\n" /* end-of-line, for abstraction consistency */

View File

@@ -953,5 +953,54 @@ copy_bytes(int ifd, int ofd)
} while (nfrom == BUFSIZ);
return TRUE;
}
#define MAX_D 5
struct datamodel_information {
int sz[MAX_D];
const char *datamodel;
};
static struct datamodel_information dm[] = {
{ { (int) sizeof(short), (int) sizeof(int), (int) sizeof(long),
(int) sizeof(long long), (int) sizeof(genericptr_t) },
"" },
{ { 2, 4, 4, 8, 4 }, "ILP32LL64" }, /* Windows, Unix x86 */
{ { 2, 4, 4, 8, 8 }, "IL32LLP64" }, /* Windows x64 */
{ { 2, 4, 8, 8, 8 }, "I32LP64" }, /* Unix 64-bit */
{ { 2, 8, 8, 8, 8 }, "ILP64" }, /* HAL, SPARC64 */
};
const char *
datamodel(void)
{
int i, j, matchcount;
static const char *unknown = "Unknown";
for (i = 1; i < SIZE(dm); ++i) {
matchcount = 0;
for (j = 0; j < MAX_D; ++j) {
if (dm[0].sz[j] == dm[i].sz[j])
++matchcount;
}
if (matchcount == MAX_D)
return dm[i].datamodel;
}
return unknown;
}
const char *
what_datamodel_is_this(int szshort, int szint, int szlong, int szll,
int szptr)
{
int i;
static const char *unknown = "Unknown";
for (i = 1; i < SIZE(dm); ++i) {
if (szshort == dm[i].sz[0] && szint == dm[i].sz[1]
&& szlong == dm[i].sz[2] && szll == dm[i].sz[3]
&& szptr == dm[i].sz[4])
return dm[i].datamodel;
}
return unknown;
}
#undef MAX_D
/*hacklib.c*/

View File

@@ -429,11 +429,9 @@ save_light_sources(NHFILE *nhfp, int range)
discard_flashes();
gv.vision_full_recalc = 0;
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
count = maybe_write_ls(nhfp, range, FALSE);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfo_int(nhfp, &count, "lightsource-count");
actual = maybe_write_ls(nhfp, range, TRUE);
if (actual != count)
panic("counted %d light sources, wrote %d! [range=%d]", count,
@@ -482,20 +480,17 @@ restore_light_sources(NHFILE *nhfp)
light_source *ls;
/* restore elements */
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfi_int(nhfp, &count, "lightsource-count");
while (count-- > 0) {
ls = (light_source *) alloc(sizeof(light_source));
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) ls, sizeof(light_source));
}
Sfi_ls_t(nhfp, ls, "lightsource");
ls->next = gl.light_base;
gl.light_base = ls;
}
}
DISABLE_WARNING_FORMAT_NONLITERAL
/* to support '#stats' wizard-mode command */
@@ -641,9 +636,7 @@ write_ls(NHFILE *nhfp, light_source *ls)
if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) {
if (ls->flags & LSF_NEEDS_FIXUP) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source));
}
Sfo_ls_t(nhfp, ls, "lightsource");
} else {
/* replace object pointer with id for write, then put back */
arg_save = ls->id;
@@ -695,9 +688,7 @@ write_ls(NHFILE *nhfp, light_source *ls)
/* TODO: cleanup this ls, or skip writing it */
}
ls->flags |= LSF_NEEDS_FIXUP;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source));
}
Sfo_ls_t(nhfp, ls, "lightsource");
ls->id = arg_save;
ls->flags &= ~LSF_NEEDS_FIXUP;
ls->flags &= ~LSF_IS_PROBLEMATIC;
@@ -985,5 +976,4 @@ wiz_light_sources(void)
#undef LSF_SHOW
#undef LSF_NEEDS_FIXUP
#undef mon_is_local
/*light.c*/

View File

@@ -56,6 +56,7 @@
static boolean date_via_env = FALSE;
extern unsigned long md_ignored_features(void);
extern const char *datamodel(void);
char *version_id_string(char *, size_t, const char *) NONNULL NONNULLPTRS;
char *bannerc_string(char *, size_t, const char *) NONNULL NONNULLPTRS;
int case_insensitive_comp(const char *, const char *) NONNULLPTRS;
@@ -87,7 +88,6 @@ staticfn void build_options(void);
staticfn int count_and_validate_winopts(void);
staticfn void opt_out_words(char *, int *) NONNULLPTRS;
staticfn void build_savebones_compat_string(void);
staticfn const char *datamodel(void);
static int idxopttext, done_runtime_opt_init_once = 0;
#define MAXOPT 60 /* 3.7: currently 40 lines get inserted into opttext[] */
@@ -237,41 +237,6 @@ md_ignored_features(void)
);
}
#define MAX_D 5
struct datamodel_information {
int sz[MAX_D];
const char *datamodel;
};
static struct datamodel_information dm[] = {
{ { (int) sizeof(short), (int) sizeof(int), (int) sizeof(long),
(int) sizeof(long long), (int) sizeof(genericptr_t) },
"" },
{ { 2, 4, 4, 8, 4 }, "ILP32LL64" }, /* Windows, Unix x86 */
{ { 2, 4, 4, 8, 8 }, "IL32LLP64" }, /* Windows x64 */
{ { 2, 4, 8, 8, 8 }, "I32LP64" }, /* Unix 64-bit */
{ { 2, 8, 8, 8, 8 }, "ILP64" }, /* HAL, SPARC64 */
};
staticfn const char *
datamodel(void)
{
int i, j, matchcount;
static const char *unknown = "Unknown";
for (i = 1; i < SIZE(dm); ++i) {
matchcount = 0;
for (j = 0; j < MAX_D; ++j) {
if (dm[0].sz[j] == dm[i].sz[j])
++matchcount;
}
if (matchcount == MAX_D)
return dm[i].datamodel;
}
return unknown;
}
#undef MAX_D
staticfn void
make_version(void)
{

View File

@@ -1720,21 +1720,17 @@ save_waterlevel(NHFILE *nhfp)
if (!svb.bbubbles)
return;
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
int n = 0;
for (b = svb.bbubbles; b; b = b->next)
++n;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &n, sizeof(int));
bwrite(nhfp->fd, (genericptr_t) &svx.xmin, sizeof(int));
bwrite(nhfp->fd, (genericptr_t) &svy.ymin, sizeof(int));
bwrite(nhfp->fd, (genericptr_t) &svx.xmax, sizeof(int));
bwrite(nhfp->fd, (genericptr_t) &svy.ymax, sizeof(int));
}
Sfo_int(nhfp, &n, "waterlevel-bubble_count");
Sfo_int(nhfp, &svx.xmin, "waterlevel-xmin");
Sfo_int(nhfp, &svy.ymin, "waterlevel-ymin");
Sfo_int(nhfp, &svx.xmax, "waterlevel-xmax");
Sfo_int(nhfp, &svy.ymax, "waterlevel-ymax");
for (b = svb.bbubbles; b; b = b->next) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) b, sizeof(struct bubble));
}
Sfo_bubble(nhfp, b, "waterlevel-bubble");
}
}
if (release_data(nhfp))
@@ -1748,21 +1744,15 @@ restore_waterlevel(NHFILE *nhfp)
struct bubble *b = (struct bubble *) 0, *btmp;
int i, n = 0;
svb.bbubbles = (struct bubble *) 0;
set_wportal();
if (nhfp->structlevel) {
mread(nhfp->fd,(genericptr_t) &n, sizeof (int));
mread(nhfp->fd,(genericptr_t) &svx.xmin, sizeof (int));
mread(nhfp->fd,(genericptr_t) &svy.ymin, sizeof (int));
mread(nhfp->fd,(genericptr_t) &svx.xmax, sizeof (int));
mread(nhfp->fd,(genericptr_t) &svy.ymax, sizeof (int));
}
Sfi_int(nhfp, &n, "waterlevel-bubble_count");
Sfi_int(nhfp, &svx.xmin, "waterlevel-xmin");
Sfi_int(nhfp, &svy.ymin, "waterlevel-ymin");
Sfi_int(nhfp, &svx.xmax, "waterlevel-xmax");
Sfi_int(nhfp, &svy.ymax, "waterlevel-ymax");
for (i = 0; i < n; i++) {
btmp = b;
b = (struct bubble *) alloc((unsigned) sizeof *b);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) b, (unsigned) sizeof *b);
}
Sfi_bubble(nhfp, b, "waterlevel-bubble");
if (btmp) {
btmp->next = b;
b->prev = btmp;

View File

@@ -25,8 +25,10 @@ staticfn void mktemple(void);
staticfn coord *shrine_pos(int);
staticfn struct permonst *morguemon(void);
staticfn struct permonst *squadmon(void);
staticfn void save_room(NHFILE *, struct mkroom *);
staticfn void rest_room(NHFILE *, struct mkroom *);
staticfn boolean invalid_shop_shape(struct mkroom *sroom);
#define sq(x) ((x) * (x))
@@ -845,9 +847,7 @@ save_room(NHFILE *nhfp, struct mkroom *r)
* of writing the whole structure. That is I should not write
* the gs.subrooms pointers, but who cares ?
*/
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom));
}
Sfo_mkroom(nhfp, r, "room-mkroom");
for (i = 0; i < r->nsubrooms; i++) {
save_room(nhfp, r->sbrooms[i]);
}
@@ -862,9 +862,7 @@ save_rooms(NHFILE *nhfp)
short i;
/* First, write the number of rooms */
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svn.nroom, sizeof svn.nroom);
}
Sfo_int(nhfp, &svn.nroom, "room-nroom");
for (i = 0; i < svn.nroom; i++)
save_room(nhfp, &svr.rooms[i]);
}
@@ -874,9 +872,7 @@ rest_room(NHFILE *nhfp, struct mkroom *r)
{
short i;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom));
}
Sfi_mkroom(nhfp, r, "room-mkroom");
for (i = 0; i < r->nsubrooms; i++) {
r->sbrooms[i] = &gs.subrooms[gn.nsubroom];
@@ -894,9 +890,7 @@ rest_rooms(NHFILE *nhfp)
{
short i;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svn.nroom, sizeof svn.nroom);
}
Sfi_int(nhfp, &svn.nroom, "room-nroom");
gn.nsubroom = 0;
for (i = 0; i < svn.nroom; i++) {

View File

@@ -3115,7 +3115,7 @@ muse_unslime(
* Monsters don't start with oil and don't actively pick up oil
* so this may never occur in a real game. (Possible though;
* nymph can steal potions of oil; shapechanger could take on
* nymph form or vacuum up stuff as a g.cube and then eventually
* nymph form or vacuum up stuff as a gel.cube and then eventually
* engage with a green slime.)
*/

View File

@@ -1264,6 +1264,8 @@ get_nh_lua_variables(void)
RESTORE_WARNING_UNREACHABLE_CODE
/* char *lua_data; */
/* save nh_lua_variables table to file */
void
save_luadata(NHFILE *nhfp)
@@ -1274,11 +1276,8 @@ save_luadata(NHFILE *nhfp)
if (!lua_data)
lua_data = dupstr(emptystr);
lua_data_len = Strlen(lua_data) + 1; /* +1: include the terminator */
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &lua_data_len,
(unsigned) sizeof lua_data_len);
bwrite(nhfp->fd, (genericptr_t) lua_data, lua_data_len);
}
Sfo_unsigned(nhfp, &lua_data_len, "luadata-lua_data_len");
Sfo_char(nhfp, lua_data, "lua_data", lua_data_len);
free(lua_data);
}
@@ -1288,14 +1287,10 @@ restore_luadata(NHFILE *nhfp)
{
unsigned lua_data_len = 0;
char *lua_data;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &lua_data_len,
(unsigned) sizeof lua_data_len);
}
Sfi_unsigned(nhfp, &lua_data_len, "luadata-lua_data_len");
lua_data = (char *) alloc(lua_data_len);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) lua_data, lua_data_len);
}
Sfi_char(nhfp, lua_data, "luadata", lua_data_len);
if (!gl.luacore)
l_nhcore_init();
luaL_loadstring(gl.luacore, lua_data);

View File

@@ -375,22 +375,15 @@ savenames(NHFILE *nhfp)
int i;
unsigned int len;
if (perform_bwrite(nhfp)) {
for (i = 0; i < (MAXOCLASSES + 2); ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svb.bases[i], sizeof (int));
}
if (update_file(nhfp)) {
for (i = 0; i < (MAXOCLASSES + 2); ++i) {
Sfo_int(nhfp, &svb.bases[i], "names-bases");
}
for (i = 0; i < NUM_OBJECTS; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svd.disco[i], sizeof (short));
}
Sfo_short(nhfp, &svd.disco[i], "names-disco");
}
for (i = 0; i < NUM_OBJECTS; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &objects[i],
sizeof (struct objclass));
}
Sfo_objclass(nhfp, &objects[i], "names-objclass");
}
}
/* as long as we use only one version of Hack we
@@ -398,12 +391,11 @@ savenames(NHFILE *nhfp)
oc_uname for all objects */
for (i = 0; i < NUM_OBJECTS; i++)
if (objects[i].oc_uname) {
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
len = Strlen(objects[i].oc_uname) + 1;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &len, sizeof len);
bwrite(nhfp->fd, (genericptr_t) &objects[i].oc_uname[0], len);
}
Sfo_unsigned(nhfp, &len, "names-len");
Sfo_char(nhfp, objects[i].oc_uname, "names-oc_uname",
(int) len);
}
if (release_data(nhfp)) {
free((genericptr_t) objects[i].oc_uname);
@@ -419,30 +411,19 @@ restnames(NHFILE *nhfp)
unsigned int len = 0;
for (i = 0; i < (MAXOCLASSES + 2); ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svb.bases[i], sizeof(int));
}
Sfi_int(nhfp, &svb.bases[i], "names-bases");
}
for (i = 0; i < NUM_OBJECTS; ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svd.disco[i], sizeof(short));
}
Sfi_short(nhfp, &svd.disco[i], "names-disco");
}
for (i = 0; i < NUM_OBJECTS; ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &objects[i],
sizeof(struct objclass));
}
Sfi_objclass(nhfp, &objects[i], "names-objclass");
}
for (i = 0; i < NUM_OBJECTS; i++) {
if (objects[i].oc_uname) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &len, sizeof len);
}
Sfi_unsigned(nhfp, &len, "names-len");
objects[i].oc_uname = (char *) alloc(len);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &objects[i].oc_uname[0], len);
}
Sfi_char(nhfp, objects[i].oc_uname, "names-oc_uname", (int) len);
}
}
#ifdef TILES_IN_GLYPHMAP

View File

@@ -814,7 +814,7 @@ freeroleoptvals(void)
void
saveoptvals(NHFILE *nhfp)
{
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
char *val;
unsigned len;
int i, j;
@@ -823,11 +823,9 @@ saveoptvals(NHFILE *nhfp)
for (j = 0; j < num_opt_phases; ++j) {
val = roleoptvals[i][j];
len = val ? Strlen(val) + 1 : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &len, sizeof len);
if (val)
bwrite(nhfp->fd, (genericptr_t) val, len);
}
Sfo_unsigned(nhfp, &len, "optvals-len");
if (val)
Sfo_char(nhfp, val, "optvals-val", len);
}
}
if (release_data(nhfp))
@@ -846,10 +844,10 @@ restoptvals(NHFILE *nhfp)
for (i = 0; i < 4; ++i)
for (j = 0; j < num_opt_phases; ++j) {
/* len includes terminating '\0' for non-Null values */
mread(nhfp->fd, (genericptr_t) &len, sizeof len);
Sfi_unsigned(nhfp, &len, "optvals-len");
if (len) {
val = roleoptvals[i][j] = (char *) alloc(len);
mread(nhfp->fd, (genericptr_t) val, len);
Sfi_char(nhfp, val, "opvals-val", (int) len);
} else {
roleoptvals[i][j] = NULL;
}
@@ -7127,6 +7125,8 @@ initoptions_init(void)
boolean have_branch = (nomakedefs.git_branch && *nomakedefs.git_branch);
go.opt_phase = builtin_opt; /* Did I need to move this here? */
/* initialize the function pointers for saving the game */
sf_init();
memcpy(allopt, allopt_init, sizeof(allopt));
determine_ambiguities();
@@ -7777,6 +7777,7 @@ msgtype_free(void)
tmp2 = tmp->next;
free((genericptr_t) tmp->pattern);
regex_free(tmp->regex);
tmp->regex = 0;
free((genericptr_t) tmp);
}
gp.plinemsg_types = (struct plinemsg_type *) 0;

View File

@@ -12,6 +12,7 @@
#define NO_CALLBACK (-1)
void free_region(NhRegion *);
boolean inside_gas_cloud(genericptr, genericptr);
boolean expire_gas_cloud(genericptr, genericptr);
boolean inside_rect(NhRect *, int, int);
@@ -24,7 +25,6 @@ boolean mon_in_region(NhRegion *, struct monst *);
#if 0
NhRegion *clone_region(NhRegion *);
#endif
void free_region(NhRegion *);
void add_region(NhRegion *);
void remove_region(NhRegion *);
@@ -739,72 +739,49 @@ save_regions(NHFILE *nhfp)
int i, j;
unsigned n;
if (!perform_bwrite(nhfp))
if (!update_file(nhfp))
goto skip_lots;
if (nhfp->structlevel) {
/* timestamp */
bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves);
bwrite(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions);
}
/* timestamp */
Sfo_long(nhfp, &svm.moves, "region-tmstamp");
Sfo_int(nhfp, &svn.n_regions, "region-region_count");
for (i = 0; i < svn.n_regions; i++) {
r = gr.regions[i];
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &r->bounding_box,
sizeof (NhRect));
bwrite(nhfp->fd, (genericptr_t) &r->nrects, sizeof (short));
}
Sfo_nhrect(nhfp, &r->bounding_box, "region-bounding_box");
Sfo_short(nhfp, &r->nrects, "region-nrects");
for (j = 0; j < r->nrects; j++) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &r->rects[j],
sizeof (NhRect));
}
Sfo_nhrect(nhfp, &r->rects[j], "region-rect");
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean));
bwrite(nhfp->fd, (genericptr_t) &r->attach_2_m, sizeof (unsigned));
}
Sfo_boolean(nhfp, &r->attach_2_u, "region-attach_2_u");
Sfo_unsigned(nhfp, &r->attach_2_m, "region-attach_2_m");
n = 0;
n = !r->enter_msg ? 0U : (unsigned) strlen(r->enter_msg);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &n, sizeof n);
}
Sfo_unsigned(nhfp, &n, "region-enter_msg_length");
if (n > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) r->enter_msg, n);
}
Sfo_char(nhfp, (char *) r->enter_msg,
"region-enter_msg", (int) n);
}
n = !r->leave_msg ? 0U : (unsigned) strlen(r->leave_msg);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &n, sizeof n);
}
Sfo_unsigned(nhfp, &n, "region-leave_msg_length");
if (n > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) r->leave_msg, n);
}
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &r->ttl, sizeof (long));
bwrite(nhfp->fd, (genericptr_t) &r->expire_f, sizeof (short));
bwrite(nhfp->fd, (genericptr_t) &r->can_enter_f, sizeof (short));
bwrite(nhfp->fd, (genericptr_t) &r->enter_f, sizeof (short));
bwrite(nhfp->fd, (genericptr_t) &r->can_leave_f, sizeof (short));
bwrite(nhfp->fd, (genericptr_t) &r->leave_f, sizeof (short));
bwrite(nhfp->fd, (genericptr_t) &r->inside_f, sizeof (short));
bwrite(nhfp->fd, (genericptr_t) &r->player_flags,
sizeof (unsigned));
bwrite(nhfp->fd, (genericptr_t) &r->n_monst, sizeof (short));
Sfo_char(nhfp, (char *) r->leave_msg, "region-leave_msg", (int) n);
}
Sfo_long(nhfp, &r->ttl, "region-ttl");
Sfo_short(nhfp, &r->expire_f, "region-expire_f");
Sfo_short(nhfp, &r->can_enter_f, "region-can_enter_f");
Sfo_short(nhfp, &r->enter_f, "region-enter_f");
Sfo_short(nhfp, &r->can_leave_f, "region-can_leave_f");
Sfo_short(nhfp, &r->leave_f, "region-leave_f");
Sfo_short(nhfp, &r->inside_f, "region-inside_f");
Sfo_unsigned(nhfp, &r->player_flags, "region-player_flags");
Sfo_short(nhfp, &r->n_monst, "region-monster_count");
for (j = 0; j < r->n_monst; j++) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &r->monsters[j],
sizeof (unsigned));
}
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &r->visible, sizeof (boolean));
bwrite(nhfp->fd, (genericptr_t) &r->glyph, sizeof (int));
bwrite(nhfp->fd, (genericptr_t) &r->arg, sizeof (anything));
Sfo_unsigned(nhfp, &r->monsters[j], "region-monster");
}
Sfo_boolean(nhfp, &r->visible, "region-visible");
Sfo_int(nhfp, &r->glyph, "region-glyph");
Sfo_any(nhfp, &r->arg, "region-arg");
}
skip_lots:
@@ -823,105 +800,77 @@ rest_regions(NHFILE *nhfp)
boolean ghostly = (nhfp->ftype == NHF_BONESFILE);
clear_regions(); /* Just for security */
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &tmstamp, sizeof(tmstamp));
}
Sfi_long(nhfp, &tmstamp, "region-tmstamp");
if (ghostly)
tmstamp = 0;
else
tmstamp = (svm.moves - tmstamp);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions);
}
Sfi_int(nhfp, &svn.n_regions, "region-region_count");
gm.max_regions = svn.n_regions;
if (svn.n_regions > 0)
gr.regions = (NhRegion **) alloc(svn.n_regions * sizeof (NhRegion *));
for (i = 0; i < svn.n_regions; i++) {
r = gr.regions[i] = (NhRegion *) alloc(sizeof (NhRegion));
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &r->bounding_box, sizeof (NhRect));
mread(nhfp->fd, (genericptr_t) &r->nrects, sizeof (short));
}
Sfi_nhrect(nhfp, &r->bounding_box, "region-bounding box");
Sfi_short(nhfp, &r->nrects, "region-nrects");
if (r->nrects > 0)
r->rects = (NhRect *) alloc(r->nrects * sizeof (NhRect));
else
r->rects = (NhRect *) 0;
for (j = 0; j < r->nrects; j++) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &r->rects[j], sizeof(NhRect));
}
}
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean));
mread(nhfp->fd, (genericptr_t) &r->attach_2_m, sizeof (unsigned));
mread(nhfp->fd, (genericptr_t) &n, sizeof n);
Sfi_nhrect(nhfp, &r->rects[j], "region-rect");
}
Sfi_boolean(nhfp, &r->attach_2_u, "region-attach_2_u");
Sfi_unsigned(nhfp, &r->attach_2_m, "region-attach_2_m");
Sfi_unsigned(nhfp, &n, "region-enter_msg_length");
if (n > 0) {
msg_buf = (char *) alloc(n + 1);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) msg_buf, n);
}
Sfi_char(nhfp, msg_buf, "region-enter_msg", n);
msg_buf[n] = '\0';
} else {
msg_buf = (char *) 0;
}
r->enter_msg = (const char *) msg_buf;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &n, sizeof n);
}
if (n > 0) {
Sfi_unsigned(nhfp, &n, "region-leave_msg_length");
if (n > 0) {
msg_buf = (char *) alloc(n + 1);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) msg_buf, n);
}
Sfi_char(nhfp, msg_buf, "region-leave_msg", n);
msg_buf[n] = '\0';
} else {
msg_buf = (char *) 0;
}
r->leave_msg = (const char *) msg_buf;
r->leave_msg = (const char *) msg_buf;
} else {
msg_buf = (char *) 0;
}
r->leave_msg = (const char *) msg_buf;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &r->ttl, sizeof(long));
}
Sfi_long(nhfp, &r->ttl, "region-ttl");
/* check for expired region */
if (r->ttl >= 0L)
r->ttl = (r->ttl > tmstamp) ? r->ttl - tmstamp : 0L;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &r->expire_f, sizeof (short));
mread(nhfp->fd, (genericptr_t) &r->can_enter_f, sizeof (short));
mread(nhfp->fd, (genericptr_t) &r->enter_f, sizeof (short));
mread(nhfp->fd, (genericptr_t) &r->can_leave_f, sizeof (short));
mread(nhfp->fd, (genericptr_t) &r->leave_f, sizeof (short));
mread(nhfp->fd, (genericptr_t) &r->inside_f, sizeof (short));
mread(nhfp->fd, (genericptr_t) &r->player_flags,
sizeof (unsigned));
}
Sfi_short(nhfp, &r->expire_f, "region-expire_f");
Sfi_short(nhfp, &r->can_enter_f, "region-can_enter_f");
Sfi_short(nhfp, &r->enter_f, "region-enter_f");
Sfi_short(nhfp, &r->can_leave_f, "region-can_leave_f");
Sfi_short(nhfp, &r->leave_f, "region-leave_f");
Sfi_short(nhfp, &r->inside_f, "region-inside_f");
Sfi_unsigned(nhfp, &r->player_flags, "region-player_flags");
if (ghostly) { /* settings pertained to old player */
clear_hero_inside(r);
clear_heros_fault(r);
}
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &r->n_monst, sizeof (short));
}
Sfi_short(nhfp, &r->n_monst, "region-monster_count");
if (r->n_monst > 0)
r->monsters = (unsigned *) alloc(r->n_monst * sizeof (unsigned));
else
r->monsters = (unsigned *) 0;
r->max_monst = r->n_monst;
for (j = 0; j < r->n_monst; j++) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &r->monsters[j],
sizeof(unsigned));
}
}
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &r->visible, sizeof (boolean));
mread(nhfp->fd, (genericptr_t) &r->glyph, sizeof (int));
mread(nhfp->fd, (genericptr_t) &r->arg, sizeof (anything));
Sfi_unsigned(nhfp, &r->monsters[j], "region-monster");
}
Sfi_boolean(nhfp, &r->visible, "region-visible");
Sfi_int(nhfp, &r->glyph, "region-glyph");
Sfi_any(nhfp, &r->arg, "region-arg");
}
/* remove expired regions, do not trigger the expire_f callback (yet!);
also update monster lists if this data is coming from a bones file */

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*/

View File

@@ -584,10 +584,10 @@ init_oracles(dlb *fp)
(void) dlb_fgets(line, sizeof line, fp);
if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) {
svo.oracle_cnt = (unsigned) cnt;
go.oracle_loc = (unsigned long *) alloc((unsigned) cnt * sizeof(long));
svo.oracle_loc = (unsigned long *) alloc((unsigned) cnt * sizeof(long));
for (i = 0; i < cnt; i++) {
(void) dlb_fgets(line, sizeof line, fp);
(void) sscanf(line, "%5lx\n", &go.oracle_loc[i]);
(void) sscanf(line, "%5lx\n", &svo.oracle_loc[i]);
}
}
return;
@@ -598,17 +598,11 @@ save_oracles(NHFILE *nhfp)
{
int i;
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svo.oracle_cnt,
sizeof svo.oracle_cnt);
}
if (update_file(nhfp)) {
Sfo_unsigned(nhfp, &svo.oracle_cnt, "oracle-oracle_cnt");
if (svo.oracle_cnt) {
for (i = 0; (unsigned) i < svo.oracle_cnt; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &go.oracle_loc[i],
sizeof (unsigned long));
}
Sfo_ulong(nhfp, &svo.oracle_loc[i], "oracle-oracle_loc");
}
}
}
@@ -616,9 +610,8 @@ save_oracles(NHFILE *nhfp)
if (svo.oracle_cnt) {
svo.oracle_cnt = 0, go.oracle_flg = 0;
}
if (go.oracle_loc) {
free((genericptr_t) go.oracle_loc);
go.oracle_loc = 0;
if (svo.oracle_loc) {
free((genericptr_t) svo.oracle_loc);
}
}
}
@@ -628,18 +621,12 @@ restore_oracles(NHFILE *nhfp)
{
int i;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svo.oracle_cnt,
sizeof svo.oracle_cnt);
}
Sfi_unsigned(nhfp, &svo.oracle_cnt, "oracle-oracle_cnt");
if (svo.oracle_cnt) {
go.oracle_loc =
svo.oracle_loc =
(unsigned long *) alloc(svo.oracle_cnt * sizeof (unsigned long));
for (i = 0; (unsigned) i < svo.oracle_cnt; ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &go.oracle_loc[i],
sizeof (unsigned long));
}
Sfi_ulong(nhfp, &svo.oracle_loc[i], "oracle-oracle_loc");
}
go.oracle_flg = 1; /* no need to call init_oracles() */
}
@@ -672,9 +659,9 @@ outoracle(boolean special, boolean delphi)
if (svo.oracle_cnt <= 1 && !special)
goto close_oracles; /*(shouldn't happen)*/
oracle_idx = special ? 0 : rnd((int) svo.oracle_cnt - 1);
(void) dlb_fseek(oracles, (long) go.oracle_loc[oracle_idx], SEEK_SET);
(void) dlb_fseek(oracles, (long) svo.oracle_loc[oracle_idx], SEEK_SET);
if (!special) /* move offset of very last one into this slot */
go.oracle_loc[oracle_idx] = go.oracle_loc[--svo.oracle_cnt];
svo.oracle_loc[oracle_idx] = svo.oracle_loc[--svo.oracle_cnt];
tmpwin = create_nhwindow(NHW_TEXT);
if (delphi)

View File

@@ -115,6 +115,7 @@ dosave0(void)
clear_nhwindow(WIN_MESSAGE);
There("seems to be an old save file.");
if (y_n("Overwrite the old file?") == 'n') {
//nh_sfconvert(fq_save);
nh_compress(fq_save);
goto done;
}
@@ -129,6 +130,10 @@ dosave0(void)
(void) delete_savefile(); /* ab@unido */
goto done;
}
if (nhfp && nhfp->fplog) {
/* (void) fprintf(nhfp->fplog, "# just opened\n"); */
nhfp->count = 0L;
}
vision_recalc(2); /* shut down vision to prevent problems
in the event of an impossible() call */
@@ -150,8 +155,6 @@ dosave0(void)
#endif
nhfp->mode = WRITING | FREEING;
store_version(nhfp);
if (nhfp && nhfp->fplog)
(void) fprintf(nhfp->fplog, "# post-validation\n");
store_plname_in_file(nhfp);
/* savelev() might save uball and uchain, releasing their memory if
FREEING, so we need to check their status now; if hero is swallowed,
@@ -206,9 +209,7 @@ dosave0(void)
}
getlev(onhfp, svh.hackpid, ltmp);
close_nhfile(onhfp);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &ltmp, sizeof ltmp); /* lvl no. */
}
Sfo_xint8(nhfp, &ltmp, "gamestate-level_number");
savelev(nhfp, ltmp); /* actual level*/
delete_levelfile(ltmp);
}
@@ -220,6 +221,7 @@ dosave0(void)
/* get rid of current level --jgm */
delete_levelfile(ledger_no(&u.uz));
delete_levelfile(0);
///nh_sfconvert(fq_save);
nh_compress(fq_save);
/* this should probably come sooner... */
program_state.something_worth_saving = 0;
@@ -239,28 +241,23 @@ save_gamelog(NHFILE *nhfp)
while (tmp) {
tmp2 = tmp->next;
if (perform_bwrite(nhfp)) {
if (nhfp->mode & (COUNTING | WRITING)) {
slen = Strlen(tmp->text);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &slen, sizeof slen);
bwrite(nhfp->fd, (genericptr_t) tmp->text, slen);
bwrite(nhfp->fd, (genericptr_t) tmp,
sizeof (struct gamelog_line));
}
Sfo_int(nhfp, &slen, "gamelog-length");
Sfo_char(nhfp, tmp->text, "gamelog-gamelog_text", slen);
Sfo_gamelog_line(nhfp, tmp, "gamelog-gamelog_line");
}
if (release_data(nhfp)) {
if (nhfp->mode & FREEING) {
free((genericptr_t) tmp->text);
free((genericptr_t) tmp);
}
tmp = tmp2;
}
if (perform_bwrite(nhfp)) {
if (nhfp->mode & (COUNTING | WRITING)) {
slen = -1;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &slen, sizeof slen);
}
Sfo_int(nhfp, &slen, "gamelog-length");
}
if (release_data(nhfp))
if (nhfp->mode & FREEING)
gg.gamelog = NULL;
}
@@ -272,21 +269,16 @@ savegamestate(NHFILE *nhfp)
program_state.saving++; /* caller should/did already set this... */
uid = (unsigned long) getuid();
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid);
bwrite(nhfp->fd, (genericptr_t) &svc.context, sizeof svc.context);
bwrite(nhfp->fd, (genericptr_t) &flags, sizeof flags);
}
Sfo_ulong(nhfp, &uid, "gamestate-uid");
Sfo_context_info(nhfp, &svc.context, "gamestate-context");
Sfo_flag(nhfp, &flags, "gamestate-flags");
urealtime.finish_time = getnow();
urealtime.realtime += timet_delta(urealtime.finish_time,
urealtime.start_timing);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &u, sizeof u);
bwrite(nhfp->fd, yyyymmddhhmmss(ubirthday), 14);
bwrite(nhfp->fd, (genericptr_t) &urealtime.realtime,
sizeof urealtime.realtime);
bwrite(nhfp->fd, yyyymmddhhmmss(urealtime.start_timing), 14);
}
Sfo_you(nhfp, &u, "gamestate-you");
Sfo_char(nhfp, yyyymmddhhmmss(ubirthday), "gamestate-ubirthday", 14);
Sfo_long(nhfp, &urealtime.realtime, "gamestate-realtime");
Sfo_char(nhfp, yyyymmddhhmmss(urealtime.start_timing), "gamestate-start_timing", 14);
/* this is the value to use for the next update of urealtime.realtime */
urealtime.start_timing = urealtime.finish_time;
save_killers(nhfp);
@@ -307,32 +299,20 @@ savegamestate(NHFILE *nhfp)
if (release_data(nhfp))
gm.migrating_mons = (struct monst *) 0;
for (i = 0; i < NUMMONS; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svm.mvitals[i],
sizeof (struct mvitals));
}
Sfo_mvitals(nhfp, &svm.mvitals[i], "gamestate-mvitals");
}
save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp),
save_dungeon(nhfp, (boolean) !!update_file(nhfp),
(boolean) !!release_data(nhfp));
savelevchn(nhfp);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves);
bwrite(nhfp->fd, (genericptr_t) &svq.quest_status,
sizeof svq.quest_status);
}
Sfo_long(nhfp, &svm.moves, "gamestate-moves");
Sfo_q_score(nhfp, &svq.quest_status, "gamestate-quest_status");
for (i = 0; i < (MAXSPELL + 1); ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svs.spl_book[i],
sizeof(struct spell));
}
Sfo_spell(nhfp, &svs.spl_book[i], "gamestate-spl_book");
}
save_artifacts(nhfp);
save_oracles(nhfp);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) svp.pl_character,
sizeof svp.pl_character);
bwrite(nhfp->fd, (genericptr_t) svp.pl_fruit, sizeof svp.pl_fruit);
}
Sfo_char(nhfp, svp.pl_character, "gamestate-pl_character", sizeof svp.pl_character);
Sfo_char(nhfp, svp.pl_fruit, "gamestate-pl_fruit", sizeof svp.pl_fruit);
savefruitchn(nhfp);
savenames(nhfp);
save_msghistory(nhfp);
@@ -391,9 +371,7 @@ savestateinlock(void)
return;
}
if (nhfp->structlevel) {
(void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid);
}
Sfi_int(nhfp, &hpid, "gamestate-hackpid");
if (svh.hackpid != hpid) {
Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!",
hpid, svh.hackpid);
@@ -416,16 +394,11 @@ savestateinlock(void)
return;
}
nhfp->mode = WRITING;
if (nhfp->structlevel)
(void) write(nhfp->fd, (genericptr_t) &svh.hackpid,
sizeof svh.hackpid);
Sfo_int(nhfp, &svh.hackpid, "gamestate-hackpid");
if (flags.ins_chkpt) {
int currlev = ledger_no(&u.uz);
if (nhfp->structlevel) {
(void) write(nhfp->fd, (genericptr_t) &currlev,
sizeof currlev);
}
Sfo_int(nhfp, &currlev, "gamestate-savestateinlock");
save_savefile_name(nhfp);
store_version(nhfp);
store_plname_in_file(nhfp);
@@ -453,7 +426,7 @@ savelev(NHFILE *nhfp, xint8 lev)
if not, we need to set it for save_bubbles(); caveat: if the
player quits during character selection, u.uz won't be set yet
but we'll be called during run-down */
if (set_uz_save && perform_bwrite(nhfp)) {
if (set_uz_save && (nhfp->mode & (COUNTING | WRITING))) {
if (u.uz.dnum == 0 && u.uz.dlevel == 0) {
program_state.something_worth_saving = 0;
panic("savelev: where are we?");
@@ -511,10 +484,8 @@ savelev_core(NHFILE *nhfp, xint8 lev)
if (lev >= 0 && lev <= maxledgerno())
svl.level_info[lev].flags |= VISITED;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid);
bwrite(nhfp->fd, (genericptr_t) &lev, sizeof lev);
}
Sfo_int(nhfp, &svh.hackpid, "gamestate-hackpid");
Sfo_xint8(nhfp, &lev, "gamestate-dlvl");
}
/* bones info comes before level data; the intent is for an external
@@ -528,35 +499,25 @@ savelev_core(NHFILE *nhfp, xint8 lev)
goto skip_lots;
savelevl(nhfp);
for (c = 0; c < COLNO; ++c)
for (c = 0; c < COLNO; ++c) {
for (r = 0; r < ROWNO; ++r) {
bwrite(nhfp->fd, (genericptr_t) &svl.lastseentyp[c][r],
sizeof(schar));
Sfo_schar(nhfp, &svl.lastseentyp[c][r], "lastseentyp");
}
/* svm.moves below will actually be read back into svo.omoves on restore */
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves);
}
/* svm.moves will actually be read back into svo.omoves on restore */
Sfo_long(nhfp, &svm.moves, "lev-timestmp");
save_stairs(nhfp);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svu.updest, sizeof(dest_area));
bwrite(nhfp->fd, (genericptr_t) &svd.dndest, sizeof(dest_area));
bwrite(nhfp->fd, (genericptr_t) &svl.level.flags,
sizeof svl.level.flags);
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svd.doors_alloc,
sizeof svd.doors_alloc);
}
Sfo_dest_area(nhfp, &svu.updest, "lev-updest");
Sfo_dest_area(nhfp, &svd.dndest, "lev-dndest");
Sfo_levelflags(nhfp, &svl.level.flags, "lev-level_flags");
Sfo_int(nhfp, &svd.doors_alloc, "lev-doors_alloc");
/* don't rely on underlying write() behavior to write
* nothing if count arg is 0, just skip it */
* nothing if count arg is 0, just skip it */
if (svd.doors_alloc) {
tmpc = svd.doors;
for (i = 0; i < svd.doors_alloc; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) tmpc,
sizeof (coord));
}
Sfo_nhcoord(nhfp, tmpc, "lev-doors");
tmpc++;
}
}
@@ -602,11 +563,8 @@ savelevl(NHFILE *nhfp)
for (x = 0; x < COLNO; x++) {
for (y = 0; y < ROWNO; y++) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &levl[x][y],
sizeof(struct rm));
}
}
Sfo_rm(nhfp, &levl[x][y], "location-rm");
}
}
return;
}
@@ -626,9 +584,12 @@ save_bubbles(NHFILE *nhfp, xint8 lev)
bbubbly = 0;
if (lev == ledger_no(&water_level) || lev == ledger_no(&air_level))
bbubbly = lev; /* non-zero */
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &bbubbly, sizeof bbubbly);
}
if (update_file(nhfp))
Sfo_xint8(nhfp, &bbubbly, "bubbles-bbubbly");
#if 0
if (nhfp->structlevel)
xxwrite(nhfp->fd, (genericptr_t) &bbubbly, sizeof bbubbly);
#endif
if (bbubbly)
save_waterlevel(nhfp); /* save air bubbles or clouds */
@@ -642,18 +603,14 @@ savecemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr)
int flag;
flag = *cemeteryaddr ? 0 : -1;
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &flag, sizeof flag);
}
if (update_file(nhfp)) {
Sfo_int(nhfp, &flag, "cemetery-cemetery_flag");
}
nextbones = *cemeteryaddr;
while ((thisbones = nextbones) != 0) {
nextbones = thisbones->next;
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) thisbones, sizeof *thisbones);
}
if (update_file(nhfp)) {
Sfo_cemetery(nhfp, thisbones, "cemetery-bonesinfo");
}
if (release_data(nhfp))
free((genericptr_t) thisbones);
@@ -671,16 +628,12 @@ savedamage(NHFILE *nhfp)
damageptr = svl.level.damagelist;
for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
xl++;
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &xl, sizeof xl);
}
if (update_file(nhfp)) {
Sfo_unsigned(nhfp, &xl, "damage-damage_count");
}
while (damageptr) {
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) damageptr, sizeof *damageptr);
}
if (update_file(nhfp)) {
Sfo_damage(nhfp, damageptr, "damage");
}
tmp_dam = damageptr;
damageptr = damageptr->next;
@@ -698,17 +651,15 @@ save_stairs(NHFILE *nhfp)
int buflen = (int) sizeof *stway;
while (stway) {
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
boolean use_relative = (program_state.restoring != REST_GSTATE
&& stway->tolev.dnum == u.uz.dnum);
if (use_relative) {
/* make dlevel relative to current level */
stway->tolev.dlevel -= u.uz.dlevel;
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
bwrite(nhfp->fd, (genericptr_t) stway, sizeof *stway);
}
Sfo_int(nhfp, &buflen, "stairs-staircount");
Sfo_stairway(nhfp, stway, "stairs-stairway");
if (use_relative) {
/* reset stairway dlevel back to absolute */
stway->tolev.dlevel += u.uz.dlevel;
@@ -716,11 +667,9 @@ save_stairs(NHFILE *nhfp)
}
stway = stway->next;
}
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
buflen = -1;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
}
Sfo_int(nhfp, &buflen, "stairs-staircount");
}
}
@@ -755,51 +704,38 @@ save_bc(NHFILE *nhfp)
}
/* save one object;
caveat: this is only for perform_bwrite(); caller handles release_data() */
caveat: this is only for update_file(); caller handles release_data() */
staticfn void
saveobj(NHFILE *nhfp, struct obj *otmp)
{
int buflen, zerobuf = 0;
buflen = (int) sizeof (struct obj);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
bwrite(nhfp->fd, (genericptr_t) otmp, buflen);
}
Sfo_int(nhfp, &buflen, "obj-obj_length");
Sfo_obj(nhfp, otmp, "obj");
if (otmp->oextra) {
buflen = ONAME(otmp) ? (int) strlen(ONAME(otmp)) + 1 : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
}
Sfo_int(nhfp, &buflen, "obj-oname_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) ONAME(otmp), buflen);
}
Sfo_char(nhfp, ONAME(otmp), "obj-oname", buflen);
}
/* defer to savemon() for this one */
if (OMONST(otmp)) {
savemon(nhfp, OMONST(otmp));
} else {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &zerobuf, sizeof zerobuf);
}
Sfo_int(nhfp, &zerobuf, "obj-omonst_length");
}
/* extra info about scroll of mail */
buflen = OMAILCMD(otmp) ? (int) strlen(OMAILCMD(otmp)) + 1 : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
}
Sfo_int(nhfp, &buflen, "obj-omailcmd_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) OMAILCMD(otmp), buflen);
}
Sfo_char(nhfp, OMAILCMD(otmp), "obj-omailcmd", buflen);
}
/* omid used to be indirect via a pointer in oextra but has
become part of oextra itself; 0 means not applicable and
gets saved/restored whenever any other oextra components do */
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &OMID(otmp), sizeof OMID(otmp));
}
Sfo_unsigned(nhfp, &OMID(otmp), "obj-omid");
}
}
@@ -815,7 +751,7 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p)
while (otmp) {
otmp2 = otmp->nobj;
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
saveobj(nhfp, otmp);
}
if (Has_contents(otmp))
@@ -859,10 +795,8 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p)
}
otmp = otmp2;
}
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int));
}
if (update_file(nhfp)) {
Sfo_int(nhfp, &minusone, "obj-obj_length");
}
if (release_data(nhfp)) {
if (is_invent)
@@ -879,80 +813,48 @@ savemon(NHFILE *nhfp, struct monst *mtmp)
mtmp->mtemplit = 0; /* normally clear; if set here then a panic save
* is being written while bhit() was executing */
buflen = (int) sizeof (struct monst);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
bwrite(nhfp->fd, (genericptr_t) mtmp, buflen);
}
Sfo_int(nhfp, &buflen, "monst-monst_length");
Sfo_monst(nhfp, mtmp, "monst");
if (mtmp->mextra) {
buflen = MGIVENNAME(mtmp) ? (int) strlen(MGIVENNAME(mtmp)) + 1 : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
}
Sfo_int(nhfp, &buflen, "monst-mgivenname_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) MGIVENNAME(mtmp), buflen);
}
Sfo_char(nhfp, MGIVENNAME(mtmp), "monst-mgivenname", buflen);
}
buflen = EGD(mtmp) ? (int) sizeof (struct egd) : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
}
Sfo_int(nhfp, &buflen, "monst-egd_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) EGD(mtmp), buflen);
}
Sfo_egd(nhfp, EGD(mtmp), "monst-egd");
}
buflen = EPRI(mtmp) ? (int) sizeof (struct epri) : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
}
Sfo_int(nhfp, &buflen, "monst-epri_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) EPRI(mtmp), buflen);
}
Sfo_epri(nhfp, EPRI(mtmp), "monst-epri");
}
buflen = ESHK(mtmp) ? (int) sizeof (struct eshk) : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int));
}
Sfo_int(nhfp, &buflen, "monst-eshk_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) ESHK(mtmp), buflen);
}
Sfo_eshk(nhfp, ESHK(mtmp), "monst-eshk");
}
buflen = EMIN(mtmp) ? (int) sizeof (struct emin) : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int));
}
Sfo_int(nhfp, &buflen, "monst-emin_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) EMIN(mtmp), buflen);
}
Sfo_emin(nhfp, EMIN(mtmp), "monst-emin");
}
buflen = EDOG(mtmp) ? (int) sizeof (struct edog) : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int));
}
Sfo_int(nhfp, &buflen, "monst-edog_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) EDOG(mtmp), buflen);
}
Sfo_edog(nhfp, EDOG(mtmp), "monst-edog");
}
buflen = EBONES(mtmp) ? (int) sizeof (struct ebones) : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int));
}
Sfo_int(nhfp, &buflen, "monst-ebones_length");
if (buflen > 0) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) EBONES(mtmp), buflen);
}
Sfo_ebones(nhfp, EBONES(mtmp), "monst-ebones");
}
/* mcorpsenm is inline int rather than pointer to something,
so doesn't need to be preceded by a length field */
buflen = (int) MCORPSENM(mtmp);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int));
}
Sfo_int(nhfp, &buflen, "monst-mcorpsenm");
}
}
@@ -964,7 +866,7 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp)
while (mtmp) {
mtmp2 = mtmp->nmon;
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
mtmp->mnum = monsndx(mtmp->data);
if (mtmp->ispriest)
forget_temple_entry(mtmp); /* EPRI() */
@@ -986,10 +888,8 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp)
}
mtmp = mtmp2;
}
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int));
}
if (update_file(nhfp)) {
Sfo_int(nhfp, &minusone, "monst-monst_length");
}
}
@@ -1006,10 +906,8 @@ savetrapchn(NHFILE *nhfp, struct trap *trap)
trap2 = trap->ntrap;
if (use_relative)
trap->dst.dlevel -= u.uz.dlevel; /* make it relative */
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) trap, sizeof *trap);
}
if (update_file(nhfp)) {
Sfo_trap(nhfp, trap, "trap");
}
if (use_relative)
trap->dst.dlevel += u.uz.dlevel; /* reset back to absolute */
@@ -1017,10 +915,8 @@ savetrapchn(NHFILE *nhfp, struct trap *trap)
dealloc_trap(trap);
trap = trap2;
}
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &zerotrap, sizeof zerotrap);
}
if (update_file(nhfp)) {
Sfo_trap(nhfp, &zerotrap, "trap");
}
}
@@ -1038,19 +934,15 @@ savefruitchn(NHFILE *nhfp)
f1 = gf.ffruit;
while (f1) {
f2 = f1->nextf;
if (f1->fid >= 0 && perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) f1, sizeof *f1);
}
if (f1->fid >= 0 && update_file(nhfp)) {
Sfo_fruit(nhfp, f1, "fruit");
}
if (release_data(nhfp))
dealloc_fruit(f1);
f1 = f2;
}
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &zerofruit, sizeof zerofruit);
}
if (update_file(nhfp)) {
Sfo_fruit(nhfp, &zerofruit, "fruit");
}
if (release_data(nhfp))
gf.ffruit = 0;
@@ -1064,17 +956,13 @@ savelevchn(NHFILE *nhfp)
for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev->next)
cnt++;
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &cnt, sizeof cnt);
}
if (update_file(nhfp)) {
Sfo_int(nhfp, &cnt, "levchn-lev_count");
}
for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev2) {
tmplev2 = tmplev->next;
if (perform_bwrite(nhfp)) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) tmplev, sizeof *tmplev);
}
if (update_file(nhfp)) {
Sfo_s_level(nhfp, tmplev, "levchn-s_level");
}
if (release_data(nhfp))
free((genericptr_t) tmplev);
@@ -1107,13 +995,12 @@ store_plname_in_file(NHFILE *nhfp)
assert(hero[PL_NSIZ_PLUS - 1 - 1] == '\0');
hero[PL_NSIZ_PLUS - 1] = wizard ? 'D' : discover ? 'X' : '-';
if (nhfp->structlevel) {
bufoff(nhfp->fd);
/* bwrite() before bufon() uses plain write() */
bwrite(nhfp->fd, (genericptr_t) &plsiztmp, sizeof plsiztmp);
bwrite(nhfp->fd, (genericptr_t) hero, plsiztmp);
if (nhfp->structlevel)
bufoff(nhfp->fd); /* bwrite() before bufon() uses plain write() */
Sfo_int(nhfp, &plsiztmp, "plname-size");
Sfo_char(nhfp, hero, "plname", plsiztmp);
if (nhfp->structlevel)
bufon(nhfp->fd);
}
return;
}
@@ -1121,11 +1008,11 @@ staticfn void
save_msghistory(NHFILE *nhfp)
{
char *msg;
int msgcount = 0, msglen;
int minusone = -1;
int msgcount = 0;
int minusone = -1, msglen;
boolean init = TRUE;
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
/* ask window port for each message in sequence */
while ((msg = getmsghistory(init)) != 0) {
init = FALSE;
@@ -1136,15 +1023,11 @@ save_msghistory(NHFILE *nhfp)
no need to modify msg[] since terminator isn't written */
if (msglen > BUFSZ - 1)
msglen = BUFSZ - 1;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &msglen, sizeof msglen);
bwrite(nhfp->fd, (genericptr_t) msg, msglen);
}
Sfo_int(nhfp, &msglen, "msghistory-length");
Sfo_char(nhfp, msg, "msghistory-msg", msglen);
++msgcount;
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int));
}
Sfo_int(nhfp, &minusone, "msghistory-length");
}
debugpline1("Stored %d messages into savefile.", msgcount);
/* note: we don't attempt to handle release_data() here */
@@ -1261,6 +1144,7 @@ freedynamicdata(void)
#endif
discard_gamelog();
release_runtime_info(); /* build-time options and version stuff */
//free_convert_filenames();
#endif /* FREE_ALL_MEMORY */
if (VIA_WINDOWPORT())
@@ -1275,7 +1159,6 @@ freedynamicdata(void)
/* last, because it frees data that might be used by panic() to provide
feedback to the user; conceivably other freeing might trigger panic */
sysopt_release(); /* SYSCF strings */
return;
}
/*save.c*/

209
src/sfbase.c Normal file
View File

@@ -0,0 +1,209 @@
/* NetHack 3.7 sfbase.c.template $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */
/* Copyright (c) Michael Allison, 2025. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "sfprocs.h"
/* #define DO_DEBUG */
struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS],
zerosfoprocs = {0}, zerosfiprocs = {0};
void sf_log(NHFILE *, const char *, size_t, int);
#define SF_A(dtyp) \
void sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \
{ \
if (nhfp->fplog) \
sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \
if (nhfp->structlevel) { \
(*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \
} \
} \
\
void sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \
{ \
if (nhfp->structlevel) { \
(*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \
} \
if (nhfp->fplog && !nhfp->eof) \
sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \
if (nhfp->eof) \
return; \
if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \
sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \
}
#define SF_C(keyw, dtyp) \
void sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \
{ \
\
if (nhfp->structlevel) { \
(*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \
} \
if (nhfp->fplog && !nhfp->eof) \
sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \
} \
\
void sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \
{ \
if (nhfp->structlevel) { \
(*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \
} \
if (nhfp->fplog && !nhfp->eof) \
sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \
if (nhfp->eof) \
return; \
if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \
sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \
}
#define SF_X(xxx, dtyp) \
void sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \
{ \
if (nhfp->structlevel) { \
(*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \
} \
if (nhfp->fplog && !nhfp->eof) \
sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \
} \
\
void sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \
{ \
if (nhfp->structlevel) { \
(*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \
} \
if (nhfp->fplog && !nhfp->eof) \
sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \
if (nhfp->eof) \
return; \
if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \
sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname, bfsz); \
}
SF_C(struct, arti_info)
SF_C(struct, nhrect)
SF_C(struct, branch)
SF_C(struct, bubble)
SF_C(struct, cemetery)
SF_C(struct, context_info)
SF_C(struct, nhcoord)
SF_C(struct, damage)
SF_C(struct, dest_area)
SF_C(struct, dgn_topology)
SF_C(struct, dungeon)
SF_C(struct, d_level)
SF_C(struct, ebones)
SF_C(struct, edog)
SF_C(struct, egd)
SF_C(struct, emin)
SF_C(struct, engr)
SF_C(struct, epri)
SF_C(struct, eshk)
SF_C(struct, fe)
SF_C(struct, flag)
SF_C(struct, fruit)
SF_C(struct, gamelog_line)
SF_C(struct, kinfo)
SF_C(struct, levelflags)
SF_C(struct, ls_t)
SF_C(struct, linfo)
SF_C(struct, mapseen_feat)
SF_C(struct, mapseen_flags)
SF_C(struct, mapseen_rooms)
SF_C(struct, mkroom)
SF_C(struct, monst)
SF_C(struct, mvitals)
SF_C(struct, obj)
SF_C(struct, objclass)
SF_C(struct, q_score)
SF_C(struct, rm)
SF_C(struct, spell)
SF_C(struct, stairway)
SF_C(struct, s_level)
SF_C(struct, trap)
SF_C(struct, version_info)
SF_C(struct, you)
SF_C(union, any)
SF_A(aligntyp)
SF_A(boolean)
SF_A(coordxy)
SF_A(genericptr)
SF_A(int)
SF_A(int16)
SF_A(int32)
SF_A(int64)
SF_A(long)
SF_A(schar)
SF_A(short)
SF_A(size_t)
SF_A(time_t)
SF_A(uchar)
SF_A(uint16)
SF_A(uint32)
SF_A(uint64)
SF_A(ulong)
SF_A(unsigned)
SF_A(ushort)
SF_A(xint16)
SF_A(xint8)
void
sfo_char(NHFILE *nhfp, char *d_char, const char *myname, int cnt)
{
if (nhfp->structlevel) {
(*sfoprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myname, cnt);
}
if (nhfp->fplog && !nhfp->eof)
sf_log(nhfp, myname, sizeof (char), cnt);
}
void
sfi_char(NHFILE *nhfp, char *d_char, const char *myname, int cnt)
{
if (nhfp->structlevel) {
(*sfiprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myname, cnt);
}
if (nhfp->fplog && !nhfp->eof)
sf_log(nhfp, myname, sizeof (char), cnt);
if (nhfp->eof)
return;
if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert)
sfo_char(nhfp->nhfpconvert, d_char, myname, cnt);
}
SF_X(uint8_t, bitfield)
/* ---------------------------------------------------------------*/
void
sf_log(NHFILE *nhfp, const char *t1, size_t sz, int cnt)
{
FILE *fp = nhfp->fplog;
if (fp) {
(void) fprintf(fp, "%ld %s sz=%zu cnt=%d\n",
nhfp->count++,
t1, sz, cnt);
fflush(fp);
}
}
/*
*----------------------------------------------------------------------------
* initialize the function pointers. These are called from initoptions_init().
*----------------------------------------------------------------------------
*/
void
sf_init(void)
{
sfoprocs[invalid] = zerosfoprocs;
sfiprocs[invalid] = zerosfiprocs;
sfoprocs[historical] = historical_sfo_procs;
sfiprocs[historical] = historical_sfi_procs;
}

View File

@@ -1,9 +1,326 @@
/* NetHack 3.7 sfstruct.c $NHDT-Date: 1606765215 2020/11/30 19:40:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2009. */
/*-Copyright (c) Michael Allison, 2025. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "sfprocs.h"
/* #define SFLOGGING */ /* debugging */
/* historical full struct savings */
#ifdef SAVEFILE_DEBUGGING
#if defined(__GNUC__)
#define DEBUGFORMATSTR64 "%s %s %ld %ld %d\n"
#elif defined(_MSC_VER)
#define DEBUGFORMATSTR64 "%s %s %lld %ld %d\n"
#endif
#endif
#ifdef SFLOGGING
staticfn void logging_finish(void);
#endif
#define SFO_BODY(dt) \
{ \
bwrite(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \
}
#define SFI_BODY(dt) \
{ \
mread(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \
if (restoreinfo.mread_flags == -1) \
nhfp->eof = TRUE; \
}
#define SF_A(dtyp) \
void historical_sfo_##dtyp(NHFILE *, dtyp *d_##dtyp, const char *); \
void historical_sfi_##dtyp(NHFILE *, dtyp *d_##dtyp, const char *); \
\
void historical_sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \
const char *myname UNUSED) \
SFO_BODY(dtyp) \
\
void historical_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \
const char *myname UNUSED) \
SFI_BODY(dtyp)
#define SF_C(keyw, dtyp) \
void historical_sfo_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \
const char *); \
void historical_sfi_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \
const char *); \
\
void historical_sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \
const char *myname UNUSED) \
SFO_BODY(dtyp) \
\
void historical_sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \
const char *myname UNUSED) \
SFI_BODY(dtyp)
#define SF_X(xxx, dtyp) \
void historical_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, const char *, int); \
void historical_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, const char *, int); \
\
void historical_sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \
const char *myname UNUSED, int bflen UNUSED) \
SFO_BODY(dtyp) \
\
void historical_sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \
const char *myname UNUSED, int bflen UNUSED) \
SFI_BODY(dtyp)
SF_C(struct, arti_info)
SF_C(struct, nhrect)
SF_C(struct, branch)
SF_C(struct, bubble)
SF_C(struct, cemetery)
SF_C(struct, context_info)
SF_C(struct, nhcoord)
SF_C(struct, damage)
SF_C(struct, dest_area)
SF_C(struct, dgn_topology)
SF_C(struct, dungeon)
SF_C(struct, d_level)
SF_C(struct, ebones)
SF_C(struct, edog)
SF_C(struct, egd)
SF_C(struct, emin)
SF_C(struct, engr)
SF_C(struct, epri)
SF_C(struct, eshk)
SF_C(struct, fe)
SF_C(struct, flag)
SF_C(struct, fruit)
SF_C(struct, gamelog_line)
SF_C(struct, kinfo)
SF_C(struct, levelflags)
SF_C(struct, ls_t)
SF_C(struct, linfo)
SF_C(struct, mapseen_feat)
SF_C(struct, mapseen_flags)
SF_C(struct, mapseen_rooms)
SF_C(struct, mkroom)
SF_C(struct, monst)
SF_C(struct, mvitals)
SF_C(struct, obj)
SF_C(struct, objclass)
SF_C(struct, q_score)
SF_C(struct, rm)
SF_C(struct, spell)
SF_C(struct, stairway)
SF_C(struct, s_level)
SF_C(struct, trap)
SF_C(struct, version_info)
SF_C(struct, you)
SF_C(union, any)
SF_A(aligntyp)
SF_A(boolean)
SF_A(coordxy)
SF_A(genericptr_t)
SF_A(int)
SF_A(int16)
SF_A(int32)
SF_A(int64)
SF_A(long)
SF_A(schar)
SF_A(short)
SF_A(size_t)
SF_A(time_t)
SF_A(uchar)
SF_A(uint16)
SF_A(uint32)
SF_A(uint64)
SF_A(ulong)
SF_A(unsigned)
SF_A(ushort)
SF_A(xint16)
SF_A(xint8)
void historical_sfo_char(NHFILE *, char *d_char, const char *, int);
void historical_sfi_char(NHFILE *, char *d_char, const char *, int);
void
historical_sfo_char(NHFILE *nhfp, char *d_char,
const char *myname UNUSED, int cnt)
{
bwrite(nhfp->fd, (genericptr_t) d_char, cnt * sizeof (char));
}
void
historical_sfi_char(NHFILE *nhfp, char *d_char,
const char *myname UNUSED, int cnt)
{
mread(nhfp->fd, (genericptr_t) d_char, cnt * sizeof (char));
if (restoreinfo.mread_flags == -1)
nhfp->eof = TRUE;
}
SF_X(uint8_t, bitfield)
struct sf_structlevel_procs historical_sfo_procs = {
"",
/* sf */
{
historical_sfo_arti_info,
historical_sfo_nhrect,
historical_sfo_branch,
historical_sfo_bubble,
historical_sfo_cemetery,
historical_sfo_context_info,
historical_sfo_nhcoord,
historical_sfo_damage,
historical_sfo_dest_area,
historical_sfo_dgn_topology,
historical_sfo_dungeon,
historical_sfo_d_level,
historical_sfo_ebones,
historical_sfo_edog,
historical_sfo_egd,
historical_sfo_emin,
historical_sfo_engr,
historical_sfo_epri,
historical_sfo_eshk,
historical_sfo_fe,
historical_sfo_flag,
historical_sfo_fruit,
historical_sfo_gamelog_line,
historical_sfo_kinfo,
historical_sfo_levelflags,
historical_sfo_ls_t,
historical_sfo_linfo,
historical_sfo_mapseen_feat,
historical_sfo_mapseen_flags,
historical_sfo_mapseen_rooms,
historical_sfo_mkroom,
historical_sfo_monst,
historical_sfo_mvitals,
historical_sfo_obj,
historical_sfo_objclass,
historical_sfo_q_score,
historical_sfo_rm,
historical_sfo_spell,
historical_sfo_stairway,
historical_sfo_s_level,
historical_sfo_trap,
historical_sfo_version_info,
historical_sfo_you,
historical_sfo_any,
historical_sfo_aligntyp,
historical_sfo_boolean,
historical_sfo_coordxy,
historical_sfo_genericptr_t,
historical_sfo_int,
historical_sfo_int16,
historical_sfo_int32,
historical_sfo_int64,
historical_sfo_long,
historical_sfo_schar,
historical_sfo_short,
historical_sfo_size_t,
historical_sfo_time_t,
historical_sfo_uchar,
historical_sfo_uint16,
historical_sfo_uint32,
historical_sfo_uint64,
historical_sfo_ulong,
historical_sfo_unsigned,
historical_sfo_ushort,
historical_sfo_xint16,
historical_sfo_xint8,
historical_sfo_char,
historical_sfo_bitfield,
}
};
struct sf_structlevel_procs historical_sfi_procs = {
"",
/* sf */
{
historical_sfi_arti_info,
historical_sfi_nhrect,
historical_sfi_branch,
historical_sfi_bubble,
historical_sfi_cemetery,
historical_sfi_context_info,
historical_sfi_nhcoord,
historical_sfi_damage,
historical_sfi_dest_area,
historical_sfi_dgn_topology,
historical_sfi_dungeon,
historical_sfi_d_level,
historical_sfi_ebones,
historical_sfi_edog,
historical_sfi_egd,
historical_sfi_emin,
historical_sfi_engr,
historical_sfi_epri,
historical_sfi_eshk,
historical_sfi_fe,
historical_sfi_flag,
historical_sfi_fruit,
historical_sfi_gamelog_line,
historical_sfi_kinfo,
historical_sfi_levelflags,
historical_sfi_ls_t,
historical_sfi_linfo,
historical_sfi_mapseen_feat,
historical_sfi_mapseen_flags,
historical_sfi_mapseen_rooms,
historical_sfi_mkroom,
historical_sfi_monst,
historical_sfi_mvitals,
historical_sfi_obj,
historical_sfi_objclass,
historical_sfi_q_score,
historical_sfi_rm,
historical_sfi_spell,
historical_sfi_stairway,
historical_sfi_s_level,
historical_sfi_trap,
historical_sfi_version_info,
historical_sfi_you,
historical_sfi_any,
historical_sfi_aligntyp,
historical_sfi_boolean,
historical_sfi_coordxy,
historical_sfi_genericptr_t,
historical_sfi_int,
historical_sfi_int16,
historical_sfi_int32,
historical_sfi_int64,
historical_sfi_long,
historical_sfi_schar,
historical_sfi_short,
historical_sfi_size_t,
historical_sfi_time_t,
historical_sfi_uchar,
historical_sfi_uint16,
historical_sfi_uint32,
historical_sfi_uint64,
historical_sfi_ulong,
historical_sfi_unsigned,
historical_sfi_ushort,
historical_sfi_xint16,
historical_sfi_xint8,
historical_sfi_char,
historical_sfi_bitfield,
}
};
/*
* The historical bwrite() and mread() functions follow
*/
#ifdef SAVEFILE_DEBUGGING
static long floc = 0L;
#endif
/*
* historical structlevel savefile writing and reading routines follow.
@@ -28,6 +345,19 @@ static int bw_buffered[MAXFD] = {0,0,0,0,0};
static FILE *bw_FILE[MAXFD] = {0,0,0,0,0};
#endif
#ifdef SFLOGGING
static FILE *ofp[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
char ofnamebuf[80];
static long ocnt = 0L;
static FILE *ifp[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
char ifnamebuf[80];
static long icnt = 0L;
#endif
/*
* Presumably, the fdopen() to allow use of stdio fwrite()
* over write() was done for performance or functionality
@@ -146,6 +476,17 @@ bclose(int fd)
/* return the idx to the pool */
bw_sticky[idx] = -1;
}
#ifdef SFLOGGING
if (fd >= 0 && fd <= SIZE(ofp)) {
if (ofp[fd]) {
fclose(ofp[fd]);
ofp[fd] = 0;
} else if (ifp[fd]) {
fclose(ifp[fd]);
ifp[fd] = 0;
}
}
#endif
return;
}
@@ -171,6 +512,20 @@ bwrite(int fd, const genericptr_t loc, unsigned num)
boolean failed;
int idx = getidx(fd, NOFLG);
#ifdef SFLOGGING
if (fd >= 0 && fd < SIZE(ofp)) {
if (!ofp[fd]) {
Snprintf(ofnamebuf, sizeof ofnamebuf, "bwrite_%02d.log", fd);
ofp[fd] = fopen(ofnamebuf, "w");
}
if (ofp[fd]) {
fprintf(ofp[fd], "%08ld, %08ld, %d\n", ocnt,
ftell(ofp[fd]), num);
ocnt++;
}
}
#endif
if (idx >= 0) {
if (num == 0) {
/* nothing to do; we need a special case to exit early
@@ -209,7 +564,22 @@ bwrite(int fd, const genericptr_t loc, unsigned num)
void
mread(int fd, genericptr_t buf, unsigned len)
{
#if defined(BSD) || defined(ULTRIX)
#ifdef SFLOGGING
if (fd >= 0 && fd < 9) {
if (!ifp[fd]) {
Snprintf(ifnamebuf, sizeof ifnamebuf, "mread_%02d.log", fd);
ifp[fd] = fopen(ifnamebuf, "w");
}
if (ifp[fd]) {
fprintf(ifp[fd], "%08ld, %08ld, %d\n", icnt,
ftell(ifp[fd]), (int) len);
icnt++;
}
}
#endif
#if defined(BSD) || defined(ULTRIX) || defined(WIN32)
#define readLenType int
#else /* e.g. SYSV, __TURBOC__ */
#define readLenType unsigned
@@ -235,3 +605,27 @@ mread(int fd, genericptr_t buf, unsigned len)
}
#ifdef SFLOGGING
staticfn void
logging_finish(void)
{
int i;
for (i = 0; i < SIZE(ofp); ++i) {
if (ofp[i]) {
fclose(ofp[i]);
ofp[i] = 0;
}
}
ocnt = 0L;
for (i = 0; i < SIZE(ifp); ++i) {
if (ifp[i]) {
fclose(ifp[i]);
ifp[i] = 0;
}
}
icnt = 0L;
}
#endif

View File

@@ -99,8 +99,7 @@ sys_early_init(void)
sysopt.check_plname = 0;
sysopt.seduce = 1; /* if it's compiled in, default to on */
sysopt_seduce_set(sysopt.seduce);
/* default to little-endian in 3.7 */
sysopt.saveformat[0] = sysopt.bonesformat[0] = lendian;
sysopt.saveformat[0] = sysopt.bonesformat[0] = historical;
sysopt.accessibility = 0;
#ifdef WIN32
sysopt.portable_device_paths = 0;

View File

@@ -2022,7 +2022,7 @@ print_queue(winid win, timer_element *base)
for (curr = base; curr; curr = curr->next) {
#ifdef VERBOSE_TIMER
Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout,
curr->tid, kind_name(curr->kind),
(long) curr->tid, kind_name(curr->kind),
timeout_funcs[curr->func_index].name,
fmt_ptr((genericptr_t) curr->arg.a_void));
#else
@@ -2496,25 +2496,19 @@ write_timer(NHFILE *nhfp, timer_element *timer)
case TIMER_GLOBAL:
case TIMER_LEVEL:
/* assume no pointers in arg */
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element));
}
Sfo_fe(nhfp, timer, "timer");
break;
case TIMER_OBJECT:
if (timer->needs_fixup) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element));
}
Sfo_fe(nhfp, timer, "timer");
} else {
/* replace object pointer with id */
arg_save.a_obj = timer->arg.a_obj;
timer->arg = cg.zeroany;
timer->arg.a_uint = (arg_save.a_obj)->o_id;
timer->needs_fixup = 1;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element));
}
Sfo_fe(nhfp, timer, "timer");
timer->arg.a_obj = arg_save.a_obj;
timer->needs_fixup = 0;
}
@@ -2522,18 +2516,14 @@ write_timer(NHFILE *nhfp, timer_element *timer)
case TIMER_MONSTER:
if (timer->needs_fixup) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element));
}
Sfo_fe(nhfp, timer, "timer");
} else {
/* replace monster pointer with id */
arg_save.a_monst = timer->arg.a_monst;
timer->arg = cg.zeroany;
timer->arg.a_uint = (arg_save.a_monst)->m_id;
timer->needs_fixup = 1;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element));
}
Sfo_fe(nhfp, timer, "timer");
timer->arg.a_monst = arg_save.a_monst;
timer->needs_fixup = 0;
}
@@ -2665,17 +2655,12 @@ save_timers(NHFILE *nhfp, int range)
timer_element *curr, *prev, *next_timer = 0;
int count;
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
if (range == RANGE_GLOBAL) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &svt.timer_id,
sizeof svt.timer_id);
}
Sfo_ulong(nhfp, &svt.timer_id, "timer-timer_id");
}
count = maybe_write_timer(nhfp, range, FALSE);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfo_int(nhfp, &count, "timer-timer_count");
(void) maybe_write_timer(nhfp, range, TRUE);
}
@@ -2710,22 +2695,14 @@ restore_timers(NHFILE *nhfp, int range, long adjust)
boolean ghostly = (nhfp->ftype == NHF_BONESFILE); /* from a ghost level */
if (range == RANGE_GLOBAL) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &svt.timer_id,
sizeof svt.timer_id);
}
Sfi_ulong(nhfp, &svt.timer_id, "timer-timer_id");
}
/* restore elements */
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfi_int(nhfp, &count, "timer-timer_count");
while (count-- > 0) {
curr = (timer_element *) alloc(sizeof(timer_element));
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) curr, sizeof(timer_element));
}
Sfi_fe(nhfp, curr, "timer");
if (ghostly)
curr->timeout += adjust;
insert_timer(curr);

View File

@@ -69,20 +69,13 @@ hastrack(coordxy x, coordxy y)
void
save_track(NHFILE *nhfp)
{
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
int i;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt);
bwrite(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt);
}
Sfo_int(nhfp, &utcnt, "track-utcnt");
Sfo_int(nhfp, &utpnt, "track-utpnt");
for (i = 0; i < utcnt; i++) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &utrack[i].x,
sizeof utrack[i].x);
bwrite(nhfp->fd, (genericptr_t) &utrack[i].y,
sizeof utrack[i].y);
}
Sfo_nhcoord(nhfp, &utrack[i], "utrack");
}
}
if (release_data(nhfp))
@@ -95,17 +88,13 @@ rest_track(NHFILE *nhfp)
{
int i;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt);
mread(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt);
}
Sfi_int(nhfp, &utcnt, "track-utcnt");
Sfi_int(nhfp, &utpnt, "track-utpnt");
if (utcnt > UTSZ || utpnt > UTSZ)
panic("rest_track: impossible pt counts");
for (i = 0; i < utcnt; i++) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &utrack[i].x, sizeof utrack[i].x);
mread(nhfp->fd, (genericptr_t) &utrack[i].y, sizeof utrack[i].y);
}
Sfi_nhcoord(nhfp, &utrack[i], "utrack");
}
}

View File

@@ -373,6 +373,10 @@ check_version(
#endif
complain = FALSE; /* 'complain' requires 'filename' for pline("%s") */
}
if ((version_data->feature_set & SFCTOOL_BIT) != 0) {
gc.converted_savefile_loaded = TRUE;
version_data->feature_set &= ~(SFCTOOL_BIT);
}
if (
#ifdef VERSION_COMPATIBILITY /* patchlevel.h */
version_data->incarnation < VERSION_COMPATIBILITY
@@ -421,13 +425,11 @@ store_version(NHFILE *nhfp)
bufoff(nhfp->fd);
store_critical_bytes(nhfp);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &version_data,
(unsigned) (sizeof version_data));
}
Sfo_version_info(nhfp, (struct version_info *) &version_data,
"version_info");
if (nhfp->structlevel)
bufon(nhfp->fd);
bufon(nhfp->fd);
return;
}
@@ -661,90 +663,170 @@ store_critical_bytes(NHFILE *nhfp)
if (nhfp->mode & WRITING) {
indicate = (nhfp->structlevel) ? 'h'
: (nhfp->fnidx == ascii) ? 'a'
: 'l';
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &indicate,
(unsigned) sizeof indicate);
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &csc_count,
(unsigned) sizeof csc_count);
}
: (nhfp->fnidx == cnvascii) ? 'a'
: '?';
Sfo_char(nhfp, &indicate, "indicate-format", 1);
Sfo_char(nhfp, &csc_count, "count-critical_sizes", 1);
cnt = (int) csc_count;
for (i = 0; i < cnt; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &critical_sizes[i].ucsize,
(unsigned) sizeof (uchar));
}
Sfo_uchar(nhfp, &critical_sizes[i].ucsize, "critical_sizes");
}
}
}
/* this used to be based on file date and somewhat OS-dependent,
but now examines the initial part of the file's contents */
boolean
* but now examines the initial part of the file's contents.
*
* returns:
*
* 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
*/
int
uptodate(NHFILE *nhfp, const char *name, unsigned long utdflags)
{
struct version_info vers_info;
char indicator;
int sfstatus = 0, idx_1st_mismatch = 0;
boolean quietly = (utdflags & UTD_QUIETLY) != 0;
boolean verbose = name ? TRUE : FALSE;
int ccbresult = 0;
/* int you_size = (int) sizeof (struct you); */
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &indicator, sizeof indicator);
}
if ((ccbresult = compare_critical_bytes(nhfp)) != 0) {
if (ccbresult > 0) {
raw_printf("compare of critical bytes failed at %d (%s).",
critical_sizes[ccbresult].ucsize,
critical_sizes[ccbresult].nm);
Sfi_char(nhfp, &indicator, "indicate-format", 1);
if ((sfstatus = compare_critical_bytes(nhfp, &idx_1st_mismatch, utdflags))
!= SF_UPTODATE) {
if (sfstatus > 0 && idx_1st_mismatch) {
if (!quietly)
raw_printf("comparison of critical bytes mismatched at %d (%s).",
critical_sizes[idx_1st_mismatch].ucsize,
critical_sizes[idx_1st_mismatch].nm);
}
return FALSE;
return sfstatus;
}
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &vers_info, sizeof vers_info);
}
Sfi_version_info(nhfp, &vers_info, "version_info");
if (!check_version(&vers_info, name, verbose, utdflags)) {
if (verbose) {
if ((utdflags & UTD_WITHOUT_WAITSYNCH_PERFILE) == 0)
wait_synch();
}
return FALSE;
return SF_OUTDATED;
}
return TRUE;
return SF_UPTODATE;
}
/*
* returns:
*
* 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
*/
int
compare_critical_bytes(NHFILE *nhfp)
compare_critical_bytes(NHFILE *nhfp, int *idx_1st_mismatch, unsigned long utdflags)
{
char active_csc_count = (char) SIZE(critical_sizes),
file_csc_count = 0;
int i, cnt = (int) active_csc_count;
file_csc_count;
int i, cnt = (int) active_csc_count,
dmmismatch = SF_DM_MISMATCH;
boolean quietly = (utdflags & UTD_QUIETLY) != 0;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &file_csc_count,
sizeof file_csc_count);
}
Sfi_char(nhfp, &file_csc_count, "count-critical_sizes", 1);
if (file_csc_count > cnt) {
raw_printf("critical byte counts do not match"
", file:%d, critical_sizes:%d.",
file_csc_count, SIZE(critical_sizes));
return -1;
if (!quietly)
raw_printf("critical byte counts do not match"
", file:%d, critical_sizes:%d.",
file_csc_count, SIZE(critical_sizes));
return SF_CRITICAL_BYTE_COUNT_MISMATCH;
}
for (i = 0; i < (int) file_csc_count; ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &cscbuf[i],
sizeof (uchar));
}
Sfi_uchar(nhfp, &cscbuf[i], "critical_sizes");
}
for (i = 1; i < cnt; ++i) {
if (cscbuf[i] != critical_sizes[i].ucsize)
return i;
if (cscbuf[i] != critical_sizes[i].ucsize) {
const char *dm = datamodel(), *dmfile;
dmfile = what_datamodel_is_this(cscbuf[1], /* short */
cscbuf[2], /* int */
cscbuf[3], /* long */
cscbuf[4], /* long long */
cscbuf[5]); /* ptr */
if (!strcmp(dmfile, "IL32LLP64") && !strcmp(dm, "ILP32LL64")) {
/* Windows x64 savefile on x86 */
dmmismatch = SF_DM_IL32LLP64_ON_ILP32LL64;
} else if (!strcmp(dmfile, "I32LP64")
&& !strcmp(dm, "ILP32LL64")) {
/* Unix 64 savefile on x86*/
dmmismatch = SF_DM_I32LP64_ON_ILP32LL64;
} else if (!strcmp(dmfile, "ILP32LL64")
&& !strcmp(dm, "I32LP64")) {
/* x86 savefile on Unix 64 */
dmmismatch = SF_DM_ILP32LL64_ON_I32LP64;
} else if (!strcmp(dmfile, "ILP32LL64")
&& !strcmp(dm, "IL32LLP64")) {
/* x86 savefile on Windows x64 */
dmmismatch = SF_DM_ILP32LL64_ON_IL32LLP64;
} else if (!strcmp(dmfile, "I32LP64")
&& !strcmp(dm, "IL32LLP64")) {
/* Unix 64 savefile on Windows x64 */
dmmismatch = SF_DM_I32LP64_ON_IL32LLP64;
} else if (!strcmp(dmfile, "IL32LLP64")
&& !strcmp(dm, "I32LP64")) {
/* Windows x64 savefile on Unix 64 */
dmmismatch = SF_DM_IL32LLP64_ON_I32LP64;
}
if (idx_1st_mismatch)
*idx_1st_mismatch = i;
return dmmismatch;
}
}
return 0; /* everything matched */
return SF_UPTODATE; /* everything matched */
}
/*
* returns:
*
* 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
*/
int
validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile)
{
unsigned long utdflags = 0L;
int validsf = 0;
if (nhfp->structlevel)
utdflags |= UTD_CHECKSIZES;
if (without_waitsynch_perfile)
utdflags |= UTD_WITHOUT_WAITSYNCH_PERFILE;
if (nhfp->fieldlevel)
utdflags |= UTD_CHECKFIELDCOUNTS | UTD_SKIP_SANITY1 | UTD_QUIETLY;
validsf = uptodate(nhfp, name, utdflags);
return validsf;
}
#endif /* MINIMAL_FOR_RECOVER */

View File

@@ -16,6 +16,7 @@ struct wseg {
staticfn void toss_wsegs(struct wseg *, boolean) NO_NNARGS;
staticfn void shrink_worm(int);
#if 0
staticfn void random_dir(int, int, int *, int *);
#endif
@@ -527,31 +528,22 @@ save_worm(NHFILE *nhfp)
int count;
struct wseg *curr, *temp;
if (perform_bwrite(nhfp)) {
if (update_file(nhfp)) {
for (i = 1; i < MAX_NUM_WORMS; i++) {
for (count = 0, curr = wtails[i]; curr; curr = curr->nseg)
count++;
/* Save number of segments */
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfo_int(nhfp, &count, "worm-segment_count");
/* Save segment locations of the monster. */
if (count) {
for (curr = wtails[i]; curr; curr = curr->nseg) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &(curr->wx),
sizeof curr->wx);
bwrite(nhfp->fd, (genericptr_t) &(curr->wy),
sizeof curr->wy);
}
Sfo_coordxy(nhfp, &(curr->wx), "worm-wx");
Sfo_coordxy(nhfp, &(curr->wy), "worm-wy");
}
}
}
for (i = 0; i < MAX_NUM_WORMS; ++i) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &wgrowtime[i], sizeof (long));
}
}
for (i = 0; i < MAX_NUM_WORMS; ++i)
Sfo_long(nhfp, &wgrowtime[i], "worm-wgrowtime");
}
if (release_data(nhfp)) {
@@ -580,22 +572,19 @@ save_worm(NHFILE *nhfp)
void
rest_worm(NHFILE *nhfp)
{
int i, j, count = 0;
int i, j;
int count = 0;
struct wseg *curr, *temp;
for (i = 1; i < MAX_NUM_WORMS; i++) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &count, sizeof count);
}
Sfi_int(nhfp, &count, "worm-segment_count");
/* Get the segments. */
for (curr = (struct wseg *) 0, j = 0; j < count; j++) {
temp = newseg();
temp->nseg = (struct wseg *) 0;
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &(temp->wx), sizeof temp->wx);
mread(nhfp->fd, (genericptr_t) &(temp->wy), sizeof temp->wy);
}
Sfi_coordxy(nhfp, &(temp->wx), "worm-wx");
Sfi_coordxy(nhfp, &(temp->wy), "worm-wy");
if (curr)
curr->nseg = temp;
else
@@ -605,9 +594,7 @@ rest_worm(NHFILE *nhfp)
wheads[i] = curr;
}
for (i = 0; i < MAX_NUM_WORMS; ++i) {
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &wgrowtime[i], sizeof (long));
}
Sfi_long(nhfp, &wgrowtime[i], "worm-wgrowtime");
}
}