distinguish global variables that get written to savefile

The g? structs had a mix of variables that were written to
the savefile, and those that were not.

For better clarity and to distinguish those that end up in
the savefile, relocate some g? variables that get written
directly to the savefile into different structs.

This updates EDITLEVEL, although technically it probably
didn't need to, since savefile contents are not changing.

Details:

    gb.bases            -> svb.bases
    gb.bbubbles         -> svb.bbubbles
    gb.branches         -> svb.branches
    gc.context          -> svc.context
    gd.disco            -> svd.disco
    gd.dndest           -> svd.dndest
    gd.doors            -> svd.doors
    gd.doors_alloc      -> svd.doors_alloc
    gd.dungeon_topology -> svd.dungeon_topology
    gd.dungeons         -> svd.dungeons
    ge.exclusion_zones  -> sve.exclusion_zones
    gh.hackpid          -> svh.hackpid
    gi.inv_pos          -> svi.inv_pos
    gk.killer           -> svk.killer
    gl.lastseentyp      -> svl.lastseentyp
    gl.level            -> svl.level
    gl.level_info       -> svl.level_info
    gm.mapseenchn       -> svm.mapseenchn
    gm.moves            -> svm.moves
    gm.mvitals          -> svm.mvitals
    gn.n_dgns           -> svn.n_dgns
    gn.n_regions        -> svn.n_regions
    gn.nroom            -> svn.nroom
    go.oracle_cnt       -> svo.oracle_cnt
    gp.pl_character     -> svp.pl_character
    gp.pl_fruit         -> svp.pl_fruit
    gp.plname           -> svp.plname
    gp.program_state    -> svp.program_state
    gq.quest_status     -> svq.quest_status
    gr.rooms            -> svr.rooms
    gs.sp_levchn        -> svs.sp_levchn
    gs.spl_book         -> svs.spl_book
    gt.timer_id         -> svt.timer_id
    gt.tune             -> svt.tune
    gu.updest           -> svu.updest
    gx.xmax             -> svx.xmax
    gx.xmin             -> svx.xmin
    gy.ymax             -> svy.ymax
    gy.ymin             -> svy.ymin

Related note:
There are some pointer variables that are heads of chains that were not
moved from 'g?' to 'sv?', because they are not actually written to the
savefile directly, but the objects/monst/trap/lightsource/timer in the
chains they point to are. That can be changed, if desired.
Examples: gi.invent, gm.migrating_objs, gb.billobjs, gm.migrating_mons,
          gf.ftrap, gl.light_base, gt.timer_base
This commit is contained in:
nhmall
2024-07-13 14:57:50 -04:00
parent 0e4083153c
commit 6c0ae092c6
174 changed files with 3502 additions and 3305 deletions

138
src/end.c
View File

