knockback knocking riding hero out of saddle
I've implemented targetted dismount such that being knocked out of the saddle will place the hero opposite the attacker in preference to a random spot adjacent to the steed. If that opposite spot isn't appropriate, the two spots next to it get tried. In these map fragments, H is knocking mounted hero off of u. The digits indicate priority of potential destinations. |..... |..21. |...2. |..u2. |.Hu1. |.H... |...2. |..... If spot 1 isn't acceptable, both of spots 2 (in random order) will be tried next. If those aren't acceptable either, it will try the other 5 spots adjacent to the steed (the one of those with the attacker will always be unacceptable). And as before, it none of those work, it uses enexto() to pick a random spot as close to the steed as feasible. Not knockback: when dismounting due to polymorph, avoid diagonal adjacent spots if hero's new form can't move diagonally. (The hero can't already be in no-diagonal form because riding requires that the rider be humanoid. I keep thinking the restriction is "can't be polymorphed" but that isn't correct.)
This commit is contained in:
@@ -5433,7 +5433,7 @@ void
|
|||||||
confdir(boolean force_impairment)
|
confdir(boolean force_impairment)
|
||||||
{
|
{
|
||||||
if (force_impairment || u_maybe_impaired()) {
|
if (force_impairment || u_maybe_impaired()) {
|
||||||
register coordxy x = NODIAG(u.umonnum) ? dirs_ord[rn2(4)] : rn2(N_DIRS);
|
int x = NODIAG(u.umonnum) ? (int) dirs_ord[rn2(4)] : rn2(N_DIRS);
|
||||||
|
|
||||||
u.dx = xdir[x];
|
u.dx = xdir[x];
|
||||||
u.dy = ydir[x];
|
u.dy = ydir[x];
|
||||||
|
|||||||
+99
-38
@@ -440,49 +440,111 @@ landing_spot(
|
|||||||
int reason,
|
int reason,
|
||||||
int forceit)
|
int forceit)
|
||||||
{
|
{
|
||||||
int i = 0, distance, min_distance = -1;
|
coord cc, try[8]; /* 8: the 8 spots adjacent to the hero's spot */
|
||||||
|
int i, j, best_j, clockwise_j, counterclk_j,
|
||||||
|
n, viable, distance, min_distance = -1;
|
||||||
coordxy x, y;
|
coordxy x, y;
|
||||||
boolean found = FALSE;
|
boolean found, impaird, kn_trap, boulder;
|
||||||
struct trap *t;
|
struct trap *t;
|
||||||
|
|
||||||
|
(void) memset((genericptr_t) try, 0, sizeof try);
|
||||||
|
n = 0;
|
||||||
|
j = xytod(u.dx, u.dy);
|
||||||
|
if (reason == DISMOUNT_KNOCKED && j != DIR_ERR) {
|
||||||
|
/* we'll check preferred location first; if viable it'll be picked */
|
||||||
|
best_j = j;
|
||||||
|
try[0].x = u.dx, try[0].y = u.dy;
|
||||||
|
/* the two next best locations are checked second and third */
|
||||||
|
i = rn2(2);
|
||||||
|
clockwise_j = (j + 1) % N_DIRS;
|
||||||
|
dtoxy(&cc, clockwise_j);
|
||||||
|
try[1 + i].x = cc.x, try[1 + i].y = cc.y; /* [1] or [2] */
|
||||||
|
counterclk_j = (j + N_DIRS - 1) % N_DIRS;
|
||||||
|
dtoxy(&cc, counterclk_j);
|
||||||
|
try[2 - i].x = cc.x, try[2 - i].y = cc.y; /* [2] or [1] */
|
||||||
|
n = 3;
|
||||||
|
debugpline3("knock from saddle: best %s, next %s or %s",
|
||||||
|
directionname(best_j),
|
||||||
|
directionname(clockwise_j), directionname(counterclk_j));
|
||||||
|
} else {
|
||||||
|
best_j = clockwise_j = counterclk_j = -1;
|
||||||
|
}
|
||||||
|
for (j = 0; j < N_DIRS; ++j) {
|
||||||
|
/* fortunately NODIAG() handling isn't needed for DISMOUNT_KNOCKED
|
||||||
|
because hero can only ride when humanoid */
|
||||||
|
if (j == best_j || j == clockwise_j || j == counterclk_j)
|
||||||
|
continue;
|
||||||
|
/* j==0 is W, j==1 NW, j==2 N, j==3 NE, ..., around to j==7 SW;
|
||||||
|
so odd j values are diagonal directions here */
|
||||||
|
if (reason == DISMOUNT_POLY && NODIAG(u.umonnum) && (j % 1) != 0)
|
||||||
|
continue;
|
||||||
|
dtoxy(&cc, j);
|
||||||
|
try[n++] = cc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO:
|
* Up to three passes;
|
||||||
* for reason==DISMOUNT_KNOCKED, prefer the spot directly behind
|
* i==0: voluntary dismount without impairment avoids known traps and
|
||||||
* current position relative to the attacker; first need to figure
|
* boulders;
|
||||||
* how to obtain attacker information...
|
* i==1: voluntary dismount with impairment or knocked out of saddle
|
||||||
|
* avoids boulders but allows known traps;
|
||||||
|
* i==2: other, allow traps and boulders.
|
||||||
|
*
|
||||||
|
* Fallback to i==1 if nothing appropriate was found for i==0 and
|
||||||
|
* to i==2 as last resort.
|
||||||
*/
|
*/
|
||||||
|
impaird = (Stunned || Confusion || Fumbling);
|
||||||
|
viable = 0;
|
||||||
|
found = FALSE;
|
||||||
|
for (i = (reason == DISMOUNT_BYCHOICE && !impaird) ? 0
|
||||||
|
: ((reason == DISMOUNT_BYCHOICE && impaird)
|
||||||
|
|| reason == DISMOUNT_KNOCKED) ? 1
|
||||||
|
: 2;
|
||||||
|
i <= 2 && !found; ++i) {
|
||||||
|
for (j = 0; j < n; ++j) {
|
||||||
|
x = u.ux + try[j].x;
|
||||||
|
y = u.uy + try[j].y;
|
||||||
|
if (!isok(x, y) || u_at(x, y)) /* [note: u_at() can't happen] */
|
||||||
|
continue;
|
||||||
|
|
||||||
/* avoid known traps (i == 0) and boulders, but allow them as a backup */
|
if (accessible(x, y) && !MON_AT(x, y)
|
||||||
if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling)
|
&& test_move(u.ux, u.uy, x - u.ux, y - u.uy, TEST_MOVE)) {
|
||||||
i = 1;
|
++viable;
|
||||||
for (; !found && i < 2; ++i) {
|
distance = distu(x, y);
|
||||||
for (x = u.ux - 1; x <= u.ux + 1; x++)
|
if (min_distance < 0 /* no viable candidate yet */
|
||||||
for (y = u.uy - 1; y <= u.uy + 1; y++) {
|
/* or better than pending candidate (note: distance
|
||||||
if (!isok(x, y) || u_at(x, y))
|
is never less than min_distance because we're
|
||||||
continue;
|
limiting search to radius 1; j==0 won't get here
|
||||||
|
because 'min_distance < 0' will always pass for it) */
|
||||||
if (accessible(x, y) && !MON_AT(x, y)
|
|| (distance < min_distance || (best_j != -1 && j == 0))
|
||||||
&& test_move(u.ux, u.uy, x - u.ux, y - u.uy, TEST_MOVE)) {
|
/* or equally good, maybe substitute this one */
|
||||||
distance = distu(x, y);
|
|| (distance == min_distance && !rn2(viable))) {
|
||||||
if (min_distance < 0 || distance < min_distance
|
/* traps avoided on pass 0; boulders avoided on 0 and 1 */
|
||||||
|| (distance == min_distance && rn2(2))) {
|
kn_trap = i == 0 && ((t = t_at(x, y)) != 0 && t->tseen
|
||||||
if (i > 0 || (((t = t_at(x, y)) == 0 || !t->tseen)
|
&& t->ttyp != VIBRATING_SQUARE);
|
||||||
&& (!sobj_at(BOULDER, x, y)
|
boulder = i <= 1 && (sobj_at(BOULDER, x, y)
|
||||||
|| throws_rocks(g.youmonst.data)))) {
|
&& !throws_rocks(g.youmonst.data));
|
||||||
spot->x = x;
|
if (!kn_trap && !boulder) {
|
||||||
spot->y = y;
|
spot->x = x;
|
||||||
min_distance = distance;
|
spot->y = y;
|
||||||
found = TRUE;
|
min_distance = distance;
|
||||||
}
|
found = TRUE;
|
||||||
|
if (best_j != -1 && j < 3)
|
||||||
|
/* since best_j is first candidate (j==0), j==1
|
||||||
|
and j==2 can only get here when best_j was
|
||||||
|
not viable; 50:50 chance for clockwise_j to
|
||||||
|
come before counterclk_j so each has same
|
||||||
|
chance to be next after best_j */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we didn't find a good spot and forceit is on, try enexto(). */
|
/* If we didn't find a good spot and forceit is on, try enexto(). */
|
||||||
if (forceit && min_distance < 0
|
if (forceit && !found)
|
||||||
&& !enexto(spot, u.ux, u.uy, g.youmonst.data))
|
found = enexto(spot, u.ux, u.uy, g.youmonst.data);
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
@@ -618,7 +680,7 @@ dismount_steed(
|
|||||||
if (enexto(&cc, u.ux, u.uy, mtmp->data))
|
if (enexto(&cc, u.ux, u.uy, mtmp->data))
|
||||||
rloc_to(mtmp, cc.x, cc.y);
|
rloc_to(mtmp, cc.x, cc.y);
|
||||||
else /* evidently no room nearby; move steed elsewhere */
|
else /* evidently no room nearby; move steed elsewhere */
|
||||||
(void) rloc(mtmp, RLOC_ERR|RLOC_NOMSG);
|
(void) rloc(mtmp, RLOC_ERR | RLOC_NOMSG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,12 +720,11 @@ dismount_steed(
|
|||||||
*
|
*
|
||||||
* Clearly this is not the best way to do it. A full fix would
|
* Clearly this is not the best way to do it. A full fix would
|
||||||
* involve having these functions not call pickup() at all,
|
* involve having these functions not call pickup() at all,
|
||||||
* instead
|
* instead calling them first and calling pickup() afterwards.
|
||||||
* calling them first and calling pickup() afterwards. But it
|
* But it would take a lot of work to keep this change from
|
||||||
* would take a lot of work to keep this change from having any
|
* having any unforeseen side effects (for instance, you would
|
||||||
* unforeseen side effects (for instance, you would no longer be
|
* no longer be able to walk onto a square with a hole, and
|
||||||
* able to walk onto a square with a hole, and autopickup before
|
* autopickup before falling into the hole).
|
||||||
* falling into the hole).
|
|
||||||
*/
|
*/
|
||||||
/* [ALI] No need to move the player if the steed died. */
|
/* [ALI] No need to move the player if the steed died. */
|
||||||
if (!DEADMONSTER(mtmp)) {
|
if (!DEADMONSTER(mtmp)) {
|
||||||
|
|||||||
+6
-1
@@ -4732,10 +4732,15 @@ mhitm_knockback(
|
|||||||
|
|
||||||
/* do the actual knockback effect */
|
/* do the actual knockback effect */
|
||||||
if (u_def) {
|
if (u_def) {
|
||||||
|
/* normally dx,dy indicates direction hero is throwing, zapping, &c
|
||||||
|
but here it is used to pass the preferred direction for dismount
|
||||||
|
to dismount_steed (used for DISMOUNT_KNOCKED only) */
|
||||||
|
u.dx = sgn(u.ux - magr->mx); /* [sgn() is superfluous here] */
|
||||||
|
u.dy = sgn(u.uy - magr->my); /* [ditto] */
|
||||||
if (u.usteed)
|
if (u.usteed)
|
||||||
dismount_steed(DISMOUNT_KNOCKED);
|
dismount_steed(DISMOUNT_KNOCKED);
|
||||||
else
|
else
|
||||||
hurtle(u.ux - magr->mx, u.uy - magr->my, rnd(2), FALSE);
|
hurtle(u.dx, u.dy, rnd(2), FALSE);
|
||||||
|
|
||||||
set_apparxy(magr); /* update magr's idea of where you are */
|
set_apparxy(magr); /* update magr's idea of where you are */
|
||||||
if (!rn2(4))
|
if (!rn2(4))
|
||||||
|
|||||||
Reference in New Issue
Block a user