1 /* NetHack 3.7 nhlua.c $NHDT-Date: 1737545957 2025/01/22 03:39:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ */
2 /* Copyright (c) 2018 by Pasi Kallinen */
3 /* NetHack may be freely redistributed. See license for details. */
9 struct selectionvar
*l_selection_check(lua_State
*, int);
10 staticfn
struct selectionvar
*l_selection_push_new(lua_State
*);
12 /* lua_CFunction prototypes */
13 staticfn
int l_selection_new(lua_State
*);
14 staticfn
int l_selection_clone(lua_State
*);
15 staticfn
int l_selection_numpoints(lua_State
*);
16 staticfn
int l_selection_getpoint(lua_State
*);
17 staticfn
int l_selection_setpoint(lua_State
*);
18 staticfn
int l_selection_filter_percent(lua_State
*);
19 staticfn
int l_selection_rndcoord(lua_State
*);
20 staticfn
int l_selection_room(lua_State
*);
21 staticfn
int l_selection_getbounds(lua_State
*);
22 staticfn boolean
params_sel_2coords(lua_State
*, struct selectionvar
**,
23 coordxy
*, coordxy
*, coordxy
*, coordxy
*);
24 staticfn
int l_selection_line(lua_State
*);
25 staticfn
int l_selection_randline(lua_State
*);
26 staticfn
int l_selection_rect(lua_State
*);
27 staticfn
int l_selection_fillrect(lua_State
*);
28 staticfn
int l_selection_grow(lua_State
*);
29 staticfn
int l_selection_filter_mapchar(lua_State
*);
30 staticfn
int l_selection_match(lua_State
*);
31 staticfn
int l_selection_flood(lua_State
*);
32 staticfn
int l_selection_circle(lua_State
*);
33 staticfn
int l_selection_ellipse(lua_State
*);
34 staticfn
int l_selection_gradient(lua_State
*);
35 staticfn
int l_selection_iterate(lua_State
*);
36 staticfn
int l_selection_gc(lua_State
*);
37 staticfn
int l_selection_not(lua_State
*);
38 staticfn
int l_selection_and(lua_State
*);
39 staticfn
int l_selection_or(lua_State
*);
40 staticfn
int l_selection_xor(lua_State
*);
41 /* There doesn't seem to be a point in having a l_selection_add since it would
42 * do the same thing as l_selection_or. The addition operator is mapped to
44 staticfn
int l_selection_sub(lua_State
*);
46 /* the following do not appear to currently be
47 used and because they are static, the OSX
48 compiler is complaining about them. I've
49 if ifdef'd out the prototype here and the
52 staticfn
int l_selection_ipairs(lua_State
*);
53 staticfn
struct selectionvar
*l_selection_to(lua_State
*, int);
57 l_selection_check(lua_State
*L
, int index
)
59 struct selectionvar
*sel
;
61 luaL_checktype(L
, index
, LUA_TUSERDATA
);
62 sel
= (struct selectionvar
*) luaL_checkudata(L
, index
, "selection");
64 nhl_error(L
, "Selection error");
69 l_selection_gc(lua_State
*L
)
71 struct selectionvar
*sel
= l_selection_check(L
, 1);
74 selection_free(sel
, FALSE
);
79 staticfn
struct selectionvar
*
80 l_selection_to(lua_State
*L
, int index
)
82 struct selectionvar
*sel
83 = (struct selectionvar
*) lua_touserdata(L
, index
);
86 nhl_error(L
, "Selection error");
91 /* push a new selection into lua stack, return the selectionvar */
92 staticfn
struct selectionvar
*
93 l_selection_push_new(lua_State
*L
)
95 struct selectionvar
*tmp
= selection_new();
96 struct selectionvar
*sel
97 = (struct selectionvar
*) lua_newuserdata(L
, sizeof (struct selectionvar
));
99 luaL_getmetatable(L
, "selection");
100 lua_setmetatable(L
, -2);
103 sel
->map
= dupstr(tmp
->map
);
104 selection_free(tmp
, TRUE
);
109 /* push a copy of selectionvar tmp to lua stack */
111 l_selection_push_copy(lua_State
*L
, struct selectionvar
*tmp
)
113 struct selectionvar
*sel
114 = (struct selectionvar
*) lua_newuserdata(L
, sizeof (struct selectionvar
));
116 luaL_getmetatable(L
, "selection");
117 lua_setmetatable(L
, -2);
120 sel
->map
= dupstr(tmp
->map
);
124 /* local sel = selection.new(); */
126 l_selection_new(lua_State
*L
)
128 (void) l_selection_push_new(L
);
132 /* Replace the topmost selection in the stack with a clone of it. */
133 /* local sel = selection.clone(sel); */
135 l_selection_clone(lua_State
*L
)
137 struct selectionvar
*sel
= l_selection_check(L
, 1);
138 struct selectionvar
*tmp
;
140 (void) l_selection_new(L
);
141 tmp
= l_selection_check(L
, 2);
145 tmp
->map
= dupstr(sel
->map
);
149 DISABLE_WARNING_UNREACHABLE_CODE
151 /* selection.set(sel, x, y); */
152 /* selection.set(sel, x, y, value); */
153 /* local sel = selection.set(); */
154 /* local sel = sel:set(); */
155 /* local sel = selection.set(sel); */
156 /* TODO: allow setting multiple coords at once: set({x1,y1},{x2,y2},...); */
158 l_selection_setpoint(lua_State
*L
)
160 struct selectionvar
*sel
= (struct selectionvar
*) 0;
161 coordxy x
= -1, y
= -1;
163 int argc
= lua_gettop(L
);
167 (void) l_selection_new(L
);
168 } else if (argc
== 1) {
169 sel
= l_selection_check(L
, 1);
170 } else if (argc
== 2) {
171 x
= (coordxy
) luaL_checkinteger(L
, 1);
172 y
= (coordxy
) luaL_checkinteger(L
, 2);
174 (void) l_selection_new(L
);
175 sel
= l_selection_check(L
, 1);
177 sel
= l_selection_check(L
, 1);
178 x
= (coordxy
) luaL_checkinteger(L
, 2);
179 y
= (coordxy
) luaL_checkinteger(L
, 3);
180 val
= (int) luaL_optinteger(L
, 4, 1);
183 if (!sel
|| !sel
->map
) {
184 nhl_error(L
, "Selection setpoint error");
189 if (x
== -1 && y
== -1)
190 crd
= SP_COORD_PACK_RANDOM(0);
192 crd
= SP_COORD_PACK(x
,y
);
193 get_location_coord(&x
, &y
, ANY_LOC
,
194 gc
.coder
? gc
.coder
->croom
: NULL
, crd
);
195 selection_setpoint(x
, y
, sel
, val
);
200 /* local numpoints = selection.numpoints(sel); */
202 l_selection_numpoints(lua_State
*L
)
204 struct selectionvar
*sel
= l_selection_check(L
, 1);
207 NhRect rect
= cg
.zeroNhRect
;
209 selection_getbounds(sel
, &rect
);
211 for (x
= rect
.lx
; x
<= rect
.hx
; x
++)
212 for (y
= rect
.ly
; y
<= rect
.hy
; y
++)
213 if (selection_getpoint(x
, y
, sel
))
217 lua_pushinteger(L
, ret
);
221 /* local value = selection.get(sel, x, y); */
223 l_selection_getpoint(lua_State
*L
)
225 struct selectionvar
*sel
= l_selection_check(L
, 1);
231 lua_remove(L
, 1); /* sel */
232 if (!nhl_get_xy_params(L
, &ix
, &iy
)) {
233 nhl_error(L
, "l_selection_getpoint: Incorrect params");
240 if (x
== -1 && y
== -1)
241 crd
= SP_COORD_PACK_RANDOM(0);
243 crd
= SP_COORD_PACK(x
,y
);
244 get_location_coord(&x
, &y
, ANY_LOC
,
245 gc
.coder
? gc
.coder
->croom
: NULL
, crd
);
247 val
= selection_getpoint(x
, y
, sel
);
249 lua_pushnumber(L
, val
);
253 RESTORE_WARNING_UNREACHABLE_CODE
255 /* local s = selection.negate(sel); */
256 /* local s = selection.negate(); */
257 /* local s = sel:negate(); */
259 l_selection_not(lua_State
*L
)
261 int argc
= lua_gettop(L
);
262 struct selectionvar
*sel
, *sel2
;
265 (void) l_selection_new(L
);
266 sel
= l_selection_check(L
, 1);
267 selection_clear(sel
, 1);
269 (void) l_selection_check(L
, 1);
270 (void) l_selection_clone(L
);
271 sel2
= l_selection_check(L
, 2);
278 /* local sel = selection.area(4,5, 40,10) & selection.rect(7,8, 60,14); */
280 l_selection_and(lua_State
*L
)
283 struct selectionvar
*sela
= l_selection_check(L
, 1);
284 struct selectionvar
*selb
= l_selection_check(L
, 2);
285 struct selectionvar
*selr
= l_selection_push_new(L
);
286 NhRect rect
= cg
.zeroNhRect
;
288 rect_bounds(sela
->bounds
, selb
->bounds
, &rect
);
290 for (x
= rect
.lx
; x
<= rect
.hx
; x
++)
291 for (y
= rect
.ly
; y
<= rect
.hy
; y
++) {
292 int val
= (selection_getpoint(x
, y
, sela
)
293 & selection_getpoint(x
, y
, selb
));
295 selection_setpoint(x
, y
, selr
, val
);
303 /* local sel = selection.area(4,5, 40,10) | selection.rect(7,8, 60,14); */
305 l_selection_or(lua_State
*L
)
308 struct selectionvar
*sela
= l_selection_check(L
, 1);
309 struct selectionvar
*selb
= l_selection_check(L
, 2);
310 struct selectionvar
*selr
= l_selection_push_new(L
);
311 NhRect rect
= cg
.zeroNhRect
;
313 rect_bounds(sela
->bounds
, selb
->bounds
, &rect
);
315 for (x
= rect
.lx
; x
<= rect
.hx
; x
++)
316 for (y
= rect
.ly
; y
<= rect
.hy
; y
++) {
317 int val
= (selection_getpoint(x
, y
, sela
)
318 | selection_getpoint(x
, y
, selb
));
320 selection_setpoint(x
, y
, selr
, val
);
329 /* local sel = selection.area(4,5, 40,10) ~ selection.rect(7,8, 60,14); */
331 l_selection_xor(lua_State
*L
)
334 struct selectionvar
*sela
= l_selection_check(L
, 1);
335 struct selectionvar
*selb
= l_selection_check(L
, 2);
336 struct selectionvar
*selr
= l_selection_push_new(L
);
337 NhRect rect
= cg
.zeroNhRect
;
339 rect_bounds(sela
->bounds
, selb
->bounds
, &rect
);
341 for (x
= rect
.lx
; x
<= rect
.hx
; x
++)
342 for (y
= rect
.ly
; y
<= rect
.hy
; y
++) {
343 int val
= (selection_getpoint(x
, y
, sela
)
344 ^ selection_getpoint(x
, y
, selb
));
346 selection_setpoint(x
, y
, selr
, val
);
348 /* this may have created a smaller or irregular selection with
349 * bounds_dirty set to true - update its boundaries */
350 selection_recalc_bounds(selr
);
357 /* local sel = selection.area(10,10, 20,20) - selection.area(14,14, 17,17)
358 * - i.e. points that are in A but not in B */
360 l_selection_sub(lua_State
*L
)
363 struct selectionvar
*sela
= l_selection_check(L
, 1);
364 struct selectionvar
*selb
= l_selection_check(L
, 2);
365 struct selectionvar
*selr
= l_selection_push_new(L
);
366 NhRect rect
= cg
.zeroNhRect
;
368 rect_bounds(sela
->bounds
, selb
->bounds
, &rect
);
370 for (x
= rect
.lx
; x
<= rect
.hx
; x
++)
371 for (y
= rect
.ly
; y
<= rect
.hy
; y
++) {
372 coordxy a_pt
= selection_getpoint(x
, y
, sela
);
373 coordxy b_pt
= selection_getpoint(x
, y
, selb
);
374 int val
= (a_pt
^ b_pt
) & a_pt
;
375 selection_setpoint(x
, y
, selr
, val
);
377 /* this may have created a smaller or irregular selection with
378 * bounds_dirty set to true - update its boundaries */
379 selection_recalc_bounds(selr
);
386 /* local s = selection.percentage(sel, 50); */
388 l_selection_filter_percent(lua_State
*L
)
390 int argc
= lua_gettop(L
);
391 struct selectionvar
*sel
= l_selection_check(L
, 1);
392 int p
= (int) luaL_checkinteger(L
, 2);
393 struct selectionvar
*tmp
;
395 tmp
= selection_filter_percent(sel
, p
);
397 l_selection_push_copy(L
, tmp
);
398 selection_free(tmp
, TRUE
);
403 /* local pt = selection.rndcoord(sel); */
404 /* local pt = selection.rndcoord(sel, 1); */
406 l_selection_rndcoord(lua_State
*L
)
408 struct selectionvar
*sel
= l_selection_check(L
, 1);
409 int removeit
= (int) luaL_optinteger(L
, 2, 0);
410 coordxy x
= -1, y
= -1;
411 selection_rndcoord(sel
, &x
, &y
, removeit
);
412 if (!(x
== -1 && y
== -1)) {
414 if (gc
.coder
&& gc
.coder
->croom
) {
415 x
-= gc
.coder
->croom
->lx
;
416 y
-= gc
.coder
->croom
->ly
;
424 nhl_add_table_entry_int(L
, "x", x
);
425 nhl_add_table_entry_int(L
, "y", y
);
429 /* local s = selection.room(); */
431 l_selection_room(lua_State
*L
)
433 struct selectionvar
*sel
;
434 int argc
= lua_gettop(L
);
435 struct mkroom
*croom
= NULL
;
438 int i
= luaL_checkinteger(L
, -1);
440 croom
= (i
>= 0 && i
< svn
.nroom
) ? &svr
.rooms
[i
] : NULL
;
443 sel
= selection_from_mkroom(croom
);
445 l_selection_push_copy(L
, sel
);
446 selection_free(sel
, TRUE
);
451 /* local rect = sel:bounds(); */
453 l_selection_getbounds(lua_State
*L
)
455 struct selectionvar
*sel
= l_selection_check(L
, 1);
456 NhRect rect
= cg
.zeroNhRect
;
458 selection_getbounds(sel
, &rect
);
461 nhl_add_table_entry_int(L
, "lx", rect
.lx
);
462 nhl_add_table_entry_int(L
, "ly", rect
.ly
);
463 nhl_add_table_entry_int(L
, "hx", rect
.hx
);
464 nhl_add_table_entry_int(L
, "hy", rect
.hy
);
468 /* internal function to get a selection and 4 integer values from lua stack.
469 removes the integers from the stack.
470 returns TRUE if params are good.
472 /* function(selection, x1,y1, x2,y2) */
473 /* selection:function(x1,y1, x2,y2) */
475 params_sel_2coords(lua_State
*L
, struct selectionvar
**sel
,
476 coordxy
*x1
, coordxy
*y1
, coordxy
*x2
, coordxy
*y2
)
478 int argc
= lua_gettop(L
);
481 (void) l_selection_new(L
);
482 *x1
= (coordxy
) luaL_checkinteger(L
, 1);
483 *y1
= (coordxy
) luaL_checkinteger(L
, 2);
484 *x2
= (coordxy
) luaL_checkinteger(L
, 3);
485 *y2
= (coordxy
) luaL_checkinteger(L
, 4);
486 *sel
= l_selection_check(L
, 5);
492 } else if (argc
== 5) {
493 *sel
= l_selection_check(L
, 1);
494 *x1
= (coordxy
) luaL_checkinteger(L
, 2);
495 *y1
= (coordxy
) luaL_checkinteger(L
, 3);
496 *x2
= (coordxy
) luaL_checkinteger(L
, 4);
497 *y2
= (coordxy
) luaL_checkinteger(L
, 5);
504 /* local s = selection.line(sel, x1,y1, x2,y2); */
505 /* local s = selection.line(x1,y1, x2,y2); */
506 /* s:line(x1,y1, x2,y2); */
508 l_selection_line(lua_State
*L
)
510 struct selectionvar
*sel
= NULL
;
511 coordxy x1
, y1
, x2
, y2
;
513 if (!params_sel_2coords(L
, &sel
, &x1
, &y1
, &x2
, &y2
)) {
514 nhl_error(L
, "selection.line: illegal arguments");
517 get_location_coord(&x1
, &y1
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
518 SP_COORD_PACK(x1
, y1
));
519 get_location_coord(&x2
, &y2
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
520 SP_COORD_PACK(x2
, y2
));
522 (void) l_selection_clone(L
);
523 sel
= l_selection_check(L
, 2);
524 selection_do_line(x1
,y1
,x2
,y2
, sel
);
528 /* local s = selection.rect(sel, x1,y1, x2,y2); */
530 l_selection_rect(lua_State
*L
)
532 struct selectionvar
*sel
= NULL
;
533 coordxy x1
, y1
, x2
, y2
;
535 if (!params_sel_2coords(L
, &sel
, &x1
, &y1
, &x2
, &y2
)) {
536 nhl_error(L
, "selection.rect: illegal arguments");
539 get_location_coord(&x1
, &y1
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
540 SP_COORD_PACK(x1
, y1
));
541 get_location_coord(&x2
, &y2
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
542 SP_COORD_PACK(x2
, y2
));
544 (void) l_selection_clone(L
);
545 sel
= l_selection_check(L
, 2);
546 selection_do_line(x1
, y1
, x2
, y1
, sel
);
547 selection_do_line(x1
, y1
, x1
, y2
, sel
);
548 selection_do_line(x2
, y1
, x2
, y2
, sel
);
549 selection_do_line(x1
, y2
, x2
, y2
, sel
);
553 /* local s = selection.fillrect(sel, x1,y1, x2,y2); */
554 /* local s = selection.fillrect(x1,y1, x2,y2); */
555 /* s:fillrect(x1,y1, x2,y2); */
556 /* selection.area(x1,y1, x2,y2); */
558 l_selection_fillrect(lua_State
*L
)
560 struct selectionvar
*sel
= NULL
;
562 coordxy x1
, y1
, x2
, y2
;
564 if (!params_sel_2coords(L
, &sel
, &x1
, &y1
, &x2
, &y2
)) {
565 nhl_error(L
, "selection.fillrect: illegal arguments");
568 get_location_coord(&x1
, &y1
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
569 SP_COORD_PACK(x1
, y1
));
570 get_location_coord(&x2
, &y2
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
571 SP_COORD_PACK(x2
, y2
));
573 (void) l_selection_clone(L
);
574 sel
= l_selection_check(L
, 2);
576 for (y
= y1
; y
<= y2
; y
++)
577 selection_setpoint(x1
, y
, sel
, 1);
579 for (y
= y1
; y
<= y2
; y
++)
580 selection_do_line(x1
, y
, x2
, y
, sel
);
585 /* local s = selection.randline(sel, x1,y1, x2,y2, roughness); */
586 /* local s = selection.randline(x1,y1, x2,y2, roughness); */
587 /* TODO: selection.randline(x1,y1, x2,y2, roughness); */
588 /* TODO: selection.randline({x1,y1}, {x2,y2}, roughness); */
590 l_selection_randline(lua_State
*L
)
592 int argc
= lua_gettop(L
);
593 struct selectionvar
*sel
;
594 coordxy x1
= 0, y1
= 0, x2
= 0, y2
= 0;
598 (void) l_selection_check(L
, 1);
599 x1
= (coordxy
) luaL_checkinteger(L
, 2);
600 y1
= (coordxy
) luaL_checkinteger(L
, 3);
601 x2
= (coordxy
) luaL_checkinteger(L
, 4);
602 y2
= (coordxy
) luaL_checkinteger(L
, 5);
603 roughness
= (int) luaL_checkinteger(L
, 6);
605 } else if (argc
== 5 && lua_type(L
, 1) == LUA_TNUMBER
) {
606 x1
= (coordxy
) luaL_checkinteger(L
, 1);
607 y1
= (coordxy
) luaL_checkinteger(L
, 2);
608 x2
= (coordxy
) luaL_checkinteger(L
, 3);
609 y2
= (coordxy
) luaL_checkinteger(L
, 4);
610 roughness
= (int) luaL_checkinteger(L
, 5);
612 (void) l_selection_new(L
);
613 (void) l_selection_check(L
, 1);
616 get_location_coord(&x1
, &y1
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
617 SP_COORD_PACK(x1
, y1
));
618 get_location_coord(&x2
, &y2
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
619 SP_COORD_PACK(x2
, y2
));
621 (void) l_selection_clone(L
);
622 sel
= l_selection_check(L
, 2);
623 selection_do_randline(x1
, y1
, x2
, y2
, roughness
, 12, sel
);
627 /* local s = selection.grow(sel); */
628 /* local s = selection.grow(sel, "north"); */
630 l_selection_grow(lua_State
*L
)
632 static const char *const growdirs
[] = {
633 "all", "random", "north", "west", "east", "south", NULL
635 static const int growdirs2i
[] = {
636 W_ANY
, W_RANDOM
, W_NORTH
, W_WEST
, W_EAST
, W_SOUTH
, 0
638 struct selectionvar
*sel
;
639 int dir
, argc
= lua_gettop(L
);
641 (void) l_selection_check(L
, 1);
642 dir
= growdirs2i
[luaL_checkoption(L
, 2, "all", growdirs
)];
645 lua_pop(L
, 1); /* get rid of growdir */
647 (void) l_selection_clone(L
);
648 sel
= l_selection_check(L
, 2);
649 selection_do_grow(sel
, dir
);
654 /* local s = selection.filter_mapchar(sel, mapchar, lit); */
656 l_selection_filter_mapchar(lua_State
*L
)
658 int argc
= lua_gettop(L
);
659 struct selectionvar
*sel
= l_selection_check(L
, 1);
660 char *mapchr
= dupstr(luaL_checkstring(L
, 2));
661 coordxy typ
= check_mapchr(mapchr
);
662 int lit
= (int) luaL_optinteger(L
, 3, -2); /* TODO: special lit values */
663 struct selectionvar
*tmp
;
665 if (typ
== INVALID_TYPE
)
666 nhl_error(L
, "Erroneous map char");
668 tmp
= selection_filter_mapchar(sel
, typ
, lit
);
670 l_selection_push_copy(L
, tmp
);
671 selection_free(tmp
, TRUE
);
679 /* local s = selection.match([[...]]); */
681 l_selection_match(lua_State
*L
)
683 int argc
= lua_gettop(L
);
684 struct selectionvar
*sel
= (struct selectionvar
*) 0;
685 struct mapfragment
*mf
= (struct mapfragment
*) 0;
690 char *mapstr
= dupstr(luaL_checkstring(L
, 1));
692 (void) l_selection_new(L
);
693 sel
= l_selection_check(L
, 1);
695 mf
= mapfrag_fromstr(mapstr
);
698 if ((err
= mapfrag_error(mf
)) != NULL
) {
704 nhl_error(L
, "wrong parameters");
708 for (y
= 0; y
<= sel
->hei
; y
++)
709 for (x
= 1; x
< sel
->wid
; x
++)
710 selection_setpoint(x
, y
, sel
, mapfrag_match(mf
, x
,y
) ? 1 : 0);
718 /* local s = selection.floodfill(x,y); */
719 /* local s = selection.floodfill(x,y, diagonals); */
721 l_selection_flood(lua_State
*L
)
723 int argc
= lua_gettop(L
);
724 struct selectionvar
*sel
= (struct selectionvar
*) 0;
725 coordxy x
= 0, y
= 0;
726 boolean diagonals
= FALSE
;
728 if (argc
== 2 || argc
== 3) {
729 x
= (coordxy
) luaL_checkinteger(L
, 1);
730 y
= (coordxy
) luaL_checkinteger(L
, 2);
732 diagonals
= lua_toboolean(L
, 3);
734 (void) l_selection_new(L
);
735 sel
= l_selection_check(L
, 1);
737 nhl_error(L
, "wrong parameters");
741 get_location_coord(&x
, &y
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
742 SP_COORD_PACK(x
, y
));
745 set_floodfillchk_match_under(levl
[x
][y
].typ
);
746 selection_floodfill(sel
, x
, y
, diagonals
);
752 /* local s = selection.circle(x,y, radius); */
753 /* local s = selection.circle(x, y, radius, filled); */
754 /* local s = selection.circle(sel, x, y, radius); */
755 /* local s = selection.circle(sel, x, y, radius, filled); */
757 l_selection_circle(lua_State
*L
)
759 int argc
= lua_gettop(L
);
760 struct selectionvar
*sel
= (struct selectionvar
*) 0;
761 coordxy x
= 0, y
= 0;
762 int r
= 0, filled
= 0;
765 x
= (coordxy
) luaL_checkinteger(L
, 1);
766 y
= (coordxy
) luaL_checkinteger(L
, 2);
767 r
= (int) luaL_checkinteger(L
, 3);
769 (void) l_selection_new(L
);
770 sel
= l_selection_check(L
, 1);
772 } else if (argc
== 4 && lua_type(L
, 1) == LUA_TNUMBER
) {
773 x
= (coordxy
) luaL_checkinteger(L
, 1);
774 y
= (coordxy
) luaL_checkinteger(L
, 2);
775 r
= (int) luaL_checkinteger(L
, 3);
776 filled
= (int) luaL_checkinteger(L
, 4); /* TODO: boolean*/
778 (void) l_selection_new(L
);
779 sel
= l_selection_check(L
, 1);
780 } else if (argc
== 4 || argc
== 5) {
781 sel
= l_selection_check(L
, 1);
782 x
= (coordxy
) luaL_checkinteger(L
, 2);
783 y
= (coordxy
) luaL_checkinteger(L
, 3);
784 r
= (int) luaL_checkinteger(L
, 4);
785 filled
= (int) luaL_optinteger(L
, 5, 0); /* TODO: boolean */
787 nhl_error(L
, "wrong parameters");
791 get_location_coord(&x
, &y
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
792 SP_COORD_PACK(x
, y
));
794 selection_do_ellipse(sel
, x
, y
, r
, r
, !filled
);
800 /* local s = selection.ellipse(x, y, radius1, radius2); */
801 /* local s = selection.ellipse(x, y, radius1, radius2, filled); */
802 /* local s = selection.ellipse(sel, x, y, radius1, radius2); */
803 /* local s = selection.ellipse(sel, x, y, radius1, radius2, filled); */
805 l_selection_ellipse(lua_State
*L
)
807 int argc
= lua_gettop(L
);
808 struct selectionvar
*sel
= (struct selectionvar
*) 0;
809 coordxy x
= 0, y
= 0;
810 int r1
= 0, r2
= 0, filled
= 0;
813 x
= (coordxy
) luaL_checkinteger(L
, 1);
814 y
= (coordxy
) luaL_checkinteger(L
, 2);
815 r1
= (int) luaL_checkinteger(L
, 3);
816 r2
= (int) luaL_checkinteger(L
, 4);
818 (void) l_selection_new(L
);
819 sel
= l_selection_check(L
, 1);
821 } else if (argc
== 5 && lua_type(L
, 1) == LUA_TNUMBER
) {
822 x
= (coordxy
) luaL_checkinteger(L
, 1);
823 y
= (coordxy
) luaL_checkinteger(L
, 2);
824 r1
= (int) luaL_checkinteger(L
, 3);
825 r2
= (int) luaL_checkinteger(L
, 4);
826 filled
= (int) luaL_optinteger(L
, 5, 0); /* TODO: boolean */
828 (void) l_selection_new(L
);
829 sel
= l_selection_check(L
, 1);
830 } else if (argc
== 5 || argc
== 6) {
831 sel
= l_selection_check(L
, 1);
832 x
= (coordxy
) luaL_checkinteger(L
, 2);
833 y
= (coordxy
) luaL_checkinteger(L
, 3);
834 r1
= (int) luaL_checkinteger(L
, 4);
835 r2
= (int) luaL_checkinteger(L
, 5);
836 filled
= (int) luaL_optinteger(L
, 6, 0); /* TODO: boolean */
838 nhl_error(L
, "wrong parameters");
842 get_location_coord(&x
, &y
, ANY_LOC
, gc
.coder
? gc
.coder
->croom
: NULL
,
843 SP_COORD_PACK(x
, y
));
845 selection_do_ellipse(sel
, x
, y
, r1
, r2
, !filled
);
851 /* Gradients are versatile enough, with so many independently optional
852 * arguments, that it doesn't seem helpful to provide a non-table form with
853 * non-obvious argument order. */
854 /* selection.gradient({ type = "radial", x = 3, y = 5, x2 = 10, y2 = 12,
855 * mindist = 4, maxdist = 10, limited = false }); */
857 l_selection_gradient(lua_State
*L
)
859 int argc
= lua_gettop(L
);
860 struct selectionvar
*sel
= (struct selectionvar
*) 0;
861 /* if x2 and y2 aren't set, the gradient has a single center point of x,y;
862 * if they are set, the gradient is centered on a (x,y) to (x2,y2) line */
863 coordxy x
= 0, y
= 0, x2
= -1, y2
= -1;
864 /* points are always added within mindist of the center; the chance for a
865 * point between mindist and maxdist to be added to the selection starts
866 * at 100% at mindist and decreases linearly to 0% at maxdist */
867 coordxy mindist
= 0, maxdist
= 0;
869 static const char *const gradtypes
[] = {
870 "radial", "square", NULL
872 static const int gradtypes2i
[] = {
873 SEL_GRADIENT_RADIAL
, SEL_GRADIENT_SQUARE
, -1
876 if (argc
== 1 && lua_type(L
, 1) == LUA_TTABLE
) {
877 lcheck_param_table(L
);
878 type
= gradtypes2i
[get_table_option(L
, "type", "radial", gradtypes
)];
879 x
= (coordxy
) get_table_int(L
, "x");
880 y
= (coordxy
) get_table_int(L
, "y");
881 x2
= (coordxy
) get_table_int_opt(L
, "x2", -1);
882 y2
= (coordxy
) get_table_int_opt(L
, "y2", -1);
883 cvt_to_abscoord(&x
, &y
);
884 cvt_to_abscoord(&x2
, &y2
);
885 /* maxdist is required because there's no obvious default value for
886 * it, whereas mindist has an obvious default of 0 */
887 maxdist
= get_table_int(L
, "maxdist");
888 mindist
= get_table_int_opt(L
, "mindist", 0);
891 (void) l_selection_new(L
);
892 sel
= l_selection_check(L
, 1);
894 nhl_error(L
, "selection.gradient requires table argument");
898 /* someone might conceivably want to draw a gradient somewhere off-map. So
899 * the only coordinate that's "illegal" for that is (-1,-1).
900 * If a level designer really needs to draw a gradient line using that
901 * coordinate, they can do so by setting regular x and y to -1. */
902 if (x2
== -1 && y2
== -1) {
907 selection_do_gradient(sel
, x
, y
, x2
, y2
, type
, mindist
, maxdist
);
912 /* sel:iterate(function(x,y) ... end);
913 * The x, y coordinates passed to the function are map- or room-relative
914 * rather than absolute, unless there has been no previous map or room
918 l_selection_iterate(lua_State
*L
)
920 int argc
= lua_gettop(L
);
921 struct selectionvar
*sel
= (struct selectionvar
*) 0;
923 NhRect rect
= cg
.zeroNhRect
;
925 if (argc
== 2 && lua_type(L
, 2) == LUA_TFUNCTION
) {
926 sel
= l_selection_check(L
, 1);
927 selection_getbounds(sel
, &rect
);
928 for (y
= rect
.ly
; y
<= rect
.hy
; y
++)
929 for (x
= max(1,rect
.lx
); x
<= rect
.hx
; x
++)
930 if (selection_getpoint(x
, y
, sel
)) {
931 coordxy tmpx
= x
, tmpy
= y
;
932 cvt_to_relcoord(&tmpx
, &tmpy
);
934 lua_pushinteger(L
, tmpx
);
935 lua_pushinteger(L
, tmpy
);
936 if (nhl_pcall_handle(L
, 2, 0, "l_selection_iterate",
938 /* abort loops to prevent possible error cascade */
943 nhl_error(L
, "wrong parameters");
951 static const struct luaL_Reg l_selection_methods
[] = {
952 { "new", l_selection_new
},
953 { "clone", l_selection_clone
},
954 { "get", l_selection_getpoint
},
955 { "set", l_selection_setpoint
},
956 { "numpoints", l_selection_numpoints
},
957 { "negate", l_selection_not
},
958 { "percentage", l_selection_filter_percent
},
959 { "rndcoord", l_selection_rndcoord
},
960 { "line", l_selection_line
},
961 { "randline", l_selection_randline
},
962 { "rect", l_selection_rect
},
963 { "fillrect", l_selection_fillrect
},
964 { "area", l_selection_fillrect
},
965 { "grow", l_selection_grow
},
966 { "filter_mapchar", l_selection_filter_mapchar
},
967 { "match", l_selection_match
},
968 { "floodfill", l_selection_flood
},
969 { "circle", l_selection_circle
},
970 { "ellipse", l_selection_ellipse
},
971 { "gradient", l_selection_gradient
},
972 { "iterate", l_selection_iterate
},
973 { "bounds", l_selection_getbounds
},
974 { "room", l_selection_room
},
978 static const luaL_Reg l_selection_meta
[] = {
979 { "__gc", l_selection_gc
},
980 { "__unm", l_selection_not
},
981 { "__band", l_selection_and
},
982 { "__bor", l_selection_or
},
983 { "__bxor", l_selection_xor
},
984 { "__bnot", l_selection_not
},
985 { "__add", l_selection_or
}, /* this aliases + to be the same as | */
986 { "__sub", l_selection_sub
},
987 /* TODO: http://lua-users.org/wiki/MetatableEvents
988 { "__ipairs", l_selection_ipairs },
994 l_selection_register(lua_State
*L
)
996 /* Table of instance methods and static methods. */
997 luaL_newlib(L
, l_selection_methods
);
999 /* metatable = { __name = "selection", __gc = l_selection_gc } */
1000 luaL_newmetatable(L
, "selection");
1001 luaL_setfuncs(L
, l_selection_meta
, 0);
1003 /* metatable.__index points at the selection method table. */
1004 lua_pushvalue(L
, -2);
1005 lua_setfield(L
, -2, "__index");
1007 /* Don't let lua code mess with the real metatable.
1008 Instead offer a fake one that only contains __gc. */
1009 luaL_newlib(L
, l_selection_meta
);
1010 lua_setfield(L
, -2, "__metatable");
1012 /* We don't need the metatable anymore. It's safe in the
1013 Lua registry for use by luaL_setmetatable. */
1016 /* global selection = the method table we created at the start */
1017 lua_setglobal(L
, "selection");