The Battle for Wesnoth  1.19.20+dev
lua_map_location_ops.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2025
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
17 #include "scripting/lua_common.hpp"
18 #include "scripting/push_check.hpp"
19 
20 #include "map/location.hpp"
21 #include "pathutils.hpp"
22 
23 #include <string>
24 #include <utility>
25 
26 static bool luaW_tocubeloc(lua_State* L, int idx, cubic_location& out) {
27  if(!lua_istable(L, idx)) {
28  return false;
29  }
30  int n = lua_absindex(L, -1);
31  if(!luaW_tableget(L, n, "q")) {
32  return false;
33  }
34  out.q = luaL_checkinteger(L, -1);
35  if(!luaW_tableget(L, n, "r")) {
36  return false;
37  }
38  out.r = luaL_checkinteger(L, -1);
39  if(luaW_tableget(L, n, "s")) {
40  out.s = luaL_checkinteger(L, -1);
41  } else {
42  out.s = -out.q - out.r;
43  }
44  if(out.q + out.s + out.r != 0) {
45  return false;
46  }
47  return true;
48 }
49 
50 static cubic_location luaW_checkcubeloc(lua_State* L, int idx) {
52  if(!luaW_tocubeloc(L, idx, loc)) {
53  luaL_argerror(L, idx, "expected cubic location");
54  }
55  return loc;
56 }
57 
58 static void luaW_pushcubeloc(lua_State* L, cubic_location loc) {
59  static const lua_named_tuple_builder tuple_builder{ {"q", "r", "s"} };
60  tuple_builder.push(L);
61  lua_pushinteger(L, loc.q);
62  lua_rawseti(L, -2, 1);
63  lua_pushinteger(L, loc.r);
64  lua_rawseti(L, -2, 2);
65  lua_pushinteger(L, loc.s);
66  lua_rawseti(L, -2, 3);
67 }
68 
69 namespace lua_map_location {
70 
71 /**
72  * Expose map_location::get_direction function to lua
73  * Arg 1: a location
74  * Arg 2: a direction
75  * Arg 3: (optional) number of steps
76  */
77 int intf_get_direction(lua_State* L)
78 {
79  map_location l;
80  if(!luaW_tolocation(L, 1, l)) {
81  return luaL_argerror(L, 1, "get_direction: first argument(S) must be a location");
82  }
83  int nargs = lua_gettop(L);
84  if (nargs < 2) {
85  luaL_error(L, "get_direction: not missing direction argument");
86  return 0;
87  }
88 
89  int n = 1;
90  if (nargs == 3) {
91  n = luaL_checkinteger(L, -1);
92  lua_pop(L,1);
93  }
94 
96  if (lua_isstring(L, -1)) {
97  d = map_location::parse_direction(luaL_checkstring(L,-1));
98  lua_pop(L,1);
99  } else {
100  std::string msg("get_direction: second argument should be a direction string, instead found a ");
101  msg += lua_typename(L, lua_type(L, -1));
102  return luaL_argerror(L, -1, msg.c_str());
103  }
104 
105  map_location result = l.get_direction(d, n);
106  luaW_pushlocation(L, result);
107  return 1;
108 }
109 
110 /**
111  * Expose map_location::vector_sum to lua
112  */
113 int intf_vector_sum(lua_State* L)
114 {
115  map_location l1, l2;
116  if(!luaW_tolocation(L, 1, l1) || !luaW_tolocation(L, 2, l2)) {
117  lua_pushstring(L, "vector_sum: requires two locations");
118  return lua_error(L);
119  }
120 
122  return 1;
123 }
124 
125 /**
126  * Expose map_location::vector_difference to lua
127  */
128 int intf_vector_diff(lua_State* L)
129 {
130  map_location l1, l2;
131  if(!luaW_tolocation(L, 1, l1) || !luaW_tolocation(L, 2, l2)) {
132  lua_pushstring(L, "vector_diff: requires two locations");
133  return lua_error(L);
134  }
135 
137  return 1;
138 }
139 
140 /**
141  * Expose map_location::vector_negation to lua
142  * - Arg 1: Location
143  * - Ret: Negated vector
144  */
145 int intf_vector_negation(lua_State* L)
146 {
147  map_location l1;
148  if(!luaW_tolocation(L, 1, l1)) {
149  return luaL_argerror(L, 1, "expected a location");
150  }
151 
153  return 1;
154 }
155 
156 /**
157  * Expose map_location::rotate_right_around_center to lua
158  */
160 {
161  int k = luaL_checkinteger(L, -1);
162  lua_pop(L,1);
163  map_location center, loc;
164  if(!luaW_tolocation(L, 1, loc) || !luaW_tolocation(L, 2, center)) {
165  lua_pushstring(L, "rotate_right_around_center: requires two locations");
166  return lua_error(L);
167  }
168 
170  return 1;
171 }
172 
173 /**
174  * Expose map_location tiles_adjacent
175  * - Args 1, 2: Two locations
176  * - Ret: True if the locations are adjacent
177  */
178 int intf_tiles_adjacent(lua_State* L)
179 {
180  map_location l1, l2;
181  if(!luaW_tolocation(L, 1, l1) || !luaW_tolocation(L, 2, l2)) {
182  lua_pushstring(L, "tiles_adjacent: requires two locations");
183  return lua_error(L);
184  }
185 
186  lua_pushboolean(L, tiles_adjacent(l1,l2));
187  return 1;
188 }
189 
190 /**
191  * Expose map_location get_adjacent_tiles
192  * - Arg 1: A location
193  * - Ret 1 - 6: The adjacent locations
194  */
195 int intf_get_adjacent_tiles(lua_State* L)
196 {
197  map_location l1;
198  if(!luaW_tolocation(L, 1, l1)) {
199  return luaL_argerror(L, 1, "expected a location");
200  }
201 
202  for(const map_location& adj : get_adjacent_tiles(l1)) {
203  luaW_pushlocation(L, adj);
204  }
205 
206  return 6;
207 }
208 
209 /**
210  * Expose map_location get_tile_ring
211  * - Arg 1: A location
212  * - Arg 2: A radius
213  * - Ret: The locations
214  */
215 int intf_get_tile_ring(lua_State* L)
216 {
217  map_location l1;
218  if(!luaW_tolocation(L, 1, l1)) {
219  return luaL_argerror(L, 1, "expected a location");
220  }
221  int radius = luaL_checkinteger(L, 2);
222 
223  std::vector<map_location> locs;
224  get_tile_ring(l1, radius, locs);
225  lua_push(L, locs);
226 
227  return 1;
228 }
229 
230 /**
231 * Expose map_location get_tiles_in_radius
232 * - Arg 1: A location
233 * - Arg 2: A radius
234 * - Ret: The locations
235 */
236 int intf_get_tiles_in_radius(lua_State* L)
237 {
238  map_location l1;
239  if(!luaW_tolocation(L, 1, l1)) {
240  return luaL_argerror(L, 1, "expected a location");
241  }
242  int radius = luaL_checkinteger(L, 2);
243 
244  std::vector<map_location> locs;
245  get_tiles_in_radius(l1, radius, locs);
246  lua_push(L, locs);
247 
248  return 1;
249 }
250 
251 /**
252  * Expose map_location distance_between
253  * - Args 1, 2: Two locations
254  * - Ret: The distance between the two locations
255  */
256 int intf_distance_between(lua_State* L)
257 {
258  map_location l1, l2;
259  if(!luaW_tolocation(L, 1, l1) || !luaW_tolocation(L, 2, l2)) {
260  lua_pushstring(L, "distance_between: requires two locations");
261  return lua_error(L);
262  }
263 
264  lua_pushinteger(L, distance_between(l1,l2));
265  return 1;
266 }
267 
268 /**
269  * Expose map_location to_cubic
270  * - Arg: Location
271  * - Ret: Location in cubic coordinates
272  */
273 int intf_get_in_cubic(lua_State* L)
274 {
275  map_location l1;
276  if(!luaW_tolocation(L, 1, l1)) {
277  return luaL_argerror(L, 1, "expected a location");
278  }
279  cubic_location h = l1.to_cubic();
280  // Due to the way that locations in Lua have are 1 more on each coordinate
281  // compared to the C++ coordinates, the output here also needs to be adjusted.
282  h.q++;
283  h.s--;
284  luaW_pushcubeloc(L, h);
285  return 1;
286 }
287 
288 /**
289  * Expose map_location from_cubic
290  * - Arg: Location in cubic coordinates
291  * - Ret: Location
292  */
293 int intf_get_from_cubic(lua_State* L)
294 {
296  // Adjust it from the WML location system
297  h.q--;
298  h.s++;
300  luaW_pushlocation(L, l);
301  return 1;
302 }
303 
304 /**
305  * Expose map_location get_relative_dir
306  * - Args 1, 2: Two locations
307  * - Ret: The direction of location 2 from location 1
308  */
309 int intf_get_relative_dir(lua_State* L)
310 {
311  map_location l1, l2;
312  if(!luaW_tolocation(L, 1, l1) || !luaW_tolocation(L, 2, l2)) {
313  lua_pushstring(L, "get_relative_dir: requires two locations");
314  return lua_error(L);
315  }
316 
317  const std::string dir = map_location::write_direction(l1.get_relative_dir(l2));
318  lua_pushlstring(L, dir.c_str(), dir.length());
319  return 1;
320 }
321 
322 } // end namespace lua_map_location
map_location loc
Definition: move.cpp:172
Efficiently creates new LUA "named tuples" with the specified field names.
Definition: lua_common.hpp:85
void push(lua_State *L) const
Push an empty "named tuple" onto the stack.
Definition: lua_common.cpp:733
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.cpp:584
void get_adjacent_tiles(const map_location &a, utils::span< map_location, 6 > res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:513
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:541
void luaW_pushlocation(lua_State *L, const map_location &ml)
Converts a map location object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:785
bool luaW_tableget(lua_State *L, int index, const char *key)
bool luaW_tolocation(lua_State *L, int index, map_location &loc)
Converts an optional table or pair of integers to a map location object.
Definition: lua_common.cpp:798
static void luaW_pushcubeloc(lua_State *L, cubic_location loc)
static cubic_location luaW_checkcubeloc(lua_State *L, int idx)
static bool luaW_tocubeloc(lua_State *L, int idx, cubic_location &out)
int intf_get_relative_dir(lua_State *L)
Expose map_location get_relative_dir.
int intf_vector_negation(lua_State *L)
Expose map_location::vector_negation to lua.
int intf_distance_between(lua_State *L)
Expose map_location distance_between.
int intf_get_in_cubic(lua_State *L)
Expose map_location to_cubic.
int intf_tiles_adjacent(lua_State *L)
Expose map_location tiles_adjacent.
int intf_vector_diff(lua_State *L)
Expose map_location::vector_difference to lua.
int intf_get_from_cubic(lua_State *L)
Expose map_location from_cubic.
int intf_vector_sum(lua_State *L)
Expose map_location::vector_sum to lua.
int intf_get_tile_ring(lua_State *L)
Expose map_location get_tile_ring.
int intf_rotate_right_around_center(lua_State *L)
Expose map_location::rotate_right_around_center to lua.
int intf_get_tiles_in_radius(lua_State *L)
Expose map_location get_tiles_in_radius.
int intf_get_adjacent_tiles(lua_State *L)
Expose map_location get_adjacent_tiles.
int intf_get_direction(lua_State *L)
Expose map_location::get_direction function to lua Arg 1: a location Arg 2: a direction Arg 3: (optio...
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
void get_tiles_in_radius(const map_location &center, const int radius, std::vector< map_location > &result)
Function that will add to result all locations within radius tiles of center (excluding center itself...
Definition: pathutils.cpp:56
void get_tile_ring(const map_location &center, const int radius, std::vector< map_location > &result)
Function that will add to result all locations exactly radius tiles from center (or nothing if radius...
Definition: pathutils.cpp:32
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:425
Represents a map location in cubic hexagonal coordinates.
Definition: location.hpp:34
Encapsulates the map of the game.
Definition: location.hpp:46
map_location & vector_sum_assign(const map_location &a)
Definition: location.hpp:143
map_location & vector_difference_assign(const map_location &a)
Definition: location.hpp:151
static map_location from_cubic(cubic_location h)
Definition: location.hpp:173
static std::string write_direction(direction dir)
Definition: location.cpp:154
map_location vector_negation() const
Definition: location.hpp:133
map_location get_direction(direction dir, unsigned int n=1u) const
Definition: location.cpp:362
map_location rotate_right_around_center(const map_location &center, int k) const
Definition: location.cpp:299
cubic_location to_cubic() const
Definition: location.hpp:167
direction
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:48
direction get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:238
static direction parse_direction(const std::string &str)
Definition: location.cpp:79
static map_location::direction n
#define d
#define h