From cb5e93e9e5c095cfc04688d7201831723489fe54 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 29 Dec 2023 02:29:16 -0800 Subject: [PATCH] polymorphing into placeholder monsters "human", "dwarf", "elf", "gnome", and "orc" are all flagged M2_NOPOLY; so is "giant". But dwarf and gnome are ordinary monsters and should be eligible to be polymorph targets, so take the no-poly flag off of them. The others are used for corpses and not intended to be distinct monsters. But they are reasonable polymorph targets, so if player with control picks any of them, choose a substitute. The exception is human, which already has special poly-self handling. --- include/mondata.h | 4 +++- include/monsters.h | 21 ++++++++++++--------- src/polyself.c | 25 ++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/include/mondata.h b/include/mondata.h index f565d9da1..b12d6e382 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 mondata.h $NHDT-Date: 1606473485 2020/11/27 10:38:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.45 $ */ +/* NetHack 3.7 mondata.h $NHDT-Date: 1703845738 2023/12/29 10:28:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.63 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ @@ -161,6 +161,8 @@ #define is_rider(ptr) \ ((ptr) == &mons[PM_DEATH] || (ptr) == &mons[PM_FAMINE] \ || (ptr) == &mons[PM_PESTILENCE]) +/* note: placeholder monsters are used for corposes of zombies and mummies; + PM_DWARF and PM_GNOME are normal monsters, not placeholders */ #define is_placeholder(ptr) \ ((ptr) == &mons[PM_ORC] || (ptr) == &mons[PM_GIANT] \ || (ptr) == &mons[PM_ELF] || (ptr) == &mons[PM_HUMAN]) diff --git a/include/monsters.h b/include/monsters.h index 14ee32dd6..a34c662c8 100644 --- a/include/monsters.h +++ b/include/monsters.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 monsters.h $NHDT-Date: 1700725870 2023/11/23 07:51:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.113 $ */ +/* NetHack 3.7 monsters.h $NHDT-Date: 1703845746 2023/12/29 10:29:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.117 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -417,12 +417,13 @@ NO_ATTK), SIZ(500, 200, MS_HUMANOID, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 2, CLR_GREEN, HOBBIT), + /* unlike plain human|elf|orc, plain "dwarf" is an ordinary monster */ MON("dwarf", S_HUMANOID, LVL(2, 6, 10, 10, 4), (G_GENO | 3), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, - M2_NOPOLY | M2_DWARF | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, + M2_DWARF | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 4, CLR_RED, DWARF), MON("bugbear", S_HUMANOID, LVL(3, 9, 5, 0, -6), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), @@ -630,10 +631,9 @@ SIZ(1000, 200, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_ORC | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 3, CLR_BROWN, HOBGOBLIN), - /* plain "orc" for zombie corpses only; not created at random; - * orcs (but not goblins and hobgoblins) are granted poison resistance; - * however, their corpses don't confer it - */ + /* Plain "orc" for zombie and mummy corpses only; not created at random. + * Orcs (but not goblins and hobgoblins) are granted poison resistance; + * however, their corpses don't confer it. */ MON("orc", S_ORC, LVL(1, 9, 10, 0, -3), (G_GENO | G_NOGEN | G_LGROUP), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), @@ -1417,12 +1417,13 @@ M2_HOSTILE | M2_NEUTER, 0, 5, CLR_MAGENTA, VIOLET_FUNGUS), /* * Gnomes + * Unlike plain human|elf|orc, plain "gnome" is an ordinary monster. */ MON("gnome", S_GNOME, LVL(1, 6, 10, 4, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(650, 100, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, - M2_NOPOLY | M2_GNOME | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, + M2_GNOME | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 3, CLR_BROWN, GNOME), MON3("gnome lord", "gnome lady", "gnome leader", S_GNOME, LVL(3, 8, 10, 4, 0), (G_GENO | 2), @@ -2205,14 +2206,15 @@ /* * humans, including elves and were-critters; * the '@' class does not obey rule #2. + * Plain "human" is a placeholder, not a normal monster. */ MON("human", S_HUMAN, LVL(0, 12, 10, 0, 0), G_NOGEN, /* for corpses */ A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, - M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, - 2, HI_DOMESTIC, HUMAN), + M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, + M3_INFRAVISIBLE, 2, HI_DOMESTIC, HUMAN), MON("wererat", S_HUMAN, LVL(2, 12, 10, 10, -7), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), @@ -2234,6 +2236,7 @@ M1_HUMANOID | M1_POIS | M1_REGEN | M1_OMNIVORE, M2_NOPOLY | M2_WERE | M2_HOSTILE | M2_HUMAN | M2_COLLECT, M3_INFRAVISIBLE, 6, CLR_ORANGE, HUMAN_WEREWOLF), + /* plain "elf" is a placeholder, not a normal monster */ MON("elf", S_HUMAN, LVL(0, 12, 10, 2, -3), G_NOGEN, /* for corpses */ A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), diff --git a/src/polyself.c b/src/polyself.c index 807e5ef8c..c5f7b077a 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 polyself.c $NHDT-Date: 1702274031 2023/12/11 05:53:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.204 $ */ +/* NetHack 3.7 polyself.c $NHDT-Date: 1703845752 2023/12/29 10:29:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.207 $ */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -502,6 +502,7 @@ polyself(int psflags) if (controllable_poly || forcecontrol) { buf[0] = '\0'; tryct = 5; + do { mntmp = NON_PM; getlin("Become what kind of monster? [type the name]", buf); @@ -528,7 +529,28 @@ polyself(int psflags) mntmp = (draconian && class == S_DRAGON) ? armor_to_dragon(uarm->otyp) : mkclass_poly(class); + + /* placeholder monsters are for corpses and all flagged + M2_NOPOLY but they are reasonable polymorph targets; + pick a suitable substitute (which might be geno'd) */ + } else if (is_placeholder(&mons[mntmp]) + /* when your own race, fall to !polyok() case */ + && !your_race(&mons[mntmp]) + /* same for generic human, even if hero isn't human */ + && mntmp != PM_HUMAN) { + /* far less general than mkclass() */ + if (mntmp == PM_ORC) + mntmp = rn2(3) ? PM_HILL_ORC : PM_MORDOR_ORC; + else if (mntmp == PM_ELF) + mntmp = rn2(3) ? PM_GREEN_ELF : PM_GREY_ELF; + else if (mntmp == PM_GIANT) + mntmp = rn2(3) ? PM_STONE_GIANT : PM_HILL_GIANT; + /* note: PM_DWARF and PM_GNOME are ordinary monsters and + no longer flagged no-poly so have no need for placeholder + handling; PM_HUMAN is a placeholder without a suitable + substitute so gets handled differently below */ } + if (mntmp < LOW_PM) { if (!class) pline("I've never heard of such monsters."); @@ -581,6 +603,7 @@ polyself(int psflags) } else break; } while (--tryct > 0); + if (!tryct) pline1(thats_enough_tries); /* allow skin merging, even when polymorph is controlled */