1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ultima/nuvie/core/nuvie_defs.h"
24 #include "ultima/nuvie/misc/u6_misc.h"
25 #include "ultima/nuvie/conf/configuration.h"
26 #include "ultima/nuvie/core/game.h"
27 #include "ultima/nuvie/core/game_clock.h"
28 #include "ultima/nuvie/gui/widgets/map_window.h"
29 #include "ultima/nuvie/gui/widgets/msg_scroll.h"
30 #include "ultima/nuvie/actors/actor_manager.h"
31 #include "ultima/nuvie/actors/actor.h"
32 #include "ultima/nuvie/core/converse.h"
33 #include "ultima/nuvie/core/player.h"
34 #include "ultima/nuvie/core/party.h"
35 #include "ultima/nuvie/core/book.h"
36 #include "ultima/nuvie/views/view_manager.h"
37 #include "ultima/nuvie/views/portrait_view.h"
38 #include "ultima/nuvie/core/timed_event.h"
39 #include "ultima/nuvie/views/inventory_view.h"
40 #include "ultima/nuvie/views/party_view.h"
41 #include "ultima/nuvie/views/actor_view.h"
42 #include "ultima/nuvie/gui/widgets/command_bar.h"
43 #include "ultima/nuvie/core/events.h"
44 #include "ultima/nuvie/core/u6_objects.h"
45 #include "ultima/nuvie/core/effect.h"
46 #include "ultima/nuvie/core/effect_manager.h"
47 #include "ultima/nuvie/files/nuvie_io_file.h"
48 #include "ultima/nuvie/core/magic.h"
49 #include "ultima/nuvie/gui/gui_yes_no_dialog.h"
50 #include "ultima/nuvie/menus/game_menu_dialog.h"
51 #include "ultima/nuvie/views/inventory_widget.h"
52 #include "ultima/nuvie/keybinding/keys.h"
53 #include "ultima/nuvie/views/spell_view.h"
54 #include "ultima/nuvie/gui/widgets/fps_counter.h"
55 #include "ultima/nuvie/script/script.h"
56 
57 #include "common/system.h"
58 
59 namespace Ultima {
60 namespace Nuvie {
61 
62 Events *Events::g_events;
63 
64 using Std::string;
65 
~EventInput_s()66 EventInput_s::~EventInput_s() {
67 	if (target_init) delete target_init;
68 	if (str) delete str;
69 	if (loc) delete loc;
70 }
71 
set_loc(MapCoord c)72 void EventInput_s::set_loc(MapCoord c) {
73 	if ((type == EVENTINPUT_MAPCOORD || type == EVENTINPUT_MAPCOORD_DIR) && loc != 0) delete loc;
74 	loc = new MapCoord(c);
75 }
76 
Events(Shared::EventsCallback * callback,Configuration * cfg)77 Events::Events(Shared::EventsCallback *callback, Configuration *cfg) : Shared::EventsManager(callback), config(cfg) {
78 	g_events = this;
79 	clear();
80 }
81 
~Events()82 Events::~Events() {
83 	g_events = nullptr;
84 
85 	delete time_queue;
86 	delete game_time_queue;
87 }
88 
clear()89 void Events::clear() {
90 	clear_alt_code();
91 	active_alt_code = 0;
92 	alt_code_input_num = 0;
93 
94 	game = Game::get_game();
95 	gui = NULL;
96 	obj_manager = NULL;
97 	map_window = NULL;
98 	scroll = NULL;
99 	clock = NULL;
100 	player = NULL;
101 	view_manager = NULL;
102 	usecode = NULL;
103 	magic = NULL;
104 	drop_obj = NULL;
105 	ts = 0;
106 	drop_qty = 0;
107 	drop_x = drop_y = -1;
108 	rest_time = 0;
109 	rest_guard = 0;
110 	push_obj = NULL;
111 	push_actor = NULL;
112 	drop_from_key = false;
113 	move_in_inventory = false;
114 	time_queue = game_time_queue = NULL;
115 	showingDialog = false;
116 	gamemenu_dialog = NULL;
117 	ignore_timeleft = false;
118 	in_control_cheat = false;
119 	looking_at_spellbook = false;
120 	using_pickpocket_cheat = false;
121 	do_not_show_target_cursor = false;
122 	config->value("config/input/direction_selects_target", direction_selects_target, true);
123 
124 	mode = MOVE_MODE;
125 	last_mode = MOVE_MODE;
126 
127 	fps_timestamp = 0;
128 	fps_counter = 0;
129 
130 	scriptThread = NULL;
131 }
132 
init(ObjManager * om,MapWindow * mw,MsgScroll * ms,Player * p,Magic * mg,GameClock * gc,ViewManager * vm,UseCode * uc,GUI * g,KeyBinder * kb)133 bool Events::init(ObjManager *om, MapWindow *mw, MsgScroll *ms, Player *p, Magic *mg,
134 				 GameClock *gc, ViewManager *vm, UseCode *uc, GUI *g, KeyBinder *kb) {
135 	clear();
136 
137 	gui = g;
138 	obj_manager = om;
139 	map_window = mw;
140 	scroll = ms;
141 	clock = gc;
142 	player = p;
143 	view_manager = vm;
144 	usecode = uc;
145 
146 	mode = MOVE_MODE;
147 	last_mode = MOVE_MODE;
148 	input.get_direction = false;
149 	input.get_text = false;
150 	cursor_mode = false;
151 	input.target_init = NULL;
152 
153 	time_queue = new TimeQueue;
154 	game_time_queue = new TimeQueue;
155 	magic = mg;
156 	keybinder = kb;
157 
158 	fps_timestamp = clock->get_ticks();
159 
160 	fps_counter_widget = new FpsCounter(game);
161 	gui->AddWidget(fps_counter_widget);
162 	fps_counter_widget->Hide();
163 	scriptThread = NULL;
164 
165 	return true;
166 }
167 
update_timers()168 void Events::update_timers() {
169 	time_queue->call_timers(clock->get_ticks());
170 	game_time_queue->call_timers(clock->get_game_ticks());
171 }
172 
update()173 bool Events::update() {
174 	bool idle = true;
175 	// timed
176 	time_queue->call_timers(clock->get_ticks());
177 	game_time_queue->call_timers(clock->get_game_ticks());
178 
179 	// polled
180 	Common::Event evt;
181 	while (pollEvent(evt)) {
182 		idle = false;
183 		switch (gui->HandleEvent(&evt)) {
184 		case GUI_PASS :
185 			if (handleEvent(&evt) == false) {
186 				game->quit();
187 				return false;
188 			}
189 			break;
190 
191 		case GUI_QUIT :
192 			game->quit();
193 			return false;
194 
195 		default :
196 			break;
197 		}
198 	}
199 
200 	if (idle)
201 		gui->Idle(); // run Idle() for all widgets
202 
203 	if (showingDialog) // temp. fix to show normal cursor over quit dialog
204 		game->set_mouse_pointer(0);
205 
206 	return true;
207 }
208 
handleSDL_KEYDOWN(const Common::Event * event_)209 bool Events::handleSDL_KEYDOWN(const Common::Event *event_) {
210 	// when casting the magic class will handle keyboard events
211 	if (mode == KEYINPUT_MODE) {
212 		Common::KeyCode sym = event_->kbd.keycode;
213 		ActionKeyType action_key_type = OTHER_KEY;
214 
215 		if (!((magic->is_selecting_spell() && ((sym >= Common::KEYCODE_a && sym <= Common::KEYCODE_z) || sym == Common::KEYCODE_BACKSPACE)) ||
216 		        ((magic->is_waiting_for_location() || last_mode == USE_MODE) && sym >= Common::KEYCODE_1 && sym <= Common::KEYCODE_9))) {
217 			ActionType a = keybinder->get_ActionType(event_->kbd);
218 			action_key_type = keybinder->GetActionKeyType(a);
219 			//switch (action_key_type) {
220 			//default:
221 				if (keybinder->handle_always_available_keys(a)) return true;
222 			//	break;
223 			//}
224 		}
225 		input.type = EVENTINPUT_KEY;
226 		input.key = sym;
227 		input.action_key_type = action_key_type;
228 		// callback should return a true value if it handled the event_
229 		if (action_key_type != CANCEL_ACTION_KEY && message(CB_DATA_READY, (char *) &input))
230 			return true;
231 		callback_target = 0;
232 		endAction(); // no more keys for you! (end KEYINPUT_MODE)
233 		keybinder->HandleEvent(event_);
234 		return true;
235 	}
236 
237 	byte mods = event_->kbd.flags;
238 	// alt-code input
239 	if (mods & Common::KBD_ALT) {
240 		if (mode == MOVE_MODE)
241 			switch (event_->kbd.keycode) {
242 			case Common::KEYCODE_KP0:
243 			case Common::KEYCODE_0:
244 				alt_code_str[alt_code_len++] = '0';
245 				break;
246 
247 			case Common::KEYCODE_KP1:
248 			case Common::KEYCODE_1:
249 				alt_code_str[alt_code_len++] = '1';
250 				break;
251 
252 			case Common::KEYCODE_KP2:
253 			case Common::KEYCODE_2:
254 				alt_code_str[alt_code_len++] = '2';
255 				break;
256 
257 			case Common::KEYCODE_KP3:
258 			case Common::KEYCODE_3:
259 				alt_code_str[alt_code_len++] = '3';
260 				break;
261 
262 			case Common::KEYCODE_KP4:
263 			case Common::KEYCODE_4:
264 				alt_code_str[alt_code_len++] = '4';
265 				break;
266 
267 			case Common::KEYCODE_KP5:
268 			case Common::KEYCODE_5:
269 				alt_code_str[alt_code_len++] = '5';
270 				break;
271 
272 			case Common::KEYCODE_KP6:
273 			case Common::KEYCODE_6:
274 				alt_code_str[alt_code_len++] = '6';
275 				break;
276 
277 			case Common::KEYCODE_KP7:
278 			case Common::KEYCODE_7:
279 				alt_code_str[alt_code_len++] = '7';
280 				break;
281 
282 			case Common::KEYCODE_KP8:
283 			case Common::KEYCODE_8:
284 				alt_code_str[alt_code_len++] = '8';
285 				break;
286 
287 			case Common::KEYCODE_KP9:
288 			case Common::KEYCODE_9:
289 				alt_code_str[alt_code_len++] = '9';
290 				break;
291 			default:
292 				keybinder->HandleEvent(event_);
293 				return true;
294 			}
295 		if (alt_code_len != 0) {
296 			alt_code_str[alt_code_len] = '\0';
297 			if (alt_code_len == 3) {
298 				alt_code(alt_code_str);
299 				clear_alt_code();
300 			}
301 		}
302 		return true;
303 	}
304 
305 	keybinder->HandleEvent(event_);
306 
307 	return true;
308 }
309 
target_spell()310 void Events::target_spell() {
311 	input.type = EVENTINPUT_KEY;
312 	input.key = Common::KEYCODE_RETURN; // only needed to overwrite old value so it isn't a number or backspace
313 	input.action_key_type = DO_ACTION_KEY;
314 	message(CB_DATA_READY, (char *) &input);
315 	callback_target = 0;
316 	endAction();
317 	doAction();
318 }
319 
close_spellbook()320 void Events::close_spellbook() {
321 	if (callback_target) {
322 		callback_target = 0;
323 		endAction();
324 	}
325 	cancelAction();
326 }
327 
handleEvent(const Common::Event * event_)328 bool Events::handleEvent(const Common::Event *event_) {
329 	if (game->user_paused())
330 		return true;
331 
332 	switch (event_->type) {
333 	case Common::EVENT_MOUSEMOVE:
334 		break;
335 	case Common::EVENT_KEYUP:
336 		if (event_->kbd.flags & Common::KBD_ALT) {
337 			clear_alt_code();
338 		}
339 		break;
340 
341 	case Common::EVENT_KEYDOWN:
342 		handleSDL_KEYDOWN(event_);
343 		break;
344 
345 	case Common::EVENT_QUIT:
346 		return false;
347 
348 	default:
349 		break;
350 	}
351 
352 	if (input.get_text && scroll->has_input()) {
353 		if (active_alt_code) {
354 			endAction(); // exit INPUT_MODE
355 			alt_code_input(scroll->get_input().c_str());
356 		} else {
357 			doAction();
358 		}
359 	}
360 	return true;
361 }
362 
get_direction(const char * prompt)363 void Events::get_direction(const char *prompt) {
364 //    use_obj = src;
365 	assert(mode != INPUT_MODE);
366 	set_mode(INPUT_MODE); // saves previous mode
367 	if (prompt)
368 		scroll->display_string(prompt);
369 	input.get_direction = true;
370 
371 	moveCursorToMapWindow();
372 	map_window->centerCursor();
373 	map_window->set_show_cursor(false);
374 //    map_window->set_show_use_cursor(true); // set in moveCursorToMapWindow()
375 	if (do_not_show_target_cursor && direction_selects_target)
376 		map_window->set_show_use_cursor(false);
377 	input.target_init = new MapCoord(map_window->get_cursorCoord()); // depends on MapWindow size
378 }
379 /* This version of get_direction() doesn't show the cursor. */
get_direction(const MapCoord & from,const char * prompt)380 void Events::get_direction(const MapCoord &from, const char *prompt) {
381 	get_direction(prompt);
382 	map_window->moveCursor(from.x - map_window->get_cur_x(), from.y - map_window->get_cur_y());
383 	input.target_init->x = from.x;
384 	input.target_init->y = from.y;
385 	if (input_really_needs_directon()) { // actually getting a direction
386 		if (!direction_selects_target)
387 			map_window->set_show_cursor(true);
388 		map_window->set_show_use_cursor(false);
389 		map_window->set_mousecenter(from.x - map_window->get_cur_x(), from.y - map_window->get_cur_y());
390 	}
391 }
392 
get_target(const char * prompt)393 void Events::get_target(const char *prompt) {
394 //    use_obj = src;
395 	assert(mode != INPUT_MODE);
396 	set_mode(INPUT_MODE); // saves previous mode
397 	if (prompt)
398 		scroll->display_string(prompt);
399 	input.get_direction = false;
400 
401 	map_window->centerCursor();
402 	moveCursorToMapWindow();
403 }
404 
get_target(const MapCoord & init,const char * prompt)405 void Events::get_target(const MapCoord &init, const char *prompt) {
406 	get_target(prompt);
407 	map_window->moveCursor(init.x, init.y);
408 }
409 
410 /* Switch focus to MsgScroll and start getting user input. */
get_scroll_input(const char * allowed,bool can_escape,bool using_target_cursor,bool set_numbers_only_to_true)411 void Events::get_scroll_input(const char *allowed,
412 							 bool can_escape,
413 							 bool using_target_cursor,
414 							 bool set_numbers_only_to_true) {
415 	assert(scroll);
416 	if (!using_target_cursor) {
417 		assert(mode != INPUT_MODE);
418 		set_mode(INPUT_MODE); // saves previous mode
419 	}
420 	input.get_text = true;
421 	scroll->set_input_mode(true, allowed, can_escape, using_target_cursor, set_numbers_only_to_true);
422 //no need to grab focus because any input will eventually reach MsgScroll,
423 //    scroll->grab_focus();
424 }
425 
get_inventory_obj(Actor * actor,bool getting_target)426 void Events::get_inventory_obj(Actor *actor, bool getting_target) {
427 	if (getting_target) {
428 		get_target("");
429 		moveCursorToInventory();
430 	} else if (!game->is_new_style())
431 		view_manager->set_inventory_mode();
432 	if (game->is_new_style()) {
433 		//view_manager->set_inventory_mode();
434 		view_manager->open_container_view(actor); //FIXME need to open container gump in pickpocket mode.
435 		view_manager->open_doll_view(actor);
436 	} else {
437 		view_manager->get_inventory_view()->set_actor(actor, true);
438 	}
439 }
440 
get_spell_num(Actor * caster,Obj * spell_container)441 void Events::get_spell_num(Actor *caster, Obj *spell_container) {
442 	//get_target("");
443 	view_manager->set_spell_mode(caster, spell_container, true);
444 	view_manager->get_current_view()->grab_focus();
445 }
446 
447 /* Send all keyboard input to caller, with user_data.
448    ESC always cancels sending any further input. */
key_redirect(CallBack * caller,void * user_data)449 void Events::key_redirect(CallBack *caller, void *user_data) {
450 	assert(mode != INPUT_MODE && mode != KEYINPUT_MODE);
451 	request_input(caller, user_data);
452 	set_mode(KEYINPUT_MODE); // saves previous mode
453 }
454 
cancel_key_redirect()455 void Events::cancel_key_redirect() {
456 	assert(mode == KEYINPUT_MODE);
457 	endAction();
458 }
459 
460 /* Switch focus to PortraitView, display a portrait, and wait for user input. */
display_portrait(Actor * actor,const char * name)461 void Events::display_portrait(Actor *actor, const char *name) {
462 	view_manager->set_portrait_mode(actor, name);
463 	view_manager->get_portrait_view()->set_waiting(true);
464 }
465 
466 /* Set callback & callback_user_data so that a message will be sent to the
467  * caller when input has been gathered. */
request_input(CallBack * caller,void * user_data)468 void Events::request_input(CallBack *caller, void *user_data) {
469 	callback_target = caller;
470 	callback_user_data = (char *) user_data;
471 }
472 
473 // typically this will be coming from inventory
select_obj(Obj * obj,Actor * actor)474 bool Events::select_obj(Obj *obj, Actor *actor) {
475 	if (looking_at_spellbook && view_manager->get_spell_view() != NULL) {
476 		view_manager->get_spell_view()->close_look();
477 		return false;
478 	}
479 	assert(mode == INPUT_MODE);
480 	//assert(input.select_from_inventory == true);
481 
482 	input.type = EVENTINPUT_OBJECT;
483 	input.obj = obj;
484 	input.actor = actor;
485 	endAction(); // mode = prev_mode
486 	doAction();
487 	return true;
488 }
489 
select_actor(Actor * actor)490 bool Events::select_actor(Actor *actor) {
491 	assert(mode == INPUT_MODE);
492 
493 	input.type = EVENTINPUT_MAPCOORD;
494 	input.actor = actor;
495 	input.set_loc(actor->get_location());
496 	endAction(); // mode = prev_mode
497 	doAction();
498 	return true;
499 }
500 
select_direction(sint16 rel_x,sint16 rel_y)501 bool Events::select_direction(sint16 rel_x, sint16 rel_y) {
502 	assert(mode == INPUT_MODE);
503 	assert(input.get_direction == true);
504 
505 	input.type = EVENTINPUT_MAPCOORD_DIR;
506 	input.set_loc(MapCoord(rel_x, rel_y));
507 	// assumes mapwindow cursor is at the location
508 	input.actor = map_window->get_actorAtCursor();
509 	input.obj = map_window->get_objAtCursor();
510 	endAction(); // mode = prev_mode
511 	doAction();
512 	return true;
513 }
514 
515 // automatically converted to direction if requested
select_target(uint16 x,uint16 y,uint8 z)516 bool Events::select_target(uint16 x, uint16 y, uint8 z) {
517 	// FIXME: is this even correct behavior?! if an arrow key is used, a direction
518 	// should be returned, but you can still select any target with the mouse
519 	// (which works, but then what's the point of using directions?)
520 	if (input.get_direction)
521 		return select_direction(x - input.target_init->x,
522 		                        y - input.target_init->y);
523 	if (mode != ATTACK_MODE) { // FIXME: make ATTACK_MODE use INPUT_MODE
524 		// need to handle weapon range
525 		assert(mode == INPUT_MODE);
526 
527 		input.type = EVENTINPUT_MAPCOORD;
528 		input.set_loc(MapCoord(x, y, z));
529 		// assumes mapwindow cursor is at the location
530 		input.actor = map_window->get_actorAtCursor();
531 		input.obj = map_window->get_objAtCursor();
532 		endAction(); // mode = prev_mode
533 	}
534 	doAction();
535 	return true;
536 }
537 
538 // called when selecting an actor by number
select_party_member(uint8 num)539 bool Events::select_party_member(uint8 num) {
540 	Party *party = player->get_party();
541 	if (num < party->get_party_size()) {
542 		select_actor(party->get_actor(num));
543 		return true;
544 	}
545 	return false;
546 }
547 
select_spell_num(sint16 spell_num)548 bool Events::select_spell_num(sint16 spell_num) {
549 	//assert(mode == INPUT_MODE);
550 	//assert(input.select_from_inventory == true);
551 
552 
553 
554 	input.type = EVENTINPUT_SPELL_NUM;
555 	input.spell_num = spell_num;
556 	//endAction(); // mode = prev_mode
557 	game->get_view_manager()->close_spell_mode();
558 	doAction();
559 	return true;
560 }
561 
562 // move the cursor or walk around; do action for direction-targeted modes
move(sint16 rel_x,sint16 rel_y)563 bool Events::move(sint16 rel_x, sint16 rel_y) {
564 	MapCoord cursor_coord;
565 
566 	if (game->user_paused())
567 		return false;
568 	EventMode current_mode;
569 	if (last_mode == MULTIUSE_MODE && game->get_party()->is_in_combat_mode())
570 		current_mode = ATTACK_MODE;
571 	else
572 		current_mode = mode;
573 
574 	switch (current_mode) {
575 	case ATTACK_MODE     :
576 		cursor_coord = map_window->get_cursorCoord();
577 		cursor_coord.x = WRAPPED_COORD(cursor_coord.x + rel_x, cursor_coord.z);
578 		cursor_coord.y = WRAPPED_COORD(cursor_coord.y + rel_y, cursor_coord.z);
579 		if (!player->weapon_can_hit(cursor_coord.x, cursor_coord.y))
580 			break;
581 		DEBUG(0, LEVEL_DEBUGGING, "attack select(%d,%d)\n", cursor_coord.x, cursor_coord.y);
582 		map_window->moveCursorRelative(rel_x, rel_y);
583 		break;
584 
585 	case EQUIP_MODE      :
586 		map_window->moveCursorRelative(rel_x, rel_y);
587 		break;
588 
589 	case INPUT_MODE      : {
590 		bool needs_dir = input_really_needs_directon();
591 		if (!direction_selects_target && needs_dir) {
592 			cursor_coord = map_window->get_cursorCoord();
593 			cursor_coord.x = WRAPPED_COORD(cursor_coord.x + rel_x, cursor_coord.z);
594 			cursor_coord.y = WRAPPED_COORD(cursor_coord.y + rel_y, cursor_coord.z);
595 			if (input.target_init->distance(cursor_coord) > 1)
596 				break;
597 		} else if (last_mode == CAST_MODE) {
598 			cursor_coord = map_window->get_cursorCoord();
599 			cursor_coord.x = WRAPPED_COORD(cursor_coord.x + rel_x, cursor_coord.z);
600 			cursor_coord.y = WRAPPED_COORD(cursor_coord.y + rel_y, cursor_coord.z);
601 			if (player->get_actor()->get_range(cursor_coord.x, cursor_coord.y) > 7)
602 				break;
603 		}
604 		map_window->moveCursorRelative(rel_x, rel_y);
605 		if (direction_selects_target && needs_dir)
606 			select_direction(rel_x, rel_y);
607 		break;
608 	}
609 	default              :
610 		if (player->check_walk_delay() && !view_manager->gumps_are_active()) {
611 			player->moveRelative(rel_x, rel_y);
612 			game->time_changed();
613 		}
614 		break;
615 	}
616 
617 	return true;
618 }
619 
620 /* Begin a conversation with an actor if him/her/it is willing to talk.
621  * Returns true if conversation starts.
622  */
perform_talk(Actor * actor)623 bool Events::perform_talk(Actor *actor) {
624 	ActorManager *actor_manager = game->get_actor_manager();
625 	Actor *pc = player->get_actor();
626 	uint8 id = actor->get_actor_num();
627 
628 	if (game->get_game_type() != NUVIE_GAME_U6) {
629 		return game->get_script()->call_talk_to_actor(actor);
630 	}
631 
632 	if (actor->is_in_vehicle()) {
633 		scroll->display_string("Not in vehicle.\n");
634 		return false;
635 	}
636 	if (id == pc->get_actor_num()) {  // actor is controlled by player
637 		// Note: being the player, this should ALWAYS use the real name
638 		scroll->display_string(actor->get_name());
639 		scroll->display_string("\n");
640 		scroll->display_string("Talking to yourself?\n");
641 		return false;
642 	}
643 	if (actor->is_in_party() && !actor->is_onscreen()) {
644 		scroll->display_string(actor->get_name());
645 		scroll->display_string("\n");
646 		scroll->display_string("Not on screen.\n");
647 		return false;
648 	}
649 	// FIXME: this check and the "no response" messages should be in Converse
650 	if (!player->in_party_mode() && !pc->is_avatar()) { //only the avatar can talk in solo mode
651 		// always display look-string on failure
652 		scroll->display_string(actor->get_name());
653 		scroll->display_string("\n");
654 		scroll->display_string("Not in solo mode.\n");
655 	} else if (actor->is_sleeping() || actor->is_paralyzed() || actor->get_corpser_flag()
656 	           || actor->get_alignment() == ACTOR_ALIGNMENT_EVIL
657 	           || actor->get_alignment() == ACTOR_ALIGNMENT_CHAOTIC
658 	           || (actor->get_alignment() == ACTOR_ALIGNMENT_NEUTRAL && actor->will_not_talk())) {
659 		// always display name or look-string on failure
660 		scroll->display_string(actor->get_name());
661 		scroll->display_string("\n\nNo response\n");
662 	} else if (game->get_converse()->start(actor)) {  // load and begin npc script
663 		// try to use real name
664 		scroll->display_string(actor->get_name());
665 		scroll->display_string("\n");
666 		// turn towards eachother
667 		pc->face_actor(actor);
668 		if (!actor->is_immobile())
669 			actor->face_actor(pc);
670 		return (true);
671 	} else {  // some actor that has no script
672 		// always display look-string on failure
673 		scroll->display_string(actor_manager->look_actor(actor));
674 		scroll->display_string("\n");
675 		scroll->display_string("Funny, no response.\n");
676 	}
677 	return (false);
678 }
679 
680 /* Talk to `actor'. Return to the prompt if no conversation starts.
681  * Returns the result of the talk function.
682  */
talk(Actor * actor)683 bool Events::talk(Actor *actor) {
684 	bool talking = true;
685 	if (game->user_paused())
686 		return (false);
687 
688 	endAction();
689 
690 	if (!actor) {
691 		scroll->display_string("nothing!\n");
692 		talking = false;
693 	} else if (!perform_talk(actor))
694 		talking = false;
695 
696 	if (!talking) {
697 //        scroll->display_string("\n");
698 //        scroll->display_prompt();
699 		endAction(true);
700 	}
701 	return (talking);
702 }
703 
talk_cursor()704 bool Events::talk_cursor() {
705 	Actor *actor = map_window->get_actorAtCursor();
706 	if (actor && input.actor->is_visible())
707 		return talk(actor);
708 	return talk(map_window->get_objAtCursor());
709 }
710 
talk_start()711 bool Events::talk_start() {
712 	if (game->user_paused())
713 		return (false);
714 	close_gumps();
715 	get_target("Talk-");
716 	return true;
717 }
718 
719 /* You can talk to some objects using their quality as actor number. */
talk(Obj * obj)720 bool Events::talk(Obj *obj) {
721 	ActorManager *actor_manager = game->get_actor_manager();
722 	if (obj) {
723 		if (game->get_game_type() == NUVIE_GAME_U6) {
724 			if (obj->obj_n == OBJ_U6_SHRINE
725 			        || obj->obj_n == OBJ_U6_STATUE_OF_MONDAIN
726 			        || obj->obj_n == OBJ_U6_STATUE_OF_MINAX
727 			        || obj->obj_n == OBJ_U6_STATUE_OF_EXODUS)
728 				return (talk(actor_manager->get_actor(obj->quality)));
729 		} else {
730 			endAction();
731 			bool status = game->get_script()->call_talk_to_obj(obj);
732 			if (status == false) {
733 				scroll->display_string("\n");
734 				scroll->display_prompt();
735 			}
736 			return status;
737 		}
738 	}
739 	scroll->display_string("nothing!\n");
740 	endAction();
741 	scroll->display_string("\n");
742 	scroll->display_prompt();
743 	return (false);
744 }
745 
try_next_attack()746 void Events::try_next_attack() {
747 	if (Game::get_game()->get_actor_manager()->get_avatar()->get_hp() == 0) { // need to end turn if Avatar died
748 		endAction();
749 		Game::get_game()->get_actor_manager()->startActors();
750 		return;
751 	} else if (player->attack_select_next_weapon(true) == false) {
752 		player->subtract_movement_points(10);
753 		game->get_actor_manager()->startActors(); // end player turn
754 		endAction();
755 	} else {
756 		map_window->set_show_cursor(true);
757 		mode = ATTACK_MODE; // FIXME: need to return after WAIT_MODE
758 		//endAction(false);
759 		//newAction(ATTACK_MODE);
760 	}
761 }
762 
attack()763 bool Events::attack() {
764 	MapCoord target = map_window->get_cursorCoord();
765 	Actor *actor = map_window->get_actorAtCursor();
766 	Actor *p = player->get_actor();
767 	bool tile_is_black = map_window->tile_is_black(target.x, target.y);
768 
769 	if (game->get_script()->call_out_of_ammo(p, p->get_weapon_obj(player->get_current_weapon()), true)) {
770 		// the function prints out the message
771 		try_next_attack(); // SE and MD have weapons that need ammo and only take up 1 slot
772 		return true;
773 	} else if (tile_is_black)
774 		scroll->display_string("nothing!\n");
775 	else if (actor) {
776 		if (actor->get_actor_num() == player->get_actor()->get_actor_num() //don't attack yourself.
777 		        || (actor->is_in_party() && actor->get_alignment() == ACTOR_ALIGNMENT_GOOD)) {
778 			ActorManager *actor_manager = game->get_actor_manager();
779 			Actor *a = actor_manager->get_actor(actor->get_x(), actor->get_y(), actor->get_z(), true, actor);
780 			if (a) // exclude previous target if we find another actor
781 				actor = a;
782 			else if (actor->get_actor_num() == player->get_actor()->get_actor_num()) {
783 				scroll->display_string("pass.\n");
784 				player->subtract_movement_points(10);
785 				endAction(true);
786 				return true;
787 			}
788 		}
789 		if (actor->is_visible()) {
790 			scroll->display_string(actor->get_name());
791 			scroll->display_string(".\n");
792 		}
793 	}
794 	if ((!actor || !actor->is_visible()) && !tile_is_black) {
795 		Obj *obj = map_window->get_objAtCursor();
796 		if (obj && (!obj->is_on_map() || !map_window->tile_is_black(obj->x, obj->y, obj))) {
797 			scroll->display_string(obj_manager->get_obj_name(obj->obj_n, obj->frame_n));
798 			scroll->display_string(".\n");
799 		} else {
800 			scroll->display_string(game->get_game_map()->look(target.x, target.y, target.z));
801 			scroll->display_string(".\n");
802 		}
803 	}
804 
805 	map_window->set_show_cursor(false);
806 	player->attack(target, actor);
807 
808 	try_next_attack();
809 
810 	return true;
811 }
812 
get_start()813 bool Events::get_start() {
814 	if (game->user_paused())
815 		return false;
816 	if (game->get_script()->call_is_ranged_select(GET))
817 		get_target("Get-");
818 	else
819 		get_direction("Get-");
820 	return true;
821 }
822 
push_start()823 bool Events::push_start() {
824 	if (game->user_paused())
825 		return false;
826 	push_obj = NULL;
827 	push_actor = NULL;
828 	if (game->get_script()->call_is_ranged_select(MOVE))
829 		get_target("Move-");
830 	else
831 		get_direction("Move-");
832 	return true;
833 }
834 
835 /* Get object into an actor. (no mode change) */
perform_get(Obj * obj,Obj * container_obj,Actor * actor)836 bool Events::perform_get(Obj *obj, Obj *container_obj, Actor *actor) {
837 	bool got_object = false;
838 	bool can_perform_get = false;
839 	//float weight;
840 	if (game->user_paused())
841 		return (false);
842 
843 	if (obj) {
844 		if (!actor)
845 			actor = player->get_actor();
846 
847 		if (obj->is_on_map() && map_window->tile_is_black(obj->x, obj->y, obj)) {
848 			scroll->display_string("nothing");
849 		} else {
850 			scroll->display_string(obj_manager->look_obj(obj));
851 
852 			if (game->using_hackmove())
853 				can_perform_get = true;
854 			else if (!map_window->can_get_obj(actor, obj)) {
855 				scroll->display_string("\n\nCan't reach it.");
856 			} else if (obj->is_on_map()) {
857 				MapCoord target(obj->x, obj->y, obj->z);
858 				if (!game->get_script()->call_is_ranged_select(GET)
859 				        && player->get_actor()->get_location().distance(target) > 1
860 				        && map_window->get_interface() == INTERFACE_NORMAL) {
861 					scroll->display_string("\n\nOut of range!");
862 				} else if (obj_manager->obj_is_damaging(obj, actor)) {
863 					return false;
864 				} else {
865 					can_perform_get = true;
866 				}
867 			} else {
868 				can_perform_get = true;
869 			}
870 		}
871 	} else
872 		scroll->display_string("nothing");
873 
874 	if (can_perform_get) {
875 		// perform GET usecode (can't add to container)
876 		if (usecode->has_getcode(obj) && (usecode->get_obj(obj, actor) == false)) {
877 			game->get_script()->call_actor_subtract_movement_points(actor, 3);
878 			scroll->display_string("\n");
879 			scroll->display_prompt();
880 			map_window->updateBlacking();
881 			return (false); // ???
882 		}
883 
884 		got_object = game->get_script()->call_actor_get_obj(actor, obj, container_obj);
885 	}
886 
887 	scroll->display_string("\n\n");
888 	scroll->display_prompt();
889 	map_window->updateBlacking();
890 	return (got_object);
891 }
892 
893 /* Get object at selected position, and end action. */
get(sint16 rel_x,sint16 rel_y)894 bool Events::get(sint16 rel_x, sint16 rel_y) {
895 	uint16 x, y;
896 	uint8 level;
897 
898 	player->get_location(&x, &y, &level);
899 	return get(MapCoord((uint16)(x + rel_x), (uint16)(y + rel_y), level));
900 }
901 
get(MapCoord coord)902 bool Events::get(MapCoord coord) {
903 	Obj *obj = obj_manager->get_obj(coord.x, coord.y, coord.z, OBJ_SEARCH_TOP, OBJ_EXCLUDE_IGNORED);
904 	bool got_object;
905 	if (!game->is_new_style())
906 		got_object = perform_get(obj, view_manager->get_inventory_view()->get_inventory_widget()->get_container(),
907 		                         player->get_actor());
908 	else
909 		got_object = perform_get(obj, NULL, player->get_actor());
910 	view_manager->update(); //redraw views to show new item.
911 	endAction();
912 
913 	return got_object;
914 }
915 
use_start()916 bool Events::use_start() {
917 	if (game->user_paused())
918 		return false;
919 	if (game->get_script()->call_is_ranged_select(USE))
920 		get_target("Use-");
921 	else
922 		get_direction("Use-");
923 
924 	return true;
925 }
926 
use(Obj * obj)927 bool Events::use(Obj *obj) {
928 	if (game->user_paused())
929 		return false;
930 	if (obj && obj->is_on_map() && map_window->tile_is_black(obj->x, obj->y, obj)) {
931 		Obj *bottom_obj = obj_manager->get_obj(obj->x, obj->y, obj->z, false);
932 		if (game->get_game_type() == NUVIE_GAME_U6 && bottom_obj->obj_n == OBJ_U6_SECRET_DOOR // hack for frame 2
933 		        && !map_window->tile_is_black(obj->x, obj->y, bottom_obj))
934 			obj = bottom_obj;
935 		else
936 			obj = NULL;
937 	}
938 	if (!obj) {
939 		scroll->display_string("nothing\n");
940 		endAction(true);
941 		return true;
942 	}
943 	MapCoord target(obj->x, obj->y, obj->z);
944 	MapCoord player_loc = player->get_actor()->get_location();
945 	bool display_prompt = true;
946 
947 	scroll->display_string(obj_manager->look_obj(obj));
948 	scroll->display_string("\n");
949 
950 	if (!usecode->has_usecode(obj)) {
951 		scroll->display_string("\nNot usable\n");
952 		DEBUG(0, LEVEL_DEBUGGING, "Object %d:%d\n", obj->obj_n, obj->frame_n);
953 	} else if (!obj->is_in_inventory() && map_window->get_interface() == INTERFACE_NORMAL
954 	           && !game->get_script()->call_is_ranged_select(USE) && player->get_actor()->get_location().distance(target) > 1) {
955 		scroll->display_string("\nOut of range!\n");
956 		DEBUG(0, LEVEL_DEBUGGING, "distance to object: %d\n", player->get_actor()->get_location().distance(target));
957 	} else if (!player->in_party_mode() && obj->is_in_inventory() && !obj->get_actor_holding_obj()->is_onscreen()) {
958 		scroll->display_string("\nNot on screen.\n");
959 	} else if (!obj->is_in_inventory() && !game->get_script()->call_is_ranged_select(USE)
960 	           && !map_window->can_get_obj(player->get_actor(), obj) && player_loc != target) {
961 		scroll->display_string("\nCan't reach it\n");
962 	} else { // Usable
963 		display_prompt = usecode->use_obj(obj, player->get_actor());
964 		player->subtract_movement_points(MOVE_COST_USE);
965 	}
966 
967 	if (mode == USE_MODE && usecode->get_running_script() == NULL) // check mode because UseCode may have changed it
968 		endAction(display_prompt);
969 	return true;
970 }
971 
use(Actor * actor,uint16 x,uint16 y)972 bool Events::use(Actor *actor, uint16 x, uint16 y) {
973 	if (game->user_paused())
974 		return false;
975 	bool display_prompt = true;
976 	Obj *obj = actor->make_obj();
977 
978 	if (!map_window->tile_is_black(x, y) && usecode->has_usecode(actor)) {
979 		if (game->get_game_type() == NUVIE_GAME_U6 && obj->obj_n == OBJ_U6_HORSE_WITH_RIDER)
980 			scroll->display_string("horse");
981 		else
982 			scroll->display_string(obj_manager->look_obj(obj));
983 		scroll->display_string("\n");
984 
985 		MapCoord player_loc = player->get_actor()->get_location();
986 		MapCoord target = MapCoord(x, y, player_loc.z);
987 
988 		if (player_loc.distance(target) > 1
989 		        && map_window->get_interface() == INTERFACE_NORMAL) {
990 			scroll->display_string("\nOut of range!\n");
991 			DEBUG(0, LEVEL_DEBUGGING, "distance to object: %d\n", player_loc.distance(target));
992 		} else if (!can_get_to_actor(actor, x, y))
993 			scroll->display_string("\nBlocked.\n");
994 		else {
995 			display_prompt = usecode->use_obj(obj, player->get_actor());
996 			player->subtract_movement_points(5);
997 		}
998 	} else {
999 		scroll->display_string("nothing\n");
1000 		DEBUG(0, LEVEL_DEBUGGING, "Object %d:%d\n", obj->obj_n, obj->frame_n);
1001 	}
1002 // FIXME: usecode might request input, causing the obj to be accessed again,
1003 // so we can't delete it in that case
1004 	assert(mode == USE_MODE || game->user_paused());
1005 	delete_obj(obj); // we were using an actor so free the temp Obj
1006 	if (mode == USE_MODE) // check mode because UseCode may have changed it
1007 		endAction(display_prompt);
1008 	return (true);
1009 }
1010 
use(sint16 rel_x,sint16 rel_y)1011 bool Events::use(sint16 rel_x, sint16 rel_y) {
1012 	map_window->centerCursor();
1013 	map_window->moveCursorRelative(rel_x, rel_y);
1014 	return use(map_window->get_cursorCoord());
1015 }
1016 
use(MapCoord coord)1017 bool Events::use(MapCoord coord) {
1018 	if (game->user_paused())
1019 		return false;
1020 
1021 	if (!map_window->tile_is_black(coord.x, coord.y)) {
1022 		Actor *actor = game->get_actor_manager()->get_actor(coord.x, coord.y, coord.z);
1023 		Obj *obj = map_window->get_objAtCoord(coord, OBJ_SEARCH_TOP, OBJ_EXCLUDE_IGNORED, true);
1024 
1025 		if (obj && obj->is_on_map() && map_window->tile_is_black(obj->x, obj->y, obj)) {
1026 			Obj *bottom_obj = obj_manager->get_obj(obj->x, obj->y, obj->z, false);
1027 			if (game->get_game_type() == NUVIE_GAME_U6 && bottom_obj->obj_n == OBJ_U6_SECRET_DOOR // hack for frame 2
1028 			        && !map_window->tile_is_black(obj->x, obj->y, bottom_obj))
1029 				obj = bottom_obj;
1030 			else
1031 				obj = NULL;
1032 		}
1033 		bool visible_actor = actor && actor->is_visible();
1034 
1035 		if (obj && (!visible_actor || !usecode->has_usecode(actor)))
1036 			return (use(obj));
1037 		if (visible_actor) {
1038 			return (use(actor, coord.x, coord.y));
1039 		}
1040 	}
1041 
1042 	scroll->display_string("nothing\n");
1043 	endAction(true);
1044 	return true;
1045 }
1046 
look_start()1047 bool Events::look_start() {
1048 	if (game->user_paused())
1049 		return (false);
1050 	get_target("Look-");
1051 	return true;
1052 }
1053 
1054 /* Returns true if object can be searched. (false if prompt shouldn't be shown)
1055  */
look(Obj * obj)1056 bool Events::look(Obj *obj) {
1057 	if (game->user_paused())
1058 		return (false);
1059 
1060 	if (obj) {
1061 		if (game->get_game_type() == NUVIE_GAME_U6) {
1062 			if (obj->obj_n == OBJ_U6_STATUE_OF_MONDAIN
1063 			        || obj->obj_n == OBJ_U6_STATUE_OF_MINAX
1064 			        || obj->obj_n == OBJ_U6_STATUE_OF_EXODUS) {
1065 				Actor *actor = game->get_actor_manager()->get_actor(obj->quality);
1066 				look(actor);
1067 				return false;
1068 			} else if (obj->obj_n == OBJ_U6_SPELLBOOK) {
1069 				looking_at_spellbook = true;
1070 				game->get_script()->call_look_obj(obj);
1071 				Actor *reader = obj->get_actor_holding_obj();
1072 				if (!reader)
1073 					reader = player->get_actor();
1074 				view_manager->close_all_gumps();
1075 				view_manager->set_spell_mode(reader, obj, false);
1076 				view_manager->get_current_view()->grab_focus();
1077 				return false;
1078 			}
1079 		}
1080 		obj_manager->print_obj(obj, false); // DEBUG
1081 		/*      if(game->is_new_style())
1082 		      {
1083 		          new TextEffect(obj_manager->look_obj(obj, true), MapCoord((obj->x - map_window->get_cur_x())*16,(obj->y-map_window->get_cur_y())*16,obj->z));
1084 		      }*/
1085 		if (game->get_script()->call_look_obj(obj) == false) {
1086 			scroll->display_prompt();
1087 			return false;
1088 		}
1089 	}
1090 
1091 	return true;
1092 }
1093 
1094 /* Returns true if there was a portrait for actor. */
look(Actor * actor)1095 bool Events::look(Actor *actor) {
1096 	ActorManager *actor_manager = game->get_actor_manager();
1097 	sint16 p_id = -1; // party member number of actor
1098 	bool had_portrait = false;
1099 
1100 	if (game->user_paused())
1101 		return (false);
1102 
1103 	if (actor->get_actor_num() != 0) {
1104 		display_portrait(actor);
1105 		had_portrait = view_manager->get_portrait_view()->get_waiting();
1106 	}
1107 
1108 	actor_manager->print_actor(actor); // DEBUG
1109 	scroll->display_string("Thou dost see ");
1110 	// show real actor name and portrait if in avatar's party
1111 	if ((p_id = player->get_party()->get_member_num(actor)) >= 0)
1112 		scroll->display_string(player->get_party()->get_actor_name(p_id));
1113 	else
1114 		scroll->display_string(actor_manager->look_actor(actor, true));
1115 	scroll->display_string("\n");
1116 	return (had_portrait);
1117 }
1118 
search(Obj * obj)1119 bool Events::search(Obj *obj) {
1120 	MapCoord player_loc = player->get_actor()->get_location(),
1121 	         target_loc = map_window->get_cursorCoord();
1122 
1123 	if (game->user_paused())
1124 		return (false);
1125 
1126 	if (obj->get_engine_loc() == OBJ_LOC_MAP && player_loc.distance(target_loc) <= 1) {
1127 		scroll->display_string("\nSearching here, you find ");
1128 		if (!usecode->search_obj(obj, player->get_actor()))
1129 			scroll->display_string("nothing.\n");
1130 		else {
1131 			scroll->display_string(".\n");
1132 			map_window->updateBlacking(); // secret doors
1133 		}
1134 		return (true);
1135 	}
1136 	return (false);
1137 }
1138 
1139 // looks at the whatever is at MapWindow cursor location
lookAtCursor(bool delayed,uint16 x,uint16 y,uint8 z,Obj * obj,Actor * actor)1140 bool Events::lookAtCursor(bool delayed, uint16 x, uint16 y, uint8 z, Obj *obj, Actor *actor) {
1141 	bool display_prompt = true;
1142 
1143 	if (!delayed) {
1144 		x = map_window->get_cursorCoord().x;
1145 		y = map_window->get_cursorCoord().y;
1146 		z = map_window->get_cursorCoord().z;
1147 		obj = map_window->get_objAtCursor();
1148 		actor = map_window->get_actorAtCursor();
1149 	}
1150 
1151 	if (obj && obj->is_on_map() && ((obj->status & OBJ_STATUS_INVISIBLE) || map_window->tile_is_black(x, y, obj))) {
1152 		Obj *bottom_obj = obj_manager->get_obj(x, y, z, false);
1153 		if (game->get_game_type() == NUVIE_GAME_U6 && bottom_obj->obj_n == OBJ_U6_SECRET_DOOR // hack for frame 2
1154 		        && !map_window->tile_is_black(x, y, bottom_obj))
1155 			obj = bottom_obj;
1156 		else
1157 			obj = NULL;
1158 	}
1159 	if (game->user_paused())
1160 		return false;
1161 
1162 	if (map_window->tile_is_black(x, y))
1163 		scroll->display_string("Thou dost see darkness.\n");
1164 	else if (actor && actor->is_visible())
1165 		display_prompt = !look(actor);
1166 	else if (obj) {
1167 		if (look(obj))
1168 			search(obj);
1169 		else
1170 			display_prompt = false;
1171 	} else { // ground
1172 		scroll->display_string("Thou dost see ");
1173 		/*   if(game->is_new_style())
1174 		     new TextEffect(game->get_game_map()->look(x, y, z), MapCoord((x - map_window->get_cur_x())*16,(y-map_window->get_cur_y())*16,z));*/
1175 		scroll->display_string(game->get_game_map()->look(x, y, z));
1176 		scroll->display_string("\n");
1177 	}
1178 
1179 	endAction(display_prompt);
1180 	return true;
1181 }
1182 
pushTo(Obj * obj,Actor * actor)1183 bool Events::pushTo(Obj *obj, Actor *actor) {
1184 	bool ok = false;
1185 
1186 	if (obj) {
1187 		if (game->get_game_type() == NUVIE_GAME_SE || push_obj != obj)
1188 			scroll->display_string(obj_manager->look_obj(obj));
1189 		scroll->display_string("\n");
1190 
1191 		if (obj_manager->can_store_obj(obj, push_obj)) {
1192 			if (obj->is_in_inventory()) {
1193 				Actor *src_actor = game->get_player()->get_actor();
1194 				Actor *target_actor = obj->get_actor_holding_obj();
1195 				if (can_move_obj_between_actors(push_obj, src_actor, target_actor, false))
1196 					obj_manager->moveto_container(push_obj, obj);
1197 				scroll->message("\n\n");
1198 				endAction();
1199 				return (true);
1200 			}
1201 			ok = obj_manager->moveto_container(push_obj, obj);
1202 		}
1203 	} else {
1204 		if (actor) {
1205 			Actor *src_actor;
1206 			if (push_obj->is_in_inventory())
1207 				src_actor = push_obj->get_actor_holding_obj();
1208 			else
1209 				src_actor = game->get_player()->get_actor();
1210 
1211 			if (can_move_obj_between_actors(push_obj, src_actor, actor, true))
1212 				obj_manager->moveto_inventory(push_obj, actor);
1213 			scroll->message("\n\n");
1214 			endAction();
1215 			return (true);
1216 		} else {
1217 			scroll->message("nobody.\n\n");
1218 			endAction();
1219 			return false;
1220 		}
1221 	}
1222 
1223 	if (!ok) {
1224 		if (obj == push_obj) {
1225 			if (game->get_game_type() == NUVIE_GAME_MD)
1226 				scroll->display_string("\nAn item can't be placed inside itself!\n\n");
1227 			else if (game->get_game_type() == NUVIE_GAME_SE)
1228 				scroll->display_string("\nYou can't do that!\n\n");
1229 			else if (obj->container)
1230 				scroll->display_string("\nHow can a container go into itself!\n\n");
1231 			else
1232 				scroll->display_string("\nnot a container\n\n");
1233 		} else if (game->get_game_type() == NUVIE_GAME_U6 && obj->obj_n == OBJ_U6_VORTEX_CUBE)
1234 			scroll->display_string("\nOnly moonstones can go into the vortex cube.\n\n");
1235 		else if (game->get_game_type() == NUVIE_GAME_U6 && obj->obj_n == OBJ_U6_SPELLBOOK) {
1236 			if (push_obj->obj_n == OBJ_U6_SPELL)
1237 				scroll->display_string("\nThe spellbook already has this spell.\n\n");
1238 			else
1239 				scroll->display_string("\nOnly spells can go into the spellbook.\n\n");
1240 		} else if (game->get_game_type() == NUVIE_GAME_U6 && !obj->container)
1241 			scroll->display_string("\nnot a container\n\n");
1242 		else if (game->get_game_type() == NUVIE_GAME_U6)
1243 			scroll->display_string("\nNot possible!\n\n");
1244 		else
1245 			scroll->display_string("\nYou can't do that!\n\n");
1246 	}
1247 
1248 	scroll->display_prompt();
1249 	endAction();
1250 	return (true);
1251 }
1252 
1253 /* Move selected object in direction relative to object.
1254  * (coordinates can be relative to player or object)
1255  */
pushTo(sint16 rel_x,sint16 rel_y,bool push_from)1256 bool Events::pushTo(sint16 rel_x, sint16 rel_y, bool push_from) {
1257 	Tile *obj_tile;
1258 	bool can_move = false; // some checks must determine if object can_move
1259 	Map *map = game->get_game_map();
1260 	MapCoord pusher = player->get_actor()->get_location();
1261 	MapCoord from, to; // absolute locations: object, target
1262 	sint16 pushrel_x, pushrel_y; // direction relative to object
1263 	LineTestResult lt;
1264 	Script *script = game->get_script();
1265 
1266 	if (game->user_paused())
1267 		return (false);
1268 
1269 	if (!push_actor && !push_obj) {
1270 		scroll->display_string("what?\n\n");
1271 		scroll->display_prompt();
1272 		endAction();
1273 		return (false);
1274 	}
1275 
1276 	if (push_actor) {
1277 		if (!push_actor->can_be_moved() || push_actor->get_tile_type() != ACTOR_ST) {
1278 			scroll->display_string("Not possible\n\n");
1279 			scroll->display_prompt();
1280 			endAction();
1281 			return false;
1282 		}
1283 		from = push_actor->get_location();
1284 	} else {
1285 		if (push_obj->is_on_map()) {
1286 			from = MapCoord(push_obj->x, push_obj->y, push_obj->z);
1287 		} else {
1288 			// exchange inventory.
1289 			Actor *src_actor = push_obj->get_actor_holding_obj();
1290 			if (!src_actor) // container on the map (container gump)
1291 				src_actor = player->get_actor();
1292 //            if(src_actor)
1293 			{
1294 				Actor *target_actor = map->get_actor(rel_x, rel_y, src_actor->get_z());
1295 				if (can_move_obj_between_actors(push_obj, src_actor, target_actor, true)) {
1296 					obj_manager->moveto_inventory(push_obj, target_actor);
1297 					script->call_actor_subtract_movement_points(src_actor, 5);
1298 				}
1299 			}
1300 			scroll->message("\n\n");
1301 			endAction();
1302 			return (true);
1303 		}
1304 	}
1305 
1306 	if (push_from == PUSH_FROM_PLAYER) { // coordinates must be converted
1307 		to.x = pusher.x + rel_x;
1308 		to.y = pusher.y + rel_y;
1309 	} else {
1310 		to.x = from.x + rel_x;
1311 		to.y = from.y + rel_y;
1312 	}
1313 	pushrel_x = to.x - from.x;
1314 	pushrel_y = to.y - from.y;
1315 
1316 	if (map_window->get_interface() == INTERFACE_NORMAL || push_actor) {
1317 		// you can only push one space at a time
1318 		pushrel_x = (pushrel_x == 0) ? 0 : (pushrel_x < 0) ? -1 : 1;
1319 		pushrel_y = (pushrel_y == 0) ? 0 : (pushrel_y < 0) ? -1 : 1;
1320 	}
1321 	to.x = from.x + pushrel_x;
1322 	to.y = from.y + pushrel_y;
1323 	to.z = from.z;
1324 
1325 	scroll->display_string(get_direction_name(pushrel_x, pushrel_y));
1326 	scroll->display_string(".\n\n");
1327 
1328 	if (pushrel_x == 0 && pushrel_y == 0) {
1329 		scroll->display_prompt();
1330 		endAction();
1331 		return true;
1332 	}
1333 	CanDropOrMoveMsg can_move_check;
1334 	if (push_obj && (can_move_check = map_window->can_drop_or_move_obj(to.x, to.y, player->get_actor(), push_obj))
1335 	        != MSG_SUCCESS) {
1336 //        scroll->display_string("Blocked.\n");  // using text from can_drop_or_move_obj
1337 		map_window->display_can_drop_or_move_msg(can_move_check, "");
1338 		endAction(true);
1339 		return true;
1340 	}
1341 	DEBUG(0, LEVEL_WARNING, "deduct moves from player\n");
1342 	// FIXME: the random chance here is just made up, I don't know what
1343 	//        kind of check U6 did ("Failed.\n\n")
1344 	if (push_actor) {
1345 		// if actor can take a step, do so; else 50% chance of pushing them
1346 		if (push_actor == player->get_actor()) {
1347 			if (player->check_walk_delay() && !view_manager->gumps_are_active()) {
1348 				player->moveRelative(pushrel_x, pushrel_y);
1349 				game->time_changed();
1350 			}
1351 		} else if (map->lineTest(to.x, to.y, to.x, to.y, to.z, LT_HitActors | LT_HitUnpassable, lt))
1352 			scroll->display_string("Blocked.\n\n");
1353 		else if (!push_actor->moveRelative(pushrel_x, pushrel_y)) {
1354 			if (NUVIE_RAND() % 2) { // already checked if target is passable
1355 				push_actor->move(to.x, to.y, from.z, ACTOR_FORCE_MOVE | ACTOR_IGNORE_DANGER);
1356 				player->subtract_movement_points(5);
1357 			} else
1358 				scroll->display_string("Failed.\n\n");
1359 		}
1360 	} else {
1361 		if (map_window->get_interface() != INTERFACE_IGNORE_BLOCK
1362 		        && map_window->blocked_by_wall(player->get_actor(), push_obj)) {
1363 			scroll->display_string("Blocked.\n\n");
1364 		} else if (!usecode->has_movecode(push_obj) || usecode->move_obj(push_obj, pushrel_x, pushrel_y)) {
1365 			if (game->get_game_type() == NUVIE_GAME_U6 && (push_obj->obj_n == OBJ_U6_SKIFF
1366 			        || push_obj->obj_n == OBJ_U6_RAFT)) {
1367 				Obj *to_obj = obj_manager->get_obj(to.x, to.y, to.z, true);
1368 				if (to_obj) {
1369 					if (obj_manager->can_store_obj(to_obj, push_obj))
1370 						can_move = obj_manager->moveto_container(push_obj, to_obj);
1371 				} else if (map->lineTest(to.x, to.y, to.x, to.y, to.z, LT_HitActors | LT_HitUnpassable, lt)) {
1372 					if (!lt.hitActor && map->is_water(to.x, to.y, to.z))
1373 						can_move = obj_manager->move(push_obj, to.x, to.y, to.z);
1374 				} else
1375 					can_move = obj_manager->move(push_obj, to.x, to.y, to.z);
1376 			} else if (map_window->get_interface() != INTERFACE_IGNORE_BLOCK &&
1377 			           map->lineTest(to.x,
1378 			                         to.y,
1379 			                         to.x,
1380 			                         to.y,
1381 			                         to.z,
1382 			                         LT_HitActors | LT_HitUnpassable,
1383 			                         lt,
1384 			                         0,
1385 			                         game->get_game_type() == NUVIE_GAME_U6 ? NULL
1386 			                         : push_obj)) { //FIXME should we exclude push_obj for U6 too?
1387 				if (lt.hitObj) {
1388 					if (obj_manager->can_store_obj(lt.hitObj, push_obj)) { //if we are moving onto a container.
1389 						can_move = obj_manager->moveto_container(push_obj, lt.hitObj);
1390 					} else {
1391 						// We can place an object on a bench or table. Or on any other object if
1392 						// the object is passable and not on a boundary.
1393 
1394 						obj_tile = obj_manager->get_obj_tile(lt.hitObj->obj_n, lt.hitObj->frame_n);
1395 						if ((obj_tile->flags3 & TILEFLAG_CAN_PLACE_ONTOP) ||
1396 						        (obj_tile->passable && !map->is_boundary(lt.hit_x, lt.hit_y, lt.hit_level))) {
1397 							/* do normal move if no usecode or return from usecode was true */
1398 							//if(!usecode->has_movecode(push_obj) || usecode->move_obj(push_obj,pushrel_x,pushrel_y))
1399 							can_move = obj_manager->move(push_obj, to.x, to.y, from.z);
1400 						}
1401 					}
1402 				}
1403 			} else {
1404 				Obj *obj = obj_manager->get_obj(to.x, to.y, to.z);
1405 				if (map_window->get_interface() == INTERFACE_IGNORE_BLOCK
1406 				        && map->get_actor(to.x, to.y, to.z)) {} // don't allow moving under actor
1407 				else if (obj && obj_manager->can_store_obj(obj, push_obj)) { //if we are moving onto a container.
1408 					can_move = obj_manager->moveto_container(push_obj, obj);
1409 				} else {
1410 					/* do normal move if no usecode or return from usecode was true */
1411 					//if(!usecode->has_movecode(push_obj) || usecode->move_obj(push_obj,pushrel_x,pushrel_y))
1412 					can_move = obj_manager->move(push_obj, to.x, to.y, from.z);
1413 				}
1414 			}
1415 			if (!can_move)
1416 				scroll->display_string("Blocked.\n\n");
1417 		}
1418 		if (can_move)
1419 			player->subtract_movement_points(5);
1420 	}
1421 	scroll->display_prompt();
1422 	endAction();
1423 	return (true);
1424 }
1425 
pushFrom(Obj * obj)1426 bool Events::pushFrom(Obj *obj) {
1427 	scroll->display_string(obj_manager->look_obj(obj));
1428 	push_obj = obj;
1429 	if (game->get_game_type() == NUVIE_GAME_MD)
1430 		get_target("\nWhere? ");
1431 	else
1432 		get_target("\nTo ");
1433 	return true;
1434 }
1435 
1436 /* Select object to move. */
pushFrom(sint16 rel_x,sint16 rel_y)1437 bool Events::pushFrom(sint16 rel_x, sint16 rel_y) {
1438 	MapCoord from = player->get_actor()->get_location();
1439 	MapCoord target = MapCoord(from.x + rel_x, from.y + rel_y, from.z);
1440 	return pushFrom(target);
1441 }
1442 
1443 /* Select object to move. */
pushFrom(MapCoord target)1444 bool Events::pushFrom(MapCoord target) {
1445 	ActorManager *actor_manager = game->get_actor_manager();
1446 	Script *script = game->get_script();
1447 	MapCoord from = player->get_actor()->get_location();
1448 
1449 	if (game->user_paused())
1450 		return (false);
1451 
1452 	map_window->set_show_use_cursor(false);
1453 	if (from.x != target.x || from.y != target.y) {
1454 		push_obj = obj_manager->get_obj(target.x, target.y, from.z);
1455 	}
1456 	push_actor = actor_manager->get_actor(target.x, target.y, from.z);
1457 	if (map_window->tile_is_black(target.x, target.y, push_obj)) {
1458 		scroll->display_string("nothing.\n");
1459 		endAction(true);
1460 		return false;
1461 	}
1462 	if (push_obj
1463 	        && (obj_manager->get_obj_weight(push_obj, OBJ_WEIGHT_EXCLUDE_CONTAINER_ITEMS) == 0))
1464 		push_obj = NULL;
1465 
1466 	if (push_actor && push_actor->is_visible()) {
1467 		scroll->display_string(push_actor->get_name());
1468 		push_obj = NULL;
1469 	} else if (push_obj) {
1470 		scroll->display_string(obj_manager->look_obj(push_obj));
1471 		push_actor = NULL;
1472 	} else {
1473 		scroll->display_string("nothing.\n");
1474 		endAction(true);
1475 		return false;
1476 	}
1477 
1478 	if (from.distance(target) > 1 && !script->call_is_ranged_select(MOVE)
1479 	        && map_window->get_interface() == INTERFACE_NORMAL) {
1480 		scroll->display_string("\n\nOut of range!\n");
1481 		endAction(true);
1482 	} else if (map_window->get_interface() != INTERFACE_NORMAL
1483 	           && ((push_obj && !map_window->can_get_obj(player->get_actor(), push_obj))
1484 	               || (push_actor && !can_get_to_actor(push_actor, target.x, target.y)))) {
1485 		scroll->display_string("\n\nCan't reach it\n");
1486 		endAction(true);
1487 	} else {
1488 		get_direction(MapCoord(target.x, target.y), "\nTo ");
1489 	}
1490 	return true;
1491 }
1492 
actor_exists(Actor * a)1493 bool Events::actor_exists(Actor *a) {
1494 	if (a->get_z() > 5 || a->get_actor_num() == 0
1495 	        || ((a->is_temp() || a->get_strength() == 0) && a->get_x() == 0 && a->get_y() == 0
1496 	            && a->get_z() == 0) // temp actor that has been cleaned up or invalid normal npc
1497 	        /*|| strcmp(a->get_name(true), "Nothing") == 0*/) { // This last one probably isn't needed anymore
1498 		scroll->display_string("\nnpc is invalid or at invalid location");
1499 		return false;
1500 	}
1501 	return true;
1502 }
1503 
1504 /* Send input to active alt-code. */
alt_code_input(const char * in)1505 void Events::alt_code_input(const char *in) {
1506 	ActorManager *am = game->get_actor_manager();
1507 	Actor *a = am->get_actor((uint8) strtol(in, NULL, 10));
1508 	static string teleport_string = "";
1509 	static Obj obj;
1510 	uint8 a_num = 0;
1511 	switch (active_alt_code) {
1512 	case 300: // show NPC portrait (FIXME: should be show portrait number)
1513 		if (a) {
1514 			am->print_actor(a); //print actor debug info
1515 			display_portrait(a);
1516 		}
1517 		scroll->display_string("\n");
1518 		active_alt_code = 0;
1519 		break;
1520 
1521 	case 301: // Show Midgame graphics
1522 		game->get_script()->call_play_midgame_sequence((uint16) strtol(in, NULL, 10));
1523 		scroll->display_string("\n");
1524 		active_alt_code = 0;
1525 		break;
1526 
1527 	case 400: // talk to NPC (FIXME: get portrait and inventory too)
1528 		a_num = (uint8) strtol(in, NULL, 10);
1529 		if (a_num == 0 || !game->get_converse()->start(a_num)) {
1530 			scroll->display_string("\n");
1531 			scroll->display_prompt();
1532 		}
1533 		active_alt_code = 0;
1534 		break;
1535 
1536 	/*        case 214:
1537 	            alt_code_teleport(in); //teleport player & party to location string
1538 	            scroll->display_string("\n");
1539 	            scroll->display_prompt();
1540 	            active_alt_code = 0;
1541 	            break;
1542 	*/
1543 
1544 	case 214: // teleport player & party to location string
1545 		teleport_string += " ";
1546 		teleport_string += in;
1547 		++alt_code_input_num;
1548 		if (alt_code_input_num == 1) {
1549 			if (game->get_game_type() == NUVIE_GAME_U6)
1550 				scroll->display_string("\n<uai>: ");
1551 			else
1552 				scroll->display_string("\ny: ");
1553 			get_scroll_input(NULL, true, false, false);
1554 		} else if (alt_code_input_num == 2) {
1555 			if (game->get_game_type() == NUVIE_GAME_U6)
1556 				scroll->display_string("\n<zi>: ");
1557 			else
1558 				scroll->display_string("\nz: ");
1559 			get_scroll_input(NULL, true, false, false);
1560 		} else {
1561 			alt_code_teleport(teleport_string.c_str());
1562 			scroll->display_string("\n");
1563 			scroll->display_prompt();
1564 			teleport_string = "";
1565 			alt_code_input_num = 0;
1566 			active_alt_code = 0;
1567 		}
1568 		break;
1569 
1570 	case 314: // teleport player & party to selected location
1571 		if (strtol(in, NULL, 10) != 0)
1572 			alt_code_teleport_menu((uint32) strtol(in, NULL, 10));
1573 		if (strtol(in, NULL, 10) == 0 || alt_code_input_num > 2) {
1574 			scroll->display_string("\n");
1575 			scroll->display_prompt();
1576 			alt_code_input_num = 0;
1577 			active_alt_code = 0;
1578 		}
1579 		break;
1580 
1581 	case 414: // teleport player & party to NPC location
1582 		if (actor_exists(a))
1583 			alt_code_teleport_to_person((uint32) strtol(in, NULL, 10));
1584 		scroll->display_string("\n\n");
1585 		scroll->display_prompt();
1586 		active_alt_code = 0;
1587 		break;
1588 
1589 	case 500: // control/watch anyone
1590 		if (!actor_exists(a)) {
1591 			scroll->display_string("\n\n");
1592 		} else if (!a->is_alive()) {
1593 			scroll->display_string("\n");
1594 			scroll->display_string(a->get_name(true));
1595 			scroll->display_string(" is dead\n\n");
1596 		} else {
1597 			player->set_actor(a);
1598 			player->set_mapwindow_centered(true);
1599 			if (!game->is_new_style())
1600 				view_manager->set_inventory_mode(); // reset inventoryview
1601 			if (game->get_party()->contains_actor(player->get_actor())) {
1602 				in_control_cheat = false;
1603 				uint8 member_num = game->get_party()->get_member_num(player->get_actor());
1604 				if (!game->is_new_style())
1605 					view_manager->get_inventory_view()->set_party_member(member_num);
1606 			} else {
1607 				in_control_cheat = true;
1608 				if (!game->is_new_style())
1609 					view_manager->get_inventory_view()->set_actor(player->get_actor());
1610 			}
1611 			game->get_party()->update_light_sources();
1612 			scroll->display_string("\n\n");
1613 		}
1614 		scroll->display_prompt();
1615 		active_alt_code = 0;
1616 		break;
1617 
1618 	case 501: { // resurrect npc
1619 		if (!actor_exists(a)) {
1620 			// Do nothing. It already prints a message
1621 		} else if (a->is_alive()) {
1622 			scroll->display_string("\n");
1623 			scroll->display_string(a->get_name(true));
1624 			scroll->display_string(" is not dead.");
1625 		} else {
1626 			bool failed = true;
1627 			for (int i = 1; i < 8; i++) {
1628 				uint16 newx = NUVIE_RAND() % 10 + player->get_actor()->get_x() - 5;
1629 				uint16 newy = NUVIE_RAND() % 10 + player->get_actor()->get_y() - 5;
1630 				if (a->move(newx, newy, player->get_actor()->get_z())) {
1631 					failed = false;
1632 					MapCoord res_loc(newx, newy, player->get_actor()->get_z());
1633 					a->resurrect(res_loc);
1634 				}
1635 			}
1636 			if (failed) // No location found. Resurrect anyway.
1637 				a->resurrect(player->get_actor()->get_location());
1638 		}
1639 		scroll->display_string("\n\n");
1640 		scroll->display_prompt();
1641 		active_alt_code = 0;
1642 		break;
1643 	}
1644 	case 456: // polymorph
1645 		if (alt_code_input_num == 0) {
1646 			obj.obj_n = strtol(in, NULL, 10);
1647 			scroll->display_string("\nNpc number? ");
1648 			get_scroll_input();
1649 			++alt_code_input_num;
1650 		} else {
1651 			a->morph(obj.obj_n);
1652 			scroll->display_string("\nMorphed!\n\n");
1653 			scroll->display_prompt();
1654 			alt_code_input_num = 0;
1655 			active_alt_code = 0;
1656 		}
1657 		break;
1658 	}
1659 }
1660 
1661 /* Get an alt-code from `cs' and use it.
1662  */
alt_code(const char * cs)1663 void Events::alt_code(const char *cs) {
1664 	uint16 c = (uint16) strtol(cs, NULL, 10);
1665 	switch (c) {
1666 	case 300: // display portrait by number
1667 		scroll->display_string("Portrait? ");
1668 		get_scroll_input();
1669 		active_alt_code = c;
1670 		break;
1671 
1672 	case 301: // display midgame sequence
1673 		scroll->display_string("Midgame? ");
1674 		get_scroll_input();
1675 		active_alt_code = c;
1676 		break;
1677 
1678 	case 400: // talk to anyone (FIXME: get portrait and inventory too)
1679 		scroll->display_string("Npc number? ");
1680 		get_scroll_input();
1681 		active_alt_code = c;
1682 		break;
1683 
1684 	case 500: // control/watch anyone
1685 		if (player->is_in_vehicle()
1686 		        || game->get_party()->is_in_combat_mode()) {
1687 			if (player->is_in_vehicle())
1688 				display_not_aboard_vehicle(false);
1689 			else
1690 				scroll->display_string("\nNot while in combat mode!\n\n");
1691 			scroll->display_prompt();
1692 			active_alt_code = 0;
1693 			break;
1694 		}
1695 		scroll->display_string("Npc number? ");
1696 		get_scroll_input();
1697 		active_alt_code = c;
1698 		break;
1699 
1700 	case 501: // resurrect npc
1701 		if (player->is_in_vehicle()) {
1702 			display_not_aboard_vehicle(false);
1703 			scroll->display_prompt();
1704 			active_alt_code = 0;
1705 			break;
1706 		}
1707 		scroll->display_string("Npc number? ");
1708 		get_scroll_input();
1709 		active_alt_code = c;
1710 		break;
1711 
1712 	case 456: // polymorph
1713 		scroll->display_string("Object number? ");
1714 		get_scroll_input();
1715 		active_alt_code = c;
1716 		break;
1717 
1718 	case 213:
1719 		alt_code_infostring();
1720 		active_alt_code = 0;
1721 		break;
1722 
1723 	/*        case 214:
1724 	            scroll->display_string("Location: \n",2);
1725 	            scroll->display_string(" ",0);
1726 	            get_scroll_input();
1727 	            active_alt_code = c;
1728 	            break;
1729 	*/
1730 	case 214:
1731 		if (player->is_in_vehicle()) {
1732 			if (game->get_game_type() == NUVIE_GAME_U6)
1733 				scroll->display_string("\n<nat uail abord wip!>\n");
1734 			else
1735 				display_not_aboard_vehicle();
1736 			scroll->display_prompt();
1737 			active_alt_code = 0;
1738 		} else {
1739 			if (game->get_game_type() == NUVIE_GAME_U6)
1740 				scroll->display_string("\n<gotu eks>: ");
1741 			else
1742 				scroll->display_string("\ngoto x: ");
1743 			get_scroll_input(NULL, true, false, false);
1744 			active_alt_code = c;
1745 		}
1746 		break;
1747 
1748 	case 215:
1749 		//clock->advance_to_next_hour();
1750 		game->get_script()->call_advance_time(60);
1751 		scroll->display_string(clock->get_time_string());
1752 		scroll->display_string("\n");
1753 		scroll->display_prompt();
1754 		game->time_changed();
1755 		active_alt_code = 0;
1756 		break;
1757 
1758 	case 216:
1759 		scroll->display_string(clock->get_time_string());
1760 		scroll->display_string("\n");
1761 		scroll->display_prompt();
1762 		active_alt_code = 0;
1763 		break;
1764 	case 222: {
1765 		bool ethereal = !game->is_ethereal();
1766 		game->set_ethereal(ethereal);
1767 		game->get_party()->set_ethereal(ethereal);
1768 		const char *message = ethereal ? "Party desolidifies!\n\n" : "Party solidifies!\n\n";
1769 		scroll->message(message);
1770 		break;
1771 	}
1772 	case 314: // teleport player & party to selected location
1773 		if (player->is_in_vehicle()) {
1774 			display_not_aboard_vehicle();
1775 			active_alt_code = 0;
1776 		} else {
1777 			alt_code_teleport_menu(0);
1778 			active_alt_code = c;
1779 		}
1780 		break;
1781 
1782 	case 414: // teleport player & party to NPC location
1783 		if (player->is_in_vehicle()) {
1784 			display_not_aboard_vehicle();
1785 			active_alt_code = 0;
1786 			break;
1787 		}
1788 		scroll->display_string("Npc number? ");
1789 		get_scroll_input();
1790 		active_alt_code = c;
1791 		break;
1792 
1793 	case 600: // map editor
1794 		view_manager->open_mapeditor_view();
1795 		active_alt_code = 0;
1796 		break;
1797 
1798 	default: // attempt to handle the altcode with lua script.
1799 		Game::get_game()->get_script()->call_handle_alt_code(c);
1800 		scroll->display_prompt();
1801 		break;
1802 	}
1803 }
1804 
alt_code_teleport(const char * location_string)1805 bool Events::alt_code_teleport(const char *location_string) {
1806 	char *next_num;
1807 	uint16 x, y, z;
1808 
1809 	if (!location_string || !strlen(location_string))
1810 		return false;
1811 
1812 	x = strtol(location_string, &next_num, 16);
1813 	y = strtol(next_num, &next_num, 16);
1814 	z = strtol(next_num, &next_num, 16);
1815 
1816 	if ((x == 0 && y == 0) || z > 5)
1817 		return false;
1818 	player->move(x, y, z, true);
1819 
1820 	// This is a bit of a hack but we would like to update the music when teleporting.
1821 	game->get_party()->update_music();
1822 
1823 	return true;
1824 }
1825 
1826 // changed to show time instead of date (SB-X)
alt_code_infostring()1827 void Events::alt_code_infostring() {
1828 	char buf[14]; // kkhhmmxxxyyyz
1829 	uint8 karma;
1830 	uint8 hour;
1831 	uint8 minute;
1832 	uint16 x, y;
1833 	uint8 z;
1834 
1835 	karma = player->get_karma();
1836 	player->get_location(&x, &y, &z);
1837 
1838 	hour = clock->get_hour();
1839 	minute = clock->get_minute();
1840 
1841 	sprintf(buf, "%02d%02d%02d%03X%03X%x", karma, hour, minute, x, y, z);
1842 
1843 	scroll->display_string(buf);
1844 	scroll->display_string("\n");
1845 	new PeerEffect((x - x % 8) - 18, (y - y % 8) - 18, z); // wrap to chunk boundary, and center
1846 	// in 11x11 MapWindow
1847 }
1848 
1849 /* Move player to NPC location. */
alt_code_teleport_to_person(uint32 npc)1850 bool Events::alt_code_teleport_to_person(uint32 npc) {
1851 	ActorManager *actor_manager = game->get_actor_manager();
1852 	MapCoord actor_location = actor_manager->get_actor(npc)->get_location();
1853 	player->move(actor_location.x, actor_location.y, actor_location.z, true);
1854 	if (!actor_manager->toss_actor(player->get_actor(), 2, 2))
1855 		actor_manager->toss_actor(player->get_actor(), 4, 4);
1856 	return (true);
1857 }
1858 
1859 /* Display teleport destinations, get input. */
alt_code_teleport_menu(uint32 selection)1860 void Events::alt_code_teleport_menu(uint32 selection) {
1861 	static uint8 category = 0;
1862 	const char *teleport_dest = "";
1863 	if (alt_code_input_num == 0) { // select category
1864 		if (game->get_game_type() == NUVIE_GAME_U6) {
1865 			scroll->display_string("\nLazy Teleporters' Menu!\n");
1866 			scroll->display_string(" 1) Cities\n");
1867 			scroll->display_string(" 2) Major Areas\n");
1868 			scroll->display_string(" 3) Shrines\n");
1869 			scroll->display_string(" 4) Gargoyles\n");
1870 			scroll->display_string(" 5) Dungeons\n");
1871 			scroll->display_string(" 6) More Dungeons\n");
1872 			scroll->display_string(" 7) Other\n");
1873 			scroll->display_string("Category? ");
1874 			get_scroll_input("01234567");
1875 		} else if (game->get_game_type() == NUVIE_GAME_SE) {
1876 			scroll->display_string("\nLazy Teleporters' Menu!\n");
1877 			scroll->display_string(" 1) Villages\n");
1878 			scroll->display_string(" 2) More Villages\n");
1879 			scroll->display_string(" 3) S. Places\n");
1880 			scroll->display_string(" 4) Resources\n");
1881 			scroll->display_string(" 5) Teleport Pads\n");
1882 			scroll->display_string(" 6) Caves\n");
1883 			scroll->display_string(" 7) Myrm. Holes\n");
1884 			scroll->display_string("Category? ");
1885 			get_scroll_input("01234567");
1886 		}
1887 	} else if (alt_code_input_num == 1) { // selected category, select location
1888 		category = selection;
1889 		scroll->display_string("\n");
1890 		if (game->get_game_type() == NUVIE_GAME_U6) {
1891 			switch (selection) {
1892 			case 1:
1893 				scroll->display_string("Cities\n");
1894 				scroll->display_string(" 1) Britain\n");
1895 				scroll->display_string(" 2) Trinsic\n");
1896 				scroll->display_string(" 3) Yew\n");
1897 				scroll->display_string(" 4) Minoc\n");
1898 				scroll->display_string(" 5) Moonglow\n");
1899 				scroll->display_string(" 6) Jhelom\n");
1900 				scroll->display_string(" 7) Skara Brae\n");
1901 				scroll->display_string(" 8) New Magincia\n");
1902 				if (!game->is_new_style())
1903 					scroll->display_string(" 9) Buc's Den\n");
1904 				else
1905 					scroll->display_string(" 9) Buccaneer's Den\n");
1906 				scroll->display_string("Location? ");
1907 				get_scroll_input("0123456789");
1908 				break;
1909 			case 2:
1910 				scroll->display_string("Major Areas\n");
1911 				scroll->display_string(" 1) Cove\n");
1912 				scroll->display_string(" 2) Paws\n");
1913 				scroll->display_string(" 3) Serpent's Hold\n");
1914 				scroll->display_string(" 4) Empath Abbey\n");
1915 				scroll->display_string(" 5) Lycaeum\n");
1916 				scroll->display_string(" 6) Library\n");
1917 				scroll->display_string(" 7) Sutek's Island\n");
1918 				scroll->display_string(" 8) Stonegate\n");
1919 				scroll->display_string(" 9) The Codex\n");
1920 				scroll->display_string("Location? ");
1921 				get_scroll_input("0123456789");
1922 				break;
1923 			case 3:
1924 				scroll->display_string("Shrines\n");
1925 				scroll->display_string(" 1) Honesty\n");
1926 				scroll->display_string(" 2) Compassion\n");
1927 				scroll->display_string(" 3) Valor\n");
1928 				scroll->display_string(" 4) Justice\n");
1929 				scroll->display_string(" 5) Sacrifice\n");
1930 				scroll->display_string(" 6) Honor\n");
1931 				scroll->display_string(" 7) Humility\n");
1932 				scroll->display_string(" 8) Spirituality\n");
1933 				scroll->display_string("Location? ");
1934 				get_scroll_input("012345678");
1935 				break;
1936 			case 4:
1937 				scroll->display_string("Gargoyles\n");
1938 				if (!game->is_new_style())
1939 					scroll->display_string(" 1) Hall\n");
1940 				else
1941 					scroll->display_string(" 1) Hall of Knowledge\n");
1942 				scroll->display_string(" 2) Singularity\n");
1943 				scroll->display_string(" 3) King's Temple\n");
1944 				scroll->display_string(" 4) Tomb of Kings\n");
1945 				scroll->display_string(" 5) Hythloth\n");
1946 				scroll->display_string(" 6) Control\n");
1947 				scroll->display_string(" 7) Passion\n");
1948 				scroll->display_string(" 8) Diligence\n");
1949 				scroll->display_string("Location? ");
1950 				get_scroll_input("012345678");
1951 				break;
1952 			case 5:
1953 				scroll->display_string("Dungeons\n");
1954 				scroll->display_string(" 1) Ant Mound\n");
1955 				if (!game->is_new_style())
1956 					scroll->display_string(" 2) Buc's Cave\n");
1957 				else
1958 					scroll->display_string(" 2) Buccaneer's Cave\n");
1959 				scroll->display_string(" 3) Covetous\n");
1960 				scroll->display_string(" 4) Crypts\n");
1961 				scroll->display_string(" 5) Cyclops Cave\n");
1962 				scroll->display_string(" 6) Deceit\n");
1963 				scroll->display_string(" 7) Despise\n");
1964 				scroll->display_string(" 8) Destard\n");
1965 				if (!game->is_new_style())
1966 					scroll->display_string(" 9) Heftimus's\n");
1967 				else
1968 					scroll->display_string(" 9) Heftimus's Cave\n");
1969 				scroll->display_string("Location? ");
1970 				get_scroll_input("0123456789");
1971 				break;
1972 			case 6:
1973 				scroll->display_string("More Dungeons\n");
1974 				scroll->display_string(" 1) Hero's Hole\n");
1975 				scroll->display_string(" 2) Hythloth\n");
1976 				scroll->display_string(" 3) Pirate Cave\n");
1977 				scroll->display_string(" 4) Sewers\n");
1978 				scroll->display_string(" 5) Shame\n");
1979 				scroll->display_string(" 6) Spider Cave\n");
1980 				scroll->display_string(" 7) Sutek's Island\n");
1981 				scroll->display_string(" 8) Swamp Cave\n");
1982 				scroll->display_string(" 9) Wrong\n");
1983 				scroll->display_string("Location? ");
1984 				get_scroll_input("0123456789");
1985 				break;
1986 			case 7:
1987 				scroll->display_string("Other\n");
1988 				scroll->display_string(" 1) Iolo's Hut\n");
1989 				scroll->display_string(" 2) Lumberjack\n");
1990 				scroll->display_string(" 3) Saw Mill\n");
1991 				scroll->display_string(" 4) Thieves Guild\n");
1992 				scroll->display_string(" 5) Wisps\n");
1993 				scroll->display_string(" 6) Dagger Isle\n");
1994 				scroll->display_string(" 7) Shipwreck\n");
1995 				scroll->display_string(" 8) Phoenix\n");
1996 				scroll->display_string("Location? ");
1997 				get_scroll_input("012345678");
1998 				break;
1999 			}
2000 		} else if (game->get_game_type() == NUVIE_GAME_SE) {
2001 			switch (selection) {
2002 			case 1:
2003 				scroll->display_string("Villages\n");
2004 				scroll->display_string(" 1) Barako\n");
2005 				scroll->display_string(" 2) Kurak\n");
2006 				scroll->display_string(" 3) Pindiro\n");
2007 				scroll->display_string(" 4) Yolaru\n");
2008 				scroll->display_string(" 5) Tichticatl\n");
2009 				scroll->display_string(" 6) Jukari\n");
2010 				scroll->display_string(" 7) Disquiqui\n");
2011 				scroll->display_string(" 8) Barrab\n");
2012 				scroll->display_string(" 9) Urali\n");
2013 				scroll->display_string("Location? ");
2014 				get_scroll_input("0123456789");
2015 				break;
2016 			case 2:
2017 				scroll->display_string("More Villages\n");
2018 				scroll->display_string(" 1) Haakur\n");
2019 				scroll->display_string(" 2) Sakkhra\n");
2020 				scroll->display_string(" 3) Old Pindiro\n");
2021 				scroll->display_string("Location? ");
2022 				get_scroll_input("0123");
2023 				break;
2024 			case 3:
2025 				scroll->display_string("Special Places\n");
2026 				scroll->display_string(" 1) Laboratory\n");
2027 				scroll->display_string(" 2) Drum Hill\n");
2028 				scroll->display_string(" 3) Topuru's Isle\n");
2029 				scroll->display_string(" 4) Gem Stand\n");
2030 				if (!game->is_new_style())
2031 					scroll->display_string(" 5) Thunderer\n");
2032 				else
2033 					scroll->display_string(" 5) Thunderer Peak\n");
2034 				scroll->display_string(" 6) Great Mesa\n");
2035 				scroll->display_string(" 7) Kotl City\n");
2036 				scroll->display_string(" 8) Disq. Tyran.\n");
2037 				scroll->display_string(" 9) Silverback\n");
2038 				scroll->display_string("Location? ");
2039 				get_scroll_input("0123456789");
2040 				break;
2041 			case 4:
2042 				scroll->display_string("Resources\n");
2043 				scroll->display_string(" 1) Sulphur Pits\n");
2044 				scroll->display_string(" 2) Tar Pits\n");
2045 				scroll->display_string(" 3) Pot.Nitrate\n");
2046 				scroll->display_string(" 4) Yucca Plants\n");
2047 				scroll->display_string(" 5) Bamboo\n");
2048 				scroll->display_string(" 6) River Banks\n");
2049 				scroll->display_string(" 7) Corn Stalks\n");
2050 				scroll->display_string(" 8) Blue Stone\n");
2051 				scroll->display_string("Location? ");
2052 				get_scroll_input("012345678");
2053 				break;
2054 			case 5:
2055 				scroll->display_string("Teleport Pads\n");
2056 				scroll->display_string(" 1) Barako\n");
2057 				scroll->display_string(" 2) Dead Pad\n");
2058 				if (!game->is_new_style())
2059 					scroll->display_string(" 3) K./Y.\n");
2060 				else
2061 					scroll->display_string(" 3) Kurak/Yolaru\n");
2062 				scroll->display_string(" 4) Nahuatla\n");
2063 				scroll->display_string(" 5) Jukari\n");
2064 				scroll->display_string(" 6) Disquiqui\n");
2065 				scroll->display_string(" 7) Barrab\n");
2066 				scroll->display_string(" 8) Sakkhra\n");
2067 				scroll->display_string(" 9) Hub\n");
2068 				scroll->display_string("Location? ");
2069 				get_scroll_input("0123456789");
2070 				break;
2071 			case 6:
2072 				scroll->display_string("Caves\n");
2073 				scroll->display_string(" 1) Spider\n");
2074 				scroll->display_string(" 2) Jukari Ritual\n");
2075 				scroll->display_string(" 3) Silverback\n");
2076 				scroll->display_string(" 4) Fritz\n");
2077 				scroll->display_string(" 5) Urali Spirit\n");
2078 				scroll->display_string(" 6) Urali Chief\n");
2079 				scroll->display_string(" 7) To Urali\n");
2080 				scroll->display_string(" 8) From Urali\n");
2081 				scroll->display_string(" 9) Denys\n");
2082 				scroll->display_string("Location? ");
2083 				get_scroll_input("0123456789");
2084 				break;
2085 			case 7:
2086 				scroll->display_string("Myrmidex Holes\n");
2087 				if (!game->is_new_style())
2088 					scroll->display_string(" 1) S of Disq.\n");
2089 				else
2090 					scroll->display_string(" 1) S of Disquiqui\n");
2091 				if (!game->is_new_style())
2092 					scroll->display_string(" 2) W of G. Mesa\n");
2093 				else
2094 					scroll->display_string(" 2) W of Great Mesa\n");
2095 				scroll->display_string(" 3) W of Hub\n");
2096 				if (!game->is_new_style())
2097 					scroll->display_string(" 4) E of Drum H.\n");
2098 				else
2099 					scroll->display_string(" 4) E of Drum Hill\n");
2100 				scroll->display_string(" 5) SW of Kurak\n");
2101 				scroll->display_string(" 6) Old Pindiro\n");
2102 				scroll->display_string(" 7) S of Pindiro\n");
2103 				scroll->display_string("Location? ");
2104 				get_scroll_input("01234567");
2105 				break;
2106 			}
2107 		}
2108 	} else if (alt_code_input_num == 2) { // selected location, teleport
2109 		if (game->get_game_type() == NUVIE_GAME_U6) {
2110 			switch (category) {
2111 			case 1:
2112 				if (selection == 1) // Britain
2113 					teleport_dest = "133 1a3 0";
2114 				else if (selection == 2) // Trinsic
2115 					teleport_dest = "19b 2e2 0";
2116 				else if (selection == 3) // Yew
2117 					teleport_dest = "ec a7 0";
2118 				else if (selection == 4) // Minoc
2119 					teleport_dest = "254 63 0";
2120 				else if (selection == 5) // Moonglow
2121 					teleport_dest = "38a 203 0";
2122 				else if (selection == 6) // Jhelom
2123 					teleport_dest = "a0 36b 0";
2124 				else if (selection == 7) // Skara Brae
2125 					teleport_dest = "54 203 0";
2126 				else if (selection == 8) // New Magincia
2127 					teleport_dest = "2e3 2ab 0";
2128 				else if (selection == 9) // Buc's Den
2129 					teleport_dest = "246 274 0";
2130 				break;
2131 			case 2:
2132 				if (selection == 1) // Cove
2133 					teleport_dest = "223 163 0";
2134 				else if (selection == 2) // Paws
2135 					teleport_dest = "198 264 0";
2136 				else if (selection == 3) // Serpent's Hold
2137 					teleport_dest = "22e 3bc 0";
2138 				else if (selection == 4) // Empath Abbey
2139 					teleport_dest = "83 db 0";
2140 				else if (selection == 5) // Lycaeum
2141 					teleport_dest = "37b 1a4 0";
2142 				else if (selection == 6) // Library
2143 					teleport_dest = "37b 1b4 0";
2144 				else if (selection == 7) // Sutek's Island
2145 					teleport_dest = "316 3d4 0";
2146 				else if (selection == 8) // Stonegate
2147 					teleport_dest = "25f 11d 0";
2148 				else if (selection == 9) // The Codex
2149 					teleport_dest = "39b 354 0";
2150 				break;
2151 			case 3:
2152 				if (selection == 1) // Honesty
2153 					teleport_dest = "3a7 109 0";
2154 				else if (selection == 2) // Compassion
2155 					teleport_dest = "1f7 168 0";
2156 				else if (selection == 3) // Valor
2157 					teleport_dest = "9f 3b1 0";
2158 				else if (selection == 4) // Justice
2159 					teleport_dest = "127 28 0";
2160 				else if (selection == 5) // Sacrifice
2161 					teleport_dest = "33e a6 0";
2162 				else if (selection == 6) // Honor
2163 					teleport_dest = "147 339 0";
2164 				else if (selection == 7) // Humility
2165 					teleport_dest = "397 3a8 0";
2166 				else if (selection == 8) // Spirituality
2167 					teleport_dest = "18 16 1";
2168 				break;
2169 			case 4:
2170 				if (selection == 1) // Hall of Knowledge
2171 					teleport_dest = "7f af 5";
2172 				else if (selection == 2) // Temple of Singularity
2173 					teleport_dest = "7f 37 5";
2174 				else if (selection == 3) // Temple of Kings
2175 					teleport_dest = "7f 50 5";
2176 				else if (selection == 4) // Tomb of Kings
2177 					teleport_dest = "7f 9 4";
2178 				else if (selection == 5) // Hythloth exit
2179 					teleport_dest = "dc db 5";
2180 				else if (selection == 6) // Shrine of Control
2181 					teleport_dest = "43 2c 5";
2182 				else if (selection == 7) // Shrine of Passion
2183 					teleport_dest = "bc 2c 5";
2184 				else if (selection == 8) // Shrine of Diligence
2185 					teleport_dest = "6c dc 5";
2186 				break;
2187 			case 5:
2188 				if (selection == 1) // Ant Mound
2189 					teleport_dest = "365 bb 0";
2190 				else if (selection == 2) // Buc's Cave
2191 					teleport_dest = "234 253 0";
2192 				else if (selection == 3) // Covetous
2193 					teleport_dest = "273 73 0";
2194 				else if (selection == 4) // Crypts
2195 					teleport_dest = "364 15a 0";
2196 				else if (selection == 5) // Cyclops Cave
2197 					teleport_dest = "b9 1b5 0";
2198 				else if (selection == 6) // Deceit
2199 					teleport_dest = "3c4 136 0";
2200 				else if (selection == 7) // Despise
2201 					teleport_dest = "16D 10a 0";
2202 				else if (selection == 8) // Destard
2203 					teleport_dest = "11c 292 0";
2204 				else if (selection == 9) // Heftimus's
2205 					teleport_dest = "84 35b 0";
2206 				break;
2207 			case 6:
2208 				if (selection == 1) // Hero's Hole
2209 					teleport_dest = "15c 32a 0";
2210 				else if (selection == 2) // Hythloth
2211 					teleport_dest = "3b4 3a4 0";
2212 				else if (selection == 3) // Pirate Cave
2213 					teleport_dest = "2c3 342 0";
2214 				else if (selection == 4) // Sewers
2215 					teleport_dest = "123 17a 0";
2216 				else if (selection == 5) // Shame
2217 					teleport_dest = "eb 19b 0";
2218 				else if (selection == 6) // Spider Cave
2219 					teleport_dest = "5c fb 0";
2220 				else if (selection == 7) // Sutek's Island
2221 					teleport_dest = "316 3d4 0";
2222 				else if (selection == 8) // Swamp Cave
2223 					teleport_dest = "263 16c 0";
2224 				else if (selection == 9) // Wrong
2225 					teleport_dest = "1f4 53 0";
2226 				break;
2227 			case 7:
2228 				if (selection == 1) // Iolo's Hut
2229 					teleport_dest = "c3 e8 0";
2230 				else if (selection == 2) // Lumberjack (Yew)
2231 					teleport_dest = "b2 94 0";
2232 				else if (selection == 3) // Saw Mill (Minoc)
2233 					teleport_dest = "2a4 65 0";
2234 				else if (selection == 4) // Thieves Guild
2235 					teleport_dest = "233 25e 0";
2236 				else if (selection == 5) // Wisps
2237 					teleport_dest = "a5 115 0";
2238 				else if (selection == 6) // Dagger Island
2239 					teleport_dest = "3a9 d3 0";
2240 				else if (selection == 7) // Shipwreck
2241 					teleport_dest = "1aa 3a6 0";
2242 				else if (selection == 8) // Phoenix
2243 					teleport_dest = "76 46 3";
2244 				break;
2245 			}
2246 		} else if (game->get_game_type() == NUVIE_GAME_SE) {
2247 			// Modifications needed when collision working
2248 			// Currently NPC's end in 'bad spots' on some locations
2249 			switch (category) {
2250 			case 1:
2251 				if (selection == 1) // Barako
2252 					teleport_dest = "153 d1 0";
2253 				else if (selection == 2) // Kurak
2254 					teleport_dest = "19c 11a 0";
2255 				else if (selection == 3) // Pindiro
2256 					teleport_dest = "244 7f 0";
2257 				else if (selection == 4) // Yolaru
2258 					teleport_dest = "24b 142 0";
2259 				else if (selection == 5) // Tichticatl
2260 					teleport_dest = "242 22f 0";
2261 				else if (selection == 6) // Jukari
2262 					teleport_dest = "2ad 331 0";
2263 				else if (selection == 7) // Disquiqui
2264 					teleport_dest = "17d 228 0";
2265 				else if (selection == 8) // Barrab
2266 					teleport_dest = "f3 27a 0";
2267 				else if (selection == 9) // Urali
2268 					teleport_dest = "3e5 157 0";
2269 				break;
2270 			case 2:
2271 				if (selection == 1) // Haakur
2272 					teleport_dest = "34d 28e 0";
2273 				else if (selection == 2) // Sakkhra
2274 					teleport_dest = "6c 25e 0";
2275 				else if (selection == 3) // Old Pindiro
2276 					teleport_dest = "18e 2f 0";
2277 				break;
2278 			case 3:
2279 				if (selection == 1) // Laboratory
2280 					teleport_dest = "1db 18a 0";
2281 				else if (selection == 2) // Drum Hill
2282 					teleport_dest = "216 1c8 0";
2283 				else if (selection == 3) // Topuru's Isle
2284 					teleport_dest = "10e b9 0";
2285 				else if (selection == 4) // Gem Stand
2286 					teleport_dest = "a9 1e4 0";
2287 				else if (selection == 5) // Thunderer Peak
2288 					teleport_dest = "d8 192 0";
2289 				else if (selection == 6) // Great Mesa
2290 					teleport_dest = "c2 210 0";
2291 				else if (selection == 7) // Kotl City ??? Approx
2292 					teleport_dest = "bd 1c9 0";
2293 				else if (selection == 8) // Disq. Tyran.
2294 					teleport_dest = "1a6 249 0";
2295 				else if (selection == 9) // Silverback
2296 					teleport_dest = "110 49 0";
2297 				break;
2298 			case 4:
2299 				if (selection == 1) // Sulphur Pits
2300 					teleport_dest = "2da 2bb 0";
2301 				else if (selection == 2) // Tar Pits
2302 					teleport_dest = "1c3 150 0";
2303 				else if (selection == 3) // Pot.Nitrate
2304 					teleport_dest = "2dd 19e 0";
2305 				else if (selection == 4) // Yucca Plants
2306 					teleport_dest = "19f 115 0";
2307 				else if (selection == 5) // Bamboo
2308 					teleport_dest = "2fe 23e 0";
2309 				else if (selection == 6) // River Banks
2310 					teleport_dest = "253 5e 0";
2311 				else if (selection == 7) // Corn Stalks
2312 					teleport_dest = "18b 221 0";
2313 				else if (selection == 8) // Blue Stone
2314 					teleport_dest = "a8 259 0";
2315 				break;
2316 			case 5:
2317 				if (selection == 1) // Barako
2318 					teleport_dest = "178 ac 0";
2319 				else if (selection == 2) // Dead Pad
2320 					teleport_dest = "198 1e 0";
2321 				else if (selection == 3) // Kurak/Yolaru
2322 					teleport_dest = "216 11d 0";
2323 				else if (selection == 4) // Nahuatla
2324 					teleport_dest = "26b 259 0";
2325 				else if (selection == 5) // Jukari
2326 					teleport_dest = "2ba 306 0";
2327 				else if (selection == 6) // Disquiqui
2328 					teleport_dest = "171 25b 0";
2329 				else if (selection == 7) // Barrab
2330 					teleport_dest = "ce 26a 0";
2331 				else if (selection == 8) // Sakkhra
2332 					teleport_dest = "67 266 0";
2333 				else if (selection == 9) // Hub
2334 					teleport_dest = "b8 1c6 0";
2335 				break;
2336 			case 6:
2337 				if (selection == 1) // Spider
2338 					teleport_dest = "389 2ed 0";
2339 				else if (selection == 2) // Jukari Ritual
2340 					teleport_dest = "3a1 34d 0";
2341 				else if (selection == 3) // Silverback
2342 					teleport_dest = "123 45 0";
2343 				else if (selection == 4) // Fritz
2344 					teleport_dest = "1f1 4d 0";
2345 				else if (selection == 5) // Urali Spirit
2346 					teleport_dest = "3bc ec 0";
2347 				else if (selection == 6) // Urali Chief
2348 					teleport_dest = "3db 19e 0";
2349 				else if (selection == 7) // To Urali
2350 					teleport_dest = "2ad 176 0";
2351 				else if (selection == 8) // From Urali
2352 					teleport_dest = "335 15e 0";
2353 				else if (selection == 9) // Denys
2354 					teleport_dest = "2d5 19e 0";
2355 				break;
2356 			case 7:
2357 				if (selection == 1) // S of Disquiqui
2358 					teleport_dest = "15e 277 0";
2359 				else if (selection == 2) // W of Great Mesa
2360 					teleport_dest = "8d 1fc 0";
2361 				else if (selection == 3) // W of Hub
2362 					teleport_dest = "8d 1ca 0";
2363 				else if (selection == 4) // E of Drum Hill
2364 					teleport_dest = "27b 1d3 0";
2365 				else if (selection == 5) // SW of Kurak
2366 					teleport_dest = "173 14f 0";
2367 				else if (selection == 6) // Old Pindiro
2368 					teleport_dest = "189 45 0";
2369 				else if (selection == 7) // S of Pindiro
2370 					teleport_dest = "257 dc 0";
2371 				break;
2372 			}
2373 		}
2374 		if (strlen(teleport_dest)) {
2375 			scroll->display_string("\n(");
2376 			scroll->display_string(teleport_dest);
2377 			scroll->display_string(")\n");
2378 			alt_code_teleport(teleport_dest);
2379 		}
2380 	}
2381 	++alt_code_input_num;
2382 }
2383 
wait()2384 void Events::wait() {
2385 	if (!ignore_timeleft)
2386 		g_system->delayMillis(TimeLeft());
2387 }
2388 
2389 //Protected
2390 
TimeLeft()2391 inline uint32 Events::TimeLeft() {
2392 	static uint32 next_time = 0;
2393 	uint32 now;
2394 
2395 	now = clock->get_ticks();
2396 	if (fps_counter == 60) {
2397 		fps_counter = 0;
2398 		float fps = 1000 / ((float)(now - fps_timestamp) / 60);
2399 		//printf("FPS: %f %d\n", fps, (uint32)(now - fps_timestamp));
2400 		fps_counter_widget->setFps(fps);
2401 		fps_timestamp = now;
2402 	} else
2403 		fps_counter++;
2404 
2405 	if (next_time <= now) {
2406 		next_time = now + NUVIE_INTERVAL;
2407 		return (0);
2408 	}
2409 	uint32 delay = next_time - now;
2410 	next_time += NUVIE_INTERVAL;
2411 	return (delay);
2412 }
2413 
toggleFpsDisplay()2414 void Events::toggleFpsDisplay() {
2415 	if (fps_counter_widget->Status() == WIDGET_VISIBLE)
2416 		fps_counter_widget->Hide();
2417 	else
2418 		fps_counter_widget->Show();
2419 	if (!game->is_new_style())
2420 		game->get_gui()->force_full_redraw();
2421 }
2422 
quitDialog()2423 void Events::quitDialog() {
2424 	GUI_Widget *quit_dialog;
2425 	if (mode == MOVE_MODE || mode == EQUIP_MODE) {
2426 		map_window->set_looking(false);
2427 		map_window->set_walking(false);
2428 		showingDialog = true;
2429 
2430 		close_gumps();
2431 		uint16 x_off = game->get_game_x_offset();
2432 		uint16 y_off = game->get_game_y_offset();
2433 
2434 		x_off += (game->get_game_width() - 170) / 2;
2435 		y_off += (game->get_game_height() - 80) / 2;
2436 		quit_dialog = (GUI_Widget *) new GUI_YesNoDialog(gui,
2437 		              x_off,
2438 		              y_off,
2439 		              170,
2440 		              80,
2441 		              "Do you want to Quit",
2442 		              this,
2443 		              this);
2444 
2445 		gui->AddWidget(quit_dialog);
2446 		gui->lock_input(quit_dialog);
2447 	}
2448 
2449 	return;
2450 }
2451 
gameMenuDialog()2452 void Events::gameMenuDialog() {
2453 	if (mode == MOVE_MODE && !view_manager->gumps_are_active()) {
2454 		showingDialog = true;
2455 		map_window->set_looking(false);
2456 		map_window->set_walking(false);
2457 		gamemenu_dialog = new GameMenuDialog(this);
2458 		gui->AddWidget(gamemenu_dialog);
2459 		gui->lock_input(gamemenu_dialog);
2460 		keybinder->set_enable_joy_repeat(false);
2461 	} else
2462 		cancelAction();
2463 }
2464 
callback(uint16 msg,CallBack * caller,void * data)2465 uint16 Events::callback(uint16 msg, CallBack *caller, void *data) {
2466 	GUI_Widget *widget;
2467 
2468 	switch (msg) { // Handle callback from quit dialog.
2469 	case YESNODIALOG_CB_YES :
2470 		showingDialog = false;
2471 		game->get_gui()->unlock_input();
2472 		return GUI_QUIT;
2473 	case YESNODIALOG_CB_NO :
2474 		widget = (GUI_Widget *)data;
2475 		widget->Delete();
2476 
2477 		showingDialog = false;
2478 		if (gamemenu_dialog != NULL)
2479 			gui->lock_input(gamemenu_dialog);
2480 		else
2481 			game->get_gui()->unlock_input();
2482 		return GUI_YUM;
2483 	case GAMEMENUDIALOG_CB_DELETE :
2484 		showingDialog = false;
2485 		gamemenu_dialog = NULL;
2486 		keybinder->set_enable_joy_repeat(true);
2487 		return GUI_YUM;
2488 	}
2489 
2490 	return GUI_PASS;
2491 }
2492 
2493 /* Switch to solo mode.
2494  */
solo_mode(uint32 party_member)2495 void Events::solo_mode(uint32 party_member) {
2496 	Actor *actor = player->get_party()->get_actor(party_member);
2497 
2498 	if (game->user_paused())
2499 		return;
2500 
2501 	if (!actor || player->is_in_vehicle())
2502 		return;
2503 
2504 	if (player->get_party()->is_in_combat_mode())
2505 		scroll->display_string("Not in combat mode!\n\n");
2506 	else if (player->set_solo_mode(actor)) {
2507 		scroll->display_string("Solo mode\n\n");
2508 		player->set_mapwindow_centered(true);
2509 		actor->set_worktype(0x02); // Player
2510 		if (in_control_cheat)
2511 			game->get_party()->update_light_sources();
2512 		in_control_cheat = false;
2513 
2514 		if (game->is_new_style()) {// do nothing for now
2515 		} else if (view_manager->get_current_view() == view_manager->get_inventory_view())
2516 			view_manager->get_inventory_view()->set_party_member(party_member);
2517 		else if (view_manager->get_current_view() == view_manager->get_actor_view())
2518 			view_manager->get_actor_view()->set_party_member(party_member);
2519 	}
2520 	scroll->display_prompt();
2521 }
2522 
2523 /* Switch to party mode. */
party_mode()2524 bool Events::party_mode() {
2525 	bool was_in_control_cheat; // go in party mode no matter what (we know are we not in combat or vehicle)
2526 	MapCoord leader_loc;
2527 	if (in_control_cheat) {
2528 		in_control_cheat = false;
2529 		was_in_control_cheat = true;
2530 		view_manager->set_party_mode();
2531 		game->get_party()->update_light_sources();
2532 	} else
2533 		was_in_control_cheat = false;
2534 	Actor *actor = player->get_party()->get_actor(0);
2535 	assert(actor); // there must be a leader
2536 
2537 	if (game->user_paused() && !was_in_control_cheat) // don't return if died in control cheat
2538 		return false;
2539 
2540 	if (player->is_in_vehicle())
2541 		return false;
2542 
2543 	bool success = false;
2544 	leader_loc = actor->get_location();
2545 
2546 	if (player->get_party()->is_in_combat_mode())
2547 		scroll->display_string("Not in combat mode!\n");
2548 	else if (player->get_party()->is_at(leader_loc, 6) || was_in_control_cheat) {
2549 		if (player->set_party_mode(player->get_party()->get_actor(0))) {
2550 			success = true;
2551 			scroll->display_string("Party mode\n");
2552 			player->set_mapwindow_centered(true);
2553 		}
2554 	} else
2555 		scroll->display_string("Not everyone is here.\n");
2556 	scroll->display_string("\n");
2557 	scroll->display_prompt();
2558 	return success;
2559 }
2560 
2561 /* Switch to or from combat mode. */
toggle_combat()2562 bool Events::toggle_combat() {
2563 	Party *party = player->get_party();
2564 	bool combat_mode = !party->is_in_combat_mode();
2565 
2566 	if (!player->in_party_mode()) {
2567 		scroll->display_string("Not in solo mode.\n\n");
2568 		scroll->display_prompt();
2569 	} else if (party->is_in_vehicle()) {
2570 		display_not_aboard_vehicle();
2571 	} else if (in_control_cheat) {
2572 		scroll->display_string("\nNot while using control cheat!\n\n");
2573 		scroll->display_prompt();
2574 	} else
2575 		party->set_in_combat_mode(combat_mode);
2576 
2577 	if (party->is_in_combat_mode() == combat_mode) {
2578 		if (combat_mode)
2579 			scroll->display_string("Begin combat!\n\n");
2580 		else {
2581 			scroll->display_string("Break off combat!\n\n");
2582 			player->set_actor(party->get_leader_actor()); // return control to leader
2583 			player->set_mapwindow_centered(true); // center mapwindow
2584 		}
2585 		scroll->display_prompt();
2586 
2587 		return true;
2588 	}
2589 
2590 	return false;
2591 }
2592 
2593 /* Make actor wear an object they are holding. */
ready(Obj * obj,Actor * actor)2594 bool Events::ready(Obj *obj, Actor *actor) {
2595 	if (!actor)
2596 		actor = game->get_actor_manager()->get_actor(obj->x);
2597 	bool readied = false;
2598 
2599 	if (game->user_paused())
2600 		return (false);
2601 
2602 	scroll->display_fmt_string("Ready-%s\n", obj_manager->look_obj(obj, false));
2603 	float obj_weight = obj_manager->get_obj_weight(obj, OBJ_WEIGHT_INCLUDE_CONTAINER_ITEMS,
2604 	                   OBJ_WEIGHT_DO_SCALE, OBJ_WEIGHT_EXCLUDE_QTY);
2605 	float equip_weight = actor->get_inventory_equip_weight() + obj_weight;
2606 	float total_weight = actor->get_inventory_weight();
2607 
2608 	if (obj->get_actor_holding_obj() != actor)
2609 		total_weight += obj_weight;
2610 
2611 	if ((actor->get_strength() < equip_weight
2612 	        || actor->get_strength() * 2 < total_weight) && !game->using_hackmove())
2613 		scroll->display_string("\nToo heavy!\n");
2614 	// perform READY usecode
2615 	else if (actor->can_ready_obj(obj) && usecode->has_readycode(obj) && (usecode->ready_obj(obj, actor) == false)) {
2616 		scroll->display_string("\n");
2617 		scroll->display_prompt();
2618 		return (obj->is_readied()); // handled by usecode
2619 	} else if (obj->is_in_container() && obj->get_actor_holding_obj() != actor
2620 	           && !Game::get_game()->get_map_window()->can_get_obj(actor, obj->get_container_obj()))
2621 		scroll->display_string("\nCan't reach it\n");
2622 	else if (!(readied = actor->add_readied_object(obj))) {
2623 		if (actor->get_object_readiable_location(obj) == ACTOR_NOT_READIABLE)
2624 			scroll->display_string("\nCan't be readied!\n");
2625 		else
2626 			scroll->display_string("\nNo place to put!\n");
2627 	}
2628 	scroll->display_string("\n");
2629 	scroll->display_prompt();
2630 	return (readied);
2631 }
2632 
2633 /* Make actor hold an object they are wearing. */
unready(Obj * obj)2634 bool Events::unready(Obj *obj) {
2635 	Actor *actor = game->get_actor_manager()->get_actor(obj->x);
2636 
2637 	if (game->user_paused())
2638 		return (false);
2639 
2640 	scroll->display_fmt_string("Unready-%s\n", obj_manager->look_obj(obj, false));
2641 
2642 	// perform unREADY usecode
2643 	if (usecode->has_readycode(obj) && (usecode->ready_obj(obj, actor) == false)) {
2644 		scroll->display_string("\n");
2645 		scroll->display_prompt();
2646 		return (!obj->is_readied()); // handled by usecode
2647 	}
2648 
2649 	actor->remove_readied_object(obj, false); // already ran usecode so don't run when unequipping
2650 
2651 	scroll->display_string("\n");
2652 	scroll->display_prompt();
2653 	return (true);
2654 }
2655 
drop_start()2656 bool Events::drop_start() {
2657 	if (game->user_paused())
2658 		return false;
2659 	drop_obj = NULL;
2660 	drop_qty = 0;
2661 	drop_x = drop_y = -1;
2662 
2663 //    get_obj_from_inventory(some actor, "Drop-");
2664 //    get_obj_from_inventory("Drop-");
2665 	get_target("Drop-");
2666 //    moveCursorToInventory(); done in newAction()
2667 	return true;
2668 }
2669 
2670 /* Print object name and select it as object to be dropped. If qty is 0, the
2671  * amount to drop may be requested.
2672  */
drop_select(Obj * obj,uint16 qty)2673 bool Events::drop_select(Obj *obj, uint16 qty) {
2674 	if (game->user_paused())
2675 		return false;
2676 
2677 	drop_obj = obj;
2678 	scroll->display_string(drop_obj ? obj_manager->look_obj(drop_obj) : "nothing");
2679 	scroll->display_string("\n");
2680 	if (drop_from_key)
2681 		close_gumps();
2682 	if (drop_obj) {
2683 		if (qty == 0 && obj_manager->is_stackable(drop_obj) && drop_obj->qty > 1) {
2684 			scroll->display_string("How many? ");
2685 //            newAction(DROPCOUNT_MODE);
2686 			get_scroll_input(); // "How many?"
2687 			return true;
2688 		}
2689 		drop_count(1);
2690 	} else endAction(true);
2691 
2692 	return true;
2693 }
2694 
2695 /* Select quantity of `drop_obj' to be dropped. (qty 0 = drop nothing) */
drop_count(uint16 qty)2696 bool Events::drop_count(uint16 qty) {
2697 	if (game->user_paused())
2698 		return (false);
2699 
2700 	drop_qty = qty;
2701 	scroll->display_string("\n");
2702 
2703 	if (drop_qty != 0) {
2704 		if (drop_x == -1)
2705 			get_target("Location:");
2706 		else { // h4x0r3d by SB-X... eventually integrate MapWindow dragndrop better with this drop-action
2707 			scroll->display_string("Location:");
2708 			perform_drop(); // use already selected target: drop_x,drop_y
2709 		}
2710 	} else
2711 		endAction(true); // cancelled
2712 
2713 	return true;
2714 }
2715 
2716 /* Make actor holding selected object drop it at cursor coordinates. Wait for
2717  * drop effect to complete before ending the action.
2718  */
perform_drop()2719 bool Events::perform_drop() {
2720 	if (game->user_paused())
2721 		return false;
2722 	if (drop_x == -1 || drop_y == -1) {
2723 		if (input.loc == NULL) {
2724 			scroll->display_string("Not possible\n");
2725 			endAction(true);
2726 			return false;
2727 		}
2728 
2729 		if (drop_x == -1) drop_x = input.loc->x;
2730 		if (drop_y == -1) drop_y = input.loc->y;
2731 	}
2732 
2733 	return (drop(drop_obj, drop_qty, uint16(drop_x), uint16(drop_y)));
2734 }
2735 
2736 /* Make actor holding object drop it at x,y. */
drop(Obj * obj,uint16 qty,uint16 x,uint16 y)2737 bool Events::drop(Obj *obj, uint16 qty, uint16 x, uint16 y) {
2738 	if (game->user_paused())
2739 		return false;
2740 
2741 	bool drop_from_map = obj->get_engine_loc() == OBJ_LOC_MAP;
2742 
2743 	Actor *actor = (obj->is_in_inventory()) // includes held containers
2744 	               ? obj->get_actor_holding_obj()
2745 	               : player->get_actor();
2746 	MapCoord actor_loc = actor->get_location();
2747 	MapCoord drop_loc(x, y, actor_loc.z);
2748 	/* not used in the original game engine
2749 	    sint16 rel_x = x - actor_loc.x;
2750 	    sint16 rel_y = y - actor_loc.y;
2751 	    if(rel_x != 0 || rel_y != 0)
2752 	    {
2753 	        scroll->display_string(get_direction_name(rel_x, rel_y));
2754 	        scroll->display_string(".");
2755 	    }*/
2756 	CanDropOrMoveMsg can_drop;
2757 	if (!drop_from_map // already checked in map window
2758 	        && (can_drop = map_window->can_drop_or_move_obj(drop_loc.x, drop_loc.y, actor, obj)) != MSG_SUCCESS) {
2759 //        scroll->display_string("\n\nNot possible\n"); // using text from can_drop_or_move_obj
2760 		map_window->display_can_drop_or_move_msg(can_drop, "\n\n");
2761 		endAction(true); // because the DropEffect is never called to do this
2762 		return false;
2763 	}
2764 
2765 	// all object management is contained in the effect (use requested quantity)
2766 	if (!usecode->has_dropcode(obj)
2767 	        || usecode->drop_obj(obj, actor, drop_loc.x, drop_loc.y, qty ? qty : obj->qty)) {
2768 		bool interface_fullscreen = map_window->get_interface() != INTERFACE_NORMAL;
2769 		if (interface_fullscreen) {
2770 			if (qty < obj->qty && obj_manager->is_stackable(obj))
2771 				obj = obj_manager->get_obj_from_stack(obj, qty);
2772 			Obj *dest_obj = obj_manager->get_obj(drop_loc.x, drop_loc.y, drop_loc.z);
2773 			if (obj_manager->can_store_obj(dest_obj, obj))
2774 				obj_manager->moveto_container(obj, dest_obj);
2775 			else
2776 				obj_manager->moveto_map(obj, drop_loc);
2777 		} else if (drop_from_map) {
2778 			if (qty >= obj->qty || !obj_manager->is_stackable(obj))
2779 				obj_manager->remove_obj_from_map(obj); // stop ghosting from drop effect
2780 		}
2781 
2782 		if (!drop_from_map) // preserve ok to take if it was never in inventory
2783 			obj->status |= OBJ_STATUS_OK_TO_TAKE;
2784 
2785 		if (!interface_fullscreen)
2786 			new DropEffect(obj, qty ? qty : obj->qty, actor, &drop_loc);
2787 		if (drop_from_map && map_window->original_obj_loc.distance(drop_loc) > 1) // get plus drop
2788 			player->subtract_movement_points(6); // get plus drop
2789 		else if (drop_from_map) // move
2790 			player->subtract_movement_points(5);
2791 		else
2792 			game->get_script()->call_actor_subtract_movement_points(actor, 3);
2793 		scroll->message("\n\n");
2794 		endAction(false);
2795 		set_mode(MOVE_MODE);
2796 		return true;
2797 	}
2798 	// handled by usecode
2799 	endAction(true); // because the DropEffect is never called to do this
2800 	return false;
2801 }
2802 
rest()2803 bool Events::rest() {
2804 	if (rest_time != 0) { // already got time & started the campfire; time to Rest
2805 		assert(last_mode == REST_MODE); // we'll need to clear Rest mode after
2806 		// exiting Wait mode
2807 		player->get_party()->rest_sleep(rest_time, rest_guard - 1);
2808 		return true;
2809 	}
2810 	scroll->display_string("Rest");
2811 
2812 	string err_str;
2813 	if (!player->get_party()->can_rest(err_str)) {
2814 		scroll->display_string(err_str);
2815 		scroll->display_string("\n");
2816 		endAction(true);
2817 		return false;
2818 	}
2819 
2820 	if (player->get_actor()->get_obj_n() == OBJ_U6_SHIP) {
2821 		scroll->display_string("\n");
2822 		player->repairShip();
2823 		endAction(true);
2824 	} else {
2825 		scroll->display_string("\nHow many hours? ");
2826 		get_scroll_input("0123456789");
2827 	}
2828 	return true;
2829 }
2830 
2831 /* Get hours to Rest, or number of party member who will guard. These must be
2832    entered in order. */
rest_input(uint16 input_)2833 bool Events::rest_input(uint16 input_) {
2834 	Party *party = player->get_party();
2835 	scroll->set_input_mode(false);
2836 	scroll->display_string("\n");
2837 	if (rest_time == 0) {
2838 		rest_time = input_;
2839 		if (rest_time == 0) {
2840 			endAction(true);
2841 			return false;
2842 		}
2843 		if (party->get_party_size() > 1) {
2844 			scroll->display_string("Who will guard? ");
2845 			get_target("");
2846 			get_scroll_input("0123456789", true, true);
2847 		} else {
2848 			party->rest_gather(); // nobody can guard; start now
2849 		}
2850 	} else {
2851 		rest_guard = input_;
2852 		if (rest_guard > party->get_party_size())
2853 			rest_guard = 0;
2854 		if (rest_guard == 0)
2855 			scroll->display_string("none\n");
2856 		else {
2857 			scroll->display_string(party->get_actor(rest_guard - 1)->get_name());
2858 			scroll->display_string("\n");
2859 		}
2860 		scroll->display_string("\n");
2861 		party->rest_gather();
2862 	}
2863 	return true;
2864 }
2865 
cast_spell_directly(uint8 spell_num)2866 void Events::cast_spell_directly(uint8 spell_num) {
2867 	endAction(false);
2868 	newAction(SPELL_MODE);
2869 	input.type = EVENTINPUT_KEY;
2870 	input.spell_num = spell_num;
2871 	doAction();
2872 }
2873 
2874 /* Walk the player towards the mouse cursor. (just 1 space for now) */
walk_to_mouse_cursor(uint32 mx,uint32 my)2875 void Events::walk_to_mouse_cursor(uint32 mx, uint32 my) {
2876 // FIXME: might add generic walk_to() action to Player
2877 // player->walk_to(uint16 x, uint16 y, uint16 move_max, uint16 timeout_seconds);
2878 //    int wx, wy;
2879 	sint16 rx, ry;
2880 
2881 	if (game->user_paused() || !player->check_walk_delay())
2882 		return;
2883 
2884 	// Mouse->World->RelativeDirection
2885 //    map_window->mouseToWorldCoords((int)mx, (int)my, wx, wy);
2886 	map_window->get_movement_direction((uint16) mx, (uint16) my, rx, ry);
2887 	player->moveRelative(rx, ry, true);
2888 	game->time_changed();
2889 }
2890 
2891 /* Talk to NPC, read a sign, or use an object at map coordinates.
2892  * FIXME: should be able to handle objects from inventory
2893  */
multiuse(uint16 wx,uint16 wy)2894 void Events::multiuse(uint16 wx, uint16 wy) {
2895 	ActorManager *actor_manager = game->get_actor_manager();
2896 	Obj *obj = NULL;
2897 	Actor *actor = NULL, *player_actor = player->get_actor();
2898 	bool using_actor = false; //, talking = false;
2899 	MapCoord player_location(player_actor->get_location());
2900 	MapCoord target(player_actor->get_location()); // changes to target location
2901 	bool in_combat = player->get_party()->is_in_combat_mode();
2902 
2903 	if (game->user_paused() || map_window->tile_is_black(wx, wy))
2904 		return;
2905 
2906 	obj = obj_manager->get_obj(wx, wy, target.z);
2907 	actor = actor_manager->get_actor(wx, wy, target.z);
2908 
2909 	// use object or actor?
2910 	if (actor) {
2911 		if ((!actor->is_visible() && !in_combat) || (in_combat
2912 		        && (actor->get_actor_num() == player->get_actor()->get_actor_num() //don't attack yourself.
2913 		            || actor->get_alignment() == ACTOR_ALIGNMENT_GOOD))) {
2914 			Actor *a = actor_manager->get_actor(actor->get_x(), actor->get_y(), actor->get_z(), true, actor);
2915 			if (a || (!in_combat && (!actor->is_visible() // null invisible actors if not in combat and no one is found
2916 			                         || (actor == player_actor && !game->is_new_style()
2917 			                             && actor->get_actor_num() != 0)))) // pass if in combat if player and not showing inventory
2918 				actor = a;
2919 		}
2920 
2921 		if (actor) {
2922 			using_actor = true;
2923 			target.x = actor->get_location().x;
2924 			target.y = actor->get_location().y;
2925 			DEBUG(0, LEVEL_DEBUGGING, "Use actor at %d,%d\n", target.x, target.y);
2926 		}
2927 	}
2928 	if (obj && !using_actor) {
2929 		target.x = obj->x;
2930 		target.y = obj->y;
2931 		DEBUG(0, LEVEL_DEBUGGING, "Use object at %d,%d\n", obj->x, obj->y);
2932 	}
2933 
2934 	if (in_combat && (obj || using_actor)) {
2935 		if (!using_actor || actor->get_alignment() != ACTOR_ALIGNMENT_GOOD) {
2936 			newAction(ATTACK_MODE);
2937 			if (get_mode() == ATTACK_MODE) {
2938 				map_window->moveCursor(wx - map_window->get_cur_x(), wy - map_window->get_cur_y());
2939 				select_target(uint16(wx), uint16(wy), target.z);
2940 			}
2941 			return;
2942 		}
2943 	}
2944 
2945 	if (using_actor) { // use or talk to an actor
2946 		if (using_pickpocket_cheat && game->are_cheats_enabled()) {
2947 			get_inventory_obj(actor, false);
2948 			return;
2949 		}
2950 		bool can_use;
2951 		if (game->get_game_type() == NUVIE_GAME_U6 && (actor->get_actor_num() == 132 // Smith
2952 		        || actor->get_actor_num() == 130)) // Pushme Pullyu
2953 			can_use = false;
2954 		else
2955 			can_use = usecode->has_usecode(actor);
2956 		if (can_use) {
2957 			scroll->display_string("Use-", MSGSCROLL_NO_MAP_DISPLAY);
2958 			set_mode(USE_MODE);
2959 			use(actor, wx, wy);
2960 		} else {
2961 			if (game->is_new_style() && actor == actor_manager->get_player()) {
2962 				//open inventory here.
2963 				view_manager->open_doll_view(in_control_cheat ? actor : NULL);
2964 			} else if (target == player_location)
2965 				using_actor = false;
2966 			else {
2967 				newAction(TALK_MODE);
2968 				talk(actor);
2969 			}
2970 		}
2971 		if (using_actor)
2972 			return;
2973 	}
2974 	if (!obj)
2975 		return;
2976 	else if (usecode->is_readable(obj)) {
2977 		scroll->display_string("Look-", MSGSCROLL_NO_MAP_DISPLAY);
2978 		set_mode(LOOK_MODE);
2979 		look(obj);
2980 		endAction(false); // FIXME: should be in look()
2981 	} else if (game->get_game_type() == NUVIE_GAME_U6
2982 	           && (obj->obj_n == OBJ_U6_SHRINE
2983 	               || obj->obj_n == OBJ_U6_STATUE_OF_MONDAIN
2984 	               || obj->obj_n == OBJ_U6_STATUE_OF_MINAX
2985 	               || obj->obj_n == OBJ_U6_STATUE_OF_EXODUS)) {
2986 		scroll->display_string("Talk-", MSGSCROLL_NO_MAP_DISPLAY);
2987 		set_mode(TALK_MODE);
2988 		talk(obj);
2989 	} else { // use a real object
2990 		if (newAction(USE_MODE))
2991 			select_obj(obj);
2992 	}
2993 }
2994 
2995 /* Do the final action for the current mode, with a selected target. */
doAction()2996 void Events::doAction() {
2997 	if (game->user_paused())
2998 		return;
2999 
3000 	if (mode == MOVE_MODE) {
3001 		scroll->display_string("what?\n", MSGSCROLL_NO_MAP_DISPLAY);
3002 		endAction(true);
3003 		return;
3004 	}
3005 	if (mode == INPUT_MODE) { // set input to current cursor coord
3006 		if (input.get_text) {
3007 			if (last_mode == REST_MODE && rest_time != 0 && !scroll->has_input()) {
3008 				select_target(map_window->get_cursorCoord().x,
3009 				              map_window->get_cursorCoord().y,
3010 				              map_window->get_cursorCoord().z);
3011 				return;
3012 			}
3013 			assert(scroll->has_input()); // doAction should only be called when input is ready
3014 			assert(input.str == 0);
3015 			input.str = new string(scroll->get_input());
3016 			endAction();
3017 			doAction();
3018 		} else if (input.select_from_inventory) // some redirection here...
3019 			view_manager->get_inventory_view()->select_objAtCursor();
3020 		else
3021 			select_target(map_window->get_cursorCoord().x, map_window->get_cursorCoord().y, map_window->get_cursorCoord().z);
3022 		// the above function will switch back to the previous mode that
3023 		// started getting input, and call doAction() again, which should
3024 		// eventually result in an endAction()
3025 		return;
3026 	} else if (callback_target) { // send input elsewhere
3027 		message(CB_DATA_READY, (char *) &input);
3028 		callback_target = 0;
3029 		endAction(true);
3030 		return;
3031 	}
3032 
3033 	if (mode == LOOK_MODE) {
3034 		if (looking_at_spellbook && view_manager->get_spell_view() != NULL) {
3035 			view_manager->get_spell_view()->close_look();
3036 			return;
3037 		}
3038 		if (input.type == EVENTINPUT_OBJECT && input.obj && (!input.obj->is_on_map()
3039 		        || (!(input.obj->status & OBJ_STATUS_INVISIBLE)
3040 		            && !map_window->tile_is_black(input.obj->x,
3041 		                    input.obj->y,
3042 		                    input.obj)))) {   // look() returns false if prompt was already printed
3043 			bool prompt_in_endAction = look(input.obj);
3044 			endAction(prompt_in_endAction);
3045 		} else if (input.type == EVENTINPUT_MAPCOORD && input.actor && input.actor->is_visible()) {
3046 			bool prompt = !look(input.actor);
3047 			endAction(prompt);
3048 		} else {
3049 			lookAtCursor();
3050 		}
3051 	} else if (mode == TALK_MODE) {
3052 		if (input.type == EVENTINPUT_OBJECT)
3053 			talk(input.obj);
3054 		else if (input.type == EVENTINPUT_MAPCOORD && input.actor && input.actor->is_visible())
3055 			talk(input.actor);
3056 		else
3057 			talk_cursor();
3058 		endAction();
3059 	} else if (mode == USE_MODE) {
3060 
3061 		if (usecode) {
3062 			ScriptThread *usecode_script = usecode->get_running_script();
3063 			if (usecode_script != NULL) {
3064 				uint8 script_state = usecode_script->get_state();
3065 				switch (script_state) {
3066 				case NUVIE_SCRIPT_GET_DIRECTION :
3067 					if (input.type == EVENTINPUT_MAPCOORD_DIR) {
3068 						usecode_script->resume_with_direction(get_direction_code(input.loc->sx, input.loc->sy));
3069 					}
3070 					break;
3071 				case NUVIE_SCRIPT_GET_OBJ :
3072 					usecode_script->resume_with_obj(input.obj);
3073 					if (!game->is_new_style()) {
3074 						view_manager->get_inventory_view()->release_focus();
3075 						sint8 leader = game->get_party()->get_leader();
3076 						if (leader >= 0) {
3077 							view_manager->get_inventory_view()->set_party_member(leader);
3078 						}
3079 					} else
3080 						view_manager->close_all_gumps();
3081 					break;
3082 				}
3083 			} else {
3084 //          if(game->is_new_style()) // don't do this it wll crash when using containers inside a gump
3085 //            view_manager->close_all_gumps();
3086 
3087 				if (input.type == EVENTINPUT_OBJECT)
3088 					use(input.obj);
3089 				else if (input.type == EVENTINPUT_MAPCOORD_DIR) {
3090 					if (input.actor && input.actor->is_visible() && usecode->has_usecode(input.actor)) {
3091 						MapCoord loc = game->get_player()->get_actor()->get_location();
3092 						use(input.actor, loc.x + input.loc->sx, loc.y + input.loc->sy);
3093 					} else
3094 						use(input.loc->sx, input.loc->sy);
3095 				} else if (input.type == EVENTINPUT_MAPCOORD) {
3096 					use(*input.loc);
3097 				} else {
3098 					scroll->display_string("what?\n");
3099 					endAction(true);
3100 				}
3101 			}
3102 
3103 			usecode_script = usecode->get_running_script();
3104 			if (usecode_script != NULL) {
3105 				uint8 script_state = usecode_script->get_state();
3106 				switch (script_state) {
3107 				case NUVIE_SCRIPT_GET_DIRECTION :
3108 					get_direction("");
3109 					break;
3110 				case NUVIE_SCRIPT_GET_OBJ :
3111 					get_target("");
3112 					break;
3113 				}
3114 			}
3115 
3116 			if (mode == USE_MODE && (usecode_script == NULL || usecode_script->is_running() == false)) {
3117 				endAction(true);
3118 			}
3119 		}
3120 
3121 		// assert(mode != USE_MODE);
3122 	} else if (mode == GET_MODE) {
3123 		if (input.type == EVENTINPUT_OBJECT)
3124 			perform_get(input.obj);
3125 		else if (input.type == EVENTINPUT_MAPCOORD_DIR)
3126 			get(input.loc->sx, input.loc->sy);
3127 		else if (input.type == EVENTINPUT_MAPCOORD)
3128 			get(*input.loc);
3129 		else {
3130 			scroll->display_string("what?\n");
3131 			endAction(true);
3132 		}
3133 		endAction();
3134 	} else if (mode == ATTACK_MODE) {
3135 		attack();
3136 	} else if (mode == PUSH_MODE) {
3137 		assert(
3138 		    input.type == EVENTINPUT_MAPCOORD_DIR || input.type == EVENTINPUT_OBJECT || input.type == EVENTINPUT_MAPCOORD);
3139 		if (input.type == EVENTINPUT_MAPCOORD_DIR) {
3140 			if (!push_obj && !push_actor)
3141 				pushFrom(input.loc->sx, input.loc->sy);
3142 			else
3143 				pushTo(input.loc->sx, input.loc->sy, PUSH_FROM_OBJECT);
3144 		} else if (input.type == EVENTINPUT_MAPCOORD && !move_in_inventory) {
3145 			if (!push_obj && !push_actor)
3146 				pushFrom(*input.loc);
3147 			else
3148 				pushTo(input.loc->x, input.loc->y);
3149 		} else {
3150 			if (!push_obj) {
3151 				move_in_inventory = true;
3152 				pushFrom(input.obj);
3153 			} else {
3154 				pushTo(input.obj, input.actor);
3155 			}
3156 		}
3157 	} else if (mode == DROP_MODE) { // called repeatedly
3158 		if (!drop_obj) {
3159 			if (input.select_from_inventory == false)
3160 				return endAction(true);
3161 
3162 			if (input.type == EVENTINPUT_MAPCOORD) {
3163 				scroll->display_string("nothing\n");
3164 				return endAction(true);
3165 			}
3166 
3167 			assert(input.type == EVENTINPUT_OBJECT);
3168 			drop_select(input.obj);
3169 		} else if (!drop_qty) {
3170 			assert(input.str);
3171 			if (strncmp(input.str->c_str(), "", input.str->length()) == 0) {
3172 				char buf[6];
3173 				snprintf(buf, sizeof(buf), "%u", drop_obj->qty);
3174 				scroll->display_string(buf);
3175 				drop_count(drop_obj->qty);
3176 			} else
3177 				drop_count(strtol(input.str->c_str(), NULL, 10));
3178 		} else
3179 			perform_drop();
3180 	} else if (mode == REST_MODE) {
3181 		if (rest_time != 0 && !input.str) {
3182 			sint8 party_num;
3183 			if (input.actor)
3184 				party_num = game->get_party()->get_member_num(input.actor) + 1;
3185 			else
3186 				party_num = 0;
3187 			rest_input(party_num > 0 ? party_num : 0);
3188 			return;
3189 		}
3190 		assert(input.str);
3191 		if (strncmp(input.str->c_str(), "", input.str->length()) == 0) {
3192 			if (rest_time == 0)
3193 				scroll->display_string("0");
3194 			rest_input(0);
3195 		} else
3196 			rest_input(strtol(input.str->c_str(), NULL, 10));
3197 	} else if (mode == CAST_MODE || mode == SPELL_MODE) {
3198 		if (input.type == EVENTINPUT_MAPCOORD) {
3199 			if (magic->is_waiting_for_location())
3200 				magic->resume(MapCoord(input.loc->x, input.loc->y, input.loc->z));
3201 			else if (magic->is_waiting_for_obj())
3202 				magic->resume(input.obj);
3203 			else {
3204 				magic->resume();
3205 				if (!game->is_new_style() && game->get_party()->get_leader() != -1)
3206 					view_manager->get_inventory_view()->set_party_member(game->get_party()->get_leader());
3207 			}
3208 		} else if (input.type == EVENTINPUT_MAPCOORD_DIR) {
3209 			magic->resume(get_direction_code(input.loc->sx, input.loc->sy));
3210 		} else if (input.type == EVENTINPUT_OBJECT) {
3211 			magic->resume(input.obj);
3212 			if (!game->is_new_style() && game->get_party()->get_leader() != -1) {
3213 				view_manager->get_inventory_view()->release_focus();
3214 				view_manager->get_inventory_view()->set_party_member(game->get_party()->get_leader());
3215 			} else
3216 				view_manager->get_inventory_view()->Hide();
3217 		} else if (input.type == EVENTINPUT_SPELL_NUM) {
3218 			if (input.spell_num != -1)
3219 				magic->resume_with_spell_num(input.spell_num);
3220 			else
3221 				magic->resume();
3222 		} else {
3223 			if (mode == CAST_MODE)
3224 				magic->cast();
3225 			else
3226 				magic->cast_spell_directly(input.spell_num);
3227 		}
3228 
3229 		for (; magic->is_waiting_to_talk();) {
3230 			talk(magic->get_actor_from_script());
3231 			magic->resume();
3232 		}
3233 
3234 		if (magic->is_waiting_for_location() || magic->is_waiting_for_obj())
3235 			get_target("");
3236 		else if (magic->is_waiting_for_direction())
3237 			get_direction("");
3238 		else if (magic->is_waiting_for_inventory_obj()) {
3239 			get_inventory_obj(magic->get_actor_from_script());
3240 		} else if (magic->is_waiting_for_spell()) {
3241 			get_spell_num(player->get_actor(), magic->get_spellbook_obj());
3242 		} else {
3243 			endAction(true);
3244 		}
3245 	} else if (mode == MULTIUSE_MODE) {
3246 		if (input.loc) { // on map
3247 			set_mode(MOVE_MODE);
3248 			multiuse(input.loc->sx, input.loc->sy);
3249 		} else { // tryed on views/gumps
3250 			Obj *obj = input.obj; // newAction(USE_MODE) will NULL input.obj
3251 			if (!obj) { // not sure if this is needed
3252 				set_mode(MOVE_MODE);
3253 				return;
3254 			}
3255 
3256 			if (usecode->is_readable(obj)) { // look at a scroll or book
3257 				set_mode(LOOK_MODE);
3258 				look(obj);
3259 				endAction(false); // FIXME: should be in look()
3260 				return;
3261 			}
3262 			set_mode(USE_MODE);
3263 			use(obj);
3264 		}
3265 	} else if (cursor_mode) {
3266 		MapCoord loc = map_window->get_cursorCoord(); // need to preserve locations if a target is needed
3267 		uint16 cursor_x = loc.x - map_window->get_cur_x();
3268 		uint16 cursor_y = loc.y - map_window->get_cur_y();
3269 
3270 		if (!game->get_command_bar()->try_selected_action(-1)) { // no input needed
3271 			map_window->set_show_cursor(false);
3272 			return;
3273 		}
3274 		map_window->moveCursor(cursor_x, cursor_y);
3275 		select_target(loc.x, loc.y, loc.z); // the returned location
3276 	} else if (mode == SCRIPT_MODE) {
3277 		if (scriptThread != NULL) {
3278 			uint8 script_state = scriptThread->get_state();
3279 			switch (script_state) {
3280 			case NUVIE_SCRIPT_GET_DIRECTION :
3281 				if (input.type == EVENTINPUT_MAPCOORD_DIR) {
3282 					scriptThread->resume_with_direction(get_direction_code(input.loc->sx, input.loc->sy));
3283 				}
3284 				break;
3285 			case NUVIE_SCRIPT_GET_TARGET :
3286 			case NUVIE_SCRIPT_GET_OBJ :
3287 				if (input.type == EVENTINPUT_MAPCOORD) {
3288 					scriptThread->resume_with_location(MapCoord(input.loc->x, input.loc->y, input.loc->z));
3289 				}
3290 				break;
3291 			default:
3292 				break;
3293 			}
3294 
3295 			script_state = scriptThread->get_state();
3296 			switch (script_state) {
3297 			case NUVIE_SCRIPT_GET_DIRECTION :
3298 				get_direction("");
3299 				break;
3300 			case NUVIE_SCRIPT_GET_TARGET :
3301 				get_target("");
3302 				break;
3303 
3304 			case NUVIE_SCRIPT_FINISHED:
3305 				delete scriptThread;
3306 				scriptThread = NULL;
3307 				endAction(true);
3308 				return;
3309 
3310 			default:
3311 				break;
3312 			}
3313 		}
3314 	} else
3315 		cancelAction();
3316 }
3317 
3318 /* Cancel the action for the current mode, switch back to MOVE_MODE if possible. */
cancelAction()3319 void Events::cancelAction() {
3320 	if (game->user_paused())
3321 		return;
3322 	if (view_manager->gumps_are_active() && (magic == NULL || !magic->is_waiting_for_inventory_obj()))
3323 		return close_gumps();
3324 	if (mode == INPUT_MODE) { // cancel action of previous mode
3325 		if (magic != NULL && magic->is_waiting_for_inventory_obj()) {
3326 			if (!game->is_new_style() && game->get_party()->get_leader() != -1) {
3327 				view_manager->get_inventory_view()->release_focus();
3328 				view_manager->get_inventory_view()->set_party_member(game->get_party()->get_leader());
3329 			} else
3330 				view_manager->get_inventory_view()->Hide();
3331 		} else {
3332 			if (usecode) {
3333 				if (usecode->is_script_running()) {
3334 					if (!game->is_new_style()
3335 					        && game->get_party()->get_leader() != -1) { //FIXME consolidate this logic with magic script logic above
3336 						view_manager->get_inventory_view()->release_focus();
3337 						view_manager->get_inventory_view()->set_party_member(game->get_party()->get_leader());
3338 					}
3339 //              else
3340 //                  view_manager->close_all_gumps();
3341 				}
3342 			}
3343 			if (last_mode == PUSH_MODE) {
3344 				if (push_obj || push_actor) {
3345 					if (move_in_inventory)
3346 						scroll->display_string("nobody.\n");
3347 					else
3348 						scroll->display_string("nowhere.\n");
3349 					endAction();
3350 					endAction(true);
3351 					return;
3352 				}
3353 			}
3354 		}
3355 		endAction();
3356 		cancelAction();
3357 		return;
3358 	}
3359 
3360 	if (mode == MOVE_MODE) {
3361 		player->pass();
3362 	} else if (mode == CAST_MODE) {
3363 		if (magic->is_waiting_to_resume())
3364 			magic->resume();
3365 		else {
3366 
3367 			scroll->display_string("nothing\n");
3368 			view_manager->close_spell_mode();
3369 		}
3370 	} else if (mode == USE_MODE) {
3371 		if (usecode->is_script_running()) {
3372 			usecode->get_running_script()->resume_with_nil();
3373 		}
3374 
3375 		if (callback_target) {
3376 			message(CB_INPUT_CANCELED, (char *) &input);
3377 			callback_target = NULL;
3378 			callback_user_data = NULL;
3379 		}
3380 	} else if (mode == EQUIP_MODE) {
3381 		endAction();
3382 		return;
3383 	} else if (looking_at_spellbook && view_manager->get_spell_view() != NULL) {
3384 		view_manager->get_spell_view()->close_look();
3385 		return;
3386 	} else {
3387 		scroll->display_string("what?\n");
3388 		if (mode == ATTACK_MODE) {
3389 			player->subtract_movement_points(10);
3390 			game->get_actor_manager()->startActors(); // end player turn
3391 			endAction();
3392 			return;
3393 		}
3394 	}
3395 
3396 	endAction(true);
3397 }
3398 
3399 /* Request new EventMode, for selecting a target.
3400  * Returns true the mode is changed. (basically if a new "select an
3401  * object/direction for this action" prompt is displayed)
3402  */
newAction(EventMode new_mode)3403 bool Events::newAction(EventMode new_mode) {
3404 	map_window->set_looking(false);
3405 	map_window->set_walking(false);
3406 
3407 	if (game->user_paused())
3408 		return (false);
3409 	cursor_mode = false;
3410 // FIXME: make ATTACK_MODE use INPUT_MODE
3411 	if (mode == ATTACK_MODE && new_mode == ATTACK_MODE) {
3412 		close_gumps();
3413 		doAction();
3414 		return (mode == ATTACK_MODE);
3415 	}
3416 	if (looking_at_spellbook && view_manager->get_spell_view() != NULL) { // pushed L while looking at spell book
3417 		view_manager->get_spell_view()->close_look();
3418 		return false;
3419 	}
3420 	// since INPUT_MODE must be set to get input, it wouldn't make sense that
3421 	// a mode would be requested again to complete the action
3422 	assert(mode != new_mode);
3423 
3424 	// called again (same key pressed twice); equivalent of pressing ENTER so call doAction() to set input
3425 	if (mode == INPUT_MODE && new_mode == last_mode) {
3426 		doAction();
3427 		return (!(mode == MOVE_MODE));
3428 	} else if (mode != MOVE_MODE && mode != EQUIP_MODE) { // already in another mode; exit
3429 		cancelAction();
3430 		return (false);
3431 	}
3432 	move_in_inventory = false;
3433 
3434 	set_mode(new_mode);
3435 	if (new_mode != COMBAT_MODE)
3436 		game->set_mouse_pointer(1);
3437 	switch (new_mode) {
3438 	case CAST_MODE:
3439 		/* TODO check if spellbook ready before changing mode */
3440 		scroll->display_string("Cast-");
3441 		if (!magic->start_new_spell()) {
3442 			mode = MOVE_MODE;
3443 			scroll->display_prompt();
3444 		} else
3445 			key_redirect((CallBack *) magic, NULL);
3446 		break;
3447 	case SPELL_MODE:
3448 		break;
3449 	case LOOK_MODE:
3450 		look_start();
3451 		break;
3452 	case TALK_MODE:
3453 		talk_start();
3454 		break;
3455 	case USE_MODE:
3456 		use_start();
3457 		break;
3458 	case GET_MODE:
3459 		get_start();
3460 		break;
3461 	case MULTIUSE_MODE:
3462 		get_target("");
3463 		if (game->get_party()->is_in_combat_mode())
3464 			player->attack_select_init(false);
3465 		break;
3466 	case ATTACK_MODE:
3467 		close_gumps();
3468 		if (game->get_game_type() == NUVIE_GAME_U6
3469 		        && player->is_in_vehicle()
3470 		        && player->get_actor()->get_obj_n() != OBJ_U6_SHIP) {
3471 			scroll->display_string("Attack-");
3472 			display_not_aboard_vehicle(false);
3473 			endAction(true);
3474 			return false;
3475 		}
3476 		if (game->get_game_type() != NUVIE_GAME_U6) {
3477 			scriptThread = game->get_script()->call_function_in_thread("player_attack");
3478 			mode = SCRIPT_MODE;
3479 			scriptThread->start();
3480 			switch (scriptThread->get_state()) {
3481 			case NUVIE_SCRIPT_GET_TARGET:
3482 				get_target("");
3483 				break;
3484 			}
3485 			break;
3486 		}
3487 		player->attack_select_init();
3488 		map_window->set_show_cursor(true);
3489 		break;
3490 	case PUSH_MODE:
3491 		push_start();
3492 		break;
3493 	case DROP_MODE:
3494 		drop_start();
3495 		// fall through
3496 	case EQUIP_MODE: // if this was called from moveCursorToInventory, the
3497 		// mode has now changed, so it wont be called again
3498 		moveCursorToInventory();
3499 		break;
3500 //		case DROPCOUNT_MODE:
3501 //			get_scroll_input(); /* "How many?" */
3502 //			break;
3503 	case REST_MODE:
3504 		rest_time = rest_guard = 0;
3505 		rest();
3506 		break;
3507 	case COMBAT_MODE:
3508 		toggle_combat();
3509 		mode = MOVE_MODE;
3510 		break;
3511 	default:
3512 		cancelAction(); // "what?"
3513 		return (false);
3514 	}
3515 	return (true); // ready for object/direction
3516 }
3517 
3518 /* Revert to default MOVE_MODE. (walking)
3519  * This clears visible cursors, and resets all variables used by actions.
3520  */
endAction(bool prompt)3521 void Events::endAction(bool prompt) {
3522 	if (prompt) {
3523 		scroll->display_string("\n");
3524 		scroll->display_prompt();
3525 	}
3526 
3527 	if (mode == PUSH_MODE) {
3528 		push_obj = NULL;
3529 		push_actor = NULL;
3530 		map_window->reset_mousecenter();
3531 	} else if (mode == DROP_MODE) {
3532 		drop_obj = NULL;
3533 		drop_qty = 0;
3534 		drop_from_key = false;
3535 	} else if (mode == REST_MODE) {
3536 		rest_time = rest_guard = 0;
3537 		scroll->set_using_target_cursor(false);
3538 	}
3539 	if (cursor_mode || mode == EQUIP_MODE) {
3540 		cursor_mode = false;
3541 		map_window->set_show_cursor(false);
3542 	}
3543 	if (mode == ATTACK_MODE) { // FIXME: make ATTACK_MODE use INPUT_MODE
3544 		map_window->set_show_cursor(false);
3545 	}
3546 
3547 	// Revert to the previous mode, instead of MOVE_MODE.
3548 	/* Switching from INPUT_MODE, clear state indicating the type of input
3549 	     to return, but leave returned input. Clear returned input only when
3550 	     entering INPUT_MODE, or deleting Events. */
3551 	if (/*game->user_paused() ||*/ mode == INPUT_MODE || mode == KEYINPUT_MODE) {
3552 		mode = last_mode;
3553 //        callback_target = 0;
3554 		input.get_text = false;
3555 //        input.select_from_inventory = false; // indicates cursor location
3556 		input.get_direction = false;
3557 		do_not_show_target_cursor = false;
3558 		map_window->set_show_use_cursor(false);
3559 		map_window->set_show_cursor(false);
3560 		if (!game->is_new_style())
3561 			view_manager->get_inventory_view()->set_show_cursor(false);
3562 //    game->set_mouse_pointer(0);
3563 		return;
3564 	} else if (!looking_at_spellbook)
3565 		set_mode(MOVE_MODE);
3566 
3567 	map_window->updateBlacking();
3568 }
3569 // save current mode if switching to WAIT_MODE or INPUT_MODE
set_mode(EventMode new_mode)3570 void Events::set_mode(EventMode new_mode) {
3571 	DEBUG(0,
3572 	      LEVEL_DEBUGGING,
3573 	      "new mode = %s,  mode = %s, last mode = %s\n",
3574 	      print_mode(new_mode),
3575 	      print_mode(mode),
3576 	      print_mode(last_mode));
3577 	if (new_mode == WAIT_MODE && (last_mode == EQUIP_MODE || last_mode == REST_MODE))
3578 		last_mode = mode;
3579 	else if ((new_mode == INPUT_MODE || new_mode == KEYINPUT_MODE))
3580 		last_mode = mode;
3581 	else
3582 		last_mode = MOVE_MODE;
3583 	mode = new_mode;
3584 
3585 	// re-init input state
3586 	if (mode == INPUT_MODE || mode == KEYINPUT_MODE) {
3587 		if (input.target_init) delete input.target_init;
3588 		if (input.str) delete input.str;
3589 		if (input.loc) delete input.loc;
3590 		input.target_init = 0;
3591 		input.str = 0;
3592 		input.loc = 0;
3593 		input.actor = 0;
3594 		input.obj = 0;
3595 	}
3596 }
3597 
moveCursorToInventory()3598 void Events::moveCursorToInventory() {
3599 	if (push_actor)
3600 		return;
3601 	cursor_mode = false;
3602 	if (mode == MOVE_MODE)
3603 		newAction(EQUIP_MODE);
3604 	else {
3605 		map_window->set_show_cursor(false); // hide both MapWindow cursors
3606 		map_window->set_show_use_cursor(false);
3607 		if (!game->is_new_style()) {
3608 			view_manager->get_inventory_view()->set_show_cursor(true);
3609 			view_manager->get_inventory_view()->grab_focus(); // Inventory wants keyboard input
3610 		} else {
3611 			//view_manager->open_container_view(player->get_actor());
3612 		}
3613 	}
3614 	input.select_from_inventory = true;
3615 }
3616 
3617 // Note that the cursor is not recentered here.
moveCursorToMapWindow(bool ToggleCursor)3618 void Events::moveCursorToMapWindow(bool ToggleCursor) {
3619 	input.select_from_inventory = false;
3620 	if (!game->is_new_style()) {
3621 		view_manager->get_inventory_view()->set_show_cursor(false);
3622 		view_manager->get_inventory_view()->release_focus();
3623 	} else {
3624 		//Removed due to delete issues while dragging. view_manager->close_container_view(player->get_actor());
3625 	}
3626 	if (input.get_direction) // show the correct MapWindow cursor
3627 		map_window->set_show_use_cursor(true);
3628 	else if (ToggleCursor && mode == EQUIP_MODE) {
3629 		if (game->get_command_bar()->get_selected_action() == -1)
3630 			mode = MOVE_MODE;
3631 		else {
3632 			cursor_mode = true;
3633 			map_window->centerCursor();
3634 			map_window->set_show_cursor(true);
3635 		}
3636 	} else
3637 		map_window->set_show_cursor(true);
3638 
3639 //    map_window->grab_focus(); FIXME add move() and keyhandler to MapWindow, and uncomment this
3640 }
3641 
3642 static const char eventModeStrings[][17] = {
3643 	"LOOK_MODE",
3644 	"USE_MODE",
3645 	"GET_MODE",
3646 	"MOVE_MODE",
3647 	"DROP_MODE",
3648 	"TALK_MODE", /* finding an actor to talk to */
3649 	"ATTACK_MODE",
3650 	"PUSH_MODE",
3651 	"REST_MODE",
3652 	"CAST_MODE",
3653 	"COMBAT_MODE", /* only used to cancel previous actions */
3654 	"SPELL_MODE", //direct spell casting without spell select etc.
3655 	"EQUIP_MODE",
3656 	"WAIT_MODE", /* waiting for something, optionally display prompt when finished */
3657 	"INPUT_MODE",
3658 	"MULTIUSE_MODE",
3659 	"KEYINPUT_MODE",
3660 	"SCRIPT_MODE"
3661 };
3662 
print_mode(EventMode mode_)3663 const char *Events::print_mode(EventMode mode_) {
3664 	return eventModeStrings[mode_];
3665 }
3666 
can_target_icon()3667 bool Events::can_target_icon() {
3668 	if (mode == INPUT_MODE && (last_mode == TALK_MODE
3669 	                           || last_mode == CAST_MODE || last_mode == SPELL_MODE
3670 	                           || last_mode == LOOK_MODE || move_in_inventory
3671 	                           || last_mode == USE_MODE || last_mode == REST_MODE))
3672 		return true;
3673 	else
3674 		return false;
3675 }
3676 
display_not_aboard_vehicle(bool show_prompt)3677 void Events::display_not_aboard_vehicle(bool show_prompt) {
3678 	if (player->get_actor()->get_obj_n() == OBJ_U6_INFLATED_BALLOON)
3679 		scroll->display_string("Not while aboard balloon!\n\n");
3680 	else
3681 		scroll->display_string("Not while aboard ship!\n\n");
3682 	if (show_prompt)
3683 		scroll->display_prompt();
3684 }
3685 
can_move_obj_between_actors(Obj * obj,Actor * src_actor,Actor * target_actor,bool display_name)3686 bool Events::can_move_obj_between_actors(Obj *obj,
3687 										Actor *src_actor,
3688 										Actor *target_actor,
3689 										bool display_name) { // exchange inventory
3690 	MapCoord from = src_actor->get_location();
3691 
3692 	if (target_actor) {
3693 		if (display_name) {
3694 			scroll->display_string(target_actor == src_actor ? "yourself" : target_actor->get_name());
3695 			scroll->display_string(".");
3696 		}
3697 
3698 		if (!target_actor->is_in_party() && target_actor != player->get_actor()) {
3699 			scroll->display_string("\n\nOnly within the party!");
3700 			return false;
3701 		}
3702 
3703 		if (game->using_hackmove())
3704 			return true;
3705 		if (player->is_in_vehicle()) {
3706 			display_not_aboard_vehicle();
3707 			return false;
3708 		}
3709 
3710 		if (target_actor == src_actor && obj->is_in_inventory())
3711 			return true;
3712 
3713 		MapCoord to = target_actor->get_location();
3714 
3715 		if (!map_window->tile_is_black(from.x, from.y)
3716 		        && !map_window->tile_is_black(to.x, to.y)) {
3717 			if (from.distance(to) < 5 || (map_window->get_interface() != INTERFACE_NORMAL
3718 			                              && target_actor->is_onscreen() && src_actor->is_onscreen())) {
3719 				if (game->get_script()->call_actor_get_obj(target_actor, obj))
3720 					return true;
3721 			} else
3722 				scroll->display_string("\n\nOut of range!");
3723 		} else
3724 			scroll->display_string("\n\nBlocked!"); // original said Out of Range!
3725 	} else
3726 		scroll->display_string("\n\nnobody.");
3727 
3728 	return false;
3729 }
3730 
display_move_text(Actor * target_actor,Obj * obj)3731 void Events::display_move_text(Actor *target_actor, Obj *obj) {
3732 	scroll->display_string("Move-");
3733 	scroll->display_string(obj_manager->look_obj(obj, OBJ_SHOW_PREFIX));
3734 	if (game->get_game_type() == NUVIE_GAME_MD)
3735 		scroll->display_string("\nWhere? ");
3736 	else
3737 		scroll->display_string(" To ");
3738 	scroll->display_string(target_actor->get_name());
3739 	scroll->display_string(".");
3740 }
3741 
can_get_to_actor(Actor * actor,uint16 x,uint16 y)3742 bool Events::can_get_to_actor(Actor *actor, uint16 x, uint16 y) { // need the exact tile
3743 	if (map_window->get_interface() == INTERFACE_IGNORE_BLOCK
3744 	        || player->get_actor() == actor)
3745 		return true;
3746 
3747 	LineTestResult lt;
3748 	Map *map = game->get_game_map();
3749 	MapCoord player_loc = player->get_actor()->get_location();
3750 
3751 // FIXME false obj matches can occur (should be extremly rare)
3752 	if (map->lineTest(player_loc.x, player_loc.y, x, y, player_loc.z, LT_HitUnpassable, lt)
3753 	        && (!lt.hitObj || lt.hitObj->quality != actor->get_actor_num())) // actor part
3754 		return false;
3755 
3756 	return true;
3757 }
3758 
select_view_obj(Obj * obj,Actor * actor)3759 bool Events::select_view_obj(Obj *obj, Actor *actor) {
3760 	if ((last_mode == CAST_MODE || last_mode == SPELL_MODE)
3761 	        && !magic->is_waiting_for_obj() && !magic->is_waiting_for_inventory_obj())
3762 		cancelAction();
3763 	else {
3764 		if (!obj || push_actor != NULL)
3765 			return false;
3766 		if (usecode->cannot_unready(obj) && ((last_mode == DROP_MODE && drop_obj == NULL)
3767 		                                     || (last_mode == PUSH_MODE && push_obj == NULL))) {
3768 			scroll->display_string(obj_manager->look_obj(obj, false));
3769 			scroll->display_string("\n");
3770 			usecode->ready_obj(obj, obj->get_actor_holding_obj());
3771 			endAction(true);
3772 			set_mode(MOVE_MODE);
3773 		} else
3774 			select_obj(obj, actor);
3775 	}
3776 	return true;
3777 }
3778 
close_gumps()3779 void Events::close_gumps() {
3780 //	if(game->is_new_style())
3781 	{
3782 		view_manager->close_all_gumps();
3783 	}
3784 }
3785 
dont_show_target_cursor()3786 bool Events::dont_show_target_cursor() {
3787 	if (do_not_show_target_cursor || push_actor)
3788 		return true;
3789 	else
3790 		return false;
3791 }
3792 
input_really_needs_directon()3793 bool Events::input_really_needs_directon() {
3794 	if ((input.get_direction && (map_window->get_interface() == INTERFACE_NORMAL || last_mode == CAST_MODE)) ||
3795 	        dont_show_target_cursor())
3796 		return true;
3797 	else
3798 		return false;
3799 }
3800 
shouldQuit()3801 bool shouldQuit() {
3802 	return g_engine->shouldQuit();
3803 }
3804 
3805 } // End of namespace Nuvie
3806 } // End of namespace Ultima
3807