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 <aosdict@gmail.com>,
inspired by a YANI by Kahran042.
This commit is contained in:
Pasi Kallinen
2022-02-16 21:09:20 +02:00
parent f588a707bb
commit 122634ec9e
6 changed files with 94 additions and 26 deletions

View 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

View 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 */

View 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

View 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);

View 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;

View File

@@ -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*/