From 5e570b181fc6dcacbb4a9f9e91cb0007b353e773 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 2 Dec 2020 14:49:09 -0800 Subject: [PATCH 1/2] saving followup If attempting to checkpoint when changing levels discovered that the alock.0 or 123wizard.0 file was missing and the game was running in wizard mode, play continued after reporting trickery but screen updating was left disabled. An early return in savegamestateinlock() wasn't resetting the program_state.saving flag to revert to normal screen updates. I added a few return statements at the ends of void routines, where they're optional, because it makes searching for early returns easier. (Without these then when no early return is present between current point and end of routine, the search would move past the routine looking for 'return' later in the file.) save_stairs() was placed in between saveobj() and saveobjchn() so I've moved it. (Has no effect on the recently reported stair anomalies.) It was also accumulating the total stairway data size in 'len' and never using that for anything, so I got rid of it. (Ditto about anomalies.) --- src/save.c | 85 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/save.c b/src/save.c index c8f1865da..d1dcf15fd 100644 --- a/src/save.c +++ b/src/save.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 save.c $NHDT-Date: 1606919257 2020/12/02 14:27:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.163 $ */ +/* NetHack 3.7 save.c $NHDT-Date: 1606949327 2020/12/02 22:48:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.164 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -21,15 +21,12 @@ int dotcnt, dotrow; /* also used in restore */ #endif static void FDECL(savelevchn, (NHFILE *)); -static void FDECL(savedamage, (NHFILE *)); -/* static void FDECL(saveobj, (NHFILE *,struct obj *)); */ -/* static void FDECL(savemon, (NHFILE *,struct monst *)); */ -/* static void FDECL(savelevl, (NHFILE *, BOOLEAN_P)); */ -static void FDECL(saveobj, (NHFILE *,struct obj *)); -static void FDECL(savemon, (NHFILE *,struct monst *)); static void FDECL(savelevl, (NHFILE *,BOOLEAN_P)); +static void FDECL(savedamage, (NHFILE *)); static void FDECL(save_stairs, (NHFILE *)); +static void FDECL(saveobj, (NHFILE *,struct obj *)); static void FDECL(saveobjchn, (NHFILE *,struct obj **)); +static void FDECL(savemon, (NHFILE *,struct monst *)); static void FDECL(savemonchn, (NHFILE *,struct monst *)); static void FDECL(savetrapchn, (NHFILE *,struct trap *)); static void FDECL(savegamestate, (NHFILE *)); @@ -214,7 +211,7 @@ dosave0() getlev(onhfp, g.hackpid, ltmp); close_nhfile(onhfp); if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/ + bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* lvl no. */ savelev(nhfp, ltmp); /* actual level*/ delete_levelfile(ltmp); } @@ -242,9 +239,7 @@ NHFILE *nhfp; unsigned long uid; struct obj *bc_objs = (struct obj *)0; - if (!g.program_state.saving) - impossible("savegamestate called when not saving or changing levels?"); - + g.program_state.saving++; /* caller should/did already set this... */ uid = (unsigned long) getuid(); if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid); @@ -326,8 +321,11 @@ NHFILE *nhfp; save_msghistory(nhfp); if (nhfp->structlevel) bflush(nhfp->fd); + g.program_state.saving--; + return; } +/* potentially called from goto_level(do.c) as well as savestateinlock() */ boolean tricked_fileremoved(nhfp, whynot) NHFILE *nhfp; @@ -371,8 +369,10 @@ savestateinlock() * readable by an external utility */ nhfp = open_levelfile(0, whynot); - if (tricked_fileremoved(nhfp, whynot)) + if (tricked_fileremoved(nhfp, whynot)) { + g.program_state.saving--; return; + } if (nhfp->structlevel) (void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid); @@ -420,6 +420,7 @@ savestateinlock() } g.program_state.saving--; g.havestate = flags.ins_chkpt; + return; } #endif @@ -537,6 +538,7 @@ xchar lev; bflush(nhfp->fd); } g.program_state.saving--; + return; } static void @@ -598,6 +600,7 @@ boolean rlecomp; if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) levl, sizeof levl); } + return; } /* used when saving a level and also when saving dungeon overview data */ @@ -656,6 +659,32 @@ NHFILE *nhfp; g.level.damagelist = 0; } +static void +save_stairs(nhfp) +NHFILE *nhfp; +{ + stairway *stway = g.stairs; + int buflen = (int) sizeof *stway; + + while (stway) { + if (perform_bwrite(nhfp)) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); + bwrite(nhfp->fd, (genericptr_t) stway, sizeof *stway); + } + } + stway = stway->next; + } + if (perform_bwrite(nhfp)) { + if (nhfp->structlevel) { + buflen = -1; + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); + } + } +} + +/* save one object; + caveat: this is only for perform_bwrite(); caller handles release_data() */ static void saveobj(nhfp, otmp) NHFILE *nhfp; @@ -694,40 +723,14 @@ struct obj *otmp; } /* 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 oxtra components do */ + gets saved/restored whenever any other oextra components do */ if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &OMID(otmp), sizeof OMID(otmp)); } } -static void -save_stairs(nhfp) -NHFILE *nhfp; -{ - stairway *stway = g.stairs; - int buflen = (int) sizeof (stairway); - int len = 0; - - while (stway) { - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - len += sizeof(buflen); - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - len += sizeof(stairway); - bwrite(nhfp->fd, (genericptr_t) stway, sizeof(stairway)); - } - } - stway = stway->next; - } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - buflen = -1; - len += sizeof(buflen); - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } - } -} - +/* save an object chain; sets head of list to Null when done; + handles release_data() for each object in the list */ static void saveobjchn(nhfp, obj_p) NHFILE *nhfp; From 3e7283e8fd7df2aa0d2a5a8f0b9d9e3b6f30a27c Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 2 Dec 2020 16:11:53 -0800 Subject: [PATCH 2/2] Qt fix for typing "#version" The #version command is a leading substring of the #versionshort command and for Qt, it couldn't be executed by typing, only via mouse click or one of the Qt-specific menus. #version or #version now works for that. The #versionshort command ought to be renamed to something else. --- doc/fixes37.0 | 6 +++++- win/Qt/qt_xcmd.cpp | 34 ++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 4794c86ad..d7fad4bb9 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.370 $ $NHDT-Date: 1606919254 2020/12/02 14:27:34 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.371 $ $NHDT-Date: 1606954304 2020/12/03 00:11:44 $ General Fixes and Modified Features ----------------------------------- @@ -507,6 +507,10 @@ Qt: don't get stuck in a loop after choosing "play" while the character name field is empty in the character selection widget Qt: when a new message is issued, pan the message window to its left edge if player panned it horizontally then didn't manually scroll it back +Qt: there was no way to enter extended command "#version" by typing; command + name matching was waiting to disambiguate it from "#versionshort" + and the only way to that was to type #version but + explicitly triggered rejection, cancelling '#' processing Qt: {maybe just Qt+OSX:} when viewing a text window ('V' to look at 'history' for instance), clicking on [Search], entering a search target in the resulting popup and clicking on [Okay] or typing , the text diff --git a/win/Qt/qt_xcmd.cpp b/win/Qt/qt_xcmd.cpp index ce81fbb44..ed6f870d3 100644 --- a/win/Qt/qt_xcmd.cpp +++ b/win/Qt/qt_xcmd.cpp @@ -167,26 +167,40 @@ void NetHackQtExtCmdRequestor::keyPressEvent(QKeyEvent *event) if (promptstr != "#") prompt->setText(promptstr.left(promptstr.size() - 1)); enableButtons(); - /*} else if (uc == '\r' || uc == '\n'; || uc == ' ') {*/ - } else if (uc < ' ' || uc > std::max('z', 'Z')) { + } else if ((uc < ' ' && !(uc == '\n' || uc == '\r')) + || uc > std::max('z', 'Z')) { reject(); // done() } else { - promptstr += QChar(uc); // event()->text() + // is necessary if one command is a leading substring + // of another and superfluous otherwise + boolean checkexact = (uc == '\n' || uc == '\r' || uc == ' '); + if (!checkexact) + promptstr += QChar(uc); // event()->text() QString typedstr = promptstr.mid(1); // skip the '#' unsigned matches = 0; - unsigned match = 0; + unsigned matchindx = 0; for (unsigned i=0; extcmdlist[i].ef_txt; i++) { if (!interesting_command(i)) continue; - if (QString(extcmdlist[i].ef_txt).startsWith(typedstr)) { - ++matches; - if (matches >= 2) - break; - match = i; + QString cmdtxt = QString(extcmdlist[i].ef_txt); + if (cmdtxt.startsWith(typedstr)) { + if (checkexact) { + if (cmdtxt == typedstr) { + matchindx = i; + matches = 1; + break; + } + } else { + if (++matches >= 2) + break; + matchindx = i; + } } } if (matches == 1) - done(match+1); + done(matchindx + 1); + else if (checkexact) + reject(); else if (matches >= 2) prompt->setText(promptstr); enableButtons();