1 /* NetHack may be freely redistributed. See license for details. */
2
3 #include <ctype.h>
4
5 #include <SDL.h>
6
7 /* nethack headers */
8 extern "C" {
9
10 #include "hack.h"
11 #include "rm.h"
12 #include "display.h"
13 #include "dlb.h"
14 #ifdef SHORT_FILENAMES
15 #include "patchlev.h"
16 #else
17 #include "patchlevel.h"
18 #endif
19 #include "extern.h"
20
21 #include "func_tab.h" /* For extended commands list */
22 }
23
24 #define TRAVEL_HACK /* XXX This is to be removed once Slash'EM (NetHack?) fixes the problem of infinite loops */
25
26 /* vulture headers */
27 #include "vulture_main.h"
28 #include "vulture_gra.h"
29 #include "vulture_gen.h"
30 #include "vulture_win.h"
31 #include "vulture_sdl.h"
32 #include "vulture_init.h"
33 #include "vulture_pcmusic.h"
34 #include "vulture_sound.h"
35 #include "vulture_mou.h"
36 #include "vulture_opt.h"
37
38 #include "winclass/nhwindow.h"
39 #include "winclass/anykeydialog.h"
40 #include "winclass/button.h"
41 #include "winclass/choicedialog.h"
42 #include "winclass/dirdialog.h"
43 #include "winclass/endingwin.h"
44 #include "winclass/inventory.h"
45 #include "winclass/levelwin.h"
46 #include "winclass/messagewin.h"
47 #include "winclass/statuswin.h"
48 #include "winclass/mapdata.h"
49 #include "winclass/map.h"
50 #include "winclass/minimap.h"
51
52 /* Interface definition, for windows.c */
53 struct window_procs vulture_procs = {
54 "vulture",
55 WC_COLOR |
56 WC_HILITE_PET |
57 WC_PLAYER_SELECTION |
58 WC_SPLASH_SCREEN |
59 WC_POPUP_DIALOG |
60 WC_FONT_TEXT,
61 WC2_FULLSCREEN,
62 vulture_init_nhwindows,
63 vulture_player_selection,
64 vulture_askname,
65 vulture_get_nh_event,
66 vulture_exit_nhwindows,
67 vulture_suspend_nhwindows,
68 vulture_resume_nhwindows,
69 vulture_create_nhwindow,
70 vulture_clear_nhwindow,
71 vulture_display_nhwindow,
72 vulture_destroy_nhwindow,
73 vulture_curs,
74 vulture_putstr,
75 vulture_display_file,
76 vulture_start_menu,
77 vulture_add_menu,
78 vulture_end_menu,
79 vulture_select_menu,
80 vulture_message_menu,
81 vulture_update_inventory,
82 vulture_mark_synch,
83 vulture_wait_synch,
84 #ifdef CLIPPING
85 vulture_cliparound,
86 #endif
87 #ifdef POSITIONBAR
88 vulture_update_positionbar,
89 #endif
90 vulture_print_glyph,
91 vulture_raw_print,
92 vulture_raw_print_bold,
93 vulture_nhgetch,
94 vulture_nh_poskey,
95 vulture_nhbell,
96 vulture_doprev_message,
97 vulture_yn_function,
98 vulture_getlin,
99 vulture_get_ext_cmd,
100 vulture_number_pad,
101 vulture_delay_output,
102 #ifdef CHANGE_COLOR
103 vulture_change_colour,
104 #ifdef MAC
105 vulture_change_background,
106 vulture_set_font_name,
107 #endif
108 vulture_get_colour_string,
109 #endif
110 vulture_start_screen,
111 vulture_end_screen,
112 vulture_outrip,
113 vulture_preference_update
114 };
115
116
117 int vulture_whatis_active = 0;
118
119 static int vulture_stop_travelling = 0;
120
121
122
123 /*****************************
124 * nethack interface api
125 *****************************/
126
win_vulture_init(void)127 void win_vulture_init(void)
128 {
129 #if defined(WIN32)
130 /*nt_kbhit = vulture_kbhit;*/ /* this should be unnecessary and we haven't implemented a "vulture_kbhit" anywhere */
131 #endif
132 }
133
134
vulture_init_nhwindows(int * argcp,char ** argv)135 void vulture_init_nhwindows(int *argcp, char **argv)
136 {
137 unsigned int mask;
138
139 /* try to chdir to our datadir */
140 vulture_chdir_to_datadir(argv[0]);
141
142 if (!vulture_init_graphics())
143 panic("could not initalize graphic mode");
144
145 #ifdef PCMUSIC
146 vulture_pcmusic_init();
147 #endif
148
149 /*
150 * hide some menu options that are not relevant for us
151 */
152 set_option_mod_status("altkeyhandler", SET_IN_FILE);
153 set_option_mod_status("DECgraphics", SET_IN_FILE);
154 set_option_mod_status("IBMgraphics", SET_IN_FILE);
155 set_option_mod_status("menu_headings", SET_IN_FILE);
156 set_option_mod_status("null", SET_IN_FILE);
157 set_option_mod_status("boulder", SET_IN_FILE);
158 set_option_mod_status("sound", SET_IN_FILE);
159 set_option_mod_status("silent", SET_IN_FILE);
160 set_option_mod_status("lit_corridor", SET_IN_FILE);
161 set_option_mod_status("msghistory", SET_IN_FILE);
162 set_option_mod_status("windowtype", SET_IN_FILE);
163 set_option_mod_status("perm_invent", SET_IN_FILE);
164
165 mask = WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_ASCII_MAP | WC_COLOR | WC_EIGHT_BIT_IN |
166 WC_FONTSIZ_TEXT | WC_MAP_MODE | WC_PLAYER_SELECTION | WC_POPUP_DIALOG |
167 WC_PRELOAD_TILES | WC_SCROLL_AMOUNT | WC_SCROLL_MARGIN | WC_TILED_MAP |
168 WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE | WC_INVERSE | WC_VARY_MSGCOUNT |
169 WC_WINDOWCOLORS | WC_MOUSE_SUPPORT;
170
171 set_wc_option_mod_status(mask, SET_IN_FILE);
172
173 /* these _must_ have the right value for vulture to work correctly */
174 set_option_mod_status("menu_tab_sep", SET_IN_FILE);
175
176 /* Setting options here makes sure they have the right value
177 * as this is done _after_ reading in .nethackrc and co */
178 iflags.menu_tab_sep = 1;
179 iflags.wc_hilite_pet = 1;
180
181 vulture_show_logo_screen();
182
183 map_data = new mapdata();
184
185 new levelwin(map_data);
186 vulture_windows_inited = 1;
187
188 /* Success! */
189 iflags.window_inited = TRUE;
190 }
191
192
193
vulture_exit_nhwindows(const char * str)194 void vulture_exit_nhwindows(const char * str)
195 {
196 /* destroy any surviving windows */
197 delete ROOTWIN;
198 delete map_data;
199
200 /* close the application window */
201 vulture_exit_graphics_mode();
202 if (str)
203 printf("%s\n", str);
204
205 /* clean up all the memory we allocated */
206 vulture_destroy_graphics();
207
208 vulture_write_userconfig();
209 }
210
211
212
vulture_create_nhwindow(int type)213 winid vulture_create_nhwindow(int type)
214 {
215 nhwindow *win = new nhwindow(type);
216
217 switch(type) {
218 case NHW_STATUS:
219 win->impl = new statuswin(NULL);
220 break;
221
222 case NHW_MESSAGE:
223 win->impl = new messagewin(NULL);
224 break;
225
226 case NHW_MAP:
227 win->impl = ROOTWIN;
228 static_cast<levelwin*>(ROOTWIN)->init();
229 break;
230
231 case NHW_MENU:
232 case NHW_TEXT:
233 break;
234
235 default:
236 return WIN_ERR;
237 }
238 return win->id;
239 }
240
241
242
vulture_clear_nhwindow(int winid)243 void vulture_clear_nhwindow(int winid)
244 {
245 if (!vulture_get_nhwindow(winid))
246 return;
247
248 /* this doesn't seem to be used for anything other than the map ... */
249 if (winid == WIN_MAP)
250 map_data->clear();
251
252 /* nethack also wants to clear WIN_MESSAGE frequently, but we don't do that
253 * because we have our own way of handling the message window... */
254 }
255
256
257 /* helper called by vulture_display_nhwindow */
vulture_display_nhmap(window * win,vulture_event * result,BOOLEAN_P blocking)258 static void vulture_display_nhmap(window *win, vulture_event *result, BOOLEAN_P blocking)
259 {
260 if (u.uz.dlevel != 0) {
261 /* u.uz.dlevel == 0 when the game hasn't been fully initialized yet
262 * you can't actually go there, the astral levels have negative numbers */
263
264 /* Center the view on the hero, if necessary */
265 if (!vulture_whatis_active &&
266 (vulture_opts.recenter || !levwin->need_recenter(u.ux, u.uy)))
267 levwin->set_view(u.ux, u.uy);
268
269 if (mapwin)
270 mapwin->need_redraw = 1;
271
272 if (vulture_opts.show_minimap)
273 minimapwin->need_redraw = 1;
274
275 win->need_redraw = 1;
276
277 if (flags.travel) {
278 if (vulture_event_dispatcher_nonblocking(result, NULL))
279 vulture_stop_travelling = 1;
280 } else {
281 win->draw_windows();
282 vulture_refresh_window_region();
283 }
284 }
285
286 /* blocking is set for things like monster detection, where we wait for an
287 * event before returning to a normal state */
288 if (blocking) {
289 vulture_event dummy;
290 /* go into the event+drawing loop until we get a response */
291 vulture_event_dispatcher(&dummy, V_RESPOND_POSKEY, NULL);
292
293 /* we may have tried to initiate travel in the event handler, but we don't want that here */
294 u.tx = u.ux;
295 u.ty = u.uy;
296 }
297 }
298
vulture_display_nhwindow(int winid,BOOLEAN_P blocking)299 void vulture_display_nhwindow(int winid, BOOLEAN_P blocking)
300 {
301 nhwindow *win = vulture_get_nhwindow(winid);
302 menu_item *menu_list; /* Dummy pointer for displaying NHW_MENU windows */
303 vulture_event result = {-1, -1, 0, 0};
304
305 if (!win)
306 return;
307
308 switch(win->type) {
309 case NHW_TEXT:
310 if (win->ending_type > 0) {
311 int response;
312
313 win->impl = new endingwin(ROOTWIN, win->items, win->ending_type);
314 win->impl->need_redraw = 1;
315 win->impl->visible = 1;
316
317 /* need to run the eventloop manually */
318 vulture_event_dispatcher(&response, V_RESPOND_INT, win->impl);
319
320 delete win->impl;
321 win->impl = NULL;
322
323 vulture_fade_out(0.5);
324 return;
325 }
326 /* else fall through */
327
328 case NHW_MENU:
329 /* note that win->impl is NULL for menu windows! */
330 vulture_end_menu(winid, NULL);
331 vulture_select_menu(winid, PICK_NONE, &menu_list);
332 break;
333
334 case NHW_MAP:
335 vulture_display_nhmap(win->impl, &result, blocking);
336 break;
337
338 case NHW_STATUS:
339 /* status is always visible, so we consider this a request for redraw */
340 win->impl->visible = 1;
341 win->impl->need_redraw = 1;
342 break;
343
344 case NHW_MESSAGE:
345 win->impl->need_redraw = 1;
346 /* we need to actually draw here so that we get output even when the
347 * message window isn't on the current drawing loop */
348 win->impl->draw_windows();
349 vulture_refresh_window_region();
350 break;
351
352 default:
353 win->impl->need_redraw = 1;
354 }
355 }
356
357
vulture_destroy_nhwindow(int winid)358 void vulture_destroy_nhwindow(int winid)
359 {
360 nhwindow *win = vulture_get_nhwindow(winid);
361
362 if (winid == WIN_MAP) {
363 vulture_fade_out(0.2);
364 return;
365 }
366
367 else if (win && winid == WIN_STATUS)
368 win->impl->visible = 0;
369
370 delete win;
371 }
372
373
vulture_start_menu(int winid)374 void vulture_start_menu(int winid)
375 {
376 nhwindow *win = vulture_get_nhwindow(winid);
377
378 /* sanity checks */
379 if(!win)
380 return;
381
382 if (win->type != NHW_MENU)
383 return;
384
385 win->reset();
386 }
387
388
389 /* add an item to a menu that was started with vulture_start_menu */
vulture_add_menu(int winid,int glyph,const ANY_P * identifier,CHAR_P accelerator,CHAR_P groupacc,int attr,const char * str,BOOLEAN_P preselected)390 void vulture_add_menu(int winid, int glyph, const ANY_P * identifier,
391 CHAR_P accelerator, CHAR_P groupacc, int attr,
392 const char *str, BOOLEAN_P preselected)
393 {
394 nhwindow *win = vulture_get_nhwindow(winid);
395 if (!win)
396 return;
397
398 if (glyph_is_object(glyph))
399 win->has_objects = true;
400
401 win->add_menuitem(str, !!preselected, identifier->a_void, accelerator, groupacc, glyph);
402 }
403
404
405 /* finalize a menu window and add the title and accelerators */
vulture_end_menu(int winid,const char * prompt)406 void vulture_end_menu(int winid, const char *prompt)
407 {
408 nhwindow *win = vulture_get_nhwindow(winid);
409 if(!win)
410 return;
411
412 /* we (ab)use the prompt as the window title */
413 if (prompt)
414 win->caption = prompt;
415 }
416
417
418
vulture_select_menu(int winid,int how,menu_item ** menu_list)419 int vulture_select_menu(int winid, int how, menu_item **menu_list)
420 {
421 nhwindow *nhwin;
422 menuwin *win;
423 int response, n_selected;
424 vulture_event *queued_event;
425
426 bool objwin_ok = ((winid == WIN_INVEN && !vulture_opts.use_standard_inventory) ||
427 (winid != WIN_INVEN && !vulture_opts.use_standard_object_menus));
428
429 nhwin = vulture_get_nhwindow(winid);
430 if(!nhwin)
431 return -1;
432
433
434 /* assign accelerators to menuitems, if necessary */
435 *menu_list = NULL; /* realloc blows up if this contains a random memory location */
436
437 /* check for an autoresponse to this menu */
438 if (how != PICK_NONE && (queued_event = vulture_eventstack_get()) &&
439 queued_event->rtype == V_RESPOND_ANY) {
440 for (nhwindow::item_iterator iter = nhwin->items.begin();
441 iter != nhwin->items.end(); ++iter) {
442 if ( (iter->accelerator == (char)queued_event->num) ||
443 (iter->group_accelerator == (char)queued_event->num) ) {
444 *menu_list = (menu_item *)malloc(sizeof(menu_item));
445 (*menu_list)[0].item.a_void = (void*)iter->identifier;
446 (*menu_list)[0].count = -1;
447 return -1;
448 }
449 }
450 }
451
452 if (objwin_ok && nhwin->has_objects) {
453 win = new inventory(ROOTWIN, nhwin->items, how, nhwin->id);
454 }else {
455 win = new menuwin(ROOTWIN, nhwin->items, how);
456 if (how == PICK_NONE )
457 new button(win, "Continue", V_MENU_ACCEPT, 0);
458 else {
459 if (how == PICK_ANY )
460 new button(win, "Accept", V_MENU_ACCEPT, 0);
461 new button(win, "Cancel", V_MENU_CANCEL, 0);
462 }
463 }
464
465 win->caption = nhwin->caption;
466 win->visible = 1;
467 win->need_redraw = 1;
468 win->layout();
469
470 vulture_event_dispatcher(&response, V_RESPOND_INT, win);
471
472 /* nothing selected, because the window was canceled or no selection was requested */
473 if (response == V_MENU_CANCEL || how == PICK_NONE) {
474 delete win;
475 return -1;
476 }
477
478 n_selected = 0;
479
480 for (menuwin::selection_iterator iter = win->selection_begin();
481 iter != win->selection_end(); ++iter) {
482 n_selected++;
483 *menu_list = (menu_item *)realloc(*menu_list, n_selected*sizeof(menu_item));
484 (*menu_list)[n_selected-1].item.a_void = (void*)(*iter).identifier;
485 (*menu_list)[n_selected-1].count = (*iter).count;
486 }
487
488 delete win;
489 return n_selected;
490 }
491
492
493
494 /*****************************
495 * Output functions
496 *****************************/
497
vulture_print_glyph(winid window,XCHAR_P x,XCHAR_P y,int glyph)498 void vulture_print_glyph(winid window, XCHAR_P x, XCHAR_P y, int glyph)
499 {
500 map_data->set_glyph(x, y, glyph);
501 }
502
503
vulture_raw_print(const char * str)504 void vulture_raw_print(const char *str)
505 {
506 if (str == NULL || *str == '\0')
507 return;
508 vulture_write_log(V_LOG_NETHACK, NULL, 0, "%s\n", str);
509
510 /* also print to stdout, this allows nethack topten to be displayed */
511 printf("%s\n", str);
512 }
513
514
515
vulture_raw_print_bold(const char * str)516 void vulture_raw_print_bold(const char *str)
517 {
518 if (str == NULL || *str == '\0')
519 return;
520 vulture_write_log(V_LOG_NETHACK, NULL, 0, "%s\n", str);
521
522 /* also print to stdout, this allows nethack topten to be displayed */
523 printf("%s\n", str);
524 }
525
526
527
vulture_putstr(int winid,int attr,const char * str)528 void vulture_putstr(int winid, int attr, const char *str)
529 {
530 nhwindow *win;
531
532 if (!str)
533 return;
534
535 /* Display error messages immediately */
536 if (winid == WIN_ERR) {
537 vulture_messagebox(str);
538 return;
539 }
540
541 win = vulture_get_nhwindow(winid);
542
543 /*
544 * For windows of type NHW_MESSAGE, both the messages
545 * and their send time are stored.
546 */
547 switch (win->type) {
548 case NHW_MESSAGE:
549 /* If "what's this" is active,skip the help messages
550 * associated with NetHack's lookat command. */
551 if (vulture_suppress_helpmsg) {
552 /* Skip help line [Please move the cursor to an unknown object.] */
553 if (strncmp(str, "Please move", 11) == 0) return;
554 /* Skip help line [(For instructions type a ?)] */
555 if (strncmp(str, "(For instru", 11) == 0) return;
556 /* Skip help line [Pick an object.] */
557 if (strncmp(str, "Pick an obj", 11) == 0) return;
558 }
559
560 /* Skip line [Done.] */
561 if (strncmp(str, "Done.", 5) == 0)
562 return;
563
564 msgwin->add_message(std::string(str));
565
566 /* Play any event sounds associated with this message */
567 vulture_play_event_sound(str);
568
569 /* Copy message to toplines[] */
570 strcpy(toplines, str);
571
572 /* Redisplay message window */
573 vulture_display_nhwindow(winid, FALSE);
574 break;
575
576 case NHW_TEXT:
577 case NHW_MENU:
578 /* Add the new text line as a menu item */
579 win->add_menuitem(str, false, NULL, '\0', '\0', 0);
580 break;
581
582 case NHW_STATUS:
583 stwin->parse_statusline(str);
584 stwin->need_redraw = 1;
585 break;
586 }
587 }
588
589
590
591 /********************************************
592 * functions that get input from the user
593 ********************************************/
594
vulture_nhgetch(void)595 int vulture_nhgetch(void)
596 {
597 vulture_event * queued_event;
598 SDL_Event event;
599
600 /* check eventstack */
601 queued_event = vulture_eventstack_get();
602 if (queued_event)
603 return queued_event->num;
604
605 vulture_wait_key(&event);
606
607 return vulture_translate_key(vulture_make_nh_key(event.key.keysym.sym, event.key.keysym.mod, event.key.keysym.unicode));
608 }
609
610
611
vulture_nh_poskey(int * x,int * y,int * mod)612 int vulture_nh_poskey(int *x, int *y, int *mod)
613 {
614 vulture_event result = {-1, -1, 0, 0};
615
616 /* Play ambient music or sound effects */
617 vulture_play_ambient_sound(0);
618
619 vulture_event_dispatcher(&result, V_RESPOND_POSKEY, NULL);
620
621 *x = result.x;
622 *y = result.y;
623
624 return result.num;
625 }
626
627
628
vulture_yn_function(const char * ques,const char * choices,CHAR_P defchoice)629 char vulture_yn_function(const char *ques, const char *choices, CHAR_P defchoice)
630 {
631 window *win;
632 char response;
633
634 /* a save: yes/no or ring: right/left question */
635 if (choices)
636 win = new choicedialog(ROOTWIN, ques, choices, 0);
637
638 /* An "In what direction ..." question */
639 else if (strstr(ques, "n what direc"))
640 win = new dirdialog(ROOTWIN, ques);
641
642 /* default case: What do you want to <foo>, where any key is a valid response */
643 else
644 win = new anykeydialog(ROOTWIN, ques);
645
646 /* get input for our window */
647 vulture_event_dispatcher(&response, V_RESPOND_CHARACTER, win);
648
649 /* clean up */
650 delete win;
651
652 return response;
653 }
654
655
656
vulture_getlin(const char * ques,char * input)657 void vulture_getlin(const char *ques, char *input)
658 {
659 if (!vulture_get_input(-1, -1, ques, input))
660 strcpy(input, "\033");
661 }
662
663
664
665 /*************************************
666 * non windowing-related nh functions
667 *************************************/
668
vulture_outrip(int winid,int how)669 void vulture_outrip(int winid, int how)
670 {
671 nhwindow *win = vulture_get_nhwindow(winid);
672
673 if (!win)
674 return;
675
676 win->ending_type = how;
677 }
678
679
680 /* handle options updates here */
vulture_preference_update(const char * pref)681 void vulture_preference_update(const char *pref)
682 {
683 if (strcmpi(pref, "hilite_pet") == 0)
684 vulture_display_nhwindow(WIN_MAP, FALSE);
685
686 return;
687 }
688
689
690 /* clean up and quit */
vulture_bail(const char * mesg)691 void vulture_bail(const char *mesg)
692 {
693 clearlocks();
694 vulture_exit_nhwindows(mesg);
695 terminate(EXIT_SUCCESS);
696 /*NOTREACHED*/
697 }
698
699 extern int NDECL(extcmd_via_menu);
700
701 /* display a list of extended commands for the user to pick from */
vulture_get_ext_cmd(void)702 int vulture_get_ext_cmd(void)
703 {
704 return extcmd_via_menu();
705 // TODO if ( iflags.extmenu ) return extcmd_via_menu();
706 // ... in the rest of this function should be code to create an input box
707 // where individual (autocompleted) characters could be entered.
708 }
709
710
711 /* display a file in a menu window */
vulture_display_file(const char * fname,BOOLEAN_P complain)712 void vulture_display_file(const char *fname, BOOLEAN_P complain)
713 {
714 dlb * f; /* Data librarian */
715 char tempbuffer[1024];
716 int window;
717
718 /* Read the file */
719 f = dlb_fopen(fname, "r");
720 if (!f) {
721 if (complain == TRUE) {
722 sprintf(tempbuffer, "Can't open file [%s].\n", fname);
723 vulture_messagebox(tempbuffer);
724 }
725 return;
726 }
727
728 window = vulture_create_nhwindow(NHW_MENU);
729
730 while (dlb_fgets(tempbuffer, 1024, f))
731 vulture_putstr(window, ATR_NONE, tempbuffer);
732
733 dlb_fclose(f);
734
735
736 /* Display the file */
737 vulture_display_nhwindow(window, TRUE);
738
739 /* Clean up */
740 vulture_destroy_nhwindow(window);
741 }
742
743
744
vulture_doprev_message(void)745 int vulture_doprev_message(void)
746 {
747 nhwindow *messages;
748
749 int pos = msgwin->getshown();
750 msgwin->setshown(pos+1);
751
752 messages = vulture_get_nhwindow(WIN_MESSAGE);
753 messages->impl->need_redraw = 1;
754 messages->impl->draw_windows();
755 vulture_refresh_window_region();
756
757 return 0;
758 }
759
760
761 /* delay output is _supposed to_ simply pause for a bit; unfortunately that
762 * would cause the mouse to freeze, because the eventloop would also pause */
vulture_delay_output(void)763 void vulture_delay_output(void)
764 {
765 int delay = 50, origdelay;
766 int elapsed;
767 int starttick, endtick;
768 vulture_event result;
769 int funcstart, funcend;
770 int loops = 0;
771
772 funcstart = SDL_GetTicks();
773
774 /* the time it took to draw the map is subtracted from the delay time;
775 * this allows the game to adapt to slow-drawing systems (ie unaccelerated
776 * software graphics) */
777 if (vulture_map_draw_lastmove == moves) {
778 delay -= vulture_map_draw_msecs;
779 if (delay < 0)
780 delay = 1;
781 vulture_map_draw_msecs = 0;
782 }
783 origdelay = delay;
784
785 /* delay in small increments and run the eventloop in between */
786 while (delay > 10) {
787 starttick = SDL_GetTicks();
788
789 if (vulture_event_dispatcher_nonblocking(&result, NULL))
790 vulture_stop_travelling = 1;
791
792 endtick = SDL_GetTicks();
793 elapsed = endtick - starttick;
794 if (elapsed < 10) {
795 SDL_Delay(10 - elapsed);
796 elapsed = 10;
797 }
798 delay -= elapsed;
799 loops++;
800 }
801
802 funcend = SDL_GetTicks();
803 elapsed = funcend - funcstart;
804
805 /* we use >5 in the condition rather than the theoretically more correct >0
806 * because we expect a delay granularity or 10 ms. By using >5 we should get
807 * the correct delay on average ...*/
808 if (origdelay - elapsed > 5)
809 SDL_Delay(origdelay - elapsed);
810 }
811
812
vulture_message_menu(CHAR_P let,int how,const char * mesg)813 char vulture_message_menu(CHAR_P let, int how, const char *mesg)
814 {
815 pline("%s", mesg);
816 return '\0';
817 }
818
819
820
821 /* the textmode ui highlights one position onscreen, this is the cursor
822 * vulture has no real equivalent, however in some situations we allow
823 * the mose to be moved via keyboard input */
vulture_curs(winid window,int x,int y)824 void vulture_curs(winid window, int x, int y)
825 {
826 /* allow selecting a position via keyboard for look and teleport (both set vulture_whatis_active) */
827 if (window == WIN_MAP && vulture_whatis_active) {
828 point mappos, mouse;
829
830 mappos.x = x; mappos.y = y;
831 mouse = levwin->map_to_mouse( mappos );
832
833 /* move the viewport when the mouse approaches the edge */
834 if (mouse.x < 50 || mouse.x > (vulture_screen->w-50) ||
835 mouse.y < 50 || mouse.y > (vulture_screen->h-50)) {
836 levwin->set_view(x, y);
837
838 /* calculate the new mouse position */
839 mouse = levwin->map_to_mouse( mappos );
840 }
841
842 vulture_set_mouse_pos( mouse.x, mouse.y );
843 }
844 }
845
846
847 /* called by the core, this function is intended to do window event processing
848 * we misuse it to stop travelling, either because this was requested, or
849 * because a loop in the travel algorithm was detected */
vulture_get_nh_event(void)850 void vulture_get_nh_event(void)
851 {
852 static point lastpos[2] = {{-1,-1}, {-1,-1}};
853
854 if (flags.travel) {
855 /* if the positon 2 turns ago is identical to the current position,
856 * the travel algorithm has hung and travel needs to be canceled */
857 if (vulture_stop_travelling ||
858 ((lastpos[1].x != lastpos[0].x || lastpos[1].y != lastpos[0].y) &&
859 lastpos[1].x == u.ux && lastpos[1].y == u.uy)) {
860 flags.travel = 0;
861 flags.mv = 0;
862 u.tx = u.ux;
863 u.ty = u.uy;
864 lastpos[0].x = lastpos[1].x = -1;
865 } else {
866 lastpos[1] = lastpos[0];
867 lastpos[0].x = u.ux;
868 lastpos[0].y = u.uy;
869 }
870 }
871 else
872 lastpos[0].x = lastpos[1].x = -1;
873
874 vulture_stop_travelling = 0;
875 }
876
877
878 /*******************************************************
879 * utility functions
880 *******************************************************/
881
vulture_find_menu_accelerator(char * used_accelerators)882 int vulture_find_menu_accelerator(char *used_accelerators)
883 {
884 char acc_found;
885 int cur_accelerator;
886 unsigned int i, j;
887 char acclist[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";
888
889 /* Find an unused accelerator */
890 acc_found = 0;
891 cur_accelerator = 0;
892
893 /* Pick any available letter from [a-zA-Z] */
894 for (i = 0; i < strlen(acclist); i++) {
895 cur_accelerator = acclist[i];
896
897 acc_found = 1;
898 for (j = 0; used_accelerators[j] != '\0'; j++)
899 if (used_accelerators[j] == cur_accelerator)
900 acc_found = 0;
901 if (acc_found)
902 break;
903 }
904
905 if (acc_found) {
906 /* Add found accelerator to string of used ones (assume there's enough room) */
907 j = strlen(used_accelerators);
908 used_accelerators[j] = cur_accelerator;
909 used_accelerators[j+1] = '\0';
910 return cur_accelerator;
911 }
912
913 return -1;
914 }
915
916 /*******************************************************
917 * unsupported/unnecessary functions of the nethack api
918 *******************************************************/
919
920 /* suspend/resume is disabled in vulture, because
921 * it makes no sense for a gui app to have */
vulture_suspend_nhwindows(const char * str)922 void vulture_suspend_nhwindows(const char *str) {}
vulture_resume_nhwindows(void)923 void vulture_resume_nhwindows(void) {}
924
vulture_mark_synch(void)925 void vulture_mark_synch(void){}
vulture_wait_synch(void)926 void vulture_wait_synch(void) {}
vulture_nhbell(void)927 void vulture_nhbell(void) {}
vulture_number_pad(int state)928 void vulture_number_pad(int state) {}
vulture_update_inventory(void)929 void vulture_update_inventory(void) {}
vulture_start_screen(void)930 void vulture_start_screen(void) {}
vulture_end_screen(void)931 void vulture_end_screen(void) {}
932
933
934 #ifdef CLIPPING
vulture_cliparound(int x,int y)935 void vulture_cliparound(int x, int y) {}
936 #endif
937
938 #ifdef POSITIONBAR
vulture_update_positionbar(char * features)939 void vulture_update_positionbar(char *features) {}
940 #endif
941