diff --git a/src/sp_lev.c b/src/sp_lev.c index d60c4a062..1a5a2ac02 100755 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sp_lev.c $NHDT-Date: 1585361055 2020/03/28 02:04:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.183 $ */ +/* NetHack 3.6 sp_lev.c $NHDT-Date: 1585569501 2020/03/30 11:58:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.185 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -30,6 +30,7 @@ static void FDECL(lvlfill_solid, (SCHAR_P, SCHAR_P)); static void FDECL(lvlfill_swamp, (SCHAR_P, SCHAR_P, SCHAR_P)); static void FDECL(flip_drawbridge_horizontal, (struct rm *)); static void FDECL(flip_drawbridge_vertical, (struct rm *)); +static void FDECL(flip_visuals, (int, int, int, int, int)); static int FDECL(flip_encoded_direction_bits, (int, int)); static void FDECL(set_wall_property, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, int)); @@ -370,16 +371,17 @@ struct rm *lev; } /* for #wizlevelflip; not needed when flipping during level creation; - update seen vector for whole level and glyph for walls */ + update seen vector for whole flip area and glyph for known walls */ static void -flip_visuals(flp) +flip_visuals(flp, minx, miny, maxx, maxy) int flp; +int minx, miny, maxx, maxy; { struct rm *lev; int x, y, seenv; - for (y = 0; y < ROWNO; ++y) { - for (x = 1; x < COLNO; ++x) { + for (y = miny; y <= maxy; ++y) { + for (x = minx; x <= maxx; ++x) { lev = &levl[x][y]; seenv = lev->seenv & 0xff; /* locations which haven't been seen can be skipped */ @@ -432,7 +434,17 @@ flip_encoded_direction_bits(int flp, int val) #define FlipX(val) ((maxx - (val)) + minx) #define FlipY(val) ((maxy - (val)) + miny) -#define inFlipArea(x,y) ((x) >= minx && (x) <= maxx && (y) >= miny && (y) <= maxy) +#define inFlipArea(x,y) \ + ((x) >= minx && (x) <= maxx && (y) >= miny && (y) <= maxy) +#define Flip_coord(cc) \ + do { \ + if ((cc).x && inFlipArea((cc).x, (cc).y)) { \ + if (flp & 1) \ + (cc).y = FlipY((cc).y); \ + if (flp & 2) \ + (cc).x = FlipX((cc).x); \ + } \ + } while (0) /* transpose top with bottom or left with right or both; sometimes called for new special levels, or for any level via the #wizlevelflip command */ @@ -450,8 +462,11 @@ boolean extras; struct engr *etmp; struct mkroom *sroom; timer_element *timer; - boolean ball_active = (Punished && uball->where != OBJ_FREE); - boolean ball_fliparea; + boolean ball_active = FALSE, ball_fliparea = FALSE; + + /* nothing to do unless (flp & 1) or (flp & 2) or both */ + if ((flp & 3) == 0) + return; get_level_extends(&minx, &miny, &maxx, &maxy); /* get_level_extends() returns -1,-1 to COLNO,ROWNO at max */ @@ -464,12 +479,25 @@ boolean extras; if (maxy >= ROWNO) maxy = (ROWNO - 1); - ball_fliparea = Punished - && inFlipArea(uball->ox, uball->oy) == inFlipArea(uchain->ox, uchain->oy) - && inFlipArea(uball->ox, uball->oy) == inFlipArea(u.ux, u.uy); - - if (ball_active && extras && !ball_fliparea) - unplacebc(); + if (extras) { + if (Punished && uball->where != OBJ_FREE) { + ball_active = TRUE; + /* if hero and ball and chain are all inside flip area, + flip b&c coordinates along with other objects; if they + are all outside, leave them to be rejected when flipping + so that they stay as is; if some are inside and some are + outside, un-place here and subsequently re-place them on + hero's [possibly new] spot below */ + if (carried(uball)) + uball->ox = u.ux, uball->oy = u.uy; + ball_fliparea = ((inFlipArea(uball->ox, uball->oy) + == inFlipArea(uchain->ox, uchain->oy)) + && (inFlipArea(uball->ox, uball->oy) + == inFlipArea(u.ux, u.uy))); + if (!ball_fliparea) + unplacebc(); + } + } /* stairs and ladders */ if (flp & 1) { @@ -550,28 +578,28 @@ boolean extras; /* skip the occasional earth elemental outside the flip area */ if (!inFlipArea(mtmp->mx, mtmp->my)) continue; - if (flp & 1) { + if (flp & 1) mtmp->my = FlipY(mtmp->my); - if (mtmp->ispriest) - EPRI(mtmp)->shrpos.y = FlipY(EPRI(mtmp)->shrpos.y); - else if (mtmp->isshk) { - ESHK(mtmp)->shk.y = FlipY(ESHK(mtmp)->shk.y); - ESHK(mtmp)->shd.y = FlipY(ESHK(mtmp)->shd.y); - } else if (mtmp->wormno) { - flip_worm_segs_vertical(mtmp, miny, maxy); - } - } - if (flp & 2) { + if (flp & 2) mtmp->mx = FlipX(mtmp->mx); - if (mtmp->ispriest) - EPRI(mtmp)->shrpos.x = FlipX(EPRI(mtmp)->shrpos.x); - else if (mtmp->isshk) { - ESHK(mtmp)->shk.x = FlipX(ESHK(mtmp)->shk.x); - ESHK(mtmp)->shd.x = FlipX(ESHK(mtmp)->shd.x); - } else if (mtmp->wormno) { + + if (mtmp->ispriest) { + Flip_coord(EPRI(mtmp)->shrpos); + } else if (mtmp->isshk) { + Flip_coord(ESHK(mtmp)->shk); /* shk's preferred spot */ + Flip_coord(ESHK(mtmp)->shd); /* shop door */ + } else if (mtmp->wormno) { + if (flp & 1) + flip_worm_segs_vertical(mtmp, miny, maxy); + if (flp & 2) flip_worm_segs_horizontal(mtmp, minx, maxx); - } } +#if 0 /* not useful unless tracking also gets flipped */ + if (extras) { + if (mtmp->tame && has_edog(mtmp)) + Flip_coord(EDOG(mtmp)->ogoal); + } +#endif } /* engravings */ @@ -621,8 +649,9 @@ boolean extras; } /* rooms */ - for(sroom = &g.rooms[0]; ; sroom++) { - if (sroom->hx < 0) break; + for (sroom = &g.rooms[0]; ; sroom++) { + if (sroom->hx < 0) + break; if (flp & 1) { sroom->ly = FlipY(sroom->ly); @@ -670,10 +699,7 @@ boolean extras; /* doors */ for (i = 0; i < g.doorindex; i++) { - if (flp & 1) - g.doors[i].y = FlipY(g.doors[i].y); - if (flp & 2) - g.doors[i].x = FlipX(g.doors[i].x); + Flip_coord(g.doors[i]); } /* the map */ @@ -723,32 +749,39 @@ boolean extras; /* timed effects */ for (timer = g.timer_base; timer; timer = timer->next) { if (timer->func_index == MELT_ICE_AWAY) { - long ty = ((long)timer->arg.a_void) & 0xFFFF; - long tx = (((long)timer->arg.a_void) >> 16) & 0xFFFF; + long ty = ((long) timer->arg.a_void) & 0xffff; + long tx = (((long) timer->arg.a_void) >> 16) & 0xffff; + if (flp & 1) ty = FlipY(ty); if (flp & 2) tx = FlipX(tx); - timer->arg.a_void = (genericptr_t)((tx << 16) | ty); + timer->arg.a_void = (genericptr_t) ((tx << 16) | ty); } } - if (extras) { + if (extras) { /* for #wizlevelflip rather than during level creation */ /* flip hero location only if inside the flippable area */ - if (!(u.ux < minx || u.ux > maxx || u.uy < miny || u.uy > maxy)) { + if (inFlipArea(u.ux, u.uy)) { if (flp & 1) - u.uy = FlipY(u.uy), u.uy0 = FlipY(u.uy0); + u.uy = FlipY(u.uy); if (flp & 2) - u.ux = FlipX(u.ux), u.ux0 = FlipX(u.ux0); + u.ux = FlipX(u.ux); + /* we could flip too if it's inside the flip area, + but have to resort to this if outside, so just do this */ + u.ux0 = u.ux, u.uy0 = u.uy; } if (ball_active && !ball_fliparea) placebc(); + Flip_coord(iflags.travelcc); + Flip_coord(g.context.digging.pos); } fix_wall_spines(1, 0, COLNO - 1, ROWNO - 1); if (extras && flp) { set_wall_state(); - flip_visuals(flp); /* after wall_spines; flips seenv and wall joins */ + /* after wall_spines; flips seenv and wall joins */ + flip_visuals(flp, minx, miny, maxx, maxy); } vision_reset(); }