From 82476afdd6da4cae9cf07a5b3309bce3dba22ecc Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 12 Oct 2022 02:05:32 -0700 Subject: [PATCH] more github issue #679 - orc strength Handle alternate values for hero poly'd into a 'strongmonst' form more thoroughly by propagating max values other than 18/100 to the attribute manipulation routines. ATTRMAX(A_STR), which used to be a relatively simple expression, now contains a function call. Along the way, change the races[] terminator's value for 'mnum' from 0 (giant ant) to NON_PM. --- include/attrib.h | 6 ++-- include/extern.h | 4 ++- src/polyself.c | 79 +++++++++++++++++++++++++++++++++--------------- src/role.c | 51 ++++++++++++++++++------------- 4 files changed, 90 insertions(+), 50 deletions(-) diff --git a/include/attrib.h b/include/attrib.h index b3a5d82e7..17671f464 100644 --- a/include/attrib.h +++ b/include/attrib.h @@ -40,10 +40,8 @@ struct attribs { schar a[A_MAX]; }; -#define ATTRMAX(x) \ - ((x == A_STR && Upolyd && strongmonst(g.youmonst.data)) \ - ? STR18(100) \ - : g.urace.attrmax[x]) +#define ATTRMAX(x) \ + ((x == A_STR && Upolyd) ? uasmon_maxStr() : g.urace.attrmax[x]) #define ATTRMIN(x) (g.urace.attrmin[x]) #endif /* ATTRIB_H */ diff --git a/include/extern.h b/include/extern.h index 85c0afd09..815bf6a4e 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2152,6 +2152,7 @@ extern void change_sex(void); extern void livelog_newform(boolean, int, int); extern void polyself(int); extern int polymon(int); +extern schar uasmon_maxStr(void); extern void rehumanize(void); extern int dobreathe(void); extern int dospit(void); @@ -2398,14 +2399,15 @@ extern void rigid_role_checks(void); extern boolean setrolefilter(const char *); extern boolean gotrolefilter(void); extern void clearrolefilter(void); -extern char *build_plselection_prompt(char *, int, int, int, int, int); extern char *root_plselection_prompt(char *, int, int, int, int, int); +extern char *build_plselection_prompt(char *, int, int, int, int, int); extern void plnamesuffix(void); extern void role_selection_prolog(int, winid); extern void role_menu_extra(int, winid, boolean); extern void role_init(void); extern const char *Hello(struct monst *); extern const char *Goodbye(void); +extern const struct Race *character_race(short); /* ### rumors.c ### */ diff --git a/src/polyself.c b/src/polyself.c index be2ddcbcd..e8c2ee35b 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -683,7 +683,7 @@ polymon(int mntmp) char buf[BUFSZ]; boolean sticky = sticks(g.youmonst.data) && u.ustuck && !u.uswallow, was_blind = !!Blind, dochange = FALSE; - int mlvl; + int mlvl, newMaxStr; if (g.mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ You_feel("rather %s-ish.", @@ -760,33 +760,16 @@ polymon(int mntmp) /* New stats for monster, to last only as long as polymorphed. * Currently only strength gets changed. */ - if (strongmonst(&mons[mntmp]) && !is_elf(&mons[mntmp])) { - /* ettins, titans and minotaurs don't pass the is_giant() test; - giant mummies and giant zombies do but we throttle those; - Lord Surtur and Cyclops pass the test but can't be poly'd into */ - boolean live_H = is_giant(&mons[mntmp]) && !is_undead(&mons[mntmp]); - int newStr = live_H ? STR19(19) : STR18(100); - - /* hero orcs are limited to 18/50 for maximum strength, so treat - hero poly'd into an orc the same; goblins, orc shamans, and orc - zombies don't have strongmonst() attribute so won't get here; - hobgoblins and orc mummies do get here and are limited to 18/50 - like normal orcs; however, Uruk-hai retain 18/100 strength; - hero gnomes are also limited to 18/50; hero elves are limited to - 18/00 so we treat strongmonst elves (elf-noble, elven monarch) - as if they're not (in 'if' above, so they don't get here) */ - if ((is_orc(&mons[mntmp]) - && !strstri(pmname(&mons[mntmp], NEUTRAL), "Uruk")) - || is_gnome(&mons[mntmp])) - newStr = STR18(50); - - ABASE(A_STR) = AMAX(A_STR) = newStr; + newMaxStr = uasmon_maxStr(); + if (strongmonst(&mons[mntmp])) { + ABASE(A_STR) = AMAX(A_STR) = (schar) newMaxStr; } else { /* not a strongmonst(); if hero has exceptional strength, remove it (note: removal is temporary until returning to original form); we don't attempt to enforce lower maximum for wimpy forms; - we do avoid boosting current strength to 18 if presently less */ - AMAX(A_STR) = 18; /* same as STR18(0) */ + unlike for strongmonst, current strength does not get set to max */ + AMAX(A_STR) = (schar) newMaxStr; + /* make sure current is not higher than max (strip exceptional Str) */ if (ABASE(A_STR) > AMAX(A_STR)) ABASE(A_STR) = AMAX(A_STR); } @@ -981,6 +964,54 @@ polymon(int mntmp) return 1; } +/* determine hero's temporary strength value used while polymorphed; + hero poly'd into M2_STRONG monster usually gets 18/100 strength but + there are exceptions; non-M2_STRONG get maximum strength set to 18 */ +schar +uasmon_maxStr(void) +{ + const struct Race *R; + int newMaxStr; + int mndx = u.umonnum; + struct permonst *ptr = &mons[mndx]; + + if (is_orc(ptr)) { + if (mndx != PM_URUK_HAI) + mndx = PM_ORC; + } else if (is_elf(ptr)) { + mndx = PM_ELF; + } else if (is_dwarf(ptr)) { + mndx = PM_DWARF; + } else if (is_gnome(ptr)) { + mndx = PM_GNOME; +#if 0 /* use the mons[] value for humans */ + } else if (is_human(ptr)) { + mndx = PM_HUMAN; +#endif + } + R = character_race(mndx); + + if (strongmonst(ptr)) { + /* ettins, titans and minotaurs don't pass the is_giant() test; + giant mummies and giant zombies do but we throttle those */ + boolean live_H = is_giant(ptr) && !is_undead(ptr); + + /* hero orcs are limited to 18/50 for maximum strength, so treat + hero poly'd into an orc the same; goblins, orc shamans, and orc + zombies don't have strongmonst() attribute so won't get here; + hobgoblins and orc mummies do get here and are limited to 18/50 + like normal orcs; however, Uruk-hai retain 18/100 strength; + hero gnomes are also limited to 18/50; hero elves are limited + to 18/00 regardless of whether they're strongmonst, but the two + strongmonst types (monarchs and nobles) have current strength + set to 18 [by polymon()], the others don't */ + newMaxStr = R ? R->attrmax[A_STR] : live_H ? STR19(19) : STR18(100); + } else { + newMaxStr = R ? R->attrmax[A_STR] : 18; /* 18 is same as STR18(0) */ + } + return (schar) newMaxStr; +} + /* dropx() jacket for break_armor() */ static void dropp(struct obj *obj) diff --git a/src/role.c b/src/role.c index a83e45706..613f83c49 100644 --- a/src/role.c +++ b/src/role.c @@ -676,7 +676,7 @@ const struct Race races[] = { { 1, 0, 1, 0, 1, 0 } /* Energy */ }, /* Array terminator */ - { 0, 0, 0, 0 } + { 0, 0, 0, 0, { 0, 0 }, NON_PM } }; /* Table of all genders */ @@ -1697,11 +1697,10 @@ role_selection_prolog(int which, winid where) : !*g.plname ? not_yet : g.plname); putstr(where, 0, buf); Sprintf(buf, "%12s ", "role:"); - Strcat(buf, (which == RS_ROLE) ? choosing : (r == ROLE_NONE) - ? not_yet - : (r == ROLE_RANDOM) - ? rand_choice - : roles[r].name.m); + Strcat(buf, (which == RS_ROLE) ? choosing + : (r == ROLE_NONE) ? not_yet + : (r == ROLE_RANDOM) ? rand_choice + : roles[r].name.m); if (r >= 0 && roles[r].name.f) { /* distinct female name [caveman/cavewoman, priest/priestess] */ if (gend == 1) @@ -1713,25 +1712,22 @@ role_selection_prolog(int which, winid where) } putstr(where, 0, buf); Sprintf(buf, "%12s ", "race:"); - Strcat(buf, (which == RS_RACE) ? choosing : (c == ROLE_NONE) - ? not_yet - : (c == ROLE_RANDOM) - ? rand_choice - : races[c].noun); + Strcat(buf, (which == RS_RACE) ? choosing + : (c == ROLE_NONE) ? not_yet + : (c == ROLE_RANDOM) ? rand_choice + : races[c].noun); putstr(where, 0, buf); Sprintf(buf, "%12s ", "gender:"); - Strcat(buf, (which == RS_GENDER) ? choosing : (gend == ROLE_NONE) - ? not_yet - : (gend == ROLE_RANDOM) - ? rand_choice - : genders[gend].adj); + Strcat(buf, (which == RS_GENDER) ? choosing + : (gend == ROLE_NONE) ? not_yet + : (gend == ROLE_RANDOM) ? rand_choice + : genders[gend].adj); putstr(where, 0, buf); Sprintf(buf, "%12s ", "alignment:"); - Strcat(buf, (which == RS_ALGNMNT) ? choosing : (a == ROLE_NONE) - ? not_yet - : (a == ROLE_RANDOM) - ? rand_choice - : aligns[a].adj); + Strcat(buf, (which == RS_ALGNMNT) ? choosing + : (a == ROLE_NONE) ? not_yet + : (a == ROLE_RANDOM) ? rand_choice + : aligns[a].adj); putstr(where, 0, buf); } @@ -2078,4 +2074,17 @@ Goodbye(void) } } +/* if pmindex is any player race (not necessarily the hero's), + return a pointer to the races[] entry for it */ +const struct Race * +character_race(short pmindex) +{ + const struct Race *r; + + for (r = races; r->mnum >= LOW_PM; ++r) + if (r->mnum == pmindex) + return r; + return (const struct Race *) NULL; +} + /* role.c */