]> granicus.if.org Git - nethack/commitdiff
Lua: coordinate tweaking
authorPasi Kallinen <paxed@alt.org>
Tue, 22 Mar 2022 07:16:15 +0000 (09:16 +0200)
committerPasi Kallinen <paxed@alt.org>
Tue, 22 Mar 2022 07:16:19 +0000 (09:16 +0200)
Make selection rndcoord return a table with x and y keys.
Allow (most) coordinate parameters accept such a table.
Fix selection and des lua tests broken by the above changes and
an earlier change, because selections tried to set terrain
at column 0, and it now causes a complaint.

19 files changed:
dat/Bar-strt.lua
dat/Mon-strt.lua
dat/Pri-strt.lua
dat/Rog-strt.lua
dat/astral.lua
dat/castle.lua
dat/juiblex.lua
dat/medusa-3.lua
dat/medusa-4.lua
dat/minetn-1.lua
dat/soko1-1.lua
dat/soko1-2.lua
doc/lua.adoc
include/extern.h
src/nhlsel.c
src/nhlua.c
src/sp_lev.c
test/test_des.lua
test/test_sel.lua

index 57297b73a1b68271c69670ce30c2c00f8b17b0c6..37d7face1eec035ed499a6f815eddc9b2dffbb43 100644 (file)
@@ -95,6 +95,5 @@ des.monster("giant eel", 39, 15)
 -- Monsters on siege duty.
 local ogrelocs = selection.floodfill(37,7) & selection.area(40,03, 45,20)
 for i = 0, 11 do
-   local x,y = ogrelocs:rndcoord(1);
-   des.monster({ id = "ogre", coord={x,y}, peaceful=0 })
+   des.monster({ id = "ogre", coord = ogrelocs:rndcoord(1), peaceful = 0 })
 end
index 0ae685a698c57fa5f511e30e86fc3fe9fddf57c8..0bbdfcf00d164db2b7be5c9cc03d47c14b229ea7 100644 (file)
@@ -88,8 +88,7 @@ des.monster("abbot", 33, 12)
 des.non_diggable(selection.area(18,03,55,16))
 -- Random traps
 for i = 1, 2 do
-   local x,y = spacelocs:rndcoord(1);
-   des.trap("dart",x,y)
+   des.trap("dart", spacelocs:rndcoord(1))
 end
 des.trap()
 des.trap()
@@ -97,10 +96,8 @@ des.trap()
 des.trap()
 -- Monsters on siege duty.
 for i = 1, 8 do
-   local x,y = spacelocs:rndcoord(1);
-   des.monster("earth elemental", x, y)
+   des.monster("earth elemental", spacelocs:rndcoord(1))
 end
 for i = 1, 4 do
-   local x,y = spacelocs:rndcoord(1);
-   des.monster("xorn", x, y)
+   des.monster("xorn", spacelocs:rndcoord(1))
 end
index fb66e64925b236480ff8741a7475eee81f166eb6..696941cc31053178a605883b17760f9153db4db0 100644 (file)
@@ -90,8 +90,7 @@ des.monster("acolyte", 33, 12)
 des.non_diggable(selection.area(18,03,55,16))
 -- Random traps
 for i = 1, 2 do
-   local x,y = spacelocs:rndcoord(1);
-   des.trap("dart",x,y)
+   des.trap("dart", spacelocs:rndcoord(1))
 end
 des.trap()
 des.trap()
@@ -99,6 +98,5 @@ des.trap()
 des.trap()
 -- Monsters on siege duty.
 for i = 1, 12 do
-   local x,y = spacelocs:rndcoord(1);
-   des.monster("human zombie", x, y);
+   des.monster("human zombie", spacelocs:rndcoord(1));
 end
index b2fd32a792b3ec5ae5937e8ca78516ec8ba81864..e0431b47cf91406ea93eb1369632e2df808ffd15 100644 (file)
@@ -158,9 +158,9 @@ des.monster({ id = "leprechaun", x=25, y=19, peaceful=0 })
 des.monster({ id = "water nymph", x=25, y=18, peaceful=0 })
 -- Wandering the streets.
 for i=1,4 + math.random(1 - 1,1*3)  do
-   des.monster({ id = "water nymph", coord = {streets:rndcoord(1)}, peaceful=0 })
-   des.monster({ id = "leprechaun", coord = {streets:rndcoord(1)}, peaceful=0 })
+   des.monster({ id = "water nymph", coord = streets:rndcoord(1), peaceful=0 })
+   des.monster({ id = "leprechaun", coord = streets:rndcoord(1), peaceful=0 })
 end
 for i=1,7 + math.random(1 - 1,1*3)  do
-   des.monster({ id = "chameleon", coord = {streets:rndcoord(1)}, peaceful=0 })
+   des.monster({ id = "chameleon", coord = streets:rndcoord(1), peaceful=0 })
 end
index cbf2bc0ae5d93c742340ac8e35930dbb49d9120d..2624a578dfe5fbeb079516da8cef2f98313286ab 100644 (file)
@@ -59,9 +59,9 @@ for i=1,2 do
      end
      -- extra monsters; was [6 + 3d4] when both wings were opened up at once
      for i=1,3 + math.random(2 - 1,2*3) do
-        des.monster({ id="Angel", coord = { hall:rndcoord(1) }, align="noalign", peaceful=0 })
+        des.monster({ id="Angel", coord = hall:rndcoord(1), align="noalign", peaceful=0 })
         if percent(50) then
