From 28f112fb1700109ac999ea85b5117d477c5bf182 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 4 Apr 2021 20:06:45 -0700 Subject: [PATCH] fix pull request #485 - genetic engineer attacks Pull request fixed two genetic engineer problems: 1) lack of "you hit " message when you were poly'd into one; 2) lack of shield effect animation ('sparkle') when a genetic engineer hit magic resistant hero. That opened a can o' worms. 3) hero lacking see invisible, poly'd into genetic engineer, and turning target into an invisible stalker got no feedback about the target vanishing. A genetic engineer attacking a monster would polymorph it turn after turn. 4) put back the teleport capability I removed when bringing it over from slash'em; 5) have genetic engineer teleport away after polymorphing someone. The various mhitm_ad_XXXX() routines used g.vis to have caller decide visibility, but hmonas() for poly'd hero didn't set that so some messages--not just attack induced polymorph--were based on visibility of earlier monster vs monster activity. 6) have hmonas() set up g.vis even though it doesn't use that. There may have been one or two other minor fixes before I managed to force the lid back onto the can. Fixes #485 --- doc/fixes37.0 | 3 +++ src/mhitm.c | 31 +++++++++++++++++++++++-------- src/monst.c | 2 +- src/uhitm.c | 23 ++++++++++++++--------- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index b74a0cae4..8618ab6dc 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -584,6 +584,9 @@ avoid "Not carrying anything. Never mind." for 'force_invmenu' 'altmeta' option could be toggled On but once On could not be toggled back Off wearing a ring of protection and any amulet behaved as if wearing an amulet of guarding when determining MC value +messaging for genetic engineer attacks had several problems +give genetic engineers teleport capability (as they had in slash'em); 'port + away after polymorphing someone so that they don't just repeat that curses: 'msg_window' option wasn't functional for curses unless the binary also included tty support diff --git a/src/mhitm.c b/src/mhitm.c index e6f990593..6c046c9c0 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -946,9 +946,11 @@ mdamagem(struct monst *magr, struct monst *mdef, int mon_poly(struct monst *magr, struct monst *mdef, int dmg) { + static const char freaky[] = " undergoes a freakish metamorphosis"; + if (mdef == &g.youmonst) { if (Antimagic) { - shieldeff(mdef->mx, mdef->my); + shieldeff(u.ux, u.uy); } else if (Unchanging) { ; /* just take a little damage */ } else { @@ -994,14 +996,27 @@ mon_poly(struct monst *magr, struct monst *mdef, int dmg) monkilled(mdef, "", AD_RBRE); } } else if (newcham(mdef, (struct permonst *) 0, FALSE, FALSE)) { - if (g.vis && canspotmon(mdef)) - pline("%s%s turns into %s.", Before, - !flags.verbose ? "" - : " undergoes a freakish metamorphosis and", - x_monnam(mdef, ARTICLE_A, (char *) 0, - (SUPPRESS_NAME | SUPPRESS_IT - | SUPPRESS_INVISIBLE), FALSE)); + if (g.vis) { /* either seen or adjacent */ + boolean was_seen = !!strcmpi("It", Before), + verbosely = flags.verbose || !was_seen; + + if (canspotmon(mdef)) + pline("%s%s%s turns into %s.", Before, + verbosely ? freaky : "", verbosely ? " and" : "", + x_monnam(mdef, ARTICLE_A, (char *) 0, + (SUPPRESS_NAME | SUPPRESS_IT + | SUPPRESS_INVISIBLE), FALSE)); + else if (was_seen || magr == &g.youmonst) + pline("%s%s%s.", Before, freaky, + !was_seen ? "" : " and disappears"); + } dmg = 0; + if (can_teleport(magr->data)) { + if (magr == &g.youmonst) + tele(); + else if (!tele_restrict(magr)) + (void) rloc(magr, TRUE); + } } else { if (g.vis && flags.verbose) pline1(nothing_happens); diff --git a/src/monst.c b/src/monst.c index b225da061..2c7cb6424 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1760,7 +1760,7 @@ struct permonst _mons2[] = { A(ATTK(AT_CLAW, AD_POLY, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 20, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0, - M1_HUMANOID | M1_OMNIVORE | M1_POIS, M2_HOSTILE | M2_NASTY, + M1_HUMANOID | M1_OMNIVORE | M1_POIS | M1_TPORT, M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE, 14, CLR_GREEN), /* * Rust monster or disenchanter diff --git a/src/uhitm.c b/src/uhitm.c index d16b41acc..ee5d3dfa0 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -3087,27 +3087,27 @@ mhitm_ad_conf(struct monst *magr, struct attack *mattk, struct monst *mdef, } void -mhitm_ad_poly(struct monst *magr, - struct attack *mattk UNUSED, /* implied */ - struct monst *mdef, - struct mhitm_data *mhm) +mhitm_ad_poly(struct monst *magr, struct attack *mattk, + struct monst *mdef, struct mhitm_data *mhm) { if (magr == &g.youmonst) { /* uhitm */ int armpro = magic_negation(mdef); - /* since hero can't be cancelled, only defender's armor applies */ - boolean negated = !(rn2(10) >= 3 * armpro); + /* require weaponless attack in order to honor AD_POLY; + since hero can't be cancelled, only defender's armor applies */ + boolean negated = uwep || !(rn2(10) >= 3 * armpro); if (!negated && mhm->damage < mdef->mhp) - mhm->damage = mon_poly(magr, mdef, mhm->damage); + mhm->damage = mon_poly(&g.youmonst, mdef, mhm->damage); } else if (mdef == &g.youmonst) { /* mhitu */ - int armpro = magic_negation(mdef); + int armpro = magic_negation(&g.youmonst); boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + hitmsg(magr, mattk); if (uncancelled && Maybe_Half_Phys(mhm->damage) < (Upolyd ? u.mh : u.uhp)) - mhm->damage = mon_poly(magr, mdef, mhm->damage); + mhm->damage = mon_poly(magr, &g.youmonst, mhm->damage); } else { /* mhitm */ if (!magr->mcan && mhm->damage < mdef->mhp) @@ -4414,6 +4414,9 @@ hmonas(struct monst *mon) dhit = 0, attknum = 0; int dieroll, multi_claw = 0; + /* not used here but umpteen mhitm_ad_xxxx() need this */ + g.vis = (canseemon(mon) || distu(mon->mx, mon->my) <= 2); + /* with just one touch/claw/weapon attack, both rings matter; with more than one, alternate right and left when checking whether silver ring causes successful hit */ @@ -4793,6 +4796,8 @@ hmonas(struct monst *mon) if (g.multi < 0) break; /* If paralyzed while attacking, i.e. floating eye */ } + + g.vis = FALSE; /* reset */ /* return value isn't used, but make it match hitum()'s */ return !DEADMONSTER(mon); }