Start of movement tests
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.
This commit is contained in:
@@ -18,6 +18,7 @@ extern char *fmt_ptr(const void *);
|
|||||||
|
|
||||||
/* ### allmain.c ### */
|
/* ### allmain.c ### */
|
||||||
|
|
||||||
|
extern void moveloop_core(void);
|
||||||
extern void moveloop(boolean);
|
extern void moveloop(boolean);
|
||||||
extern void stop_occupation(void);
|
extern void stop_occupation(void);
|
||||||
extern void display_gamewindows(void);
|
extern void display_gamewindows(void);
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ struct instance_flags {
|
|||||||
boolean window_inited; /* true if init_nhwindows() completed */
|
boolean window_inited; /* true if init_nhwindows() completed */
|
||||||
boolean vision_inited; /* true if vision is ready */
|
boolean vision_inited; /* true if vision is ready */
|
||||||
boolean sanity_check; /* run sanity checks */
|
boolean sanity_check; /* run sanity checks */
|
||||||
|
boolean debug_mongen; /* debug: prevent monster generation */
|
||||||
boolean mon_polycontrol; /* debug: control monster polymorphs */
|
boolean mon_polycontrol; /* debug: control monster polymorphs */
|
||||||
boolean in_dumplog; /* doing the dumplog right now? */
|
boolean in_dumplog; /* doing the dumplog right now? */
|
||||||
boolean in_parse; /* is a command being parsed? */
|
boolean in_parse; /* is a command being parsed? */
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
static void moveloop_preamble(boolean);
|
static void moveloop_preamble(boolean);
|
||||||
static void u_calc_moveamt(int);
|
static void u_calc_moveamt(int);
|
||||||
static void moveloop_core(void);
|
|
||||||
#ifdef POSITIONBAR
|
#ifdef POSITIONBAR
|
||||||
static void do_positionbar(void);
|
static void do_positionbar(void);
|
||||||
#endif
|
#endif
|
||||||
@@ -133,17 +132,17 @@ u_calc_moveamt(int wtcap)
|
|||||||
g.youmonst.movement = 0;
|
g.youmonst.movement = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
#if defined(MICRO) || defined(WIN32)
|
||||||
|
static int mvl_abort_lev;
|
||||||
|
#endif
|
||||||
|
static int mvl_wtcap = 0;
|
||||||
|
static int mvl_change = 0;
|
||||||
|
|
||||||
|
void
|
||||||
moveloop_core(void)
|
moveloop_core(void)
|
||||||
{
|
{
|
||||||
#if defined(MICRO) || defined(WIN32)
|
|
||||||
char ch;
|
|
||||||
int abort_lev;
|
|
||||||
#endif
|
|
||||||
int wtcap = 0, change = 0;
|
|
||||||
boolean monscanmove = FALSE;
|
boolean monscanmove = FALSE;
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
#ifdef SAFERHANGUP
|
#ifdef SAFERHANGUP
|
||||||
if (g.program_state.done_hup)
|
if (g.program_state.done_hup)
|
||||||
end_of_input();
|
end_of_input();
|
||||||
@@ -158,7 +157,7 @@ moveloop_core(void)
|
|||||||
g.youmonst.movement -= NORMAL_SPEED;
|
g.youmonst.movement -= NORMAL_SPEED;
|
||||||
|
|
||||||
do { /* hero can't move this turn loop */
|
do { /* hero can't move this turn loop */
|
||||||
wtcap = encumber_msg();
|
mvl_wtcap = encumber_msg();
|
||||||
|
|
||||||
g.context.mon_moving = TRUE;
|
g.context.mon_moving = TRUE;
|
||||||
do {
|
do {
|
||||||
@@ -190,7 +189,7 @@ moveloop_core(void)
|
|||||||
(void) makemon((struct permonst *) 0, 0, 0,
|
(void) makemon((struct permonst *) 0, 0, 0,
|
||||||
NO_MM_FLAGS);
|
NO_MM_FLAGS);
|
||||||
|
|
||||||
u_calc_moveamt(wtcap);
|
u_calc_moveamt(mvl_wtcap);
|
||||||
settrack();
|
settrack();
|
||||||
|
|
||||||
g.monstermoves++; /* [obsolete (for a long time...)] */
|
g.monstermoves++; /* [obsolete (for a long time...)] */
|
||||||
@@ -236,24 +235,24 @@ moveloop_core(void)
|
|||||||
*/
|
*/
|
||||||
if (u.uinvulnerable) {
|
if (u.uinvulnerable) {
|
||||||
/* for the moment at least, you're in tiptop shape */
|
/* for the moment at least, you're in tiptop shape */
|
||||||
wtcap = UNENCUMBERED;
|
mvl_wtcap = UNENCUMBERED;
|
||||||
} else if (!Upolyd ? (u.uhp < u.uhpmax)
|
} else if (!Upolyd ? (u.uhp < u.uhpmax)
|
||||||
: (u.mh < u.mhmax
|
: (u.mh < u.mhmax
|
||||||
|| g.youmonst.data->mlet == S_EEL)) {
|
|| g.youmonst.data->mlet == S_EEL)) {
|
||||||
/* maybe heal */
|
/* maybe heal */
|
||||||
regen_hp(wtcap);
|
regen_hp(mvl_wtcap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* moving around while encumbered is hard work */
|
/* moving around while encumbered is hard work */
|
||||||
if (wtcap > MOD_ENCUMBER && u.umoved) {
|
if (mvl_wtcap > MOD_ENCUMBER && u.umoved) {
|
||||||
if (!(wtcap < EXT_ENCUMBER ? g.moves % 30
|
if (!(mvl_wtcap < EXT_ENCUMBER ? g.moves % 30
|
||||||
: g.moves % 10)) {
|
: g.moves % 10)) {
|
||||||
overexert_hp();
|
overexert_hp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u.uen < u.uenmax
|
if (u.uen < u.uenmax
|
||||||
&& ((wtcap < MOD_ENCUMBER
|
&& ((mvl_wtcap < MOD_ENCUMBER
|
||||||
&& (!(g.moves % ((MAXULEV + 8 - u.ulevel)
|
&& (!(g.moves % ((MAXULEV + 8 - u.ulevel)
|
||||||
* (Role_if(PM_WIZARD) ? 3 : 4)
|
* (Role_if(PM_WIZARD) ? 3 : 4)
|
||||||
/ 6)))) || Energy_regeneration)) {
|
/ 6)))) || Energy_regeneration)) {
|
||||||
@@ -281,22 +280,22 @@ moveloop_core(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* delayed change may not be valid anymore */
|
/* delayed change may not be valid anymore */
|
||||||
if ((change == 1 && !Polymorph)
|
if ((mvl_change == 1 && !Polymorph)
|
||||||
|| (change == 2 && u.ulycn == NON_PM))
|
|| (mvl_change == 2 && u.ulycn == NON_PM))
|
||||||
change = 0;
|
mvl_change = 0;
|
||||||
if (Polymorph && !rn2(100))
|
if (Polymorph && !rn2(100))
|
||||||
change = 1;
|
mvl_change = 1;
|
||||||
else if (u.ulycn >= LOW_PM && !Upolyd
|
else if (u.ulycn >= LOW_PM && !Upolyd
|
||||||
&& !rn2(80 - (20 * night())))
|
&& !rn2(80 - (20 * night())))
|
||||||
change = 2;
|
mvl_change = 2;
|
||||||
if (change && !Unchanging) {
|
if (mvl_change && !Unchanging) {
|
||||||
if (g.multi >= 0) {
|
if (g.multi >= 0) {
|
||||||
stop_occupation();
|
stop_occupation();
|
||||||
if (change == 1)
|
if (mvl_change == 1)
|
||||||
polyself(0);
|
polyself(0);
|
||||||
else
|
else
|
||||||
you_were();
|
you_were();
|
||||||
change = 0;
|
mvl_change = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,21 +417,23 @@ moveloop_core(void)
|
|||||||
|
|
||||||
if (g.multi >= 0 && g.occupation) {
|
if (g.multi >= 0 && g.occupation) {
|
||||||
#if defined(MICRO) || defined(WIN32)
|
#if defined(MICRO) || defined(WIN32)
|
||||||
abort_lev = 0;
|
mvl_abort_lev = 0;
|
||||||
if (kbhit()) {
|
if (kbhit()) {
|
||||||
|
char ch;
|
||||||
|
|
||||||
if ((ch = pgetchar()) == ABORT)
|
if ((ch = pgetchar()) == ABORT)
|
||||||
abort_lev++;
|
mvl_abort_lev++;
|
||||||
else
|
else
|
||||||
pushch(ch);
|
pushch(ch);
|
||||||
}
|
}
|
||||||
if (!abort_lev && (*g.occupation)() == 0)
|
if (!mvl_abort_lev && (*g.occupation)() == 0)
|
||||||
#else
|
#else
|
||||||
if ((*g.occupation)() == 0)
|
if ((*g.occupation)() == 0)
|
||||||
#endif
|
#endif
|
||||||
g.occupation = 0;
|
g.occupation = 0;
|
||||||
if (
|
if (
|
||||||
#if defined(MICRO) || defined(WIN32)
|
#if defined(MICRO) || defined(WIN32)
|
||||||
abort_lev ||
|
mvl_abort_lev ||
|
||||||
#endif
|
#endif
|
||||||
monster_nearby()) {
|
monster_nearby()) {
|
||||||
stop_occupation();
|
stop_occupation();
|
||||||
@@ -442,7 +443,7 @@ moveloop_core(void)
|
|||||||
if (!(++g.occtime % 7))
|
if (!(++g.occtime % 7))
|
||||||
display_nhwindow(WIN_MAP, FALSE);
|
display_nhwindow(WIN_MAP, FALSE);
|
||||||
#endif
|
#endif
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iflags.sanity_check || iflags.debug_fuzzer)
|
if (iflags.sanity_check || iflags.debug_fuzzer)
|
||||||
@@ -460,7 +461,7 @@ moveloop_core(void)
|
|||||||
if (!g.multi) {
|
if (!g.multi) {
|
||||||
/* lookaround may clear multi */
|
/* lookaround may clear multi */
|
||||||
g.context.move = 0;
|
g.context.move = 0;
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
if (g.context.mv) {
|
if (g.context.mv) {
|
||||||
if (g.multi < COLNO && !--g.multi)
|
if (g.multi < COLNO && !--g.multi)
|
||||||
@@ -492,14 +493,15 @@ moveloop_core(void)
|
|||||||
/* [should this be flush_screen() instead?] */
|
/* [should this be flush_screen() instead?] */
|
||||||
display_nhwindow(WIN_MAP, FALSE);
|
display_nhwindow(WIN_MAP, FALSE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
moveloop(boolean resuming)
|
moveloop(boolean resuming)
|
||||||
{
|
{
|
||||||
moveloop_preamble(resuming);
|
moveloop_preamble(resuming);
|
||||||
moveloop_core();
|
for (;;) {
|
||||||
|
moveloop_core();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define U_CAN_REGEN() (Regeneration || (Sleepy && u.usleep))
|
#define U_CAN_REGEN() (Regeneration || (Sleepy && u.usleep))
|
||||||
|
|||||||
@@ -1123,6 +1123,9 @@ makemon(register struct permonst *ptr,
|
|||||||
fakemon = cg.zeromonst;
|
fakemon = cg.zeromonst;
|
||||||
cc.x = cc.y = 0;
|
cc.x = cc.y = 0;
|
||||||
|
|
||||||
|
if (iflags.debug_mongen)
|
||||||
|
return (struct monst *) 0;
|
||||||
|
|
||||||
/* if caller wants random location, do it here */
|
/* if caller wants random location, do it here */
|
||||||
if (x == 0 && y == 0) {
|
if (x == 0 && y == 0) {
|
||||||
fakemon.data = ptr; /* set up for goodpos */
|
fakemon.data = ptr; /* set up for goodpos */
|
||||||
|
|||||||
68
src/nhlua.c
68
src/nhlua.c
@@ -19,6 +19,9 @@ static int nhl_dump_fmtstr(lua_State *);
|
|||||||
#endif /* DUMPLOG */
|
#endif /* DUMPLOG */
|
||||||
static int nhl_dnum_name(lua_State *);
|
static int nhl_dnum_name(lua_State *);
|
||||||
static int nhl_stairways(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_test(lua_State *);
|
||||||
static int nhl_getmap(lua_State *);
|
static int nhl_getmap(lua_State *);
|
||||||
static void nhl_add_table_entry_bool(lua_State *, const char *, boolean);
|
static void nhl_add_table_entry_bool(lua_State *, const char *, boolean);
|
||||||
@@ -936,6 +939,68 @@ nhl_test(lua_State *L)
|
|||||||
return 1;
|
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[] = {
|
static const struct luaL_Reg nhl_functions[] = {
|
||||||
{"test", nhl_test},
|
{"test", nhl_test},
|
||||||
|
|
||||||
@@ -967,6 +1032,9 @@ static const struct luaL_Reg nhl_functions[] = {
|
|||||||
#endif /* DUMPLOG */
|
#endif /* DUMPLOG */
|
||||||
{"dnum_name", nhl_dnum_name},
|
{"dnum_name", nhl_dnum_name},
|
||||||
{"stairways", nhl_stairways},
|
{"stairways", nhl_stairways},
|
||||||
|
{"pushkey", nhl_pushkey},
|
||||||
|
{"doturn", nhl_doturn},
|
||||||
|
{"monster_generation", nhl_monster_generation},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
65
test/testmove.lua
Normal file
65
test/testmove.lua
Normal file
@@ -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();
|
||||||
Reference in New Issue
Block a user