]> granicus.if.org Git - nethack/commitdiff
Start of movement tests
authorPasi Kallinen <paxed@alt.org>
Wed, 28 Jul 2021 16:11:30 +0000 (19:11 +0300)
committerPasi Kallinen <paxed@alt.org>
Wed, 28 Jul 2021 16:19:40 +0000 (19:19 +0300)
Adds the following lua functions:

- nh.pushkey("x")
    Pushes a key into the command queue. Support is spotty,
    currently only the keys handled in rhack.
- nh.doturn()
    Runs one turn of main loop, or if optional boolean param
    is true, until g.multi == 0
- nh.monster_generation(false)
    Disable monster generation, and kill off all monsters.

Adds a testmove.lua script to test hero movement. Currently
covers only hjklyubn and HJKLYUBN.

include/extern.h
include/flag.h
src/allmain.c
src/makemon.c
src/nhlua.c
test/testmove.lua [new file with mode: 0644]

index f512bd581cc60f6341d7d898ce852e6b944ef7fe..f0d3292e0dcd5fb762f50a298006c1d9b4ce662b 100644 (file)
@@ -18,6 +18,7 @@ extern char *fmt_ptr(const void *);
 
 /* ### allmain.c ### */
 
+extern void moveloop_core(void);
 extern void moveloop(boolean);
 extern void stop_occupation(void);
 extern void display_gamewindows(void);
index f403569dea81f3760c782f50e5065e2d7c2cb8ff..c8a7567143b2938db7116c8894572ca2a8d9f059 100644 (file)
@@ -204,6 +204,7 @@ struct instance_flags {
     boolean window_inited; /* true if init_nhwindows() completed */
     boolean vision_inited; /* true if vision is ready */
     boolean sanity_check;  /* run sanity checks */
+    boolean debug_mongen;  /* debug: prevent monster generation */
     boolean mon_polycontrol; /* debug: control monster polymorphs */
     boolean in_dumplog;    /* doing the dumplog right now? */
     boolean in_parse;      /* is a command being parsed? */
index 2e77900f1efbcea1542c00b773b9081bfa24295d..1363915ec2b923c59bde7583501cfe99aea16d5e 100644 (file)
@@ -14,7 +14,6 @@
 
 static void moveloop_preamble(boolean);
 static void u_calc_moveamt(int);
-static void moveloop_core(void);
 #ifdef POSITIONBAR
 static void do_positionbar(void);
 #endif
@@ -133,17 +132,17 @@ u_calc_moveamt(int wtcap)
         g.youmonst.movement = 0;
 }
 
