make rank() static again
[NetHack.git] / src / selvar.c
blob5d08ca95e58d0e616be18f061609296083dbc07f
1 /* NetHack 3.7 selvar.c $NHDT-Date: 1709677544 2024/03/05 22:25:44 $ $NHDT-Branch: keni-mdlib-followup $:$NHDT-Revision: 1.360 $ */
2 /* Copyright (c) 2024 by Pasi Kallinen */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
6 #include "selvar.h"
7 #include "sp_lev.h"
9 staticfn boolean sel_flood_havepoint(coordxy, coordxy, coordxy *, coordxy *,
10 int);
11 staticfn long line_dist_coord(long, long, long, long, long, long);
13 /* selection */
14 struct selectionvar *
15 selection_new(void)
17 struct selectionvar *tmps = (struct selectionvar *) alloc(sizeof *tmps);
19 tmps->wid = COLNO;
20 tmps->hei = ROWNO;
21 tmps->bounds_dirty = FALSE;
22 tmps->bounds.lx = COLNO;
23 tmps->bounds.ly = ROWNO;
24 tmps->bounds.hx = tmps->bounds.hy = 0;
25 tmps->map = (char *) alloc((COLNO * ROWNO) + 1);
26 (void) memset(tmps->map, 1, (COLNO * ROWNO));
27 tmps->map[(COLNO * ROWNO)] = '\0';
29 return tmps;
32 void
33 selection_free(struct selectionvar *sel, boolean freesel)
35 if (sel) {
36 if (sel->map)
37 free(sel->map);
38 sel->map = NULL;
39 if (freesel)
40 free((genericptr_t) sel);
41 else
42 (void) memset((genericptr_t) sel, 0, sizeof *sel);
46 /* clear selection, setting all locations to value val */
47 void
48 selection_clear(struct selectionvar *sel, int val)
50 (void) memset(sel->map, 1 + val, (COLNO * ROWNO));
51 if (val) {
52 sel->bounds.lx = 0;
53 sel->bounds.ly = 0;
54 sel->bounds.hx = COLNO - 1;
55 sel->bounds.hy = ROWNO - 1;
56 } else {
57 sel->bounds.lx = COLNO;
58 sel->bounds.ly = ROWNO;
59 sel->bounds.hx = sel->bounds.hy = 0;
61 sel->bounds_dirty = FALSE;
64 struct selectionvar *
65 selection_clone(struct selectionvar *sel)
67 struct selectionvar *tmps = (struct selectionvar *) alloc(sizeof *tmps);
69 *tmps = *sel;
70 tmps->map = dupstr(sel->map);
72 return tmps;
75 /* get boundary rect of selection sel into b */
76 void
77 selection_getbounds(struct selectionvar *sel, NhRect *b)
79 if (!sel || !b)
80 return;
82 selection_recalc_bounds(sel);
84 if (sel->bounds.lx >= sel->wid) {
85 b->lx = 0;
86 b->ly = 0;
87 b->hx = COLNO - 1;
88 b->hy = ROWNO - 1;
89 } else {
90 b->lx = sel->bounds.lx;
91 b->ly = sel->bounds.ly;
92 b->hx = sel->bounds.hx;
93 b->hy = sel->bounds.hy;
97 /* recalc the boundary of selection, if necessary */
98 void
99 selection_recalc_bounds(struct selectionvar *sel)
101 coordxy x, y;
102 NhRect r;
104 if (!sel->bounds_dirty)
105 return;
107 sel->bounds.lx = COLNO;
108 sel->bounds.ly = ROWNO;
109 sel->bounds.hx = sel->bounds.hy = 0;
111 r.lx = r.ly = r.hx = r.hy = -1;
113 /* left */
114 for (x = 0; x < sel->wid; x++) {
115 for (y = 0; y < sel->hei; y++) {
116 if (selection_getpoint(x, y, sel)) {
117 r.lx = x;
118 break;
121 if (r.lx > -1)
122 break;
125 if (r.lx > -1) {
126 /* right */
127 for (x = sel->wid-1; x >= r.lx; x--) {
128 for (y = 0; y < sel->hei; y++) {
129 if (selection_getpoint(x, y, sel)) {
130 r.hx = x;
131 break;
134 if (r.hx > -1)
135 break;
138 /* top */
139 for (y = 0; y < sel->hei; y++) {
140 for (x = r.lx; x <= r.hx; x++) {
141 if (selection_getpoint(x, y, sel)) {
142 r.ly = y;
143 break;
146 if (r.ly > -1)
147 break;
150 /* bottom */
151 for (y = sel->hei-1; y >= r.ly; y--) {
152 for (x = r.lx; x <= r.hx; x++) {
153 if (selection_getpoint(x, y, sel)) {
154 r.hy = y;
155 break;
158 if (r.hy > -1)
159 break;
161 sel->bounds = r;
164 sel->bounds_dirty = FALSE;
167 coordxy
168 selection_getpoint(
169 coordxy x, coordxy y,
170 struct selectionvar *sel)
172 if (!sel || !sel->map)
173 return 0;
174 if (x < 0 || y < 0 || x >= sel->wid || y >= sel->hei)
175 return 0;
177 return (sel->map[sel->wid * y + x] - 1);
180 void
181 selection_setpoint(
182 coordxy x, coordxy y,
183 struct selectionvar *sel,
184 int c)
186 if (!sel || !sel->map)
187 return;
188 if (x < 0 || y < 0 || x >= sel->wid || y >= sel->hei)
189 return;
191 if (c && !sel->bounds_dirty) {
192 if (sel->bounds.lx > x) sel->bounds.lx = x;
193 if (sel->bounds.ly > y) sel->bounds.ly = y;
194 if (sel->bounds.hx < x) sel->bounds.hx = x;
195 if (sel->bounds.hy < y) sel->bounds.hy = y;
196 } else {
197 sel->bounds_dirty = TRUE;
200 sel->map[sel->wid * y + x] = (char) (c + 1);
203 struct selectionvar *
204 selection_not(struct selectionvar *s)
206 int x, y;
207 NhRect tmprect = cg.zeroNhRect;
209 for (x = 0; x < s->wid; x++)
210 for (y = 0; y < s->hei; y++)
211 selection_setpoint(x, y, s, selection_getpoint(x, y, s) ? 0 : 1);
212 selection_getbounds(s, &tmprect);
213 return s;
216 struct selectionvar *
217 selection_filter_percent(
218 struct selectionvar *ov,
219 int percent)
221 int x, y;
222 struct selectionvar *ret;
223 NhRect rect = cg.zeroNhRect;
225 if (!ov)
226 return NULL;
228 ret = selection_new();
230 selection_getbounds(ov, &rect);
232 for (x = rect.lx; x <= rect.hx; x++)
233 for (y = rect.ly; y <= rect.hy; y++)
234 if (selection_getpoint(x, y, ov) && (rn2(100) < percent))
235 selection_setpoint(x, y, ret, 1);
237 return ret;
240 struct selectionvar *
241 selection_filter_mapchar(struct selectionvar *ov, xint16 typ, int lit)
243 int x, y;
244 struct selectionvar *ret;
245 NhRect rect = cg.zeroNhRect;
247 if (!ov)
248 return NULL;
250 ret = selection_new();
252 selection_getbounds(ov, &rect);
254 for (x = rect.lx; x <= rect.hx; x++)
255 for (y = rect.ly; y <= rect.hy; y++)
256 if (selection_getpoint(x, y, ov)
257 && match_maptyps(typ, levl[x][y].typ)) {
258 switch (lit) {
259 default:
260 case -2:
261 selection_setpoint(x, y, ret, 1);
262 break;
263 case -1:
264 selection_setpoint(x, y, ret, rn2(2));
265 break;
266 case 0:
267 case 1:
268 if (levl[x][y].lit == (unsigned int) lit)
269 selection_setpoint(x, y, ret, 1);
270 break;
273 return ret;
277 selection_rndcoord(
278 struct selectionvar *ov,
279 coordxy *x, coordxy *y,
280 boolean removeit)
282 int idx = 0;
283 int c;
284 int dx, dy;
285 NhRect rect = cg.zeroNhRect;
287 selection_getbounds(ov, &rect);
289 for (dx = rect.lx; dx <= rect.hx; dx++)
290 for (dy = rect.ly; dy <= rect.hy; dy++)
291 if (selection_getpoint(dx, dy, ov))
292 idx++;
294 if (idx) {
295 c = rn2(idx);
296 for (dx = rect.lx; dx <= rect.hx; dx++)
297 for (dy = rect.ly; dy <= rect.hy; dy++)
298 if (selection_getpoint(dx, dy, ov)) {
299 if (!c) {
300 *x = dx;
301 *y = dy;
302 if (removeit)
303 selection_setpoint(dx, dy, ov, 0);
304 return 1;
306 c--;
309 *x = *y = -1;
310 return 0;
313 void
314 selection_do_grow(struct selectionvar *ov, int dir)
316 coordxy x, y;
317 struct selectionvar *tmp;
318 NhRect rect = cg.zeroNhRect;
320 if (!ov)
321 return;
323 tmp = selection_new();
325 if (dir == W_RANDOM)
326 dir = random_wdir();
328 selection_getbounds(ov, &rect);
330 for (x = max(0, rect.lx-1); x <= min(COLNO-1, rect.hx+1); x++)
331 for (y = max(0, rect.ly-1); y <= min(ROWNO-1, rect.hy+1); y++) {
332 /* note: dir is a mask of multiple directions, but the only
333 way to specify diagonals is by including the two adjacent
334 orthogonal directions, which effectively specifies three-
335 way growth [WEST|NORTH => WEST plus WEST|NORTH plus NORTH] */
336 if (((dir & W_WEST) && selection_getpoint(x + 1, y, ov))
337 || (((dir & (W_WEST | W_NORTH)) == (W_WEST | W_NORTH))
338 && selection_getpoint(x + 1, y + 1, ov))
339 || ((dir & W_NORTH) && selection_getpoint(x, y + 1, ov))
340 || (((dir & (W_NORTH | W_EAST)) == (W_NORTH | W_EAST))
341 && selection_getpoint(x - 1, y + 1, ov))
342 || ((dir & W_EAST) && selection_getpoint(x - 1, y, ov))
343 || (((dir & (W_EAST | W_SOUTH)) == (W_EAST | W_SOUTH))
344 && selection_getpoint(x - 1, y - 1, ov))
345 || ((dir & W_SOUTH) && selection_getpoint(x, y - 1, ov))
346 || (((dir & (W_SOUTH | W_WEST)) == (W_SOUTH | W_WEST))
347 && selection_getpoint(x + 1, y - 1, ov))) {
348 selection_setpoint(x, y, tmp, 1);
352 selection_getbounds(tmp, &rect);
354 for (x = rect.lx; x <= rect.hx; x++)
355 for (y = rect.ly; y <= rect.hy; y++)
356 if (selection_getpoint(x, y, tmp))
357 selection_setpoint(x, y, ov, 1);
359 selection_free(tmp, TRUE);
362 staticfn int (*selection_flood_check_func)(coordxy, coordxy);
364 void
365 set_selection_floodfillchk(int (*f)(coordxy, coordxy))
367 selection_flood_check_func = f;
370 /* check whethere <x,y> is already in xs[],ys[] */
371 staticfn boolean
372 sel_flood_havepoint(
373 coordxy x, coordxy y,
374 coordxy xs[], coordxy ys[],
375 int n)
377 coordxy xx = x, yy = y;
379 while (n > 0) {
380 --n;
381 if (xs[n] == xx && ys[n] == yy)
382 return TRUE;
384 return FALSE;
387 void
388 selection_floodfill(
389 struct selectionvar *ov,
390 coordxy x, coordxy y,
391 boolean diagonals)
393 struct selectionvar *tmp = selection_new();
394 #define SEL_FLOOD_STACK (COLNO * ROWNO)
395 #define SEL_FLOOD(nx, ny) \
396 do { \
397 if (idx < SEL_FLOOD_STACK) { \
398 dx[idx] = (nx); \
399 dy[idx] = (ny); \
400 idx++; \
401 } else \
402 panic(floodfill_stack_overrun); \
403 } while (0)
404 #define SEL_FLOOD_CHKDIR(mx, my, sel) \
405 do { \
406 if (isok((mx), (my)) \
407 && (*selection_flood_check_func)((mx), (my)) \
408 && !selection_getpoint((mx), (my), (sel)) \
409 && !sel_flood_havepoint((mx), (my), dx, dy, idx)) \
410 SEL_FLOOD((mx), (my)); \
411 } while (0)
412 static const char floodfill_stack_overrun[] = "floodfill stack overrun";
413 int idx = 0;
414 coordxy dx[SEL_FLOOD_STACK];
415 coordxy dy[SEL_FLOOD_STACK];
417 if (selection_flood_check_func == (int (*)(coordxy, coordxy)) 0) {
418 selection_free(tmp, TRUE);
419 return;
421 SEL_FLOOD(x, y);
422 do {
423 idx--;
424 x = dx[idx];
425 y = dy[idx];
426 if (isok(x, y)) {
427 selection_setpoint(x, y, ov, 1);
428 selection_setpoint(x, y, tmp, 1);
430 SEL_FLOOD_CHKDIR((x + 1), y, tmp);
431 SEL_FLOOD_CHKDIR((x - 1), y, tmp);
432 SEL_FLOOD_CHKDIR(x, (y + 1), tmp);
433 SEL_FLOOD_CHKDIR(x, (y - 1), tmp);
434 if (diagonals) {
435 SEL_FLOOD_CHKDIR((x + 1), (y + 1), tmp);
436 SEL_FLOOD_CHKDIR((x - 1), (y - 1), tmp);
437 SEL_FLOOD_CHKDIR((x - 1), (y + 1), tmp);
438 SEL_FLOOD_CHKDIR((x + 1), (y - 1), tmp);
440 } while (idx > 0);
441 #undef SEL_FLOOD
442 #undef SEL_FLOOD_STACK
443 #undef SEL_FLOOD_CHKDIR
444 selection_free(tmp, TRUE);
447 /* McIlroy's Ellipse Algorithm */
448 void
449 selection_do_ellipse(
450 struct selectionvar *ov,
451 int xc, int yc,
452 int a, int b,
453 int filled)
454 { /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
455 int x = 0, y = b;
456 long a2 = (long) a * a, b2 = (long) b * b;
457 long crit1 = -(a2 / 4 + a % 2 + b2);
458 long crit2 = -(b2 / 4 + b % 2 + a2);
459 long crit3 = -(b2 / 4 + b % 2);
460 long t = -a2 * y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
461 long dxt = 2 * b2 * x, dyt = -2 * a2 * y;
462 long d2xt = 2 * b2, d2yt = 2 * a2;
463 long width = 1;
464 long i;
466 if (!ov)
467 return;
469 filled = !filled;
471 if (!filled) {
472 while (y >= 0 && x <= a) {
473 selection_setpoint(xc + x, yc + y, ov, 1);
474 if (x != 0 || y != 0)
475 selection_setpoint(xc - x, yc - y, ov, 1);
476 if (x != 0 && y != 0) {
477 selection_setpoint(xc + x, yc - y, ov, 1);
478 selection_setpoint(xc - x, yc + y, ov, 1);
480 if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */
481 || t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */
482 x++;
483 dxt += d2xt;
484 t += dxt;
485 } else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */
486 y--;
487 dyt += d2yt;
488 t += dyt;
489 } else {
490 x++;
491 dxt += d2xt;
492 t += dxt;
493 y--;
494 dyt += d2yt;
495 t += dyt;
498 } else {
499 while (y >= 0 && x <= a) {
500 if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */
501 || t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */
502 x++;
503 dxt += d2xt;
504 t += dxt;
505 width += 2;
506 } else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */
507 for (i = 0; i < width; i++)
508 selection_setpoint(xc - x + i, yc - y, ov, 1);
509 if (y != 0)
510 for (i = 0; i < width; i++)
511 selection_setpoint(xc - x + i, yc + y, ov, 1);
512 y--;
513 dyt += d2yt;
514 t += dyt;
515 } else {
516 for (i = 0; i < width; i++)
517 selection_setpoint(xc - x + i, yc - y, ov, 1);
518 if (y != 0)
519 for (i = 0; i < width; i++)
520 selection_setpoint(xc - x + i, yc + y, ov, 1);
521 x++;
522 dxt += d2xt;
523 t += dxt;
524 y--;
525 dyt += d2yt;
526 t += dyt;
527 width += 2;
533 /* square of distance from line segment (x1,y1, x2,y2) to point (x3,y3) */
534 staticfn long
535 line_dist_coord(long x1, long y1, long x2, long y2, long x3, long y3)
537 long px = x2 - x1;
538 long py = y2 - y1;
539 long s = px * px + py * py;
540 long x, y, dx, dy, distsq = 0;
541 float lu = 0;
543 if (x1 == x2 && y1 == y2)
544 return dist2(x1, y1, x3, y3);
546 lu = ((x3 - x1) * px + (y3 - y1) * py) / (float) s;
547 if (lu > 1)
548 lu = 1;
549 else if (lu < 0)
550 lu = 0;
552 x = x1 + lu * px;
553 y = y1 + lu * py;
554 dx = x - x3;
555 dy = y - y3;
556 distsq = dx * dx + dy * dy;
558 return distsq;
561 /* guts of l_selection_gradient */
562 void
563 selection_do_gradient(
564 struct selectionvar *ov,
565 long x, long y,
566 long x2,long y2,
567 long gtyp,
568 long mind, long maxd)
570 long dx, dy, dofs;
572 if (mind > maxd) {
573 long tmp = mind;
574 mind = maxd;
575 maxd = tmp;
578 dofs = maxd * maxd - mind * mind;
579 if (dofs < 1)
580 dofs = 1;
582 switch (gtyp) {
583 default:
584 impossible("Unrecognized gradient type! Defaulting to radial...");
585 FALLTHROUGH;
586 /* FALLTHRU */
587 case SEL_GRADIENT_RADIAL: {
588 for (dx = 0; dx < COLNO; dx++)
589 for (dy = 0; dy < ROWNO; dy++) {
590 long d0 = line_dist_coord(x, y, x2, y2, dx, dy);
592 if (d0 <= mind * mind
593 || (d0 <= maxd * maxd && d0 - mind * mind < rn2(dofs)))
594 selection_setpoint(dx, dy, ov, 1);
596 break;
598 case SEL_GRADIENT_SQUARE: {
599 for (dx = 0; dx < COLNO; dx++)
600 for (dy = 0; dy < ROWNO; dy++) {
601 long d1 = line_dist_coord(x, y, x2, y2, x, dy);
602 long d2 = line_dist_coord(x, y, x2, y2, dx, y);
603 long d3 = line_dist_coord(x, y, x2, y2, x2, dy);
604 long d4 = line_dist_coord(x, y, x2, y2, dx, y2);
605 long d5 = line_dist_coord(x, y, x2, y2, dx, dy);
606 long d0 = min(d5, min(max(d1, d2), max(d3, d4)));
608 if (d0 <= mind * mind
609 || (d0 <= maxd * maxd && d0 - mind * mind < rn2(dofs)))
610 selection_setpoint(dx, dy, ov, 1);
612 break;
613 } /*case*/
614 } /*switch*/
617 /* bresenham line algo */
618 void
619 selection_do_line(
620 coordxy x1, coordxy y1,
621 coordxy x2, coordxy y2,
622 struct selectionvar *ov)
624 int d0, dx, dy, ai, bi, xi, yi;
626 if (x1 < x2) {
627 xi = 1;
628 dx = x2 - x1;
629 } else {
630 xi = -1;
631 dx = x1 - x2;
633 if (y1 < y2) {
634 yi = 1;
635 dy = y2 - y1;
636 } else {
637 yi = -1;
638 dy = y1 - y2;
641 selection_setpoint(x1, y1, ov, 1);
643 if (!dx && !dy) {
644 /* single point - already all done */
646 } else if (dx > dy) {
647 ai = (dy - dx) * 2;
648 bi = dy * 2;
649 d0 = bi - dx;
650 do {
651 if (d0 >= 0) {
652 y1 += yi;
653 d0 += ai;
654 } else
655 d0 += bi;
656 x1 += xi;
657 selection_setpoint(x1, y1, ov, 1);
658 } while (x1 != x2);
659 } else {
660 ai = (dx - dy) * 2;
661 bi = dx * 2;
662 d0 = bi - dy;
663 do {
664 if (d0 >= 0) {
665 x1 += xi;
666 d0 += ai;
667 } else
668 d0 += bi;
669 y1 += yi;
670 selection_setpoint(x1, y1, ov, 1);
671 } while (y1 != y2);
675 void
676 selection_do_randline(
677 coordxy x1, coordxy y1,
678 coordxy x2, coordxy y2,
679 schar rough,
680 schar rec,
681 struct selectionvar *ov)
683 int mx, my;
684 int dx, dy;
686 if (rec < 1 || (x2 == x1 && y2 == y1))
687 return;
689 if (rough > max(abs(x2 - x1), abs(y2 - y1)))
690 rough = max(abs(x2 - x1), abs(y2 - y1));
692 if (rough < 2) {
693 mx = ((x1 + x2) / 2);
694 my = ((y1 + y2) / 2);
695 } else {
696 do {
697 dx = rn2(rough) - (rough / 2);
698 dy = rn2(rough) - (rough / 2);
699 mx = ((x1 + x2) / 2) + dx;
700 my = ((y1 + y2) / 2) + dy;
701 } while ((mx > COLNO - 1 || mx < 0 || my < 0 || my > ROWNO - 1));
704 if (!selection_getpoint(mx, my, ov)) {
705 selection_setpoint(mx, my, ov, 1);
708 rough = (rough * 2) / 3;
710 rec--;
712 selection_do_randline(x1, y1, mx, my, rough, rec, ov);
713 selection_do_randline(mx, my, x2, y2, rough, rec, ov);
715 selection_setpoint(x2, y2, ov, 1);
718 void
719 selection_iterate(
720 struct selectionvar *ov,
721 select_iter_func func,
722 genericptr_t arg)
724 coordxy x, y;
725 NhRect rect = cg.zeroNhRect;
727 if (!ov)
728 return;
730 selection_getbounds(ov, &rect);
732 for (x = rect.lx; x <= rect.hx; x++)
733 for (y = rect.ly; y <= rect.hy; y++)
734 if (isok(x,y) && selection_getpoint(x, y, ov))
735 (*func)(x, y, arg);
738 /* selection is not rectangular, or has holes in it */
739 boolean
740 selection_is_irregular(struct selectionvar *sel)
742 coordxy x, y;
743 NhRect rect = cg.zeroNhRect;
745 selection_getbounds(sel, &rect);
747 for (x = rect.lx; x <= rect.hx; x++)
748 for (y = rect.ly; y <= rect.hy; y++)
749 if (isok(x,y) && !selection_getpoint(x, y, sel))
750 return TRUE;
752 return FALSE;
755 /* return a description of the selection size */
756 char *
757 selection_size_description(struct selectionvar *sel, char *buf)
759 NhRect rect = cg.zeroNhRect;
760 coordxy dx, dy;
762 selection_getbounds(sel, &rect);
763 dx = rect.hx - rect.lx + 1;
764 dy = rect.hy - rect.ly + 1;
765 Sprintf(buf, "%s %i by %i",
766 selection_is_irregular(sel) ? "irregularly shaped"
767 : (dx == dy) ? "square"
768 : "rectangular",
769 dx, dy);
770 return buf;
773 struct selectionvar *
774 selection_from_mkroom(struct mkroom *croom)
776 struct selectionvar *sel = selection_new();
777 coordxy x, y;
778 unsigned rmno;
780 if (!croom && gc.coder && gc.coder->croom)
781 croom = gc.coder->croom;
782 if (!croom)
783 return sel;
785 rmno = (unsigned)((croom - svr.rooms) + ROOMOFFSET);
786 for (y = croom->ly; y <= croom->hy; y++)
787 for (x = croom->lx; x <= croom->hx; x++)
788 if (isok(x, y) && !levl[x][y].edge
789 && levl[x][y].roomno == rmno)
790 selection_setpoint(x, y, sel, 1);
791 return sel;
794 void
795 selection_force_newsyms(struct selectionvar *sel)
797 coordxy x, y;
799 for (x = 1; x < sel->wid; x++)
800 for (y = 0; y < sel->hei; y++)
801 if (selection_getpoint(x, y, sel))
802 newsym_force(x, y);
805 /*selvar.c*/