diff --git a/doc/fixes35.0 b/doc/fixes35.0 index a71d585dc..00e69a6b4 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -311,6 +311,7 @@ improved container interface acid can destroy iron bars OPTIONS=playmode:normal|explore|debug to choose mode without command-line score bonus for ascending is reduced or denied for changing alignment +player can give a monster class when asked for type of monster to poly into Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index cef64a9d8..557784c8f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1050,6 +1050,7 @@ E boolean FDECL(create_critters, (int,struct permonst *,BOOLEAN_P)); E struct permonst *NDECL(rndmonst); E void FDECL(reset_rndmonst, (int)); E struct permonst *FDECL(mkclass, (CHAR_P,int)); +E int FDECL(mkclass_poly, (int)); E int FDECL(adj_lev, (struct permonst *)); E struct permonst *FDECL(grow_up, (struct monst *,struct monst *)); E int FDECL(mongets, (struct monst *,int)); diff --git a/src/makemon.c b/src/makemon.c index 6499298eb..58e33278d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1415,6 +1415,37 @@ int spc; return(&mons[first]); } +/* like mkclass(), but excludes difficulty considerations; used when + player with polycontrol picks a class instead of a specific type; + genocided types are avoided but extinct ones are acceptable */ +int +mkclass_poly(class) +int class; +{ + register int first, last, num = 0; + + for (first = LOW_PM; first < SPECIAL_PM; first++) + if (mons[first].mlet == class) break; + if (first == SPECIAL_PM) return NON_PM; + + for (last = first; + last < SPECIAL_PM && mons[last].mlet == class; last++) + if (!(mvitals[last].mvflags & G_GENOD) && + !(mons[last].geno & (G_NOGEN|G_UNIQ)) && + !is_placeholder(&mons[last])) + num += mons[last].geno & G_FREQ; + if (!num) return NON_PM; + + for (num = rnd(num); num > 0; first++) + if (!(mvitals[first].mvflags & G_GENOD) && + !(mons[first].geno & (G_NOGEN|G_UNIQ)) && + !is_placeholder(&mons[first])) + num -= mons[first].geno & G_FREQ; + first--; /* correct an off-by-one error */ + + return first; +} + int adj_lev(ptr) /* adjust strength of monsters based on u.uz and u.ulevel */ register struct permonst *ptr; diff --git a/src/mondata.c b/src/mondata.c index 3cd514041..f3e319fea 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -664,10 +664,15 @@ int *mndx_p; /* multiple-letter input which matches any of these gets rejected */ "an", "the", "or", "other", "or other", 0 }; + /* positive pm_val => specific monster; negative => class */ static NEARDATA const struct alt_spl truematch[] = { /* "long worm" won't match "worm" class but would accidentally match "long worm tail" class before the comparison with monster types */ { "long worm", PM_LONG_WORM }, + /* matches wrong--or at least suboptimal--class */ + { "demon", -S_DEMON }, /* hits "imp or minor demon" */ + /* matches specific monster (overly restrictive) */ + { "devil", -S_DEMON }, /* always "horned devil" */ /* some plausible guesses which need help */ { "bug", -S_XAN }, /* would match bugbear... */ { "fish", -S_EEL }, /* wouldn't match anything */ @@ -685,7 +690,12 @@ int *mndx_p; } else if (!in_str[1]) { /* single character */ i = def_char_to_monclass(*in_str); - if (i == MAXMCLASSES) + if (i == S_MIMIC_DEF) { /* ']' -> 'm' */ + i = S_MIMIC; + } else if (i == S_WORM_TAIL) { /* '~' -> 'w' */ + i = S_WORM; + if (mndx_p) *mndx_p = PM_LONG_WORM; + } else if (i == MAXMCLASSES) /* maybe 'I' */ i = (*in_str == DEF_INVISIBLE) ? S_invisible : 0; return i; } else { diff --git a/src/polyself.c b/src/polyself.c index 5105d6cd3..7bc84c426 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -255,7 +255,7 @@ polyself(psflags) int psflags; { char buf[BUFSZ]; - int old_light, new_light, mntmp, tryct; + int old_light, new_light, mntmp, class, tryct; boolean forcecontrol = (psflags == 1), monsterpoly = (psflags == 2), draconian = (uarm && Is_dragon_armor(uarm)), @@ -286,9 +286,18 @@ int psflags; do { getlin("Become what kind of monster? [type the name]", buf); + class = 0; mntmp = name_to_mon(buf); + if (mntmp < LOW_PM) { + class = name_to_monclass(buf, &mntmp); + if (class && mntmp == NON_PM) + mntmp = mkclass_poly(class); + } if (mntmp < LOW_PM) + if (!class) pline("I've never heard of such monsters."); + else + You_cant("polymorph into any of those."); else if (iswere && (were_beastie(mntmp) == u.ulycn || mntmp == counter_were(u.ulycn) || (Upolyd && mntmp == PM_HUMAN))) @@ -301,7 +310,7 @@ int psflags; your_race(&mons[mntmp]) || mntmp == urole.malenum || mntmp == urole.femalenum)) - You("cannot polymorph into that."); + You_cant("polymorph into that."); else break; } while (--tryct > 0); if (!tryct) pline(thats_enough_tries);