Lua tests: generation of each object
Test generation of every object, both via des.object and obj.new. Expose FIRST_OBJECT and LAST_OBJECT numbers to lua. Add lua nh.int_to_objname, a function to convert integer value to object base name and class. Allow creating new nethack lua object by specifying id and class.
This commit is contained in:
23
doc/lua.adoc
23
doc/lua.adoc
@@ -259,6 +259,17 @@ Example:
|
||||
local str = nh.ing_suffix("foo");
|
||||
|
||||
|
||||
=== int_to_objname
|
||||
|
||||
Convert integer value to object name and class.
|
||||
Returns two strings, the object base name and the class character.
|
||||
The returned strings may be empty if an error occurred.
|
||||
|
||||
Example:
|
||||
|
||||
local oname, oclass = nh.int_to_objname(45);
|
||||
|
||||
|
||||
=== int_to_pmname
|
||||
|
||||
Convert integer value to monster type name.
|
||||
@@ -850,7 +861,7 @@ Example:
|
||||
|
||||
=== object
|
||||
|
||||
Create an object. Returns the object as an <<Obj>> class.
|
||||
Create an object and place it somewhere on the map. Returns the object as an <<Obj>> class.
|
||||
The table parameter accepts the following:
|
||||
|
||||
[options="header"]
|
||||
@@ -874,8 +885,8 @@ The table parameter accepts the following:
|
||||
| greased | boolean | Is the object greased?
|
||||
| broken | boolean | Is the object broken?
|
||||
| achievement | boolean | Is there an achievement attached to the object?
|
||||
| x, y | int | Coordinates on the level
|
||||
| coord | table | x,y coordinates in table format
|
||||
| x, y | int | Coordinates on the level; defaults to a random location.
|
||||
| coord | table | x,y coordinates in table format; defaults to a random location.
|
||||
| montype | string | Monster id or class
|
||||
| historic | boolean | Is statue historic?
|
||||
| male | boolean | Is statue male?
|
||||
@@ -1380,11 +1391,13 @@ Handling objects via obj-class.
|
||||
|
||||
=== new
|
||||
|
||||
Create a new object via wishing routine.
|
||||
Create a new object, either via wishing routine, or specifying object name and class.
|
||||
Unlike des.object, does not place the object anywhere.
|
||||
|
||||
Example:
|
||||
|
||||
local o = obj.new("rock");
|
||||
local o = obj.new({ id = "invisibility", class = "!" });
|
||||
|
||||
|
||||
=== isnull
|
||||
@@ -1576,6 +1589,8 @@ These constants are in the `nhc` table.
|
||||
| NUMMONS | Number of different monster types
|
||||
| LOW_PM | First monster type id. See <<_int_to_pmname>>.
|
||||
| HIGH_PM | Last monster type id. See <<_int_to_pmname>>.
|
||||
| FIRST_OBJECT | First object type id. See <<_int_to_objname>>.
|
||||
| LAST_OBJECT | Number of object type ids. See <<_int_to_objname>>.
|
||||
| DLB | 1 or 0, depending if NetHack is compiled with DLB
|
||||
|===
|
||||
|
||||
|
||||
@@ -3033,6 +3033,8 @@ extern int nhl_abs_coord(lua_State *) NONNULLARG1;
|
||||
extern void update_croom(void);
|
||||
extern const char *get_trapname_bytype(int);
|
||||
extern void l_register_des(lua_State *) NONNULLARG1;
|
||||
extern int get_table_objclass(lua_State *) NONNULLARG1;
|
||||
extern int get_table_objtype(lua_State *) NONNULLARG1;
|
||||
#endif /* !CROSSCOMPILE || CROSSCOMPILE_TARGET */
|
||||
|
||||
/* ### spell.c ### */
|
||||
|
||||
19
src/nhlobj.c
19
src/nhlobj.c
@@ -345,12 +345,13 @@ DISABLE_WARNING_UNREACHABLE_CODE
|
||||
|
||||
/* create a new object via wishing routine */
|
||||
/* local o = obj.new("rock"); */
|
||||
/* local o = obj.new({ id = "food ration", class = "%" }); */
|
||||
staticfn int
|
||||
l_obj_new_readobjnam(lua_State *L)
|
||||
{
|
||||
int argc = lua_gettop(L);
|
||||
|
||||
if (argc == 1) {
|
||||
if (argc == 1 && lua_type(L, 1) == LUA_TSTRING) {
|
||||
char buf[BUFSZ];
|
||||
struct obj *otmp;
|
||||
|
||||
@@ -360,6 +361,22 @@ l_obj_new_readobjnam(lua_State *L)
|
||||
otmp = NULL;
|
||||
(void) l_obj_push(L, otmp);
|
||||
return 1;
|
||||
} else if (argc == 1 && lua_type(L, 1) == LUA_TTABLE) {
|
||||
short id = get_table_objtype(L);
|
||||
xint16 class = get_table_objclass(L);
|
||||
struct obj *otmp;
|
||||
|
||||
if (id >= FIRST_OBJECT) {
|
||||
otmp = mksobj(id, TRUE, FALSE);
|
||||
} else {
|
||||
class = def_char_to_objclass(class);
|
||||
if (class >= MAXOCLASSES)
|
||||
class = RANDOM_CLASS;
|
||||
otmp = mkobj(class, FALSE);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
(void) l_obj_push(L, otmp);
|
||||
return 1;
|
||||
} else
|
||||
nhl_error(L, "l_obj_new_readobjname: Wrong args");
|
||||
/*NOTREACHED*/
|
||||
|
||||
29
src/nhlua.c
29
src/nhlua.c
@@ -32,6 +32,7 @@ staticfn int nhl_dump_fmtstr(lua_State *);
|
||||
#endif /* DUMPLOG */
|
||||
staticfn int nhl_dnum_name(lua_State *);
|
||||
staticfn int nhl_int_to_pm_name(lua_State *);
|
||||
staticfn int nhl_int_to_obj_name(lua_State *);
|
||||
staticfn int nhl_stairways(lua_State *);
|
||||
staticfn int nhl_pushkey(lua_State *);
|
||||
staticfn int nhl_doturn(lua_State *);
|
||||
@@ -1185,6 +1186,31 @@ nhl_int_to_pm_name(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* convert integer to object type name and class */
|
||||
/* local oname,oclass = int_to_objname(25); */
|
||||
staticfn int
|
||||
nhl_int_to_obj_name(lua_State *L)
|
||||
{
|
||||
int argc = lua_gettop(L);
|
||||
|
||||
if (argc == 1) {
|
||||
char buf[8];
|
||||
lua_Integer i = luaL_checkinteger(L, 1);
|
||||
|
||||
if (i >= 0 && i < NUM_OBJECTS && OBJ_NAME(objects[i])) {
|
||||
lua_pushstring(L, OBJ_NAME(objects[i]));
|
||||
buf[0] = def_oc_syms[(int)objects[i].oc_class].sym;
|
||||
buf[1] = '\0';
|
||||
lua_pushstring(L, buf);
|
||||
} else {
|
||||
lua_pushstring(L, "");
|
||||
lua_pushstring(L, "");
|
||||
}
|
||||
} else
|
||||
nhl_error(L, "Expected an integer parameter");
|
||||
return 2;
|
||||
}
|
||||
|
||||
DISABLE_WARNING_UNREACHABLE_CODE
|
||||
/* because nhl_error() does not return */
|
||||
|
||||
@@ -1858,6 +1884,7 @@ static const struct luaL_Reg nhl_functions[] = {
|
||||
#endif /* DUMPLOG */
|
||||
{ "dnum_name", nhl_dnum_name },
|
||||
{ "int_to_pmname", nhl_int_to_pm_name },
|
||||
{ "int_to_objname", nhl_int_to_obj_name },
|
||||
{ "variable", nhl_variable },
|
||||
{ "stairways", nhl_stairways },
|
||||
{ "pushkey", nhl_pushkey },
|
||||
@@ -1876,6 +1903,8 @@ static const struct {
|
||||
{ "NUMMONS", NUMMONS },
|
||||
{ "LOW_PM", LOW_PM },
|
||||
{ "HIGH_PM", HIGH_PM },
|
||||
{ "FIRST_OBJECT", FIRST_OBJECT },
|
||||
{ "LAST_OBJECT", NUM_OBJECTS-1 },
|
||||
#ifdef DLB
|
||||
{ "DLB", 1 },
|
||||
#else
|
||||
|
||||
25
src/sp_lev.c
25
src/sp_lev.c
@@ -117,9 +117,7 @@ staticfn int find_montype(lua_State *, const char *, int *);
|
||||
staticfn int get_table_montype(lua_State *, int *);
|
||||
staticfn lua_Integer get_table_int_or_random(lua_State *, const char *, int);
|
||||
staticfn int get_table_buc(lua_State *);
|
||||
staticfn int get_table_objclass(lua_State *);
|
||||
staticfn int find_objtype(lua_State *, const char *);
|
||||
staticfn int get_table_objtype(lua_State *);
|
||||
staticfn int find_objtype(lua_State *, const char *, char);
|
||||
staticfn const char *get_mkroom_name(int) NONNULL;
|
||||
staticfn int get_table_roomtype_opt(lua_State *, const char *, int);
|
||||
staticfn int get_table_traptype_opt(lua_State *, const char *, int);
|
||||
@@ -3443,7 +3441,7 @@ get_table_buc(lua_State *L)
|
||||
return curse_state;
|
||||
}
|
||||
|
||||
staticfn int
|
||||
int
|
||||
get_table_objclass(lua_State *L)
|
||||
{
|
||||
char *s = get_table_str_opt(L, "class", NULL);
|
||||
@@ -3455,13 +3453,14 @@ get_table_objclass(lua_State *L)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* find object otyp by text s (optionally considering oclass) */
|
||||
staticfn int
|
||||
find_objtype(lua_State *L, const char *s)
|
||||
find_objtype(lua_State *L, const char *s, char oclass)
|
||||
{
|
||||
if (s && *s) {
|
||||
int i;
|
||||
const char *objname;
|
||||
char class = 0;
|
||||
char class = def_char_to_objclass(oclass);
|
||||
|
||||
/* In objects.h, some item classes are defined without prefixes
|
||||
(such as "scroll of ") in their names, making some names (such
|
||||
@@ -3479,6 +3478,9 @@ find_objtype(lua_State *L, const char *s)
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
if (class == MAXOCLASSES)
|
||||
class = 0;
|
||||
|
||||
if (strstri(s, " of ")) {
|
||||
for (i = 0; class_prefixes[i].prefix; i++) {
|
||||
const char *p = class_prefixes[i].prefix;
|
||||
@@ -3523,11 +3525,12 @@ find_objtype(lua_State *L, const char *s)
|
||||
return STRANGE_OBJECT;
|
||||
}
|
||||
|
||||
staticfn int
|
||||
int
|
||||
get_table_objtype(lua_State *L)
|
||||
{
|
||||
char *s = get_table_str_opt(L, "id", NULL);
|
||||
int ret = find_objtype(L, s);
|
||||
char oclass = get_table_objclass(L);
|
||||
int ret = find_objtype(L, s, oclass);
|
||||
|
||||
Free(s);
|
||||
return ret;
|
||||
@@ -3586,7 +3589,7 @@ lspo_object(lua_State *L)
|
||||
tmpobj.id = STRANGE_OBJECT;
|
||||
} else {
|
||||
tmpobj.class = -1;
|
||||
tmpobj.id = find_objtype(L, paramstr);
|
||||
tmpobj.id = find_objtype(L, paramstr, -1);
|
||||
}
|
||||
} else if (argc == 2 && lua_type(L, 1) == LUA_TSTRING
|
||||
&& lua_type(L, 2) == LUA_TTABLE) {
|
||||
@@ -3599,7 +3602,7 @@ lspo_object(lua_State *L)
|
||||
tmpobj.id = STRANGE_OBJECT;
|
||||
} else {
|
||||
tmpobj.class = -1;
|
||||
tmpobj.id = find_objtype(L, paramstr);
|
||||
tmpobj.id = find_objtype(L, paramstr, -1);
|
||||
}
|
||||
} else if (argc == 3 && lua_type(L, 2) == LUA_TNUMBER
|
||||
&& lua_type(L, 3) == LUA_TNUMBER) {
|
||||
@@ -3613,7 +3616,7 @@ lspo_object(lua_State *L)
|
||||
tmpobj.id = STRANGE_OBJECT;
|
||||
} else {
|
||||
tmpobj.class = -1;
|
||||
tmpobj.id = find_objtype(L, paramstr);
|
||||
tmpobj.id = find_objtype(L, paramstr, -1);
|
||||
}
|
||||
} else {
|
||||
lcheck_param_table(L);
|
||||
|
||||
@@ -180,6 +180,27 @@ function test_object()
|
||||
des.object({ name = "Random object" });
|
||||
des.object({ class = "*", name = "Random stone" });
|
||||
des.object({ id ="broadsword", name = "Dragonbane" })
|
||||
|
||||
for i = nhc.FIRST_OBJECT, nhc.LAST_OBJECT do
|
||||
local oid, oclass = nh.int_to_objname(i);
|
||||
if (oid ~= "") then
|
||||
local o = des.object({ id = oid, class = oclass });
|
||||
local o_t = o:totable();
|
||||
|
||||
-- crysknife reverts to worm tooth on the floor
|
||||
if not(oid == "crysknife" and o_t.otyp_name == "worm tooth") then
|
||||
if (o_t.otyp_name ~= oid) then
|
||||
error("object name \"" .. o_t.otyp_name .. "\" created, wanted \"" .. oid .. "\"");
|
||||
end
|
||||
if (o_t.oclass ~= oclass) then
|
||||
local str = string.format("object class \"%s\" created, wanted \"%s\" (%s)", o_t.oclass, oclass, oid);
|
||||
error(str);
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
des.reset_level();
|
||||
des.level_init();
|
||||
end
|
||||
|
||||
@@ -82,3 +82,22 @@ box:addcontent(o5);
|
||||
|
||||
local o6 = obj.new("statue");
|
||||
o6:addcontent(obj.new("spellbook"));
|
||||
|
||||
|
||||
-- generate one of each object, check the name and class matches
|
||||
for i = nhc.FIRST_OBJECT, nhc.LAST_OBJECT do
|
||||
local oid, oclass = nh.int_to_objname(i);
|
||||
if (oid ~= "") then
|
||||
local oi = obj.new({ id = oid, class = oclass });
|
||||
local oi_t = oi:totable();
|
||||
|
||||
if (oi_t.otyp_name ~= oid) then
|
||||
error("object name \"" .. oi_t.otyp_name .. "\" created, wanted \"" .. oid .. "\"");
|
||||
end
|
||||
if (oi_t.oclass ~= oclass) then
|
||||
local str = string.format("object class \"%s\" created, wanted \"%s\" (%s)", oi_t.oclass, oclass, oid);
|
||||
error(str);
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user