From b4474e1e22ffc0dc78afae0537106eae2ac5b092 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Fri, 8 Feb 2008 03:19:09 +0000 Subject: [PATCH] #monpolycontrol of unseen monsters and of vampires (trunk only) I was testing something with #monpolycontrol enabled and got a series of "Change it into what kind of monster? [type the name]" prompts when I went to a new level. It was asking about monsters that were being created (in this case, multiple vampires for top level of Vlad's Tower) and naturally I couldn't see them since the level wasn't finished yet. This switches to noit_mon_nam() to at least be informed about the type of creature you're being asked to specify a shape for, and adds the map coordinates so that it doesn't appear to be reprompting for the same monster over and over when multiple similar ones are being created. In the process I discovered that #monpolycontrol would let you give any type of monster for the shape of vampires. Unlike chameleons, they don't change into arbitrary shapes so that was inappropriate. [And trying to test the fix for this is what led to the previous ^G patch.] --- doc/fixes35.0 | 1 + src/mon.c | 100 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 82 insertions(+), 19 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index aef033933..6aa8ba080 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -279,6 +279,7 @@ potion thrown by monster which hit a long worm's tail gave feedback about implement energy vortex's previously unused energy drain attack changing alignment type resets alignment record to 0 (nomimally aligned) while polymorphed, suppress attribute gain/lose earned by pre-poly exercise +wizard mode #monpolycontrol prompting asked about "it" when monster was unseen Platform- and/or Interface-Specific Fixes diff --git a/src/mon.c b/src/mon.c index d0947f842..f7bd465f9 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mon.c 3.5 2007/07/13 */ +/* SCCS Id: @(#)mon.c 3.5 2008/02/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -21,6 +21,10 @@ STATIC_DCL long FDECL(mm_displacement, (struct monst *,struct monst *)); STATIC_DCL int NDECL(pick_animal); STATIC_DCL void FDECL(kill_eggs, (struct obj *)); STATIC_DCL void FDECL(dealloc_mextra, (struct mextra *)); +STATIC_DCL int FDECL(pickvampshape, (struct monst *)); +#ifdef WIZARD +STATIC_DCL boolean FDECL(validvamp, (struct monst *,int *,int)); +#endif #ifdef REINCARNATION #define LEVEL_SPECIFIC_NOCORPSE(mdat) \ @@ -2517,6 +2521,70 @@ int shiftflags; mon->female = was_female; } +STATIC_OVL int +pickvampshape(mon) +struct monst *mon; +{ + int mndx = mon->cham; + + switch (mndx) { + case PM_VLAD_THE_IMPALER: + /* ensure Vlad can keep carrying the Candelabrum */ + if (mon_has_special(mon)) break; /* leave mndx as is */ + /*FALLTHRU*/ + case PM_VAMPIRE_LORD: /* vampire lord or Vlad can become wolf */ + if (!rn2(10)) { + mndx = PM_WOLF; + break; + } + /*FALLTHRU*/ + case PM_VAMPIRE: /* any vampire can become fog or bat */ + mndx = !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT; + break; + } + return mndx; +} + +#ifdef WIZARD +/* prevent wizard mode user from specifying invalid vampshifter shape */ +static boolean +validvamp(mon, mndx_p, monclass) +struct monst *mon; +int *mndx_p, monclass; +{ + if (!is_vampshifter(mon)) return TRUE; /* simplify caller's usage */ + + 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; + } + /* basic vampires can't become wolves; any can become fog or bat */ + if (*mndx_p == PM_WOLF) return (mon->cham != PM_VAMPIRE); + if (*mndx_p == PM_FOG_CLOUD || *mndx_p == PM_VAMPIRE_BAT) return TRUE; + + /* if we get here, specific type was no good; try by class */ + switch (monclass) { + case S_VAMPIRE: *mndx_p = mon->cham; break; + case S_BAT: *mndx_p = PM_VAMPIRE_BAT; break; + case S_VORTEX: *mndx_p = PM_FOG_CLOUD; break; + case S_DOG: if (mon->cham != PM_VAMPIRE) { + *mndx_p = PM_WOLF; + break; + } + /*FALLTHRU*/ + default: *mndx_p = NON_PM; break; + } + return (*mndx_p != NON_PM); +} +#endif /*WIZARD*/ + int select_newcham_form(mon) struct monst *mon; @@ -2551,20 +2619,9 @@ struct monst *mon; if (!rn2(3)) mndx = pick_animal(); break; case PM_VLAD_THE_IMPALER: - if (mon_has_special(mon)) { /* ensure Vlad can carry it still */ - mndx = PM_VLAD_THE_IMPALER; - break; - } - /*FALLTHRU*/ case PM_VAMPIRE_LORD: - if (!rn2(10)) { - /* VAMPIRE_LORD || VLAD */ - mndx = PM_WOLF; - break; - } - /*FALLTHRU*/ case PM_VAMPIRE: - mndx = !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT; + mndx = pickvampshape(mon); break; case NON_PM: /* ordinary */ { @@ -2584,22 +2641,27 @@ struct monst *mon; int monclass; Sprintf(pprompt, - "Change %s into what kind of monster? [type the name]", - mon_nam(mon)); + "Change %s @ <%d,%d> into what kind of monster?", + noit_mon_nam(mon), (int)mon->mx, (int)mon->my); tryct = 5; do { + monclass = 0; getlin(pprompt, buf); - if (*buf == '\033') break; + mungspaces(buf); + if (*buf == '\033' || !strcmp(buf, "*") || + !strcmp(buf, "random")) break; /* mndx == NON_PM */ mndx = name_to_mon(buf); - if (mndx >= LOW_PM) break; + if (mndx >= LOW_PM && validvamp(mon, &mndx, monclass)) break; monclass = name_to_monclass(buf, &mndx); if (monclass && mndx == NON_PM) mndx = mkclass_poly(monclass); - if (mndx >= LOW_PM) break; + if (mndx >= LOW_PM && validvamp(mon, &mndx, monclass)) break; - You("cannot polymorph %s into that.", mon_nam(mon)); + pline("It can't become that."); } while (--tryct > 0); if (!tryct) pline(thats_enough_tries); + if (is_vampshifter(mon) && !validvamp(mon, &mndx, monclass)) + mndx = pickvampshape(mon); /* don't resort to arbitrary */ } #endif /*WIZARD*/ if (mndx == NON_PM) mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM);