1 /* NetHack may be freely redistributed. See license for details. */
2
3 #include "vulture_sdl.h" /* XXX this must be the first include,
4 no idea why but it won't compile otherwise */
5
6 extern "C" {
7 #include "hack.h"
8 }
9
10 #include "levelwin.h"
11 #include "hotspot.h"
12 #include "minimap.h"
13 #include "toolbar.h"
14 #include "contextmenu.h"
15 #include "map.h"
16 #include "messagewin.h"
17
18
19 #include "vulture_win.h"
20 #include "vulture_gra.h"
21 #include "vulture_opt.h"
22 #include "vulture_tile.h"
23 #include "vulture_mou.h"
24 #include "vulture_gen.h"
25 #include "vulture_main.h"
26
27 /* ??????????
28 * without this the file will occasionally fail to compile, seemingly at random
29 */
30 #undef min
31 #undef max
32 #define min(a, b) (((a) < (b)) ? (a) : (b))
33 #define max(a, b) (((a) > (b)) ? (a) : (b))
34
35 #define VULTURE_CLIPMARGIN 200
36
37
38 levelwin *levwin;
39 int vulture_map_draw_msecs = 0;
40 int vulture_map_draw_lastmove = 0;
41 int vulture_map_highlight_objects = 0;
42
43
levelwin(mapdata * data)44 levelwin::levelwin(mapdata *data) : window(NULL), map_data(data)
45 {
46 v_type = V_WINTYPE_LEVEL;
47
48 x = 0;
49 y = 0;
50 w = vulture_screen->w;
51 h = vulture_screen->h;
52 need_redraw = 1;
53
54
55 /* upper left scroll hotspot */
56 new hotspot(this, 0, 0, 20, 20, V_HOTSPOT_SCROLL_UPLEFT, "scroll diagonally");
57 /* upper right scroll hotspot */
58 new hotspot(this, w - 20, 0, 20, 20, V_HOTSPOT_SCROLL_UPRIGHT, "scroll diagonally");
59 /* left scroll hotspot */
60 new hotspot(this, 0, 20, 20, h - 40, V_HOTSPOT_SCROLL_LEFT, "scroll left");
61 /* right scroll hotspot */
62 new hotspot(this, w - 20, 20, 20, h - 40, V_HOTSPOT_SCROLL_RIGHT, "scroll right");
63 /* bottom left scroll hotspot */
64 new hotspot(this, 0, h - 20, 20, 20, V_HOTSPOT_SCROLL_DOWNLEFT, "scroll diagonally");
65 /* bottom scroll hotspot */
66 new hotspot(this, 20, h - 20, w - 40, 20, V_HOTSPOT_SCROLL_DOWN, "scroll down");
67 /* upper left scroll hotspot */
68 new hotspot(this, w - 20, h - 20, 20, 20, V_HOTSPOT_SCROLL_DOWNRIGHT, "scroll diagonally");
69
70 /* create the minimap now, so that it's drawn _under_ the message window */
71 new minimap(this, map_data);
72
73 /*NOTE: the upper scroll hotspot gets created later in ::init(),
74 * so that it covers the message window */
75
76 clip_tl_x = 999999;
77 clip_tl_y = 999999;
78 clip_br_x = 0;
79 clip_br_y = 0;
80
81 levwin = this;
82
83 map_data->add_viewer(this);
84 }
85
86
init()87 void levelwin::init()
88 {
89 int i, j;
90
91 /* Initialize map */
92 for (i = 0; i < ROWNO; i++) {
93 for (j = 0; j < COLNO; j++) {
94 map_deco[i][j] = 0;
95 room_indices[i][j] = 0;
96
97 clear_walls(i,j);
98 }
99 }
100
101 w = vulture_screen->w;
102 h = vulture_screen->h;
103
104 /* create the upper scroll hotspot. NOTE that all other scroll hotspots
105 // * are created earlier in the ctor */
106 new hotspot(this, 20, 0, w - 40, 20, V_HOTSPOT_SCROLL_UP, "scroll up");
107
108 /* Toolbar1: inventory, map, cast spell, extended commands */
109 const tb_buttondesc tb1_desc[6] = {
110 {V_HOTSPOT_BUTTON_INVENTORY, "Inventory"},
111 {V_HOTSPOT_BUTTON_MAP, "Map"},
112 {V_HOTSPOT_BUTTON_SPELLBOOK, "Cast spell"},
113 {V_HOTSPOT_BUTTON_EXTENDED, "Extended commands"},
114 {V_HOTSPOT_BUTTON_DISCOVERIES, "Show discoveries"},
115 {0,""}
116 };
117
118 new toolbar(this, V_WIN_TOOLBAR1, vulture_opts.show_actiontb,
119 w - 215, h - 84, V_FILENAME_TOOLBAR1, tb1_desc);
120
121 /* Toolbar 2: look at, previous messages, options, help */
122 const tb_buttondesc tb2_desc[6] = {
123 {V_HOTSPOT_BUTTON_GOLD, "Gold"},
124 {V_HOTSPOT_BUTTON_LOOK, "Look"},
125 {V_HOTSPOT_BUTTON_MESSAGES, "Old messages"},
126 {V_HOTSPOT_BUTTON_OPTIONS, "Options"},
127 {V_HOTSPOT_BUTTON_IFOPTIONS, "Interface Options"},
128 {V_HOTSPOT_BUTTON_HELP, "Help"}
129 };
130
131 new toolbar(this, V_WIN_TOOLBAR2, vulture_opts.show_helptb,
132 w - 255, h - 45, V_FILENAME_TOOLBAR2, tb2_desc);
133
134 /* select wall style */
135 switch (vulture_opts.wall_style)
136 {
137 case V_WALL_DISPLAY_STYLE_FULL:
138 walltiles = (struct walls*)walls_full; break;
139
140 case V_WALL_DISPLAY_STYLE_HALF_HEIGHT:
141 walltiles = (struct walls*)walls_half; break;
142
143 default:
144 walltiles = (struct walls*)walls_half; break;
145 }
146
147 view_x = COLNO/2;
148 view_y = ROWNO/2;
149 }
150
151
~levelwin()152 levelwin::~levelwin()
153 {
154 map_data->del_viewer(this);
155 }
156
157
set_view(int x,int y)158 void levelwin::set_view(int x, int y)
159 {
160 view_x = x;
161 view_y = y;
162 }
163
164
165 /* check whether the map needs recentering */
need_recenter(int map_x,int map_y)166 bool levelwin::need_recenter(int map_x, int map_y)
167 {
168 int screen_x, screen_y;
169
170 map_x -= view_x;
171 map_y -= view_y;
172 screen_x = vulture_screen->w/2 + V_MAP_XMOD*(map_x - map_y);
173 screen_y = vulture_screen->h/2 + V_MAP_YMOD*(map_x + map_y);
174
175 /* if the player is within the outer 1/4 of the screen, the map needs recentering */
176 if ((screen_x >= vulture_screen->w/4) && (screen_x < vulture_screen->w * 3 / 4) &&
177 (screen_y >= vulture_screen->h/4) && (screen_y < vulture_screen->h * 3 / 4))
178 return true;
179
180 return false;
181 }
182
183
force_redraw(void)184 void levelwin::force_redraw(void)
185 {
186 need_redraw = 1;
187
188 clip_tl_x = 0;
189 clip_tl_y = 0;
190 clip_br_x = w;
191 clip_br_y = h;
192 }
193
194
195
draw()196 bool levelwin::draw()
197 {
198 int i, j, dir_idx;
199 vulture_tile * cur_tile;
200 int x, y;
201 int tile_id, shadelevel;
202 int map_tr_x, map_tr_y, __i, __j, diff, sum;
203 int map_centre_x = this->w / 2;
204 int map_centre_y = this->h / 2;
205 int map_back, map_darkness, map_obj, map_mon;
206
207 unsigned long startticks = SDL_GetTicks();
208
209 static int cur_dlevel = -1;
210 static int prev_cx = -1;
211 static int prev_cy = -1;
212
213 if (cur_dlevel != u.uz.dlevel)
214 {
215 init_floor_decors(10);
216 cur_dlevel = u.uz.dlevel;
217 }
218
219
220 if (prev_cx != view_x ||
221 prev_cy != view_y ||
222 map_data->map_swallow != V_TILE_NONE)
223 {
224 clip_tl_x = this->abs_x;
225 clip_tl_y = this->abs_y;
226 clip_br_x = this->abs_x + this->w;
227 clip_br_y = this->abs_y + this->h;
228 }
229 else
230 {
231 clip_tl_x = min(clip_tl_x, 0);
232 clip_tl_y = min(clip_tl_y, 0);
233 clip_br_x = max(clip_br_x, this->abs_x + this->w - 1);
234 clip_br_y = max(clip_br_y, this->abs_y + this->h - 1);
235 }
236
237 if (clip_tl_x >= this->w + this->abs_x ||
238 clip_tl_y >= this->h + this->abs_y)
239 /* nothing changed onscreen */
240 return 1;
241
242 prev_cx = view_x;
243 prev_cy = view_y;
244
245 /* Only draw on map area */
246 vulture_set_draw_region(clip_tl_x, clip_tl_y,
247 clip_br_x, clip_br_y);
248
249 /* If swallowed draw ONLY the engulf tile and the player! */
250 if (u.uswallow && map_data->map_swallow != V_TILE_NONE) {
251 /* Clear map area */
252 SDL_FillRect(vulture_screen, NULL, CLR32_BLACK);
253
254 x = map_centre_x + V_MAP_XMOD*(u.ux - u.uy + view_y - view_x);
255 y = map_centre_y + V_MAP_YMOD*(u.ux + u.uy - view_y - view_x);
256
257 /* engulf tile */
258 vulture_put_tile(x, y, map_data->map_swallow);
259
260 /* player */
261 vulture_put_tile(x, y, map_data->get_glyph(MAP_MON, u.ux, u.uy));
262
263 vulture_invalidate_region(clip_tl_x, clip_tl_y,
264 clip_br_x - clip_tl_x,
265 clip_br_y - clip_tl_y);
266 return 1;
267 }
268 else
269 map_data->map_swallow = V_TILE_NONE;
270
271
272 /* prevent double redraws if the map view just moved under the mouse cursor */
273 map_highlight = mouse_to_map(vulture_get_mouse_pos());
274
275 /* coords of the top right corner */
276 map_tr_x = (-V_MAP_YMOD * (map_centre_x + 50) + V_MAP_XMOD * (map_centre_y + 50) +
277 V_MAP_XMOD * V_MAP_YMOD) / (2 * V_MAP_XMOD * V_MAP_YMOD);
278 map_tr_y = (V_MAP_YMOD * (map_centre_x + 50) + V_MAP_XMOD * (map_centre_y + 50) +
279 V_MAP_XMOD * V_MAP_YMOD) / (2 * V_MAP_XMOD * V_MAP_YMOD);
280
281 /* without the +-1 small corners within the viewport are not drawn */
282 diff = map_tr_x - map_tr_y - 1;
283 sum = map_tr_x + map_tr_y + 1;
284
285 for (__i = - map_tr_y; __i <= map_tr_y; __i++)
286 {
287 i = view_y + __i;
288
289 for (__j = diff + __i; __j + __i <= sum; __j++)
290 {
291 j = view_x + __j;
292
293 x = map_centre_x + V_MAP_XMOD*(__j - __i);
294 y = map_centre_y + V_MAP_YMOD*(__j + __i);
295
296 if (j < 1 || j >= COLNO || i < 0 || i >= ROWNO)
297 {
298 vulture_put_tile(x, y, V_MISC_OFF_MAP);
299 continue;
300 }
301
302 map_back = map_data->get_glyph(MAP_BACK, j, i);
303 map_darkness = map_data->get_glyph(MAP_DARKNESS, j, i);
304
305 /*
306 Draw Vulture's tiles, in order:
307 pass 1
308 1. Floor
309 2. Floor edges
310
311 pass 2
312 1. North & west walls
313 2. Furniture
314 3. Traps
315 4. Objects
316 5. Monsters
317 6. Effects
318 7. South & east walls
319 */
320
321 /* 0. init walls and floor edges for this tile*/
322 if (map_back == V_TILE_WALL_GENERIC ||
323 map_back == V_MISC_UNMAPPED_AREA)
324 get_wall_tiles(i, j);
325 else
326 /* certain events (amnesia or a secret door being discovered)
327 * require us to clear walls again. since we cannot check for those cases
328 * we simply clear walls whenever we don't set any... */
329 clear_walls(i, j);
330
331 if (map_back == V_TILE_FLOOR_WATER ||
332 map_back == V_TILE_FLOOR_ICE ||
333 map_back == V_TILE_FLOOR_LAVA ||
334 map_back == V_TILE_FLOOR_AIR)
335 /* these tiles get edges */
336 get_floor_edges(i, j);
337 else
338 /* everything else doesn't. However we can't just assume a tile that doesn't need egdes doesn't have any:
339 * pools may be dried out by fireballs, and suddenly we have a pit with edges :(
340 * Therefore we always clear them explicitly */
341 clear_floor_edges(i ,j);
342
343
344 /* 2. Floor */
345 tile_id = map_back;
346 shadelevel = 0;
347
348 if ((tile_id >= V_TILE_FLOOR_COBBLESTONE) &&
349 (tile_id <= V_TILE_FLOOR_DARK)) {
350 tile_id = get_floor_tile(tile_id, i, j);
351 shadelevel = map_darkness;
352 }
353 else if(tile_id == V_TILE_NONE || tile_id == V_TILE_WALL_GENERIC)
354 tile_id = V_MISC_UNMAPPED_AREA;
355
356 vulture_put_tile_shaded(x, y, tile_id, shadelevel);
357
358 /* shortcut for unmapped case */
359 if (tile_id == V_MISC_UNMAPPED_AREA)
360 continue;
361
362 if (vulture_opts.highlight_cursor_square &&
363 (j == map_highlight.x && i == map_highlight.y))
364 vulture_put_tile(x, y, V_MISC_FLOOR_HIGHLIGHT);
365
366 /* 3. Floor edges */
367 for (dir_idx = 0; dir_idx < 12; dir_idx++)
368 vulture_put_tile(x, y, maptile_floor_edge[i][j].dir[dir_idx]);
369 }
370 }
371
372 for (__i = - map_tr_y; __i <= map_tr_y; __i++)
373 {
374 i = view_y + __i;
375 if (i < 0 || i >= ROWNO)
376 continue;
377
378 for (__j = diff + __i; __j + __i <= sum; __j++)
379 {
380 j = view_x + __j;
381 if (j < 1 || j >= COLNO)
382 continue;
383 /* Find position of tile centre */
384 x = map_centre_x + V_MAP_XMOD*(__j - __i);
385 y = map_centre_y + V_MAP_YMOD*(__j + __i);
386
387 map_back = map_data->get_glyph(MAP_BACK, j, i);
388 map_obj = map_data->get_glyph(MAP_OBJ, j, i);
389 map_mon = map_data->get_glyph(MAP_MON, j, i);
390
391 /* 1. West and north walls */
392 if (j > 1)
393 vulture_put_tile_shaded(x, y, maptile_wall[i][j].west,
394 map_data->get_glyph(MAP_DARKNESS, j-1, i));
395 if (i > 1)
396 vulture_put_tile_shaded(x, y, maptile_wall[i][j].north,
397 map_data->get_glyph(MAP_DARKNESS, j, i-1));
398
399 /* shortcut for unmapped case */
400 if (map_back != V_MISC_UNMAPPED_AREA ||
401 map_obj != V_TILE_NONE) {
402 /* 2. Furniture*/
403 vulture_put_tile(x, y, map_data->get_glyph(MAP_FURNITURE, j, i));
404
405
406 /* 3. Traps */
407 vulture_put_tile(x, y, map_data->get_glyph(MAP_TRAP, j, i));
408
409
410 /* 4. Objects */
411 vulture_put_tile(x, y, map_obj);
412
413
414 /* 5. Monsters */
415 if ((cur_tile = vulture_get_tile(map_mon)) != NULL) {
416 vulture_put_tile(x, y, map_mon);
417 if (iflags.hilite_pet && map_data->get_glyph(MAP_PET, j, i))
418 vulture_put_img(x + cur_tile->xmod, y + cur_tile->ymod - 10,
419 vulture_get_tile(V_MISC_HILITE_PET)->graphic);
420 }
421
422 /* 6. Effects */
423 vulture_put_tile(x, y, map_data->get_glyph(MAP_SPECIAL, j, i));
424 }
425
426 /* 7. South & East walls */
427 if (i < ROWNO - 1)
428 vulture_put_tile_shaded(x, y, maptile_wall[i][j].south,
429 map_data->get_glyph(MAP_DARKNESS, j, i+1));
430 if (j < COLNO - 1)
431 vulture_put_tile_shaded(x, y, maptile_wall[i][j].east,
432 map_data->get_glyph(MAP_DARKNESS, j+1, i));
433 }
434 }
435
436 /* draw object highlights if requested */
437 if (vulture_map_highlight_objects)
438 {
439 for (__i = - map_tr_y; __i <= map_tr_y; __i++)
440 {
441 i = view_y + __i;
442 if (i < 0 || i >= ROWNO)
443 continue;
444
445 for (__j = diff + __i; __j + __i <= sum; __j++)
446 {
447 j = view_x + __j;
448 if (j < 1 || j >= COLNO)
449 continue;
450
451 x = map_centre_x + V_MAP_XMOD*(__j - __i);
452 y = map_centre_y + V_MAP_YMOD*(__j + __i);
453
454 vulture_put_tilehighlight(x, y, map_data->get_glyph(MAP_OBJ, j, i));
455 }
456 }
457 }
458 /* Restore drawing region */
459 vulture_set_draw_region(0, 0, vulture_screen->w-1, vulture_screen->h-1);
460
461 vulture_invalidate_region(clip_tl_x, clip_tl_y,
462 clip_br_x - clip_tl_x,
463 clip_br_y - clip_tl_y);
464
465 clip_tl_x = 999999;
466 clip_tl_y = 999999;
467 clip_br_x = 0;
468 clip_br_y = 0;
469
470 vulture_tilecache_age();
471
472 vulture_map_draw_msecs = SDL_GetTicks() - startticks;
473 vulture_map_draw_lastmove = moves;
474
475 return true;
476 }
477
478
handle_timer_event(window * target,void * result,int time)479 eventresult levelwin::handle_timer_event(window* target, void* result, int time)
480 {
481 std::string ttext;
482 point mappos, mouse;
483
484 mouse = vulture_get_mouse_pos();
485 mappos = mouse_to_map(mouse);
486
487 /* hovering on a border: scroll */
488 if (target != this && target->menu_id)
489 {
490 int increment = (time / 500) + 1;
491 switch (target->menu_id)
492 {
493 case V_HOTSPOT_SCROLL_UPLEFT:
494 view_x-=increment; break;
495 case V_HOTSPOT_SCROLL_UP:
496 view_x-=increment; view_y-=increment; break;
497 case V_HOTSPOT_SCROLL_UPRIGHT:
498 view_y-=increment; break;
499 case V_HOTSPOT_SCROLL_LEFT:
500 view_x-=increment; view_y+=increment; break;
501 case V_HOTSPOT_SCROLL_RIGHT:
502 view_x+=increment; view_y-=increment; break;
503 case V_HOTSPOT_SCROLL_DOWNLEFT:
504 view_y+=increment; break;
505 case V_HOTSPOT_SCROLL_DOWN:
506 view_x+=increment; view_y+=increment; break;
507 case V_HOTSPOT_SCROLL_DOWNRIGHT:
508 view_x+=increment; break;
509 }
510
511 view_x = (view_x < 0) ? 0 : view_x;
512 view_y = (view_y < 0) ? 0 : view_y;
513 view_x = (view_x > COLNO) ? COLNO : view_x;
514 view_y = (view_y > ROWNO) ? ROWNO : view_y;
515
516 need_redraw = 1;
517 return V_EVENT_HANDLED_REDRAW;
518 }
519
520 /* hovering over the map: display a tooltip */
521 if (time < HOVERTIMEOUT)
522 return V_EVENT_HANDLED_NOREDRAW;
523
524 if (target != this && !target->caption.empty())
525 vulture_mouse_set_tooltip(target->caption);
526 else {
527 ttext = map_data->map_square_description(mappos, 1);
528 if(!ttext.empty())
529 vulture_mouse_set_tooltip(ttext);
530 }
531
532 return V_EVENT_HANDLED_NOREDRAW;
533 }
534
535
handle_mousemotion_event(window * target,void * result,int xrel,int yrel,int state)536 eventresult levelwin::handle_mousemotion_event(window* target, void* result, int xrel,
537 int yrel, int state)
538 {
539 point mouse, mappos;
540
541 mouse = vulture_get_mouse_pos();
542 mappos = mouse_to_map(mouse);
543
544 if (target != this && target->menu_id)
545 {
546 /* show a map scroll cursor if the mouse is in the edge zone */
547 switch (target->menu_id)
548 {
549 case V_HOTSPOT_SCROLL_UPLEFT:
550 vulture_set_mcursor(V_CURSOR_SCROLLUPLEFT); break;
551 case V_HOTSPOT_SCROLL_UP:
552 vulture_set_mcursor(V_CURSOR_SCROLLUP); break;
553 case V_HOTSPOT_SCROLL_UPRIGHT:
554 vulture_set_mcursor(V_CURSOR_SCROLLUPRIGHT); break;
555 case V_HOTSPOT_SCROLL_LEFT:
556 vulture_set_mcursor(V_CURSOR_SCROLLLEFT); break;
557 case V_HOTSPOT_SCROLL_RIGHT:
558 vulture_set_mcursor(V_CURSOR_SCROLLRIGHT); break;
559 case V_HOTSPOT_SCROLL_DOWNLEFT:
560 vulture_set_mcursor(V_CURSOR_SCROLLDOWNLEFT); break;
561 case V_HOTSPOT_SCROLL_DOWN:
562 vulture_set_mcursor(V_CURSOR_SCROLLDOWN); break;
563 case V_HOTSPOT_SCROLL_DOWNRIGHT:
564 vulture_set_mcursor(V_CURSOR_SCROLLDOWNRIGHT); break;
565 default:
566 vulture_set_mcursor(get_map_cursor(mappos));
567 }
568 }
569 else
570 /* select a cursor for the current position */
571 vulture_set_mcursor(get_map_cursor(mappos));
572
573 /* if the highlight option is on, store the map position of the mouse
574 * and refresh the current and previous positions */
575 if (vulture_opts.highlight_cursor_square &&
576 (map_highlight.x != mappos.x || map_highlight.y != mappos.y))
577 {
578 mouse = map_to_mouse(map_highlight);
579 add_to_clipregion(mouse.x - V_MAP_XMOD, mouse.y - V_MAP_YMOD,
580 mouse.x + V_MAP_XMOD, mouse.y + V_MAP_YMOD);
581 mouse = map_to_mouse(mappos);
582 add_to_clipregion(mouse.x - V_MAP_XMOD, mouse.y - V_MAP_YMOD,
583 mouse.x + V_MAP_XMOD, mouse.y + V_MAP_YMOD);
584
585 map_highlight = mappos;
586 need_redraw = 1;
587 return V_EVENT_HANDLED_REDRAW;
588 }
589
590 return V_EVENT_HANDLED_NOREDRAW;
591 }
592
593
handle_mousebuttonup_event(window * target,void * result,int mouse_x,int mouse_y,int button,int state)594 eventresult levelwin::handle_mousebuttonup_event(window* target, void* result,
595 int mouse_x, int mouse_y, int button, int state)
596 {
597 point mouse, mappos;
598
599 mouse = vulture_get_mouse_pos();
600 mappos = mouse_to_map(mouse);
601
602 return map_data->handle_click(result, button, mappos);
603 }
604
605
handle_keydown_event(window * target,void * result,int sym,int mod,int unicode)606 eventresult levelwin::handle_keydown_event(window* target, void* result, int sym, int mod, int unicode)
607 {
608 int translated_key, key;
609 int macronum, i;
610
611 switch (sym) {
612 case SDLK_TAB:
613 map::toggle();
614 return V_EVENT_HANDLED_REDRAW;
615
616 /* F1- F6 trigger macros */
617 case SDLK_F1:
618 case SDLK_F2:
619 case SDLK_F3:
620 case SDLK_F4:
621 case SDLK_F5:
622 case SDLK_F6:
623 macronum = sym - SDLK_F1;
624 if (!vulture_opts.macro[macronum][0])
625 break;
626
627 ((vulture_event*)result)->num = vulture_opts.macro[macronum][0];
628 for (i = strlen(vulture_opts.macro[macronum]) - 1; i > 0; i--)
629 vulture_eventstack_add(vulture_opts.macro[macronum][i], -1, -1, V_RESPOND_ANY);
630 return V_EVENT_HANDLED_FINAL;
631
632 /* CTRL+SHIFT+o opens the interface options */
633 case SDLK_o:
634 if (!(mod & KMOD_SHIFT) || !(mod & KMOD_CTRL))
635 break;
636 vulture_iface_opts();
637 return V_EVENT_HANDLED_REDRAW;
638
639 /* CTRL+SHIFT+p shows the message log */
640 case SDLK_p:
641 if (!(mod & KMOD_SHIFT) || !(mod & KMOD_CTRL))
642 break;
643 msgwin->view_all();
644 return V_EVENT_HANDLED_REDRAW;
645
646 default:
647 break;
648 }
649
650 /* all other keys are converted and passed to the core */
651 key = vulture_make_nh_key(sym, mod, unicode);
652
653 if (!key)
654 return V_EVENT_HANDLED_NOREDRAW;
655
656 if (mapwin && isdigit(key))
657 translated_key = key;
658 else
659 translated_key = vulture_translate_key(key);
660
661 if (translated_key) {
662 ((vulture_event*)result)->num = translated_key;
663 return V_EVENT_HANDLED_FINAL;
664 }
665 return V_EVENT_HANDLED_NOREDRAW;
666 }
667
668
handle_resize_event(window * target,void * result,int res_w,int res_h)669 eventresult levelwin::handle_resize_event(window* target, void* result, int res_w, int res_h)
670 {
671 window *winelem;
672
673 if (this == target) {
674 w = res_w;
675 h = res_h;
676
677 /* update window scrolling activation regions */
678 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
679 switch (winelem->menu_id) {
680 /* case V_HOTSPOT_SCROLL_UPLEFT: never needs updating on resize*/
681 case V_HOTSPOT_SCROLL_UP:
682 winelem->w = w - 40;
683 break;
684
685 case V_HOTSPOT_SCROLL_UPRIGHT:
686 winelem->x = w - 20;
687 break;
688
689 case V_HOTSPOT_SCROLL_LEFT:
690 winelem->h = h - 40;
691 break;
692
693 case V_HOTSPOT_SCROLL_RIGHT:
694 winelem->h = h - 40;
695 winelem->x = w - 20;
696 break;
697
698 case V_HOTSPOT_SCROLL_DOWNLEFT:
699 winelem->y = h - 20;
700 break;
701
702 case V_HOTSPOT_SCROLL_DOWN:
703 winelem->y = h - 20;
704 winelem->w = w - 40;
705 break;
706
707 case V_HOTSPOT_SCROLL_DOWNRIGHT:
708 winelem->x = w - 20;
709 winelem->y = h - 20;
710 break;
711 }
712 }
713 }
714 return V_EVENT_HANDLED_NOREDRAW;
715 }
716
717
map_update(glyph_type type,int prev_glyph,int new_glyph,int x,int y)718 void levelwin::map_update(glyph_type type, int prev_glyph, int new_glyph, int x, int y)
719 {
720 int pixel_x, pixel_y;
721 int tl_x = 99999, tl_y = 99999, br_x = 0, br_y = 0;
722 vulture_tile *oldtile, *newtile;
723
724 pixel_x = (this->w / 2) + V_MAP_XMOD*(x - y + view_y - view_x);
725 pixel_y = (this->h / 2) + V_MAP_YMOD*(x + y - view_y - view_x);
726
727 if (pixel_x < -VULTURE_CLIPMARGIN ||
728 pixel_y < -VULTURE_CLIPMARGIN ||
729 pixel_x > vulture_screen->w + VULTURE_CLIPMARGIN ||
730 pixel_y > vulture_screen->h + VULTURE_CLIPMARGIN)
731 return;
732
733 oldtile = vulture_get_tile(prev_glyph);
734 newtile = vulture_get_tile(new_glyph);
735
736 if (type != MAP_BACK) {
737 if (oldtile) {
738 tl_x = oldtile->xmod;
739 tl_y = oldtile->ymod;
740
741 br_x = oldtile->xmod + oldtile->graphic->w;
742 br_y = oldtile->ymod + oldtile->graphic->h;
743 }
744
745 if (newtile) {
746 tl_x = min(newtile->xmod, tl_x);
747 tl_y = min(newtile->ymod, tl_y);
748
749 br_x = max(br_x, newtile->xmod + newtile->graphic->w);
750 br_y = max(br_y, newtile->ymod + newtile->graphic->h);
751 }
752
753 tl_x += pixel_x;
754 tl_y += pixel_y;
755 br_x += pixel_x;
756 br_y += pixel_y;
757
758 if (type == MAP_MON)
759 /* allow for the heart icon on pets */
760 tl_y -= 10;
761 }
762 else {
763 /* floor tiles tend to be placeholders until we reach draw_level,
764 * so we do this manually */
765 tl_x = pixel_x - 56;
766 tl_y = pixel_y - 100; /* 100 pixels accounts for possible walls, too */
767 br_x = pixel_x + 56;
768 br_y = pixel_y + 22;
769 }
770
771 add_to_clipregion(tl_x, tl_y, br_x, br_y);
772 }
773
774
map_clear()775 void levelwin::map_clear()
776 {
777 int i, j;
778
779 for (i = 0; i < ROWNO; i++)
780 for (j = 0; j < COLNO; j++) {
781 clear_floor_edges(i, j);
782 clear_walls(i, j);
783 }
784 }
785
mouse_to_map(point mouse)786 point levelwin::mouse_to_map(point mouse)
787 {
788 point mappos, px_offset;
789
790 px_offset.x = mouse.x - (w / 2) + (view_x - view_y) * V_MAP_XMOD;
791 px_offset.y = mouse.y - (h / 2) + (view_x + view_y)*V_MAP_YMOD;
792
793 mappos.x = ( V_MAP_YMOD * px_offset.x + V_MAP_XMOD * px_offset.y +
794 V_MAP_XMOD*V_MAP_YMOD)/(2*V_MAP_XMOD*V_MAP_YMOD);
795 mappos.y = (-V_MAP_YMOD * px_offset.x + V_MAP_XMOD * px_offset.y +
796 V_MAP_XMOD*V_MAP_YMOD)/(2*V_MAP_XMOD*V_MAP_YMOD);
797
798 return mappos;
799 }
800
801
map_to_mouse(point mappos)802 point levelwin::map_to_mouse(point mappos)
803 {
804 int map_centre_x = w / 2;
805 int map_centre_y = h / 2;
806 point mouse;
807
808 mouse.x = map_centre_x + V_MAP_XMOD*(mappos.x - mappos.y + view_y - view_x);
809 mouse.y = map_centre_y + V_MAP_YMOD*(mappos.x + mappos.y - view_y - view_x);
810
811 /* FIXME Why does this happen sometimes ? */
812 if ( mouse.x < 0 ) mouse.x = 0;
813 if ( mouse.y < 0 ) mouse.y = 0;
814
815 return mouse;
816 }
817
818
toggle_uiwin(int menuid,bool enabled)819 void levelwin::toggle_uiwin(int menuid, bool enabled)
820 {
821 window *win = this->first_child;
822 while (win)
823 {
824 if (win->menu_id == menuid)
825 win->visible = enabled;
826 win = win->sib_next;
827 }
828
829 force_redraw();
830 }
831
832
add_to_clipregion(int tl_x,int tl_y,int br_x,int br_y)833 void levelwin::add_to_clipregion(int tl_x, int tl_y, int br_x, int br_y)
834 {
835 clip_tl_x = min(clip_tl_x, tl_x);
836 clip_tl_y = min(clip_tl_y, tl_y);
837 clip_br_x = max(clip_br_x, br_x);
838 clip_br_y = max(clip_br_y, br_y);
839 }
840
841
set_wall_style(int style)842 void levelwin::set_wall_style(int style)
843 {
844 switch (style)
845 {
846 case V_WALL_DISPLAY_STYLE_FULL:
847 walltiles = (struct walls*)walls_full; break;
848 case V_WALL_DISPLAY_STYLE_HALF_HEIGHT:
849 walltiles = (struct walls*)walls_half; break;
850 }
851 }
852
853
854 /* get room index is only used to semi-randomly select room decorations
855 * therefore the number we return can be as bogus as we want, so long as
856 * it's consistently the same. Using the current depth will provide a bit of
857 * variety on the maze levels...*/
get_room_index(int x,int y)858 int levelwin::get_room_index(int x, int y)
859 {
860 int rindex;
861 if (nroom == 0) /* maze levels */
862 return u.uz.dlevel;
863
864 if (In_mines(&u.uz)) /* The mines are a patchwork dungeon otherwise :( */
865 return (u.uz.dlevel + nroom); /* cleverly prevent a repetitive sequence :P */
866
867 rindex = room_indices[y][x];
868 if (!rindex)
869 return (u.uz.dlevel + nroom);
870
871 return rindex;
872 }
873
874
875
876 /*
877 * Convert wall tile index (ie. wall type) to an associated decoration style.
878 */
get_wall_decor(int floortype,int wally,int wallx,int floory,int floorx)879 int levelwin::get_wall_decor(
880 int floortype,
881 int wally, int wallx,
882 int floory, int floorx
883 )
884 {
885 int roomid;
886
887 #ifdef REINCARNATION
888 if (Is_rogue_level(&u.uz))
889 return V_WALL_LIGHT;
890 #endif
891
892 switch (floortype)
893 {
894 case V_TILE_FLOOR_ROUGH:
895 case V_TILE_FLOOR_ROUGH_LIT:
896 return V_WALL_ROUGH;
897 case V_MISC_FLOOR_NOT_VISIBLE:
898 case V_TILE_FLOOR_COBBLESTONE:
899 {
900 roomid = get_room_index(floorx, floory);
901 switch(roomid % 4)
902 {
903 case 0: return V_WALL_STUCCO;
904 case 1: return V_WALL_BRICK + ((wally*wallx+wally+wallx)%5);
905 case 2: return V_WALL_VINE_COVERED;
906 case 3: return V_WALL_MARBLE;
907 }
908 }
909 default:
910 return V_WALL_BRICK;
911 }
912 }
913
914
915 /*
916 * Convert floor tile index (ie. floor type) to an associated decoration style.
917 */
get_floor_decor(int floorstyle,int floory,int floorx)918 int levelwin::get_floor_decor(int floorstyle, int floory, int floorx)
919 {
920 int roomid;
921 #ifdef REINCARNATION
922 if (Is_rogue_level(&u.uz))
923 return V_FLOOR_DARK;
924 #endif
925
926 switch (floorstyle)
927 {
928 case V_TILE_FLOOR_ROUGH: return V_FLOOR_ROUGH;
929 case V_TILE_FLOOR_ROUGH_LIT: return V_FLOOR_ROUGH_LIT;
930 case V_TILE_FLOOR_COBBLESTONE:
931 {
932 roomid = get_room_index(floorx, floory);
933 switch(roomid % 4)
934 {
935 case 0: return V_FLOOR_CERAMIC;
936 case 1: return V_FLOOR_COBBLESTONE;
937 case 2: return V_FLOOR_MOSS_COVERED;
938 case 3: return V_FLOOR_MARBLE;
939 }
940 }
941 case V_TILE_FLOOR_WATER: return V_FLOOR_WATER;
942 case V_TILE_FLOOR_ICE: return V_FLOOR_ICE;
943 case V_TILE_FLOOR_AIR: return V_FLOOR_AIR;
944 case V_TILE_FLOOR_LAVA: return V_FLOOR_LAVA;
945 case V_TILE_FLOOR_DARK: return V_FLOOR_DARK;
946 default: return V_FLOOR_COBBLESTONE;
947 }
948 }
949
950
951
init_floor_decors(int num_decors)952 void levelwin::init_floor_decors(int num_decors)
953 {
954 int i, j, k;
955 int lx, ly;
956
957 if (!nroom)
958 return; /* the level doesn't have distinct rooms, so do nothing */
959
960 /* after putting a decor in room roomno, we calculate (roomno + 5) modulo nroom.
961 * (nroom is the global containing the number of rooms on the level) */
962 int roomno = 0;
963 /* when roomno wraps we also add wrapadd, to ensure that a different bunch of rooms gets the next few decorations
964 * this will distibute decorations seemingly at random but repeatably throughout the level
965 * (rooms are sorted from left to right, so a step of 1 would leave most decorations on the left side)*/
966 int wrapadd = (nroom % 5) ? 0 : 1;
967
968 /* if placing a decor fails, try at most retries other rooms */
969 int retries;
970
971 /* did we manage to place the deco? */
972 int placed;
973
974 int old_deco, old_deco2;
975 int deco_height;
976 int deco_width;
977 int xoffset, yoffset;
978
979 int current_deco = V_FLOOR_CARPET;
980
981 /* reset the room indices and map decor arrays */
982 for (i = 0; i < ROWNO; i++)
983 {
984 memset(room_indices[i], 0, COLNO);
985 memset(map_deco[i], 0, COLNO);
986 }
987
988 /* init room indices */
989 for (i = 0; i < nroom; i++)
990 for (j = rooms[i].ly; j <= rooms[i].hy; j++)
991 memset(&room_indices[j][rooms[i].lx], (i+1), (rooms[i].hx-rooms[i].lx+1));
992
993 /* do no more if we're on the rogue level or in the mines, because decors there look dumb */
994 #ifdef REINCARNATION
995 if (Is_rogue_level(&u.uz))
996 return;
997 #endif
998 s_level * lev;
999 if (In_mines(&u.uz) && ((lev = Is_special(&u.uz)) == 0 || !lev->flags.town))
1000 return;
1001
1002 for (i = 0; i < num_decors; i++)
1003 {
1004 retries = nroom;
1005 placed = 0;
1006 switch (roomno % 3)
1007 {
1008 case 0: current_deco = V_FLOOR_CARPET; break;
1009 case 1: current_deco = V_FLOOR_MURAL; break;
1010 case 2: current_deco = V_FLOOR_MURAL2; break;
1011 }
1012
1013 deco_width = floorstyles[current_deco].x;
1014 deco_height = floorstyles[current_deco].y;
1015
1016 while (retries-- && !placed)
1017 {
1018 lx = rooms[roomno].lx;
1019 ly = rooms[roomno].ly;
1020 while (ly <= rooms[roomno].hy && (old_deco = (map_deco[ly][lx] >> 4)) != 0)
1021 {
1022 while (lx <= rooms[roomno].hx && (old_deco2 = (map_deco[ly][lx] >> 4)) != 0)
1023 lx += floorstyles[old_deco2-1].x;
1024 ly += floorstyles[old_deco-1].y;
1025 lx = rooms[roomno].lx;
1026 }
1027
1028 if ((rooms[roomno].hx - lx + 1) >= deco_width &&
1029 (rooms[roomno].hy - ly + 1) >= deco_height)
1030 {
1031 placed = 1;
1032 for (j=0; j<deco_height; j++)
1033 for (k=0; k<deco_width;k++)
1034 map_deco[ly+j][lx+k] = ((current_deco+1) << 4) + (j*deco_width+k);
1035 }
1036 }
1037
1038 if (!retries && !placed)
1039 /* placing this one failed, so trying to place others is futile */
1040 break;
1041
1042 roomno += 5;
1043 if (roomno > nroom)
1044 roomno = (roomno % nroom) + wrapadd;
1045 }
1046
1047 /* centre the decorations in the rooms, as the previous code always plces them in the top corner*/
1048 for (i = 0; i < nroom; i++)
1049 {
1050 lx = rooms[i].lx;
1051 ly = rooms[i].ly;
1052
1053 while (map_deco[ly][lx] != 0 && lx <= rooms[i].hx)
1054 lx++;
1055
1056 deco_width = lx - rooms[i].lx;
1057 lx = rooms[i].lx;
1058
1059 while (map_deco[ly][lx] != 0 && ly <= rooms[i].hy)
1060 ly++;
1061
1062 deco_height = ly - rooms[i].ly;
1063 xoffset = (int)((rooms[i].lx + rooms[i].hx + 1)/2.0 - deco_width/2.0);
1064 yoffset = (int)((rooms[i].ly + rooms[i].hy + 1)/2.0 - deco_height/2.0);
1065
1066 for (j = deco_height-1; j >= 0; j--)
1067 for (k = deco_width-1; k >= 0; k--)
1068 map_deco[yoffset + j][xoffset + k] = map_deco[rooms[i].ly + j][rooms[i].lx + k];
1069
1070 for (j = rooms[i].ly; j < yoffset; j++)
1071 memset(&map_deco[j][rooms[i].lx], 0, (rooms[i].hx-rooms[i].lx+1));
1072
1073 for (j = rooms[i].ly; j <= rooms[i].hy; j++)
1074 memset(&map_deco[j][rooms[i].lx], 0, (xoffset - rooms[i].lx));
1075 }
1076 }
1077
1078
get_wall_tiles(int y,int x)1079 void levelwin::get_wall_tiles(int y, int x)
1080 {
1081 int style;
1082 int bg_west, bg_north, bg_east, bg_south;
1083
1084 if (!level.locations[x][y].seenv)
1085 return;
1086
1087 /* x - 1: west wall */
1088 bg_west = map_data->get_glyph(MAP_BACK, x - 1, y);
1089 if (x > 0 && bg_west != V_TILE_WALL_GENERIC && bg_west != V_MISC_UNMAPPED_AREA) {
1090 style = get_wall_decor(bg_west, y, x, y, x-1);
1091 maptile_wall[y][x].west = walltiles[style].west;
1092 }
1093 else
1094 maptile_wall[y][x].west = V_TILE_NONE;
1095
1096 /* y - 1: north wall */
1097 bg_north = map_data->get_glyph(MAP_BACK, x, y - 1);
1098 if (y > 0 && bg_north != V_TILE_WALL_GENERIC && bg_north != V_MISC_UNMAPPED_AREA) {
1099 style = get_wall_decor(bg_north, y, x, y - 1, x);
1100 maptile_wall[y][x].north = walltiles[style].north;
1101 }
1102 else
1103 maptile_wall[y][x].north = V_TILE_NONE;
1104
1105 /* x + 1: east wall */
1106 bg_east = map_data->get_glyph(MAP_BACK, x + 1, y);
1107 if (x < COLNO - 1 && bg_east != V_TILE_WALL_GENERIC && bg_east != V_MISC_UNMAPPED_AREA) {
1108 style = get_wall_decor(bg_east, y, x, y, x + 1);
1109 maptile_wall[y][x].east = walltiles[style].east;
1110 }
1111 else
1112 maptile_wall[y][x].east = V_TILE_NONE;
1113
1114 /* y + 1: south wall */
1115 bg_south = map_data->get_glyph(MAP_BACK, x, y + 1);
1116 if (y < ROWNO - 1 && bg_south != V_TILE_WALL_GENERIC && bg_south != V_MISC_UNMAPPED_AREA) {
1117 style = get_wall_decor(bg_south, y, x, y + 1, x);
1118 maptile_wall[y][x].south = walltiles[style].south;
1119 }
1120 else
1121 maptile_wall[y][x].south = V_TILE_NONE;
1122 }
1123
1124
1125
get_floor_tile(int tile,int y,int x)1126 int levelwin::get_floor_tile(int tile, int y, int x)
1127 {
1128 int style;
1129 int deco_pos;
1130 unsigned char deco = map_deco[y][x];
1131
1132 if (deco && tile == V_TILE_FLOOR_COBBLESTONE) {
1133 style = (deco >> 4) - 1;
1134 deco_pos = (int)(deco & 0x0F);
1135 return floorstyles[style].array[deco_pos];
1136 }
1137
1138 style = get_floor_decor(tile, y, x);
1139 deco_pos = floorstyles[style].x * (y % floorstyles[style].y) + (x % floorstyles[style].x);
1140 return floorstyles[style].array[deco_pos];
1141 }
1142
1143
1144
get_floor_edges(int y,int x)1145 void levelwin::get_floor_edges(int y, int x)
1146 {
1147 int i, x2, y2;
1148 int tile = map_data->get_glyph(MAP_BACK, x, y);
1149 int style = V_FLOOR_EDGE_COBBLESTONE;
1150
1151 point s_delta[4] = {{-1,0}, {0,-1}, {1,0}, {0,1}};
1152 point d_delta[4] = {{-1,1}, {-1,-1}, {1,-1}, {1,1}};
1153
1154 /* Default: no floor edges around tile */
1155 clear_floor_edges(y, x);
1156
1157 /* straight sections */
1158 for (i = 0; i < 4; i++) {
1159 x2 = x+s_delta[i].x;
1160 y2 = y+s_delta[i].y;
1161 if (x > 0 && x < COLNO-s_delta[i].x && y > 0 && y < ROWNO-s_delta[i].y &&
1162 tile != map_data->get_glyph(MAP_BACK, x2, y2) &&
1163 tile + map_data->get_glyph(MAP_BACK, x2, y2) !=
1164 V_TILE_FLOOR_WATER + V_TILE_FLOOR_ICE) /* this prevents borders between water and ice*/
1165 maptile_floor_edge[y][x].dir[i] = flooredges[style].dir[i];
1166 }
1167
1168
1169 /* "inward pointing" corners */
1170 for (i = 4; i < 8; i++) {
1171 if ((maptile_floor_edge[y][x].dir[(i+3)%4] != V_TILE_NONE) &&
1172 (maptile_floor_edge[y][x].dir[i%4]) != V_TILE_NONE)
1173
1174 maptile_floor_edge[y][x].dir[i] = flooredges[style].dir[i];
1175 }
1176
1177
1178 /* "outward pointing" corners */
1179 for (i = 8; i < 12; i++) {
1180 x2 = x+d_delta[i%4].x;
1181 y2 = y+d_delta[i%4].y;
1182 if ((maptile_floor_edge[y][x].dir[(i+3)%4] == V_TILE_NONE) &&
1183 (maptile_floor_edge[y][x].dir[i%4] == V_TILE_NONE) &&
1184 x > 0 && x < COLNO - 1 && y > 0 && y < ROWNO - 1 &&
1185 tile != map_data->get_glyph(MAP_BACK, x2, y2) &&
1186 tile + map_data->get_glyph(MAP_BACK, x2, y2) !=
1187 V_TILE_FLOOR_WATER + V_TILE_FLOOR_ICE)
1188 maptile_floor_edge[y][x].dir[i] = flooredges[style].dir[i];
1189 }
1190
1191 /* for (i = 0; i < 12; i++)
1192 if (!maptile_floor_edge[y][x].dir[i])
1193 maptile_floor_edge[y][x].dir[i] = V_TILE_NONE;*/
1194 }
1195
clear_walls(int y,int x)1196 void levelwin::clear_walls(int y, int x)
1197 {
1198 maptile_wall[y][x].west = V_TILE_NONE;
1199 maptile_wall[y][x].north = V_TILE_NONE;
1200 maptile_wall[y][x].east = V_TILE_NONE;
1201 maptile_wall[y][x].south = V_TILE_NONE;
1202 }
1203
1204
1205
clear_floor_edges(int y,int x)1206 void levelwin::clear_floor_edges(int y, int x)
1207 {
1208 int i;
1209 for (i = 0; i < 12; i++)
1210 maptile_floor_edge[y][x].dir[i] = V_TILE_NONE;
1211 }
1212
1213
1214 /* select an appropriate cursor for the given location */
get_map_cursor(point mappos)1215 int levelwin::get_map_cursor(point mappos)
1216 {
1217 if ((mappos.x < 1) || (mappos.x >= COLNO) ||
1218 (mappos.y < 0) || (mappos.y >= ROWNO))
1219 return V_CURSOR_TARGET_INVALID;
1220
1221 /* whatis: look or teleport */
1222 if (vulture_whatis_active)
1223 return V_CURSOR_TARGET_HELP;
1224
1225 /* monsters and objects get a red circle */
1226 if (map_data->get_glyph(MAP_MON, mappos.x, mappos.y) != V_TILE_NONE &&
1227 ((mappos.x != u.ux) || (mappos.y != u.uy)))
1228 return V_CURSOR_TARGET_RED;
1229
1230 if (map_data->get_glyph(MAP_OBJ, mappos.x, mappos.y) != V_TILE_NONE)
1231 return V_CURSOR_TARGET_RED;
1232
1233 /* other valid visible locations */
1234 if (map_data->get_glyph(MAP_BACK, mappos.x, mappos.y) != V_TILE_NONE) {
1235 int furniture = map_data->get_glyph(MAP_FURNITURE, mappos.x, mappos.y);
1236 /* Closed doors get an 'open door' cursor */
1237 if ((furniture == V_MISC_VDOOR_WOOD_CLOSED) ||
1238 (furniture == V_MISC_HDOOR_WOOD_CLOSED))
1239 return V_CURSOR_OPENDOOR;
1240
1241 /* Stairs and ladders get a 'stairs' cursor */
1242 if ((furniture == V_MISC_STAIRS_UP) || (furniture == V_MISC_STAIRS_DOWN) ||
1243 (furniture == V_MISC_LADDER_UP) || (furniture == V_MISC_LADDER_DOWN))
1244 return V_CURSOR_STAIRS;
1245
1246 /* Fountains get a 'goblet' cursor */
1247 if (furniture == V_MISC_FOUNTAIN)
1248 return V_CURSOR_GOBLET;
1249
1250 if (map_data->get_glyph(MAP_BACK, mappos.x, mappos.y) != V_TILE_WALL_GENERIC)
1251 return V_CURSOR_TARGET_GREEN;
1252 }
1253
1254 return V_CURSOR_TARGET_INVALID;
1255 }
1256
1257