]> granicus.if.org Git - nethack/commitdiff
Hallucinatory rays
authorPasi Kallinen <paxed@alt.org>
Wed, 16 Feb 2022 19:09:20 +0000 (21:09 +0200)
committerPasi Kallinen <paxed@alt.org>
Wed, 16 Feb 2022 19:09:23 +0000 (21:09 +0200)
When hallucinating, use nonsensical names for the rays
(wands, spells, and breath weapons), and random ray glyphs.

Original code from xNetHack by copperwater <aosdict@gmail.com>,
inspired by a YANI by Kahran042.

doc/fixes3-7-0.txt
include/extern.h
src/mcastu.c
src/mthrowu.c
src/music.c
src/zap.c

index 95dacd28bd2ad289f09d1029c92d7e8e65f00384..5b28a3b391052781563ec0d360b7e044d176ad29 100644 (file)
@@ -780,6 +780,7 @@ don't show rusting of items that land in water
 the water used on the Plane of Water stops thrown or kicked items
 looting will do #force if you could do it and the container is locked
        and you didn't have a tool to unlock it
+use silly names for rays (such as breath weapons) when hallucinating
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index 75c8c92a72b59278c9b4ac8f62b37091e0d1fdce..0e2d2b655b6b6aee535226bf03f016c9734226d0 100644 (file)
@@ -1670,6 +1670,7 @@ extern void Delay(int);
 
 /* ### mthrowu.c ### */
 
+extern const char *rnd_hallublast(void);
 extern boolean m_has_launcher_and_ammo(struct monst *);
 extern int thitu(int, int, struct obj **, const char *);
 extern int ohitmon(struct monst *, struct obj *, int, boolean);
@@ -3279,6 +3280,7 @@ extern void destroy_item(int, int);
 extern int destroy_mitem(struct monst *, int, int);
 extern int resist(struct monst *, char, int, int);
 extern void makewish(void);
+extern const char *flash_str(int, boolean);
 
 #endif /* !MAKEDEFS_C && !MDLIB_C */
 
index b31572f28bfb6bd06962be333561c4d1005efb5f..c84ed4e8b440301d80596610ad22dcb3bec34cee 100644 (file)
@@ -45,8 +45,6 @@ static boolean is_undirected_spell(unsigned int, int);
 static boolean
 spell_would_be_useless(struct monst *, unsigned int, int);
 
-extern const char *const flash_types[]; /* from zap.c */
-
 /* feedback when frustrated monster couldn't cast a spell */
 static void
 cursetxt(struct monst *mtmp, boolean undirected)
@@ -873,7 +871,7 @@ buzzmu(register struct monst *mtmp, register struct attack *mattk)
         if (mattk->adtyp && (mattk->adtyp < 11)) { /* no cf unsigned >0 */
             if (canseemon(mtmp))
                 pline("%s zaps you with a %s!", Monnam(mtmp),
-                      flash_types[ad_to_typ(mattk->adtyp)]);
+                      flash_str(ad_to_typ(mattk->adtyp), FALSE));
             buzz(-ad_to_typ(mattk->adtyp), (int) mattk->damn, mtmp->mx,
                  mtmp->my, sgn(g.tbx), sgn(g.tby));
         } else
index 7f546d8157c01b69178bebb37a9a1d60e3fb0537..a5c9ddcffe324c2d79b25918a8b0b13f979b8f17 100644 (file)
@@ -7,6 +7,7 @@
 
 static int monmulti(struct monst *, struct obj *, struct obj *);
 static void monshoot(struct monst *, struct obj *, struct obj *);
+static const char* breathwep_name(int);
 static int drop_throw(struct obj *, boolean, int, int);
 static int m_lined_up(struct monst *, struct monst *);
 
@@ -22,6 +23,33 @@ static NEARDATA const char *breathwep[] = {
     "strange breath #9"
 };
 
+/* hallucinatory ray types */
+const char *const hallublasts[] = {
+    "asteroids", "beads", "bubbles", "butterflies", "champagne", "chaos",
+    "coins", "cotton candy", "crumbs", "dark matter", "darkness", "dust specks",
+    "emoticons", "emotions", "entropy", "flowers", "foam", "fog", "gamma rays",
+    "gelatin", "gemstones", "ghosts", "glass shards", "glitter", "good vibes",
+    "gravel", "gravity", "gravy", "grawlixes", "holy light", "hornets",
+    "hot air", "hyphens", "hypnosis", "infrared", "insects", "laser beams",
+    "leaves", "lightening", "logic gates", "magma", "marbles", "mathematics",
+    "megabytes", "metal shavings", "metapatterns", "meteors", "mist", "mud",
+    "music", "nanites", "needles", "noise", "nostalgia", "oil", "paint",
+    "photons", "pixels", "plasma", "polarity", "powder", "powerups",
+    "prismatic light", "pure logic", "purple", "radio waves", "rainbows",
+    "rock music", "rocket fuel", "rope", "sadness", "salt", "sand", "scrolls",
+    "sludge", "smileys", "snowflakes", "sparkles", "specularity", "spores",
+    "stars", "steam", "tetrahedrons", "text", "the past", "tornadoes",
+    "toxic waste", "ultraviolet light", "viruses", "water", "waveforms", "wind",
+    "X-rays", "zorkmids"
+};
+
+/* Return a random hallucinatory blast. */
+const char *
+rnd_hallublast(void)
+{
+    return hallublasts[rn2(SIZE(hallublasts))];
+}
+
 boolean
 m_has_launcher_and_ammo(struct monst* mtmp)
 {
@@ -829,6 +857,18 @@ spitmm(struct monst* mtmp, struct attack* mattk, struct monst* mtarg)
     return MM_MISS;
 }
 
