Skip to content

Commit

Permalink
Make pit fiends live up to their name.
Browse files Browse the repository at this point in the history
Pit fiends now have an attack that creates pits.  If the attack tries
to create a pit where there already is one, it turns into a hole.

Most types of non-floor terrain and dungeon features and some kinds of
existing traps are exempt from being converted.
  • Loading branch information
tsadok committed Apr 19, 2015
1 parent 8bd0300 commit 17ac4d7
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 37 deletions.
3 changes: 3 additions & 0 deletions doc/changelog-fourk.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ Chronological Changelog (most recent at top):
Changes in 4.3.0.1:
-------------------

* Some monsters have been given more interesting attacks. Notably,
pit fiends now have an attack that creates pits.

* Fixing status ailments with a unicorn horn is now mostly free; the
only penalty is that a blessed horn can become uncursed. Blessed
horns are now guaranteed to fix at least one trouble (assuming you
Expand Down
3 changes: 3 additions & 0 deletions libnethack/include/extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ extern void bury_objs(struct level *, int, int);
extern void unearth_objs(struct level *lev, int x, int y);
extern void rot_organic(void *, long);
extern void rot_corpse(void *, long);
extern void pit_under_player(int);
extern void pit_under_monster(struct monst *, int, boolean);
extern void do_pit_attack(struct level *, struct monst *, struct monst *);

/* ### display.c ### */

Expand Down
3 changes: 2 additions & 1 deletion libnethack/include/monattk.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
# define AD_ENCH 41 /* remove enchantment (disenchanter) */
# define AD_CORR 42 /* corrode armor (black pudding) */
# define AD_FLPN 43 /* you feel the monster's pain -- very special-cased */
# define AD_OTHER 44 /* Numbers starting here can be used for non-damage
# define AD_PITS 45 /* creates pits */
# define AD_OTHER 46 /* Numbers starting here can be used for non-damage
* constants stored in a damage type field, such as the
* field in the artilist that governs what an artifact
* grants when equipped, which in vanilla can only be a
Expand Down
205 changes: 205 additions & 0 deletions libnethack/src/dig.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ static schar fillholetyp(int, int);
static void dig_up_grave(void);
static boolean dighole(boolean);
static struct obj *bury_an_obj(struct obj *);
static void no_pit_message(struct monst *, struct monst *);

/* Indices returned by dig_typ() */
#define DIGTYP_UNDIGGABLE 0
Expand Down Expand Up @@ -1477,4 +1478,208 @@ rot_corpse(void *arg, long timeout)
update_inventory();
}

/* Called when a new pit is created under the player. */
void
pit_under_player(int typ)
{
if (Levitation || Flying || is_clinger(youmonst.data)) {
pline("A chasm opens up under you!");
pline("You don't fall in!");
} else {
pline("You fall into a chasm!");
if (typ == HOLE) {
fall_through(TRUE);
} else {
u.utrap = rn1(6, 2);
u.utraptype = TT_PIT;
turnstate.vision_full_recalc = TRUE;
losehp(rnd(6), "fell into a chasm");
selftouch("Falling, you",
"falling into a chasm while wielding");
}
}
}

/* Called when a new pit is created under a monster. */
void
pit_under_monster(struct monst *mtmp, int typ, boolean blameplayer)
{
if (mtmp == &youmonst) {
pit_under_player(typ);
return;
}
if (!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) {
mtmp->mtrapped = 1;
if (cansee(mtmp->mx, mtmp->my))
pline("%s falls into a chasm!", Monnam(mtmp));
else if (humanoid(mtmp->data))
You_hear("a scream!");

if (typ == HOLE)
mlevel_tele_trap(mtmp, t_at(level, mtmp->mx, mtmp->my),
FALSE, cansee(mtmp->mx, mtmp->my));
else {
mselftouch(mtmp, "Falling, ", TRUE);
if (mtmp->mhp > 0)
if ((mtmp->mhp -= rnd(6)) <= 0) {
if (!cansee(mtmp->mx, mtmp->my))
pline("It is destroyed!");
else if (!blameplayer)
pline("%s is destroyed", Monnam(mtmp));
else {
pline("You destroy %s!",
mtmp->mtame ?
x_monnam(mtmp, ARTICLE_THE,
"poor", mtmp->mnamelth ?
SUPPRESS_SADDLE : 0,
FALSE) : mon_nam(mtmp));
}
if (blameplayer)
xkilled(mtmp, 0);
}
}
}
}

