diff --git a/doc/map_syntax.dox b/doc/map_syntax.dox index 97c2f7313..34cd2ea29 100644 --- a/doc/map_syntax.dox +++ b/doc/map_syntax.dox @@ -336,7 +336,7 @@ the interaction will be started only if the hero touches the south face of the e behavior describes what happens when the player presses the action key near this entity. There are three possible options: -- dialog#XXX: starts a dialog with first message XXX +- dialog#XXX: starts the dialog with id XXX - map: calls the map script (event_hero_interaction) - item#XXX calls the script of the item XXX (event_hero_interaction) @@ -462,7 +462,7 @@ A shop item is a treasure one can buy in a shop in exchange for money. Syntax of a shop item: @verbatim -16 layer x y entity_name treasure_name treasure_variant treasure_savegame_variable price message_id +16 layer x y entity_name treasure_name treasure_variant treasure_savegame_variable price dialog_id @endverbatim treasure_name, treasure_variant and treasure_savegame_variable @@ -476,8 +476,8 @@ and is not removed from the map. price is the number of rupees to pay to buy the item. -message_id is the id of the message to show when the player looks at the item. -The message describes the item. It is automatically followed by a dialog that asks to the player +dialog_id is the id of the dialog to show when the player looks at the item. +The dialog describes the item. It is automatically followed by a dialog that asks to the player if he wants to buy the item. @section conveyor_belt Conveyor belt (17) diff --git a/include/DialogBox.h b/include/DialogBox.h index b15378795..b2455e215 100644 --- a/include/DialogBox.h +++ b/include/DialogBox.h @@ -79,10 +79,9 @@ class DialogBox { // current message KeysEffect::ActionKeyEffect action_key_effect_saved; /**< effect of the action key before starting the message sequence */ KeysEffect::SwordKeyEffect sword_key_effect_saved; /**< effect of the sword key before starting the message sequence */ - MessageId first_message_id; /**< id of the first message of the current sequence */ - Message *current_message; /**< the message currently shown (NULL if the dialog box is disabled) */ - MessageId current_message_id; /**< id of the message currently shown */ - std::map variables; /**< variables to display if the next messages */ + std::string dialog_id; /**< id of the current dialog */ + Message* current_message; /**< the message currently shown (NULL if the dialog box is disabled) */ + std::map variables; /**< variables to display in dialogs */ Script* issuer_script; /**< the script (if any) that started the current sequence of messages */ Speed speed; /**< speed of the text */ @@ -90,7 +89,7 @@ class DialogBox { int icon_number; /* index of the 16*16 icon displayed, or -1 if there is no icon */ bool skipped; /* true if the user has skipped the dialog */ int last_answer; /**< the answer selected in the last message sequence: 0 for the first one, 1 for the second one, - * -1 if there was no question */ + * -1 if there was no question */ // graphics Surface *dialog_surface; /**< surface where the dialog is drawn*/ @@ -106,7 +105,7 @@ class DialogBox { Rectangle icon_dst_position; /**< destination rectangle of the icon */ void set_vertical_position(VerticalPosition vertical_position); - void show_message(const MessageId &message_id); + void show_message(); void show_next_message(); void close(); @@ -126,8 +125,8 @@ class DialogBox { bool is_enabled(); // current message - void start_dialog(const MessageId &first_message_id, Script *issuer_script = NULL, - VerticalPosition vertical_position = POSITION_AUTO); + void start_dialog(const std::string& dialog_id, Script *issuer_script = NULL, + VerticalPosition vertical_position = POSITION_AUTO); Speed get_speed(); void set_speed(Speed speed); SkipMode get_skip_mode(); @@ -135,13 +134,13 @@ class DialogBox { int get_icon_number(); void set_icon_number(int icon_number); bool is_letter_sound_enabled(); - void set_variable(const MessageId &first_message_id, const std::string &value); - void set_variable(const MessageId &first_message_id, int value); + void set_variable(const std::string& dialog_id, const std::string &value); + void set_variable(const std::string& dialog_id, int value); const std::string& get_variable(); int get_last_answer(); void set_last_answer(int answer); void key_pressed(GameControls::GameKey key); - MessageId get_first_message_id(); + const std::string& get_dialog_id(); bool is_finished(); bool was_skipped(); void show_all_now(); diff --git a/include/Game.h b/include/Game.h index 79650192c..21007bb30 100755 --- a/include/Game.h +++ b/include/Game.h @@ -118,7 +118,7 @@ class Game: public Screen { // current game state bool is_paused(); - bool is_showing_message(); + bool is_showing_dialog(); bool is_playing_transition(); bool is_showing_gameover(); bool is_suspended(); // true if at least one of the three functions above returns true diff --git a/include/Message.h b/include/Message.h index 80b38c728..63c6c29e7 100644 --- a/include/Message.h +++ b/include/Message.h @@ -21,54 +21,44 @@ #include "DialogBox.h" /** - * @brief A message displayed in a dialog box. + * @brief Lines of text displayed in a dialog box. * - * This class parses the message from a data file and displays it in a dialog box. + * This class displays three lines of text in a dialog box. * A message is usually part of a sequence of several messages called a dialog. */ class Message { private: - // the dialog box where this message is displayed - DialogBox *dialog_box; - // properties of the message - std::string lines[3]; // the 3 lines of the message - TextSurface *text_surfaces[3]; - bool question; // is this message a question? - MessageId next_message_id; // id of the next message (or an empty string if this is the last message) - MessageId next_message_id_2; - - int x; - int y; - - void parse(MessageId message_id); - void set_variable(const std::string &value); - - // current state of the display + DialogBox& dialog_box; /**< the dialog box where this message is displayed */ + std::string lines[3]; /**< the 3 lines of text of the message */ + TextSurface* text_surfaces[3]; /**< the 3 corresponding text surfaces */ + bool question; /**< is this message a question? */ + bool last; /**< is this message the last one of the dialog? */ - unsigned int line_index; // line currently displayed (0 to 2) - unsigned int char_index; // index of the next character to show - uint32_t delay; - uint32_t next_char_date; - bool show_all; + // current state of displaying - uint32_t next_sound_date; + unsigned int line_index; /**< line currently displayed (0 to 2) */ + unsigned int char_index; /**< index of the next character to show */ + uint32_t delay; /**< delay between two characters in milliseconds */ + uint32_t next_char_date; /**< when the next character is displayed */ + uint32_t next_sound_date; /**< date of the next character sound */ + bool show_all; /**< makes all text be displayed now */ void update_char_delay(); void add_character(); + void set_variable(const std::string& value); public: // creation and destruction - Message(DialogBox *dialog_box, MessageId message_id, int x, int y); + Message(DialogBox& dialog_box, const std::string& dialog_id, int x, int y); ~Message(); // message properties bool is_question(); - MessageId get_next_message_id(); // message current state bool is_finished(); diff --git a/include/Types.h b/include/Types.h index 7b34635bd..7c541408e 100644 --- a/include/Types.h +++ b/include/Types.h @@ -60,11 +60,6 @@ typedef std::string SoundId; */ typedef std::string SpriteAnimationSetId; -/** - * @brief Type of the id of messages. - */ -typedef std::string MessageId; - // declaration of all classes to avoid dependencies between the header files // main classes diff --git a/include/entities/Door.h b/include/entities/Door.h index 1a419bec7..607a25578 100644 --- a/include/entities/Door.h +++ b/include/entities/Door.h @@ -47,8 +47,8 @@ class Door: public Detector { private: - static const std::string animations[]; /**< sprite animation name of each subtype */ - static const MessageId key_required_message_ids[]; /**< id of the message shown for each subtype */ + static const std::string animations[]; /**< sprite animation name of each subtype */ + static const std::string key_required_dialog_ids[]; /**< id of the dialog shown for each subtype */ // properties Subtype subtype; /**< subtype of door */ diff --git a/include/entities/NPC.h b/include/entities/NPC.h index 228c68193..3f97bceb2 100644 --- a/include/entities/NPC.h +++ b/include/entities/NPC.h @@ -67,7 +67,7 @@ class NPC: public Detector { Subtype subtype; /**< subtpype of NPC */ Behavior behavior; /**< type of action done when the player interacts with this entity */ - MessageId message_to_show; /**< message to show when an interaction occurs, or an empty string */ + std::string dialog_to_show; /**< dialog to show when an interaction occurs, or an empty string */ Script* script_to_call; /**< map script or item script to call when an interaction occurs, or NULL */ void initialize_sprite(SpriteAnimationSetId& sprite_name, int initial_direction); @@ -75,8 +75,9 @@ class NPC: public Detector { public: - NPC(Game& game, const std::string& name, Layer layer, int x, int y, Subtype subtype, - SpriteAnimationSetId sprite_name, int initial_direction, const std::string& behavior_string); + NPC(Game& game, const std::string& name, Layer layer, int x, int y, + Subtype subtype, SpriteAnimationSetId sprite_name, + int initial_direction, const std::string& behavior_string); ~NPC(); static CreationFunction parse; diff --git a/include/entities/ShopItem.h b/include/entities/ShopItem.h index c91c04043..f7af7e873 100644 --- a/include/entities/ShopItem.h +++ b/include/entities/ShopItem.h @@ -36,7 +36,7 @@ class ShopItem: public Detector { // data Treasure treasure; /**< the treasure the player can buy */ int price; /**< the treasure's price in rupees */ - MessageId message_id; /**< id of the message describing the shop item */ + std::string dialog_id; /**< id of the dialog describing the shop item */ // displaying TextSurface *price_digits; /**< the digits that show the price */ @@ -46,14 +46,14 @@ class ShopItem: public Detector { bool is_looking_item; /**< indicates that the message describing the item is being shown */ bool is_asking_question; /**< indicates that the buy question is being shown */ - ShopItem(const std::string &name, Layer layer, int x, int y, - const Treasure &treasure, int price, const MessageId &message_id); + ShopItem(const std::string& name, Layer layer, int x, int y, + const Treasure& treasure, int price, const std::string& dialog_id); public: ~ShopItem(); - static ShopItem* create(Game &game, const std::string &name, Layer layer, int x, int y, - const Treasure &treasure, int price, const MessageId &message_id); + static ShopItem* create(Game& game, const std::string& name, Layer layer, int x, int y, + const Treasure& treasure, int price, const std::string& dialog_id); static CreationFunction parse; EntityType get_type(); diff --git a/include/hud/HUD.h b/include/hud/HUD.h index 04849037f..50effc5d9 100644 --- a/include/hud/HUD.h +++ b/include/hud/HUD.h @@ -31,7 +31,7 @@ class HUD { int nb_elements; HudElement *elements[16]; - bool showing_message; + bool showing_dialog; void update_blinking(); diff --git a/include/lua/Script.h b/include/lua/Script.h index 1fcdd8a0a..0d4c791b0 100644 --- a/include/lua/Script.h +++ b/include/lua/Script.h @@ -383,10 +383,11 @@ class Script { bool has_played_music(); void event_map_changed(Map &map); - void event_dialog_started(const MessageId &message_id); - void event_dialog_finished(const MessageId &first_message_id, int answer); + void event_dialog_started(const std::string& dialog_id); + void event_dialog_finished(const std::string& dialog_id, int answer); void event_npc_interaction(const std::string& npc_name); - bool event_npc_interaction_item(const std::string& npc_name, const std::string& item_name, int variant); + bool event_npc_interaction_item(const std::string& npc_name, + const std::string& item_name, int variant); void event_npc_collision_fire(const std::string &npc_name); void do_callback(int callback_ref); diff --git a/src/DebugKeys.cpp b/src/DebugKeys.cpp index 5f5739e19..27ee0bc9b 100644 --- a/src/DebugKeys.cpp +++ b/src/DebugKeys.cpp @@ -192,7 +192,7 @@ void DebugKeys::update() { #ifdef SOLARUS_DEBUG_KEYS if (InputEvent::is_shift_down()) { - if (game != NULL && game->is_showing_message()) { + if (game != NULL && game->is_showing_dialog()) { game->get_dialog_box().show_all_now(); } } diff --git a/src/DialogBox.cpp b/src/DialogBox.cpp index 117465bee..9f3a0b5e6 100644 --- a/src/DialogBox.cpp +++ b/src/DialogBox.cpp @@ -34,7 +34,8 @@ * @param game the game this dialog box belongs to */ DialogBox::DialogBox(Game &game): - game(game), current_message(NULL) { + game(game), + current_message(NULL) { // initialize the surface dialog_surface = new Surface(320, 240); @@ -187,46 +188,48 @@ bool DialogBox::is_letter_sound_enabled() { } /** - * @brief Specifies the value of a variable that will occur in a future message. + * @brief Specifies the value of a variable that will occur in a dialog. * - * A value is expected in a message when the '$v' sequence is read. - * You can specify only one variable at the same time per message sequence. - * If a variable was already specified for this sequence of messages, it is replaced. + * A value is expected in a dialog when the '$v' sequence is read. + * You can specify only one variable at the same time per dialog. + * If a variable was already specified for this dialog, it is replaced. * - * @param first_message_id id of the first message of the sequence where this value will appear + * @param dialog_id id of the dialog where this value will appear * @param value the value to add */ -void DialogBox::set_variable(const MessageId &first_message_id, const std::string &value) { - variables[first_message_id] = value; +void DialogBox::set_variable(const std::string& dialog_id, const std::string& value) { + variables[dialog_id] = value; } /** - * @brief Same thing as set_variable(MessageId, string) but with an integer parameter. + * @brief Same thing as set_variable(string, string) but with an integer parameter. * * This function just converts the integer value to a string * add calls the other function. * - * @param first_message_id id of the first message of the sequence where this value will appear + * @param dialog id id of the dialog where this value will appear * @param value the value to set */ -void DialogBox::set_variable(const MessageId &first_message_id, int value) { +void DialogBox::set_variable(const std::string& dialog_id, int value) { + std::ostringstream oss; oss << value; - set_variable(first_message_id, oss.str()); + set_variable(dialog_id, oss.str()); } /** * @brief Returns the variable specified by a previous - * call to set_variable(), for the current sequence of messages. + * call to set_variable(), for the current dialog. * This function is called by * the current message when it reads the '$v' sequence. * @return the value of the variable */ const std::string& DialogBox::get_variable() { - const std::string &value = variables[first_message_id]; + const std::string& value = variables[dialog_id]; - Debug::check_assertion(value.size() > 0, StringConcat() << "Missing variable in message '" << current_message_id << "'"); + Debug::check_assertion(value.size() > 0, StringConcat() + << "Missing variable in dialog '" << dialog_id << "'"); return value; } @@ -252,22 +255,23 @@ void DialogBox::set_last_answer(int answer) { } /** - * @brief Starts a sequence of messages. + * @brief Starts a dialog. * * The dialog box should not be enabled already when you call this function. * - * @param first_message_id id of the first message of the sequence + * @param dialog_id of the dialog * @param issuer_script the script that issued the request to start a dialog * (will be notified when the dialog finishes), or NULL * @param vertical_position vertical position where to display the dialog box (default: auto) */ -void DialogBox::start_dialog(const MessageId &first_message_id, Script *issuer_script, +void DialogBox::start_dialog(const std::string& dialog_id, Script* issuer_script, VerticalPosition vertical_position) { - Debug::check_assertion(!is_enabled(), StringConcat() << "Cannot start message sequence '" << first_message_id << ": the dialog box is already enabled"); + Debug::check_assertion(!is_enabled(), StringConcat() << + "Cannot start dialog '" << dialog_id << ": the dialog box is already enabled"); // save the action and sword keys - KeysEffect &keys_effect = game.get_keys_effect(); + KeysEffect& keys_effect = game.get_keys_effect(); action_key_effect_saved = keys_effect.get_action_key_effect(); sword_key_effect_saved = keys_effect.get_sword_key_effect(); @@ -277,27 +281,26 @@ void DialogBox::start_dialog(const MessageId &first_message_id, Script *issuer_s set_skip_mode(SKIP_NONE); set_icon_number(-1); this->skipped = false; - this->first_message_id = first_message_id; - show_message(first_message_id); + this->dialog_id = dialog_id; + show_message(); // notify the scripts - game.get_map_script().event_dialog_started(first_message_id); + game.get_map_script().event_dialog_started(dialog_id); this->issuer_script = issuer_script; if (issuer_script != NULL) { - issuer_script->event_dialog_started(first_message_id); + issuer_script->event_dialog_started(dialog_id); } } /** * @brief Shows a new message in the dialog box. - * @param message_id id of the message to create (must be a valid id) */ -void DialogBox::show_message(const MessageId &message_id) { +void DialogBox::show_message() { // create the message delete current_message; - current_message = new Message(this, message_id, box_dst_position.get_x(), box_dst_position.get_y()); - current_message_id = message_id; + current_message = new Message(*this, dialog_id, + box_dst_position.get_x(), box_dst_position.get_y()); if (current_message->is_question()) { set_last_answer(0); @@ -326,10 +329,10 @@ void DialogBox::show_message(const MessageId &message_id) { */ void DialogBox::show_next_message() { - MessageId next_message_id = current_message->get_next_message_id(); + const std::string next_dialog_id; // TODO - if (next_message_id != "" && next_message_id != "_unknown") { - show_message(next_message_id); + if (next_dialog_id != "" && next_dialog_id != "_unknown") { + show_message(); } else { close(); @@ -351,14 +354,14 @@ void DialogBox::close() { keys_effect.set_sword_key_effect(sword_key_effect_saved); // notify the script if necessary - if (!skipped && first_message_id[0] != '_') { // FIXME: remove the '_' restriction + if (!skipped && dialog_id[0] != '_') { // FIXME: remove the '_' restriction // a dialog of the quest was just finished: notify the scripts - Script &map_script = game.get_map_script(); - map_script.event_dialog_finished(first_message_id, last_answer); + Script& map_script = game.get_map_script(); + map_script.event_dialog_finished(dialog_id, last_answer); if (issuer_script != NULL && issuer_script != &map_script) { // also notify the issuer script if different - issuer_script->event_dialog_finished(first_message_id, last_answer); + issuer_script->event_dialog_finished(dialog_id, last_answer); } } } @@ -452,11 +455,11 @@ void DialogBox::show_all_now() { } /** - * @brief Returns the id of the first message shown in the current dialog box sequence. - * @return the id of the first message shown + * @brief Returns the id of the current dialog. + * @return the id of the dialog currently shown */ -MessageId DialogBox::get_first_message_id() { - return first_message_id; +const std::string& DialogBox::get_dialog_id() { + return dialog_id; } /** @@ -503,8 +506,8 @@ void DialogBox::update() { KeysEffect &keys_effect = game.get_keys_effect(); if (!end_message_sprite->is_animation_started()) { - MessageId next_message_id = current_message->get_next_message_id(); - if (next_message_id != "" || current_message->is_question()) { + const std::string next_dialog_id; // TODO + if (next_dialog_id != "" || current_message->is_question()) { end_message_sprite->set_current_animation("next"); keys_effect.set_action_key_effect(KeysEffect::ACTION_KEY_NEXT); } diff --git a/src/Game.cpp b/src/Game.cpp index 8f326bb95..592b05c93 100755 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -192,7 +192,7 @@ void Game::key_pressed(GameControls::GameKey key) { } // is a message being shown? - else if (is_showing_message()) { + else if (is_showing_dialog()) { dialog_box->key_pressed(key); } @@ -376,7 +376,7 @@ void Game::update_transitions() { void Game::update_keys_effect() { // when the game is paused or a dialog box is shown, the sword key is not the usual one - if (is_paused() || is_showing_message()) { + if (is_paused() || is_showing_dialog()) { return; // if the game is interrupted for some other reason (e.g. a transition), let the normal sword icon } @@ -438,7 +438,7 @@ void Game::display(Surface *screen_surface) { } // display the dialog box if any - if (is_showing_message()) { + if (is_showing_dialog()) { dialog_box->display(screen_surface); } } @@ -598,15 +598,15 @@ bool Game::is_playing_transition() { * @return true if the game is suspended */ bool Game::is_suspended() { - return current_map == NULL || is_paused() || is_showing_message() || + return current_map == NULL || is_paused() || is_showing_dialog() || is_playing_transition() || is_showing_gameover() || !current_map->is_camera_fixed_on_hero(); } /** - * @brief Returns whether we are showing a message. - * @return true if a message is being shown. + * @brief Returns whether we are showing a dialog box. + * @return true if a dialog box is being shown */ -bool Game::is_showing_message() { +bool Game::is_showing_dialog() { return dialog_box->is_enabled(); } diff --git a/src/Message.cpp b/src/Message.cpp index ece67d65e..6cc5e0154 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -41,14 +41,11 @@ static const uint32_t char_delays[3] = { * @param x x position of the dialog box * @param y y position of the dialog box */ -Message::Message(DialogBox *dialog_box, MessageId message_id, int x, int y): - dialog_box(dialog_box), x(x), y(y) { - - // parse the message - parse(message_id); +Message::Message(DialogBox& dialog_box, const std::string& dialog_id, int x, int y): + dialog_box(dialog_box) { // create the text surfaces - int text_x = x + ((dialog_box->get_icon_number() == -1) ? 16 : 48); + int text_x = x + ((dialog_box.get_icon_number() == -1) ? 16 : 48); int text_y = y - 1; for (int i = 0; i < 3; i++) { text_y += 13; @@ -79,69 +76,6 @@ Message::~Message() { } } -/** - * @brief Reads the message from the data file and initializes - * the fields accordingly. - * @param message_id id of the message - */ -void Message::parse(MessageId message_id) { - - // open the file - std::string file_name = "text/dialogs.dat"; - - // parse the message - IniFile ini_file(file_name, IniFile::READ_LANGUAGE); - - Debug::check_assertion(ini_file.has_group(message_id), StringConcat() << "The message '" << message_id << "' does not exist"); - ini_file.set_group(message_id); - - // text - lines[0] = ini_file.get_string_value("line1", ""); - lines[1] = ini_file.get_string_value("line2", ""); - lines[2] = ini_file.get_string_value("line3", ""); - for (int i = 0; i < 3; i++) { - int size = lines[i].size(); - if (lines[i][0] == '"') { - lines[i] = lines[i].substr(1); - size--; - } - if (lines[i][size - 1] == '"') { - lines[i] = lines[i].substr(0, size - 1); - } - } - - // icon - int icon_number = ini_file.get_integer_value("icon", -2); - if (icon_number != -2) { - // if an icon number is specified (even -1) - dialog_box->set_icon_number(icon_number); - } - - // next message - next_message_id = ini_file.get_string_value("next", ""); - next_message_id_2 = ini_file.get_string_value("next2", ""); - - // question - question = ini_file.get_boolean_value("question", false); - - // skip mode - const std::string &skip_mode_text = ini_file.get_string_value("skip", ""); - - if (skip_mode_text != "") { // a skip mode is specified - DialogBox::SkipMode skip_mode; - if (skip_mode_text == "current") { - skip_mode = DialogBox::SKIP_CURRENT; - } - else if (skip_mode_text == "all") { - skip_mode = question ? DialogBox::SKIP_CURRENT : DialogBox::SKIP_ALL; - } - else { - skip_mode = DialogBox::SKIP_NONE; - } - dialog_box->set_skip_mode(skip_mode); - } -} - /** * @brief Returns whether this message is a question. * @return true if the message is a question @@ -150,22 +84,6 @@ bool Message::is_question() { return question; } -/** - * @brief Returns the id of the next message to display. - * - * If this is the last message, an empty string is returned. - * - * @return the id of the message to display when this one is over - */ -MessageId Message::get_next_message_id() { - - if (question && dialog_box->get_last_answer() == 1) { - return next_message_id_2; - } - - return next_message_id; -} - /** * @brief Returns whether the message is now completely displayed. * @return true if the message is over @@ -178,6 +96,7 @@ bool Message::is_finished() { * @brief Shows all characters of the message now. */ void Message::show_all_now() { + show_all = true; update_char_delay(); } @@ -190,7 +109,7 @@ void Message::show_all_now() { void Message::update_char_delay() { if (!show_all) { - delay = char_delays[dialog_box->get_speed()]; + delay = char_delays[dialog_box.get_speed()]; } else { delay = 0; @@ -233,24 +152,24 @@ void Message::add_character() { case '1': // slow - dialog_box->set_speed(DialogBox::SPEED_SLOW); + dialog_box.set_speed(DialogBox::SPEED_SLOW); update_char_delay(); break; case '2': // medium - dialog_box->set_speed(DialogBox::SPEED_MEDIUM); + dialog_box.set_speed(DialogBox::SPEED_MEDIUM); update_char_delay(); break; case '3': // fast - dialog_box->set_speed(DialogBox::SPEED_FAST); + dialog_box.set_speed(DialogBox::SPEED_FAST); update_char_delay(); break; case 'v': - set_variable(dialog_box->get_variable()); + set_variable(dialog_box.get_variable()); break; default: @@ -277,7 +196,7 @@ void Message::add_character() { } uint32_t now = System::now(); - if (now >= next_sound_date && dialog_box->is_letter_sound_enabled()) { + if (now >= next_sound_date && dialog_box.is_letter_sound_enabled()) { Sound::play("message_letter"); next_sound_date = now + 100; } @@ -288,7 +207,8 @@ void Message::add_character() { * @brief Replaces the first occurence of "$v" by the specified value. * @param value the value to set */ -void Message::set_variable(const std::string &value) { +void Message::set_variable(const std::string& value) { + char_index -= 2; lines[line_index] = lines[line_index].replace(char_index, 2, value); } diff --git a/src/entities/Door.cpp b/src/entities/Door.cpp index b91acbd93..d308e49c4 100644 --- a/src/entities/Door.cpp +++ b/src/entities/Door.cpp @@ -38,7 +38,7 @@ const std::string Door::animations[] = { "closed", "small_key", "small_key_block", "big_key", "boss_key", "weak", "very_weak", "", "weak_block" }; -const MessageId Door::key_required_message_ids[] = { +const std::string Door::key_required_dialog_ids[] = { "", "_small_key_required", "_small_key_required", "_big_key_required", "_boss_key_required", "", "", "", "" }; @@ -53,7 +53,7 @@ const MessageId Door::key_required_message_ids[] = { * @param savegame_variable variable where the door's state is saved * (can be -1 for the subtype CLOSED) */ -Door::Door(const std::string &name, Layer layer, int x, int y, +Door::Door(const std::string& name, Layer layer, int x, int y, int direction, Subtype subtype, int savegame_variable): Detector(COLLISION_FACING_POINT | COLLISION_SPRITE, name, layer, x, y, 16, 16), subtype(subtype), @@ -393,7 +393,7 @@ void Door::action_key_pressed() { } else { Sound::play("wrong"); - get_dialog_box().start_dialog(key_required_message_ids[subtype]); + get_dialog_box().start_dialog(key_required_dialog_ids[subtype]); } } } diff --git a/src/entities/NPC.cpp b/src/entities/NPC.cpp index d7c413035..dad83dac9 100644 --- a/src/entities/NPC.cpp +++ b/src/entities/NPC.cpp @@ -44,7 +44,7 @@ * @param direction for a generalized NPC: direction for which the interactions are allowed * (0 to 4, or -1 for any direction), for a usual NPC: initial direction of the NPC's sprite * @param behavior_string indicates what happens when the hero interacts with this NPC: - * "message#XXX" to start the dialog XXX, "map" to call the map script + * "dialog#XXX" to start the dialog XXX, "map" to call the map script * (with an event_hero_interaction() call) or "item#XXX" to call the script * of item XXX (with an event_hero_interaction() call) */ @@ -53,7 +53,7 @@ NPC::NPC(Game& game, const std::string& name, Layer layer, int x, int y, int direction, const std::string& behavior_string): Detector(COLLISION_FACING_POINT | COLLISION_RECTANGLE, name, layer, x, y, 0, 0), subtype(subtype), - message_to_show(""), + dialog_to_show(""), script_to_call(NULL) { initialize_sprite(sprite_name, direction); @@ -73,7 +73,7 @@ NPC::NPC(Game& game, const std::string& name, Layer layer, int x, int y, } else if (behavior_string.substr(0, 7) == "dialog#") { behavior = BEHAVIOR_DIALOG; - message_to_show = behavior_string.substr(7); + dialog_to_show = behavior_string.substr(7); } else { Debug::die(StringConcat() << "Invalid behavior string for interactive entity '" << name @@ -282,7 +282,7 @@ void NPC::action_key_pressed() { if (effect != KeysEffect::ACTION_KEY_LIFT) { // start the normal behavior if (behavior == BEHAVIOR_DIALOG) { - get_dialog_box().start_dialog(message_to_show); + get_dialog_box().start_dialog(dialog_to_show); } else { call_script_hero_interaction(); diff --git a/src/entities/PickableItem.cpp b/src/entities/PickableItem.cpp index cb2d57815..29f2c9d5e 100644 --- a/src/entities/PickableItem.cpp +++ b/src/entities/PickableItem.cpp @@ -282,7 +282,7 @@ void PickableItem::notify_collision(MapEntity &entity_overlapping, CollisionMode if (entity_overlapping.is_hero() && can_be_picked - && !get_game().is_showing_message()) { + && !get_game().is_showing_dialog()) { remove_from_map(); give_item_to_player(); } diff --git a/src/entities/ShopItem.cpp b/src/entities/ShopItem.cpp index 61ece802e..2049e6ffb 100644 --- a/src/entities/ShopItem.cpp +++ b/src/entities/ShopItem.cpp @@ -40,13 +40,16 @@ * @param y y coordinate of the entity to create * @param treasure the treasure that the hero can buy (will be deleted automatically) * @param price the treasure's price in rupees - * @param message_id id of the message describing the item when the player watches it + * @param dialog_id id of the dialog describing the item when the player watches it */ -ShopItem::ShopItem(const std::string &name, Layer layer, int x, int y, - const Treasure &treasure, int price, const MessageId &message_id): +ShopItem::ShopItem(const std::string& name, Layer layer, int x, int y, + const Treasure& treasure, int price, const std::string& dialog_id): Detector(COLLISION_FACING_POINT, name, layer, x, y, 32, 32), - treasure(treasure), price(price), message_id(message_id), - is_looking_item(false), is_asking_question(false) { + treasure(treasure), + price(price), + dialog_id(dialog_id), + is_looking_item(false), + is_asking_question(false) { std::ostringstream oss; oss << price; @@ -61,6 +64,7 @@ ShopItem::ShopItem(const std::string &name, Layer layer, int x, int y, * @brief Destructor. */ ShopItem::~ShopItem() { + delete price_digits; delete rupee_icon_sprite; } @@ -77,22 +81,22 @@ ShopItem::~ShopItem() { * @param y y coordinate of the entity * @return the instance created */ -MapEntity* ShopItem::parse(Game &game, std::istream &is, Layer layer, int x, int y) { +MapEntity* ShopItem::parse(Game& game, std::istream& is, Layer layer, int x, int y) { std::string name, treasure_name; int treasure_variant, treasure_savegame_variable, price; - MessageId message_id; + std::string dialog_id; FileTools::read(is, name); FileTools::read(is, treasure_name); FileTools::read(is, treasure_variant); FileTools::read(is, treasure_savegame_variable); FileTools::read(is, price); - FileTools::read(is, message_id); + FileTools::read(is, dialog_id); return create(game, name, Layer(layer), x, y, Treasure(game, treasure_name, treasure_variant, treasure_savegame_variable), - price, message_id); + price, dialog_id); } /** @@ -104,18 +108,18 @@ MapEntity* ShopItem::parse(Game &game, std::istream &is, Layer layer, int x, int * @param y y coordinate of the entity to create * @param treasure the treasure that the hero can buy * @param price the treasure's price in rupees - * @param message_id id of the message describing the item when the player watches it + * @param dialog_id id of the dialog describing the item when the player watches it * @return the shop item created, or NULL if it is already bought */ -ShopItem* ShopItem::create(Game &game, const std::string &name, Layer layer, int x, int y, - const Treasure &treasure, int price, const MessageId &message_id) { +ShopItem* ShopItem::create(Game& game, const std::string& name, Layer layer, int x, int y, + const Treasure &treasure, int price, const std::string& dialog_id) { // see if the item is not already bought if (treasure.is_found()) { return NULL; } - return new ShopItem(name, layer, x, y, treasure, price, message_id); + return new ShopItem(name, layer, x, y, treasure, price, dialog_id); } /** @@ -161,7 +165,7 @@ void ShopItem::notify_collision(MapEntity &entity_overlapping, CollisionMode col Hero &hero = (Hero&) entity_overlapping; if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE - && hero.is_free()) { + && hero.is_free()) { // we show the 'look' icon get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); @@ -181,7 +185,7 @@ void ShopItem::action_key_pressed() { if (get_hero().is_free() && get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_LOOK) { - get_dialog_box().start_dialog(message_id); + get_dialog_box().start_dialog(dialog_id); is_looking_item = true; } } @@ -191,16 +195,16 @@ void ShopItem::action_key_pressed() { */ void ShopItem::update() { - if (is_looking_item && !get_game().is_showing_message()) { + if (is_looking_item && !get_game().is_showing_dialog()) { // the description message has just finished - std::string question_message_id = "_shop.question"; - get_dialog_box().start_dialog(question_message_id); - get_dialog_box().set_variable(question_message_id, price); + const std::string question_dialog_id = "_shop.question"; + get_dialog_box().start_dialog(question_dialog_id); + get_dialog_box().set_variable(question_dialog_id, price); is_asking_question = true; is_looking_item = false; } - else if (is_asking_question && !get_game().is_showing_message()) { + else if (is_asking_question && !get_game().is_showing_dialog()) { // the question has just finished is_asking_question = false; @@ -209,17 +213,17 @@ void ShopItem::update() { if (answer == 0) { // the player wants to buy the item - Equipment &equipment = get_equipment(); + Equipment& equipment = get_equipment(); if (equipment.get_money() < price) { - // not enough rupees - Sound::play("wrong"); - get_dialog_box().start_dialog("_shop.not_enough_money"); + // not enough rupees + Sound::play("wrong"); + get_dialog_box().start_dialog("_shop.not_enough_money"); } else if (equipment.has_item_maximum(treasure.get_item_name())) { - // the player already has the maximum amount of this item - Sound::play("wrong"); - get_dialog_box().start_dialog("_shop.amount_full"); + // the player already has the maximum amount of this item + Sound::play("wrong"); + get_dialog_box().start_dialog("_shop.amount_full"); } else { diff --git a/src/hero/TreasureState.cpp b/src/hero/TreasureState.cpp index 7c199a2cd..77b75fdaf 100644 --- a/src/hero/TreasureState.cpp +++ b/src/hero/TreasureState.cpp @@ -89,7 +89,7 @@ void Hero::TreasureState::update() { State::update(); - if (!get_game().is_showing_message()) { + if (!get_game().is_showing_dialog()) { // the treasure's dialog is over: if the treasure was a tunic, // a sword or a shield, we have to reload the hero's sprites now diff --git a/src/hud/HUD.cpp b/src/hud/HUD.cpp index 74bdaa667..bd5c7dbe9 100644 --- a/src/hud/HUD.cpp +++ b/src/hud/HUD.cpp @@ -32,7 +32,9 @@ * @param game the current game (cannot be NULL) */ HUD::HUD(Game &game): - game(game), nb_elements(0), showing_message(false) { + game(game), + nb_elements(0), + showing_dialog(false) { elements[nb_elements++] = new HeartsView(game, 216, 6); elements[nb_elements++] = new RupeesCounter(game, 8, 220); @@ -110,21 +112,21 @@ void HUD::update_blinking() { */ void HUD::update() { - // detect when the game is showing a message - if (game.is_showing_message() && !showing_message) { - showing_message = true; + // detect when the game is showing a dialog + if (game.is_showing_dialog() && !showing_dialog) { + showing_dialog = true; - // a message is shown: hide or move the top-left icons + // a dialog is shown: hide or move the top-left icons elements[3]->set_visible(false); // item 0 elements[4]->set_visible(false); // item 1 elements[6]->set_visible(false); // pause icon elements[5]->set_position(-11, 17); // sword icon elements[7]->set_position(-11, 43); // action icon } - else if (!game.is_showing_message()) { + else if (!game.is_showing_dialog()) { - if (showing_message) { - showing_message = false; + if (showing_dialog) { + showing_dialog = false; // a message is finished: restore the top-left icons elements[3]->set_visible(true); // item 0 diff --git a/src/lua/MapAPI.cpp b/src/lua/MapAPI.cpp index 178a458e9..0c2b04ef6 100644 --- a/src/lua/MapAPI.cpp +++ b/src/lua/MapAPI.cpp @@ -40,45 +40,40 @@ #include /** - * @brief Creates a dialog box and starts displaying a message. + * @brief Shows the dialog box and starts displaying a dialog. * - * If the message is followed by other messages, they are also - * displayed. - * If the message (or one of its next messages) contains a variable, - * then you have to call dialog_set_variable() to specify its value. + * If the dialog contains a variable, + * then you have to call sol.map.dialog_set_variable() to specify its value. * - * - Argument 1 (string): id of the message to display + * - Argument 1 (string): id of the dialog to display * * @param l the Lua context that is calling this function */ -int Script::map_api_dialog_start(lua_State *l) { +int Script::map_api_dialog_start(lua_State* l) { Script& script = get_script(l, 1); - const std::string &message_id = luaL_checkstring(l, 1); + const std::string& dialog_id = luaL_checkstring(l, 1); - script.get_game().get_dialog_box().start_dialog(message_id, &script); + script.get_game().get_dialog_box().start_dialog(dialog_id, &script); return 0; } /** - * @brief Sets the value of the variable in a diabog. + * @brief Sets the value of the variable in a dialog. * - * The function has to be called after the dialog box is created, - * i.e. after calling dialog_start(). - * - * - Argument 1 (string): id of the message containing the variable + * - Argument 1 (string): id of the dialog containing the variable * - Argument 2 (string): value of the variable * * @param l the Lua context that is calling this function */ -int Script::map_api_dialog_set_variable(lua_State *l) { +int Script::map_api_dialog_set_variable(lua_State* l) { Script& script = get_script(l, 2); - const MessageId &message_id = luaL_checkstring(l, 1); - const std::string &value = luaL_checkstring(l, 2); + const std::string& dialog_id = luaL_checkstring(l, 1); + const std::string& value = luaL_checkstring(l, 2); - script.get_game().get_dialog_box().set_variable(message_id, value); + script.get_game().get_dialog_box().set_variable(dialog_id, value); return 0; } diff --git a/src/lua/Script.cpp b/src/lua/Script.cpp index 3e3a96ce1..e52203be7 100644 --- a/src/lua/Script.cpp +++ b/src/lua/Script.cpp @@ -869,7 +869,7 @@ bool Script::is_new_timer_suspended(void) { if (apis_enabled && GAME_API) { // start the timer even if the game is suspended (e.g. a timer started during a camera movement) // except when it is suspended because of a dialog box - return get_game().is_showing_message(); + return get_game().is_showing_dialog(); } return false; @@ -974,28 +974,28 @@ void Script::event_map_changed(Map &map) { /** * @brief Notifies the script that a dialog has just started to be displayed * in the dialog box. - * @param message_id id of the first message in this dialog + * @param dialog_id id of the dialog */ -void Script::event_dialog_started(const MessageId &message_id) { +void Script::event_dialog_started(const std::string& dialog_id) { - notify_script("event_dialog_started", "s", message_id.c_str()); + notify_script("event_dialog_started", "s", dialog_id.c_str()); } /** * @brief Notifies the script that the dialog box has just finished. * - * This function is called when the last message of a dialog is finished. + * This function is called when the last group of 3 lines of a dialog is + * finished. * The dialog box has just been closed but the game is still suspended. * Note that this event is not called if the dialog was skipped. * - * @param first_message_id id of the first message in the dialog - * that has just finished + * @param dialog_id id of the dialog that has just finished * @param answer the answer selected by the player: 0 for the first one, * 1 for the second one, -1 if there was no question */ -void Script::event_dialog_finished(const MessageId &first_message_id, int answer) { +void Script::event_dialog_finished(const std::string& dialog_id, int answer) { - notify_script("event_dialog_finished", "si", first_message_id.c_str(), answer); + notify_script("event_dialog_finished", "si", dialog_id.c_str(), answer); } /**