+/* Return the name of a breath weapon. If the player is hallucinating, return
+ * a silly name instead.
+ * typ is AD_MAGM, AD_FIRE, etc */
+static const char *
+breathwep_name(int typ)
+{
+    if (Hallucination)
+        return rnd_hallublast();
+
+    return breathwep[typ - 1];
+}
+
 /* monster breathes at monster (ranged) */
 int
 breamm(struct monst* mtmp, struct attack* mattk, struct monst* mtarg)
@@ -858,7 +898,8 @@ breamm(struct monst* mtmp, struct attack* mattk, struct monst* mtarg)
             if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
                 boolean utarget = (mtarg == &g.youmonst);
                 if (canseemon(mtmp))
-                    pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
+                    pline("%s breathes %s!",
+                          Monnam(mtmp), breathwep_name(typ));
                 dobuzz((int) (-20 - (typ - 1)), (int) mattk->damn,
                        mtmp->mx, mtmp->my, sgn(g.tbx), sgn(g.tby), utarget);
                 nomul(0);
index 6cea749a55731c46505ffb0795957bad68389381..1e38064e3b5c93e4a400f48150e000c7184c5016 100644 (file)
@@ -601,8 +601,11 @@ do_improvisation(struct obj* instr)
                 losehp(damage, buf, KILLED_BY); /* fire or frost damage */
             }
         } else {
-            buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1,
-                 rn1(6, 6), u.ux, u.uy, u.dx, u.dy);
+            int type = (instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1;
+
+            if (!Blind)
+                pline("A %s blasts out of the horn!", flash_str(type, FALSE));
+            buzz(type, rn1(6, 6), u.ux, u.uy, u.dx, u.dy);
         }
         makeknown(instr->otyp);
         break;
index f9973720258db0afd3f90e761af8df0eb02bac36..efe8b0f43add0b8da120b3662ea7b9e616da6bd8 100644 (file)
--- a/src/zap.c
+++ b/src/zap.c
@@ -2766,9 +2766,8 @@ void
 ubreatheu(struct attack *mattk)
 {
     int dtyp = 20 + mattk->adtyp - 1;      /* breath by hero */
-    const char *fltxt = flash_types[dtyp]; /* blast of <something> */
 
-    zhitu(dtyp, mattk->damn, fltxt, u.ux, u.uy);
+    zhitu(dtyp, mattk->damn, flash_str(dtyp, TRUE), u.ux, u.uy);
 }
 
 /* light damages hero in gremlin form */
@@ -4246,14 +4245,14 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
     struct monst *mon;
     coord save_bhitpos;
     boolean shopdamage = FALSE;
-    const char *fltxt;
     struct obj *otmp;
     int spell_type;
+    int fltyp = (type <= -30) ? abstype : abs(type);
+    int habstype = Hallucination ? rn2(6) : abstype;
 
     /* if its a Hero Spell then get its SPE_TYPE */
     spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
 