void
no_pit_message(struct monst *magr, struct monst *mdef)
{
if (magr == &youmonst)
pline("The %s near %s is inhospitable, the epitome of hardness.",
surface(m_mx(mdef), m_my(mdef)),
mon_nam(mdef));
else
pline("%s %s %s.", Monnam(magr),
(m_cansee(magr, m_mx(mdef), m_my(mdef)) ?
"looks piteously at" :
mindless(magr->data) ? "capitulates to" :
"thinks piteously about"),
(mdef == &youmonst) ? "you" : mon_nam(mdef));
}

/* I'm designing this function so that it can be called more or less identically
for the mhitu, mhitm, and uhitm cases. The defender's tile always gets a pit
unless it's an immune tile (certain terrains, dungeon features, and trap
types are immune, and undiggable floor of course). The attacker's tile never
gets a pit unless it is also the defender's tile (which however may be
possible in the case of an engulfed player pit fiend). Other tiles in the
vicinity may get pits or not. */
void
do_pit_attack(struct level *lev, struct monst *mdef, struct monst *magr)
{
struct monst *mtmp; /* monster at target location */
struct obj *otmp; /* object, likewise */
struct trap *chasm, *oldtrap; /* chasm is a new one, oldtrap extant */
int x, y, i, tries, newtyp;
int pcount = rne(2);
boolean growlarger = FALSE;

if (!can_dig_down(lev)) {
no_pit_message(magr, mdef);
return;
}

for (i = 0; i < pcount; i++) {
tries = 0;
if (i==0) {
x = m_mx(mdef);
y = m_my(mdef);
} else {
do {
x = m_mx(mdef) + (rn2(2) ? -1 : 1) * (rne(2)-1);
y = m_my(mdef) + (rn2(2) ? -1 : 1) * (rne(2)-1);
} while ((!isok(x, y) ||
((x == m_mx(magr)) && (y == m_my(magr))) ||
((x == m_mx(mdef)) && (y == m_my(mdef))) ||
!((lev->locations[x][y].typ == ROOM) ||
(lev->locations[x][y].typ == DOOR) ||
(lev->locations[x][y].typ == GRAVE) ||
(lev->locations[x][y].typ == CORR) ||
(lev->locations[x][y].typ == SCORR) ||
(lev->locations[x][y].typ == ICE))) &&
(tries++ < 25));
}
if (tries >= 25) {
no_pit_message(magr, mdef);
return;
} else if (isok(x, y)) {
oldtrap = t_at(lev, x, y);
if (oldtrap && ((oldtrap->ttyp == PIT) ||
(oldtrap->ttyp == SPIKED_PIT))) {
growlarger = TRUE;
newtyp = HOLE;
} else {
switch (rn2(6)) {
case 1:
case 2:
newtyp = SPIKED_PIT;
case 3:
newtyp = HOLE;
default:
newtyp = PIT;
}
}
/* Some types of traps should not be converted to pits. */
if (oldtrap &&
((oldtrap->ttyp == MAGIC_PORTAL) ||
(oldtrap->ttyp == VIBRATING_SQUARE))) {
no_pit_message(magr, mdef);
return;
} else if (oldtrap && (newtyp != HOLE) &&
((oldtrap->ttyp == PIT) ||
(oldtrap->ttyp == SPIKED_PIT) ||
(oldtrap->ttyp == HOLE))) {
mtmp = m_at(lev, x, y);
if (cansee(x, y))
pline("The chasm%s seems to grow larger.",
((x == u.ux) && (y == u.uy)) ? " below you" :
mtmp ? msgprintf(" below %s", mon_nam(mtmp)) : "");
} else {
mtmp = m_at(lev, x, y);
if (mtmp)
mtmp->msleeping = 0;
/* When a drum of earthquake wakes monsters, it also unhides
mimics and other hiders. I prefer not to do that here
but need to test whether not doing so causes problems. */
if (oldtrap && (oldtrap->ttyp == BEAR_TRAP)) {
if (mtmp)
mtmp->mtrapped = 0;
cnv_trap_obj(lev, BEARTRAP, 1, oldtrap);
}
chasm = maketrap(lev, x, y, newtyp, rng_main);
if (chasm && cansee(x, y))
chasm->tseen = 1;
otmp = sobj_at(BOULDER, lev, x, y);
if (otmp) {
if (cansee(x, y))
pline("KADOOM! The boulder falls into a chasm%s!",
((x == u.ux) &&
(y == u.uy)) ? " below you" : "");
if (mtmp)
mtmp->mtrapped = 0;
obj_extract_self(otmp);
flooreffects(otmp, x, y, "");
}
/* If the new pit /hasn't/ just been filled by a boulder,
someone might fall into it. */
chasm = t_at(lev, x, y);
if (chasm) {
if (magr == &youmonst) {
chasm->madeby_u = 1;
}
if (mtmp && !(mtmp == &youmonst)) {
pit_under_monster(mtmp, newtyp, (magr == &youmonst));
} else if (!u.utrap && x == u.ux && y == u.uy) {
pit_under_player(newtyp);
} else if (cansee(x,y))
pline("A chasm %s in the %s.",
(growlarger ? "widens" : "opens"),
surface(x, y));
newsym(x, y);
}
}
}
}
}

