Split kicking non-door terrain out of dokick

This commit is contained in:
Pasi Kallinen
2024-01-25 21:43:55 +02:00
parent 4be4f55ccf
commit 47fa2eb000
+216 -208
View File
@@ -23,6 +23,7 @@ static boolean watchman_door_damage(struct monst *,
static void kick_dumb(coordxy, coordxy); static void kick_dumb(coordxy, coordxy);
static void kick_ouch(coordxy, coordxy, const char *) NONNULLARG3; static void kick_ouch(coordxy, coordxy, const char *) NONNULLARG3;
static void kick_door(coordxy, coordxy, int); static void kick_door(coordxy, coordxy, int);
static int kick_nondoor(coordxy, coordxy, int);
static void otransit_msg(struct obj *, boolean, boolean, long); static void otransit_msg(struct obj *, boolean, boolean, long);
static void drop_to(coord *, schar, coordxy, coordxy) NONNULLARG1; static void drop_to(coord *, schar, coordxy, coordxy) NONNULLARG1;
@@ -897,6 +898,7 @@ kick_ouch(coordxy x, coordxy y, const char *kickobjnam)
hurtle(-u.dx, -u.dy, rn1(2, 4), TRUE); /* assume it's heavy */ hurtle(-u.dx, -u.dy, rn1(2, 4), TRUE); /* assume it's heavy */
} }
/* kick a door */
static void static void
kick_door(coordxy x, coordxy y, int avrg_attrib) kick_door(coordxy x, coordxy y, int avrg_attrib)
{ {
@@ -955,215 +957,10 @@ kick_door(coordxy x, coordxy y, int avrg_attrib)
} }
} }
/* the #kick command */ /* kick non-door terrain */
int static int
dokick(void) kick_nondoor(coordxy x, coordxy y, int avrg_attrib)
{ {
coordxy x, y;
int avrg_attrib;
int glyph, oldglyph = -1;
register struct monst *mtmp;
boolean no_kick = FALSE;
if (nolimbs(gy.youmonst.data) || slithy(gy.youmonst.data)) {
You("have no legs to kick with.");
no_kick = TRUE;
} else if (verysmall(gy.youmonst.data)) {
You("are too small to do any kicking.");
no_kick = TRUE;
} else if (u.usteed) {
if (yn_function("Kick your steed?", ynchars, 'y', TRUE) == 'y') {
You("kick %s.", mon_nam(u.usteed));
kick_steed();
return ECMD_TIME;
} else {
return ECMD_OK;
}
} else if (Wounded_legs) {
legs_in_no_shape("kicking", FALSE);
no_kick = TRUE;
} else if (near_capacity() > SLT_ENCUMBER) {
Your("load is too heavy to balance yourself for a kick.");
no_kick = TRUE;
} else if (gy.youmonst.data->mlet == S_LIZARD) {
Your("legs cannot kick effectively.");
no_kick = TRUE;
} else if (u.uinwater && !rn2(2)) {
Your("slow motion kick doesn't hit anything.");
no_kick = TRUE;
} else if (u.utrap) {
no_kick = TRUE;
switch (u.utraptype) {
case TT_PIT:
if (!Passes_walls)
pline("There's not enough room to kick down here.");
else
no_kick = FALSE;
break;
case TT_WEB:
case TT_BEARTRAP:
You_cant("move your %s!", body_part(LEG));
break;
default:
break;
}
} else if (sobj_at(BOULDER, u.ux, u.uy) && !Passes_walls) {
pline("There's not enough room to kick in here.");
no_kick = TRUE;
}
if (no_kick) {
/* ignore direction typed before player notices kick failed */
display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
return ECMD_FAIL;
}
if (!getdir((char *) 0))
return ECMD_CANCEL;
if (!u.dx && !u.dy)
return ECMD_CANCEL;
x = u.ux + u.dx;
y = u.uy + u.dy;
/* KMH -- Kicking boots always succeed */
if (uarmf && uarmf->otyp == KICKING_BOOTS)
avrg_attrib = 99;
else
avrg_attrib = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3;
if (u.uswallow) {
switch (rn2(3)) {
case 0:
You_cant("move your %s!", body_part(LEG));
break;
case 1:
if (digests(u.ustuck->data)) {
pline("%s burps loudly.", Monnam(u.ustuck));
break;
}
/*FALLTHRU*/
default:
Your("feeble kick has no effect.");
break;
}
return ECMD_TIME;
} else if (u.utrap && u.utraptype == TT_PIT) {
/* must be Passes_walls */
You("kick at the side of the pit.");
return ECMD_TIME;
}
if (Levitation) {
coordxy xx, yy;
xx = u.ux - u.dx;
yy = u.uy - u.dy;
/* doors can be opened while levitating, so they must be
* reachable for bracing purposes
* Possible extension: allow bracing against stuff on the side?
*/
if (isok(xx, yy) && !IS_ROCK(levl[xx][yy].typ)
&& !IS_DOOR(levl[xx][yy].typ)
&& (!Is_airlevel(&u.uz) || !OBJ_AT(xx, yy))) {
You("have nothing to brace yourself against.");
return ECMD_OK;
}
}
mtmp = isok(x, y) ? m_at(x, y) : 0;
/* might not kick monster if it is hidden and becomes revealed,
if it is peaceful and player declines to attack, or if the
hero passes out due to encumbrance with low hp; gc.context.move
will be 1 unless player declines to kick peaceful monster */
if (mtmp) {
oldglyph = glyph_at(x, y);
if (!maybe_kick_monster(mtmp, x, y))
return (gc.context.move ? ECMD_TIME : ECMD_OK);
}
wake_nearby();
u_wipe_engr(2);
if (!isok(x, y)) {
gm.maploc = &gn.nowhere;
kick_ouch(x, y, "");
return ECMD_TIME;
}
gm.maploc = &levl[x][y];
/*
* The next five tests should stay in their present order:
* monsters, pools, objects, non-doors, doors.
*
* [FIXME: Monsters who are hidden underneath objects or
* in pools should lead to hero kicking the concealment
* rather than the monster, probably exposing the hidden
* monster in the process. And monsters who are hidden on
* ceiling shouldn't be kickable (unless hero is flying?);
* kicking toward them should just target whatever is on
* the floor at that spot.]
*/
if (mtmp) {
/* save mtmp->data (for recoil) in case mtmp gets killed */
struct permonst *mdat = mtmp->data;
kick_monster(mtmp, x, y);
glyph = glyph_at(x, y);
/* see comment in attack_checks() */
if (DEADMONSTER(mtmp)) { /* DEADMONSTER() */
/* if we mapped an invisible monster and immediately
killed it, we don't want to forget what we thought
was there before the kick */
if (glyph != oldglyph && glyph_is_invisible(glyph))
show_glyph(x, y, oldglyph);
} else if (!canspotmon(mtmp)
/* check <x,y>; monster that evades kick by jumping
to an unseen square doesn't leave an I behind */
&& mtmp->mx == x && mtmp->my == y
&& !glyph_is_invisible(glyph)
&& !engulfing_u(mtmp)) {
map_invisible(x, y);
}
/* recoil if floating */
if ((Is_airlevel(&u.uz) || Levitation) && gc.context.move) {
int range;
range =
((int) gy.youmonst.data->cwt + (weight_cap() + inv_weight()));
if (range < 1)
range = 1; /* divide by zero avoidance */
range = (3 * (int) mdat->cwt) / range;
if (range < 1)
range = 1;
hurtle(-u.dx, -u.dy, range, TRUE);
}
return ECMD_TIME;
}
(void) unmap_invisible(x, y);
if ((is_pool(x, y) || gm.maploc->typ == LAVAWALL) ^ !!u.uinwater) {
/* objects normally can't be removed from water by kicking */
You("splash some %s around.",
hliquid(is_pool(x, y) ? "water" : "lava"));
/* pretend the kick is fast enough for lava not to burn */
return ECMD_TIME;
}
if (OBJ_AT(x, y) && (!Levitation || Is_airlevel(&u.uz)
|| Is_waterlevel(&u.uz) || sobj_at(BOULDER, x, y))) {
char kickobjnam[BUFSZ];
if (kick_object(x, y, kickobjnam)) {
if (Is_airlevel(&u.uz))
hurtle(-u.dx, -u.dy, 1, TRUE); /* assume it's light */
return ECMD_TIME;
}
kick_ouch(x, y, kickobjnam);
return ECMD_TIME;
}
if (!IS_DOOR(gm.maploc->typ)) {
if (gm.maploc->typ == SDOOR) { if (gm.maploc->typ == SDOOR) {
if (!Levitation && rn2(30) < avrg_attrib) { if (!Levitation && rn2(30) < avrg_attrib) {
cvt_sdoor_to_door(gm.maploc); /* ->typ = DOOR */ cvt_sdoor_to_door(gm.maploc); /* ->typ = DOOR */
@@ -1443,7 +1240,218 @@ dokick(void)
return ECMD_TIME; return ECMD_TIME;
} }
/* the #kick command */
int
dokick(void)
{
coordxy x, y;
int avrg_attrib;
int glyph, oldglyph = -1;
register struct monst *mtmp;
boolean no_kick = FALSE;
if (nolimbs(gy.youmonst.data) || slithy(gy.youmonst.data)) {
You("have no legs to kick with.");
no_kick = TRUE;
} else if (verysmall(gy.youmonst.data)) {
You("are too small to do any kicking.");
no_kick = TRUE;
} else if (u.usteed) {
if (yn_function("Kick your steed?", ynchars, 'y', TRUE) == 'y') {
You("kick %s.", mon_nam(u.usteed));
kick_steed();
return ECMD_TIME;
} else {
return ECMD_OK;
}
} else if (Wounded_legs) {
legs_in_no_shape("kicking", FALSE);
no_kick = TRUE;
} else if (near_capacity() > SLT_ENCUMBER) {
Your("load is too heavy to balance yourself for a kick.");
no_kick = TRUE;
} else if (gy.youmonst.data->mlet == S_LIZARD) {
Your("legs cannot kick effectively.");
no_kick = TRUE;
} else if (u.uinwater && !rn2(2)) {
Your("slow motion kick doesn't hit anything.");
no_kick = TRUE;
} else if (u.utrap) {
no_kick = TRUE;
switch (u.utraptype) {
case TT_PIT:
if (!Passes_walls)
pline("There's not enough room to kick down here.");
else
no_kick = FALSE;
break;
case TT_WEB:
case TT_BEARTRAP:
You_cant("move your %s!", body_part(LEG));
break;
default:
break;
}
} else if (sobj_at(BOULDER, u.ux, u.uy) && !Passes_walls) {
pline("There's not enough room to kick in here.");
no_kick = TRUE;
}
if (no_kick) {
/* ignore direction typed before player notices kick failed */
display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
return ECMD_FAIL;
}
if (!getdir((char *) 0))
return ECMD_CANCEL;
if (!u.dx && !u.dy)
return ECMD_CANCEL;
x = u.ux + u.dx;
y = u.uy + u.dy;
/* KMH -- Kicking boots always succeed */
if (uarmf && uarmf->otyp == KICKING_BOOTS)
avrg_attrib = 99;
else
avrg_attrib = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3;
if (u.uswallow) {
switch (rn2(3)) {
case 0:
You_cant("move your %s!", body_part(LEG));
break;
case 1:
if (digests(u.ustuck->data)) {
pline("%s burps loudly.", Monnam(u.ustuck));
break;
}
/*FALLTHRU*/
default:
Your("feeble kick has no effect.");
break;
}
return ECMD_TIME;
} else if (u.utrap && u.utraptype == TT_PIT) {
/* must be Passes_walls */
You("kick at the side of the pit.");
return ECMD_TIME;
}
if (Levitation) {
coordxy xx, yy;
xx = u.ux - u.dx;
yy = u.uy - u.dy;
/* doors can be opened while levitating, so they must be
* reachable for bracing purposes
* Possible extension: allow bracing against stuff on the side?
*/
if (isok(xx, yy) && !IS_ROCK(levl[xx][yy].typ)
&& !IS_DOOR(levl[xx][yy].typ)
&& (!Is_airlevel(&u.uz) || !OBJ_AT(xx, yy))) {
You("have nothing to brace yourself against.");
return ECMD_OK;
}
}
mtmp = isok(x, y) ? m_at(x, y) : 0;
/* might not kick monster if it is hidden and becomes revealed,
if it is peaceful and player declines to attack, or if the
hero passes out due to encumbrance with low hp; gc.context.move
will be 1 unless player declines to kick peaceful monster */
if (mtmp) {
oldglyph = glyph_at(x, y);
if (!maybe_kick_monster(mtmp, x, y))
return (gc.context.move ? ECMD_TIME : ECMD_OK);
}
wake_nearby();
u_wipe_engr(2);
if (!isok(x, y)) {
gm.maploc = &gn.nowhere;
kick_ouch(x, y, "");
return ECMD_TIME;
}
gm.maploc = &levl[x][y];
/*
* The next five tests should stay in their present order:
* monsters, pools, objects, non-doors, doors.
*
* [FIXME: Monsters who are hidden underneath objects or
* in pools should lead to hero kicking the concealment
* rather than the monster, probably exposing the hidden
* monster in the process. And monsters who are hidden on
* ceiling shouldn't be kickable (unless hero is flying?);
* kicking toward them should just target whatever is on
* the floor at that spot.]
*/
if (mtmp) {
/* save mtmp->data (for recoil) in case mtmp gets killed */
struct permonst *mdat = mtmp->data;
kick_monster(mtmp, x, y);
glyph = glyph_at(x, y);
/* see comment in attack_checks() */
if (DEADMONSTER(mtmp)) { /* DEADMONSTER() */
/* if we mapped an invisible monster and immediately
killed it, we don't want to forget what we thought
was there before the kick */
if (glyph != oldglyph && glyph_is_invisible(glyph))
show_glyph(x, y, oldglyph);
} else if (!canspotmon(mtmp)
/* check <x,y>; monster that evades kick by jumping
to an unseen square doesn't leave an I behind */
&& mtmp->mx == x && mtmp->my == y
&& !glyph_is_invisible(glyph)
&& !engulfing_u(mtmp)) {
map_invisible(x, y);
}
/* recoil if floating */
if ((Is_airlevel(&u.uz) || Levitation) && gc.context.move) {
int range;
range =
((int) gy.youmonst.data->cwt + (weight_cap() + inv_weight()));
if (range < 1)
range = 1; /* divide by zero avoidance */
range = (3 * (int) mdat->cwt) / range;
if (range < 1)
range = 1;
hurtle(-u.dx, -u.dy, range, TRUE);
}
return ECMD_TIME;
}
(void) unmap_invisible(x, y);
if ((is_pool(x, y) || gm.maploc->typ == LAVAWALL) ^ !!u.uinwater) {
/* objects normally can't be removed from water by kicking */
You("splash some %s around.",
hliquid(is_pool(x, y) ? "water" : "lava"));
/* pretend the kick is fast enough for lava not to burn */
return ECMD_TIME;
}
if (OBJ_AT(x, y) && (!Levitation || Is_airlevel(&u.uz)
|| Is_waterlevel(&u.uz) || sobj_at(BOULDER, x, y))) {
char kickobjnam[BUFSZ];
if (kick_object(x, y, kickobjnam)) {
if (Is_airlevel(&u.uz))
hurtle(-u.dx, -u.dy, 1, TRUE); /* assume it's light */
return ECMD_TIME;
}
kick_ouch(x, y, kickobjnam);
return ECMD_TIME;
}
if (IS_DOOR(gm.maploc->typ))
kick_door(x, y, avrg_attrib); kick_door(x, y, avrg_attrib);
else
return kick_nondoor(x, y, avrg_attrib);
return ECMD_TIME; return ECMD_TIME;
} }