]> granicus.if.org Git - nethack/commitdiff
Hallucination vs gaze attacks (trunk only)
authornethack.rankin <nethack.rankin>
Tue, 29 May 2007 02:00:25 +0000 (02:00 +0000)
committernethack.rankin <nethack.rankin>
Tue, 29 May 2007 02:00:25 +0000 (02:00 +0000)
     Suggested by <Someone> in March, 2005 based on newsgroup discussion
at the time:  hallucination protects against touch of death attack by
disrupting how the hero's brain reacts, so why not against gaze attacks
too?  This gives hallucinating hero 75% chance of being unaffected by
gazes.  If unaffected or if the gazer has been cancelled, the gaze will
fail with some feedback.  Previously, all cancelled gazes failed but only
Medusa's gave feedback.

     This will give players another way to defeat Medusa, but since it
isn't foolproof and there are several sure fire ways already, I don't
think it'll hurt play balance there.  It may be useful to avoid getting
repeatedly stunned by Archons though.

doc/fixes35.0
src/apply.c
src/mhitu.c
src/polyself.c
src/uhitm.c

index ce95be87cc4efe5ed4b1023f5ebb6348933dc500..225180b9bb2ea19a9a632be8fb17ec3cf11cafb8 100644 (file)
@@ -344,6 +344,7 @@ pile_limit option to control when to switch to "there are objects here"
 some monsters will use fire to prevent selves being turned into green slime
 add `#vanquished' debug mode command
 C and #name commands are now same and use menu to choose monster vs object
+hallucination provides partial protection against gaze attacks
 
 
 Platform- and/or Interface-Specific New Features
index f889fb265aa1c81dce37a0e573d5140a8564868a..1d30731816c59edde6d0125412f0fd8f9eaafaaa 100644 (file)
@@ -751,7 +751,8 @@ struct obj *obj;
                                pline("Yow!  The %s stares back!", mirror);
                            else
                                pline("Yikes!  You've frozen yourself!");
-                           nomul(-rnd((MAXULEV+6) - u.ulevel));
+                           if (!Hallucination || !rn2(4))
+                               nomul(-rnd(MAXULEV + 6 - u.ulevel));
                            nomovemsg = 0;  /* default, "you can move again" */
                        }
                    } else if (youmonst.data->mlet == S_VAMPIRE)
index b181dbe6b478927dec0bbf5412100459a7ce4505..1e38b0c8d69a39fff508989bac563b4cc0a43085 100644 (file)
@@ -1921,17 +1921,38 @@ gazemu(mtmp, mattk)     /* monster gazes at you */
        register struct monst *mtmp;
        register struct attack  *mattk;
 {
+       static const char * const reactions[] = {
+           "confused",                 /* [0] */
+           "stunned",                  /* [1] */
+           "puzzled", "dazzled",       /* [2,3] */
+           "irritated", "inflamed",    /* [4,5] */
+           "tired",                    /* [6] */
+           "dulled",                   /* [7] */
+       };
+       int react = -1;
+       boolean cancelled = (mtmp->mcan != 0), already = FALSE;
+
+       /* assumes that hero has to see monster's gaze in order to be
+          affected, rather than monster just having to look at hero;
+          when hallucinating, hero's brain doesn't register what
+          it's seeing correctly so the gaze is usually ineffective
+          [this could be taken a lot farther and select a gaze effect
+          appropriate to what's currently being displayed, giving
+          ordinary monsters a gaze attack when hero thinks he or she
+          is facing a gazing creature, but let's not go that far...] */
+       if (Hallucination && rn2(4)) cancelled = TRUE;
+
        switch(mattk->adtyp) {
-           case AD_STON:
-               if (mtmp->mcan || !mtmp->mcansee) {
+       case AD_STON:
+           if (cancelled || !mtmp->mcansee) {
                    if (!canseemon(mtmp)) break;        /* silently */
                    pline("%s %s.", Monnam(mtmp),
                          (mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan) ?
                                "doesn't look all that ugly" :
                                "gazes ineffectually");
                    break;
-               }
-               if (Reflecting && couldsee(mtmp->mx, mtmp->my) &&
+           }
+           if (Reflecting && couldsee(mtmp->mx, mtmp->my) &&
                        mtmp->data == &mons[PM_MEDUSA]) {
                    /* hero has line of sight to Medusa and she's not blind */
                    boolean useeit = canseemon(mtmp);
@@ -1956,8 +1977,8 @@ gazemu(mtmp, mattk)       /* monster gazes at you */
 
                    if (mtmp->mhp > 0) break;
                    return 2;
-               }
-               if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
+           }
+           if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
                    !Stone_resistance) {
                    You("meet %s gaze.", s_suffix(mon_nam(mtmp)));
                    stop_occupation();
@@ -1967,12 +1988,15 @@ gazemu(mtmp, mattk)     /* monster gazes at you */
                    killer.format = KILLED_BY;
                    Strcpy(killer.name, mtmp->data->mname);
                    done(STONING);
-               }
-               break;
-           case AD_CONF:
-               if(!mtmp->mcan && canseemon(mtmp) &&
-                  couldsee(mtmp->mx, mtmp->my) &&
+           }
+           break;
+       case AD_CONF:
+           if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
                   mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
+               if (cancelled) {
+                   react = 0;  /* "confused" */
+                   already = (mtmp->mconf != 0);
+               } else {
                    int conf = d(3,4);
 
                    mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6));
@@ -1984,11 +2008,15 @@ gazemu(mtmp, mattk)     /* monster gazes at you */
                    make_confused(HConfusion + conf, FALSE);
                    stop_occupation();
                }
-               break;
-           case AD_STUN:
-               if(!mtmp->mcan && canseemon(mtmp) &&
-                  couldsee(mtmp->mx, mtmp->my) &&
+           }
+           break;
+       case AD_STUN:
+           if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
                   mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
+               if (cancelled) {
+                   react = 1;  /* "stunned" */
+                   already = (mtmp->mstun != 0);
+               } else {
                    int stun = d(2,6);
 
                    mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6));
@@ -1996,10 +2024,19 @@ gazemu(mtmp, mattk)     /* monster gazes at you */
                    make_stunned(HStun + stun, TRUE);
                    stop_occupation();
                }
-               break;
-           case AD_BLND:
-               if (!mtmp->mcan && canseemon(mtmp) && !resists_blnd(&youmonst)
-                       && distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) {
+           }
+           break;
+       case AD_BLND:
+           if (canseemon(mtmp) && !resists_blnd(&youmonst) &&
+                   distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) {
+               if (cancelled) {
+                   react = rn1(2,2);   /* "puzzled" || "dazzled" */
+                   already = (mtmp->mcansee == 0);
+                   /* Archons gaze every round; we don't want cancelled ones
+                      giving the "seems puzzled/dazzled" message that often */
+                   if (mtmp->mcan && mtmp->data == &mons[PM_ARCHON] && rn2(5))
+                       react = -1;
+               } else {
                    int blnd = d((int)mattk->damn, (int)mattk->damd);
 
                    You("are blinded by %s radiance!",
@@ -2012,12 +2049,15 @@ gazemu(mtmp, mattk)     /* monster gazes at you */
                    if (!Blind) Your(vision_clears);
                    else make_stunned((long)d(1,3),TRUE);
                }
-               break;
-           case AD_FIRE:
-               if (!mtmp->mcan && canseemon(mtmp) &&
-                       couldsee(mtmp->mx, mtmp->my) &&
+           }
+           break;
+       case AD_FIRE:
+           if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
                        mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
-                   int dmg = d(2,6);
+               if (cancelled) {
+                   react = rn1(2,4);   /* "irritated" || "inflamed" */
+               } else {
+                   int dmg = d(2,6), lev = (int)mtmp->m_lev;
 
                    pline("%s attacks you with a fiery gaze!", Monnam(mtmp));
                    stop_occupation();
@@ -2026,37 +2066,53 @@ gazemu(mtmp, mattk)     /* monster gazes at you */
                        dmg = 0;
                    }
                    burn_away_slime();
-                   if ((int) mtmp->m_lev > rn2(20))
-                       destroy_item(SCROLL_CLASS, AD_FIRE);
-                   if ((int) mtmp->m_lev > rn2(20))
-                       destroy_item(POTION_CLASS, AD_FIRE);
-                   if ((int) mtmp->m_lev > rn2(25))
-                       destroy_item(SPBOOK_CLASS, AD_FIRE);
+                   if (lev > rn2(20)) destroy_item(SCROLL_CLASS, AD_FIRE);
+                   if (lev > rn2(20)) destroy_item(POTION_CLASS, AD_FIRE);
+                   if (lev > rn2(25)) destroy_item(SPBOOK_CLASS, AD_FIRE);
                    if (dmg) mdamageu(mtmp, dmg);
                }
-               break;
+           }
+           break;
 #ifdef PM_BEHOLDER /* work in progress */
-           case AD_SLEE:
-               if(!mtmp->mcan && canseemon(mtmp) &&
-                  couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee &&
-                  multi >= 0 && !rn2(5) && !Sleep_resistance) {
-
+       case AD_SLEE:
+           if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
+               mtmp->mcansee && multi >= 0 && !rn2(5) && !Sleep_resistance) {
+               if (cancelled) {
+                   react = 6;  /* "tired" */
+                   already = (mtmp->mfrozen != 0);     /* can't happen... */
+               } else {
                    fall_asleep(-rnd(10), TRUE);
                    pline("%s gaze makes you very sleepy...",
                          s_suffix(Monnam(mtmp)));
                }
-               break;
-           case AD_SLOW:
-               if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
-                  (HFast & (INTRINSIC|TIMEOUT)) &&
-                  !defends(AD_SLOW, uwep) && !rn2(4))
-
+           }
+           break;
+       case AD_SLOW:
+           if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
+                   mtmp->mcansee && (HFast & (INTRINSIC|TIMEOUT)) &&
+                   !defends(AD_SLOW, uwep) && !rn2(4)) {
+               if (cancelled) {
+                   react = 7;  /* "dulled" */
+                   already = (mtmp->mspeed == MSLOW);
+               } else {
                    u_slow_down();
                    stop_occupation();
-               break;
-#endif
-           default: impossible("Gaze attack %d?", mattk->adtyp);
-               break;
+               }
+           }
+           break;
+#endif /* BEHOLDER */
+       default:
+           impossible("Gaze attack %d?", mattk->adtyp);
+           break;
+       }
+       if (react >= 0) {
+           if (Hallucination && rn2(3)) react = rn2(SIZE(reactions));
+           /* cancelled/hallucinatory feedback; monster might look "confused",
+              "stunned",&c but we don't actually set corresponding attribute */
+           pline("%s looks %s%s.", Monnam(mtmp),
+                 !rn2(3) ? "" : already ? "quite " :
+                       (!rn2(2) ? "a bit " : "somewhat "),
+                 reactions[react]);
        }
        return(0);
 }
index b7af15e226373e8055206d5cd488c13952742f80..27ff576876cc789bc488aef72349a51327ac0749 100644 (file)
@@ -1085,10 +1085,12 @@ dogaze()
            return 0;
        }
 
-
        if (Blind) {
            You_cant("see anything to gaze at.");
            return 0;
+       } else if (Hallucination) {
+           You_cant("gaze at anything you can see.");
+           return 0;
        }
        if (u.uen < 15) {
            You("lack the energy to use your special gaze!");
@@ -1109,12 +1111,10 @@ dogaze()
                        || mtmp->m_ap_type == M_AP_OBJECT) {
                    looked--;
                    continue;
-               } else if (flags.safe_dog && !Confusion && !Hallucination
-                 && mtmp->mtame) {
+               } else if (flags.safe_dog && mtmp->mtame && !Confusion) {
                    You("avoid gazing at %s.", y_monnam(mtmp));
                } else {
-                   if (flags.confirm && mtmp->mpeaceful && !Confusion
-                                                       && !Hallucination) {
+                   if (flags.confirm && mtmp->mpeaceful && !Confusion) {
                        Sprintf(qbuf, "Really %s %s?",
                            (adtyp == AD_CONF) ? "confuse" : "attack",
                            mon_nam(mtmp));
@@ -1137,26 +1137,28 @@ dogaze()
                                                        Monnam(mtmp));
                        mtmp->mconf = 1;
                    } else if (adtyp == AD_FIRE) {
-                       int dmg = d(2,6);
+                       int dmg = d(2,6), lev = (int)u.ulevel;
+
                        You("attack %s with a fiery gaze!", mon_nam(mtmp));
                        if (resists_fire(mtmp)) {
                            pline_The("fire doesn't burn %s!", mon_nam(mtmp));
                            dmg = 0;
                        }
-                       if((int) u.ulevel > rn2(20))
+                       if (lev > rn2(20))
                            (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
-                       if((int) u.ulevel > rn2(20))
+                       if (lev > rn2(20))
                            (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
-                       if((int) u.ulevel > rn2(25))
+                       if (lev > rn2(25))
                            (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
-                       if (dmg && !DEADMONSTER(mtmp)) mtmp->mhp -= dmg;
+                       if (dmg) mtmp->mhp -= dmg;
                        if (mtmp->mhp <= 0) killed(mtmp);
                    }
                    /* For consistency with passive() in uhitm.c, this only
                     * affects you if the monster is still alive.
                     */
-                   if (!DEADMONSTER(mtmp) &&
-                         (mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) {
+                   if (DEADMONSTER(mtmp)) continue;
+
+                   if (mtmp->data == &mons[PM_FLOATING_EYE] && !mtmp->mcan) {
                        if (!Free_action) {
                            You("are frozen by %s gaze!",
                                             s_suffix(mon_nam(mtmp)));
@@ -1175,8 +1177,7 @@ dogaze()
                     * works on the monster's turn, but for it to *not* have an
                     * effect would be too weird.
                     */
-                   if (!DEADMONSTER(mtmp) &&
-                           (mtmp->data == &mons[PM_MEDUSA]) && !mtmp->mcan) {
+                   if (mtmp->data == &mons[PM_MEDUSA] && !mtmp->mcan) {
                        pline(
                         "Gazing at the awake %s is not a very good idea.",
                            l_monnam(mtmp));
index 1c6b55653cdaa285c36c7f3743ae6c168666d638..3373ba7b5e0d93fc2f8dcd06771a930a19d7b98d 100644 (file)
@@ -2352,6 +2352,10 @@ boolean wep_was_destroyed;
                        else if (Free_action)
                            You("momentarily stiffen under %s gaze!",
                                    s_suffix(mon_nam(mon)));
+                       else if (Hallucination && rn2(4))
+                           pline("%s looks %s%s.", Monnam(mon),
+                                 !rn2(2) ? "" : "rather ",
+                                 !rn2(2) ? "numb" : "stupified");
                        else {
                            You("are frozen by %s gaze!",
                                  s_suffix(mon_nam(mon)));