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