]> granicus.if.org Git - nethack/commitdiff
fix pull request #485 - genetic engineer attacks
authorPatR <rankin@nethack.org>
Mon, 5 Apr 2021 03:06:45 +0000 (20:06 -0700)
committerPatR <rankin@nethack.org>
Mon, 5 Apr 2021 03:06:45 +0000 (20:06 -0700)
Pull request fixed two genetic engineer problems:
1) lack of "you hit <foo>" 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
src/mhitm.c
src/monst.c
src/uhitm.c

index b74a0cae460dbc38848c61a250b9b0f8e75ddb4f..8618ab6dc1b7dd099eb94cf9f07d64634307fe17 100644 (file)
@@ -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
index e6f990593ae641ed46666904d59a4cc4dbb551ca..6c046c9c0534ab63aa5feef891457f188fe0ac9f 100644 (file)
@@ -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);
index b225da0611d6de9b18d7ad4b76bd4832b3bff15e..2c7cb6424264d1b2f9a3c72dcb5114179eb1c410 100644 (file)
@@ -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
index d16b41acc5a1452576ff5655c56d69e8c177b872..ee5d3dfa0c36f26631e4204868db77474aa75f9b 100644 (file)
@@ -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);
 }