/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef NUVIE_CORE_EVENT_H #define NUVIE_CORE_EVENT_H #include "ultima/shared/std/containers.h" #include "ultima/shared/std/string.h" #include "ultima/nuvie/misc/call_back.h" #include "ultima/nuvie/keybinding/keys_enum.h" #include "ultima/nuvie/core/obj_manager.h" namespace Ultima { namespace Nuvie { class Actor; class CallbackTarget; class Configuration; class Converse; class Book; class Game; class TimeQueue; class MapWindow; class MsgScroll; class GameClock; class Player; class ViewManager; class UseCode; class GUI; class GUI_Dialog; class Magic; class KeyBinder; class FpsCounter; class ScriptThread; #define NUVIE_INTERVAL 50 #define PUSH_FROM_PLAYER false #define PUSH_FROM_OBJECT true #define BUTTON_MASK(MB) (1 << ((int)(MB) - 1)) enum EventMode { LOOK_MODE = 0, USE_MODE, GET_MODE, MOVE_MODE, DROP_MODE, TALK_MODE, /* finding an actor to talk to */ ATTACK_MODE, PUSH_MODE, REST_MODE, /* modes before this need targets if using the command bar selected action */ CAST_MODE, COMBAT_MODE, /* only used to cancel previous actions */ SPELL_MODE, //direct spell casting without spell select etc. EQUIP_MODE, WAIT_MODE, /* waiting for something, optionally display prompt when finished */ INPUT_MODE, MULTIUSE_MODE, KEYINPUT_MODE, SCRIPT_MODE }; extern uint32 nuvieGameCounter; // type of input that event may collect and send somewhere #define EVENTINPUT_MAPCOORD 0 #define EVENTINPUT_KEY 1 #define EVENTINPUT_STRING 2 #define EVENTINPUT_OBJECT 3 #define EVENTINPUT_MAPCOORD_DIR 4 #define EVENTINPUT_SPELL_NUM 5 /** * Joystick actions mapped to dummy unused keycode values */ const Common::KeyCode FIRST_JOY = (Common::KeyCode)400; const Common::KeyCode JOY_UP = FIRST_JOY; // PS d-pad when analog is disabled. left stick when enabled const Common::KeyCode JOY_DOWN = (Common::KeyCode)(FIRST_JOY + 1); const Common::KeyCode JOY_LEFT = (Common::KeyCode)(FIRST_JOY + 2); const Common::KeyCode JOY_RIGHT = (Common::KeyCode)(FIRST_JOY + 3); const Common::KeyCode JOY_RIGHTUP = (Common::KeyCode)(FIRST_JOY + 4); const Common::KeyCode JOY_RIGHTDOWN = (Common::KeyCode)(FIRST_JOY + 5); const Common::KeyCode JOY_LEFTUP = (Common::KeyCode)(FIRST_JOY + 6); const Common::KeyCode JOY_LEFTDOWN = (Common::KeyCode)(FIRST_JOY + 7); const Common::KeyCode JOY_UP2 = (Common::KeyCode)(FIRST_JOY + 8); // PS right stick when analog is enabled const Common::KeyCode JOY_DOWN2 = (Common::KeyCode)(FIRST_JOY + 9); const Common::KeyCode JOY_LEFT2 = (Common::KeyCode)(FIRST_JOY + 10); const Common::KeyCode JOY_RIGHT2 = (Common::KeyCode)(FIRST_JOY + 11); const Common::KeyCode JOY_RIGHTUP2 = (Common::KeyCode)(FIRST_JOY + 12); const Common::KeyCode JOY_RIGHTDOWN2 = (Common::KeyCode)(FIRST_JOY + 13); const Common::KeyCode JOY_LEFTUP2 = (Common::KeyCode)(FIRST_JOY + 14); const Common::KeyCode JOY_LEFTDOWN2 = (Common::KeyCode)(FIRST_JOY + 15); const Common::KeyCode JOY_UP3 = (Common::KeyCode)(FIRST_JOY + 16); const Common::KeyCode JOY_DOWN3 = (Common::KeyCode)(FIRST_JOY + 17); const Common::KeyCode JOY_LEFT3 = (Common::KeyCode)(FIRST_JOY + 18); const Common::KeyCode JOY_RIGHT3 = (Common::KeyCode)(FIRST_JOY + 19); const Common::KeyCode JOY_RIGHTUP3 = (Common::KeyCode)(FIRST_JOY + 20); const Common::KeyCode JOY_RIGHTDOWN3 = (Common::KeyCode)(FIRST_JOY + 21); const Common::KeyCode JOY_LEFTUP3 = (Common::KeyCode)(FIRST_JOY + 22); const Common::KeyCode JOY_LEFTDOWN3 = (Common::KeyCode)(FIRST_JOY + 23); const Common::KeyCode JOY_UP4 = (Common::KeyCode)(FIRST_JOY + 24); const Common::KeyCode JOY_DOWN4 = (Common::KeyCode)(FIRST_JOY + 25); const Common::KeyCode JOY_LEFT4 = (Common::KeyCode)(FIRST_JOY + 26); const Common::KeyCode JOY_RIGHT4 = (Common::KeyCode)(FIRST_JOY + 27); const Common::KeyCode JOY_RIGHTUP4 = (Common::KeyCode)(FIRST_JOY + 28); const Common::KeyCode JOY_RIGHTDOWN4 = (Common::KeyCode)(FIRST_JOY + 29); const Common::KeyCode JOY_LEFTUP4 = (Common::KeyCode)(FIRST_JOY + 30); const Common::KeyCode JOY_LEFTDOWN4 = (Common::KeyCode)(FIRST_JOY + 31); const Common::KeyCode JOY_HAT_UP = (Common::KeyCode)(FIRST_JOY + 32); // PS d-pad when analog is enabled const Common::KeyCode JOY_HAT_DOWN = (Common::KeyCode)(FIRST_JOY + 33); const Common::KeyCode JOY_HAT_LEFT = (Common::KeyCode)(FIRST_JOY + 34); const Common::KeyCode JOY_HAT_RIGHT = (Common::KeyCode)(FIRST_JOY + 35); const Common::KeyCode JOY_HAT_RIGHTUP = (Common::KeyCode)(FIRST_JOY + 36); const Common::KeyCode JOY_HAT_RIGHTDOWN = (Common::KeyCode)(FIRST_JOY + 37); const Common::KeyCode JOY_HAT_LEFTUP = (Common::KeyCode)(FIRST_JOY + 38); const Common::KeyCode JOY_HAT_LEFTDOWN = (Common::KeyCode)(FIRST_JOY + 39); const Common::KeyCode JOY0 = (Common::KeyCode)(FIRST_JOY + 40); // PS triangle const Common::KeyCode JOY1 = (Common::KeyCode)(FIRST_JOY + 41); // PS circle const Common::KeyCode JOY2 = (Common::KeyCode)(FIRST_JOY + 42); // PS x const Common::KeyCode JOY3 = (Common::KeyCode)(FIRST_JOY + 43); // PS square const Common::KeyCode JOY4 = (Common::KeyCode)(FIRST_JOY + 44); // PS L2 const Common::KeyCode JOY5 = (Common::KeyCode)(FIRST_JOY + 45); // PS R2 const Common::KeyCode JOY6 = (Common::KeyCode)(FIRST_JOY + 46); // PS L1 const Common::KeyCode JOY7 = (Common::KeyCode)(FIRST_JOY + 47); // PS R1 const Common::KeyCode JOY8 = (Common::KeyCode)(FIRST_JOY + 48); // PS select const Common::KeyCode JOY9 = (Common::KeyCode)(FIRST_JOY + 49); // PS start const Common::KeyCode JOY10 = (Common::KeyCode)(FIRST_JOY + 50); // PS L3 (analog must be enabled) const Common::KeyCode JOY11 = (Common::KeyCode)(FIRST_JOY + 51); // PS R3 (analog must be enabled) const Common::KeyCode JOY12 = (Common::KeyCode)(FIRST_JOY + 52); const Common::KeyCode JOY13 = (Common::KeyCode)(FIRST_JOY + 53); const Common::KeyCode JOY14 = (Common::KeyCode)(FIRST_JOY + 54); const Common::KeyCode JOY15 = (Common::KeyCode)(FIRST_JOY + 55); const Common::KeyCode JOY16 = (Common::KeyCode)(FIRST_JOY + 56); const Common::KeyCode JOY17 = (Common::KeyCode)(FIRST_JOY + 57); const Common::KeyCode JOY18 = (Common::KeyCode)(FIRST_JOY + 58); const Common::KeyCode JOY19 = (Common::KeyCode)(FIRST_JOY + 59); struct EventInput_s { uint8 type; // 0=loc,1=key,2=str,3=obj,4=actor // union // { Common::KeyCode key; // last key entered, if capturing input ActionKeyType action_key_type; // last ActionKeyType entered if capturing input MapCoord *loc; // target location, or direction if relative ??? Std::string *str; // ??? // }; void set_loc(const MapCoord &c); EventInput_s() : loc(0), str(0), obj(0), actor(0), get_direction(false), get_text(false), target_init(0), select_from_inventory(false), select_range(0), key(Common::KEYCODE_INVALID), action_key_type(ActionKeyType::CANCEL_ACTION_KEY), spell_num(0), type(0) { } ~EventInput_s(); Obj *obj; // top object at loc (or object from inventory) Actor *actor; // actor at loc bool get_direction; // if true, entering directions selects a target bool get_text; // if true, the MsgScroll is polled for text input MapCoord *target_init; // where MapWindow cursor is centered when targeting bool select_from_inventory; // if true, objects from inventory will be selected (and not from the map) uint8 select_range; // limits movement of MapWindow cursor from center sint16 spell_num; }; typedef struct EventInput_s EventInput; class Events : public CallBack { friend class Magic; // FIXME private: const Configuration *config; GUI *gui; Game *game; ObjManager *obj_manager; MapWindow *map_window; MsgScroll *scroll; GameClock *clock; Player *player; Converse *converse; ViewManager *view_manager; UseCode *usecode; Magic *magic; KeyBinder *keybinder; GUI_Dialog *gamemenu_dialog; GUI_Dialog *assetviewer_dialog; Common::Event event; EventMode mode, last_mode; EventInput input; // collected/received input (of any type) // Std::vector mode_stack; // current mode is at the end of the list int ts; //timestamp for TimeLeft() method. int altCodeVal; uint16 active_alt_code; // alt-code that needs more input uint8 alt_code_input_num; // alt-code can get multiple inputs TimeQueue *time_queue, *game_time_queue; Obj *drop_obj; uint16 drop_qty; sint32 drop_x, drop_y; // only to allow pre-targeting from MapWindow, feel free to ignore this uint8 rest_time; // How many hours? uint8 rest_guard; // Who will guard? Obj *push_obj; Actor *push_actor; bool drop_from_key; bool showingDialog; bool showingQuitDialog; bool ignore_timeleft; // do not wait for NUVIE_INTERVAL bool move_in_inventory; bool in_control_cheat; bool looking_at_spellbook; bool direction_selects_target; bool _keymapperStateBeforeKEYINPUT; uint32 fps_timestamp; uint16 fps_counter; FpsCounter *fps_counter_widget; ScriptThread *scriptThread; Common::Point _mousePos; uint8 _buttonsDown; static Events *g_events; protected: inline uint32 TimeLeft(); uint16 callback(uint16 msg, CallBack *caller, void *data = nullptr) override; bool handleSDL_KEYDOWN(const Common::Event *event); const char *print_mode(EventMode mode); void try_next_attack(); public: enum MouseButton { BUTTON_NONE = 0, BUTTON_LEFT = 1, BUTTON_RIGHT = 2, BUTTON_MIDDLE = 3, MOUSE_LAST }; Events(const Configuration *cfg); ~Events() override; void clear(); bool init(ObjManager *om, MapWindow *mw, MsgScroll *ms, Player *p, Magic *mg, GameClock *gc, ViewManager *vm, UseCode *uc, GUI *g, KeyBinder *kb); GUI_Dialog *get_gamemenu_dialog() { return gamemenu_dialog; } TimeQueue *get_time_queue() { return time_queue; } TimeQueue *get_game_time_queue() { return game_time_queue; } EventMode get_mode() const { return mode; } EventMode get_last_mode() const { return last_mode; } void set_mode(EventMode new_mode); bool is_direction_selecting_targets() const { return direction_selects_target; } void set_direction_selects_target(bool val) { direction_selects_target = val; } /** * Return the mouse position */ Common::Point getMousePos() const { return _mousePos; } /** * Returns the mouse buttons states */ byte getButtonState() const { return _buttonsDown; } bool using_pickpocket_cheat; bool cursor_mode; void update_timers(); bool update(); static MouseButton whichButton(Common::EventType type); bool pollEvent(Common::Event &event); bool handleEvent(const Common::Event *event); void request_input(CallBack *caller, void *user_data = nullptr); void target_spell(); void close_spellbook(); // Prompt for input. // obsolete: // void useselect_mode(Obj *src, const char *prompt = nullptr); // deprecated // void freeselect_mode(Obj *src, const char *prompt = nullptr); // deprecated void get_scroll_input(const char *allowed = nullptr, bool can_escape = true, bool using_target_cursor = false, bool set_numbers_only_to_true = true); void get_inventory_obj(Actor *actor, bool getting_target = true); void get_spell_num(Actor *caster, Obj *spell_container); // void get_amount(); void get_direction(const char *prompt); void get_direction(const MapCoord &from, const char *prompt); void get_target(const char *prompt); void get_target(const MapCoord &init, const char *prompt); // void get_obj_from_inventory(Actor *actor, const char *prompt); void display_portrait(Actor *actor, const char *name = nullptr); // Start a new action, setting a new mode and prompting for input. bool newAction(EventMode new_mode); // void doAction(sint16 rel_x = 0, sint16 rel_y = 0); // void doAction(Obj *obj); void doAction(); void cancelAction(); void endAction(bool prompt = false); // Send input back to Events, performing an action for the current mode. bool select_obj(Obj *obj, Actor *actor = nullptr); bool select_view_obj(Obj *obj, Actor *actor); bool select_actor(Actor *actor); bool select_direction(sint16 rel_x, sint16 rel_y); bool select_target(uint16 x, uint16 y, uint8 z = 0); bool select_party_member(uint8 num); bool select_spell_num(sint16 spell_num); // bool select_obj(Obj *obj = nullptr, Actor *actor = nullptr); // bool select_obj(sint16 rel_x, sint16 rel_y); // There is no "select_text", as Events polls MsgScroll for new input. // Similarly, a "select_key" is unnecessary. The following method // starts sending all keyboard input to 'caller'. (with the CB_DATA_READY message) void key_redirect(CallBack *caller, void *user_data); void cancel_key_redirect(); /* These will be replaced in the future with an InputAction class. */ bool move(sint16 rel_x, sint16 rel_y); bool use_start(); bool use(sint16 rel_x, sint16 rel_y); bool use(const MapCoord &coord); bool use(Obj *obj); bool use(Actor *actor, uint16 x, uint16 y); bool get_start(); bool get(const MapCoord &coord); bool get(sint16 rel_x, sint16 rel_y); bool perform_get(Obj *obj, Obj *container_obj = nullptr, Actor *actor = nullptr); bool look_start(); bool lookAtCursor(bool delayed = false, uint16 x = 0, uint16 y = 0, uint8 z = 0, Obj *obj = nullptr, Actor *actor = nullptr); bool look(Obj *obj); bool look(Actor *actor); bool search(Obj *obj); bool talk_start(); bool talk_cursor(); bool talk(Actor *actor); bool talk(Obj *obj); bool perform_talk(Actor *actor); bool attack(); bool push_start(); bool pushFrom(Obj *obj); bool pushFrom(sint16 rel_x, sint16 rel_y); bool pushFrom(const MapCoord &target); bool pushTo(Obj *obj, Actor *actor); bool pushTo(sint16 rel_x, sint16 rel_y, bool push_from = PUSH_FROM_PLAYER); void solo_mode(uint32 actor_num); bool party_mode(); bool toggle_combat(); bool ready(Obj *obj, Actor *actor = nullptr); bool unready(Obj *obj); bool drop_start(); bool drop_select(Obj *obj, uint16 qty = 0); bool drop_count(uint16 qty); bool perform_drop(); void set_drop_from_key(bool closing_gumps) { drop_from_key = closing_gumps; } bool drop(Obj *obj, uint16 qty, uint16 x, uint16 y); bool drop(uint16 x, uint16 y) { return (drop(drop_obj, drop_qty, x, y)); } void set_drop_target(uint16 x, uint16 y) { drop_x = sint32(x); drop_y = sint32(y); } bool can_move_obj_between_actors(Obj *obj, Actor *src_actor, Actor *target_actor, bool display_name = false); void display_not_aboard_vehicle(bool show_prompt = true); void display_move_text(Actor *target_actor, Obj *obj); bool can_get_to_actor(const Actor *actor, uint16 x, uint16 y); bool using_control_cheat() const { return in_control_cheat; } void set_control_cheat(bool control_cheat) { in_control_cheat = control_cheat; } bool is_looking_at_spellbook() const { return looking_at_spellbook; } void set_looking_at_spellbook(bool looking) { looking_at_spellbook = looking; } bool rest(); bool rest_input(uint16 input); void cast_spell_directly(uint8 spell_num); bool can_target_icon(); // Target the actor or container tile in inventory and party view // these are both for mouse-using convenience void walk_to_mouse_cursor(uint32 mx, uint32 my); void multiuse(uint16 wx, uint16 wy); void alt_code(int c); void alt_code_input(const char *in); void clear_alt_code() { altCodeVal = 0; } void toggleAltCodeMode(bool enable); void appendAltCode(int code); bool alt_code_teleport(const char *location_string); void alt_code_infostring(); void alt_code_teleport_menu(uint32 selection); bool alt_code_teleport_to_person(uint32 npc); void wait(); void set_ignore_timeleft(bool newsetting) { ignore_timeleft = newsetting; } EventInput *get_input() { return &input; } // These cursor methods are use to make sure Events knows where the cursor is // when objects are selected with ENTER. (since MapWindow and InventoryView // may each independently show/hide their own cursors) void moveCursorToMapWindow(bool ToggleCursor = false); void moveCursorToInventory(); void toggleFpsDisplay(); void close_gumps(); bool do_not_show_target_cursor; bool dont_show_target_cursor() const; bool input_really_needs_directon() const; void quitDialog(); void gameMenuDialog(); void assetViewer(); bool actor_exists(const Actor *a) const; /* FIXME: Some of the above (action) functions can be removed from public, so that we don't need to check for WAIT mode in all of them. */ /** * Gets a reference to the events manager */ static Events *get() { return g_events; } }; extern bool shouldQuit(); } // End of namespace Nuvie } // End of namespace Ultima #endif