@@ -43,7 +43,7 @@ ATTRNORETURN extern void nethack_exit(int) NORETURN;
#define nethack_exit exit
#endif
#define done_stopprint gp.program_state.stopprint
#define done_stopprint svp.program_state.stopprint
/*
* The order of these needs to match the macros in hack.h.
@@ -175,7 +175,7 @@ staticfn void
done_hangup(int sig)
{
#ifdef HANGUPHANDLING
gp.program_state.done_hup++;
svp.program_state.done_hup++;
#endif
sethanguphandler((void (*)(int)) SIG_IGN);
done_intr(sig);
@@ -201,19 +201,19 @@ done_in_by(struct monst *mtmp, int how)
You((how == STONING) ? "turn to stone..." : "die...");
mark_synch(); /* flush buffered screen output */
buf[0] = '\0';
gk.killer.format = KILLED_BY_AN;
svk.killer.format = KILLED_BY_AN;
/* "killed by the high priest of Crom" is okay,
"killed by the high priest" alone isn't */
if ((mptr->geno & G_UNIQ) != 0 && !(imitator && !mimicker)
&& !(mptr == &mons[PM_HIGH_CLERIC] && !mtmp->ispriest)) {
if (!type_is_pname(mptr))
Strcat(buf, "the ");
gk.killer.format = KILLED_BY;
svk.killer.format = KILLED_BY;
}
/* _the_ <invisible> <distorted> ghost of Dudley */
if (mptr == &mons[PM_GHOST] && has_mgivenname(mtmp)) {
Strcat(buf, "the ");
gk.killer.format = KILLED_BY;
svk.killer.format = KILLED_BY;
}
(void) monhealthdescr(mtmp, TRUE, eos(buf));
if (mtmp->minvis)
@@ -264,7 +264,7 @@ done_in_by(struct monst *mtmp, int how)
: mtmp->female ? "Ms. " : "Mr. ";
Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm);
gk.killer.format = KILLED_BY;
svk.killer.format = KILLED_BY;
} else if (mtmp->ispriest || mtmp->isminion) {
/* m_monnam() suppresses "the" prefix plus "invisible", and
it overrides the effect of Hallucination on priestname() */
@@ -275,7 +275,7 @@ done_in_by(struct monst *mtmp, int how)
Sprintf(eos(buf), " called %s", MGIVENNAME(mtmp));
}
Strcpy(gk.killer.name, buf);
Strcpy(svk.killer.name, buf);
/* might need to fix up multi_reason if 'mtmp' caused the reason */
if (gm.multi_reason
@@ -330,7 +330,7 @@ done_in_by(struct monst *mtmp, int how)
/* this could happen if a high-end vampire kills the hero
when ordinary vampires are genocided; ditto for wraiths */
if (u.ugrave_arise >= LOW_PM
&& (gm.mvitals[u.ugrave_arise].mvflags & G_GENOD))
&& (svm.mvitals[u.ugrave_arise].mvflags & G_GENOD))
u.ugrave_arise = NON_PM;
done(how);
@@ -391,7 +391,7 @@ panic VA_DECL(const char *, str)
VA_START(str);
VA_INIT(str, char *);
if (gp.program_state.panicking++)
if (svp.program_state.panicking++)
NH_abort(NULL); /* avoid loops - this should never happen*/
gb.bot_disabled = TRUE;
@@ -404,9 +404,9 @@ panic VA_DECL(const char *, str)
iflags.window_inited = FALSE; /* they're gone; force raw_print()ing */
}
raw_print(gp.program_state.gameover
raw_print(svp.program_state.gameover
? "Postgame wrapup disrupted."
: !gp.program_state.something_worth_saving
: !svp.program_state.something_worth_saving
? "Program initialization has failed."
: "Suddenly, the dungeon collapses.");
#ifndef MICRO
@@ -414,11 +414,11 @@ panic VA_DECL(const char *, str)
if (!wizard)
raw_printf("Report the following error to \"%s\" or at \"%s\".",
DEVTEAM_EMAIL, DEVTEAM_URL);
else if (gp.program_state.something_worth_saving)
else if (svp.program_state.something_worth_saving)
raw_print("\nError save file being written.\n");
#else /* !NOTIFY_NETHACK_BUGS */
if (!wizard) {
const char *maybe_rebuild = !gp.program_state.something_worth_saving
const char *maybe_rebuild = !svp.program_state.something_worth_saving
? "."
: "\nand it may be possible to rebuild.";
@@ -437,7 +437,7 @@ panic VA_DECL(const char *, str)
/* XXX can we move this above the prints? Then we'd be able to
* suppress "it may be possible to rebuild" based on dosave0()
* or say it's NOT possible to rebuild. */
if (gp.program_state.something_worth_saving && !iflags.debug_fuzzer) {
if (svp.program_state.something_worth_saving && !iflags.debug_fuzzer) {
set_error_savefile();
if (dosave0()) {
/* os/win port specific recover instructions */
@@ -566,7 +566,7 @@ dump_everything(
/* character name and basic role info */
Sprintf(pbuf, "%s, %s %s %s %s",
gp.plname, aligns[1 - u.ualign.type].adj,
svp.plname, aligns[1 - u.ualign.type].adj,
genders[flags.female].adj, gu.urace.adj,
(flags.female && gu.urole.name.f) ? gu.urole.name.f
: gu.urole.name.m);
@@ -715,7 +715,7 @@ savelife(int how)
make_sick(0L, (char *) 0, FALSE, SICK_ALL);
}
gn.nomovemsg = "You survived that attempt on your life.";
gc.context.move = 0;
svc.context.move = 0;
gm.multi = -1; /* can't move again during the current turn */
/* in case being life-saved is immediately followed by being killed
@@ -731,7 +731,7 @@ savelife(int how)
u.ugrave_arise = NON_PM;
HUnchanging = 0L;
curs_on_u();
if (!gc.context.mon_moving)
if (!svc.context.mon_moving)
endmultishot(FALSE);
if (u.uswallow) {
/* might drop hero onto a trap that kills her all over again */
@@ -937,7 +937,7 @@ fuzzer_savelife(int how)
* Some debugging code pulled out of done() to unclutter it.
* 'done_seq' is maintained in done().
*/
if (!gp.program_state.panicking
if (!svp.program_state.panicking
&& how != PANICKED && how != TRICKED) {
savelife(how);
@@ -983,8 +983,8 @@ fuzzer_savelife(int how)
}
}
/* clear stale cause of death info after life-saving */
gk.killer.name[0] = '\0';
gk.killer.format = 0;
svk.killer.name[0] = '\0';
svk.killer.format = 0;
/* Guard against getting stuck in a loop if we die in one of
* the few ways where life-saving isn't effective (cited case
@@ -1009,19 +1009,19 @@ done(int how)
boolean survive = FALSE;
if (how == TRICKED) {
if (gk.killer.name[0]) {
paniclog("trickery", gk.killer.name);
gk.killer.name[0] = '\0';
if (svk.killer.name[0]) {
paniclog("trickery", svk.killer.name);
svk.killer.name[0] = '\0';
}
if (wizard) {
You("are a very tricky wizard, it seems.");
gk.killer.format = KILLED_BY_AN; /* reset to 0 */
svk.killer.format = KILLED_BY_AN; /* reset to 0 */
return;
}
}
if (gp.program_state.panicking
if (svp.program_state.panicking
#ifdef HANGUPHANDLING
|| gp.program_state.done_hup
|| svp.program_state.done_hup
#endif
|| (how == QUIT && done_stopprint)) {
/* skip status update if panicking or disconnected
@@ -1045,13 +1045,13 @@ done(int how)
return;
}
if (how == ASCENDED || (!gk.killer.name[0] && how == GENOCIDED))
gk.killer.format = NO_KILLER_PREFIX;
if (how == ASCENDED || (!svk.killer.name[0] && how == GENOCIDED))
svk.killer.format = NO_KILLER_PREFIX;
/* Avoid killed by "a" burning or "a" starvation */
if (!gk.killer.name[0] && (how == STARVING || how == BURNING))
gk.killer.format = KILLED_BY;
if (!gk.killer.name[0] || how >= PANICKED)
Strcpy(gk.killer.name, deaths[how]);
if (!svk.killer.name[0] && (how == STARVING || how == BURNING))
svk.killer.format = KILLED_BY;
if (!svk.killer.name[0] || how >= PANICKED)
Strcpy(svk.killer.name, deaths[how]);
if (how < PANICKED) {
u.umortality++;
@@ -1094,7 +1094,7 @@ done(int how)
/* if hangup has occurred, the only possible answer to a paranoid
query is 'no'; we want 'no' as the default for "Die?" but can't
accept it more than once if there's no user supplying it */
&& !(gp.program_state.done_hup && gd.done_seq++ == gh.hero_seq)
&& !(svp.program_state.done_hup && gd.done_seq++ == gh.hero_seq)
#endif
&& !paranoid_query(ParanoidDie, "Die?")) {
pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
@@ -1104,8 +1104,8 @@ done(int how)
}
if (survive) {
gk.killer.name[0] = '\0';
gk.killer.format = KILLED_BY_AN; /* reset to 0 */
svk.killer.name[0] = '\0';
svk.killer.format = KILLED_BY_AN; /* reset to 0 */
return;
}
really_done(how);
@@ -1128,11 +1128,11 @@ really_done(int how)
/*
* The game is now over...
*/
gp.program_state.gameover = 1;
svp.program_state.gameover = 1;
/* in case of a subsequent panic(), there's no point trying to save */
gp.program_state.something_worth_saving = 0;
svp.program_state.something_worth_saving = 0;
#ifdef HANGUPHANDLING
if (gp.program_state.done_hup)
if (svp.program_state.done_hup)
done_stopprint++;
#endif
/* render vision subsystem inoperative */
@@ -1140,7 +1140,7 @@ really_done(int how)
/* maybe use up active invent item(s), place thrown/kicked missile,
deal with ball and chain possibly being temporarily off the map */
if (!gp.program_state.panicking)
if (!svp.program_state.panicking)
done_object_cleanup();
/* in case we're panicking; normally cleared by done_object_cleanup() */
iflags.perm_invent = FALSE;
@@ -1170,7 +1170,7 @@ really_done(int how)
* On those rare occasions you get hosed immediately, go out
* smiling... :-) -3.
*/
if (gm.moves <= 1 && how < PANICKED && !done_stopprint)
if (svm.moves <= 1 && how < PANICKED && !done_stopprint)
pline("Do not pass Go. Do not collect 200 %s.", currency(200L));
if (have_windows)
@@ -1202,19 +1202,19 @@ really_done(int how)
have been genocided: genocide could occur after hero is
already infected or hero could eat a glob of one created
before genocide; don't try to arise as one if they're gone */
&& !(gm.mvitals[PM_GREEN_SLIME].mvflags & G_GENOD))
&& !(svm.mvitals[PM_GREEN_SLIME].mvflags & G_GENOD))
u.ugrave_arise = PM_GREEN_SLIME;
if (how == QUIT) {
gk.killer.format = NO_KILLER_PREFIX;
svk.killer.format = NO_KILLER_PREFIX;
if (u.uhp < 1) {
how = DIED;
u.umortality++; /* skipped above when how==QUIT */
Strcpy(gk.killer.name, "quit while already on Charon's boat");
Strcpy(svk.killer.name, "quit while already on Charon's boat");
}
}
if (how == ESCAPED || how == PANICKED)
gk.killer.format = NO_KILLER_PREFIX;
svk.killer.format = NO_KILLER_PREFIX;
fixup_death(how); /* actually, fixup gm.multi_reason */
@@ -1289,14 +1289,14 @@ really_done(int how)
/* grave creation should be after disclosure so it doesn't have
this grave in the current level's features for #overview */
if (bones_ok && u.ugrave_arise == NON_PM
&& !(gm.mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
&& !(svm.mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
/* Base corpse on race when not poly'd since original u.umonnum
is based on role, and all role monsters are human. */
int mnum = !Upolyd ? gu.urace.mnum : u.umonnum,
was_already_grave = IS_GRAVE(levl[u.ux][u.uy].typ);
corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, gp.plname);
Sprintf(pbuf, "%s, ", gp.plname);
corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, svp.plname);
Sprintf(pbuf, "%s, ", svp.plname);
formatkiller(eos(pbuf), sizeof pbuf - Strlen(pbuf), how, TRUE);
make_grave(u.ux, u.uy, pbuf);
if (IS_GRAVE(levl[u.ux][u.uy].typ) && !was_already_grave)
@@ -1391,16 +1391,16 @@ really_done(int how)
}
#endif
if (u.uhave.amulet) {
Strcat(gk.killer.name, " (with the Amulet)");
Strcat(svk.killer.name, " (with the Amulet)");
} else if (how == ESCAPED) {
if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
Strcat(gk.killer.name, " (in celestial disgrace)");
Strcat(svk.killer.name, " (in celestial disgrace)");
else if (carrying(FAKE_AMULET_OF_YENDOR))
Strcat(gk.killer.name, " (with a fake Amulet)");
Strcat(svk.killer.name, " (with a fake Amulet)");
/* don't bother counting to see whether it should be plural */
}
Sprintf(pbuf, "%s %s the %s...", Goodbye(), gp.plname,
Sprintf(pbuf, "%s %s the %s...", Goodbye(), svp.plname,
(how != ASCENDED)
? (const char *) ((flags.female && gu.urole.name.f)
? gu.urole.name.f
@@ -1511,7 +1511,7 @@ really_done(int how)
(u.uz.dlevel < 0) ? "passed away" : ends[how]);
} else {
/* more conventional demise */
const char *where = gd.dungeons[u.uz.dnum].dname;
const char *where = svd.dungeons[u.uz.dnum].dname;
if (Is_astralevel(&u.uz))
where = "The Astral Plane";
@@ -1526,7 +1526,7 @@ really_done(int how)
}
Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney,
plur(umoney), gm.moves, plur(gm.moves));
plur(umoney), svm.moves, plur(svm.moves));
dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
Sprintf(pbuf,
"You were level %d with a maximum of %d hit point%s when you %s.",
@@ -1657,7 +1657,7 @@ container_contents(
ATTRNORETURN void
nh_terminate(int status)
{
gp.program_state.in_moveloop = 0; /* won't be returning to normal play */
svp.program_state.in_moveloop = 0; /* won't be returning to normal play */
l_nhcore_call(NHCORE_GAME_EXIT);
#ifdef MAC
@@ -1665,7 +1665,7 @@ nh_terminate(int status)
#endif
/* don't bother to try to release memory if we're in panic mode, to
avoid trouble in case that happens to be due to memory problems */
if (!gp.program_state.panicking) {
if (!svp.program_state.panicking) {
freedynamicdata();
dlb_cleanup();
l_nhcore_done();
@@ -1679,10 +1679,10 @@ nh_terminate(int status)
*/
/* don't call exit() if already executing within an exit handler;
that would cancel any other pending user-mode handlers */
if (gp.program_state.exiting)
if (svp.program_state.exiting)
return;
#endif
gp.program_state.exiting = 1;
svp.program_state.exiting = 1;
nethack_exit(status);
}
@@ -1697,13 +1697,13 @@ delayed_killer(int id, int format, const char *killername)
k = (struct kinfo *) alloc(sizeof (struct kinfo));
(void) memset((genericptr_t) k, 0, sizeof (struct kinfo));
k->id = id;
k->next = gk.killer.next;
gk.killer.next = k;
k->next = svk.killer.next;
svk.killer.next = k;
}
k->format = format;
Strcpy(k->name, killername ? killername : "");
gk.killer.name[0] = 0;
svk.killer.name[0] = 0;
}
struct kinfo *
@@ -1711,7 +1711,7 @@ find_delayed_killer(int id)
{
struct kinfo *k;
for (k = gk.killer.next; k != (struct kinfo *) 0; k = k->next) {
for (k = svk.killer.next; k != (struct kinfo *) 0; k = k->next) {
if (k->id == id)
break;
}
@@ -1721,11 +1721,11 @@ find_delayed_killer(int id)
void
dealloc_killer(struct kinfo *kptr)
{
struct kinfo *prev = &gk.killer, *k;
struct kinfo *prev = &svk.killer, *k;
if (kptr == (struct kinfo *) 0)
return;
for (k = gk.killer.next; k != (struct kinfo *) 0; k = k->next) {
for (k = svk.killer.next; k != (struct kinfo *) 0; k = k->next) {
if (k == kptr)
break;
prev = k;
@@ -1746,16 +1746,16 @@ save_killers(NHFILE *nhfp)
struct kinfo *kptr;
if (perform_bwrite(nhfp)) {
for (kptr = &gk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
for (kptr = &svk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) kptr, sizeof(struct kinfo));
}
}
if (release_data(nhfp)) {
while (gk.killer.next) {
kptr = gk.killer.next->next;
free((genericptr_t) gk.killer.next);
gk.killer.next = kptr;
while (svk.killer.next) {
kptr = svk.killer.next->next;
free((genericptr_t) svk.killer.next);
svk.killer.next = kptr;
}
}
}
@@ -1765,7 +1765,7 @@ restore_killers(NHFILE *nhfp)
{
struct kinfo *kptr;
for (kptr = &gk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
for (kptr = &svk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
if (nhfp->structlevel)
mread(nhfp->fd, (genericptr_t) kptr, sizeof(struct kinfo));
if (kptr->next) {