From f0633e65414a3aff9a7022c4466e74cda08e9a7c Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 15 Jun 2019 04:13:34 -0700 Subject: [PATCH] EDIT_GETLIN vs monpolycontrol For wizard mode 'monpolycontrol', the getlin() answer buffer for the "Change @ into what kind of monster?" prompt is also used to format the coordinate portion of that prompt, so when EDIT_GETLIN is enabled getlin() was inadvertently given "" to use as default response. Clear it after the prompt is formatted instead of via an initializer. Also, shorten the prompt on the first try: "Change @ into what?", expanding to the old prompt if retry is needed. This also allows specifying 'chameleon' when is a chameleon, 'doppelganger' when it's a doppelganger, and 'sandestin' when it's one of those (but not 'doppelganger' when it's a chameleon or sandestin, and so forth), instead of blanket refusal to accept any non-vampire shapechanger as the choice. --- doc/fixes36.3 | 8 ++++++- src/mon.c | 62 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index 08e1c075a..231b49851 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.52 $ $NHDT-Date: 1560387439 2019/06/13 00:57:19 $ +$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.53 $ $NHDT-Date: 1560597210 2019/06/15 11:13:30 $ This fixes36.3 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.2 in May 2019. Please note, however, @@ -73,6 +73,9 @@ don't give feedback for monster zapping a wand if a monster plays a fire horn if hero knows the number of charges in a wand or magical horn and a monster acquires it and zaps/plays it when not in view, remove the hero's memory of the number of charges +for wizard mode 'monpolycontrol', allow usually disallowed type 'chameleon', + 'doppelganger', or 'sandestin' as answer to "change @ + into what?" prompt when is really that type of creature Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository @@ -90,6 +93,9 @@ curses: sometimes the message window would show a blank line after a prompt Platform- and/or Interface-Specific Fixes or Features ----------------------------------------------------- +EDIT_GETLIN: wizard mode 'monpolycontrol' was using the getlin() answer buffer + to format the coordinate portion of the "change @ into + what kind of monster?" prompt, resulting in "" as default answer curses: very tall menus tried to use selector characters a-z, A-Z, and 0-9, but 0-9 should be reserved for counts and if the display was tall enough for more than 62 entries, arbitrary ASCII punctuation got used diff --git a/src/mon.c b/src/mon.c index e281cb392..1c7fe5424 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1559733390 2019/06/05 11:16:30 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.292 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1560597210 2019/06/15 11:13:30 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.293 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -24,7 +24,7 @@ STATIC_DCL void FDECL(kill_eggs, (struct obj *)); STATIC_DCL int FDECL(pickvampshape, (struct monst *)); STATIC_DCL boolean FDECL(isspecmon, (struct monst *)); STATIC_DCL boolean FDECL(validspecmon, (struct monst *, int)); -STATIC_DCL struct permonst *FDECL(accept_newcham_form, (int)); +STATIC_DCL struct permonst *FDECL(accept_newcham_form, (struct monst *, int)); STATIC_DCL struct obj *FDECL(make_corpse, (struct monst *, unsigned)); STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *)); STATIC_DCL void FDECL(lifesaved_monster, (struct monst *)); @@ -3404,7 +3404,7 @@ int mndx; if (mndx == NON_PM) return TRUE; /* caller wants random */ - if (!accept_newcham_form(mndx)) + if (!accept_newcham_form(mon, mndx)) return FALSE; /* geno'd or !polyok */ if (isspecmon(mon)) { @@ -3429,17 +3429,17 @@ int *mndx_p, monclass; if (!is_vampshifter(mon)) return validspecmon(mon, *mndx_p); - if (*mndx_p == PM_VAMPIRE || *mndx_p == PM_VAMPIRE_LORD - || *mndx_p == PM_VLAD_THE_IMPALER) { - /* player picked some type of vampire; use mon's self */ - *mndx_p = mon->cham; - return TRUE; - } if (mon->cham == PM_VLAD_THE_IMPALER && mon_has_special(mon)) { /* Vlad with Candelabrum; override choice, then accept it */ *mndx_p = PM_VLAD_THE_IMPALER; return TRUE; } + if (*mndx_p >= LOW_PM && is_shapeshifter(&mons[*mndx_p])) { + /* player picked some type of shapeshifter; use mon's self + (vampire or chameleon) */ + *mndx_p = mon->cham; + return TRUE; + } /* basic vampires can't become wolves; any can become fog or bat (we don't enforce upper-case only for rogue level here) */ if (*mndx_p == PM_WOLF) @@ -3463,7 +3463,7 @@ int *mndx_p, monclass; *mndx_p = PM_WOLF; break; } - /*FALLTHRU*/ + /*FALLTHRU*/ default: *mndx_p = NON_PM; break; @@ -3526,16 +3526,35 @@ struct monst *mon; /* for debugging: allow control of polymorphed monster */ if (wizard && iflags.mon_polycontrol) { - char pprompt[BUFSZ], buf[BUFSZ] = DUMMY; - int monclass; + char pprompt[BUFSZ], parttwo[QBUFSZ], buf[BUFSZ]; + int monclass, len; - Sprintf(pprompt, "Change %s @ %s into what kind of monster?", - noit_mon_nam(mon), + /* construct prompt in pieces */ + Sprintf(pprompt, "Change %s", noit_mon_nam(mon)); + Sprintf(parttwo, " @ %s into what?", coord_desc((int) mon->mx, (int) mon->my, buf, (iflags.getpos_coords != GPCOORDS_NONE) ? iflags.getpos_coords : GPCOORDS_MAP)); - tryct = 5; + /* combine the two parts, not exceeding QBUFSZ-1 in overall length; + if combined length is too long it has to be due to monster's + name so we'll chop enough of that off to fit the second part */ + if ((len = (int) strlen(pprompt) + (int) strlen(parttwo)) >= QBUFSZ) + /* strlen(parttwo) is less than QBUFSZ/2 so strlen(pprompt) is + more than QBUFSZ/2 and excess amount being truncated can't + exceed pprompt's length and back up to before &pprompt[0]) */ + *(eos(pprompt) - (len - (QBUFSZ - 1))) = '\0'; + Strcat(pprompt, parttwo); + + buf[0] = '\0'; /* clear buffer for EDIT_GETLIN */ +#define TRYLIMIT 5 + tryct = TRYLIMIT; do { + if (tryct == TRYLIMIT - 1) { /* first retry */ + /* change "into what?" to "into what kind of monster?" */ + if (strlen(pprompt) + sizeof " kind of monster" - 1 < QBUFSZ) + Strcpy(eos(pprompt) - 1, " kind of monster?"); + } +#undef TRYLIMIT monclass = 0; getlin(pprompt, buf); mungspaces(buf); @@ -3543,7 +3562,7 @@ struct monst *mon; if (*buf == '\033') break; /* for "*", use NON_PM to pick an arbitrary shape below */ - if (!strcmp(buf, "*") || !strcmp(buf, "random")) { + if (!strcmp(buf, "*") || !strcmpi(buf, "random")) { mndx = NON_PM; break; } @@ -3565,6 +3584,7 @@ struct monst *mon; pline("It can't become that."); } while (--tryct > 0); + if (!tryct) pline1(thats_enough_tries); if (is_vampshifter(mon) && !validvamp(mon, &mndx, monclass)) @@ -3586,7 +3606,8 @@ struct monst *mon; /* this used to be inline within newcham() but monpolycontrol needs it too */ STATIC_OVL struct permonst * -accept_newcham_form(mndx) +accept_newcham_form(mon, mndx) +struct monst *mon; int mndx; { struct permonst *mdat; @@ -3603,6 +3624,11 @@ int mndx; polyok() rejects, so we need a special case here */ if (is_mplayer(mdat)) return mdat; + /* shapeshifters are rejected by polyok() but allow a shapeshifter + to take on its 'natural' form */ + if (is_shapeshifter(mdat) + && mon->cham >= LOW_PM && mdat == &mons[mon->cham]) + return mdat; /* polyok() rules out M2_PNAME, M2_WERE, and all humans except Kops */ return polyok(mdat) ? mdat : 0; } @@ -3674,7 +3700,7 @@ boolean msg; /* "The oldmon turns into a newmon!" */ tryct = 20; do { mndx = select_newcham_form(mtmp); - mdat = accept_newcham_form(mndx); + mdat = accept_newcham_form(mtmp, mndx); /* for the first several tries we require upper-case on the rogue level (after that, we take whatever we get) */ if (tryct > 15 && Is_rogue_level(&u.uz) -- 2.50.0