-           des.monster({ coord = { hall:rndcoord(1) }, peaceful=0 })
+           des.monster({ coord = hall:rndcoord(1), peaceful=0 })
         end
      end
    end
@@ -110,7 +110,7 @@ des.monster({ id = "aligned cleric",x=19,y=09,align="noalign", peaceful=0 })
 des.monster({ id = "aligned cleric",x=19,y=10,align="noalign", peaceful=0 })
 des.monster({ id = "Angel",x=20,y=09,align="noalign", peaceful=0 })
 des.monster({ id = "Angel",x=20,y=10,align="noalign", peaceful=0 })
-des.monster({ id = "Pestilence", coord = { place:rndcoord(1) }, peaceful=0 })
+des.monster({ id = "Pestilence", coord = place:rndcoord(1), peaceful=0 })
 -- South-central round room
 des.monster({ id = "aligned cleric",x=36,y=12,align="noalign", peaceful=0 })
 des.monster({ id = "aligned cleric",x=37,y=12,align="noalign", peaceful=0 })
@@ -118,7 +118,7 @@ des.monster({ id = "aligned cleric",x=38,y=12,align="noalign", peaceful=0 })
 des.monster({ id = "aligned cleric",x=36,y=13,align="noalign", peaceful=0 })
 des.monster({ id = "Angel",x=38,y=13,align="noalign", peaceful=0 })
 des.monster({ id = "Angel",x=37,y=13,align="noalign", peaceful=0 })
-des.monster({ id = "Death", coord = { place:rndcoord(1) }, peaceful=0 })
+des.monster({ id = "Death", coord = place:rndcoord(1), peaceful=0 })
 -- East round room
 des.monster({ id = "aligned cleric",x=56,y=09,align="noalign", peaceful=0 })
 des.monster({ id = "aligned cleric",x=55,y=08,align="noalign", peaceful=0 })
@@ -126,7 +126,7 @@ des.monster({ id = "aligned cleric",x=55,y=09,align="noalign", peaceful=0 })
 des.monster({ id = "aligned cleric",x=55,y=10,align="noalign", peaceful=0 })
 des.monster({ id = "Angel",x=54,y=09,align="noalign", peaceful=0 })
 des.monster({ id = "Angel",x=54,y=10,align="noalign", peaceful=0 })
-des.monster({ id = "Famine", coord = { place:rndcoord(1) }, peaceful=0 })
+des.monster({ id = "Famine", coord = place:rndcoord(1), peaceful=0 })
 --
 -- The aligned horde
 --
index c2f05f02fb48e77993ef9a615bebdcd3651de20c..585aa5e6d084b79a4e053dad645ea59b3c39a240 100644 (file)
@@ -140,8 +140,7 @@ des.object(object[4],53,11)
 des.object(object[4],54,11)
 des.object(object[4],55,11)
 -- THE WAND OF WISHING in 1 of the 4 towers
