From b8f85314c6dc1c3a7863daa0b250f6be4cb42ef6 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 19 May 2026 03:27:27 +0200 Subject: [PATCH 01/11] Only display the fireback input if enabled The presence of the fireback key/button binding in the list is made dependent on the status of the DeviceConfig's fireback bool (and its associated checkbox). - All the addListItem calls present in init, as well as a few other calls, have been moved to a new loadList function. This function is called in init but also when toggling the fireback input checkbox. It adds a clear and conditional loading for the PA_FIRE_BACK entry so that it can be used to reload the list with the fireback input being appropriately present or absent. - Make the fire back row renaming conditional on the dedicated fireback input being active - When checking for binding issues, skip the fire back input if it's not enabled (otherwise we might try to color a list item which doesn't exist) - Also remove a bunch of pointless empty lines --- .../options/options_screen_device.cpp | 56 ++++++++++--------- .../options/options_screen_device.hpp | 1 + 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/states_screens/options/options_screen_device.cpp b/src/states_screens/options/options_screen_device.cpp index 2a494e29fea..dfc601e08be 100644 --- a/src/states_screens/options/options_screen_device.cpp +++ b/src/states_screens/options/options_screen_device.cpp @@ -157,12 +157,26 @@ void OptionsScreenDevice::init() LabelWidget* label_widget = getWidget("title"); label_widget->setText( m_config->getName().c_str(), false ); + loadList(true /* select list */); + + // Disable deleting or disabling configuration mid-race + if (StateManager::get()->getGameState() == GUIEngine::INGAME_MENU) + { + delete_button->setActive(false); + disable_toggle->setActive(false); + } +} // init + +void OptionsScreenDevice::loadList(bool select_list) +{ // ---- create list skeleton (right number of items, right internal names) // their actualy contents will be adapted as needed after ListWidget* actions = getWidget("actions"); assert( actions != NULL ); + actions->clear(); + //I18N: Key binding section addListItemSubheader(actions, "game_keys_section", _("Game Keys")); addListItem(actions, PA_STEER_LEFT); @@ -173,7 +187,8 @@ void OptionsScreenDevice::init() addListItem(actions, PA_NITRO); addListItem(actions, PA_DRIFT); addListItem(actions, PA_LOOK_BACK); - addListItem(actions, PA_FIRE_BACK); + if (m_config->hasDedicatedFireback()) + addListItem(actions, PA_FIRE_BACK); addListItem(actions, PA_RESCUE); addListItem(actions, PA_PAUSE_RACE); @@ -190,16 +205,12 @@ void OptionsScreenDevice::init() updateInputButtons(); // Focus the list and select its first item - actions->setFocusForPlayer(PLAYER_ID_GAME_MASTER); - actions->setSelectionID(0); - - // Disable deleting or disabling configuration mid-race - if (StateManager::get()->getGameState() == GUIEngine::INGAME_MENU) + if (select_list) { - delete_button->setActive(false); - disable_toggle->setActive(false); + actions->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + actions->setSelectionID(0); } -} // init +} // loadList // ----------------------------------------------------------------------------- @@ -254,34 +265,27 @@ void OptionsScreenDevice::updateInputButtons() //I18N: Key binding name renameRow(actions, i++, _("Steer Left"), PA_STEER_LEFT); - //I18N: Key binding name renameRow(actions, i++, _("Steer Right"), PA_STEER_RIGHT); - //I18N: Key binding name renameRow(actions, i++, _("Accelerate"), PA_ACCEL); - //I18N: Key binding name renameRow(actions, i++, _("Brake / Reverse"), PA_BRAKE); - //I18N: Key binding name renameRow(actions, i++, _("Fire"), PA_FIRE); - //I18N: Key binding name renameRow(actions, i++, _("Nitro"), PA_NITRO); - //I18N: Key binding name renameRow(actions, i++, _("Skidding"), PA_DRIFT); - //I18N: Key binding name renameRow(actions, i++, _("Look Back"), PA_LOOK_BACK); - - //I18N: Key binding name - renameRow(actions, i++, _("Fire Back"), PA_FIRE_BACK); - + if (m_config->hasDedicatedFireback()) + { + //I18N: Key binding name + renameRow(actions, i++, _("Fire Back"), PA_FIRE_BACK); + } //I18N: Key binding name renameRow(actions, i++, _("Rescue"), PA_RESCUE); - //I18N: Key binding name renameRow(actions, i++, _("Pause Game"), PA_PAUSE_RACE); @@ -289,24 +293,18 @@ void OptionsScreenDevice::updateInputButtons() //I18N: Key binding name renameRow(actions, i++, _("Up"), PA_MENU_UP); - //I18N: Key binding name renameRow(actions, i++, _("Down"), PA_MENU_DOWN); - //I18N: Key binding name renameRow(actions, i++, _("Left"), PA_MENU_LEFT); - //I18N: Key binding name renameRow(actions, i++, _("Right"), PA_MENU_RIGHT); - //I18N: Key binding name renameRow(actions, i++, _("Select"), PA_MENU_SELECT); - //I18N: Key binding name renameRow(actions, i++, _("Cancel/Back"), PA_MENU_CANCEL); - bool conflicts_between = false; bool conflicts_inside = false; // ---- make sure there are no binding conflicts @@ -316,6 +314,9 @@ void OptionsScreenDevice::updateInputButtons() action <= PA_LAST_GAME_ACTION; action=PlayerAction(action+1)) { + if (!m_config->hasDedicatedFireback() && action == PA_FIRE_BACK) + continue; + const irr::core::stringw item = m_config->getMappingIdString(action); if (currently_used_keys.find(item) == currently_used_keys.end()) { @@ -643,6 +644,7 @@ void OptionsScreenDevice::eventCallback(Widget* widget, bool status = getWidget("dedicated_fireback")->getState(); m_config->setDedicatedFireback(status); input_manager->getDeviceManager()->save(); + loadList(false /* select list */); } else if (name == "force_feedback") { diff --git a/src/states_screens/options/options_screen_device.hpp b/src/states_screens/options/options_screen_device.hpp index 87ec6ce8b5f..6bb199bf326 100644 --- a/src/states_screens/options/options_screen_device.hpp +++ b/src/states_screens/options/options_screen_device.hpp @@ -60,6 +60,7 @@ class OptionsScreenDevice : public GUIEngine::Screen, void addListItemSubheader(GUIEngine::ListWidget* actions, const char* id, const core::stringw& text); + void loadList(bool select_list); public: friend class GUIEngine::ScreenSingleton; From e766c9ac8cc9bf66928959d001855587c3905c20 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 19 May 2026 04:18:29 +0200 Subject: [PATCH 02/11] Significantly reduce code duplication in binding conflict detection The game inputs and menu inputs are separate for the purpose of conflict-checking (a key may have one role in the menu and another in-game), and so the old code simply duplicated everything. - Add a checkForConflicts function which take the first and last player action it has to loop over. We call it first with game actions and then with menu actions. - This also incidentally fixes the emphasis missing for menu actions set to 'none'. --- .../options/options_screen_device.cpp | 110 +++++++----------- .../options/options_screen_device.hpp | 4 +- 2 files changed, 42 insertions(+), 72 deletions(-) diff --git a/src/states_screens/options/options_screen_device.cpp b/src/states_screens/options/options_screen_device.cpp index dfc601e08be..4f4d42fc171 100644 --- a/src/states_screens/options/options_screen_device.cpp +++ b/src/states_screens/options/options_screen_device.cpp @@ -304,19 +304,44 @@ void OptionsScreenDevice::updateInputButtons() //I18N: Key binding name renameRow(actions, i++, _("Cancel/Back"), PA_MENU_CANCEL); - + // menu keys and game keys can overlap, no problem, so we check separately bool conflicts_between = false; bool conflicts_inside = false; + checkForConflicts(actions, PA_FIRST_GAME_ACTION, PA_LAST_GAME_ACTION, + &conflicts_between, &conflicts_inside); + checkForConflicts(actions, PA_FIRST_MENU_ACTION, PA_LAST_MENU_ACTION, + &conflicts_between, &conflicts_inside); + + core::stringw warning; + if (conflicts_between) + { + warning = _("* A blue item means a conflict with another configuration"); + if (conflicts_inside) + warning += "\n"; + } + if (conflicts_inside) + warning += _("* A red item means a conflict in the current configuration"); + if (!warning.empty()) + MessageQueue::add(MessageQueue::MT_ERROR, warning); + +} // updateInputButtons + +// ----------------------------------------------------------------------------- + +void OptionsScreenDevice::checkForConflicts(GUIEngine::ListWidget* actions, + PlayerAction check_first, PlayerAction check_last, + bool* conflicts_between, bool* conflicts_inside) +{ + std::set currently_used_keys; // ---- make sure there are no binding conflicts // (same key used for two actions) - std::set currently_used_keys; - for (PlayerAction action = PA_FIRST_GAME_ACTION; - action <= PA_LAST_GAME_ACTION; + for (PlayerAction action = check_first; + action <= check_last; action=PlayerAction(action+1)) { if (!m_config->hasDedicatedFireback() && action == PA_FIRE_BACK) continue; - + const irr::core::stringw item = m_config->getMappingIdString(action); if (currently_used_keys.find(item) == currently_used_keys.end()) { @@ -328,89 +353,32 @@ void OptionsScreenDevice::updateInputButtons() } currently_used_keys.insert( item ); if (m_config->isKeyboard() - && conflictsBetweenKbdConfig(action, PA_FIRST_GAME_ACTION, - PA_LAST_GAME_ACTION)) + && conflictsBetweenKbdConfig(action, check_first, check_last)) { - conflicts_between = true; + *conflicts_between = true; actions->markItemBlue (KartActionStrings[action]); } } - else + else // existing key { // binding conflict! actions->markItemRed( KartActionStrings[action] ); // also mark others - for (PlayerAction others = PA_FIRST_GAME_ACTION; + for (PlayerAction others = check_first; others < action; others=PlayerAction(others+1)) { const irr::core::stringw others_item = m_config->getMappingIdString(others); if (others_item == item) { - conflicts_inside = true; + *conflicts_inside = true; actions->markItemRed( KartActionStrings[others] ); } - } - - //actions->renameItem( KartActionStrings[action], - // _("Binding Conflict!") ); - } - } - - // menu keys and game keys can overlap, no problem, so forget game keys - // before checking menu keys - currently_used_keys.clear(); - for (PlayerAction action = PA_FIRST_MENU_ACTION; - action <= PA_LAST_MENU_ACTION; - action=PlayerAction(action+1)) - { - const irr::core::stringw item = m_config->getBindingAsString(action); - if (currently_used_keys.find(item) == currently_used_keys.end()) - { - currently_used_keys.insert( item ); - if (m_config->isKeyboard() - && conflictsBetweenKbdConfig(action, PA_FIRST_MENU_ACTION, - PA_LAST_MENU_ACTION)) - { - conflicts_between = true; - actions->markItemBlue (KartActionStrings[action]); - } - } - else // existing key - { - // binding conflict! - actions->markItemRed( KartActionStrings[action] ); - - // also mark others - for (PlayerAction others = PA_FIRST_MENU_ACTION; - others < action; others=PlayerAction(others+1)) - { - const irr::core::stringw others_item = - m_config->getBindingAsString(others); - if (others_item == item) - { - conflicts_inside = true; - actions->markItemRed( KartActionStrings[others] ); - } - } // for others < action - - } // if existing key - } // for action <= PA_LAST_MENU_ACTION; - - core::stringw warning; - if (conflicts_between) - { - warning = _("* A blue item means a conflict with another configuration"); - if (conflicts_inside) - warning += "\n"; - } - if (conflicts_inside) - warning += _("* A red item means a conflict in the current configuration"); - if (!warning.empty()) - MessageQueue::add(MessageQueue::MT_ERROR, warning); - -} // updateInputButtons + } // for others < action + } // if existing key + } // for action <= check_last +} // checkForConflicts // ----------------------------------------------------------------------------- diff --git a/src/states_screens/options/options_screen_device.hpp b/src/states_screens/options/options_screen_device.hpp index 6bb199bf326..4e1b10f10c9 100644 --- a/src/states_screens/options/options_screen_device.hpp +++ b/src/states_screens/options/options_screen_device.hpp @@ -61,7 +61,9 @@ class OptionsScreenDevice : public GUIEngine::Screen, const char* id, const core::stringw& text); void loadList(bool select_list); - + void checkForConflicts(GUIEngine::ListWidget* actions, + PlayerAction check_first, PlayerAction check_last, + bool* conflicts_between, bool* conflicts_inside); public: friend class GUIEngine::ScreenSingleton; From 8199744eee0be0e6b8d6fb2f8f59ea65913d6d63 Mon Sep 17 00:00:00 2001 From: virophagesp <96668463+virophagesp@users.noreply.github.com> Date: Tue, 26 May 2026 07:51:42 +1200 Subject: [PATCH 03/11] Fix the server-only build (#5750) --- src/graphics/attachable_library_manager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/graphics/attachable_library_manager.cpp b/src/graphics/attachable_library_manager.cpp index bb0a92450aa..153aebbb6c2 100644 --- a/src/graphics/attachable_library_manager.cpp +++ b/src/graphics/attachable_library_manager.cpp @@ -95,8 +95,10 @@ void AttachableLibraryManager::loadLibraryNode(const std::string& folder_name, file_manager->pushTextureSearchPath(lib_path + "/", unique_path); file_manager->pushModelSearchPath(lib_path); material_manager->pushTempMaterial(lib_path + "/materials.xml"); +#ifndef SERVER_ONLY if (CVS->isGLSL()) SP::SPShaderManager::get()->loadSPShaders(lib_path); +#endif // based on Track::loadObjects unsigned int node_count = libroot->getNumNodes(); From ce6d1c75b07e57662f4b53eb52dfe0b459b49f4a Mon Sep 17 00:00:00 2001 From: Gustavo Barreira <155913980+GustaLOLE@users.noreply.github.com> Date: Mon, 25 May 2026 17:00:45 -0300 Subject: [PATCH 04/11] Fix compilation for mobile (#5749) Code behind a MOBILE_STK guard required an additional variable that wasn't available within the context of the new function introduced in 4a487a1. --- src/input/input_manager.cpp | 5 +++-- src/input/input_manager.hpp | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index 2359ae7f249..3142b18e86f 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -815,7 +815,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, if (player == NULL) return; - passActionToController(player, action, value, lookback_to_fireback); + passActionToController(type, player, action, value, lookback_to_fireback); } else if (RaceManager::get() && RaceManager::get()->isWatchingReplay() && !GUIEngine::ModalDialog::isADialogActive() && @@ -907,7 +907,8 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, //----------------------------------------------------------------------------- -void InputManager::passActionToController(StateManager::ActivePlayer* player, +void InputManager::passActionToController(Input::InputType type, + StateManager::ActivePlayer* player, PlayerAction action, int value, bool lookback_to_fireback) { diff --git a/src/input/input_manager.hpp b/src/input/input_manager.hpp index 8c15ea5665f..38de8091abf 100644 --- a/src/input/input_manager.hpp +++ b/src/input/input_manager.hpp @@ -78,9 +78,10 @@ class InputManager: public NoCopy void handleStaticAction(int id0, int value); void inputSensing(Input::InputType type, int deviceID, int btnID, Input::AxisDirection axisDirection, int value); - void passActionToController(StateManager::ActivePlayer* player, - PlayerAction action, int value, - bool lookback_to_fireback); + void passActionToController(Input::InputType type, + StateManager::ActivePlayer* player, + PlayerAction action, int value, + bool lookback_to_fireback); #ifndef SERVER_ONLY std::map > m_sdl_controller; From 90792e62fb84cd0e5244c68eeced0ee522f6ef0f Mon Sep 17 00:00:00 2001 From: ewingwm <65508610+ewingwm@users.noreply.github.com> Date: Sat, 30 May 2026 09:27:56 -0400 Subject: [PATCH 05/11] Hide attachable library templates (#5757) This fixes #5730 --- src/graphics/attachable_library_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graphics/attachable_library_manager.cpp b/src/graphics/attachable_library_manager.cpp index 153aebbb6c2..091eb91a200 100644 --- a/src/graphics/attachable_library_manager.cpp +++ b/src/graphics/attachable_library_manager.cpp @@ -70,7 +70,8 @@ void AttachableLibraryManager::loadLibraryNode(const std::string& folder_name, } m_attachable_lib_nodes[identifier] = irr_driver->getSceneManager()->addEmptySceneNode(); - + m_attachable_lib_nodes[identifier]->setVisible(false); + XMLNode* libroot; // During reloads, the folder map is preserved but the attachable nodes aren't if (m_folder_map.count(identifier) == 0) From 3528cddb8440c7c500f3ebf08df40c1fdf91f623 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 1 Jun 2026 19:54:26 +0200 Subject: [PATCH 06/11] Add a default parameter to scripting's setEnabled This removes the need to update the scripting.as file for existing tracks and library objects, as the game will default to ignoring the library lock for scripting calls. --- src/scriptengine/script_track.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scriptengine/script_track.cpp b/src/scriptengine/script_track.cpp index e2b00acd8a0..0de54330e55 100644 --- a/src/scriptengine/script_track.cpp +++ b/src/scriptengine/script_track.cpp @@ -612,7 +612,7 @@ namespace Scripting call_conv); assert(r >= 0); // TrackObject - r = engine->RegisterObjectMethod("TrackObject", "void setEnabled(bool status, bool ignore_lock)", + r = engine->RegisterObjectMethod("TrackObject", "void setEnabled(bool status, bool ignore_lock = true)", mp ? WRAP_MFN(::TrackObject, setEnabled) : asMETHOD(::TrackObject, setEnabled), call_conv_thiscall); assert(r >= 0); From c8d6c4a74e0678d84364d3a44d3d799214af4fb6 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:52:08 +0200 Subject: [PATCH 07/11] Make checklines taller by default and allow custom-height checklines There are two components to a checkline's height, the component below the reference height (this reference height is called 'min height' in code) and the component above. Track creators may either define the reference height manually or just let the game autocompute it by checking the height of the driveline near the center of the check line. Therefore, depending on surrounding terrain, track creators may want to modify the size of the up component (to prevent karts jumping above - while preventing the checkline from being touched incorrectly in e.g. loops with 2 levels of road above the same point) or the down component (to prevent karts from driving under the checkline). This commit: - Increases the default height parameter from 4 up / 1 down to 10 up / 2 down. This should be a better default in the vast majority of cases. - Adds support for a 'height-up' and a 'height-down' parameter in XML to allow custom adjustment by track creators depending on the specific needs of their project. --- src/tracks/check_line.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/tracks/check_line.cpp b/src/tracks/check_line.cpp index 7149c7c3947..eddede22607 100644 --- a/src/tracks/check_line.cpp +++ b/src/tracks/check_line.cpp @@ -81,13 +81,17 @@ CheckLine::CheckLine(const XMLNode &node, unsigned int index) normal = Graph::get()->getQuad(sector)->getNormal(); } - // How much a kart is allowed to be under the minimum height of a - // quad and still considered to be able to cross it. - float under_min_height = 1.0f; + // How much a kart is allowed to be under the reference height of a + // checkline and still be considered able to cross it. + float under_min_height = 2.0f; + if(node.get("height-down", &under_min_height)) + under_min_height = std::max(under_min_height, 0.0f); // Prevent negative values - // How much a kart is allowed to be over the minimum height of a - // quad and still considered to be able to cross it. - float over_min_height = 4.0f; + // How much a kart is allowed to be over the reference height of a + // checkline and still be considered able to cross it. + float over_min_height = 10.0f; + if(node.get("height-up", &over_min_height)) + over_min_height = std::max(over_min_height, 1.0f); // Prevent values <= 1 m_check_plane[0].pointA = Vec3(m_left_point + (normal * under_min_height * -1.0f)).toIrrVector(); From 48434d0c387b64eac485c3670a5e9edbe7b467e7 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Thu, 4 Jun 2026 19:49:22 +0200 Subject: [PATCH 08/11] Add a new config option for artist debug quick start Instead of automatically having quick start in artist debug mode in races without opponents, this behavior now depends on an additional UserConfig parameter. Code duplication is also reduced, with the bool used to check if there should be an accelerated start computed once and checked when needed. --- src/config/user_config.hpp | 5 +++++ src/modes/world_status.cpp | 38 +++++++++++--------------------------- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index c817b079a1a..422ccbb06a5 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -1407,6 +1407,11 @@ namespace UserConfigParams PARAM_DEFAULT( BoolUserConfigParam(false, "artist_debug_mode", "Whether to enable track debugging features") ); + PARAM_PREFIX BoolUserConfigParam m_artist_debug_quick_start + PARAM_DEFAULT( BoolUserConfigParam(false, "artist_debug_quick_start", + "Whether to skip the normal race start sequence " + "if artist debug mode is on") ); + PARAM_PREFIX BoolUserConfigParam m_hide_gui PARAM_DEFAULT(BoolUserConfigParam(false, "debug_hide_gui", "Whether to hide the GUI (artist debug mode)")); diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index ca1db6ddfe8..8b7b5400c35 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -209,6 +209,13 @@ void WorldStatus::update(int ticks) */ void WorldStatus::updateTime(int ticks) { + bool is_artist_quick_start = UserConfigParams::m_artist_debug_mode && + UserConfigParams::m_artist_debug_quick_start && + !NetworkConfig::get()->isNetworking() && + (RaceManager::get()->getNumberOfKarts() - + RaceManager::get()->getNumSpareTireKarts()) == 1 && + RaceManager::get()->getTrackName() != "tutorial"; + switch (m_phase.load()) { // Note: setup phase must be a separate phase, since the race_manager @@ -234,14 +241,8 @@ void WorldStatus::updateTime(int ticks) case TRACK_INTRO_PHASE: m_auxiliary_ticks++; - if (UserConfigParams::m_artist_debug_mode && - !NetworkConfig::get()->isNetworking() && - RaceManager::get()->getNumberOfKarts() - - RaceManager::get()->getNumSpareTireKarts() == 1 && - RaceManager::get()->getTrackName() != "tutorial") - { + if (is_artist_quick_start) m_auxiliary_ticks += 6; - } if (!m_play_track_intro_sound) { @@ -333,14 +334,8 @@ void WorldStatus::updateTime(int ticks) // In artist debug mode, when without opponents, skip the // ready/set/go counter faster - if (UserConfigParams::m_artist_debug_mode && - !NetworkConfig::get()->isNetworking() && - RaceManager::get()->getNumberOfKarts() - - RaceManager::get()->getNumSpareTireKarts() == 1 && - RaceManager::get()->getTrackName() != "tutorial") - { + if (is_artist_quick_start) m_auxiliary_ticks += 6; - } return; // Do not increase time case SET_PHASE: @@ -364,12 +359,7 @@ void WorldStatus::updateTime(int ticks) onGo(); // In artist debug mode, when without opponents, // skip the ready/set/go counter faster - m_start_music_ticks = - UserConfigParams::m_artist_debug_mode && - !NetworkConfig::get()->isNetworking() && - RaceManager::get()->getNumberOfKarts() - - RaceManager::get()->getNumSpareTireKarts() == 1 && - RaceManager::get()->getTrackName() != "tutorial" ? + m_start_music_ticks = is_artist_quick_start ? stk_config->time2Ticks(0.2f) : stk_config->time2Ticks(1.0f); } @@ -378,14 +368,8 @@ void WorldStatus::updateTime(int ticks) // In artist debug mode, when without opponents, // skip the ready/set/go counter faster - if (UserConfigParams::m_artist_debug_mode && - !NetworkConfig::get()->isNetworking() && - RaceManager::get()->getNumberOfKarts() - - RaceManager::get()->getNumSpareTireKarts() == 1 && - RaceManager::get()->getTrackName() != "tutorial") - { + if (is_artist_quick_start) m_auxiliary_ticks += 6; - } return; // Do not increase time case GO_PHASE: From f0b6f3e10d1c5677513f20694f9a3165b2bf02ff Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Thu, 4 Jun 2026 23:06:31 +0200 Subject: [PATCH 09/11] Update the changelog for STK Evolution - Add all changes since the previous update - Fix formatting for sub-entries - Rework a few entries for greater clarity or to better account for more recent tweaks in the same area --- CHANGELOG.md | 126 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c94df60652..6299c3aa930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,37 +8,47 @@ For similar reasons, and because some features are vastly more complex than othe ## SuperTuxKart Evolution (work in progress) ### Gameplay -* In lower difficulty levels, apply a relative decrease to the strength of speed boosts, by Alayan -* In lower difficulty levels, reduce the nitro consumption rate, by Alayan * Add a fifth difficulty level, for more gradation between easiest and hardest, by Alayan * Increase the time to reach maximum steering in lower difficulties, by Alayan * Reduce the duration and fade-out time of the startup boost, by Alayan * Slightly reduce rescue duration, by Alayan * Allow braking while accelerating, by Alayan * Ensure the AI is bound by the same durations as the player to change steering, by Alayan -* Make the boosts from ground zippers and zipper powerups distinct, only applying the better one, by Nomagno -* New multi-level handicap system, by Alayan +* Make the boosts from ground zippers and zipper powerups distinct (the ground zipper type not giving an off-road bonus), only applying the better one, by Nomagno +* Use the ground zipper boost type for the startup boost, by Alayan +* New multi-level handicap system, with 7 handicap levels from 4% penalty to 28% penalty, by Alayan * Make handicap usable in single-player, by Alayan * Prevent validating laps driving backwards (provided at least two correctly placed checklines), by Alayan * Prevent texture slowdown and reverse speed cap from fully multiplying, by Alayan +* Don't prevent getting a startup boost because of inputs made before the countdown phase, by Alayan +* Add a new optional 'fire backward' input ('look back + fire' remains supported), by Alayan +* Reset all speed boosts and remove immunity when a kart is rescued, by Alayan +* Reduce the speed below which the kart auto-brakes if there is no acceleration input from 5 to 3, by Alayan +* Make the default lap number of a track depend on difficulty, by Alayan +* Reduce the default bomb duration from 30s to 20s, by Alayan +* Allow the bomb to be transferred to any other kart (removing the previous owner exception), but only after a minimum time has elapsed (corresponding to the bomb's growing in size after being attached), by Alayan +* Make the anchor's initial speed loss less significant and its ongoing effect on acceleration more significant (higher weight and duration), by Alayan #### Physics * Make the restitution curves (used when a kart rebounds on something) smoother and reduce the strength of rebounds at high-speeds, by Alayan * Uniformize jumping characteristics of karts (previously, heavier karts would have a much easier time taking off), by Alayan * Push karts upright much quicker when only some wheels touch the ground, by Alayan * Great improvements to the kart-on-kart collision logic, by Alayan: -- Prevent two colliding karts from locking into each other -- Make it easier to push another kart and make kart weight more meaningful -- Help karts keep their direction during and after a collision + - Prevent two colliding karts from locking into each other + - Make it easier to push another kart and make kart weight more meaningful + - Help karts keep their direction during and after a collision + - The pushing strength of a kart still affected by the impulse from a previous collision is halved +* Reduce the steering change rate when a drift is active, by Alayan +* Prevent the kart falling speed from increasing without limits during long falls, by applying pseudo-air-friction to the vertical component of a flying kart's movement, by Alayan #### Powerups * Rebalance all powerup probabilities, by Alayan: -- Account for the new powerups -- Reduce how much karts in average and bad positions attack each other -- Make it possible to get some powerups by 2 + - Account for the new powerups + - Reduce how much karts in average and bad positions attack each other + - Make it possible to get some powerups by 2 - Avoid basketballs, parachutes, triple zippers with 2 or 3 karts * Introduce a restricted randomness system, that seamlessly reduces streaks of good or bad luck, by Alayan -* Extend the early item timeout to parachute and nitro-hacks, give a zipper instead of a bowling ball, by Alayan +* Extend the early item timeout to parachutes and nitro-hacks, give a zipper instead of a bowling ball, by Alayan * Don't give basketballs if some karts have already finished the race, by Alayan * Replace swatters and bowling balls by gums during the early item timeout phase, by Alayan * Don't apply the early item timeout in non-racing modes, by Alayan @@ -50,20 +60,21 @@ For similar reasons, and because some features are vastly more complex than othe * Reduce the basketball bouncing intervall and make the transition to fast-bounce mode seamless, by Alayan * Prevent basketballs from squashing karts protected by a shield, by Alayan * Make cake speed relative to the user's kart speed, by Alayan -* Make zippers halve the texture slowdown effect, by Alayan +* Give a 50% off-road bonus to zippers (halving the texture slowdown effect), by Alayan * Reduce the max speed boost from the zipper, by Alayan * Enable the "shield restrict weapon" mode for the gum shield: using attacking powerups will drop the shield, by Alayan * New nitro-hack powerup, by Alayan: -- It can steal some nitro from karts ahead. The nitro of karts ahead can become negative as a result. If there is no karts ahead, a small amount of nitro is generated and given. -- It activates a boosted nitro mode, represented by the nitro bar and exhaust turning green instead of blue. -- It appears at a higher rate for players in front, but it is strongest for players at the back. + - It can steal some nitro from karts ahead. The nitro of karts ahead can become negative as a result. If there is no karts ahead, a small amount of nitro is generated and given. + - It activates a boosted nitro mode, represented by the nitro bar and exhaust turning green instead of blue. + - It appears at a higher rate for players in front, but it is strongest for players at the back. * New electro-shield powerup, by Alayan: -- When active, provides a small top speed boost and a huge acceleration boost. -- Also acts as a shield against most threats (not ground gums). It gets disabled upon a hit. + - When active, provides a small top speed boost and a huge acceleration boost. + - Also acts as a shield against most threats (not ground gums). It gets disabled upon a hit. + - Gives a 35% off-road bonus (non-cumulative with other such bonuses) * New mini-wish powerup, by Alayan: -- Gives the player a choice between three weaker versions of standard powerups: zipper, bubblegum and cake. -- The mini-zipper gives less speed, the mini-gum lasts shorter and drops smaller ground gums, the mini-cake is slower and has no area-of-effect. -- The first press locks the mini-item choice, the second uses it. + - Gives the player a choice between three weaker versions of standard powerups: zipper, bubblegum and cake. + - The mini-zipper gives less speed, the mini-gum lasts shorter and drops smaller ground gums, the mini-cake is slower and has no area-of-effect. + - The first press locks the mini-item choice, the second uses it. #### On-track items * Significantly reduce the nitro and gift box respawn times, by Alayan @@ -75,50 +86,103 @@ For similar reasons, and because some features are vastly more complex than othe * Prevent ground gums from being activated if the kart is simply flying above them, by Alayan #### Kart characteristics -* Introduce a new kart class, similar to medium, but with lower speed, better handling and a drift bonus, by Alayan +* Introduce a new kart class, slightly lighter and slower than medium, but with better handling and a drift bonus, by Alayan * Make it more difficult for all kart classes to take curves, and increase the differentiation between kart classes, by Alayan -* Slightly increase the base maximum speed without boosts, by Alayan +* Increase the base maximum speed without boosts (from 26.25 to 28 for heavy karts), by Alayan * Transfer some of the skidding engine power boost to base power, to make drifting less important for quick acceleration, by Alayan * Ensure heavier karts have more total power on first gear for soccer pushing-contests, by Alayan * Make the duration of kart explosions depend on kart class, by Alayan * Make the speed reduction necessary to remove a parachute depend on kart class, by Alayan +* Make the anchor's initial speed loss depend on the kart's weight, by Alayan * Reduce the turn-radius penalty of active drifting, by Alayan * Make the maximum turn-radius during drifting similar for all kart classes, by Alayan +* Make the minimum turn-radius at low speeds more similar for all kart classes, by Alayan * Apply turn-radius limitations to the reverse-gear, by Alayan -* Give a bigger speed boost from nitro the lighter the kart is, instead of the reverse, by Alayan -* Reduce the bonus nitro and nitro fadeout durations, by Alayan +* Rework nitro consumption and boost, by Alayan: + - Make it so that the lighter the kart, the bigger the speed boost (previously, heavier karts got a bigger boost but with much higher consumption) and adjust per-class nitro consumption rates in consequence (helping light karts to use all the nitro they collect) + - Reduce the bonus duration (full-boost lasting beyond active consumption) and the fade-out duration, + - Decrease the base nitro consumption rate, + - Reduce the max nitro stockpile from 20 to 15 * Reduce the speed boost from the first-level (yellow) and second-level (red) drifts, by Alayan * Reduce the duration necessary to trigger a second-level (red) drift, by Alayan -* Introduce a third-level (purple) drift with longer boost and duration, by Alayan +* Introduce a third-level (purple) drift, by Alayan: + - Longer activation time, but higher boost strength and duration + - Also provides a 20% off-road bonus (non-cumulative with other such bonuses) * Prevent skidding bonuses cumulating during fadeout, by Alayan * Prevent kart chassis from colliding into the ground at high speeds, by Alayan * Multiply all engine power boosts by a kart-class specific factor, by Alayan +* Increase turn-radius at a given speed in lower difficulties or with handicap (the turn radius at max speed is still lower than in max difficulty or without handicap), by Alayan +* Make several adjustments in lower difficulty levels, by Alayan: + - Apply a relative decrease to the strength of all speed boosts + - Reduce the nitro consumption rate + - Increase the time required to accumulate the higher level drift boosts +* In lower difficulty + +#### Battle mode +* Remove the minimum kart number and minimum arena size for spare tire karts, by Alayan +* Completely rework the spare tire karts spawn logic and parameters in 3 Strikes Battle, making their spawn more reliable and common, by Alayan + +#### Soccer mode +* Reset kart state after a goal (nitro and held powerup are preserved), by Ban1p7 and Alayan ### General * Double physics FPS from 120 to 240, by Alayan * Make various things, such as item rotation speed and the minimum nitro burst, independent from physics FPS, by Alayan * New powerup audio code, by Alayan: -- Use a shared pool of audio sources to drastically reduce how many are used, and prevent running out of sources -- Don't interrupt a kart's powerup sound effect when collecting or using a new powerup -- Better code organization, avoiding the mixing of gameplay and audio management + - Use a shared pool of audio sources to drastically reduce how many are used, and prevent running out of sources + - Don't interrupt a kart's powerup sound effect when collecting or using a new powerup + - Better code organization, avoiding the mixing of gameplay and audio management * Correctly fetch the number of relevant tracks for achievements, by Alayan * Add new achievements for the completion of egg hunts, by Alayan * Make many more parameters modifiable in configuration files, by Alayan * Remove AbstractKart for cleaner code, by Fouks +* Make checklines taller by default and make their height customizable by track-makers, by Alayan +* Add kart explosion to the effects supported by scripting, by Alayan * A lot of code clean-up, by Alayan ### Graphics * Mix skid particles to warn that the next drifting level is almost ready, by Alayan +* Support for new kart animations, by Alayan: + - New dedicated podium animations that are played on GP podiums + - False start animation that is played if the player gets a start penalty + - Neutral end animation for karts finishing in middle positions, for draw in Soccer or CTF, and for good but not winning positions in FFA + - Hurt animation, for a kart that is hit by an explosion + - Happy animation, for a kart that successfully hits another kart + - Introductory animation in kart selection, played before the main selection loop +* Allow enabling kart headlights for all karts, by Alayan +* Keep the nitro light active as long as there is a nitro speed boost, by Alayan +* Generic support for custom visual variants of kart attachments, by Alayan +* Add support for attachable library nodes, allowing to load complex visual elements independently from the track, by Alayan: + - Load templates for nodes to use as attachable library nodes, which can be copied as needed to create new instances + - Decouple animated texture handling from track +* Allow clearing individual light nodes before the end of the race, by Alayan +* Remove the animated character option, always enabling such animations, by Alayan +* Allow library nodes to use conditional visibility (appearing based on scripting functions such as reverse status, difficulty, etc.), by Alayan +* Other minor enhancements (better display of the bomb's clock handle...) ### User Interface -* Update the kart skill displays (speed, etc.) to handle the new kart characteristics and handicap levels, by Alayan -* Add a drifting skill to the kart skill display, by Alayan +* Update the kart skill displays, by Alayan: + - Handle the new kart characteristics and handicap levels + - Many changes to improve the visual scaling of the values + - Take into account multiple additional factors for the nitro-efficiency skill + - Add a drifting skill #### In-race UI * Support the display of boosted nitro and negative nitro for the Nitro-Hack, by Alayan * New speedometer, that can display a maximum speed of up to 55 (up from 40), by Alayan * Support the display of wide powerup icons, for the Mini-Wish, by Alayan +* In Egg Hunt mode, show collected on the minimap, by TuxFan53 +* Do not display the wrong way message for karts moving very slowly, by Alayan + + +### Tracks and modeling + +#### Tracks +* Support for the preliminary version 8 track format, with backward compatibility to versions 6 and 7 preserved, by Alayan + +#### Karts +* Support for the preliminary version 4 kart format, with backward compatibility to versions 2 and 3 preserved, by Alayan ## SuperTuxKart 1.5.1 @@ -460,7 +524,6 @@ For similar reasons, and because some features are vastly more complex than othe ### Race gameplay and physics * Random spawn point in local battle mode, by Aleman778 -* Add an option to show everyone's items with the left characters icons, by Fouks * Allow to choose the number of AI per team in soccer, by risostk * In CTF mode, fix a bug that prevented scoring a point when the team's flag was in its immunity state, by Alayan * Fix a bug that could result in the finish time being shown as 0:00:00, by Alayan @@ -534,6 +597,7 @@ For similar reasons, and because some features are vastly more complex than othe * Scale down the lap time indicator next to the kart icons when there are many karts, by riso * Limit how long chat and in-race messages can be, by Benau and Alayan * Add an option to disable in-race messages only, by Alayan +* Add an option to show everyone's items with the left characters icons, by Fouks ### Tracks and modeling #### Tracks From 0149308d04200ebdace69c99d850b15d330f0c94 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:44:36 +0200 Subject: [PATCH 10/11] Change the default camera FoV from 80 to 90. - More appropriate default for the most common screen aspect ratios used to run the game, improving vision of the kart's surroundings - Greater feeling of speed --- src/config/user_config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 422ccbb06a5..6a77aac147f 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -1062,7 +1062,7 @@ namespace UserConfigParams "Angle between camera and plane of kart (pitch) when the camera is pointing backwards. This is usually larger than the forward-up-angle, since the kart itself otherwise obstricts too much of the view")); PARAM_PREFIX IntUserConfigParam m_camera_fov - PARAM_DEFAULT( IntUserConfigParam(80, "fov", + PARAM_DEFAULT( IntUserConfigParam(90, "fov", &m_camera_normal, "Focal distance (single player)")); From 0a7ccd55bbb4367e1921c72f3617eb0467f54cf9 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 5 Jun 2026 19:27:50 +0200 Subject: [PATCH 11/11] Use Evolution-specific locations for extra folders The folders for user config, screenshots, replays, cached textures, custom GP and addons now use an Evolution-specific path. Data from previous locations can be safely copied to the new location if needed. An important consequence is that some folders previously shared between 1.x and Evolution installs (list of replays, screenshots, addons, etc.) are not anymore. Also: - Just put the addons folder in the same parent folder as replays, etc. on Windows - Significantly reduce code duplication. It's easier to track if everything is properly updated when we don't repeat a lot of code to create each small folder. - Change the version name from 2.0-git to alpha-git (the 'Evolution' part is implied) - Use 'replays' (plural form) rather than 'replay' Everything worked fine in my Linux testing, but validation on other OSes is needed. --- CMakeLists.txt | 4 +- android/make.sh | 2 +- ...tuxkart.2.0-git => supertuxkart.alpha-git} | 0 src/io/file_manager.cpp | 183 +++++------------- src/io/file_manager.hpp | 8 +- src/utils/string_utils.cpp | 2 +- 6 files changed, 53 insertions(+), 146 deletions(-) rename data/{supertuxkart.2.0-git => supertuxkart.alpha-git} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fae544fb04..9faba687cd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12...4.0) # root CMakeLists for the SuperTuxKart project project(SuperTuxKart) -set(PROJECT_VERSION "2.0-git") +set(PROJECT_VERSION "alpha-git") add_definitions( -DSUPERTUXKART_VERSION="${PROJECT_VERSION}" ) @@ -298,7 +298,7 @@ if (BUILD_RECORDER) find_library(OPENGLRECORDER_LIBRARY NAMES openglrecorder libopenglrecorder PATHS "${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib") find_path(OPENGLRECORDER_INCLUDEDIR NAMES openglrecorder.h PATHS "${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/include") if (NOT OPENGLRECORDER_LIBRARY OR NOT OPENGLRECORDER_INCLUDEDIR) - if(PROJECT_VERSION STREQUAL "2.0-git") + if(PROJECT_VERSION STREQUAL "alpha-git") message(WARNING "libopenglrecorder not found, disabling in-game recorder. " "To use recorder, install libopenglrecorder.") set(OPENGLRECORDER_LIBRARY CACHE INTERNAL "") diff --git a/android/make.sh b/android/make.sh index 8e9e2ba3ba9..308df254d91 100755 --- a/android/make.sh +++ b/android/make.sh @@ -217,7 +217,7 @@ fi if [ -z "$PROJECT_VERSION" ]; then if [ $IS_DEBUG_BUILD -ne 0 ]; then - export PROJECT_VERSION="2.0-git" + export PROJECT_VERSION="alpha-git" else echo "Error: Variable PROJECT_VERSION is not set. It must have unique" \ "value for release build." diff --git a/data/supertuxkart.2.0-git b/data/supertuxkart.alpha-git similarity index 100% rename from data/supertuxkart.2.0-git rename to data/supertuxkart.alpha-git diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index bfc3f6ea51d..402bb9af06b 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -209,7 +209,7 @@ FileManager::FileManager() #ifdef SUPERTUXKART_DATADIR root_dir = SUPERTUXKART_DATADIR"/data/"; #else - root_dir = "/usr/local/share/games/supertuxkart/"; + root_dir = "/usr/local/share/games/supertuxkart-evolution/"; #endif } @@ -230,7 +230,7 @@ FileManager::FileManager() #ifdef MOBILE_STK m_stk_assets_download_dir = getenv("HOME"); #ifdef IOS_STK - m_stk_assets_download_dir += "/Library/Application Support/SuperTuxKart/stk-assets/"; + m_stk_assets_download_dir += "/Library/Application Support/SuperTuxKart-Evolution/stk-assets/"; #elif defined (ANDROID) m_stk_assets_download_dir += "/stk-assets/"; #else @@ -261,12 +261,19 @@ FileManager::FileManager() addRootDirs(assets_dir); } +#if defined(__APPLE__) + bool capitalize = true; +#else + bool capitalize = false; +#endif + checkAndCreateConfigDir(); - checkAndCreateAddonsDir(); - checkAndCreateScreenshotDir(); - checkAndCreateReplayDir(); - checkAndCreateCachedTexturesDir(); - checkAndCreateGPDir(); + checkAndCreateAddonsDir(capitalize); + m_screenshot_dir = checkAndCreateGenericSharedDir(capitalize ? "Screenshots" : "screenshots"); + m_replay_dir = checkAndCreateGenericSharedDir(capitalize ? "Replays" : "replays"); + m_cached_textures_dir = checkAndCreateGenericSharedDir( + capitalize ? "CachedTextures" : "cached-textures", true /* cache dir */); + m_gp_dir = checkAndCreateGenericSharedDir(capitalize ? "GrandPrix" : "grandprix"); redirectOutput(); } // FileManager @@ -1023,7 +1030,7 @@ void FileManager::checkAndCreateConfigDir() else m_user_config_dir = "."; - m_user_config_dir += "/supertuxkart"; + m_user_config_dir += "/supertuxkart-evolution"; #elif defined(__APPLE__) @@ -1040,7 +1047,7 @@ void FileManager::checkAndCreateConfigDir() m_user_config_dir = ""; } m_user_config_dir += "/Library/Application Support/"; - const std::string CONFIGDIR("SuperTuxKart"); + const std::string CONFIGDIR("SuperTuxKart-Evolution"); m_user_config_dir += CONFIGDIR; #elif defined(__HAIKU__) @@ -1055,7 +1062,7 @@ void FileManager::checkAndCreateConfigDir() m_user_config_dir = getenv("HOME"); m_user_config_dir += "/config/settings"; } - m_user_config_dir += "/SuperTuxKart"; + m_user_config_dir += "/SuperTuxKart-Evolution"; #else @@ -1088,7 +1095,7 @@ void FileManager::checkAndCreateConfigDir() m_user_config_dir = getenv("HOME"); } } - m_user_config_dir += "/supertuxkart"; + m_user_config_dir += "/supertuxkart-evolution"; #endif @@ -1097,7 +1104,7 @@ void FileManager::checkAndCreateConfigDir() if(m_user_config_dir.size()>0 && *m_user_config_dir.rbegin()!='/') m_user_config_dir += "/"; - m_user_config_dir += "config-2.X-dev/"; + m_user_config_dir += "config-alpha/"; if(!checkAndCreateDirectoryP(m_user_config_dir)) { Log::warn("FileManager", "Can not create config dir '%s', " @@ -1106,42 +1113,48 @@ void FileManager::checkAndCreateConfigDir() } if (m_stdout_dir.empty()) - { m_stdout_dir = m_user_config_dir; - } return; } // checkAndCreateConfigDir // ---------------------------------------------------------------------------- -/** Creates the directories for the addons data. This will set m_addons_dir - * with the appropriate path, and also create the subdirectories in this - * directory. +/** Creates a subdirectory within the user config path based on the provided folder name */ -void FileManager::checkAndCreateAddonsDir() +std::string FileManager::checkAndCreateGenericSharedDir(std::string shared_folder_name, bool cache_dir) { -#if defined(WIN32) - m_addons_dir = m_user_config_dir+"../addons/"; -#elif defined(__HAIKU__) - m_addons_dir = m_user_config_dir+"addons/"; + std::string full_path = ""; +#if defined(WIN32) || defined(__HAIKU__) + full_path = m_user_config_dir + shared_folder_name + "/"; #elif defined(__APPLE__) - m_addons_dir = getenv("HOME"); - m_addons_dir += "/Library/Application Support/SuperTuxKart/Addons/"; -#elif defined(__HAIKU__) - m_addons_dir = m_user_config_dir+"addons/"; + full_path = getenv("HOME"); + full_path += "/Library/Application Support/SuperTuxKart-Evolution/" + shared_folder_name + "/"; #else - m_addons_dir = checkAndCreateLinuxDir("XDG_DATA_HOME", "supertuxkart", - ".local/share", ".stkaddons"); - m_addons_dir += "addons/"; + std::string home_type = cache_dir ? "XDG_CACHE_HOME" : "XDG_DATA_HOME"; + std::string fallback_dir = cache_dir ? ".cache" : ".local/share"; + full_path = checkAndCreateLinuxDir(home_type.c_str(), "supertuxkart-evolution", + fallback_dir.c_str(), ".stk-evolution"); + full_path += shared_folder_name + "/"; #endif - if(!checkAndCreateDirectory(m_addons_dir)) + if(!checkAndCreateDirectory(full_path)) { - Log::error("FileManager", "Can not create add-ons dir '%s', " - "falling back to '.'.", m_addons_dir.c_str()); - m_addons_dir = "./"; + Log::error("FileManager", "Can not create '%s' directory '%s', " + "falling back to '.'.", shared_folder_name.c_str(), m_screenshot_dir.c_str()); + full_path = "."; } + return full_path; +} // checkAndCreateGenericSharedDir + +// ---------------------------------------------------------------------------- +/** Creates the directories for the addons data. This will set m_addons_dir + * with the appropriate path, and also create the subdirectories in this directory. + */ +void FileManager::checkAndCreateAddonsDir(bool capitalize) +{ + m_addons_dir = checkAndCreateGenericSharedDir(capitalize ? "Addons" : "addons"); + if (!checkAndCreateDirectory(m_addons_dir + "icons/")) { Log::error("FileManager", "Failed to create add-ons icon dir at '%s'.", @@ -1152,112 +1165,8 @@ void FileManager::checkAndCreateAddonsDir() Log::error("FileManager", "Failed to create add-ons tmp dir at '%s'.", (m_addons_dir + "tmp/").c_str()); } - } // checkAndCreateAddonsDir -// ---------------------------------------------------------------------------- -/** Creates the directories for screenshots. This will set m_screenshot_dir - * with the appropriate path. - */ -void FileManager::checkAndCreateScreenshotDir() -{ -#if defined(WIN32) || defined(__HAIKU__) - m_screenshot_dir = m_user_config_dir+"screenshots/"; -#elif defined(__APPLE__) - m_screenshot_dir = getenv("HOME"); - m_screenshot_dir += "/Library/Application Support/SuperTuxKart/Screenshots/"; -#else - m_screenshot_dir = checkAndCreateLinuxDir("XDG_DATA_HOME", "supertuxkart", - ".local/share", ".stkscreenshots"); - m_screenshot_dir += "screenshots/"; -#endif - - if(!checkAndCreateDirectory(m_screenshot_dir)) - { - Log::error("FileManager", "Can not create screenshot directory '%s', " - "falling back to '.'.", m_screenshot_dir.c_str()); - m_screenshot_dir = "."; - } - -} // checkAndCreateScreenshotDir - -// ---------------------------------------------------------------------------- -/** Creates the directories for replay recorded. This will set m_replay_dir - * with the appropriate path. - */ -void FileManager::checkAndCreateReplayDir() -{ -#if defined(WIN32) || defined(__HAIKU__) - m_replay_dir = m_user_config_dir + "replay/"; -#elif defined(__APPLE__) - m_replay_dir = getenv("HOME"); - m_replay_dir += "/Library/Application Support/SuperTuxKart/replay/"; -#else - m_replay_dir = checkAndCreateLinuxDir("XDG_DATA_HOME", "supertuxkart", - ".local/share", ".supertuxkart"); - m_replay_dir += "replay/"; -#endif - - if(!checkAndCreateDirectory(m_replay_dir)) - { - Log::error("FileManager", "Can not create replay directory '%s', " - "falling back to '.'.", m_replay_dir.c_str()); - m_replay_dir = "."; - } - -} // checkAndCreateReplayDir - -// ---------------------------------------------------------------------------- -/** Creates the directories for cached textures. This will set -* m_cached_textures_dir with the appropriate path. -*/ -void FileManager::checkAndCreateCachedTexturesDir() -{ -#if defined(WIN32) || defined(__HAIKU__) - m_cached_textures_dir = m_user_config_dir + "cached-textures/"; -#elif defined(__APPLE__) - m_cached_textures_dir = getenv("HOME"); - m_cached_textures_dir += "/Library/Application Support/SuperTuxKart/CachedTextures/"; -#else - m_cached_textures_dir = checkAndCreateLinuxDir("XDG_CACHE_HOME", "supertuxkart", ".cache/", "."); - m_cached_textures_dir += "cached-textures/"; -#endif - - if (!checkAndCreateDirectory(m_cached_textures_dir)) - { - Log::error("FileManager", "Can not create cached textures directory '%s', " - "falling back to '.'.", m_cached_textures_dir.c_str()); - m_cached_textures_dir = "."; - } - -} // checkAndCreateCachedTexturesDir - -// ---------------------------------------------------------------------------- -/** Creates the directories for user-defined grand prix. This will set m_gp_dir - * with the appropriate path. - */ -void FileManager::checkAndCreateGPDir() -{ -#if defined(WIN32) || defined(__HAIKU__) - m_gp_dir = m_user_config_dir + "grandprix/"; -#elif defined(__APPLE__) - m_gp_dir = getenv("HOME"); - m_gp_dir += "/Library/Application Support/SuperTuxKart/grandprix/"; -#else - m_gp_dir = checkAndCreateLinuxDir("XDG_DATA_HOME", "supertuxkart", - ".local/share", ".supertuxkart"); - m_gp_dir += "grandprix/"; -#endif - - if(!checkAndCreateDirectory(m_gp_dir)) - { - Log::error("FileManager", "Can not create user-defined grand prix directory '%s', " - "falling back to '.'.", m_gp_dir.c_str()); - m_gp_dir = "."; - } - -} // checkAndCreateGPDir - // ---------------------------------------------------------------------------- #if !defined(WIN32) && !defined(__APPLE__) diff --git a/src/io/file_manager.hpp b/src/io/file_manager.hpp index a1cbdede14b..3c861f5509c 100644 --- a/src/io/file_manager.hpp +++ b/src/io/file_manager.hpp @@ -124,11 +124,9 @@ class FileManager : public NoCopy const std::string& fname) const; io::path createAbsoluteFilename(const std::string &f); void checkAndCreateConfigDir(); - void checkAndCreateAddonsDir(); - void checkAndCreateScreenshotDir(); - void checkAndCreateReplayDir(); - void checkAndCreateCachedTexturesDir(); - void checkAndCreateGPDir(); + std::string checkAndCreateGenericSharedDir(std::string shared_folder_name, + bool cache_dir = false); + void checkAndCreateAddonsDir(bool capitalize); void discoverPaths(); void addAssetsSearchPath(); void resetSubdir(); diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index 0a60259fe5c..0d7c4f41f81 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -961,7 +961,7 @@ namespace StringUtils int versionToInt(const std::string &version_string) { // Special case: GIT - if(version_string=="GIT" || version_string=="git" || version_string=="2.0-git") + if(version_string=="GIT" || version_string=="git" || version_string=="alpha-git") { // GIT version will be version 99.99.99i-rcJ return 10000000*99