/** * \brief This function is called by the game when a command is pressed * while a dialog is active. * * Nothing happens if the dialog is handled in Lua. * * \param command The command pressed. * \return \c true if the command was handled (that is, if the dialog box * is active and is the built-in one). */ bool DialogBoxSystem::notify_command_pressed(GameCommand command) { if (!is_enabled()) { return false; } if (!built_in) { // The dialog box is handled by a Lua script. return false; } if (command == GameCommand::ACTION) { show_more_lines(); } else if (command == GameCommand::UP || command == GameCommand::DOWN) { if (is_question && !has_more_lines()) { // Switch the selected answer. selected_first_answer = !selected_first_answer; int selected_line_index = selected_first_answer ? 1 : 2; for (int i = 0; i < nb_visible_lines; i++) { line_surfaces[i]->set_text_color(Color::white); } line_surfaces[selected_line_index]->set_text_color(Color::yellow); } } return true; }
/** * @brief This function is called when the user presses the action key. */ void DialogBox::action_key_pressed() { if (is_full()) { // the current group of 3 lines is over show_more_lines(); } else if (skip_mode != Dialog::SKIP_NONE) { show_all_now(); } }
/** * @brief Starts a dialog. * * If there was already a dialog, it must be finished. * * @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 std::string& dialog_id, Script* issuer_script, VerticalPosition vertical_position) { Debug::check_assertion(!is_enabled() || is_full(), StringConcat() << "Cannot start dialog '" << dialog_id << "': another dialog '" << this->dialog_id << "' is already started"); bool first = !is_enabled(); if (first) { // save the action and sword keys 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(); this->icon_number = -1; this->skip_mode = Dialog::SKIP_NONE; this->char_delay = char_delays[SPEED_FAST]; this->dialog_id = dialog_id; } // initialize the dialog data this->dialog = DialogResource::get_dialog(dialog_id); this->line_it = dialog.get_lines().begin(); this->line_index = 0; this->char_index = 0; this->skipped = false; if (dialog.get_skip_mode() != Dialog::SKIP_UNCHANGED) { this->skip_mode = dialog.get_skip_mode(); } if (dialog.get_icon() != -2) { // -2 means unchanged this->icon_number = dialog.get_icon(); } if (dialog.is_question()) { this->last_answer = 0; } else { this->last_answer = -1; } question_dst_position.set_y(box_dst_position.get_y() + 27); if (first) { set_vertical_position(vertical_position); // notify the scripts game.get_map_script().event_dialog_started(dialog_id); this->issuer_script = issuer_script; if (issuer_script != NULL) { issuer_script->event_dialog_started(dialog_id); } } // start displaying text show_more_lines(); }
/** * @brief This function is called when the user presses the sword key. */ void DialogBox::sword_key_pressed() { if (skip_mode == Dialog::SKIP_ALL) { skipped = true; close(); } else if (is_full()) { show_more_lines(); } else if (skip_mode == Dialog::SKIP_CURRENT) { show_all_now(); } }
/** * @brief Stops displaying gradually the current 3 lines, shows them * immediately. * If the 3 lines were already finished, the next group of 3 lines starts * (if any). */ void DialogBox::show_all_now() { if (is_full()) { show_more_lines(); } else { // check the end of the current line while (!is_full()) { while (!is_full() && char_index >= lines[line_index].size()) { char_index = 0; line_index++; } if (!is_full()) { add_character(); } } } }
/** * \brief Opens the dialog box to show a dialog. * * No other dialog should be already running. * * \param dialog_id Id of the dialog to show. * \param info_ref Lua ref to an optional info parameter to pass to the * dialog box, or an empty ref. * \param callback_ref Lua ref to a function to call when the dialog finishes, * or an empty ref. */ void DialogBoxSystem::open( const std::string& dialog_id, const ScopedLuaRef& info_ref, const ScopedLuaRef& callback_ref ) { Debug::check_assertion(!is_enabled(), "A dialog is already active"); this->dialog_id = dialog_id; this->dialog = DialogResource::get_dialog(dialog_id); this->callback_ref = callback_ref; // Save commands. KeysEffect& keys_effect = game.get_keys_effect(); keys_effect.save_action_key_effect(); keys_effect.set_action_key_effect(KeysEffect::ACTION_KEY_NONE); keys_effect.save_sword_key_effect(); keys_effect.set_sword_key_effect(KeysEffect::SWORD_KEY_NONE); keys_effect.save_pause_key_effect(); keys_effect.set_pause_key_effect(KeysEffect::PAUSE_KEY_NONE); // A dialog was just started: notify Lua. LuaContext& lua_context = game.get_lua_context(); lua_State* l = lua_context.get_internal_state(); built_in = !lua_context.notify_dialog_started( game, dialog, info_ref ); if (built_in) { // Show a built-in default dialog box. keys_effect.set_action_key_effect(KeysEffect::ACTION_KEY_NEXT); // Prepare the text. std::string text = dialog.get_text(); this->is_question = false; if (dialog_id == "_shop.question") { // Built-in dialog with the "do you want to buy" question and the price. this->is_question = true; size_t index = text.find("$v"); if (index != std::string::npos) { // Replace the special sequence '$v' by the price of the shop item. info_ref.push(); int price = LuaTools::check_int(l, -1); lua_pop(l, -1); std::ostringstream oss; oss << price; text = text.replace(index, 2, oss.str()); } } remaining_lines.clear(); std::istringstream iss(text); std::string line; while (std::getline(iss, line)) { remaining_lines.push_back(line); } // Determine the position. const Rectangle& camera_position = game.get_current_map().get_camera_position(); bool top = false; if (game.get_hero()->get_y() >= camera_position.get_y() + 130) { top = true; } int x = camera_position.get_width() / 2 - 110; int y = top ? 32 : camera_position.get_height() - 96; text_position = { x, y }; // Start showing text. show_more_lines(); } }