]> granicus.if.org Git - nethack/commitdiff
Allow flipping levels horizontally or vertically
authorPasi Kallinen <paxed@alt.org>
Thu, 20 Feb 2020 17:18:54 +0000 (19:18 +0200)
committerPasi Kallinen <paxed@alt.org>
Fri, 21 Feb 2020 16:16:14 +0000 (18:16 +0200)
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.

20 files changed:
dat/bigrm-1.lua
dat/bigrm-10.lua
dat/bigrm-2.lua
dat/bigrm-3.lua
dat/bigrm-4.lua
dat/bigrm-5.lua
dat/bigrm-6.lua
dat/bigrm-9.lua
dat/castle.lua
doc/fixes37.0
include/decl.h
include/extern.h
include/sp_lev.h
src/cmd.c
src/decl.c
src/engrave.c
src/hacklib.c
src/mkmaze.c
src/sp_lev.c
src/worm.c

index a644b129e677717f50178f0b4a89c9ea8cd9c40d..9c16f1984576ea406224a6f07d4482d1027c9461 100644 (file)
@@ -1,6 +1,6 @@
 
 des.level_init({ style = "solidfill", fg = " " });
-des.level_flags("mazelevel");
+des.level_flags("mazelevel", "noflip");
 
 des.map([[
 ---------------------------------------------------------------------------
index 693697137ac79fc8f912c8f3cd8dcef1db9e922f..69403d8f91e659eb102c571e74f0ec2b901de85d 100644 (file)
@@ -1,7 +1,7 @@
 
 
 des.level_init({ style = "solidfill", fg = " " });
-des.level_flags("mazelevel");
+des.level_flags("mazelevel", "noflip");
 
 des.map([[
 .......................................................................
index 5d7b3f98785b5186c546d378dbf3da915cb422d8..0e4483ccefab148d4db2fd9123960c56536301fd 100644 (file)
@@ -1,6 +1,6 @@
 
 des.level_init({ style = "solidfill", fg = " " });
-des.level_flags("mazelevel");
+des.level_flags("mazelevel", "noflip");
 
 des.map([[
 ---------------------------------------------------------------------------
index 2f36fc53324e36b446ec013c3a867e1201cf002c..07afad2b08b458cc129140fe14aa46e0a1fe638d 100644 (file)
@@ -1,6 +1,6 @@
 
 des.level_init({ style = "solidfill", fg = " " });
-des.level_flags("mazelevel");
+des.level_flags("mazelevel", "noflip");
 
 des.map([[
 ---------------------------------------------------------------------------
index d86f46b48a2f3b080afd85484f27e6202bd20df9..b43596292b92cd00ed25d972a4b184ec2b917d14 100644 (file)
@@ -1,6 +1,6 @@
 
 des.level_init({ style = "solidfill", fg = " " });
-des.level_flags("mazelevel");
+des.level_flags("mazelevel", "noflip");
 
 des.map([[
 -----------                                                     -----------
index c85f55e125cbc5a15bb031dfc404bcebe20b0463..1640103760f467e3e8c55d8d84bf56add66e6b4a 100644 (file)
@@ -1,6 +1,6 @@
 
 des.level_init({ style = "solidfill", fg = " " });
-des.level_flags("mazelevel");
+des.level_flags("mazelevel", "noflip");
 
 des.map([[
                             ------------------                            
index 6138be67e55dd3f0d0d70d199626edba89586671..0d136850365defcf9411b6b34145d79b49ad4cc1 100644 (file)
@@ -1,7 +1,7 @@
 
 
 des.level_init({ style = "solidfill", fg = " " });
-des.level_flags("mazelevel");
+des.level_flags("mazelevel", "noflip");
 
 des.map([[
      ---------         ---------         ---------         ---------     
index a1fdcd05f9c053ddbd92961c45344729be6632e1..2b79e8771f4843d3bc2818b57e998c9081e54c58 100644 (file)
@@ -1,6 +1,6 @@
 
 des.level_init({ style = "solidfill", fg = " " });
-des.level_flags("mazelevel");
+des.level_flags("mazelevel", "noflip");
 
 des.map([[
 }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
index fcf3d25b6d1ca2f3126ff04d04261131bb095585..e01323fa7782d0491f8b0cb4dbca8606445485e5 100644 (file)
@@ -19,7 +19,7 @@
 
 des.level_init({ style="mazegrid", bg ="-" });
 
-des.level_flags("mazelevel", "noteleport")
+des.level_flags("mazelevel", "noteleport", "noflipy")
 
 des.map([[
 }}}}}}}}}.............................................}}}}}}}}}
index e2c1970efb89c09299214b94107041325e171466..ab1be2e708673cdce366f416d33f3a28c76e7f91 100644 (file)
@@ -161,6 +161,7 @@ new glyph GLYPH_NOTHING was added so !dark_room has something to be set to
 added several new status conditions all of which are opt-in except
        the new cond_grab and cond_lava which are opt-out
 tipping your cap might get a response
+special levels can be flipped horizontally and/or vertically
 
 
 Platform- and/or Interface-Specific New Features
index 3488771f9f88627a5898cff22b08b5a1beacdb37..060a1b3c4e0ce4717cb7aab23ce7d4b7ca6280ed 100644 (file)
@@ -210,6 +210,9 @@ E NEARDATA struct obj *uarm, *uarmc, *uarmh, *uarms, *uarmg, *uarmf,
 E NEARDATA struct obj *uchain; /* defined only when punished */
 E NEARDATA struct obj *uball;
 
+#include "engrave.h"
+E struct engr *head_engr;
+
 #include "you.h"
 E NEARDATA struct you u;
 E NEARDATA time_t ubirthday;
index 4edf4423a710b7115bbd68b8bdeca7e506742a36..0660ab847295ae597e829f116d14957d5e1c37f9 100644 (file)
@@ -986,6 +986,7 @@ E void FDECL(strbuf_reserve, (strbuf_t *, int));
 E void FDECL(strbuf_empty, (strbuf_t *));
 E void FDECL(strbuf_nl_to_crlf, (strbuf_t *));
 E char *FDECL(nonconst, (const char *, char *));
+E int FDECL(swapbits, (int, int, int));
 
 /* ### insight.c ### */
 
@@ -1334,6 +1335,7 @@ E void FDECL(fix_wall_spines, (int, int, int, int));
 E void FDECL(walkfrom, (int, int, SCHAR_P));
 E void FDECL(makemaz, (const char *));
 E void FDECL(mazexy, (coord *));
+E void FDECL(get_level_extends, (int *, int *, int *, int *));
 E void NDECL(bound_digging);
 E void FDECL(mkportal, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P));
 E boolean FDECL(bad_location, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P,
@@ -2464,6 +2466,7 @@ E void FDECL(sysopt_seduce_set, (int));
 
 /* ### sp_lev.c ### */
 #if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET)
+E void FDECL(flip_level_rnd, (int));
 E boolean FDECL(check_room, (xchar *, xchar *, xchar *, xchar *, BOOLEAN_P));
 E boolean FDECL(create_room, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P,
                               XCHAR_P, XCHAR_P, XCHAR_P));
@@ -3049,6 +3052,8 @@ E int FDECL(count_wsegs, (struct monst *));
 E boolean FDECL(worm_known, (struct monst *));
 E boolean FDECL(worm_cross, (int, int, int, int));
 E int FDECL(wseg_at, (struct monst *, int, int));
+E void FDECL(flip_worm_segs_vertical, (struct monst *, int, int));
+E void FDECL(flip_worm_segs_horizontal, (struct monst *, int, int));
 
 /* ### worn.c ### */
 
index 803315688678b8c324cb9235be22317c8718d74d..783edf441411dc06e962e947eb03200dcc09ee25 100644 (file)
@@ -86,6 +86,7 @@ struct sp_coder {
     int n_subroom;
     int lvl_is_joined;
     boolean check_inaccessibles;
+    int allow_flips;
 };
 
 /*
index e4de504e9e821d3d31540187faa9e2202ff460b7..4932dd6fc66c22ecb21e95bf1956e7dc816a52ca 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -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",
index 5604140d29fa25216807c000a2fc08a37fb4890e..61706d24eaa9993493cb01be1994435f80b1cf6c 100644 (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.
index 8d37b0027657ffb4e88b29471959c2c8025cedd2..981ded64de5b6d0740234a01b2812b28e3b21f3c 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "hack.h"
 
-static NEARDATA struct engr *head_engr;
+struct engr *head_engr;
 static const char *NDECL(blengr);
 
 char *
index 610646c359a790d46372d95bcd6bf6bbab22954b..5d53bccbc5ee1df62ea443b2e3ade564d6d86e68 100644 (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*/
index b46185b6b170c9a3012df3f0b40925852a110f62..bf1741f62712aa5ff2014a971ac0eff240f55ac0 100644 (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;
 {
index 3eb2284537d06689bec2a007708376d5ccaa6fee..775dc10ea6ab404bda710bb167a6935533bc7c08 100644 (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)
index 28f47542d6f213fe664e6f27d134cd089f883726..3f173a134e2b683d5347f5e40c3b9f617fa1c918 100644 (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*/