/*dig.c*/
3 changes: 3 additions & 0 deletions libnethack/src/mhitm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,9 @@ mdamagem(struct monst *magr, struct monst *mdef, const struct attack *mattk)
/* there's no msomearmor() function, so just do damage */
/* if (cancelled) break; */
break;
case AD_PITS:
do_pit_attack(level, mdef, magr);
break;
default:
tmp = 0;
break;
Expand Down
3 changes: 3 additions & 0 deletions libnethack/src/mhitu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,9 @@ hitmu(struct monst *mtmp, const struct attack *mattk)
}
}
break;
case AD_PITS:
do_pit_attack(level, &youmonst, mtmp);
break;
default:
dmg = 0;
break;
Expand Down
4 changes: 3 additions & 1 deletion libnethack/src/monst.c
Original file line number Diff line number Diff line change
Expand Up @@ -2640,7 +2640,9 @@ const struct permonst mons[] = {
MON("pit fiend", S_DEMON,
LVL(13, 6, -3, 65, -13), (G_HELL | G_NOCORPSE | 2),
A(ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_WEAP, AD_PHYS, 4, 2),
ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
/* I'd like to make the AD_PITS attack AT_GAZE, but that
would take more doing. For now... */
ATTK(AT_CLAW, AD_PITS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, 0, MS_GROWL, MZ_LARGE),
MR_FIRE | MR_POISON, 0,
M1_SEE_INVIS | M1_POIS,
Expand Down
38 changes: 3 additions & 35 deletions libnethack/src/music.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,42 +299,10 @@ do_earthquake(int force)
/* We have to check whether monsters or player falls in a
chasm... */

if (mtmp) {
if (!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) {
mtmp->mtrapped = 1;
if (cansee(x, y))
pline("%s falls into a chasm!", Monnam(mtmp));
else if (humanoid(mtmp->data))
You_hear("a scream!");
mselftouch(mtmp, "Falling, ", TRUE);
if (mtmp->mhp > 0)
if ((mtmp->mhp -= rnd(6)) <= 0) {
if (!cansee(x, y))
pline("It is destroyed!");
else {
pline("You destroy %s!",
mtmp->mtame ?
x_monnam(mtmp, ARTICLE_THE,
"poor", mtmp->mnamelth ?
SUPPRESS_SADDLE : 0,
FALSE) : mon_nam(mtmp));
}
xkilled(mtmp, 0);
}
}
if (mtmp && !(mtmp == &youmonst)) {
pit_under_monster(mtmp, PIT, TRUE);
} else if (!u.utrap && x == u.ux && y == u.uy) {
if (Levitation || Flying || is_clinger(youmonst.data)) {
pline("A chasm opens up under you!");
pline("You don't fall in!");
} else {
pline("You fall into a chasm!");
u.utrap = rn1(6, 2);
u.utraptype = TT_PIT;
turnstate.vision_full_recalc = TRUE;
losehp(rnd(6), "fell into a chasm");
selftouch("Falling, you",
"falling into a chasm while wielding");
}
pit_under_player(PIT);
} else
newsym(x, y);
break;
Expand Down
3 changes: 3 additions & 0 deletions libnethack/src/uhitm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1727,6 +1727,9 @@ damageum(struct monst *mdef, const struct attack *mattk)
mdef->mconf = 1;
}
break;
case AD_PITS:
do_pit_attack(level, mdef, &youmonst);
break;
default:
tmp = 0;
break;
Expand Down

0 comments on commit 17ac4d7

Please sign in to comment.