/* ### allmain.c ### */
+extern void moveloop_core(void);
extern void moveloop(boolean);
extern void stop_occupation(void);
extern void display_gamewindows(void);
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? */
static void moveloop_preamble(boolean);
static void u_calc_moveamt(int);
-static void moveloop_core(void);
#ifdef POSITIONBAR
static void do_positionbar(void);
#endif
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();
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 {
(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...)] */
*/
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)) {
}
}
/* 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;
}
}
}
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();
if (!(++g.occtime % 7))
display_nhwindow(WIN_MAP, FALSE);
#endif
- continue;
+ return;
}
if (iflags.sanity_check || iflags.debug_fuzzer)
if (!g.multi) {
/* lookaround may clear multi */
g.context.move = 0;
- continue;
+ return;
}
if (g.context.mv) {
if (g.multi < COLNO && !--g.multi)
/* [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))
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 */
#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);
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},
#endif /* DUMPLOG */
{"dnum_name", nhl_dnum_name},
{"stairways", nhl_stairways},
+ {"pushkey", nhl_pushkey},
+ {"doturn", nhl_doturn},
+ {"monster_generation", nhl_monster_generation},
{NULL, NULL}
};
--- /dev/null
+
+-- 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();