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 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/config/user_config.hpp b/src/config/user_config.hpp index c817b079a1a..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)")); @@ -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/graphics/attachable_library_manager.cpp b/src/graphics/attachable_library_manager.cpp index bb0a92450aa..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) @@ -95,8 +96,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(); 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; 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/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: 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); diff --git a/src/states_screens/options/options_screen_device.cpp b/src/states_screens/options/options_screen_device.cpp index 2a494e29fea..4f4d42fc171 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,33 +293,55 @@ 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); - - + // 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()) { @@ -327,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; - 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; + *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 // ----------------------------------------------------------------------------- @@ -643,6 +612,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..4e1b10f10c9 100644 --- a/src/states_screens/options/options_screen_device.hpp +++ b/src/states_screens/options/options_screen_device.hpp @@ -60,7 +60,10 @@ class OptionsScreenDevice : public GUIEngine::Screen, void addListItemSubheader(GUIEngine::ListWidget* actions, 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; 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(); 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