-local px, py = place:rndcoord(1);
-des.object({ id = "chest", trapped = 0, locked = 1, x = px, y = py,
+des.object({ id = "chest", trapped = 0, locked = 1, coord = place:rndcoord(1),
              contents = function()
                 des.object("wishing");
              end
index 2eff9ec7902f2d690e729469c41efdd4221ed191..4fa120444c578f00885dcc244e9bbdc4713965d7 100644 (file)
@@ -63,9 +63,9 @@ des.levregion({ region = {01,00,11,20}, region_islev=1, exclude={0,0,50,17}, typ
 des.teleport_region({ region = {01,00,11,20}, region_islev=1, exclude={0,0,50,17},dir="up" })
 des.teleport_region({ region = {69,00,79,20}, region_islev=1, exclude={0,0,50,17},dir="down" })
 des.feature("fountain", place:rndcoord(1))
-des.monster({ id = "giant mimic", coord = { place:rndcoord(1) }, appear_as = "ter:fountain" })
-des.monster({ id = "giant mimic", coord = { place:rndcoord(1) }, appear_as = "ter:fountain" })
-des.monster({ id = "giant mimic", coord = { place:rndcoord(1) }, appear_as = "ter:fountain" })
+des.monster({ id = "giant mimic", coord = place:rndcoord(1), appear_as = "ter:fountain" })
+des.monster({ id = "giant mimic", coord = place:rndcoord(1), appear_as = "ter:fountain" })
+des.monster({ id = "giant mimic", coord = place:rndcoord(1), appear_as = "ter:fountain" })
 -- The demon of the swamp
 des.monster("Juiblex",25,08)
 -- And a couple demons
index 65da48b7698cc2f183ac14fe920b8bb8aaf96fdd..143c1f86b0ab030b248c3ccf4563a3815745b0fa 100644 (file)
@@ -53,18 +53,16 @@ des.non_diggable(selection.area(44,13,48,17))
 -- restricting the placement when teleporting from levels below this.
 des.teleport_region({ region = {33,02,38,07}, dir="down" })
 des.levregion({ region = {32,01,39,07}, type="stair-up" });
-local mx, my = place:rndcoord(1);
-des.stair("down", mx, my)
+
+des.stair("down", place:rndcoord(1))
 des.door("locked",08,08)
 des.door("locked",64,05)
 des.door("random",50,13)
 des.door("locked",48,15)
 --
-local px, py = place:rndcoord(1);
-des.feature("fountain", px,py);
+des.feature("fountain", place:rndcoord(1));
 --
-local px, py = place:rndcoord(1);
-des.object({ id="statue",x=px, y=py, buc="uncursed",
+des.object({ id="statue", coord=place:rndcoord(1), buc = "uncursed",
                       montype="knight", historic=1, male=1,name="Perseus",
                       contents = function()
                          if percent(75) then
index 75e910bf5dcd8fb89f0ad08b8b7d88f4fa49aaf6..d716fe952c2abaad7b9d1a08b7455fcd2c8111ca 100644 (file)
@@ -49,8 +49,8 @@ des.teleport_region({ region = {64,01,74,17}, dir="down" });
 des.teleport_region({ region = {02,02,18,13}, dir="up" });
 --
 des.levregion({ region = {67,01,74,20}, type="stair-up" });
-local mx, my = place:rndcoord(1);
-des.stair("down", mx, my)
+
+des.stair("down", place:rndcoord(1))
 --
 des.door("locked",04,06)
 des.door("locked",04,10)
@@ -66,8 +66,7 @@ des.non_diggable(selection.area(01,01,22,14));
 --
 des.object("crystal ball", 07,08)
 --
-local px, py = place:rndcoord(1);
-des.object({ id="statue",x=px, y=py, buc="uncursed",
+des.object({ id="statue",coord=place:rndcoord(1), buc="uncursed",
                       montype="knight", historic=1, male=1,name="Perseus",
                       contents = function()
                          if percent(75) then
index 187b09b46a50fb9893ff3749e9d8fa1a148cf8be..a1a9e43ed80849359218724e9fc2476e60ce49d0 100644 (file)
@@ -120,18 +120,18 @@ local near_temple = selection.area(17,8, 23,14) & inside
 
 for i=1,5 + math.random(1 - 1,1*10) do
    if percent(50) then
-      des.monster({ id = "orc-captain", coord = { inside:rndcoord(1) }, peaceful=0 });
+      des.monster({ id = "orc-captain", coord = inside:rndcoord(1), peaceful=0 });
    else
       if percent(80) then
-         des.monster({ id = "Uruk-hai", coord = { inside:rndcoord(1) }, peaceful=0 })
+         des.monster({ id = "Uruk-hai", coord = inside:rndcoord(1), peaceful=0 })
       else
-         des.monster({ id = "Mordor orc", coord = { inside:rndcoord(1) }, peaceful=0 })
+         des.monster({ id = "Mordor orc", coord = inside:rndcoord(1), peaceful=0 })
       end
    end
 end
 -- shamans can be hanging out in/near the temple
 for i=1,math.random(2 - 1,2*3) do
-   des.monster({ id = "orc shaman", coord = { near_temple:rndcoord(0) }, peaceful=0 });
+   des.monster({ id = "orc shaman", coord = near_temple:rndcoord(0), peaceful=0 });
 end
 -- these are not such a big deal
 -- to run into outside the bars
index 1d6b7c09b0bd4fdff134e09d851b3c3926a8452a..bedcf13ca05ad15dea2c6bae771b0b5fbd6c837d 100644 (file)
@@ -96,14 +96,14 @@ des.door("closed", 17, 15);
 
 des.region({ region={18,10, 22,16}, lit = 1, type = "zoo", filled = 1, irregular = 1 });
 
-px, py = selection.rndcoord(place);
+local pt = selection.rndcoord(place);
 if percent(75) then
-   des.object({ id="bag of holding", x=px, y=py,
+   des.object({ id="bag of holding", coord=pt,
                buc="not-cursed", achievement=1 });
 else
-   des.object({ id="amulet of reflection", x=px, y=py,
+   des.object({ id="amulet of reflection", coord=pt,
                buc="not-cursed", achievement=1 });
 end
-des.engraving({ x = px, y = py, type = "burn", text = "Elbereth" });
-des.object({ id = "scare monster", x = px, y = py, buc = "cursed" });
+des.engraving({ coord = pt, type = "burn", text = "Elbereth" });
+des.object({ id = "scare monster", coord = pt, buc = "cursed" });
 
index 3b54a231e9a38a6565214c2ae146825991ccaad0..8a82b02e9afd65d86be9039df1f730fd85753ca6 100644 (file)
@@ -98,13 +98,13 @@ des.door("closed",17,12)
 des.door("closed",17,14)
 des.region({ region={18,09, 22,15}, lit = 1, type = "zoo", filled = 1, irregular = 1 });
 
-px, py = selection.rndcoord(place);
+local pt = selection.rndcoord(place);
 if percent(25) then
-   des.object({ id="bag of holding", x=px, y=py,
+   des.object({ id="bag of holding", coord=pt,
                buc="not-cursed", achievement=1 });
 else
-   des.object({ id="amulet of reflection", x=px, y=py,
+   des.object({ id="amulet of reflection", coord=pt,
                buc="not-cursed", achievement=1 });
 end
-des.engraving({ x = px, y = py, type = "burn", text = "Elbereth" });
-des.object({ id = "scare monster", x = px, y = py, buc = "cursed" });
+des.engraving({ coord = pt, type = "burn", text = "Elbereth" });
+des.object({ id = "scare monster", coord = pt, buc = "cursed" });
index 584895bd6e87b853c3295259194c1ed6c5de5450..322f55cb5e30ac1150163c76bea721e648c47c06 100644 (file)
@@ -8,13 +8,16 @@ Functions exposed from the NetHack core. They are all in the `nh` table.
 
 === abscoord
 
-Convert a relative coordinate to absolute.
+Convert a room-relative coordinate to map-absolute.
+Can accept one table with x and y keys (and in that case, returns similar),
+or two integer values (and returns two integer values)
 des-routines tend to use relative coordinates, nh and obj use absolute.
 (This mess is still very much in need of improvement.)
 
 Example:
 
  local ax, ay = nh.abscoord(x, y);
+ local coord = nh.abscoord({ x = 10, y = 15 });
 
 
 === an
@@ -135,7 +138,8 @@ Example:
  local x = 20;
  local y = 10;
  local loc = nh.getmap(x,y);
- nh.pline("Map location at (" .. x .. "," .. y .. ) is " .. (loc.lit ? "lit" : "unlit") );
+ nh.pline("Map location at (" .. x .. "," .. y .. ) is " .. (loc.lit and "lit" or "unlit") );
+ local loc2 = nh.getmap({ x = 18, y = 16 });
 
 
 === get_config
@@ -166,7 +170,8 @@ Returns a table with the following elements:
 
 Example:
 
- local t = nh.gettrap(x, y);
+ local t1 = nh.gettrap(x, y);
+ local t2 = nh.gettrap({ x = 10, y = 15 });
 
 
 === has_timer_at
@@ -185,6 +190,7 @@ Delete a trap at x,y
 Example:
 
  nh.deltrap(x, y);
+ nh.deltrap({ x = 10, y = 10 });
 
 
 === impossible
@@ -281,6 +287,7 @@ When does timer at location at x,y trigger?
 Example:
 
  local melttime = nh.peek_timer_at(x,y, "melt-ice");
+ local melttime = nh.peek_timer_at({x=5,y=6}, "melt-ice");
 
 
 === pline
@@ -353,6 +360,7 @@ Start a timer at location x,y, with trigger time of `when` - relative to current
 Example:
 
  nh.start_timer_at(x,y, "melt-ice", when);
+ nh.start_timer_at({x=7,y=8}, "melt-ice", when);
 
 
 === stop_timer_at
@@ -362,6 +370,7 @@ Stop a timer at location x,y.
 Example:
 
  nh.stop_timer_at(x,y, "melt-ice");
+ nh.stop_timer_at({x=5,y=6}, "melt-ice");
 
 
 === verbalize
@@ -1033,13 +1042,14 @@ Example:
 
 === rndcoord
 
-Choose one of the selected locations, and return the x,y coordinates.
+Choose one of the selected locations, and return a table with x and y keys.
 If the optional second argument is 1, removes the location from the selection.
+If there are no coordinates in the selection, returns -1, -1.
 
 Example:
 
- local x,y = selection.rndcoord(sel);
- local x,y = selection.rndcoord(sel, 1);
+ local coord = selection.rndcoord(sel);
+ local coord = selection.rndcoord(sel, 1);
 
 === set
 
index 6ec6fc16aebdae5c762bee0b129399a59d1827b5..fdd2abe6034165bb39ef71208eb92d3cb77a36eb 100644 (file)
@@ -1767,6 +1767,7 @@ extern void lcheck_param_table(lua_State *);
 extern schar get_table_mapchr(lua_State *, const char *);
 extern schar get_table_mapchr_opt(lua_State *, const char *, schar);
 extern short nhl_get_timertype(lua_State *, int);
+extern boolean nhl_get_xy_params(lua_State *, int *, int *);
 extern void nhl_add_table_entry_int(lua_State *, const char *, lua_Integer);
 extern void nhl_add_table_entry_char(lua_State *, const char *, char);
 extern void nhl_add_table_entry_str(lua_State *, const char *, const char *);
@@ -2537,6 +2538,7 @@ extern void selection_do_gradient(struct selectionvar *, long, long, long,
                                   long, long, long, long, long);
 extern int lspo_reset_level(lua_State *);
 extern int lspo_finalize_level(lua_State *);
+extern boolean get_coord(lua_State *, int, lua_Integer *, lua_Integer *);
 extern int nhl_abs_coord(lua_State *);
 extern void update_croom(void);
 extern const char *get_trapname_bytype(int);
index 04d63c739258368a519b44ff7499aff2e936b769..619156917cce72bf4dd3a2d5cbd02d62181a4c33 100644 (file)
@@ -320,8 +320,8 @@ l_selection_filter_percent(lua_State *L)
     return 1;
 }
 
-/* local x,y = selection.rndcoord(sel); */
-/* local x,y = selection.rndcoord(sel, 1); */
+/* local pt = selection.rndcoord(sel); */
+/* local pt = selection.rndcoord(sel, 1); */
 static int
 l_selection_rndcoord(lua_State *L)
 {
@@ -338,9 +338,10 @@ l_selection_rndcoord(lua_State *L)
         y -= g.ystart;
     }
     lua_settop(L, 0);
-    lua_pushnumber(L, x);
-    lua_pushnumber(L, y);
-    return 2;
+    lua_newtable(L);
+    nhl_add_table_entry_int(L, "x", x);
+    nhl_add_table_entry_int(L, "y", y);
+    return 1;
 }
 
 /* internal function to get a selection and 4 integer values from lua stack.
@@ -585,7 +586,7 @@ l_selection_match(lua_State *L)
     }
 
     for (y = 0; y <= sel->hei; y++)
-        for (x = 0; x < sel->wid; x++)
+        for (x = 1; x < sel->wid; x++)
             selection_setpoint(x, y, sel, mapfrag_match(mf, x,y) ? 1 : 0);
 
     mapfrag_free(&mf);
@@ -801,7 +802,7 @@ l_selection_iterate(lua_State *L)
     if (argc == 2 && lua_type(L, 2) == LUA_TFUNCTION) {
         sel = l_selection_check(L, 1);
         for (y = 0; y < sel->hei; y++)
-            for (x = 0; x < sel->wid; x++)
+            for (x = 1; x < sel->wid; x++)
                 if (selection_getpoint(x, y, sel)) {
                     lua_pushvalue(L, 2);
                     lua_pushinteger(L, x - g.xstart);
index 1faef20bf7b4c01dce3ca6aa0c0d3f061c4ec3cd..1853b067c41145d398427f4146983cd7d5d675b7 100644 (file)
@@ -329,17 +329,19 @@ splev_typ2chr(schar typ)
     return 'x';
 }
 
-/* local t = gettrap(x,y); */
+/* local t = nh.gettrap(x,y); */
+/* local t = nh.gettrap({ x = 10, y = 10 }); */
 static int
 nhl_gettrap(lua_State *L)
 {
-    int argc = lua_gettop(L);
+    int x, y;
 
-    if (argc == 2) {
-        int x = (int) lua_tointeger(L, 1);
-        int y = (int) lua_tointeger(L, 2);
+    if (!nhl_get_xy_params(L, &x, &y)) {
+        nhl_error(L, "Incorrect arguments");
+        return 0;
+    }
 
-        if (x >= 0 && x < COLNO && y >= 0 && y < ROWNO) {
+    if (isok(x, y)) {
             struct trap *ttmp = t_at(x,y);
 
             if (ttmp) {
@@ -372,44 +374,68 @@ nhl_gettrap(lua_State *L)
                 nhl_error(L, "No trap at location");
         } else
             nhl_error(L, "Coordinates out of range");
-    } else
-        nhl_error(L, "Wrong args");
     return 0;
 }
 
-/* deltrap(x,y); */
+/* nh.deltrap(x,y); nh.deltrap({ x = 10, y = 15 }); */
 static int
 nhl_deltrap(lua_State *L)
 {
-    int argc = lua_gettop(L);
+    int x, y;
 
-    if (argc == 2) {
-        int x = (int) lua_tointeger(L, 1);
-        int y = (int) lua_tointeger(L, 2);
+    if (!nhl_get_xy_params(L, &x, &y)) {
+        nhl_error(L, "Incorrect arguments");
+        return 0;
+    }
 
-        if (x >= 0 && x < COLNO && y >= 0 && y < ROWNO) {
-            struct trap *ttmp = t_at(x,y);
+    if (isok(x, y)) {
+        struct trap *ttmp = t_at(x,y);
 
-            if (ttmp)
-                deltrap(ttmp);
-        }
+        if (ttmp)
+            deltrap(ttmp);
     }
     return 0;
 }
 
+/* get parameters (XX,YY) or ({ x = XX, y = YY }) or ({ XX, YY }),
+   and set the x and y values.
+   return TRUE if there are such params in the stack.
+ */
+boolean
+nhl_get_xy_params(lua_State *L, int *x, int *y)
+{
+    int argc = lua_gettop(L);
+    boolean ret = FALSE;
+
+    if (argc == 2) {
+        *x = (int) lua_tointeger(L, 1);
+        *y = (int) lua_tointeger(L, 2);
+        ret = TRUE;
+    } else if (argc == 1 && lua_type(L, 1) == LUA_TTABLE) {
+        lua_Integer ax, ay;
+
+        ret = get_coord(L, 1, &ax, &ay);
+        *x = (int) ax;
+        *y = (int) ay;
+    }
+    return ret;
+}
+
 DISABLE_WARNING_UNREACHABLE_CODE
 
-/* local loc = getmap(x,y) */
+/* local loc = nh.getmap(x,y); */
+/* local loc = nh.getmap({ x = 10, y = 35 }); */
 static int
 nhl_getmap(lua_State *L)
 {
-    int argc = lua_gettop(L);
+    int x, y;
 
-    if (argc == 2) {
-        int x = (int) lua_tointeger(L, 1);
-        int y = (int) lua_tointeger(L, 2);
+    if (!nhl_get_xy_params(L, &x, &y)) {
+        nhl_error(L, "Incorrect arguments");
+        return 0;
+    }
 
-        if (x >= 0 && x < COLNO && y >= 0 && y < ROWNO) {
+    if (isok(x, y)) {
             char buf[BUFSZ];
             lua_newtable(L);
 
@@ -478,16 +504,11 @@ nhl_getmap(lua_State *L)
             lua_settable(L, -3);
 
             return 1;
-        } else {
-            /* TODO: return zerorm instead? */
-            nhl_error(L, "Coordinates out of range");
-            return 0;
-        }
     } else {
-        nhl_error(L, "Incorrect arguments");
+        /* TODO: return zerorm instead? */
+        nhl_error(L, "Coordinates out of range");
         return 0;
     }
-    return 1;
 }
 
 RESTORE_WARNING_CONDEXPR_IS_CONSTANT
@@ -1067,62 +1088,68 @@ nhl_debug_flags(lua_State *L)
 
 /* does location at x,y have timer? */
 /* local has_melttimer = nh.has_timer_at(x,y, "melt-ice"); */
+/* local has_melttimer = nh.has_timer_at({x=4,y=7}, "melt-ice"); */
 static int
 nhl_timer_has_at(lua_State *L)
 {
-    int argc = lua_gettop(L);
     boolean ret = FALSE;
+    short timertype = nhl_get_timertype(L, -1);
+    int x, y;
+    long when;
 
-    if (argc == 3) {
-        xchar x = (xchar) lua_tointeger(L, 1);
-        xchar y = (xchar) lua_tointeger(L, 2);
-        short timertype = nhl_get_timertype(L, 3);
-        long when = spot_time_expires(x, y, timertype);
+    lua_pop(L, 1); /* remove timertype */
+    if (!nhl_get_xy_params(L, &x, &y)) {
+        nhl_error(L, "nhl_timer_has_at: Wrong args");
+        return 0;
+    }
 
+    if (isok(x, y)) {
+        when = spot_time_expires(x, y, timertype);
         ret = (when > 0L);
-    } else
-        nhl_error(L, "nhl_timer_has_at: Wrong args");
+    }
     lua_pushboolean(L, ret);
     return 1;
 }
 
 /* when does location at x,y timer trigger? */
 /* local melttime = nh.peek_timer_at(x,y, "melt-ice"); */
+/* local melttime = nh.peek_timer_at({x=5,y=6}, "melt-ice"); */
 static int
 nhl_timer_peek_at(lua_State *L)
 {
-    int argc = lua_gettop(L);
     long when = 0L;
+    short timertype = nhl_get_timertype(L, -1);
+    int x, y;
 
-    if (argc == 3) {
-        xchar x = (xchar) lua_tointeger(L, 1);
-        xchar y = (xchar) lua_tointeger(L, 2);
-        short timertype = nhl_get_timertype(L, 3);
-
-        if (timer_is_pos(timertype))
-            when = spot_time_expires(x, y, timertype);
-    } else
+    lua_pop(L, 1); /* remove timertype */
+    if (!nhl_get_xy_params(L, &x, &y)) {
         nhl_error(L, "nhl_timer_peek_at: Wrong args");
+        return 0;
+    }
+
+    if (timer_is_pos(timertype) && isok(x, y))
+        when = spot_time_expires(x, y, timertype);
     lua_pushinteger(L, when);
     return 1;
 }
 
 /* stop timer at location x,y */
 /* nh.stop_timer_at(x,y, "melt-ice"); */
+/* nh.stop_timer_at({x=6,y=8}, "melt-ice"); */
 static int
 nhl_timer_stop_at(lua_State *L)
 {
-    int argc = lua_gettop(L);
-
-    if (argc == 3) {
-        xchar x = (xchar) lua_tointeger(L, 1);
-        xchar y = (xchar) lua_tointeger(L, 2);
-        short timertype = nhl_get_timertype(L, 3);
+    short timertype = nhl_get_timertype(L, -1);
+    int x, y;
 
-        if (timer_is_pos(timertype))
-            spot_stop_timers(x, y, timertype);
-    } else
+    lua_pop(L, 1); /* remove timertype */
+    if (!nhl_get_xy_params(L, &x, &y)) {
         nhl_error(L, "nhl_timer_stop_at: Wrong args");
+        return 0;
+    }
+
+    if (timer_is_pos(timertype) && isok(x, y))
+        spot_stop_timers(x, y, timertype);
     return 0;
 }
 
@@ -1131,23 +1158,23 @@ nhl_timer_stop_at(lua_State *L)
 static int
 nhl_timer_start_at(lua_State *L)
 {
-    int argc = lua_gettop(L);
+    short timertype = nhl_get_timertype(L, -2);
+    long when = lua_tointeger(L, -1);
+    int x, y;
 
-    if (argc == 4) {
-        xchar x = (xchar) lua_tointeger(L, 1);
-        xchar y = (xchar) lua_tointeger(L, 2);
-        short timertype = nhl_get_timertype(L, 3);
-        long when = lua_tointeger(L, 4);
+    lua_pop(L, 2); /* remove when and timertype */
+    if (!nhl_get_xy_params(L, &x, &y)) {
+        nhl_error(L, "nhl_timer_start_at: Wrong args");
+        return 0;
+    }
 
-        if (timer_is_pos(timertype)) {
-            long where = ((long) x << 16) | (long) y;
+    if (timer_is_pos(timertype) && isok(x, y)) {
+        long where = ((long) x << 16) | (long) y;
 
-            spot_stop_timers(x, y, timertype);
-            (void) start_timer((long) when, TIMER_LEVEL, MELT_ICE_AWAY,
-                               long_to_any(where));
-        }
-    } else
-        nhl_error(L, "nhl_timer_stop_at: Wrong args");
+        spot_stop_timers(x, y, timertype);
+        (void) start_timer((long) when, TIMER_LEVEL, MELT_ICE_AWAY,
+                           long_to_any(where));
+    }
     return 0;
 }
 
index 2c2641a0b136b060476b1f437c7bbc3f25b131ea..e1193e04524b335052b90f906b00b8c0c53c68a5 100644 (file)
@@ -93,7 +93,6 @@ static void selection_iterate(struct selectionvar *, select_iter_func,
 static void sel_set_ter(int, int, genericptr_t);
 static void sel_set_door(int, int, genericptr_t);
 static void sel_set_feature(int, int, genericptr_t);
-static int get_coord(lua_State *, int, lua_Integer *, lua_Integer *);
 static void levregion_add(lev_region *);
 static void get_table_xy_or_coord(lua_State *, lua_Integer *, lua_Integer *);
 static int get_table_region(lua_State *, const char *, lua_Integer *, lua_Integer *, lua_Integer *,
@@ -347,8 +346,8 @@ lvlfill_swamp(schar fg, schar bg, schar lit)
     lvlfill_solid(bg, lit);
 
     /* "relaxed blockwise maze" algorithm, Jamis Buck */
-    for (x = 2; x <= g.x_maze_max; x += 2)
-        for (y = 0; y <= g.y_maze_max; y += 2) {
+    for (x = 2; x <= min(g.x_maze_max, COLNO-2); x += 2)
+        for (y = 0; y <= min(g.y_maze_max, ROWNO-2); y += 2) {
             int c = 0;
 
             (void) set_levltyp_lit(x, y, fg, lit);
@@ -2999,7 +2998,7 @@ get_table_xy_or_coord(lua_State *L, lua_Integer *x, lua_Integer *y)
 
     if (mx == -1 && my == -1) {
         lua_getfield(L, 1, "coord");
-        get_coord(L, -1, &mx, &my);
+        (void) get_coord(L, -1, &mx, &my);
         lua_pop(L, 1);
     }
 
@@ -3062,7 +3061,7 @@ lspo_monster(lua_State *L)
                && lua_type(L, 2) == LUA_TTABLE) {
         const char *paramstr = luaL_checkstring(L, 1);
 
-        get_coord(L, 2, &mx, &my);
+        (void) get_coord(L, 2, &mx, &my);
 
         if (strlen(paramstr) == 1) {
             tmpmons.class = *paramstr;
@@ -3325,7 +3324,7 @@ lspo_object(lua_State *L)
                && lua_type(L, 2) == LUA_TTABLE) {
         const char *paramstr = luaL_checkstring(L, 1);
 
-        get_coord(L, 2, &ox, &oy);
+        (void) get_coord(L, 2, &ox, &oy);
 
         if (strlen(paramstr) == 1) {
             tmpobj.class = *paramstr;
@@ -3592,7 +3591,7 @@ lspo_engraving(lua_State *L)
         txt = get_table_str(L, "text");
     } else if (argc == 3) {
         lua_Integer ex, ey;
-        get_coord(L, 1, &ex, &ey);
+        (void) get_coord(L, 1, &ex, &ey);
         x = ex;
         y = ey;
         etyp = engrtypes2i[luaL_checkoption(L, 2, "engrave", engrtypes)];
@@ -4069,7 +4068,7 @@ lspo_trap(lua_State *L)
         const char *trapstr = luaL_checkstring(L, 1);
 
         tmptrap.type = get_traptype_byname(trapstr);
-        get_coord(L, 2, &x, &y);
+        (void) get_coord(L, 2, &x, &y);
     } else if (argc == 3) {
         const char *trapstr = luaL_checkstring(L, 1);
 
@@ -4088,7 +4087,7 @@ lspo_trap(lua_State *L)
         if (lua_type(L, -1) == LUA_TTABLE) {
             lua_Integer lx = -1, ly = -1;
 
-            get_coord(L, -1, &lx, &ly);
+            (void) get_coord(L, -1, &lx, &ly);
             lua_pop(L, 1);
             g.launchplace.x = lx;
             g.launchplace.y = ly;
@@ -4131,7 +4130,7 @@ lspo_gold(lua_State *L)
         y = gy = luaL_checkinteger(L, 2);
     } else if (argc == 2 && lua_type(L, 2) == LUA_TTABLE) {
         amount = luaL_checkinteger(L, 1);
-        get_coord(L, 2, &gx, &gy);
+        (void) get_coord(L, 2, &gx, &gy);
         x = gx;
         y = gy;
     } else if (argc == 0 || (argc == 1 && lua_type(L, 1) == LUA_TTABLE)) {
@@ -4290,7 +4289,7 @@ selection_filter_mapchar(struct selectionvar* ov,  xchar typ, int lit)
     if (!ov || !ret)
         return NULL;
 
-    for (x = 0; x < ret->wid; x++)
+    for (x = 1; x < ret->wid; x++)
         for (y = 0; y < ret->hei; y++)
             if (selection_getpoint(x, y, ov)
                 && match_maptyps(typ, levl[x][y].typ)) {
@@ -4332,14 +4331,14 @@ selection_rndcoord(struct selectionvar* ov, xchar *x, xchar *y, boolean removeit
     int c;
     int dx, dy;
 
-    for (dx = 0; dx < ov->wid; dx++)
+    for (dx = 1; dx < ov->wid; dx++)
         for (dy = 0; dy < ov->hei; dy++)
             if (selection_getpoint(dx, dy, ov))
                 idx++;
 
     if (idx) {
         c = rn2(idx);
-        for (dx = 0; dx < ov->wid; dx++)
+        for (dx = 1; dx < ov->wid; dx++)
             for (dy = 0; dy < ov->hei; dy++)
                 if (selection_getpoint(dx, dy, ov)) {
                     if (!c) {
@@ -4791,7 +4790,7 @@ selection_iterate(
     /* yes, this is very naive, but it's not _that_ expensive. */
     for (x = 0; x < ov->wid; x++)
         for (y = 0; y < ov->hei; y++)
-            if (selection_getpoint(x, y, ov))
+            if (isok(x,y) && selection_getpoint(x, y, ov))
                 (*func)(x, y, arg);
 }
 
@@ -4924,7 +4923,10 @@ l_table_getset_feature_flag(
     }
 }
 
-/* convert relative coordinate to absolute */
+/* convert relative coordinate to map-absolute.
+  local ax,ay = nh.abscoord(rx, ry);
+  local pt = nh.abscoord({ x = 10, y = 5 });
+ */
 int
 nhl_abs_coord(lua_State *L)
 {
@@ -4936,11 +4938,22 @@ nhl_abs_coord(lua_State *L)
         y = (xchar) lua_tointeger(L, 2);
         x += g.xstart;
         y += g.ystart;
-    } else
+        lua_pushinteger(L, x);
+        lua_pushinteger(L, y);
+        return 2;
+    } else if (argc == 1 && lua_type(L, 1) == LUA_TTABLE) {
+        x = (xchar) get_table_int(L, "x");
+        y = (xchar) get_table_int(L, "y");
+        x += g.xstart;
+        y += g.ystart;
+        lua_newtable(L);
+        nhl_add_table_entry_int(L, "x", x);
+        nhl_add_table_entry_int(L, "y", y);
+        return 1;
+    } else {
         nhl_error(L, "nhl_abs_coord: Wrong args");
-    lua_pushinteger(L, x);
-    lua_pushinteger(L, y);
-    return 2;
+        return 0;
+    }
 }
 
 /* feature("fountain", x, y); */
@@ -4966,7 +4979,7 @@ lspo_feature(lua_State *L)
         && lua_type(L, 2) == LUA_TTABLE) {
         lua_Integer fx, fy;
         typ = features2i[luaL_checkoption(L, 1, NULL, features)];
-        get_coord(L, 2, &fx, &fy);
+        (void) get_coord(L, 2, &fx, &fy);
         x = fx;
         y = fy;
     } else if (argc == 3) {
@@ -5056,7 +5069,7 @@ lspo_terrain(lua_State *L)
         lua_Integer tx, ty;
         tmpterrain.ter = check_mapchr(luaL_checkstring(L, 2));
         lua_pop(L, 1);
-        get_coord(L, 1, &tx, &ty);
+        (void) get_coord(L, 1, &tx, &ty);
         x = tx;
         y = ty;
     } else if (argc == 2) {
@@ -5165,7 +5178,7 @@ lspo_replace_terrain(lua_State *L)
     }
 
     for (y = 0; y <= sel->hei; y++)
-        for (x = 0; x < sel->wid; x++)
+        for (x = 1; x < sel->wid; x++)
             if (selection_getpoint(x, y,sel)) {
                 if (mf) {
                     if (mapfrag_match(mf, x, y) && (rn2(100)) < chance)
@@ -5354,26 +5367,48 @@ get_table_region(
     return 1;
 }
 
-static int
+boolean
 get_coord(lua_State *L, int i, lua_Integer *x, lua_Integer *y)
 {
+    boolean ret = FALSE;
+
     if (lua_type(L, i) == LUA_TTABLE) {
         int arrlen;
+        boolean gotx = FALSE;
 
-        lua_len(L, i);
-        arrlen = lua_tointeger(L, -1);
-        lua_pop(L, 1);
-        if (arrlen != 2) {
-            nhl_error(L, "Not a coordinate");
-            return 0;
+        lua_getfield(L, i, "x");
+        if (!lua_isnil(L, -1)) {
+            *x = luaL_checkinteger(L, -1);
+            gotx = TRUE;
         }
+        lua_pop(L, 1);
 
-        *x = get_table_intarray_entry(L, i, 1);
-        *y = get_table_intarray_entry(L, i, 2);
+        if (gotx) {
+            lua_getfield(L, i, "y");
+            if (!lua_isnil(L, -1)) {
+                *y = luaL_checkinteger(L, -1);
+                lua_pop(L, 1);
+                ret = TRUE;
+            } else {
+                nhl_error(L, "Not a coordinate");
+                return FALSE;
+            }
+        } else {
+            lua_len(L, i);
+            arrlen = lua_tointeger(L, -1);
+            lua_pop(L, 1);
+            if (arrlen != 2) {
+                nhl_error(L, "Not a coordinate");
+                return FALSE;
+            }
 
-        return 1;
+            *x = get_table_intarray_entry(L, i, 1);
+            *y = get_table_intarray_entry(L, i, 2);
+
+            return TRUE;
+        }
     }
-    return 0;
+    return ret;
 }
 
 static void
index acc378c76c4659449572f250e12208e283c1b142..4a5698aed2d1c44f15d16be7e38daeb450fc5740 100644 (file)
@@ -521,4 +521,5 @@ function run_tests()
    des.level_init();
 end
 
+nh.debug_flags({mongen = false, hunger = false, overwrite_stairs = true });
 run_tests();
index a6a3295b502e441a5c9a8b0aa8b87a6e1c08cd4f..eaccba54f69a9d9ca9c248dab7abbd9530d21854 100644 (file)
@@ -61,14 +61,14 @@ function test_selection_params()
    sel:set(1, 2);
    sel_pt_ne(sel, 1,2, 1, "test_selection_params 2");
 
-   local x,y = sel:rndcoord(1);
-   if x ~= 1 or y ~= 2 then
-      error("sel:rndcoord returned unset coordinate");
+   local pt = sel:rndcoord(1);
+   if pt.x ~= 1 or pt.y ~= 2 then
+      error("sel:rndcoord returned unset coordinate (" .. pt.x .. "," .. pt.y .. ")");
    end
 
-   x,y = sel:rndcoord(1);
-   if x ~= -2 and y ~= -1 then
-      error("sel:rndcoord returned (" .. x .. "," .. y .. ") coordinate");
+   pt = sel:rndcoord(1);
+   if pt.x ~= -2 or pt.y ~= -1 then
+      error("sel:rndcoord returned (" .. pt.x .. "," .. pt.y .. ") coordinate");
    end
 
    -- OO style
@@ -466,6 +466,7 @@ function test_sel_iterate()
    is_map_at(9,5, "L");
 end
 
+nh.debug_flags({mongen = false, hunger = false, overwrite_stairs = true });
 test_selection_params();
 test_sel_negate();
 test_sel_logical_and();