From: Pasi Kallinen Date: Wed, 16 Feb 2022 19:09:20 +0000 (+0200) Subject: Hallucinatory rays X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=122634ec9ebccac5154a40b7aefe50f09cc9acf5;p=nethack Hallucinatory rays When hallucinating, use nonsensical names for the rays (wands, spells, and breath weapons), and random ray glyphs. Original code from xNetHack by copperwater , inspired by a YANI by Kahran042. --- diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 95dacd28b..5b28a3b39 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -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 diff --git a/include/extern.h b/include/extern.h index 75c8c92a7..0e2d2b655 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 */ diff --git a/src/mcastu.c b/src/mcastu.c index b31572f28..c84ed4e8b 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -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 diff --git a/src/mthrowu.c b/src/mthrowu.c index 7f546d815..a5c9ddcff 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -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); diff --git a/src/music.c b/src/music.c index 6cea749a5..1e38064e3 100644 --- a/src/music.c +++ b/src/music.c @@ -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; diff --git a/src/zap.c b/src/zap.c index f99737202..efe8b0f43 100644 --- 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 */ - 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 ". + * 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*/