-static void
-moveloop_core(void)
-{
 #if defined(MICRO) || defined(WIN32)
-    char ch;
-    int abort_lev;
+static int mvl_abort_lev;
 #endif
-    int wtcap = 0, change = 0;
+static int mvl_wtcap = 0;
+static int mvl_change = 0;
+
+void
+moveloop_core(void)
+{
     boolean monscanmove = FALSE;
 
-    for (;;) {
 #ifdef SAFERHANGUP
         if (g.program_state.done_hup)
             end_of_input();
@@ -158,7 +157,7 @@ moveloop_core(void)
             g.youmonst.movement -= NORMAL_SPEED;
 
             do { /* hero can't move this turn loop */
-                wtcap = encumber_msg();
+                mvl_wtcap = encumber_msg();
 
                 g.context.mon_moving = TRUE;
                 do {
@@ -190,7 +189,7 @@ moveloop_core(void)
                         (void) makemon((struct permonst *) 0, 0, 0,
                                        NO_MM_FLAGS);
 
-                    u_calc_moveamt(wtcap);
+                    u_calc_moveamt(mvl_wtcap);
                     settrack();
 
                     g.monstermoves++; /* [obsolete (for a long time...)] */
@@ -236,24 +235,24 @@ moveloop_core(void)
                      */
                     if (u.uinvulnerable) {
                         /* for the moment at least, you're in tiptop shape */
-                        wtcap = UNENCUMBERED;
+                        mvl_wtcap = UNENCUMBERED;
                     } else if (!Upolyd ? (u.uhp < u.uhpmax)
                                        : (u.mh < u.mhmax
                                           || g.youmonst.data->mlet == S_EEL)) {
                         /* maybe heal */
-                        regen_hp(wtcap);
+                        regen_hp(mvl_wtcap);
                     }
 
                     /* moving around while encumbered is hard work */
-                    if (wtcap > MOD_ENCUMBER && u.umoved) {
-                        if (!(wtcap < EXT_ENCUMBER ? g.moves % 30
+                    if (mvl_wtcap > MOD_ENCUMBER && u.umoved) {
+                        if (!(mvl_wtcap < EXT_ENCUMBER ? g.moves % 30
                                                    : g.moves % 10)) {
                             overexert_hp();
                         }
                     }
 
                     if (u.uen < u.uenmax
-                        && ((wtcap < MOD_ENCUMBER
+                        && ((mvl_wtcap < MOD_ENCUMBER
                              && (!(g.moves % ((MAXULEV + 8 - u.ulevel)
                                             * (Role_if(PM_WIZARD) ? 3 : 4)
                                             / 6)))) || Energy_regeneration)) {
@@ -281,22 +280,22 @@ moveloop_core(void)
                             }
                         }
                         /* delayed change may not be valid anymore */
-                        if ((change == 1 && !Polymorph)
-                            || (change == 2 && u.ulycn == NON_PM))
-                            change = 0;
+                        if ((mvl_change == 1 && !Polymorph)
+                            || (mvl_change == 2 && u.ulycn == NON_PM))
+                            mvl_change = 0;
                         if (Polymorph && !rn2(100))
-                            change = 1;
+                            mvl_change = 1;
                         else if (u.ulycn >= LOW_PM && !Upolyd
                                  && !rn2(80 - (20 * night())))
-                            change = 2;
-                        if (change && !Unchanging) {
+                            mvl_change = 2;
+                        if (mvl_change && !Unchanging) {
                             if (g.multi >= 0) {
                                 stop_occupation();
-                                if (change == 1)
+                                if (mvl_change == 1)
                                     polyself(0);
                                 else
                                     you_were();
-                                change = 0;
+                                mvl_change = 0;
                             }
                         }
                     }
@@ -418,21 +417,23 @@ moveloop_core(void)
 
         if (g.multi >= 0 && g.occupation) {
 #if defined(MICRO) || defined(WIN32)
-            abort_lev = 0;
+            mvl_abort_lev = 0;
             if (kbhit()) {
+                char ch;
+
                 if ((ch = pgetchar()) == ABORT)
-                    abort_lev++;
+                    mvl_abort_lev++;
                 else
                     pushch(ch);
             }
-            if (!abort_lev && (*g.occupation)() == 0)
+            if (!mvl_abort_lev && (*g.occupation)() == 0)
 #else
             if ((*g.occupation)() == 0)
 #endif
                 g.occupation = 0;
             if (
 #if defined(MICRO) || defined(WIN32)
-                abort_lev ||
+                mvl_abort_lev ||
 #endif
                 monster_nearby()) {
                 stop_occupation();
@@ -442,7 +443,7 @@ moveloop_core(void)
             if (!(++g.occtime % 7))
                 display_nhwindow(WIN_MAP, FALSE);
 #endif
-            continue;
+            return;
         }
 
         if (iflags.sanity_check || iflags.debug_fuzzer)
@@ -460,7 +461,7 @@ moveloop_core(void)
             if (!g.multi) {
                 /* lookaround may clear multi */
                 g.context.move = 0;
-                continue;
+                return;
             }
             if (g.context.mv) {
                 if (g.multi < COLNO && !--g.multi)
@@ -492,14 +493,15 @@ moveloop_core(void)
             /* [should this be flush_screen() instead?] */
             display_nhwindow(WIN_MAP, FALSE);
         }
-    }
 }
 
 void
 moveloop(boolean resuming)
 {
     moveloop_preamble(resuming);
-    moveloop_core();
+    for (;;) {
+        moveloop_core();
+    }
 }
 
 #define U_CAN_REGEN() (Regeneration || (Sleepy && u.usleep))
index 5ed63ab646e70323c2e54edd8c70ae44566b721a..067ef4381d36e9d95e160caf6dab696f0614758f 100644 (file)
@@ -1123,6 +1123,9 @@ makemon(register struct permonst *ptr,
     fakemon = cg.zeromonst;
     cc.x = cc.y = 0;
 
+    if (iflags.debug_mongen)
+        return (struct monst *) 0;
+
     /* if caller wants random location, do it here */
     if (x == 0 && y == 0) {
         fakemon.data = ptr; /* set up for goodpos */
index 96aca7484584472c8f7231160f253d8dbad37f86..e2704c3a53a57dbfb034b91c911278e3e27bec38 100644 (file)
@@ -19,6 +19,9 @@ static int nhl_dump_fmtstr(lua_State *);
 #endif /* DUMPLOG */
 static int nhl_dnum_name(lua_State *);
 static int nhl_stairways(lua_State *);
+static int nhl_pushkey(lua_State *);
+static int nhl_doturn(lua_State *);
+static int nhl_monster_generation(lua_State *);
 static int nhl_test(lua_State *);
 static int nhl_getmap(lua_State *);
 static void nhl_add_table_entry_bool(lua_State *, const char *, boolean);
@@ -936,6 +939,68 @@ nhl_test(lua_State *L)
     return 1;
 }
 
+/* push a key into command queue */
+/* nh.pushkey("i"); */
+static int
+nhl_pushkey(lua_State *L)
+{
+    int argc = lua_gettop(L);
+
+    if (argc == 1) {
+        const char *key = luaL_checkstring(L, 1);
+
+        cmdq_add_key(key[0]);
+    }
+
+    return 0;
+}
+
+/* do a turn of moveloop, or until g.multi is done if param is true. */
+/* nh.doturn(); nh.doturn(true); */
+static int
+nhl_doturn(lua_State *L)
+{
+    int argc = lua_gettop(L);
+    boolean domulti = FALSE;
+
+    if (argc == 1)
+        domulti = lua_toboolean(L, 1);
+
+    do {
+        moveloop_core();
+    } while (domulti && g.multi);
+
+    return 0;
+}
+
+/* disable or enable monster generation. debugging use only. */
+/* disabling also kills all monsters on current level. */
+/* local prevvalue = nh.monster_generation(false); */
+static int
+nhl_monster_generation(lua_State *L)
+{
+    int argc = lua_gettop(L);
+    boolean val = !iflags.debug_mongen; /* value in lua is negated */
+
+    if (argc == 1) {
+        iflags.debug_mongen = !lua_toboolean(L, 1);
+        if (iflags.debug_mongen) {
+            register struct monst *mtmp, *mtmp2;
+
+            for (mtmp = fmon; mtmp; mtmp = mtmp2) {
+                mtmp2 = mtmp->nmon;
+                if (DEADMONSTER(mtmp))
+                    continue;
+                mongone(mtmp);
+            }
+        }
+    }
+
+    lua_pushboolean(L, val);
+    return 1;
+}
+
+
 static const struct luaL_Reg nhl_functions[] = {
     {"test", nhl_test},
 
@@ -967,6 +1032,9 @@ static const struct luaL_Reg nhl_functions[] = {
 #endif /* DUMPLOG */
     {"dnum_name", nhl_dnum_name},
     {"stairways", nhl_stairways},
+    {"pushkey", nhl_pushkey},
+    {"doturn", nhl_doturn},
+    {"monster_generation", nhl_monster_generation},
     {NULL, NULL}
 };
 
diff --git a/test/testmove.lua b/test/testmove.lua
new file mode 100644 (file)
index 0000000..434b816
--- /dev/null
@@ -0,0 +1,65 @@
+
+-- Tests for moving the hero
+
+-- TODO: running stops if hero walks over stairs -> test fails.
+--       prevent stair generation? check where the stairs are?
+
+nh.parse_config("OPTIONS=number_pad:0");
+nh.parse_config("OPTIONS=runmode:teleport");
+
+local POS = { x = 10, y = 05 };
+
+function initlev()
+   nh.monster_generation(false);
+   des.level_flags("noflip");
+   des.reset_level();
+   des.level_init({ style = "solidfill", fg = ".", lit = true });
+   des.teleport_region({ region = {POS.x,POS.y,POS.x,POS.y}, region_islev = true, dir="both" });
+   des.finalize_level();
+end
+
+local basicmoves = {
+   h = { dx = -1,  dy =  0 },
+   j = { dx =  0,  dy =  1 },
+   k = { dx =  0,  dy = -1 },
+   l = { dx =  1,  dy =  0 },
+   y = { dx = -1,  dy = -1 },
+   u = { dx =  1,  dy = -1 },
+   b = { dx = -1,  dy =  1 },
+   n = { dx =  1,  dy =  1 },
+   H = { x = 2,  y = POS.y },
+   J = { x = POS.x, y = nhc.ROWNO-1 },
+   K = { x = POS.x, y = 0 },
+   L = { x = nhc.COLNO-2, y = POS.y },
+   Y = { x = POS.x - POS.y, y = 0 },
+   U = { x = POS.x + POS.y, y = 0 },
+   B = { x = 2, y = 13 },
+   N = { x = 25, y = nhc.ROWNO-1 },
+};
+
+
+for k, v in pairs(basicmoves) do
+   initlev();
+
+   local x = u.ux;
+   local y = u.uy;
+
+   nh.pushkey(k);
+   nh.doturn(true);
+
+   if (v.dx ~= nil) then
+      if (not (x == u.ux - v.dx and y == u.uy - v.dy)) then
+         error(string.format("Move: key '%s' gave (%i,%i), should have been (%i,%i)",
+                             k, u.ux, u.uy, u.ux - v.dx, u.uy - v.dy));
+         return;
+      end
+   elseif (v.x ~= nil) then
+      if (not (u.ux == v.x and u.uy == v.y)) then
+         error(string.format("Move: key '%s' gave (%i,%i), should have been (%i,%i)",
+                             k, u.ux, u.uy, v.x, v.y));
+         return;
+      end
+   end
+end
+
+initlev();