wishing fix

name_to_mon() has a bunch of alternate monster names, such as
"gray-elf" to match "grey-elf" and "ki rin" to match "ki-rin".  Those
worked as intended when they occurred at the end of a wish, but only
worked in the middle if their length was the same or one character
less than the canonical name in mons[].mname.

djinni figurine     -> h - a figurine of a djinni
genie figurine      -> i - a figurine of a djinni
figurine of mumak   -> j - a figurine of a mumak
mumak figurine      -> k - a figurine of a mumak
figurine of mumakil -> l - a figurine of a mumak
mumakil figurine    -> nothing fitting that description exists

(The one-less case worked because its following space ended up being
implicitly removed when skipping ahead by the length of mons[].mname;
subsequent explicit removal didn't find a space so was a no-op.)
This commit is contained in:
PatR
2020-04-19 04:58:18 -07:00
parent 37ef5a2561
commit 05403182eb
5 changed files with 52 additions and 12 deletions

View File

@@ -137,6 +137,10 @@ hostile monsters with launcher and ammo try to stay away from melee range
allow displacing peaceful creatures
unicorn horns don't restore attribute loss anymore
when a shop is changed from food to health food, change room type to match
wish parsing of things containing monster names would accept all supported
alternate spellings if they occurred at the end ("corpse of mumakil")
but only some when they occurred elsewhere ("gray-elf corpse" worked,
"mumakil corpse" yielded "does not exist") depending upon name length
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository

View File

@@ -1558,6 +1558,7 @@ E int FDECL(max_passive_dmg, (struct monst *, struct monst *));
E boolean FDECL(same_race, (struct permonst *, struct permonst *));
E int FDECL(monsndx, (struct permonst *));
E int FDECL(name_to_mon, (const char *));
E int FDECL(name_to_monplus, (const char *, const char **));
E int FDECL(name_to_monclass, (const char *, int *));
E int FDECL(gender, (struct monst *));
E int FDECL(pronoun_gender, (struct monst *, unsigned));

View File

@@ -329,7 +329,8 @@ int *rank_indx, *title_length;
register int i, j;
/* Loop through each of the roles */
for (i = 0; roles[i].name.m; i++)
for (i = 0; roles[i].name.m; i++) {
/* loop through each of the rank titles for role #i */
for (j = 0; j < 9; j++) {
if (roles[i].rank[j].m
&& !strncmpi(str, roles[i].rank[j].m,
@@ -351,6 +352,9 @@ int *rank_indx, *title_length;
: roles[i].malenum;
}
}
}
if (title_length)
*title_length = 0;
return NON_PM;
}

View File

@@ -678,10 +678,23 @@ struct alt_spl {
short pm_val;
};
/* figure out what type of monster a user-supplied string is specifying */
/* figure out what type of monster a user-supplied string is specifying;
ingore anything past the monster name */
int
name_to_mon(in_str)
const char *in_str;
{
return name_to_monplus(in_str, (const char **) 0);
}
/* figure out what type of monster a user-supplied string is specifying;
return a pointer to whatever is past the monster name--necessary if
caller wants to strip off the name and it matches one of the alternate
names rather the canonical mons[].mname */
int
name_to_monplus(in_str, remainder_p)
const char *in_str;
const char **remainder_p;
{
/* Be careful. We must check the entire string in case it was
* something such as "ettin zombie corpse". The calling routine
@@ -701,6 +714,9 @@ const char *in_str;
char buf[BUFSZ];
int len, slen;
if (remainder_p)
*remainder_p = (const char *) 0;
str = strcpy(buf, in_str);
if (!strncmp(str, "a ", 2))
@@ -767,6 +783,7 @@ const char *in_str;
{ "elf lord", PM_ELF_LORD },
{ "olog hai", PM_OLOG_HAI },
{ "arch lich", PM_ARCH_LICH },
{ "archlich", PM_ARCH_LICH },
/* Some irregular plurals */
{ "incubi", PM_INCUBUS },
{ "succubi", PM_SUCCUBUS },
@@ -785,9 +802,16 @@ const char *in_str;
};
register const struct alt_spl *namep;
for (namep = names; namep->name; namep++)
if (!strncmpi(str, namep->name, (int) strlen(namep->name)))
for (namep = names; namep->name; namep++) {
len = (int) strlen(namep->name);
if (!strncmpi(str, namep->name, len)
/* force full word (which could conceivably be possessive) */
&& (!str[len] || str[len] == ' ' || str[len] == '\'')) {
if (remainder_p)
*remainder_p = in_str + (&str[len] - buf);
return namep->pm_val;
}
}
}
for (len = 0, i = LOW_PM; i < NUMMONS; i++) {
@@ -813,7 +837,9 @@ const char *in_str;
}
}
if (mntmp == NON_PM)
mntmp = title_to_mon(str, (int *) 0, (int *) 0);
mntmp = title_to_mon(str, (int *) 0, &len);
if (len && remainder_p)
*remainder_p = in_str + (&str[len] - buf);
return mntmp;
}

View File

@@ -3585,19 +3585,24 @@ struct obj *no_wish;
&& strncmpi(bp, "ninja-to", 8) /* not the "ninja" rank */
&& strncmpi(bp, "master key", 10) /* not the "master" rank */
&& strncmpi(bp, "magenta", 7)) { /* not the "mage" rank */
const char *rest = 0;
if (mntmp < LOW_PM && strlen(bp) > 2
&& (mntmp = name_to_mon(bp)) >= LOW_PM) {
int mntmptoo, mntmplen; /* double check for rank title */
&& (mntmp = name_to_monplus(bp, &rest)) >= LOW_PM) {
char *obp = bp;
mntmptoo = title_to_mon(bp, (int *) 0, &mntmplen);
bp += (mntmp != mntmptoo) ? (int) strlen(mons[mntmp].mname)
: mntmplen;
/* 'rest' is a pointer past the matching portion; if that was
an alternate name or a rank title rather than the canonical
monster name we wouldn't otherwise know how much to skip */
bp = (char *) rest; /* cast away const */
if (*bp == ' ') {
bp++;
} else if (!strncmpi(bp, "s ", 2)) {
} else if (!strncmpi(bp, "s ", 2)
|| (bp > origbp && !strncmpi(bp - 1, "s' ", 3))) {
bp += 2;
} else if (!strncmpi(bp, "es ", 3)) {
} else if (!strncmpi(bp, "es ", 3)
|| !strncmpi(bp, "'s ", 3)) {
bp += 3;
} else if (!*bp && !actualn && !dn && !un && !oclass) {
/* no referent; they don't really mean a monster type */