-    fltxt = flash_types[(type <= -30) ? abstype : abs(type)];
     if (u.uswallow) {
         register int tmp;
 
@@ -4263,8 +4262,8 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
         if (!u.ustuck) {
             u.uswallow = 0;
         } else {
-            pline("%s rips into %s%s", The(fltxt), mon_nam(u.ustuck),
-                  exclam(tmp));
+            pline("%s rips into %s%s", The(flash_str(fltyp, FALSE)),
+                  mon_nam(u.ustuck), exclam(tmp));
             /* Using disintegration from the inside only makes a hole... */
             if (tmp == MAGIC_COOKIE)
                 u.ustuck->mhp = 0;
@@ -4280,7 +4279,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
         range = 1;
     save_bhitpos = g.bhitpos;
 
-    tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype));
+    tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, habstype));
     while (range-- > 0) {
         lsx = sx;
         sx += dx;
@@ -4322,7 +4321,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
             if (zap_hit(find_mac(mon), spell_type)) {
                 if (mon_reflects(mon, (char *) 0)) {
                     if (cansee(mon->mx, mon->my)) {
-                        hit(fltxt, mon, exclam(0));
+                        hit(flash_str(fltyp, FALSE), mon, exclam(0));
                         shieldeff(mon->mx, mon->my);
                         (void) mon_reflects(mon,
                                             "But it reflects from %s %s!");
@@ -4336,7 +4335,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                     if (is_rider(mon->data)
                         && abs(type) == ZT_BREATH(ZT_DEATH)) {
                         if (canseemon(mon)) {
-                            hit(fltxt, mon, ".");
+                            hit(flash_str(fltyp, FALSE), mon, ".");
                             pline("%s disintegrates.", Monnam(mon));
                             pline("%s body reintegrates before your %s!",
                                   s_suffix(Monnam(mon)),
@@ -4350,7 +4349,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                     }
                     if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) {
                         if (canseemon(mon)) {
-                            hit(fltxt, mon, ".");
+                            hit(flash_str(fltyp, FALSE), mon, ".");
                             pline("%s absorbs the deadly %s!", Monnam(mon),
                                   type == ZT_BREATH(ZT_DEATH) ? "blast"
                                                               : "ray");
@@ -4360,11 +4359,11 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                     }
 
                     if (tmp == MAGIC_COOKIE) { /* disintegration */
-                        disintegrate_mon(mon, type, fltxt);
+                        disintegrate_mon(mon, type, flash_str(fltyp, FALSE));
                     } else if (DEADMONSTER(mon)) {
                         if (type < 0) {
                             /* mon has just been killed by another monster */
-                            monkilled(mon, fltxt, AD_RBRE);
+                            monkilled(mon, flash_str(fltyp, FALSE), AD_RBRE);
                         } else {
                             int xkflags = XKILL_GIVEMSG; /* killed(mon); */
 
@@ -4382,7 +4381,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                         if (!otmp) {
                             /* normal non-fatal hit */
                             if (say || canseemon(mon))
-                                hit(fltxt, mon, exclam(tmp));
+                                hit(flash_str(fltyp, FALSE), mon, exclam(tmp));
                         } else {
                             /* some armor was destroyed; no damage done */
                             if (canseemon(mon))
@@ -4398,7 +4397,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                 range -= 2;
             } else {
                 if (say || canseemon(mon))
-                    miss(fltxt, mon);
+                    miss(flash_str(fltyp, FALSE), mon);
             }
         } else if (sx == u.ux && sy == u.uy && range >= 0) {
             nomul(0);
@@ -4407,7 +4406,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                 goto buzzmonst;
             } else if (zap_hit((int) u.uac, 0)) {
                 range -= 2;
-                pline("%s hits you!", The(fltxt));
+                pline("%s hits you!", The(flash_str(fltyp, FALSE)));
                 if (Reflecting) {
                     if (!Blind) {
                         (void) ureflects("But %s reflects from your %s!",
@@ -4419,10 +4418,12 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                     dy = -dy;
                     shieldeff(sx, sy);
                 } else {
-                    zhitu(type, nd, fltxt, sx, sy);
+                    /* flash_str here only used for killer; suppress
+                     * hallucination */
+                    zhitu(type, nd, flash_str(fltyp, TRUE), sx, sy);
                 }
             } else if (!Blind) {
-                pline("%s whizzes by you!", The(fltxt));
+                pline("%s whizzes by you!", The(flash_str(fltyp, FALSE)));
             } else if (abstype == ZT_LIGHTNING) {
                 Your("%s tingles.", body_part(ARM));
             }
@@ -4447,7 +4448,8 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
             if ((--range > 0 && isok(lsx, lsy) && cansee(lsx, lsy))
                 || fireball) {
                 if (Is_airlevel(&u.uz)) { /* nothing to bounce off of */
-                    pline_The("%s vanishes into the aether!", fltxt);
+                    pline_The("%s vanishes into the aether!",
+                              flash_str(fltyp, FALSE));
                     if (fireball)
                         type = ZT_WAND(ZT_FIRE); /* skip pending fireball */
                     break;
@@ -4456,7 +4458,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                     sy = lsy;
                     break; /* fireballs explode before the obstacle */
                 } else
-                    pline_The("%s bounces!", fltxt);
+                    pline_The("%s bounces!", flash_str(fltyp, FALSE));
             }
             if (!dx || !dy || !rn2(bchance)) {
                 dx = -dx;
@@ -4485,7 +4487,7 @@ dobuzz(int type, int nd, xchar sx, xchar sy, int dx, int dy,
                     dx = -dx;
                     break;
                 }
-                tmp_at(DISP_CHANGE, zapdir_to_glyph(dx, dy, abstype));
+                tmp_at(DISP_CHANGE, zapdir_to_glyph(dx, dy, habstype));
             }
         }
     }
@@ -5602,4 +5604,25 @@ makewish(void)
     }
 }
 
+/* Fills buf with the appropriate string for this ray.
+ * In the hallucination case, insert "blast of <silly thing>".
+ * Assumes that the caller will specify typ in the appropriate range for
+ * wand/spell/breath weapon. */
+const char*
+flash_str(int typ,
+          boolean nohallu) /* suppress hallucination (for death reasons) */
+{
+    static char fltxt[BUFSZ];
+    if (Hallucination && !nohallu) {
+        /* always return "blast of foo" for simplicity.
+         * This could be extended with hallucinatory rays, but probably not worth
+         * it at this time. */
+        Sprintf(fltxt, "blast of %s", rnd_hallublast());
+    }
+    else {
+        Strcpy(fltxt, flash_types[typ]);
+    }
+    return fltxt;
+}
+
 /*zap.c*/