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