Allow flipping levels horizontally or vertically

When a special level is created, there's a chance it gets flipped
horizontally and/or vertically.

Add new level flags "noflip", "noflipx", and "noflipy" to prevent
flipping the level. Add a wiz-mode command #wizlevelflip to test
the flipping on current level - although this doesn't flip everything,
as level flipping is meant to happen during level creation.
This commit is contained in:
Pasi Kallinen
2020-02-20 19:18:54 +02:00
parent 86f5e73ef3
commit 88aa0793dc
20 changed files with 397 additions and 12 deletions

View File

@@ -147,6 +147,7 @@ static int NDECL(wiz_polyself);
static int NDECL(wiz_load_lua);
static int NDECL(wiz_level_tele);
static int NDECL(wiz_level_change);
static int NDECL(wiz_flip_level);
static int NDECL(wiz_show_seenv);
static int NDECL(wiz_show_vision);
static int NDECL(wiz_smell);
@@ -1018,6 +1019,17 @@ wiz_level_tele(VOID_ARGS)
return 0;
}
/* #wizlevelflip - randomly flip the current level.
Does not handle vision, player position, monst mtrack, levregions,
as flipping is normally done only during level creation.
*/
static int
wiz_level_flip(VOID_ARGS)
{
if (wizard) flip_level_rnd(3);
return 0;
}
/* #levelchange command - adjust hero's experience level */
static int
wiz_level_change(VOID_ARGS)
@@ -1867,6 +1879,8 @@ struct ext_func_tab extcmdlist[] = {
wiz_identify, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
{ '\0', "wizintrinsic", "set an intrinsic",
wiz_intrinsic, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
{ '\0', "wizlevelflip", "flip the level",
wiz_level_flip, IFBURIED | WIZMODECMD },
{ C('v'), "wizlevelport", "teleport to another level",
wiz_level_tele, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
{ '\0', "wizloaddes", "load and execute a des-file lua script",

View File

@@ -37,6 +37,8 @@ NEARDATA struct obj *uwep, *uarm, *uswapwep,
*uarmc, *uarmh, *uarms, *uarmg,*uarmf, *uamul,
*uright, *uleft, *ublindf, *uchain, *uball;
struct engr *head_engr;
#ifdef TEXTCOLOR
/*
* This must be the same order as used for buzz() in zap.c.

View File

@@ -5,7 +5,7 @@
#include "hack.h"
static NEARDATA struct engr *head_engr;
struct engr *head_engr;
static const char *NDECL(blengr);
char *

View File

@@ -72,6 +72,7 @@
void strbuf_empty (strbuf *)
void strbuf_nl_to_crlf (strbuf_t *)
char * nonconst (const char *, char *)
int swapbits (int, int, int)
=*/
#ifdef LINT
#define Static /* pacify lint */
@@ -1290,4 +1291,14 @@ char *buf;
return retval;
}
/* swapbits(val, bita, bitb) swaps bit a with bit b in val */
int
swapbits(val, bita, bitb)
int val, bita, bitb;
{
int tmp = ((val >> bita) & 1) ^ ((val >> bitb) & 1);
return (val ^ ((tmp << bita) | (tmp << bitb)));
}
/*hacklib.c*/

View File

@@ -22,7 +22,6 @@ static void FDECL(check_ransacked, (char *));
static void FDECL(migr_booty_item, (int, const char *));
static void FDECL(migrate_orc, (struct monst *, unsigned long));
static void NDECL(stolen_booty);
static void FDECL(get_level_extends, (int *, int *, int *, int *));
/* adjust a coordinate one step in the specified direction */
#define mz_move(X, Y, dir) \
@@ -1225,7 +1224,7 @@ coord *cc;
return;
}
static void
void
get_level_extends(left, top, right, bottom)
int *left, *top, *right, *bottom;
{

View File

@@ -212,6 +212,320 @@ schar lit;
}
}
void
flip_drawbridge_horizontal(lev)
struct rm *lev;
{
if (IS_DRAWBRIDGE(lev->typ)) {
if ((lev->drawbridgemask & DB_DIR) == DB_WEST) {
lev->drawbridgemask &= ~DB_WEST;
lev->drawbridgemask |= DB_EAST;
} else if ((lev->drawbridgemask & DB_DIR) == DB_EAST) {
lev->drawbridgemask &= ~DB_EAST;
lev->drawbridgemask |= DB_WEST;
}
}
}
void
flip_drawbridge_vertical(lev)
struct rm *lev;
{
if (IS_DRAWBRIDGE(lev->typ)) {
if ((lev->drawbridgemask & DB_DIR) == DB_NORTH) {
lev->drawbridgemask &= ~DB_NORTH;
lev->drawbridgemask |= DB_SOUTH;
} else if ((lev->drawbridgemask & DB_DIR) == DB_SOUTH) {
lev->drawbridgemask &= ~DB_SOUTH;
lev->drawbridgemask |= DB_NORTH;
}
}
}
int
flip_encoded_direction_bits(int flp, int val)
{
/* These depend on xdir[] and ydir[] order */
if (flp & 1) {
val = swapbits(val, 1, 7);
val = swapbits(val, 2, 6);
val = swapbits(val, 3, 5);
}
if (flp & 2) {
val = swapbits(val, 1, 3);
val = swapbits(val, 0, 4);
val = swapbits(val, 7, 5);
}
return val;
}
#define FlipX(val) ((maxx - (val)) + minx)
#define FlipY(val) ((maxy - (val)) + miny)
void
flip_level(int flp)
{
int x, y, i;
int minx, miny, maxx, maxy;
struct rm trm;
struct trap *ttmp;
struct obj *otmp;
struct monst *mtmp;
struct engr *etmp;
struct mkroom *sroom;
get_level_extends(&minx, &miny, &maxx, &maxy);
/* get_level_extends() returns -1,-1 to COLNO,ROWNO at max */
if (miny < 0) miny = 0;
if (minx < 0) minx = 0;
if (maxx >= COLNO) maxx = (COLNO - 1);
if (maxy >= ROWNO) maxy = (ROWNO - 1);
/* stairs and ladders */
if (flp & 1) {
yupstair = FlipY(yupstair);
ydnstair = FlipY(ydnstair);
yupladder = FlipY(yupladder);
ydnladder = FlipY(ydnladder);
g.sstairs.sy = FlipY(g.sstairs.sy);
}
if (flp & 2) {
xupstair = FlipX(xupstair);
xdnstair = FlipX(xdnstair);
xupladder = FlipX(xupladder);
xdnladder = FlipX(xdnladder);
g.sstairs.sx = FlipX(g.sstairs.sx);
}
/* traps */
for (ttmp = g.ftrap; ttmp; ttmp = ttmp->ntrap) {
if (flp & 1) {
ttmp->ty = FlipY(ttmp->ty);
if (ttmp->ttyp == ROLLING_BOULDER_TRAP) {
ttmp->launch.y = FlipY(ttmp->launch.y);
ttmp->launch2.y = FlipY(ttmp->launch2.y);
} else if (is_pit(ttmp->ttyp) && ttmp->conjoined) {
ttmp->conjoined = flip_encoded_direction_bits(flp, ttmp->conjoined);
}
}
if (flp & 2) {
ttmp->tx = FlipX(ttmp->tx);
if (ttmp->ttyp == ROLLING_BOULDER_TRAP) {
ttmp->launch.x = FlipX(ttmp->launch.x);
ttmp->launch2.x = FlipX(ttmp->launch2.x);
} else if (is_pit(ttmp->ttyp) && ttmp->conjoined) {
ttmp->conjoined = flip_encoded_direction_bits(flp, ttmp->conjoined);
}
}
}
/* objects */
for (otmp = fobj; otmp; otmp = otmp->nobj) {
if (flp & 1)
otmp->oy = FlipY(otmp->oy);
if (flp & 2)
otmp->ox = FlipX(otmp->ox);
}
/* buried objects */
for (otmp = g.level.buriedobjlist; otmp; otmp = otmp->nobj) {
if (flp & 1)
otmp->oy = FlipY(otmp->oy);
if (flp & 2)
otmp->ox = FlipX(otmp->ox);
}
/* monsters */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
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) {
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) {
flip_worm_segs_horizontal(mtmp, minx, maxx);
}
}
}
/* engravings */
for (etmp = head_engr; etmp; etmp = etmp->nxt_engr) {
if (flp & 1)
etmp->engr_y = FlipY(etmp->engr_y);
if (flp & 2)
etmp->engr_x = FlipX(etmp->engr_x);
}
/* regions */
for (i = 0; i < g.num_lregions; i++) {
if (flp & 1) {
g.lregions[i].inarea.y1 = FlipY(g.lregions[i].inarea.y1);
g.lregions[i].inarea.y2 = FlipY(g.lregions[i].inarea.y2);
if (g.lregions[i].inarea.y1 > g.lregions[i].inarea.y2) {
int tmp = g.lregions[i].inarea.y1;
g.lregions[i].inarea.y1 = g.lregions[i].inarea.y2;
g.lregions[i].inarea.y2 = tmp;
}
g.lregions[i].delarea.y1 = FlipY(g.lregions[i].delarea.y1);
g.lregions[i].delarea.y2 = FlipY(g.lregions[i].delarea.y2);
if (g.lregions[i].delarea.y1 > g.lregions[i].delarea.y2) {
int tmp = g.lregions[i].delarea.y1;
g.lregions[i].delarea.y1 = g.lregions[i].delarea.y2;
g.lregions[i].delarea.y2 = tmp;
}
}
if (flp & 2) {
g.lregions[i].inarea.x1 = FlipX(g.lregions[i].inarea.x1);
g.lregions[i].inarea.x2 = FlipX(g.lregions[i].inarea.x2);
if (g.lregions[i].inarea.x1 > g.lregions[i].inarea.x2) {
int tmp = g.lregions[i].inarea.x1;
g.lregions[i].inarea.x1 = g.lregions[i].inarea.x2;
g.lregions[i].inarea.x2 = tmp;
}
g.lregions[i].delarea.x1 = FlipX(g.lregions[i].delarea.x1);
g.lregions[i].delarea.x2 = FlipX(g.lregions[i].delarea.x2);
if (g.lregions[i].delarea.x1 > g.lregions[i].delarea.x2) {
int tmp = g.lregions[i].delarea.x1;
g.lregions[i].delarea.x1 = g.lregions[i].delarea.x2;
g.lregions[i].delarea.x2 = tmp;
}
}
}
/* rooms */
for(sroom = &g.rooms[0]; ; sroom++) {
if (sroom->hx < 0) break;
if (flp & 1) {
sroom->ly = FlipY(sroom->ly);
sroom->hy = FlipY(sroom->hy);
if (sroom->ly > sroom->hy) {
int tmp = sroom->ly;
sroom->ly = sroom->hy;
sroom->hy = tmp;
}
}
if (flp & 2) {
sroom->lx = FlipX(sroom->lx);
sroom->hx = FlipX(sroom->hx);
if (sroom->lx > sroom->hx) {
int tmp = sroom->lx;
sroom->lx = sroom->hx;
sroom->hx = tmp;
}
}
if (sroom->nsubrooms)
for (i = 0; i < sroom->nsubrooms; i++) {
struct mkroom *rroom = sroom->sbrooms[i];
if (flp & 1) {
rroom->ly = FlipY(rroom->ly);
rroom->hy = FlipY(rroom->hy);
if (rroom->ly > rroom->hy) {
int tmp = rroom->ly;
rroom->ly = rroom->hy;
rroom->hy = tmp;
}
}
if (flp & 2) {
rroom->lx = FlipX(rroom->lx);
rroom->hx = FlipX(rroom->hx);
if (rroom->lx > rroom->hx) {
int tmp = rroom->lx;
rroom->lx = rroom->hx;
rroom->hx = tmp;
}
}
}
}
/* 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);
}
/* the map */
if (flp & 1) {
for (x = minx; x <= maxx; x++)
for (y = miny; y < (miny + ((maxy-miny+1) / 2)); y++) {
int ny = FlipY(y);
flip_drawbridge_vertical(&levl[x][y]);
flip_drawbridge_vertical(&levl[x][ny]);
trm = levl[x][y];
levl[x][y] = levl[x][ny];
levl[x][ny] = trm;
otmp = g.level.objects[x][y];
g.level.objects[x][y] = g.level.objects[x][ny];
g.level.objects[x][ny] = otmp;
mtmp = g.level.monsters[x][y];
g.level.monsters[x][y] = g.level.monsters[x][ny];
g.level.monsters[x][ny] = mtmp;
}
}
if (flp & 2) {
for (x = minx; x < (minx + ((maxx-minx+1) / 2)); x++)
for (y = miny; y <= maxy; y++) {
int nx = FlipX(x);
flip_drawbridge_horizontal(&levl[x][y]);
flip_drawbridge_horizontal(&levl[nx][y]);
trm = levl[x][y];
levl[x][y] = levl[nx][y];
levl[nx][y] = trm;
otmp = g.level.objects[x][y];
g.level.objects[x][y] = g.level.objects[nx][y];
g.level.objects[nx][y] = otmp;
mtmp = g.level.monsters[x][y];
g.level.monsters[x][y] = g.level.monsters[nx][y];
g.level.monsters[nx][y] = mtmp;
}
}
fix_wall_spines(1, 0, COLNO-1, ROWNO-1);
vision_reset();
}
#undef FlipX
#undef FlipY
void
flip_level_rnd(int flp)
{
int c = 0;
if ((flp & 1) && rn2(2)) c |= 1;
if ((flp & 2) && rn2(2)) c |= 2;
if (c) flip_level(c);
}
void
sel_set_wall_property(x, y, arg)
int x, y;
@@ -2886,6 +3200,12 @@ lua_State *L;
g.coder->solidify = 1;
else if (!strcmpi(s, "inaccessibles"))
g.coder->check_inaccessibles = 1;
else if (!strcmpi(s, "noflipx"))
g.coder->allow_flips &= ~2;
else if (!strcmpi(s, "noflipy"))
g.coder->allow_flips &= ~1;
else if (!strcmpi(s, "noflip"))
g.coder->allow_flips = 0;
else {
char buf[BUFSZ];
Sprintf(buf, "Unknown level flag %s", s);
@@ -5498,6 +5818,7 @@ sp_level_coder_init()
coder->premapped = FALSE;
coder->solidify = FALSE;
coder->check_inaccessibles = FALSE;
coder->allow_flips = 3; /* allow flipping level horiz/vert */
coder->croom = NULL;
coder->n_subroom = 1;
coder->lvl_is_joined = 0;
@@ -5630,6 +5951,8 @@ const char *name;
if (!g.level.flags.corrmaze)
wallification(1, 0, COLNO - 1, ROWNO - 1);
flip_level_rnd(g.coder->allow_flips);
count_features();
if (g.coder->solidify)

View File

@@ -921,4 +921,30 @@ int x, y;
return res;
}
void
flip_worm_segs_vertical(worm, miny, maxy)
struct monst *worm;
int miny, maxy;
{
struct wseg *curr = wtails[worm->wormno];
while (curr) {
curr->wy = (maxy - curr->wy + miny);
curr = curr->nseg;
}
}
void
flip_worm_segs_horizontal(worm, minx, maxx)
struct monst *worm;
int minx, maxx;
{
struct wseg *curr = wtails[worm->wormno];
while (curr) {
curr->wx = (maxx - curr->wx + minx);
curr = curr->nseg;
}
}
/*worm.c*/