From: Pasi Kallinen Date: Fri, 25 Feb 2022 13:09:56 +0000 (+0200) Subject: Split swapping places with pet code out of domove X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=48cd81dbfd31fa1e3ede5990de704a804cb8053f;p=nethack Split swapping places with pet code out of domove --- diff --git a/src/hack.c b/src/hack.c index 624eee0e8..19a43f45b 100644 --- a/src/hack.c +++ b/src/hack.c @@ -18,6 +18,7 @@ static boolean swim_move_danger(xchar, xchar); static boolean domove_bump_mon(struct monst *, int); static boolean domove_attackmon_at(struct monst *, xchar, xchar, boolean *); static boolean domove_fight_ironbars(xchar, xchar); +static boolean domove_swap_with_pet(struct monst *, xchar, xchar); static void domove_core(void); static void maybe_smudge_engr(int, int, int, int); static struct monst *monstinroom(struct permonst *, int); @@ -1683,6 +1684,125 @@ domove_fight_ironbars(xchar x, xchar y) return FALSE; } +/* maybe swap places with a pet? returns TRUE if swapped places */ +static boolean +domove_swap_with_pet(struct monst *mtmp, xchar x, xchar y) +{ + struct trap *trap; + /* if it turns out we can't actually move */ + boolean didnt_move = FALSE; + boolean u_with_boulder = (sobj_at(BOULDER, u.ux, u.uy) != 0); + + /* seemimic/newsym should be done before moving hero, otherwise + the display code will draw the hero here before we possibly + cancel the swap below (we can ignore steed mx,my here) */ + u.ux = u.ux0, u.uy = u.uy0; + mtmp->mundetected = 0; + if (M_AP_TYPE(mtmp)) + seemimic(mtmp); + u.ux = mtmp->mx, u.uy = mtmp->my; /* resume swapping positions */ + + if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0 + && is_pit(trap->ttyp) + && sobj_at(BOULDER, trap->tx, trap->ty)) { + /* can't swap places with pet pinned in a pit by a boulder */ + didnt_move = TRUE; + } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { + /* can't swap places when pet can't move to your spot */ + You("stop. %s can't move diagonally.", upstart(y_monnam(mtmp))); + didnt_move = TRUE; + } else if (u_with_boulder + && !(verysmall(mtmp->data) + && (!mtmp->minvent || curr_mon_load(mtmp) <= 600))) { + /* can't swap places when pet won't fit there with the boulder */ + You("stop. %s won't fit into the same spot that you're at.", + upstart(y_monnam(mtmp))); + didnt_move = TRUE; + } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0) + && bad_rock(mtmp->data, u.ux0, y) + && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { + /* can't swap places when pet won't fit thru the opening */ + You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); + didnt_move = TRUE; + } else if (mtmp->mpeaceful && mtmp->mtrapped) { + /* all mtame are also mpeaceful, so this affects pets too */ + You("stop. %s can't move out of that trap.", + upstart(y_monnam(mtmp))); + didnt_move = TRUE; + } else if (mtmp->mpeaceful + && (!goodpos(u.ux0, u.uy0, mtmp, 0) + || t_at(u.ux0, u.uy0) != NULL + || mundisplaceable(mtmp))) { + /* displacing peaceful into unsafe or trapped space, or trying to + * displace quest leader, Oracle, shopkeeper, or priest */ + You("stop. %s doesn't want to swap places.", + upstart(y_monnam(mtmp))); + didnt_move = TRUE; + } else { + mtmp->mtrapped = 0; + remove_monster(x, y); + place_monster(mtmp, u.ux0, u.uy0); + newsym(x, y); + newsym(u.ux0, u.uy0); + + You("%s %s.", mtmp->mpeaceful ? "swap places with" : "frighten", + x_monnam(mtmp, + mtmp->mtame ? ARTICLE_YOUR + : (!has_mgivenname(mtmp) + && !type_is_pname(mtmp->data)) ? ARTICLE_THE + : ARTICLE_NONE, + (mtmp->mpeaceful && !mtmp->mtame) ? "peaceful" : 0, + has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE)); + + /* check for displacing it into pools and traps */ + switch (minliquid(mtmp) ? Trap_Killed_Mon + : mintrap(mtmp, NO_TRAP_FLAGS)) { + case Trap_Effect_Finished: + break; + case Trap_Caught_Mon: /* trapped */ + case Trap_Moved_Mon: /* changed levels */ + /* there's already been a trap message, reinforce it */ + abuse_dog(mtmp); + adjalign(-3); + break; + case Trap_Killed_Mon: + /* drowned or died... + * you killed your pet by direct action, so get experience + * and possibly penalties; + * we want the level gain message, if it happens, to occur + * before the guilt message below + */ + { + /* minliquid() and mintrap() call mondead() rather than + killed() so we duplicate some of the latter here */ + int tmp, mndx; + + if (!u.uconduct.killer++) + livelog_printf(LL_CONDUCT, "killed for the first time"); + mndx = monsndx(mtmp->data); + tmp = experience(mtmp, (int) g.mvitals[mndx].died); + more_experienced(tmp, 0); + newexplevel(); /* will decide if you go up */ + } + /* That's no way to treat a pet! Your god gets angry. + * + * [This has always been pretty iffy. Why does your + * patron deity care at all, let alone enough to get mad?] + */ + if (rn2(4)) { + You_feel("guilty about losing your pet like this."); + u.ugangr++; + adjalign(-15); + } + break; + default: + impossible("that's strange, unknown mintrap result!"); + break; + } + } + return !didnt_move; +} + void domove(void) { @@ -1709,8 +1829,7 @@ domove_core(void) ballx = 0, bally = 0; /* ball&chain new positions */ int bc_control = 0; /* control for ball&chain */ boolean cause_delay = FALSE, /* dragging ball will skip a move */ - displaceu = FALSE, /* involuntary swap */ - u_with_boulder = (sobj_at(BOULDER, u.ux, u.uy) != 0); + displaceu = FALSE; /* involuntary swap */ if (g.context.travel) { if (!findtravelpath(FALSE)) @@ -2107,118 +2226,7 @@ domove_core(void) */ } else if (is_safemon(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) { - /* if it turns out we can't actually move */ - boolean didnt_move = FALSE; - - /* seemimic/newsym should be done before moving hero, otherwise - the display code will draw the hero here before we possibly - cancel the swap below (we can ignore steed mx,my here) */ - u.ux = u.ux0, u.uy = u.uy0; - mtmp->mundetected = 0; - if (M_AP_TYPE(mtmp)) - seemimic(mtmp); - u.ux = mtmp->mx, u.uy = mtmp->my; /* resume swapping positions */ - - if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0 - && is_pit(trap->ttyp) - && sobj_at(BOULDER, trap->tx, trap->ty)) { - /* can't swap places with pet pinned in a pit by a boulder */ - didnt_move = TRUE; - } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { - /* can't swap places when pet can't move to your spot */ - You("stop. %s can't move diagonally.", upstart(y_monnam(mtmp))); - didnt_move = TRUE; - } else if (u_with_boulder - && !(verysmall(mtmp->data) - && (!mtmp->minvent || curr_mon_load(mtmp) <= 600))) { - /* can't swap places when pet won't fit there with the boulder */ - You("stop. %s won't fit into the same spot that you're at.", - upstart(y_monnam(mtmp))); - didnt_move = TRUE; - } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0) - && bad_rock(mtmp->data, u.ux0, y) - && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { - /* can't swap places when pet won't fit thru the opening */ - You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); - didnt_move = TRUE; - } else if (mtmp->mpeaceful && mtmp->mtrapped) { - /* all mtame are also mpeaceful, so this affects pets too */ - You("stop. %s can't move out of that trap.", - upstart(y_monnam(mtmp))); - didnt_move = TRUE; - } else if (mtmp->mpeaceful - && (!goodpos(u.ux0, u.uy0, mtmp, 0) - || t_at(u.ux0, u.uy0) != NULL - || mundisplaceable(mtmp))) { - /* displacing peaceful into unsafe or trapped space, or trying to - * displace quest leader, Oracle, shopkeeper, or priest */ - You("stop. %s doesn't want to swap places.", - upstart(y_monnam(mtmp))); - didnt_move = TRUE; - } else { - mtmp->mtrapped = 0; - remove_monster(x, y); - place_monster(mtmp, u.ux0, u.uy0); - newsym(x, y); - newsym(u.ux0, u.uy0); - - You("%s %s.", mtmp->mpeaceful ? "swap places with" : "frighten", - x_monnam(mtmp, - mtmp->mtame ? ARTICLE_YOUR - : (!has_mgivenname(mtmp) - && !type_is_pname(mtmp->data)) ? ARTICLE_THE - : ARTICLE_NONE, - (mtmp->mpeaceful && !mtmp->mtame) ? "peaceful" : 0, - has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE)); - - /* check for displacing it into pools and traps */ - switch (minliquid(mtmp) ? Trap_Killed_Mon - : mintrap(mtmp, NO_TRAP_FLAGS)) { - case Trap_Effect_Finished: - break; - case Trap_Caught_Mon: /* trapped */ - case Trap_Moved_Mon: /* changed levels */ - /* there's already been a trap message, reinforce it */ - abuse_dog(mtmp); - adjalign(-3); - break; - case Trap_Killed_Mon: - /* drowned or died... - * you killed your pet by direct action, so get experience - * and possibly penalties; - * we want the level gain message, if it happens, to occur - * before the guilt message below - */ - { - /* minliquid() and mintrap() call mondead() rather than - killed() so we duplicate some of the latter here */ - int tmp, mndx; - - if (!u.uconduct.killer++) - livelog_printf(LL_CONDUCT, "killed for the first time"); - mndx = monsndx(mtmp->data); - tmp = experience(mtmp, (int) g.mvitals[mndx].died); - more_experienced(tmp, 0); - newexplevel(); /* will decide if you go up */ - } - /* That's no way to treat a pet! Your god gets angry. - * - * [This has always been pretty iffy. Why does your - * patron deity care at all, let alone enough to get mad?] - */ - if (rn2(4)) { - You_feel("guilty about losing your pet like this."); - u.ugangr++; - adjalign(-15); - } - break; - default: - impossible("that's strange, unknown mintrap result!"); - break; - } - } - - if (didnt_move) { + if (!domove_swap_with_pet(mtmp, x, y)) { u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ /* could skip this bit since we're about to call u_on_newpos() */ if (u.usteed)