From 1ade00462dda1d860136c21ac69f67d54b7aaa6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=9C=E8=8C=82=E6=A3=AE?= <35170687+dumaosen@users.noreply.github.com> Date: Wed, 18 Dec 2019 09:23:06 +0800 Subject: [PATCH] Simple tips manager (#4146) --- data/skins/coal/stkskin.xml | 3 + data/skins/forest/stkskin.xml | 3 + data/skins/ocean/stkskin.xml | 3 + data/skins/peach/stkskin.xml | 3 + data/skins/ruby/stkskin.xml | 3 + data/tips.xml | 21 ++++++ src/guiengine/engine.cpp | 24 +++++-- src/guiengine/engine.hpp | 2 +- src/main.cpp | 7 +- src/states_screens/race_result_gui.cpp | 5 ++ src/tips/tips_manager.cpp | 90 ++++++++++++++++++++++++++ src/tips/tips_manager.hpp | 75 +++++++++++++++++++++ 12 files changed, 233 insertions(+), 6 deletions(-) create mode 100644 data/tips.xml create mode 100644 src/tips/tips_manager.cpp create mode 100644 src/tips/tips_manager.hpp diff --git a/data/skins/coal/stkskin.xml b/data/skins/coal/stkskin.xml index e39217320..78e111290 100644 --- a/data/skins/coal/stkskin.xml +++ b/data/skins/coal/stkskin.xml @@ -292,6 +292,9 @@ when the border that intersect at this corner are enabled. + + + diff --git a/data/skins/forest/stkskin.xml b/data/skins/forest/stkskin.xml index f30ef7665..c1f3b06d8 100644 --- a/data/skins/forest/stkskin.xml +++ b/data/skins/forest/stkskin.xml @@ -292,6 +292,9 @@ when the border that intersect at this corner are enabled. + + + diff --git a/data/skins/ocean/stkskin.xml b/data/skins/ocean/stkskin.xml index b14180968..b77eace9e 100644 --- a/data/skins/ocean/stkskin.xml +++ b/data/skins/ocean/stkskin.xml @@ -291,6 +291,9 @@ when the border that intersect at this corner are enabled. + + + diff --git a/data/skins/peach/stkskin.xml b/data/skins/peach/stkskin.xml index 987706460..42531968c 100644 --- a/data/skins/peach/stkskin.xml +++ b/data/skins/peach/stkskin.xml @@ -309,6 +309,9 @@ all types of ttf. + + + diff --git a/data/skins/ruby/stkskin.xml b/data/skins/ruby/stkskin.xml index 04bb8955e..5bd9d815d 100644 --- a/data/skins/ruby/stkskin.xml +++ b/data/skins/ruby/stkskin.xml @@ -290,6 +290,9 @@ when the border that intersect at this corner are enabled. + + + diff --git a/data/tips.xml b/data/tips.xml new file mode 100644 index 000000000..48945e9ab --- /dev/null +++ b/data/tips.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index d9122d83d..64f66e5d6 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -684,6 +684,7 @@ namespace GUIEngine #include "modes/cutscene_world.hpp" #include "modes/world.hpp" #include "states_screens/race_gui_base.hpp" +#include "tips/tips_manager.hpp" #include "utils/debug.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -1357,10 +1358,14 @@ namespace GUIEngine // ----------------------------------------------------------------------- std::vector g_loading_icons; + core::stringw g_tips_string; - void renderLoading(bool clearIcons, bool launching) + void renderLoading(bool clearIcons, bool launching, bool update_tips) { #ifndef SERVER_ONLY + if(update_tips) + g_tips_string = _("Tip: ") + TipsManager::get()->getTip("general"); + if (clearIcons) g_loading_icons.clear(); g_skin->drawBgImage(); @@ -1382,6 +1387,10 @@ namespace GUIEngine const int screen_w = frame_size.Width; const int screen_h = frame_size.Height; + // used in drawing tips + const int text_height = getFontHeight() * 1.2f; + const int y_from = screen_h - text_height * 0.3f; + const core::rect< s32 > dest_area = core::rect< s32 >(screen_w/2 - stretched_size/2, screen_h/2 - stretched_size/2, @@ -1404,11 +1413,18 @@ namespace GUIEngine SColor(255,255,255,255), true/* center h */, false /* center v */ ); + // Draw a tip during loading + core::rect tipRect(core::position2d(0, y_from - text_height), + core::dimension2d(screen_w, text_height)); + GL32_draw2DRectangle(Skin::getColor("tips_background::neutral"), tipRect); + Private::g_font->draw(g_tips_string.c_str(), tipRect, Skin::getColor("brighttext::neutral"), + true /* hcenter */, true /* vcenter */); + const int icon_count = (int)g_loading_icons.size(); - const int icon_size = (int)(std::min(screen_w, screen_h) / 10.0f); + const int icon_size = (int)(std::min(screen_w, screen_h) / 12.0f); const int ICON_MARGIN = 6; int x = ICON_MARGIN; - int y = screen_h - icon_size - ICON_MARGIN; + int y = y_from - icon_size - ICON_MARGIN - text_height * 1.2f; for (int n=0; ngetVideoDriver() ->beginScene(true, true, video::SColor(255,100,101,140)); - renderLoading(false, true); + renderLoading(false, true, false); g_device->getVideoDriver()->endScene(); } else diff --git a/src/guiengine/engine.hpp b/src/guiengine/engine.hpp index e765965c1..9ac009cf7 100644 --- a/src/guiengine/engine.hpp +++ b/src/guiengine/engine.hpp @@ -232,7 +232,7 @@ namespace GUIEngine void render(float dt, bool is_loading = false); /** \brief renders a "loading" screen */ - void renderLoading(bool clearIcons = true, bool launching = false); + void renderLoading(bool clearIcons = true, bool launching = false, bool update_tips = true); /** \brief to spice up a bit the loading icon : add icons to the loading screen */ void addLoadingIcon(irr::video::ITexture* icon); diff --git a/src/main.cpp b/src/main.cpp index a682ced37..d5512851b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -197,6 +197,7 @@ #include "guiengine/engine.hpp" #include "guiengine/event_handler.hpp" #include "guiengine/dialog_queue.hpp" +#include "guiengine/message_queue.hpp" #include "input/device_manager.hpp" #include "input/input_manager.hpp" #include "input/keyboard_device.hpp" @@ -243,6 +244,7 @@ #include "states_screens/options/user_screen.hpp" #include "states_screens/dialogs/init_android_dialog.hpp" #include "states_screens/dialogs/message_dialog.hpp" +#include "tips/tips_manager.hpp" #include "tracks/arena_graph.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" @@ -1792,7 +1794,7 @@ void initRest() GUIEngine::init(device, driver, StateManager::get()); - GUIEngine::renderLoading(true, true); + GUIEngine::renderLoading(true, true, false); input_manager = new InputManager(); // Get into menu mode initially. input_manager->setMode(InputManager::MENU); @@ -2025,6 +2027,9 @@ int main(int argc, char *argv[]) // ServerConfig will use stk_config for server version testing stk_config->load(file_manager->getAsset("stk_config.xml")); bool no_graphics = !CommandLine::has("--graphical-server"); + + TipsManager::create(); + // Load current server config first, if any option is specified than // override it later // Disable sound if found server-config or wan/lan server name diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 68e3d943b..2b92ce562 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -60,10 +60,12 @@ #include "states_screens/main_menu_screen.hpp" #include "states_screens/online/networking_lobby.hpp" #include "states_screens/race_setup_screen.hpp" +#include "tips/tips_manager.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" + #include /** Constructor, initialises internal data structures. @@ -141,6 +143,9 @@ void RaceResultGUI::init() m_start_track = 0; m_end_track = (int)tracks.size(); } + + core::stringw tips_string = _("Tip: ") + TipsManager::get()->getTip("race"); + MessageQueue::add(MessageQueue::MT_GENERIC, tips_string); } // init //----------------------------------------------------------------------------- diff --git a/src/tips/tips_manager.cpp b/src/tips/tips_manager.cpp new file mode 100644 index 000000000..514497980 --- /dev/null +++ b/src/tips/tips_manager.cpp @@ -0,0 +1,90 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2019 dumaosen +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "tips/tips_manager.hpp" + +#include "io/file_manager.hpp" +#include "utils/log.hpp" +#include "utils/random_generator.hpp" +#include "utils/string_utils.hpp" +#include "utils/translation.hpp" + +TipsManager* TipsManager::m_tips_manager = NULL; + +// ---------------------------------------------------------------------------- +/** Constructor, which reads data/tips.xml and stores the information + * in objects. + */ +TipsManager::TipsManager() +{ + const std::string file_name = file_manager->getAsset("tips.xml"); + const XMLNode *root = file_manager->createXMLTree(file_name); + unsigned int num_nodes = root->getNumNodes(); + + for(unsigned int i = 0; i < num_nodes; i++) + { + const XMLNode *node = root->getNode(i); + addTipSet(node); + } + + if(num_nodes != m_all_tip_sets.size()) + Log::error("TipsManager", + "Multiple tipsets with the same id!"); + + delete root; +} // TipsManager + +// ---------------------------------------------------------------------------- +TipsManager::~TipsManager() +{ + m_all_tip_sets.clear(); +} // ~TipsManager + +// ---------------------------------------------------------------------------- +void TipsManager::addTipSet(const XMLNode *input) +{ + std::string id; + + if(!input->get("id", &id)) + Log::error("TipSet", + "Undefined id for tipset."); + + for(unsigned int n = 0; n < input->getNumNodes(); n++) + { + const XMLNode *node = input->getNode(n); + if (node->getName() != "tip") + continue; // ignore incorrect node + + std::string text; + if(!node->get("text", &text)) + continue; // missing text, ignore node + + // Gettext is used here + m_all_tip_sets[id].push_back(_(text.c_str())); + } + if(m_all_tip_sets[id].size() != input->getNumNodes()) + Log::error("TipSet", + "Incorrect tips for the entries of tipset \"%s\".", id.c_str()); +} + +// ---------------------------------------------------------------------------- +irr::core::stringw TipsManager::getTip(std::string id) +{ + RandomGenerator randgen; + return m_all_tip_sets[id][randgen.get(m_all_tip_sets[id].size())]; +} // getTipSet diff --git a/src/tips/tips_manager.hpp b/src/tips/tips_manager.hpp new file mode 100644 index 000000000..da53943af --- /dev/null +++ b/src/tips/tips_manager.hpp @@ -0,0 +1,75 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2019 dumaosen +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_TIPS_MANAGER_HPP +#define HEADER_TIPS_MANAGER_HPP + +#include "io/xml_node.hpp" + +#include +#include +#include +#include +#include + +typedef std::vector TipSet; + +/** This class manages the list of all tips. It reads the + * data/tips.xml file, which contains the contents for + * each tip. + */ +class TipsManager +{ +private: + /** Pointer to the single instance. */ + static TipsManager *m_tips_manager; + + std::map m_all_tip_sets; + + TipsManager (); + ~TipsManager (); + + void addTipSet(const XMLNode *input); + +public: + /** Static function to create the instance of the tips manager. */ + static void create() + { + assert(!m_tips_manager); + m_tips_manager = new TipsManager(); + } // create + // ------------------------------------------------------------------------ + /** Static function to get the tips manager. */ + static TipsManager* get() + { + assert(m_tips_manager); + return m_tips_manager; + } // get + // ------------------------------------------------------------------------ + static void destroy() + { + delete m_tips_manager; + m_tips_manager = NULL; + } // destroy + // ======================================================================== + /** Get a tip by ID. */ + irr::core::stringw getTip(std::string id); + // ------------------------------------------------------------------------ +}; // class TipsManager + +#endif \ No newline at end of file