diff --git a/CMakeLists.txt b/CMakeLists.txt index cb5caa1ad..431d35273 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8.4) # root CMakeLists for the SuperTuxKart project project(SuperTuxKart) set(PROJECT_VERSION "git") +add_definitions( -DSUPERTUXKART_VERSION="${PROJECT_VERSION}" ) if(NOT (CMAKE_MAJOR_VERSION VERSION_LESS 3)) cmake_policy(SET CMP0043 OLD) diff --git a/README.md b/README.md index 972109cc0..2996aa843 100644 --- a/README.md +++ b/README.md @@ -64,13 +64,13 @@ mesa-common-dev pkg-config zlib1g-dev ``` ### In-game recorder -In order to build the in-game recorder for STK, you have to install +To build the in-game recorder for STK, you have to install libopenglrecorder from your distribution, or compile it yourself from [here](https://github.com/Benau/libopenglrecorder). Compilation instruction is explained there. If you don't need this feature, pass `-DBUILD_RECORDER=off` to cmake. ### Compiling -Run the following commands inside `stk-code` directory to compile SuperTuxKart: +To compile SuperTuxKart, run the following commands inside `stk-code` directory: ```bash mkdir cmake_build @@ -80,6 +80,21 @@ make -j4 ``` STK can then be run from the build directory with `bin/supertuxkart` +#### Keeping your build up to date + +To recompile the latest code without redownloading the entire source, first run the ```svn up``` command inside the 'stk-assets' directory, then run the following commands inside the 'stk-code' directory: + +```bash +git pull +cd cmake_build +cmake .. +make -j4 +``` + +##### Build Speed Optimization + +"-j4" is an example, for a faster build, use "-jx" instead, where "x" is the amount of CPU threads you have, minus one. + ### Further options To create a debug version of STK, run: @@ -106,7 +121,7 @@ location, specify `CMAKE_INSTALL_PREFIX` when running cmake, e.g.: To Build SuperTuxKart on Windows, follow these instructions: 1. Download and install Visual Studio from here: [Visual Studio - Download](https://www.visualstudio.com/downloads/). The free Visual Studio Community edition works fine. -2. Download the SuperTuxKart source package from either [SuperTuxKart download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart/0.9.2) or [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), and unpack it. +2. Download the SuperTuxKart source package from either [SuperTuxKart download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart/) or [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), and unpack it. *Note: If you downloaded the source package from here: [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), then both `stk-code` and `stk-assets` **must** be in the same directory, otherwise the build can result in failure* 3. Download the Windows dependencies package from either [SuperTuxKart download area: Dependencies - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/Windows/) or [SuperTuxKart on GitHub - Dependencies](https://github.com/supertuxkart/dependencies), and unpack it; then, copy the `dependencies` directory from either the `windows` or the `windows_64bit` directories into the `stk-code` directory, rename it to `dependencies-64bit` if you want to compile a 64bit build. diff --git a/android/Android.mk b/android/Android.mk index 947ca5490..37b5d33da 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -162,8 +162,9 @@ LOCAL_CFLAGS := -I../lib/angelscript/include \ -DUSE_GLES2 \ -DHAVE_OGGVORBIS \ -DNDEBUG \ - -DANDROID_PACKAGE_NAME=\"$(PACKAGE_NAME)\" \ - -DANDROID_APP_DIR_NAME=\"$(APP_DIR_NAME)\" \ + -DANDROID_PACKAGE_NAME=\"$(PACKAGE_NAME)\" \ + -DANDROID_APP_DIR_NAME=\"$(APP_DIR_NAME)\" \ + -DSUPERTUXKART_VERSION=\"$(PROJECT_VERSION)\" \ -std=gnu++0x LOCAL_STATIC_LIBRARIES := irrlicht bullet enet freetype ifaddrs angelscript \ diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 017c35414..3a3af85ee 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,8 +1,8 @@ @@ -12,7 +12,8 @@ android:hasCode="false" android:isGame="true" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" - android:hardwareAccelerated="true"> + android:hardwareAccelerated="true" + android:resizeableActivity="false"> + android:targetSdkVersion="26" /> diff --git a/android/README.ANDROID b/android/README.ANDROID index 3577506b8..334ce4a38 100644 --- a/android/README.ANDROID +++ b/android/README.ANDROID @@ -101,6 +101,14 @@ SDK_PATH - Path to SDK directory NDK_PATH - Path to NDK directory +PROJECT_VERSION - Set Supertuxkart version number, for example "0.9.3" or + "git20170409" or whatever. + Default is: git. + +PROJECT_CODE - Set Supertuxkart version code that is used in the manifest + file. + Default is: 1. + -------------------------------------------------------------------------------- @@ -110,29 +118,13 @@ NDK_PATH - Path to NDK directory Making a release build is similar to typical compilation, but there are few additional things to do. -You have to change version numbers. This is important, because assets manager -in STK checks these numbers and detects if already extracted data files are +You have to set PROJECT_VERSION variable. This is important, because assets +manager in STK checks that value and detects if already extracted data files are up to date. So that when you will install new STK version, this will force new data extraction automatically. -So that you have to: - -1. Change "data/supertuxkart.git" to "data/supertuxkart.VERSION_NUMBER" - -2. Open "src/utils/constants.cpp" and change: - - const char STK_VERSION[] = "git"; - - to - - const char STK_VERSION[] = "VERSION_NUMBER"; - - where "VERSION_NUMBER" is for example "0.9.3" or "git20170409" or whatever. - -3. You can also update these lines in "android/AndroidManifest.xml": - android:versionCode="1" - android:versionName="1.0" - +The PROJECT_CODE variable typically should be set to a value higher than for +previous release, so that users will receive the upgrade. Before compilation you have to set: diff --git a/android/generate_assets.sh b/android/generate_assets.sh index 5225867e6..75b8811ca 100755 --- a/android/generate_assets.sh +++ b/android/generate_assets.sh @@ -180,6 +180,9 @@ convert_image() echo "Couldn't convert $FILE file" return fi + + SCALE_CMD="" + QUALITY_CMD="" if [ $W -gt $TEXTURE_SIZE ] || [ $H -gt $TEXTURE_SIZE ]; then if [ $W -gt $H ]; then diff --git a/android/make.sh b/android/make.sh index 4b10ed86e..f79d018d5 100755 --- a/android/make.sh +++ b/android/make.sh @@ -23,32 +23,32 @@ export ARCH_ARMV7=arm export HOST_ARMV7=arm-linux-androideabi export NDK_PLATFORM_ARMV7=android-19 export MIN_SDK_VERSION_ARMV7=19 -export TARGET_SDK_VERSION_ARMV7=21 -export COMPILE_SDK_VERSION_ARMV7=21 +export TARGET_SDK_VERSION_ARMV7=26 +export COMPILE_SDK_VERSION_ARMV7=26 export NDK_ABI_AARCH64=arm64-v8a export ARCH_AARCH64=arm64 export HOST_AARCH64=aarch64-linux-android export NDK_PLATFORM_AARCH64=android-21 export MIN_SDK_VERSION_AARCH64=21 -export TARGET_SDK_VERSION_AARCH64=21 -export COMPILE_SDK_VERSION_AARCH64=21 +export TARGET_SDK_VERSION_AARCH64=26 +export COMPILE_SDK_VERSION_AARCH64=26 export NDK_ABI_X86=x86 export ARCH_X86=x86 export HOST_X86=i686-linux-android export NDK_PLATFORM_X86=android-19 export MIN_SDK_VERSION_X86=19 -export TARGET_SDK_VERSION_X86=21 -export COMPILE_SDK_VERSION_X86=21 +export TARGET_SDK_VERSION_X86=26 +export COMPILE_SDK_VERSION_X86=26 export NDK_ABI_X86_64=x86_64 export ARCH_X86_64=x86_64 export HOST_X86_64=x86_64-linux-android export NDK_PLATFORM_X86_64=android-21 export MIN_SDK_VERSION_X86_64=21 -export TARGET_SDK_VERSION_X86_64=21 -export COMPILE_SDK_VERSION_X86_64=21 +export TARGET_SDK_VERSION_X86_64=26 +export COMPILE_SDK_VERSION_X86_64=26 export APP_NAME_RELEASE="SuperTuxKart" export PACKAGE_NAME_RELEASE="org.supertuxkart.stk" @@ -232,6 +232,47 @@ if [ -z "$BUILD_TOOLS_VER" ] || [ ! -d "$SDK_PATH/build-tools/$BUILD_TOOLS_VER" exit fi +# Set project version and code +if [ -f "$DIRNAME/obj/project_version" ]; then + PROJECT_VERSION_PREV=$(cat "$DIRNAME/obj/project_version") + + if [ -z "$PROJECT_VERSION" ]; then + PROJECT_VERSION="$PROJECT_VERSION_PREV" + elif [ "$PROJECT_VERSION" != "$PROJECT_VERSION_PREV" ]; then + echo "Different project version has been set. Forcing recompilation..." + touch -c "$DIRNAME/Android.mk" + fi +fi + +if [ -z "$PROJECT_VERSION" ]; then + if [ $IS_DEBUG_BUILD -ne 0 ]; then + PROJECT_VERSION="git" + else + echo "Error: Variable PROJECT_VERSION is not set. It must have unique" \ + "value for release build." + exit + fi +fi + +if [ -z "$PROJECT_CODE" ]; then + if [ $IS_DEBUG_BUILD -ne 0 ]; then + PROJECT_CODE="1" + else + echo "Error: Variable PROJECT_CODE is not set." + exit + fi +fi + +if [ -d "$DIRNAME/assets/data" ]; then + if [ ! -f "$DIRNAME/assets/data/supertuxkart.$PROJECT_VERSION" ]; then + echo "Error: supertuxkart.$PROJECT_VERSION doesn't exist in" \ + "assets/data directory." + exit + fi +fi + +echo "$PROJECT_VERSION" > "$DIRNAME/obj/project_version" + # Standalone toolchain if [ ! -f "$DIRNAME/obj/make_standalone_toolchain.stamp" ]; then @@ -425,6 +466,12 @@ sed -i "s/targetSdkVersion=\".*\"/targetSdkVersion=\"$TARGET_SDK_VERSION\"/g" \ sed -i "s/package=\".*\"/package=\"$PACKAGE_NAME\"/g" \ "$DIRNAME/AndroidManifest.xml" +sed -i "s/versionName=\".*\"/versionName=\"$PROJECT_VERSION\"/g" \ + "$DIRNAME/AndroidManifest.xml" + +sed -i "s/versionCode=\".*\"/versionCode=\"$PROJECT_CODE\"/g" \ + "$DIRNAME/AndroidManifest.xml" + cp "banner.png" "$DIRNAME/res/drawable/banner.png" cp "$APP_ICON" "$DIRNAME/res/drawable/icon.png" convert -scale 72x72 "$APP_ICON" "$DIRNAME/res/drawable-hdpi/icon.png" diff --git a/data/CREDITS b/data/CREDITS index 7d79df42d..ccbfcb7f2 100644 --- a/data/CREDITS +++ b/data/CREDITS @@ -1,6 +1,6 @@ = SuperTuxKart = A Kart Racing Game Featuring Tux & Friends -- Version git +- Version $STKVERSION$ - Visit us at supertuxkart.net - SuperTuxKart is released under GPL 3.0 - Assets are released under Creative Commons and other licenses diff --git a/data/challenges/startrack.challenge b/data/challenges/startrack.challenge index 80f317d86..446eecd46 100644 --- a/data/challenges/startrack.challenge +++ b/data/challenges/startrack.challenge @@ -1,7 +1,7 @@ - + diff --git a/data/gui/License.txt b/data/gui/License.txt index adb4c4c30..b541f8d09 100644 --- a/data/gui/License.txt +++ b/data/gui/License.txt @@ -24,7 +24,11 @@ title_font, by Marianne Gagnon (Auria), released under CC-BY-SA 3+ screen*.png, by Marianne Gagnon (Auria), including elements from the public domain Tango icon set -Gauge and bar by Totoplus62, released under CC-BY-SA 3 +speed.png by Alayan, with elements by Totoplus62, released under CC-BY-SA 3 + +speed*.png by Alayan, released under CC-0 + +gauge*.png by Alayan, released under CC-0 menu_story by tavariz91, released under CC-0 diff --git a/data/gui/android/license.txt b/data/gui/android/license.txt index a033d7a6c..002b89c02 100644 --- a/data/gui/android/license.txt +++ b/data/gui/android/license.txt @@ -2,7 +2,7 @@ Icons firstly made for SuperTuxKart UI on Android. -Files: blur_bg_button ; blur_bg_button_focus ; directionnal_wheel ; drift ; nitro ; nitro_empty ; pause ; thunderbird_reset ; wing_mirror +Files: blur_bg_button ; blur_bg_button_focus ; steering_wheel ; drift ; nitro ; nitro_empty ; pause ; thunderbird_reset ; wing_mirror - CC BY-SA 4.0 / author: Néd J. Édoire # License information: diff --git a/data/gui/android/directionnal_wheel.png b/data/gui/android/steering_wheel.png similarity index 100% rename from data/gui/android/directionnal_wheel.png rename to data/gui/android/steering_wheel.png diff --git a/data/gui/android/up_down.png b/data/gui/android/up_down.png new file mode 100644 index 000000000..e03381a4f Binary files /dev/null and b/data/gui/android/up_down.png differ diff --git a/data/gui/gauge_empty.png b/data/gui/gauge_empty.png index acdf74b73..394f38957 100644 Binary files a/data/gui/gauge_empty.png and b/data/gui/gauge_empty.png differ diff --git a/data/gui/gauge_full.png b/data/gui/gauge_full.png index 7db7e74d4..05e9061ea 100644 Binary files a/data/gui/gauge_full.png and b/data/gui/gauge_full.png differ diff --git a/data/gui/gauge_full_bright.png b/data/gui/gauge_full_bright.png index fe1c55256..973e14768 100644 Binary files a/data/gui/gauge_full_bright.png and b/data/gui/gauge_full_bright.png differ diff --git a/data/gui/gauge_goal.png b/data/gui/gauge_goal.png index 51184cf66..57a9a1508 100644 Binary files a/data/gui/gauge_goal.png and b/data/gui/gauge_goal.png differ diff --git a/data/gui/init_android.stkgui b/data/gui/init_android.stkgui index 6e565b836..81d9c13c9 100644 --- a/data/gui/init_android.stkgui +++ b/data/gui/init_android.stkgui @@ -2,18 +2,21 @@
- - - + + - + - + + + + + diff --git a/data/gui/speed.png b/data/gui/speed.png index 5655239f1..ebcc5133b 100644 Binary files a/data/gui/speed.png and b/data/gui/speed.png differ diff --git a/data/gui/speedback.png b/data/gui/speedback.png index 25a50110f..ffbebbc5c 100644 Binary files a/data/gui/speedback.png and b/data/gui/speedback.png differ diff --git a/data/gui/speedfore.png b/data/gui/speedfore.png index 2bf8e0fdc..053017ebc 100644 Binary files a/data/gui/speedfore.png and b/data/gui/speedfore.png differ diff --git a/data/kart_characteristics.xml b/data/kart_characteristics.xml index c7fd9ad7c..17d8969f9 100644 --- a/data/kart_characteristics.xml +++ b/data/kart_characteristics.xml @@ -312,21 +312,27 @@ max-speed-increase="5" duration="1" fade-out-time="2" max="20" /> - + @@ -360,9 +366,8 @@ invulnerability-time="7" /> - + - + - + diff --git a/data/po/ar.po b/data/po/ar.po index 8b283bf0a..048fd3bce 100644 --- a/data/po/ar.po +++ b/data/po/ar.po @@ -6,6 +6,7 @@ # Benamara Mohamed , 2015 # FIRST AUTHOR , 2011 # Ibrahim Al-Darra , 2017 +# A.Karim S., 2018 # Moaaz Mohamed , 2017 # صفا الفليج , 2015 msgid "" @@ -13,8 +14,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Ibrahim Al-Darra \n" +"PO-Revision-Date: 2018-01-14 08:54+0000\n" +"Last-Translator: A.Karim S.\n" "Language-Team: Arabic (http://www.transifex.com/supertuxkart/supertuxkart/language/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -40,7 +41,7 @@ msgstr "اضرب 10 عربات بكرة بولنغ." #. I18N: ./data/achievements.xml msgid "Arch Enemy" -msgstr "عدوّ الأقواس" +msgstr "عدو القوس" #. I18N: ./data/achievements.xml msgid "Hit the same kart at least 5 times in one race." @@ -118,7 +119,7 @@ msgstr "ساحة لعب البطاريق" #. I18N: ./data/grandprix/2_offthebeatentrack.grandprix msgid "Off the beaten track" -msgstr "" +msgstr "استثنائي" #. I18N: ./data/grandprix/3_tothemoonandback.grandprix msgid "To the moon and back" @@ -297,7 +298,7 @@ msgstr "الإضاءة قائمة على الصورة" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Bloom" -msgstr "" +msgstr "تفتح" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -307,7 +308,7 @@ msgstr "أعمدة النور (أشعة الله)" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient Occlusion" -msgstr "" +msgstr "إنسداد المحيطة" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -357,12 +358,12 @@ msgstr "شخصيّات متحرّكة" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Rendered image quality" -msgstr "" +msgstr "جودة الصورة المصيرة" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Geometry detail" -msgstr "" +msgstr "تفاصيل الهندسة" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -466,7 +467,7 @@ msgstr "تابع" #. I18N: ./data/gui/track_info.stkgui #. I18N: In the track info screen msgid "Record the race for ghost replay" -msgstr "" +msgstr "تسجيل السباق لشبح الاعادة" #. I18N: ./data/gui/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action @@ -487,7 +488,7 @@ msgstr "ابدأ السّباق" #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Ghost Replay Selection" -msgstr "" +msgstr "إختيار شبح الإعادة" #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -497,7 +498,7 @@ msgstr "الاقتصار على إظهار إعادات موافقة لمستو #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Record ghost replay" -msgstr "" +msgstr "تسجيل شبح الإعادة" #. I18N: ./data/gui/gp_info.stkgui #. I18N: In the grand prix info screen @@ -610,7 +611,7 @@ msgstr "أوضاع اللعب" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Multi-player" -msgstr "" +msgstr "متعدد اللاعبين" #. I18N: ./data/gui/help1.stkgui #. I18N: Tab in help menu @@ -623,11 +624,11 @@ msgstr "" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Bananas" -msgstr "" +msgstr "موز" #. I18N: ./data/gui/help1.stkgui msgid "Start the tutorial" -msgstr "" +msgstr "بدء الدورة التعليمية" #. I18N: ./data/gui/help1.stkgui #. I18N: In the help menu @@ -744,7 +745,7 @@ msgstr "اتبع المتزعّم: اسعَ إلى المرتبة الثّاني #. I18N: In the help menu msgid "" "3 Strikes Battle: Hit others with weapons until they lose all their lives." -msgstr "" +msgstr "معركة 3 ضربات: إضرب الآخرين بالأسلحة حتى يفقدو كل أرواحهم" #. I18N: ./data/gui/help3.stkgui #. I18N: In the help menu @@ -799,24 +800,24 @@ msgstr "" msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" -msgstr "" +msgstr "الإرتطام بموزة يمكن أن يؤدي إلى تعلق أحد الأشياء التالية بالكارت:" #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart." -msgstr "" +msgstr "المرساة - تبطيء الكارت كثيرا" #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Parachute - slows down the kart less than the anchor." -msgstr "" +msgstr "مظلة - تبطيء الكارت قليلا" #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after a short amount of time to throw the kart up in the " "air. Bump into another kart to transfer the bomb to another player." -msgstr "" +msgstr "قنبلة - تنفجر بعد فترة قصيرة من الوقت لترمي الكارت في الهواء. إصدم كارت آخر لنقل القنبلة إلى لاعب آخر." #. I18N: ./data/gui/karts.stkgui #. I18N: In the kart selection (player setup) screen @@ -849,7 +850,7 @@ msgstr "متعدّدة اللاعبين" #: src/states_screens/main_menu_screen.cpp:78 #: src/states_screens/online_profile_friends.cpp:222 msgid "Online" -msgstr "" +msgstr "عبر الإنترنت" #. I18N: ./data/gui/main_menu.stkgui #. I18N: Main menu button @@ -905,46 +906,46 @@ msgstr "أنهِ" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Touch Device Settings" -msgstr "" +msgstr "إعدادات جهاز اللمس" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Device enabled" -msgstr "" +msgstr "جهاز مفعّل" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Inverted buttons" -msgstr "" +msgstr "أزرار مقلوبة" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "" +msgstr "أزرار السلّم" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Accelerometer" -msgstr "" +msgstr "مقياس التسارع" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "" +msgstr "متقدم" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Deadzone" -msgstr "" +msgstr "منطقة مقطوعة" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Sensitivity" -msgstr "" +msgstr "حساسية" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Restore defaults" -msgstr "" +msgstr "استعادة الضبط الافتراضي" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog @@ -973,7 +974,7 @@ msgstr "أكّد" #. I18N: ./data/gui/online/recovery_input.stkgui #. I18N: In the recovery dialog msgid "Submit" -msgstr "" +msgstr "سلّم" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog @@ -1169,7 +1170,7 @@ msgstr "اخرج" #. I18N: ./data/gui/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View" -msgstr "" +msgstr "المنظر" #. I18N: ./data/gui/online/profile_achievements.stkgui #. I18N: ./data/gui/online/profile_achievements_tab.stkgui @@ -1205,11 +1206,11 @@ msgstr "نظرة عامّة" #. I18N: Section in the profile screen #: src/states_screens/online_profile_base.cpp:110 msgid "Servers" -msgstr "" +msgstr "الخوادم" #. I18N: ./data/gui/online/profile_servers.stkgui msgid "Local Networking" -msgstr "" +msgstr "الشبكة المحلية" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen @@ -1224,12 +1225,12 @@ msgstr "أنشئ خادومًا" #. I18N: ./data/gui/online/profile_servers.stkgui msgid "Global Networking" -msgstr "" +msgstr "الشبكة العامة" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen msgid "Quick Play" -msgstr "" +msgstr "لعب سريع" #. I18N: ./data/gui/online/profile_settings.stkgui #. I18N: Section in the profile screen @@ -1502,7 +1503,7 @@ msgstr "أنت تلعب مثل" #. I18N: ./data/gui/options_players.stkgui #. I18N: In the player configuration screen msgid "Press enter or double-click on a player to edit their settings" -msgstr "" +msgstr "إضغط على ENTER أو نقر مزدوج فوق لاعب لتعديل إعداداته" #. I18N: ./data/gui/options_players.stkgui #. I18N: In the player configuration screen @@ -1757,7 +1758,7 @@ msgstr "احذف" #. I18N: ../stk-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" -msgstr "" +msgstr "هاوية أنتيدلوفيان" #. I18N: ../stk-assets/tracks/battleisland/track.xml msgid "Battle Island" @@ -1765,7 +1766,7 @@ msgstr "جزيرة النّزال" #. I18N: ../stk-assets/tracks/candela_city/track.xml msgid "Candela City" -msgstr "" +msgstr "مدينة كانديلا" #. I18N: ../stk-assets/tracks/cave/track.xml msgid "Cave X" @@ -1777,7 +1778,7 @@ msgstr "معبد الكاكّاو" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" -msgstr "" +msgstr "معبر كورنفيلد" #. I18N: ../stk-assets/tracks/fortmagma/track.xml msgid "Fort Magma" @@ -1797,12 +1798,12 @@ msgstr "المزرعة" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" -msgstr "" +msgstr "ملعب كرة القدم الجليدي" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" -msgstr "" +msgstr "ما المشكلة؟ قائدك العظيم نو مفقود؟" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml @@ -1828,7 +1829,7 @@ msgstr "ولكنّك أيّها الغبيّ الصّغير المثير للش #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "حلبة لاس دوناس" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the lighthouse" @@ -1884,7 +1885,7 @@ msgstr "المعبد" #. I18N: ../stk-assets/tracks/volcano_island/track.xml msgid "Volcan Island" -msgstr "" +msgstr "جزيرة البركان" #. I18N: ../stk-assets/tracks/xr591/track.xml msgid "XR591" @@ -1924,7 +1925,7 @@ msgstr "هكسلي" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "كيكي" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" @@ -1964,7 +1965,7 @@ msgstr "ويلبر" #. I18N: ../stk-assets/karts/xue/kart.xml msgid "Xue" -msgstr "" +msgstr "كزو" #: src/achievements/achievement.cpp:209 #, c-format @@ -1985,7 +1986,7 @@ msgstr "خطأ في تنزيل الأخبار: '%s'." #: src/states_screens/race_result_gui.cpp:1424 #, c-format msgid "Laps: %i" -msgstr "" +msgstr "لفات: %i" #: src/challenges/challenge_data.cpp:272 msgid "Follow the leader" @@ -2045,16 +2046,16 @@ msgstr "ملفّ ضبطك كان قديمًا جدًّا، لذلك حُذف و #: src/graphics/irr_driver.cpp:535 msgid "Video recording started." -msgstr "" +msgstr "بدأ تسجيل الفيديو" #: src/graphics/irr_driver.cpp:541 #, c-format msgid "Video saved in \"%s\"." -msgstr "" +msgstr "تم حفظ الفيديو خلال \"%s\"." #: src/graphics/irr_driver.cpp:545 msgid "Encoding progress:" -msgstr "" +msgstr "تقدم الترميز:" #: src/graphics/irr_driver.cpp:1682 #, c-format @@ -2110,98 +2111,98 @@ msgstr "زرّ الفأرة الأوسط" #: src/input/binding.cpp:122 msgctxt "input_key" msgid "X1 Mouse Button" -msgstr "" +msgstr "س1 زر الفأرة" #. I18N: input configuration screen: mouse button #: src/input/binding.cpp:124 msgctxt "input_key" msgid "X2 Mouse Button" -msgstr "" +msgstr "س2 زر الفأرة" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:126 msgctxt "input_key" msgid "Backspace" -msgstr "" +msgstr "Backspace" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:128 msgctxt "input_key" msgid "Tab" -msgstr "" +msgstr "Tab" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:130 msgctxt "input_key" msgid "Clear" -msgstr "" +msgstr "Clear" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:132 msgctxt "input_key" msgid "Return" -msgstr "" +msgstr "Return" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:134 msgctxt "input_key" msgid "Shift" -msgstr "" +msgstr "Shift" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:136 msgctxt "input_key" msgid "Control" -msgstr "" +msgstr "Ctrl" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:138 msgctxt "input_key" msgid "Alt/Menu" -msgstr "" +msgstr "Alt/Menu" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:140 msgctxt "input_key" msgid "Pause" -msgstr "" +msgstr "Pause" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:142 msgctxt "input_key" msgid "Caps Lock" -msgstr "" +msgstr "Caps Lock" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:144 msgctxt "input_key" msgid "Kana" -msgstr "" +msgstr "كانا" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:146 msgctxt "input_key" msgid "Junja" -msgstr "" +msgstr "جونجا" #. I18N: input configuration screen: keyboard key #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:149 msgctxt "input_key" msgid "Final" -msgstr "" +msgstr "النهائي" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:151 msgctxt "input_key" msgid "Escape" -msgstr "" +msgstr "Escape" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:153 msgctxt "input_key" msgid "Convert" -msgstr "" +msgstr "Convert" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:155 @@ -2225,67 +2226,67 @@ msgstr "" #: src/input/binding.cpp:161 msgctxt "input_key" msgid "Space" -msgstr "" +msgstr "Space" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:163 msgctxt "input_key" msgid "Page Up" -msgstr "" +msgstr "Page Up" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:165 msgctxt "input_key" msgid "Page Down" -msgstr "" +msgstr "Page Down" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:167 msgctxt "input_key" msgid "End" -msgstr "" +msgstr "End" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:169 msgctxt "input_key" msgid "Home" -msgstr "" +msgstr "Home" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:171 msgctxt "input_key" msgid "Left" -msgstr "" +msgstr "يسار" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:173 msgctxt "input_key" msgid "Up" -msgstr "" +msgstr "أعلى" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:175 msgctxt "input_key" msgid "Right" -msgstr "" +msgstr "يمين" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:177 msgctxt "input_key" msgid "Down" -msgstr "" +msgstr "أسفل" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:179 msgctxt "input_key" msgid "Select" -msgstr "" +msgstr "Select" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:181 msgctxt "input_key" msgid "Print" -msgstr "" +msgstr "طبع" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:183 @@ -2297,37 +2298,37 @@ msgstr "" #: src/input/binding.cpp:185 msgctxt "input_key" msgid "Print Screen" -msgstr "" +msgstr "طبع الشاشة" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:187 msgctxt "input_key" msgid "Insert" -msgstr "" +msgstr "Insert" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:189 msgctxt "input_key" msgid "Delete" -msgstr "" +msgstr "حذف" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:191 msgctxt "input_key" msgid "Help" -msgstr "" +msgstr "مساعدة" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:229 msgctxt "input_key" msgid "Left Logo" -msgstr "" +msgstr "الشعار الأيسر" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:231 msgctxt "input_key" msgid "Right Logo" -msgstr "" +msgstr "الشعار الأيمن" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:233 @@ -2339,7 +2340,7 @@ msgstr "" #: src/input/binding.cpp:235 msgctxt "input_key" msgid "Sleep" -msgstr "" +msgstr "Sleep" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:237 @@ -2411,7 +2412,7 @@ msgstr "" #: src/input/binding.cpp:261 msgctxt "input_key" msgid "- (Subtract)" -msgstr "" +msgstr "- (الطرح)" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:263 @@ -2423,61 +2424,61 @@ msgstr "" #: src/input/binding.cpp:265 msgctxt "input_key" msgid "/ (Divide)" -msgstr "" +msgstr "/ (القسمة)" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:291 msgctxt "input_key" msgid "Num Lock" -msgstr "" +msgstr "Num Lock" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:293 msgctxt "input_key" msgid "Scroll Lock" -msgstr "" +msgstr "Scroll Lock" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:295 msgctxt "input_key" msgid "Left Shift" -msgstr "" +msgstr "Shift الأيسر" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:297 msgctxt "input_key" msgid "Right Shift" -msgstr "" +msgstr "Shift الأيمن" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:299 msgctxt "input_key" msgid "Left Control" -msgstr "" +msgstr "Ctrl الأيسر" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:301 msgctxt "input_key" msgid "Right Control" -msgstr "" +msgstr "Ctrl الأيمن" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:303 msgctxt "input_key" msgid "Left Menu" -msgstr "" +msgstr "Menu الأيسر" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:305 msgctxt "input_key" msgid "Right Menu" -msgstr "" +msgstr "Menu الأيمن" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:311 msgctxt "input_key" msgid "Attn" -msgstr "" +msgstr "Attn" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:313 @@ -2501,13 +2502,13 @@ msgstr "" #: src/input/binding.cpp:319 msgctxt "input_key" msgid "Play" -msgstr "" +msgstr "لعب" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:321 msgctxt "input_key" msgid "Zoom" -msgstr "" +msgstr "تكبير" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:323 @@ -2519,7 +2520,7 @@ msgstr "" #: src/input/binding.cpp:325 msgctxt "input_key" msgid "Oem Clear" -msgstr "" +msgstr "OEM Clear" #. I18N: to appear in input configuration screen, for gamepad hats #: src/input/binding.cpp:334 src/input/binding.cpp:339 @@ -2588,102 +2589,102 @@ msgstr "أبيض" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:179 src/input/gamepad_config.cpp:239 msgid "Left trigger" -msgstr "" +msgstr "المحفز الأيسر" #. I18N: name of buttons on gamepads #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:181 src/input/gamepad_config.cpp:244 msgid "Right thumb right" -msgstr "" +msgstr "الإبهام الأيمن إلى اليمين" #. I18N: name of buttons on gamepads #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:183 src/input/gamepad_config.cpp:246 msgid "Right thumb left" -msgstr "" +msgstr "الإبهام الأيمن إلى اليسار" #. I18N: name of buttons on gamepads #. I18N: name of trigger on gamepads #: src/input/gamepad_config.cpp:185 src/input/gamepad_config.cpp:240 msgid "Right thumb down" -msgstr "" +msgstr "الإبهام الأيمن إلى الأسفل" #. I18N: name of buttons on gamepads #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:187 src/input/gamepad_config.cpp:242 msgid "Right thumb up" -msgstr "" +msgstr "الإبهام الأيمن إلى الأعلى" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:189 src/input/gamepad_config.cpp:248 msgid "Right trigger" -msgstr "" +msgstr "المحفز الأيمن" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:191 src/input/gamepad_config.cpp:253 msgid "DPad right" -msgstr "" +msgstr "دي-باد يمين" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:193 src/input/gamepad_config.cpp:255 msgid "DPad left" -msgstr "" +msgstr "دي-باد يسار" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:195 src/input/gamepad_config.cpp:251 msgid "DPad down" -msgstr "" +msgstr "دي-باد أسفل" #. I18N: name of buttons on gamepads #. I18N: name of trigger on gamepads #: src/input/gamepad_config.cpp:197 src/input/gamepad_config.cpp:249 msgid "DPad up" -msgstr "" +msgstr "دي-باد أعلى" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:212 msgid "Left bumper" -msgstr "" +msgstr "ماص الصدمات الأيسر" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:214 msgid "Right bumper" -msgstr "" +msgstr "ماص الصدمات الأيمن" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:218 msgid "Start" -msgstr "" +msgstr "إبدأ" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:220 msgid "Left thumb button" -msgstr "" +msgstr "زر الإبهام الأيسر" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:222 msgid "Right thumb button" -msgstr "" +msgstr "زر الإبهام الأيمن" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:231 msgid "Left thumb right" -msgstr "" +msgstr "الإبهام الأيسر إلى اليمين" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:233 msgid "Left thumb left" -msgstr "" +msgstr "الإبهام الأيسر إلى اليسار" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:235 msgid "Left thumb down" -msgstr "" +msgstr "الإبهام الأيسر إلى الأسفل" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:237 msgid "Left thumb up" -msgstr "" +msgstr "الإبهام الأيسر إلى الأعلى" #: src/input/input_manager.cpp:807 #, c-format @@ -2731,11 +2732,11 @@ msgstr "لا تتسارع قبل إشارة الإطلاق" #: src/karts/controller/spare_tire_ai.cpp:147 msgid "You can have at most 3 lives!" -msgstr "" +msgstr "يمكنك الحصول على 3 أرواح على الأكثر!" #: src/karts/controller/spare_tire_ai.cpp:153 msgid "+1 life." -msgstr "" +msgstr "+1 روح" #: src/karts/kart.cpp:908 src/karts/kart.cpp:913 msgid "You won the race!" @@ -2758,7 +2759,7 @@ msgstr "" #: src/main.cpp:1654 msgid "Your screen resolution is too low to run STK." -msgstr "" +msgstr "ميز الشاشة منخفض جدا لتشغيل اللعبة." #: src/main.cpp:1668 msgid "" @@ -2798,7 +2799,7 @@ msgstr "%s لِـ %s" #: src/modes/linear_world.cpp:374 msgid "New fastest lap" -msgstr "" +msgstr "أسرع لفة جديدة" #: src/modes/linear_world.cpp:891 msgid "WRONG WAY!" @@ -2808,12 +2809,12 @@ msgstr "الاتّجاه الخطأ!" #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" +msgstr[0] "تم إنتاج %i إطار إحتياطي للكارت" +msgstr[1] "تم إنتاج %i إطار إحتياطي للكارت" +msgstr[2] "تم إنتاج %i إطاران إحتياطيان للكارت" +msgstr[3] "تم إنتاج %i إطارات إحتياطية للكارت" +msgstr[4] "تم إنتاج %i إطار إحتياطي للكارت" +msgstr[5] "تم إنتاج %i إطار إحتياطي للكارت" #: src/modes/world.cpp:1202 msgid "You have been eliminated!" @@ -2827,11 +2828,11 @@ msgstr "لقد استُبعد '%s'." #: src/network/protocols/server_lobby.cpp:318 #, c-format msgid "Failed to register server: %s" -msgstr "" +msgstr "أخفق تسجيل الخادم: %s" #: src/network/servers_manager.cpp:198 msgid "No LAN server detected" -msgstr "" +msgstr "لم يتم اكتشاف أي خادم لان" #: src/online/online_player_profile.cpp:419 #, c-format @@ -2913,12 +2914,12 @@ msgstr "كرة قدم" #: src/replay/replay_recorder.cpp:183 msgid "Incomplete replay file will not be saved." -msgstr "" +msgstr "ملف الإعادة غير المكتمل لن يتم حفظه." #: src/replay/replay_recorder.cpp:219 #, c-format msgid "Replay saved in \"%s\"." -msgstr "" +msgstr "تم حفظ الإعادة خلال \"%s\"." #: src/states_screens/addons_screen.cpp:50 msgid "1 week" @@ -2964,7 +2965,7 @@ msgstr "تاريخ التّحديث" msgid "" "Access to the Internet is disabled. (To enable it, go to options and select " "tab 'User Interface')" -msgstr "" +msgstr "الإتصال بالأنترنت معطل. (لتفعيله، إنتقل إلى الخيارات وإختر التبويب 'واجهة المستخدم')" #. I18N: as in: The Old Island by Johannes Sjolund #: src/states_screens/addons_screen.cpp:343 @@ -3014,16 +3015,16 @@ msgstr "حلبة عشوائية" #, c-format msgid "%d arena unavailable in single player." msgid_plural "%d arenas unavailable in single player." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" +msgstr[0] "%d حلبة غير متوفرة عند اللعب الإنفرادي. " +msgstr[1] "%d حلبة غير متوفرة عند اللعب الإنفرادي." +msgstr[2] "%d حلبتان غير متوفرة عند اللعب الإنفرادي. " +msgstr[3] "%d حلبات غير متوفرة عند اللعب الإنفرادي. " +msgstr[4] "%d حلبة غير متوفرة عند اللعب الإنفرادي. " +msgstr[5] "%d حلبة غير متوفرة عند اللعب الإنفرادي." #: src/states_screens/create_server_screen.cpp:82 msgid "Create LAN Server" -msgstr "" +msgstr "إنشاء خادم لان" #: src/states_screens/create_server_screen.cpp:87 #, c-format @@ -3164,7 +3165,7 @@ msgstr "معطّل" #: src/states_screens/dialogs/custom_video_settings.cpp:67 #: src/states_screens/options_screen_video.cpp:462 msgid "Important only" -msgstr "" +msgstr "مهم فقط" #. I18N: animations setting (only karts with human players are animated) #: src/states_screens/dialogs/custom_video_settings.cpp:74 @@ -3183,7 +3184,7 @@ msgstr "ممكّن للكلّ" #: src/states_screens/dialogs/custom_video_settings.cpp:102 #: src/states_screens/options_screen_video.cpp:469 msgid "Low" -msgstr "" +msgstr "منخفظ" #. I18N: Geometry level high : everything is displayed #. I18N: in the graphical options tooltip; @@ -3193,21 +3194,21 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:103 #: src/states_screens/options_screen_video.cpp:472 msgid "High" -msgstr "" +msgstr "مرتفع" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very low #: src/states_screens/dialogs/custom_video_settings.cpp:94 #: src/states_screens/options_screen_video.cpp:466 msgid "Very Low" -msgstr "" +msgstr "منخفظ جدا" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very high #: src/states_screens/dialogs/custom_video_settings.cpp:97 #: src/states_screens/options_screen_video.cpp:475 msgid "Very High" -msgstr "" +msgstr "مرتفع جدا" #: src/states_screens/dialogs/message_dialog.cpp:129 #: src/states_screens/edit_gp_screen.cpp:257 @@ -3217,11 +3218,11 @@ msgstr "لا" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:60 msgid "Tablet" -msgstr "" +msgstr "حاسوب لوحي" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:61 msgid "Phone" -msgstr "" +msgstr "هاتف" #: src/states_screens/dialogs/recovery_dialog.cpp:121 msgid "Username and/or email address invalid." @@ -3264,7 +3265,7 @@ msgstr "تحدّي نيترو" #: src/states_screens/dialogs/select_challenge.cpp:151 #: src/states_screens/race_setup_screen.cpp:136 msgid "Ghost replay race" -msgstr "" +msgstr "سباق شبح الإعادة" #: src/states_screens/dialogs/server_info_dialog.cpp:75 msgid "Server successfully created. You can now join it." @@ -3309,7 +3310,7 @@ msgstr "يجلب آخر تصويت" #: src/states_screens/dialogs/vote_dialog.cpp:190 msgid "You can adapt your previous rating by clicking the stars beneath." -msgstr "" +msgstr "يمكنك تكييف التقييم السابق من خلال النقر على النجوم في الأسفل." #: src/states_screens/dialogs/vote_dialog.cpp:195 msgid "" @@ -3323,7 +3324,7 @@ msgstr "نجح التّصويت! يمكنك إغلاق النّافذة." #: src/states_screens/dialogs/vote_dialog.cpp:247 msgid "Performing vote" -msgstr "" +msgstr "إجراء التصويت" #: src/states_screens/easter_egg_screen.cpp:270 #: src/states_screens/tracks_and_gp_screen.cpp:292 @@ -3401,11 +3402,11 @@ msgstr "لقد أزلت قفل سباق الجائزة الكبرى %0" #: src/states_screens/ghost_replay_selection.cpp:82 msgid "Finish Time" -msgstr "" +msgstr "وقت الإنتهاء" #: src/states_screens/ghost_replay_selection.cpp:83 msgid "User" -msgstr "" +msgstr "مستخدم" #: src/states_screens/gp_info_screen.cpp:74 msgid "Default" @@ -3479,7 +3480,7 @@ msgstr "مقفل" msgid "" "Everyone:\n" "Press the 'Select' button to join the game" -msgstr "" +msgstr "الجميع:\nإضغطو على زر 'Select' للإنضمام إلى اللعبة" #: src/states_screens/main_menu_screen.cpp:510 msgid "" @@ -3635,7 +3636,7 @@ msgstr "إلباث اللعبة" #. I18N: Key binding name #: src/states_screens/options_screen_device.cpp:250 msgid "Up" -msgstr "الأعلى" +msgstr "أعلى" #. I18N: Key binding name #: src/states_screens/options_screen_device.cpp:253 @@ -3695,7 +3696,7 @@ msgstr "أجهزة لمس" msgid "" "In multiplayer mode, players can select handicapped (more difficult) " "profiles on the kart selection screen" -msgstr "" +msgstr "في وضع متعددة اللاعبين، يمكن إختيار تشكيلات الإعاقة (أكثر صعوبة) على شاشة اختيار الكارت" #. I18N: in the language choice, to select the same language as the OS #: src/states_screens/options_screen_ui.cpp:191 @@ -3749,13 +3750,13 @@ msgstr "غشاوة الحركة: %s" #: src/states_screens/options_screen_video.cpp:501 #, c-format msgid "Anti-aliasing: %s" -msgstr "" +msgstr "تنعيم: %s" #. I18N: in graphical options #: src/states_screens/options_screen_video.cpp:504 #, c-format msgid "Ambient occlusion: %s" -msgstr "" +msgstr "إنسداد المحيطة: %s" #: src/states_screens/options_screen_video.cpp:508 #, c-format @@ -3771,7 +3772,7 @@ msgstr "الظّلال: %i" #: src/states_screens/options_screen_video.cpp:513 #, c-format msgid "Bloom: %s" -msgstr "" +msgstr "تفتح: %s" #. I18N: in graphical options #: src/states_screens/options_screen_video.cpp:517 @@ -3783,7 +3784,7 @@ msgstr "التّوهّج (الحدود): %s" #: src/states_screens/options_screen_video.cpp:521 #, c-format msgid "Light shaft (God rays): %s" -msgstr "" +msgstr "شعاع الضوء (إشعاعات الغسق): %s" #. I18N: in graphical options #: src/states_screens/options_screen_video.cpp:525 @@ -3800,7 +3801,7 @@ msgstr "الإضاءة العموميّة: %s" #: src/states_screens/options_screen_video.cpp:534 #, c-format msgid "Rendered image quality: %s" -msgstr "" +msgstr "جودة الصورة المصيرة: %s" #: src/states_screens/race_gui.cpp:358 src/states_screens/race_gui.cpp:360 msgid "Challenge Failed" @@ -3857,7 +3858,7 @@ msgstr "الرّتبة" #: src/states_screens/race_gui_overworld.cpp:518 msgid "Press fire to start the tutorial" -msgstr "" +msgstr "اضغط على إطلاق لبدء الدورة التعليمية" #: src/states_screens/race_gui_overworld.cpp:557 msgid "Type: Grand Prix" @@ -3920,7 +3921,7 @@ msgstr "إنّه تعادل" #: src/states_screens/race_result_gui.cpp:1098 #: src/states_screens/race_result_gui.cpp:1154 msgid "(Own Goal)" -msgstr "" +msgstr "(هدف خاص)" #: src/states_screens/race_result_gui.cpp:1220 #, c-format @@ -3938,12 +3939,12 @@ msgstr "النّتائج العليا" #: src/states_screens/race_result_gui.cpp:1432 #, c-format msgid "Difficulty: %s" -msgstr "" +msgstr "الصعوبة: %s" #: src/states_screens/race_result_gui.cpp:1440 #, c-format msgid "Best lap time: %s" -msgstr "" +msgstr "أفضل وقت للفة: %s" #: src/states_screens/race_setup_screen.cpp:87 msgid "All blows allowed, so catch weapons and make clever use of them!" @@ -3972,7 +3973,7 @@ msgstr "استكشف المسارات للعثور على كلّ البيضات #: src/states_screens/race_setup_screen.cpp:137 msgid "Race against ghost karts and try to beat them!" -msgstr "" +msgstr "سابق ضد أشباح الكارت وحاول التغلب عليهم!" #: src/states_screens/register_screen.cpp:218 #: src/states_screens/register_screen.cpp:225 @@ -4045,7 +4046,7 @@ msgstr "مسار لِـ %s" #: src/states_screens/track_info_screen.cpp:120 #, c-format msgid "Max players supported: %d" -msgstr "" +msgstr "الحد الأقصى لعدد اللاعبين: %d" #. I18N: In the track info screen #: src/states_screens/track_info_screen.cpp:213 @@ -4055,7 +4056,7 @@ msgstr "تسابق بالعكس" #. I18N: In the track info screen #: src/states_screens/track_info_screen.cpp:218 msgid "Random item location" -msgstr "" +msgstr "موقع الشيء عشوائي" #: src/states_screens/user_screen.cpp:111 msgid "Exit game" @@ -4125,7 +4126,7 @@ msgstr "اجمع صناديق الهدايا وأطلق السّلاح بِـ <% msgid "" "Press <%s> to look behind. Fire the weapon with <%s> while pressing <%s> to " "fire behind!" -msgstr "" +msgstr "إضغط على <%s> للنظر إلى الخلف. إرمي السلاح بواسطة <%s> أثناء الضغط على <%s> للرمي من الخلف!" #: ../stk-assets/tracks/tutorial/scripting.as:53 #: ../stk-assets/tracks/tutorial/triggers.as:54 diff --git a/data/po/be.po b/data/po/be.po index 682c92451..4b912d232 100644 --- a/data/po/be.po +++ b/data/po/be.po @@ -4,14 +4,14 @@ # # Translators: # , 2015 -# Viktar Vauchkevich, 2017 +# Viktar Vauchkevich, 2017-2018 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-01-18 18:02+0000\n" +"Last-Translator: Viktar Vauchkevich\n" "Language-Team: Belarusian (http://www.transifex.com/supertuxkart/supertuxkart/language/be/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -49,7 +49,7 @@ msgstr "Марафонец" #. I18N: ./data/achievements.xml msgid "Make a race with 5 laps or more." -msgstr "Зрабі гонку на 5 ці больш кругоў." +msgstr "Зрабі гонку на 5 ці больш колаў." #. I18N: ./data/achievements.xml msgid "Skid-row" @@ -57,7 +57,7 @@ msgstr "Дрыфтэр" #. I18N: ./data/achievements.xml msgid "Make 5 skidding in a single lap." -msgstr "Зрабі 5 заносаў за 1 круг." +msgstr "Зрабі 5 заносаў за 1 кола." #. I18N: ./data/achievements.xml msgid "Gold driver" @@ -274,7 +274,7 @@ msgstr "Стваральнікі" #. I18N: ./data/gui/custom_video_settings.stkgui msgid "Graphics Settings" -msgstr "Настаўленні графікі" +msgstr "Налады графікі" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -299,7 +299,7 @@ msgstr "Зіхаценне (Bloom)" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Light shaft (God rays)" -msgstr "Промні святла" +msgstr "Промні святла (гало)" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -354,17 +354,17 @@ msgstr "Анімацыя персанажаў" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Rendered image quality" -msgstr "" +msgstr "Якасць апрацаванай выявы" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Geometry detail" -msgstr "" +msgstr "Дэталі геаметрыі" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "* Restart STK to apply new settings" -msgstr "* Перазапусціце STK, каб ужыць новыя настаўленні" +msgstr "* Перазапусціце STK, каб ужыць новыя налады" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: ./data/gui/multitouch_settings.stkgui @@ -620,11 +620,11 @@ msgstr "Сумесная гульня" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Bananas" -msgstr "" +msgstr "Бананы" #. I18N: ./data/gui/help1.stkgui msgid "Start the tutorial" -msgstr "" +msgstr "Пачаць навучанне" #. I18N: ./data/gui/help1.stkgui #. I18N: In the help menu @@ -656,7 +656,7 @@ msgstr "Калі вы бачыце замок, то гэта азначае, ш #. I18N: ./data/gui/help1.stkgui #. I18N: in the help menu msgid "The 'skidding' key allows you to skid in sharp turns and get a boost." -msgstr "Кнопка «заноса» дазваляе слізгаць у крутым павароце і атрымаць паскарэнне." +msgstr "Кнопка «заносу» дазваляе слізгаць у крутым павароце і атрымаць паскарэнне." #. I18N: ./data/gui/help1.stkgui #. I18N: in the help screen @@ -796,24 +796,24 @@ msgstr "Пасля настройкі прылад увода вы гатовы msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" -msgstr "" +msgstr "Наезд на банан прывядзе да далучэння да карта аднаго з наступных прадметаў:" #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart." -msgstr "" +msgstr "Якар запавольвае карт." #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Parachute - slows down the kart less than the anchor." -msgstr "" +msgstr "Парашут запавольвае карт менш, чым якар." #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after a short amount of time to throw the kart up in the " "air. Bump into another kart to transfer the bomb to another player." -msgstr "" +msgstr "Бомба ўзрываецца пасля кароткага прамежку часу і падкідвае карт у паветра. Ударце іншы карт каб перадаць бомбу іншаму гульцу." #. I18N: ./data/gui/karts.stkgui #. I18N: In the kart selection (player setup) screen @@ -902,46 +902,46 @@ msgstr "Выйсці" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Touch Device Settings" -msgstr "" +msgstr "Налады сэнсарнай прылады" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Device enabled" -msgstr "" +msgstr "Пралада ўключаная" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Inverted buttons" -msgstr "" +msgstr "Інвертаваныя кнопкі" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "" +msgstr "Маштаб кнопак" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Accelerometer" -msgstr "" +msgstr "Паскарэнне" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "" +msgstr "Пашыраныя" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Deadzone" -msgstr "" +msgstr "Мёртвая зона" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Sensitivity" -msgstr "" +msgstr "Адчувальнасць" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Restore defaults" -msgstr "" +msgstr "Аднавіць агаданыя" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog @@ -1232,7 +1232,7 @@ msgstr "Хуткая гульня" #. I18N: Section in the profile screen #: src/states_screens/online_profile_base.cpp:113 msgid "Account Settings" -msgstr "Настаўленні конта" +msgstr "Налады конту" #. I18N: ./data/gui/online/profile_settings.stkgui #. I18N: In the online account settings screen @@ -1248,7 +1248,7 @@ msgstr "Змяніць" #. I18N: ./data/gui/online/recovery_input.stkgui #. I18N: In the recovery dialog msgid "Account Recovery" -msgstr "Аднаўленне конта" +msgstr "Аднаўленне конту" #. I18N: ./data/gui/online/recovery_info.stkgui #. I18N: In the recovery dialog @@ -1326,7 +1326,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at http://privacy.supertuxkart.net" -msgstr "Вы можаце гуляць без стварэння анлайн-конта, выбраўшы афлайн-конт. Але пры гэтым вы не зможаце злучыцца з сябрамі, галасаваць за дадаткі і інш. Азнаёмцеся з нашай заявай аб канфідэнцыйнасці на http://privacy.supertuxkart.net" +msgstr "Вы можаце гуляць без стварэння анлайн-конту, выбраўшы афлайн-конт. Але пры гэтым вы не зможаце злучыцца з сябрамі, галасаваць за дадаткі і інш. Азнаёмцеся з нашай заявай аб канфідэнцыйнасці на http://privacy.supertuxkart.net" #. I18N: ./data/gui/online/registration_terms.stkgui #. I18N: In the registration dialog @@ -1564,7 +1564,7 @@ msgstr "Узровень графічных эфектаў" #. I18N: ./data/gui/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." -msgstr "Свае настаўленні" +msgstr "Асабістыя налады…" #. I18N: ./data/gui/options_video.stkgui #. I18N: In the video settings @@ -1762,7 +1762,7 @@ msgstr "Баявая выспа" #. I18N: ../stk-assets/tracks/candela_city/track.xml msgid "Candela City" -msgstr "" +msgstr "Горад Кандэла" #. I18N: ../stk-assets/tracks/cave/track.xml msgid "Cave X" @@ -1774,7 +1774,7 @@ msgstr "Храм какавы" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" -msgstr "" +msgstr "Кукурузнае перакрыжаванне" #. I18N: ../stk-assets/tracks/fortmagma/track.xml msgid "Fort Magma" @@ -1799,7 +1799,7 @@ msgstr "Ледзяное футбольнае поле" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" -msgstr "Штосці не так, маленькі хіпі? Твой вялікі гну лідар знік?" +msgstr "Штосці не так, маленькі хіпі? Твой вялікі лідар гну знік?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml @@ -1825,7 +1825,7 @@ msgstr "Але ты, гаротны валацуга, ніколі не змож #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Лас-Дунас-Арэна" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the lighthouse" @@ -1921,7 +1921,7 @@ msgstr "Хекслі" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "Кікі" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" @@ -1970,7 +1970,7 @@ msgstr "Завершанае дасягненне «%s»." #: src/addons/addons_manager.cpp:104 src/addons/news_manager.cpp:322 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "" +msgstr "Не атрымалася злучыцца з северам дадаткаў SuperTuxKart." #: src/addons/news_manager.cpp:179 #, c-format @@ -2042,16 +2042,16 @@ msgstr "Ваш файл канфігурацыі занадта стары. Ён #: src/graphics/irr_driver.cpp:535 msgid "Video recording started." -msgstr "" +msgstr "Пачаўся запіс відэа." #: src/graphics/irr_driver.cpp:541 #, c-format msgid "Video saved in \"%s\"." -msgstr "" +msgstr "Відэа захаванае ў «%s»." #: src/graphics/irr_driver.cpp:545 msgid "Encoding progress:" -msgstr "" +msgstr "Прагрэс кадавання:" #: src/graphics/irr_driver.cpp:1682 #, c-format @@ -2726,11 +2726,11 @@ msgstr "Не едзьце да сігналу!" #: src/karts/controller/spare_tire_ai.cpp:147 msgid "You can have at most 3 lives!" -msgstr "" +msgstr "Вы можаце мець максімум 3 жыцці!" #: src/karts/controller/spare_tire_ai.cpp:153 msgid "+1 life." -msgstr "" +msgstr "+1 жыццё." #: src/karts/kart.cpp:908 src/karts/kart.cpp:913 msgid "You won the race!" @@ -2753,7 +2753,7 @@ msgstr "SuperTuxKart можа падлучацца да сервера, каб #: src/main.cpp:1654 msgid "Your screen resolution is too low to run STK." -msgstr "" +msgstr "Разрозненне вашага экрана занадта малое для STK." #: src/main.cpp:1668 msgid "" @@ -2803,10 +2803,10 @@ msgstr "НЯПРАВІЛЬНЫ НАПРАМАК!" #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" +msgstr[0] "%i запаска для карта з'явілася!" +msgstr[1] "%i запаскі для карта з'явіліся!" +msgstr[2] "%i запасак для карта з'явілася!" +msgstr[3] "%i запасак для карта з'явілася!" #: src/modes/world.cpp:1202 msgid "You have been eliminated!" @@ -2820,7 +2820,7 @@ msgstr "«%s» дыскваліфікаваны." #: src/network/protocols/server_lobby.cpp:318 #, c-format msgid "Failed to register server: %s" -msgstr "" +msgstr "Не атрымалася зарэгістраваць сервер: %s" #: src/network/servers_manager.cpp:198 msgid "No LAN server detected" @@ -3149,7 +3149,7 @@ msgstr "Адключана" #: src/states_screens/dialogs/custom_video_settings.cpp:67 #: src/states_screens/options_screen_video.cpp:462 msgid "Important only" -msgstr "" +msgstr "Толькі важнае" #. I18N: animations setting (only karts with human players are animated) #: src/states_screens/dialogs/custom_video_settings.cpp:74 @@ -3168,7 +3168,7 @@ msgstr "Для ўсіх" #: src/states_screens/dialogs/custom_video_settings.cpp:102 #: src/states_screens/options_screen_video.cpp:469 msgid "Low" -msgstr "" +msgstr "Нізкі" #. I18N: Geometry level high : everything is displayed #. I18N: in the graphical options tooltip; @@ -3178,21 +3178,21 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:103 #: src/states_screens/options_screen_video.cpp:472 msgid "High" -msgstr "" +msgstr "Высокі" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very low #: src/states_screens/dialogs/custom_video_settings.cpp:94 #: src/states_screens/options_screen_video.cpp:466 msgid "Very Low" -msgstr "" +msgstr "Вельмі нізкі" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very high #: src/states_screens/dialogs/custom_video_settings.cpp:97 #: src/states_screens/options_screen_video.cpp:475 msgid "Very High" -msgstr "" +msgstr "Вельмі высокі" #: src/states_screens/dialogs/message_dialog.cpp:129 #: src/states_screens/edit_gp_screen.cpp:257 @@ -3202,11 +3202,11 @@ msgstr "Не" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:60 msgid "Tablet" -msgstr "" +msgstr "Планшэт" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:61 msgid "Phone" -msgstr "" +msgstr "Тэлефон" #: src/states_screens/dialogs/recovery_dialog.cpp:121 msgid "Username and/or email address invalid." @@ -3220,7 +3220,7 @@ msgid "" "the box below, you are confirming that you understand these terms. If you " "have any questions or comments regarding these terms, one of the members of " "the development team would gladly assist you." -msgstr "" +msgstr "Калі ласка, азнаёмцеся з умовамі карыстання SuperTuxKart на «%s». Вы павінны пагадзіцца з гэтымі ўмовамі для таго, каб зарэгістраваць конт для STK. Усталяваўшы сцяжок ніжэй, вы пацвярджаеце, што вы разумееце гэтыя ўмовы. Калі вы маеце пытанні ці каменты адносна ўмоў, адзін з чальцоў каманды распрацоўнікаў з задавальненнем дапаможа вам." #: src/states_screens/dialogs/select_challenge.cpp:52 #, c-format @@ -3390,7 +3390,7 @@ msgstr "Час фінішу" #: src/states_screens/ghost_replay_selection.cpp:83 msgid "User" -msgstr "" +msgstr "Карыстальнік" #: src/states_screens/gp_info_screen.cpp:74 msgid "Default" @@ -3674,7 +3674,7 @@ msgstr "Клавіятура %i" #: src/states_screens/options_screen_input.cpp:138 msgid "Touch Device" -msgstr "" +msgstr "Сэнсарная прылада" #: src/states_screens/options_screen_ui.cpp:159 msgid "" @@ -3785,7 +3785,7 @@ msgstr "Глабальнае асвятленне: %s" #: src/states_screens/options_screen_video.cpp:534 #, c-format msgid "Rendered image quality: %s" -msgstr "" +msgstr "Якасць апрацаванай выявы: %s" #: src/states_screens/race_gui.cpp:358 src/states_screens/race_gui.cpp:360 msgid "Challenge Failed" @@ -3842,7 +3842,7 @@ msgstr "Ранг" #: src/states_screens/race_gui_overworld.cpp:518 msgid "Press fire to start the tutorial" -msgstr "" +msgstr "Націсніце Атаку, каб пачаць навучанне" #: src/states_screens/race_gui_overworld.cpp:557 msgid "Type: Grand Prix" @@ -3989,7 +3989,7 @@ msgstr "Некарэктны Email!" msgid "" "You will receive an email with further instructions regarding account " "activation. Please be patient and be sure to check your spam folder." -msgstr "Вы атрымаеце электронны ліст з далейшымі інструкцыямі для актывацыі конта. Калі ласка, будзьце церпялівымі і не забудзьце праверыць тэчку са спамам." +msgstr "Вы атрымаеце электронны ліст з далейшымі інструкцыямі для актывацыі конту. Калі ласка, будзьце церпялівымі і не забудзьце праверыць тэчку са спамам." #: src/states_screens/register_screen.cpp:402 #: src/states_screens/user_screen.cpp:338 @@ -4133,7 +4133,7 @@ msgstr "Ой! Калі ў вас праблемы, націсніце <%s> дл msgid "" "Accelerate and press the <%s> key while turning to skid. Skidding for a " "short while can help you turn faster to take sharp turns." -msgstr "Разганіцеся і націсніце <%s> пад час заноса. Коўзанне дапаможа вам прайсць крутыя павароты хутчэй." +msgstr "Разганіцеся і націсніце <%s> пад час заносу. Коўзанне дапаможа вам прайсць крутыя павароты хутчэй." #: ../stk-assets/tracks/tutorial/scripting.as:77 #: ../stk-assets/tracks/tutorial/triggers.as:78 diff --git a/data/po/br.po b/data/po/br.po index 49ca97cf5..bd760b722 100644 --- a/data/po/br.po +++ b/data/po/br.po @@ -6,7 +6,7 @@ # Alan Monfort , 2015-2016 # FIRST AUTHOR , 2013 # Gwenn M , 2015 -# Irriep Nala Novram , 2017 +# Irriep Nala Novram , 2017-2018 # Irriep Nala Novram , 2016 # Irriep Nala Novram , 2016 msgid "" @@ -14,8 +14,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-01-08 18:45+0000\n" +"Last-Translator: Irriep Nala Novram \n" "Language-Team: Breton (http://www.transifex.com/supertuxkart/supertuxkart/language/br/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -624,11 +624,11 @@ msgstr "Liesc'hoarier" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Bananas" -msgstr "" +msgstr "Bananez" #. I18N: ./data/gui/help1.stkgui msgid "Start the tutorial" -msgstr "" +msgstr "Kregiñ gant an tutorial" #. I18N: ./data/gui/help1.stkgui #. I18N: In the help menu @@ -931,21 +931,21 @@ msgstr "" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "" +msgstr "Aroakaet" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Deadzone" -msgstr "" +msgstr "Zonennvarv" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Sensitivity" -msgstr "" +msgstr "Kizidigezh" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Restore defaults" -msgstr "" +msgstr "Adderaouekaat" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog @@ -1766,7 +1766,7 @@ msgstr "Enezenn ar gad" #. I18N: ../stk-assets/tracks/candela_city/track.xml msgid "Candela City" -msgstr "" +msgstr "Kêr Gandela" #. I18N: ../stk-assets/tracks/cave/track.xml msgid "Cave X" @@ -1925,7 +1925,7 @@ msgstr "Heksley" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" @@ -2732,7 +2732,7 @@ msgstr "" #: src/karts/controller/spare_tire_ai.cpp:153 msgid "+1 life." -msgstr "" +msgstr "+1 vuhez." #: src/karts/kart.cpp:908 src/karts/kart.cpp:913 msgid "You won the race!" @@ -3160,7 +3160,7 @@ msgstr "Gweredekaet evit an holl anezho" #: src/states_screens/dialogs/custom_video_settings.cpp:102 #: src/states_screens/options_screen_video.cpp:469 msgid "Low" -msgstr "" +msgstr "Izel" #. I18N: Geometry level high : everything is displayed #. I18N: in the graphical options tooltip; @@ -3170,21 +3170,21 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:103 #: src/states_screens/options_screen_video.cpp:472 msgid "High" -msgstr "" +msgstr "Uhel" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very low #: src/states_screens/dialogs/custom_video_settings.cpp:94 #: src/states_screens/options_screen_video.cpp:466 msgid "Very Low" -msgstr "" +msgstr "Izel-kenañ" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very high #: src/states_screens/dialogs/custom_video_settings.cpp:97 #: src/states_screens/options_screen_video.cpp:475 msgid "Very High" -msgstr "" +msgstr "Uhel-kenañ" #: src/states_screens/dialogs/message_dialog.cpp:129 #: src/states_screens/edit_gp_screen.cpp:257 @@ -3194,11 +3194,11 @@ msgstr "Ket" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:60 msgid "Tablet" -msgstr "" +msgstr "Tabletezenn" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:61 msgid "Phone" -msgstr "" +msgstr "Pellgomz" #: src/states_screens/dialogs/recovery_dialog.cpp:121 msgid "Username and/or email address invalid." @@ -3382,7 +3382,7 @@ msgstr "Amzer echuiñ" #: src/states_screens/ghost_replay_selection.cpp:83 msgid "User" -msgstr "" +msgstr "Implijer" #: src/states_screens/gp_info_screen.cpp:74 msgid "Default" diff --git a/data/po/cs.po b/data/po/cs.po index d78647800..c2a446927 100644 --- a/data/po/cs.po +++ b/data/po/cs.po @@ -4,7 +4,7 @@ # # Translators: # Jakub Vaněk , 2015-2016 -# Pavel Borecki , 2015-2017 +# Pavel Borecki , 2015-2018 # ToMáš Marný, 2015 # ToMáš Marný, 2015-2016 msgid "" @@ -12,8 +12,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: ToMáš Marný\n" +"PO-Revision-Date: 2018-01-02 07:15+0000\n" +"Last-Translator: Pavel Borecki \n" "Language-Team: Czech (http://www.transifex.com/supertuxkart/supertuxkart/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2049,7 +2049,7 @@ msgstr "Zahájeno nahrávání videa." #: src/graphics/irr_driver.cpp:541 #, c-format msgid "Video saved in \"%s\"." -msgstr "Video uloženo do \"%s\"." +msgstr "Video uloženo do „%s“." #: src/graphics/irr_driver.cpp:545 msgid "Encoding progress:" @@ -2058,7 +2058,7 @@ msgstr "Průběh enkódování:" #: src/graphics/irr_driver.cpp:1682 #, c-format msgid "FPS: %d/%d/%d - %d KTris" -msgstr "FPS: %d/%d/%d - %d tisíc trojúhelníků" +msgstr "Sním./s.: %d/%d/%d – %d tisíc trojúhelníků" #: src/guiengine/engine.cpp:1296 msgid "Loading" @@ -2687,7 +2687,7 @@ msgstr "Levý palec nahoru" #: src/input/input_manager.cpp:807 #, c-format msgid "Ignoring '%s'. You needed to join earlier to play!" -msgstr "Ignoruji '%s'. Musíte se do hry připojit dříve!" +msgstr "„%s“ je ignorováno. Abyste se mohli zúčastnit, je třeba se do hry připojit dříve!" #: src/input/input_manager.cpp:837 msgid "Only the Game Master may act at this point!" @@ -2697,13 +2697,13 @@ msgstr "V tomto okamžiku může jednat pouze hráč zakládající hru!" msgid "" "Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " "instructions at supertuxkart.net/Wiimote" -msgstr "Připojte svůj Wiimote ovladač do správce Bluetooth a poté klikněte na tlačítko Budiž. Podrobný návod je na supertuxkart.net/Wiimote" +msgstr "Připojte svůj Wiimote ovladač do správce Bluetooth a poté klikněte na tlačítko OK. Podrobný návod je na supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:391 msgid "" "Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " "mode, then click on Ok. Detailed instructions at supertuxkart.net/Wiimote" -msgstr "Stiskněte současně tlačítka 1 + 2 na vašem Wiimote ovladači, přepnete jej do režimu vyhledávání, poté klikněte na tlačítko Budiž. Podrobný návod je na supertuxkart.net/Wiimote" +msgstr "Stiskněte současně tlačítka 1 + 2 na svém Wiimote ovladači, přepnete jej do režimu vyhledávání, poté klikněte na tlačítko Budiž. Podrobný návod je na supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:414 #, c-format @@ -2775,7 +2775,7 @@ msgstr "Vejce: %d / %d" #: src/modes/follow_the_leader.cpp:62 src/modes/follow_the_leader.cpp:285 msgid "Leader" -msgstr "Vůdce" +msgstr "Vedoucí" #: src/modes/linear_world.cpp:287 msgid "Final lap!" @@ -2866,7 +2866,7 @@ msgstr "Máte novou žádost o kamarádství!" msgid "" "Unable to connect to the server. Check your internet connection or try again" " later." -msgstr "Nelze se připojit k serveru. Zkontrolujte své připojení k internetu a případně\npřed dalším pokusem zkuste počkat." +msgstr "Nelze se připojit k serveru. Zkontrolujte své připojení k Internetu a případně\npřed dalším pokusem zkuste počkat." #: src/race/grand_prix_data.hpp:171 msgid "Random Grand Prix" @@ -2881,7 +2881,7 @@ msgstr "Soubor s nejvyšším skóre byl příliš starý,\nvšechna nejvyšší #. I18N: Game mode #: src/race/race_manager.hpp:179 msgid "Follow the Leader" -msgstr "Následujte vůdce" +msgstr "Následujte vedoucího" #. I18N: Game mode #: src/race/race_manager.hpp:181 @@ -2991,7 +2991,7 @@ msgstr "standardní" #: src/states_screens/kart_selection.cpp:1481 #: src/states_screens/race_setup_screen.cpp:99 msgid "Locked : solve active challenges to gain access to more!" -msgstr "Zamčeno: splň aktivní výzvy k získání přístupu!" +msgstr "Zamčeno: splňte aktivní výzvy k získání přístupu!" #: src/states_screens/arenas_screen.cpp:339 msgid "Random Arena" diff --git a/data/po/de.po b/data/po/de.po index b678b714b..5aab863e5 100644 --- a/data/po/de.po +++ b/data/po/de.po @@ -9,7 +9,7 @@ # Flakebi, 2015 # hiker , 2015 # konstin , 2015 -# Maximilian Wagenbach , 2016 +# Maximilian Wagenbach , 2016 # Tobias Markus , 2015-2016 # Wasilis Mandratzis-Walz, 2015 # wesen , 2016 @@ -18,7 +18,7 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" +"PO-Revision-Date: 2017-11-26 08:20+0000\n" "Last-Translator: Wuzzy \n" "Language-Team: German (http://www.transifex.com/supertuxkart/supertuxkart/language/de/)\n" "MIME-Version: 1.0\n" @@ -439,7 +439,7 @@ msgstr "Anzahl der Runden:" #. I18N: ./data/gui/edit_track.stkgui #. I18N: In the edit track screen msgid "Reverse:" -msgstr "Umkehren:" +msgstr "Rückwärts:" #. I18N: ./data/gui/edit_track.stkgui #. I18N: ./data/gui/general_text_field_dialog.stkgui @@ -3324,7 +3324,7 @@ msgstr "Runden" #: src/states_screens/edit_gp_screen.cpp:68 msgid "Reversed" -msgstr "Umgekehrt" +msgstr "Rückwärts" #: src/states_screens/edit_gp_screen.cpp:124 #: src/states_screens/ghost_replay_selection.cpp:177 @@ -4031,7 +4031,7 @@ msgstr "Maximal unterstützte Spieler: %d" #. I18N: In the track info screen #: src/states_screens/track_info_screen.cpp:213 msgid "Drive in reverse" -msgstr "Spiegelverkehrte Strecke" +msgstr "Rückwärts fahren" #. I18N: In the track info screen #: src/states_screens/track_info_screen.cpp:218 diff --git a/data/po/el.po b/data/po/el.po index 93588ba9a..d828bac47 100644 --- a/data/po/el.po +++ b/data/po/el.po @@ -13,8 +13,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2017-11-21 20:34+0000\n" +"Last-Translator: Vangelis Skarmoutsos \n" "Language-Team: Greek (http://www.transifex.com/supertuxkart/supertuxkart/language/el/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1828,7 +1828,7 @@ msgstr "Είσαι λίγο αξιολύπητος twerps δεν θα είσαι #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Λας Ντούνας Αρένα" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the lighthouse" @@ -1924,7 +1924,7 @@ msgstr "Έξλι" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" diff --git a/data/po/eo.po b/data/po/eo.po index 3f583772f..f5ac3de25 100644 --- a/data/po/eo.po +++ b/data/po/eo.po @@ -5,6 +5,7 @@ # Translators: # FIRST AUTHOR , 2011 # Jonas Marx , 2017 +# Rachel Singh , 2018 # Robin van der Vliet , 2015 # Любомир Василев, 2016 # Любомир Василев, 2016-2017 @@ -13,8 +14,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-04-06 18:13+0000\n" +"Last-Translator: Rachel Singh \n" "Language-Team: Esperanto (http://www.transifex.com/supertuxkart/supertuxkart/language/eo/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -3159,7 +3160,7 @@ msgstr "Enŝaltita por ĉiuj" #: src/states_screens/dialogs/custom_video_settings.cpp:102 #: src/states_screens/options_screen_video.cpp:469 msgid "Low" -msgstr "" +msgstr "Malalta" #. I18N: Geometry level high : everything is displayed #. I18N: in the graphical options tooltip; @@ -3169,21 +3170,21 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:103 #: src/states_screens/options_screen_video.cpp:472 msgid "High" -msgstr "" +msgstr "Alta" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very low #: src/states_screens/dialogs/custom_video_settings.cpp:94 #: src/states_screens/options_screen_video.cpp:466 msgid "Very Low" -msgstr "" +msgstr "Malaltega" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very high #: src/states_screens/dialogs/custom_video_settings.cpp:97 #: src/states_screens/options_screen_video.cpp:475 msgid "Very High" -msgstr "" +msgstr "Altega" #: src/states_screens/dialogs/message_dialog.cpp:129 #: src/states_screens/edit_gp_screen.cpp:257 @@ -3193,11 +3194,11 @@ msgstr "Ne" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:60 msgid "Tablet" -msgstr "" +msgstr "Tabulkomputilo" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:61 msgid "Phone" -msgstr "" +msgstr "Poŝtelefono" #: src/states_screens/dialogs/recovery_dialog.cpp:121 msgid "Username and/or email address invalid." @@ -3381,7 +3382,7 @@ msgstr "Fina tempo" #: src/states_screens/ghost_replay_selection.cpp:83 msgid "User" -msgstr "" +msgstr "Uzanto" #: src/states_screens/gp_info_screen.cpp:74 msgid "Default" @@ -3958,7 +3959,7 @@ msgstr "Ne sukcesis krei ludiston '%s'." #: src/states_screens/register_screen.cpp:277 msgid "Emails don't match!" -msgstr "" +msgstr "Retpoŝtadresoj ne estas sama!" #: src/states_screens/register_screen.cpp:281 msgid "Online username has to be between 3 and 30 characters long!" diff --git a/data/po/es.po b/data/po/es.po index 053e78f75..1bf0104f1 100644 --- a/data/po/es.po +++ b/data/po/es.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: -# Marc Coll Carrillo , 2015-2017 +# Marc Coll Carrillo , 2015-2018 # Veronica Sanchez, 2017 # William Beltrán , 2016 # William Beltrán , 2017 @@ -12,8 +12,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Veronica Sanchez\n" +"PO-Revision-Date: 2018-04-07 11:31+0000\n" +"Last-Translator: Marc Coll Carrillo \n" "Language-Team: Spanish (http://www.transifex.com/supertuxkart/supertuxkart/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -23,7 +23,7 @@ msgstr "" #. I18N: ./data/achievements.xml msgid "Christoffel Columbus" -msgstr "Cristófal Colón" +msgstr "Cristóbal Colón" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." @@ -1208,7 +1208,7 @@ msgstr "Servidores" #. I18N: ./data/gui/online/profile_servers.stkgui msgid "Local Networking" -msgstr "Red Local" +msgstr "Red local" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen @@ -1223,7 +1223,7 @@ msgstr "Crear servidor" #. I18N: ./data/gui/online/profile_servers.stkgui msgid "Global Networking" -msgstr "Red Global" +msgstr "Red global" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen @@ -1395,7 +1395,7 @@ msgstr "Votar" #. I18N: ./data/gui/online/waiting_for_others.stkgui #. I18N: Networking screen msgid "Waiting for the others..." -msgstr "Esperando a los otros..." +msgstr "Esperando a los demás..." #. I18N: ./data/gui/options_audio.stkgui #. I18N: ./data/gui/options_device.stkgui @@ -3376,7 +3376,7 @@ msgstr "Has desbloqueado el campeonato %0" #: src/states_screens/ghost_replay_selection.cpp:82 msgid "Finish Time" -msgstr "Tiempo de Llegada" +msgstr "Tiempo de llegada" #: src/states_screens/ghost_replay_selection.cpp:83 msgid "User" @@ -3895,7 +3895,7 @@ msgstr "Empatados" #: src/states_screens/race_result_gui.cpp:1098 #: src/states_screens/race_result_gui.cpp:1154 msgid "(Own Goal)" -msgstr "(Autogol)" +msgstr "(En propia puerta)" #: src/states_screens/race_result_gui.cpp:1220 #, c-format @@ -4020,7 +4020,7 @@ msgstr "Circuito creado por %s" #: src/states_screens/track_info_screen.cpp:120 #, c-format msgid "Max players supported: %d" -msgstr "Jugadores máximos soportados: %d" +msgstr "Máximos jugadores permitidos: %d" #. I18N: In the track info screen #: src/states_screens/track_info_screen.cpp:213 diff --git a/data/po/ga.po b/data/po/ga.po index 0b9816cbb..b69c4ffb2 100644 --- a/data/po/ga.po +++ b/data/po/ga.po @@ -3,14 +3,14 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: -# Aaron Kearns , 2017 +# Aaron Kearns , 2017-2018 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-02-21 22:27+0000\n" +"Last-Translator: Aaron Kearns \n" "Language-Team: Irish (http://www.transifex.com/supertuxkart/supertuxkart/language/ga/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -20,7 +20,7 @@ msgstr "" #. I18N: ./data/achievements.xml msgid "Christoffel Columbus" -msgstr "" +msgstr "Christoffel Columbus" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." @@ -544,7 +544,7 @@ msgstr "Athainmnigh" #. I18N: ./data/gui/grand_prix_lose.stkgui #. I18N: ./data/gui/grand_prix_win.stkgui msgid "Save Grand Prix" -msgstr "" +msgstr "Sábháil Grand Prix" #. I18N: ./data/gui/help1.stkgui #. I18N: ./data/gui/help2.stkgui @@ -1892,7 +1892,7 @@ msgstr "Gairdín Zen" #. I18N: ../stk-assets/karts/adiumy/kart.xml msgid "Adiumy" -msgstr "" +msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml msgid "Amanda" @@ -1904,7 +1904,7 @@ msgstr "" #. I18N: ../stk-assets/karts/emule/kart.xml msgid "Emule" -msgstr "" +msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml msgid "Gavroche" @@ -1916,7 +1916,7 @@ msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml msgid "Hexley" -msgstr "" +msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" @@ -1936,7 +1936,7 @@ msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml msgid "Puffy" -msgstr "" +msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml msgid "Sara the Racer" @@ -2172,13 +2172,13 @@ msgstr "" #: src/input/binding.cpp:144 msgctxt "input_key" msgid "Kana" -msgstr "" +msgstr "Kana" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:146 msgctxt "input_key" msgid "Junja" -msgstr "" +msgstr "Junja" #. I18N: input configuration screen: keyboard key #. I18N: input configuration screen: keyboard key diff --git a/data/po/gd.po b/data/po/gd.po index cd09fb84f..a0c3f8a22 100644 --- a/data/po/gd.po +++ b/data/po/gd.po @@ -11,7 +11,7 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" +"PO-Revision-Date: 2017-11-15 14:31+0000\n" "Last-Translator: GunChleoc\n" "Language-Team: Gaelic, Scottish (http://www.transifex.com/supertuxkart/supertuxkart/language/gd/)\n" "MIME-Version: 1.0\n" @@ -608,7 +608,7 @@ msgstr "Modhan-\r\ngeama" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Multi-player" -msgstr "Ioma-chluicheadair" +msgstr "Ioma-\nchluicheadair" #. I18N: ./data/gui/help1.stkgui #. I18N: Tab in help menu diff --git a/data/po/he.po b/data/po/he.po index 342cedeec..e6a2faaaf 100644 --- a/data/po/he.po +++ b/data/po/he.po @@ -8,6 +8,7 @@ # FIRST AUTHOR , 2010 # GenghisKhan , 2015-2016 # Liran , 2016-2017 +# Yaroslav Serhieiev , 2018 # Yevgney Sliosarenko, 2015 # ‫רואי לוי‬‎ , 2016 msgid "" @@ -15,8 +16,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Liran \n" +"PO-Revision-Date: 2018-03-25 14:36+0000\n" +"Last-Translator: Yaroslav Serhieiev \n" "Language-Team: Hebrew (http://www.transifex.com/supertuxkart/supertuxkart/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -937,7 +938,7 @@ msgstr "מתקדם" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Deadzone" -msgstr "" +msgstr "שטח מת" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -1830,7 +1831,7 @@ msgstr " אבל טיפשים קטנים ועלובים שכמותכם לעולם #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "ארנה לאס דונאס" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the lighthouse" @@ -1926,7 +1927,7 @@ msgstr "הקסלי" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "קיקי" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" diff --git a/data/po/id.po b/data/po/id.po index 23fbd429b..140dc9cde 100644 --- a/data/po/id.po +++ b/data/po/id.po @@ -7,14 +7,15 @@ # Christian "crse" Elbrianno, 2017 # FIRST AUTHOR , 2011 # Icho Yulian Chandra , 2016 +# Iwan Rahardi Putra , 2017 # Raja Sulaiman , 2017 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Christian \"crse\" Elbrianno\n" +"PO-Revision-Date: 2017-12-30 04:05+0000\n" +"Last-Translator: Iwan Rahardi Putra \n" "Language-Team: Indonesian (http://www.transifex.com/supertuxkart/supertuxkart/language/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -930,7 +931,7 @@ msgstr "Akselerometer" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "" +msgstr "Tingkat lanjut" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -3412,7 +3413,7 @@ msgstr "" #: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." -msgstr "" +msgstr "Nama kosong." #: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." @@ -3420,7 +3421,7 @@ msgstr "" #: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." -msgstr "" +msgstr "Nama terlalu panjang." #. I18N: when failing a GP #: src/states_screens/grand_prix_lose.cpp:155 @@ -3827,11 +3828,11 @@ msgstr "Peringkat" #: src/states_screens/race_gui_overworld.cpp:518 msgid "Press fire to start the tutorial" -msgstr "" +msgstr "Tekan tombol tembak untuk mulai latihan" #: src/states_screens/race_gui_overworld.cpp:557 msgid "Type: Grand Prix" -msgstr "" +msgstr "Tipe: Grand Prix" #: src/states_screens/race_gui_overworld.cpp:594 msgid "Press fire to start the challenge" @@ -3839,7 +3840,7 @@ msgstr "Tekan tembak untuk memulai tantangan" #: src/states_screens/race_result_gui.cpp:175 msgid "Continue." -msgstr "" +msgstr "Lanjutkan." #: src/states_screens/race_result_gui.cpp:178 msgid "Quit the server." @@ -3859,7 +3860,7 @@ msgstr "Mulai Ulang" #: src/states_screens/race_result_gui.cpp:224 msgid "Back to challenge selection" -msgstr "" +msgstr "Kembali ke pilihan tantangan" #: src/states_screens/race_result_gui.cpp:230 msgid "Back to the menu" @@ -3895,7 +3896,7 @@ msgstr "" #: src/states_screens/race_result_gui.cpp:1220 #, c-format msgid "Track %i/%i" -msgstr "" +msgstr "Putaran %i/%i" #: src/states_screens/race_result_gui.cpp:1304 msgid "Grand Prix progress:" @@ -3908,12 +3909,12 @@ msgstr "Highscores" #: src/states_screens/race_result_gui.cpp:1432 #, c-format msgid "Difficulty: %s" -msgstr "" +msgstr "Tingkat kesulitan: %s" #: src/states_screens/race_result_gui.cpp:1440 #, c-format msgid "Best lap time: %s" -msgstr "" +msgstr "Waktu lintasan terbaik: %s" #: src/states_screens/race_setup_screen.cpp:87 msgid "All blows allowed, so catch weapons and make clever use of them!" @@ -3930,11 +3931,11 @@ msgstr "Selalu buntuti sang pemimpin tapi jangan didahului!" #: src/states_screens/race_setup_screen.cpp:114 msgid "Hit others with weapons until they lose all their lives." -msgstr "" +msgstr "Serang yang lain dengan senjata sampai mereka kehabisan nyawa." #: src/states_screens/race_setup_screen.cpp:119 msgid "Push the ball into the opposite cage to score goals." -msgstr "" +msgstr "Dorong bola ke dalam gawang lawan untuk membuat gol." #: src/states_screens/race_setup_screen.cpp:129 msgid "Explore tracks to find all hidden eggs" @@ -3942,17 +3943,17 @@ msgstr "Eksplorasi jalur untuk menemukan semua telur tersembunyi" #: src/states_screens/race_setup_screen.cpp:137 msgid "Race against ghost karts and try to beat them!" -msgstr "" +msgstr "Berlomba dan coba kalahkan mobil hantu!" #: src/states_screens/register_screen.cpp:218 #: src/states_screens/register_screen.cpp:225 #, c-format msgid "Could not create player '%s'." -msgstr "" +msgstr "Tidak bisa membuat pemain '%s'." #: src/states_screens/register_screen.cpp:277 msgid "Emails don't match!" -msgstr "" +msgstr "Email tidak sama!" #: src/states_screens/register_screen.cpp:281 msgid "Online username has to be between 3 and 30 characters long!" @@ -3964,11 +3965,11 @@ msgstr "" #: src/states_screens/register_screen.cpp:293 msgid "Email has to be between 5 and 254 characters long!" -msgstr "" +msgstr "Panjang email harus diantara 5 sampai 254 karakter." #: src/states_screens/register_screen.cpp:299 msgid "Email is invalid!" -msgstr "" +msgstr "Email salah!" #: src/states_screens/register_screen.cpp:362 msgid "" @@ -3989,7 +3990,7 @@ msgstr "" #. I18N: track group name #: src/states_screens/tracks_and_gp_screen.cpp:144 msgid "all" -msgstr "" +msgstr "semua" #: src/states_screens/tracks_and_gp_screen.cpp:195 msgid "Locked!" @@ -3998,11 +3999,11 @@ msgstr "Dikunci!" #: src/states_screens/tracks_and_gp_screen.cpp:278 #: src/states_screens/tracks_screen.cpp:227 msgid "Locked: solve active challenges to gain access to more!" -msgstr "" +msgstr "Dikunci: selesaikan tantangan yang ada untuk akses lintasan yang lain!" #: src/states_screens/tracks_screen.cpp:194 msgid "Only official tracks are supported." -msgstr "" +msgstr "Hanya mendukung lintasan resmi." #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) @@ -4015,25 +4016,25 @@ msgstr "Lintasan oleh %s" #: src/states_screens/track_info_screen.cpp:120 #, c-format msgid "Max players supported: %d" -msgstr "" +msgstr "Maksimal pemain: %d" #. I18N: In the track info screen #: src/states_screens/track_info_screen.cpp:213 msgid "Drive in reverse" -msgstr "" +msgstr "Lintasan dibalik" #. I18N: In the track info screen #: src/states_screens/track_info_screen.cpp:218 msgid "Random item location" -msgstr "" +msgstr "Acak lokasi benda" #: src/states_screens/user_screen.cpp:111 msgid "Exit game" -msgstr "" +msgstr "Keluar permainan" #: src/states_screens/user_screen.cpp:484 msgid "You need to enter a password." -msgstr "" +msgstr "Kamu harus masukan password." #: src/states_screens/user_screen.cpp:505 #, c-format @@ -4056,7 +4057,7 @@ msgstr "Apakah anda benar-benar ingin menghapus pemain '%s' ?" #. formats. #: src/utils/time.cpp:50 msgid "%d/%m/%Y" -msgstr "" +msgstr "%d/%m/%Y" #. I18N: Do NOT literally translate this string!! Please enter Y as the #. translation if your language is a RTL (right-to-left) language, @@ -4067,7 +4068,7 @@ msgstr " N" #: ../stk-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" -msgstr "" +msgstr "Selesaikan semua tantangan untuk membuka pintu besar!" #: ../stk-assets/tracks/overworld/scripting.as:63 msgid "" @@ -4075,19 +4076,19 @@ msgid "" "to enter this challenge!\n" "Check the minimap for\n" "available challenges." -msgstr "" +msgstr "Butuh lebih banyak angka\nuntuk mengambil tantangan ini!\nPeriksa peta kecil untuk lihat\ntantangan yang ada." #: ../stk-assets/tracks/tutorial/scripting.as:21 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." -msgstr "" +msgstr "Maju dengan <%s>, dan menyetir dengan <%s> dan <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:37 #: ../stk-assets/tracks/tutorial/triggers.as:38 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" -msgstr "" +msgstr "Ambil kotak hadiah, dan tembakan senjata dengan <%s> untuk menghancurkan peti-peti ini!" #: ../stk-assets/tracks/tutorial/scripting.as:43 #: ../stk-assets/tracks/tutorial/triggers.as:44 @@ -4095,7 +4096,7 @@ msgstr "" msgid "" "Press <%s> to look behind. Fire the weapon with <%s> while pressing <%s> to " "fire behind!" -msgstr "" +msgstr "Tekan <%s> untuk lihat ke belakang. Tembakan senjata dengan <%s> saat menekan <%s> untuk menembak ke belakang!" #: ../stk-assets/tracks/tutorial/scripting.as:53 #: ../stk-assets/tracks/tutorial/triggers.as:54 @@ -4105,12 +4106,12 @@ msgstr "Gunakan nitro yang anda kumpulkan dengan menekan <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:58 msgid "Collect nitro bottles (we will use them after the curve)." -msgstr "" +msgstr "Kumpulkan botol nitro (akan kita pakai setelah tikungan)." #: ../stk-assets/tracks/tutorial/scripting.as:63 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." -msgstr "" +msgstr "Oops! Saat dalam masalah, tekan <%s> supaya diselamatkan." #: ../stk-assets/tracks/tutorial/scripting.as:69 #: ../stk-assets/tracks/tutorial/triggers.as:70 @@ -4118,14 +4119,14 @@ msgstr "" msgid "" "Accelerate and press the <%s> key while turning to skid. Skidding for a " "short while can help you turn faster to take sharp turns." -msgstr "" +msgstr "Maju dan tekan <%s> saat berbelok untuk ngesot. Ngesot beberapa saat akan membuat kamu berbelok lebih cepat pada belokan tajam." #: ../stk-assets/tracks/tutorial/scripting.as:77 #: ../stk-assets/tracks/tutorial/triggers.as:78 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" -msgstr "" +msgstr "Kalau kamu berhasil ngesot untuk beberapa detik, kamu akan mendapat bonus tambahan kecepatan sebagai hadiah." #: ../stk-assets/tracks/tutorial/scripting.as:82 #: ../stk-assets/tracks/tutorial/triggers.as:83 @@ -4135,7 +4136,7 @@ msgstr "Kini anda siap untuk balapan. Semoga beruntung!" #: ../stk-assets/tracks/tutorial/triggers.as:28 #, c-format msgid "Accelerate with <%s> and steer with <%s> and <%s>" -msgstr "" +msgstr "Maju dengan <%s> dan belok dengan <%s> dan <%s>" #: ../stk-assets/tracks/tutorial/triggers.as:59 msgid "Collect nitro bottles (we will use them after the curve)" diff --git a/data/po/it.po b/data/po/it.po index 5e455a512..ae9d0a500 100644 --- a/data/po/it.po +++ b/data/po/it.po @@ -6,7 +6,7 @@ # Davide Depau , 2015 # Enrico B. , 2015 # Giuseppe Pignataro (Fasbyte01) , 2015 -# Ioma Taani, 2016 +# Ioma Taani, 2016,2018 # lorenzo mijorus , 2015 # Luca Argentieri , 2015 # mattia_b89 , 2017 @@ -15,8 +15,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: mattia_b89 \n" +"PO-Revision-Date: 2018-01-04 07:19+0000\n" +"Last-Translator: Ioma Taani\n" "Language-Team: Italian (http://www.transifex.com/supertuxkart/supertuxkart/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -922,7 +922,7 @@ msgstr "Pulsanti invertiti" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "" +msgstr "Dimensione pulsanti" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -2806,8 +2806,8 @@ msgstr "DIREZIONE ERRATA!" #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i ruota del kart è stata creata!" +msgstr[1] "%i ruote del kart sono state create!" #: src/modes/world.cpp:1202 msgid "You have been eliminated!" diff --git a/data/po/ja.po b/data/po/ja.po index fb34038d7..fc2b87651 100644 --- a/data/po/ja.po +++ b/data/po/ja.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# David Blaszyk , 2017 # lindwurm, 2015 # Sugahara Masayuki , 2015 # lip_of_cygnus , 2015 @@ -12,8 +13,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2017-11-21 21:28+0000\n" +"Last-Translator: David Blaszyk \n" "Language-Team: Japanese (http://www.transifex.com/supertuxkart/supertuxkart/language/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -992,7 +993,7 @@ msgstr "閉じる" #. I18N: ./data/gui/online/create_server.stkgui #. I18N: In the server creation screen msgid "Server Creation" -msgstr "" +msgstr "サーバー創造" #. I18N: ./data/gui/online/create_server.stkgui #. I18N: In the server creation screen @@ -1011,7 +1012,7 @@ msgstr "" #. I18N: ./data/gui/online/create_server.stkgui #. I18N: In the server creation screen msgid "Password (optional)" -msgstr "" +msgstr "パスワード (任意)" #. I18N: ./data/gui/online/create_server.stkgui #. I18N: In the server creation screen @@ -1161,7 +1162,7 @@ msgstr "ゲームモード" #. I18N: ./data/gui/online/networking_lobby.stkgui #. I18N: In the networking lobby msgid "Exit" -msgstr "" +msgstr "終了" #. I18N: ./data/gui/online/notification_dialog.stkgui #. I18N: User info dialog @@ -1219,7 +1220,7 @@ msgstr "サーバーを見つける" #. I18N: In the online multiplayer screen #: src/states_screens/create_server_screen.cpp:83 msgid "Create Server" -msgstr "" +msgstr "サーバーを創造する" #. I18N: ./data/gui/online/profile_servers.stkgui msgid "Global Networking" @@ -1243,7 +1244,7 @@ msgstr "パスワード:" #. I18N: ./data/gui/online/profile_settings.stkgui msgid "Change" -msgstr "" +msgstr "変更" #. I18N: ./data/gui/online/recovery_info.stkgui #. I18N: In the recovery dialog @@ -1291,12 +1292,12 @@ msgstr "ユーザーを作成" #. I18N: ./data/gui/online/register.stkgui #. I18N: Section in the register screen msgid "New Online Account" -msgstr "" +msgstr "新しいオンラインアカウント" #. I18N: ./data/gui/online/register.stkgui #. I18N: Section in the register screen msgid "Existing Online Account" -msgstr "" +msgstr "現存のオンラインアカウント" #. I18N: ./data/gui/online/register.stkgui #. I18N: Section in the register screen @@ -1345,7 +1346,7 @@ msgstr "" #. I18N: ./data/gui/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept" -msgstr "" +msgstr "受け付ける" #. I18N: ./data/gui/online/server_info_dialog.stkgui #. I18N: In the server info dialog @@ -1381,7 +1382,7 @@ msgstr "フレンドを追加" #. I18N: ./data/gui/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline" -msgstr "" +msgstr "断る" #. I18N: ./data/gui/online/user_search.stkgui msgid "User search" @@ -1531,7 +1532,7 @@ msgstr "FPS 表示" #. I18N: ./data/gui/options_ui.stkgui #. I18N: In the ui settings msgid "Always show login screen" -msgstr "" +msgstr "いつもログイン画面を表示" #. I18N: ./data/gui/options_ui.stkgui #. I18N: In the ui settings @@ -1680,7 +1681,7 @@ msgstr "タイプ:" #. I18N: ./data/gui/soccer_setup.stkgui #. I18N: In soccer setup screen msgid "Number of goals to win" -msgstr "" +msgstr "ゴールの勝ち数" #. I18N: ./data/gui/soccer_setup.stkgui #. I18N: In soccer setup screen @@ -1690,7 +1691,7 @@ msgstr "" #. I18N: ./data/gui/soccer_setup.stkgui #. I18N: In soccer setup screen msgid "Game type (Goals limit / Time limit)" -msgstr "" +msgstr "ゲームタイプ (ゴール限定 / 時間限定)" #. I18N: ./data/gui/soccer_setup.stkgui #. I18N: In soccer setup screen @@ -1977,14 +1978,14 @@ msgstr "" #: src/addons/news_manager.cpp:179 #, c-format msgid "Error downloading news: '%s'." -msgstr "" +msgstr "ニューズをダウンロードエラー: '1%s'" #. I18N: number of laps to race in a challenge #: src/challenges/challenge_data.cpp:266 #: src/states_screens/race_result_gui.cpp:1424 #, c-format msgid "Laps: %i" -msgstr "" +msgstr "ラップ: 1%i" #: src/challenges/challenge_data.cpp:272 msgid "Follow the leader" @@ -2044,12 +2045,12 @@ msgstr "設定したコンフィグファイルが古すぎます。削除して #: src/graphics/irr_driver.cpp:535 msgid "Video recording started." -msgstr "" +msgstr "録画を始めた" #: src/graphics/irr_driver.cpp:541 #, c-format msgid "Video saved in \"%s\"." -msgstr "" +msgstr "ビデオは \"%s\" に保存しました" #: src/graphics/irr_driver.cpp:545 msgid "Encoding progress:" @@ -2121,43 +2122,43 @@ msgstr "" #: src/input/binding.cpp:126 msgctxt "input_key" msgid "Backspace" -msgstr "" +msgstr "バックスペース" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:128 msgctxt "input_key" msgid "Tab" -msgstr "" +msgstr "タブ" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:130 msgctxt "input_key" msgid "Clear" -msgstr "" +msgstr "消す" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:132 msgctxt "input_key" msgid "Return" -msgstr "" +msgstr "リターンキー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:134 msgctxt "input_key" msgid "Shift" -msgstr "" +msgstr "シフトキー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:136 msgctxt "input_key" msgid "Control" -msgstr "" +msgstr "コントロールキー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:138 msgctxt "input_key" msgid "Alt/Menu" -msgstr "" +msgstr "Altキー/メニュー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:140 @@ -2169,7 +2170,7 @@ msgstr "ポーズ" #: src/input/binding.cpp:142 msgctxt "input_key" msgid "Caps Lock" -msgstr "" +msgstr "キャプスロックキー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:144 @@ -2194,7 +2195,7 @@ msgstr "" #: src/input/binding.cpp:151 msgctxt "input_key" msgid "Escape" -msgstr "" +msgstr "エスケープキー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:153 @@ -2224,7 +2225,7 @@ msgstr "" #: src/input/binding.cpp:161 msgctxt "input_key" msgid "Space" -msgstr "" +msgstr "スペースキー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:163 @@ -2242,43 +2243,43 @@ msgstr "" #: src/input/binding.cpp:167 msgctxt "input_key" msgid "End" -msgstr "" +msgstr "エンドキー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:169 msgctxt "input_key" msgid "Home" -msgstr "" +msgstr "ホームキー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:171 msgctxt "input_key" msgid "Left" -msgstr "" +msgstr "左キー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:173 msgctxt "input_key" msgid "Up" -msgstr "" +msgstr "上キー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:175 msgctxt "input_key" msgid "Right" -msgstr "" +msgstr "右キー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:177 msgctxt "input_key" msgid "Down" -msgstr "" +msgstr "下キー" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:179 msgctxt "input_key" msgid "Select" -msgstr "" +msgstr "選択" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:181 @@ -2576,12 +2577,12 @@ msgstr "入力したコンフィグファイルはこのバージョンのSTKと #. I18N: Name of the black button on xbox controller #: src/input/gamepad_config.cpp:167 msgid "Black" -msgstr "" +msgstr "黒い" #. I18N: Name of the white button on xbox controller #: src/input/gamepad_config.cpp:171 msgid "White" -msgstr "" +msgstr "白い" #. I18N: name of buttons on gamepads #. I18N: name of stick on gamepads @@ -2652,7 +2653,7 @@ msgstr "" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:218 msgid "Start" -msgstr "" +msgstr "スタート" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:220 @@ -3133,7 +3134,7 @@ msgstr "無効" #: src/states_screens/dialogs/custom_video_settings.cpp:67 #: src/states_screens/options_screen_video.cpp:462 msgid "Important only" -msgstr "" +msgstr "大体だけ" #. I18N: animations setting (only karts with human players are animated) #: src/states_screens/dialogs/custom_video_settings.cpp:74 @@ -3182,19 +3183,19 @@ msgstr "" #: src/states_screens/edit_gp_screen.cpp:257 #: src/states_screens/ghost_replay_selection.cpp:117 msgid "No" -msgstr "" +msgstr "いいえ" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:60 msgid "Tablet" -msgstr "" +msgstr "タブレット" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:61 msgid "Phone" -msgstr "" +msgstr "スマホ" #: src/states_screens/dialogs/recovery_dialog.cpp:121 msgid "Username and/or email address invalid." -msgstr "" +msgstr "ユーザー名またはメールアドレスは無効" #: src/states_screens/dialogs/registration_dialog.cpp:42 #, c-format @@ -3246,7 +3247,7 @@ msgstr "リクエストを取り消す" #: src/states_screens/dialogs/user_info_dialog.cpp:154 #: src/states_screens/dialogs/user_info_dialog.cpp:211 msgid "Today" -msgstr "" +msgstr "今日" #: src/states_screens/dialogs/user_info_dialog.cpp:158 msgid "Friend request sent!" @@ -3308,7 +3309,7 @@ msgstr "コース" #: src/states_screens/edit_gp_screen.cpp:67 #: src/states_screens/ghost_replay_selection.cpp:81 msgid "Laps" -msgstr "" +msgstr "ラップ" #: src/states_screens/edit_gp_screen.cpp:68 msgid "Reversed" @@ -3374,7 +3375,7 @@ msgstr "" #: src/states_screens/ghost_replay_selection.cpp:83 msgid "User" -msgstr "" +msgstr "ユーザー" #: src/states_screens/gp_info_screen.cpp:74 msgid "Default" @@ -3793,7 +3794,7 @@ msgstr "スタート!" #. I18N: Shown when a goal is scored #: src/states_screens/race_gui_base.cpp:71 msgid "GOAL!" -msgstr "" +msgstr "ゴール!" #. I18N: string used to show the author of the music. (e.g. "Sunny Song" by #. "John Doe") @@ -3838,7 +3839,7 @@ msgstr "アイテムボタンを押してチャレンジを開始" #: src/states_screens/race_result_gui.cpp:175 msgid "Continue." -msgstr "" +msgstr "続く" #: src/states_screens/race_result_gui.cpp:178 msgid "Quit the server." @@ -3907,12 +3908,12 @@ msgstr "ハイスコア" #: src/states_screens/race_result_gui.cpp:1432 #, c-format msgid "Difficulty: %s" -msgstr "" +msgstr "難しさ: %s" #: src/states_screens/race_result_gui.cpp:1440 #, c-format msgid "Best lap time: %s" -msgstr "" +msgstr "ベストラップ時間: %s" #: src/states_screens/race_setup_screen.cpp:87 msgid "All blows allowed, so catch weapons and make clever use of them!" diff --git a/data/po/pt.po b/data/po/pt.po index 095456cb1..b7c03dd93 100644 --- a/data/po/pt.po +++ b/data/po/pt.po @@ -5,6 +5,8 @@ # Translators: # Bruno Ramalhete , 2015 # FIRST AUTHOR , 2010 +# Pedro TheGamerOficialTM , 2017 +# Pedro TheGamerOficialTM , 2017 # Rui , 2016-2017 # Rui , 2016 msgid "" @@ -12,8 +14,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Rui \n" +"PO-Revision-Date: 2017-11-25 11:08+0000\n" +"Last-Translator: Pedro TheGamerOficialTM \n" "Language-Team: Portuguese (http://www.transifex.com/supertuxkart/supertuxkart/language/pt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -95,11 +97,11 @@ msgstr "Apanhar um mínimo de 5 bananas por corrida." #. I18N: ./data/achievements.xml msgid "It's secret" -msgstr "É segredo" +msgstr "É um segredo" #. I18N: ./data/achievements.xml msgid "Really ... a secret." -msgstr "Realmente... um segredo." +msgstr "Realmente... é um segredo." #. I18N: ./data/achievements.xml msgid "Mosquito Hunter" @@ -121,7 +123,7 @@ msgstr "Fora do circuito habitual" #. I18N: ./data/grandprix/3_tothemoonandback.grandprix msgid "To the moon and back" -msgstr "Ira à Lua e voltar" +msgstr "Ir à Lua e voltar" #. I18N: ./data/grandprix/4_atworldsend.grandprix msgid "At World's End" @@ -385,7 +387,7 @@ msgstr "Todas as Pistas" #. I18N: ./data/gui/edit_gp.stkgui #. I18N: Title in edit grand prix screen msgid "Edit Grand Prix" -msgstr "Editar Grande Prémio" +msgstr "Editar o grande prémio" #. I18N: ./data/gui/edit_gp.stkgui #. I18N: Menu item @@ -481,7 +483,7 @@ msgstr "Visualizar apenas o rever" #. I18N: ./data/gui/track_info.stkgui #. I18N: In the track info screen msgid "Start Race" -msgstr "Iniciar corrida" +msgstr "Iniciar a corrida" #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -491,7 +493,7 @@ msgstr "Seleção de Rever Fantasma" #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show replays matching the current difficulty" -msgstr "Mostrar rever apenas na dificuldade atual" +msgstr "Mostrar apenas na dificuldade atual" #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -523,7 +525,7 @@ msgstr "Continuar o Grande Prémio gravado" #. I18N: ./data/gui/grand_prix_editor.stkgui #. I18N: Title in grand prix editor screen msgid "Grand Prix editor" -msgstr "Editor de Grande Prémio" +msgstr "Editor do grande prémio" #. I18N: ./data/gui/grand_prix_editor.stkgui #. I18N: Menu item @@ -646,19 +648,19 @@ msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key. You can see your current level of nitro in the" " bar at the right of the game screen." -msgstr "Se apanhares garrafas de nitro podes conseguir velocidades estonteantes sempre que carregares na tecla apropriada. Podes ver o quantidade de nitro na barra à direita do ecrã de jogo." +msgstr "Se apanhares garrafas de nitro podes conseguir velocidades brutais sempre que carregares na tecla apropriada. Podes ver a quantidade de nitro na barra à direita do ecrã do jogo." #. I18N: ./data/gui/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." -msgstr "Se vires um botão com um cadeado destes, é porque tens que completar um desafio para o desbloquear." +msgstr "Se vires um botão com um cadeado destes, é porque tens que completar uma corrida para o desbloquear." #. I18N: ./data/gui/help1.stkgui #. I18N: in the help menu msgid "The 'skidding' key allows you to skid in sharp turns and get a boost." -msgstr "A tecla \"Derrapar\" permite derrapar em curvas apertadas e ganhar aceleração." +msgstr "A tecla \"Derrapar\" permite derrapar em curvas apertadas e ganhar velocidade." #. I18N: ./data/gui/help1.stkgui #. I18N: in the help screen @@ -679,7 +681,7 @@ msgstr "Pastilha Elástica - protege-te com um escudo ou utiliza-a quando olhare #. I18N: ./data/gui/help2.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." -msgstr "Bolo - é atirado ao rival mais próximo. Deve ser utilizado para pequenas distâncias e em reta." +msgstr "Bolo - é atirado ao rival mais próximo. Deve ser utilizado para distâncias pequenas e em reta." #. I18N: ./data/gui/help2.stkgui msgid "" @@ -729,7 +731,7 @@ msgstr "Corrida Normal: todas as armas são permitidas. Apanha-as e utiliza-as!" msgid "" "Time Trial: Contains no powerups, so only your driving skills matter! This " "mode allows you to record the race for replaying." -msgstr "Corrida Contra o Tempo: não existem powerups por isso apenas contam as tuas capacidades de condução. Este modo permite gravar a corrida para poderes revê-la." +msgstr "Corrida Contra o Tempo: não existem powerups por isso, apenas contam as tuas capacidades de condução. Este modo permite gravar a corrida para poderes revê-la." #. I18N: ./data/gui/help3.stkgui #. I18N: In the help menu @@ -737,7 +739,7 @@ msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "Seguir o Líder: disputa o segundo lugar, porque o último carro será desqualificado sempre que o cronómetro atinja o valor zero. Atenção: não deves ultrapassar o líder ou serás também eliminado." +msgstr "Seguir o Líder: Disputa o segundo lugar, porque o último carro será desqualificado sempre que o cronómetro atinja o valor zero. Atenção: não deves ultrapassar o líder ou serás também eliminado." #. I18N: ./data/gui/help3.stkgui #. I18N: In the help menu @@ -762,7 +764,7 @@ msgid "" "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "* Grande parte destes modos também podem ser jogados como Grande Prémio. Em vez de fazer uma corrida, joga várias de seguida. Quanto melhor for a tua posição, mais pontos ganhas. No fim, o jogador que tiver mais pontos ganha a taça." +msgstr "* Grande parte destes modos também podem ser jogados como Grande Prémio. Em vez de fazeres uma corrida, jogas várias de seguida. Quanto melhor for a tua posição, mais pontos ganhas. No fim, o jogador que tiver mais pontos ganha a taça." #. I18N: ./data/gui/help4.stkgui msgid "SuperTuxKart can be played in multiplayer mode on the same computer" @@ -781,7 +783,7 @@ msgid "" "keyboard(s), however each player will need a different set of keys, and keep" " in mind that most keyboards are not appropriate for multiplayer gameplay " "because they do not support large number of keypresses." -msgstr "Precisas de diversos dispositivos (ter diversos comandos ou joysticks é a melhor maneira para jogos multi-jogadores). Acede às definições e configura os comandos. Também podem jogar no teclado, mas neste caso, cada jogador terá que usar diversas teclas e esta não é a melhor forma de jogar, uma vez que a maioria dos teclados não permitem que se primam várias teclas ao mesmo tempo." +msgstr "Primeiro, precisas de diversos dispositivos (ter diversos comandos ou joysticks é a melhor maneira para jogos multi-jogadores). Acede às definições e configura os comandos. Também podes jogar no teclado, mas neste caso, cada jogador terá que usar diversas teclas e esta não é a melhor forma de jogar, uma vez que a maioria dos teclados não permitem que se primam várias teclas ao mesmo tempo." #. I18N: ./data/gui/help4.stkgui #. I18N: In the help menu @@ -792,7 +794,7 @@ msgid "" " the game. Each player can use their input device to select their kart. The " "game continues when everyone selected their kart. Note that the mouse may " "not be used for this operation." -msgstr "Assim que configurares os dispositivos, podes jogar. Escolhe uma corrida multi-jogador no menu principal. Para escolher um veículo, cada jogador tem que pressionar a tecla de \"Disparo\" do comando, joystick ou teclado para entrar no jogo. Cada jogador pode usar o seu dispositivo para escolher o veículo. O jogo começará assim que todos os jogadores escolham o veículo. Para esta operação, não se pode utilizar o rato." +msgstr "Assim que configurares os dispositivos, podes jogar. Escolhe uma corrida multi-jogador no menu principal. Para escolher um veículo, cada jogador tem que pressionar a tecla de \"Disparo\" do comando, joystick ou teclado para entrar no jogo. Cada jogador pode usar o seu dispositivo para escolher o veículo. O jogo começará assim que todos os jogadores escolherem um veículo. Para esta operação, não podes utilizar o rato." #. I18N: ./data/gui/help5.stkgui msgid "" @@ -808,7 +810,7 @@ msgstr "Âncora - reduz a velocidade do kart." #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Parachute - slows down the kart less than the anchor." -msgstr "Pára-quedas - reduz a velocidade do kart, mas menos que a âncora." +msgstr "Pára-quedas - reduz a velocidade do kart, mas reduz menos que a âncora." #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu @@ -948,24 +950,24 @@ msgstr "Restaurar padrão" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog msgid "Password Change" -msgstr "Alterar Palavra-chave" +msgstr "Alterar a palavra-passe" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog msgid "Current Password" -msgstr "Palavra-chave atual" +msgstr "Palavra-passe atual" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog msgid "New Password" -msgstr "Nova Palavra-chave" +msgstr "Nova palavra-passe" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog #. I18N: ./data/gui/online/register.stkgui #. I18N: In the registration dialog msgid "Confirm" -msgstr "Confirmação" +msgstr "Confirmar" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog @@ -992,7 +994,7 @@ msgstr "Fechar" #. I18N: ./data/gui/online/create_server.stkgui #. I18N: In the server creation screen msgid "Server Creation" -msgstr "Criação de Servidor" +msgstr "Criação do Servidor" #. I18N: ./data/gui/online/create_server.stkgui #. I18N: In the server creation screen @@ -1073,7 +1075,7 @@ msgstr "Modo de jogo" #. I18N: Game mode #: src/race/race_manager.hpp:175 msgid "Normal Race" -msgstr "Corrida simples" +msgstr "Corrida normal" #. I18N: ./data/gui/online/create_server.stkgui #. I18N: Multiplayer game mode @@ -1188,7 +1190,7 @@ msgstr "Amigos" #. I18N: ./data/gui/online/profile_friends.stkgui #. I18N: In the profile screen msgid "Look for more friends:" -msgstr "Porcurar mais amigos:" +msgstr "Procurar mais amigos:" #. I18N: ./data/gui/online/profile_friends.stkgui #. I18N: ./data/gui/online/user_search.stkgui @@ -1213,7 +1215,7 @@ msgstr "Rede Local" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen msgid "Find Server" -msgstr "Localizar Servidor" +msgstr "Encontrar Servidor" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen @@ -1223,7 +1225,7 @@ msgstr "Criar Servidor" #. I18N: ./data/gui/online/profile_servers.stkgui msgid "Global Networking" -msgstr "Rede Mundial" +msgstr "Rede Global" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen @@ -1239,7 +1241,7 @@ msgstr "Definições da Conta" #. I18N: ./data/gui/online/profile_settings.stkgui #. I18N: In the online account settings screen msgid "Password:" -msgstr "Palavra-chave:" +msgstr "Palavra-passe:" #. I18N: ./data/gui/online/profile_settings.stkgui msgid "Change" @@ -1250,20 +1252,20 @@ msgstr "Alterar" #. I18N: ./data/gui/online/recovery_input.stkgui #. I18N: In the recovery dialog msgid "Account Recovery" -msgstr "Recuperação de Conta" +msgstr "Recuperação da Conta" #. I18N: ./data/gui/online/recovery_info.stkgui #. I18N: In the recovery dialog msgid "" "You will receive an email with further instructions on how to reset your " "password. Please be patient and be sure to check your spam folder." -msgstr "Vais receber um email com informações detalhadas sobre como repôr a palavra-chave. Por favor tem paciência e lembra-te de verificar a pasta de emails indesejados ou spam." +msgstr "Vais receber um email com informações detalhadas sobre como alterar a palavra-chave. Por favor tem paciência e lembra-te de verificar a pasta de emails indesejados ou spam." #. I18N: ./data/gui/online/recovery_input.stkgui msgid "" "Fill in the username and email address you supplied at registration to be " "able to reset your password." -msgstr "Preenche o nome de utilizador e o endereço de email que introduziste ao criar a conta para poderes repôr a tua palavra-passe." +msgstr "Preenche o nome de utilizador e o endereço de email que introduziste ao criar a conta para poderes alterar a tua palavra-passe." #. I18N: ./data/gui/online/recovery_input.stkgui #. I18N: In the recovery dialog @@ -1526,7 +1528,7 @@ msgstr "Tema" #. I18N: ./data/gui/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" -msgstr "Mostrar Quadros Por Segundo" +msgstr "Mostrar FPS" #. I18N: ./data/gui/options_ui.stkgui #. I18N: In the ui settings @@ -1581,7 +1583,7 @@ msgstr "Resolução" #. I18N: ./data/gui/options_video.stkgui #. I18N: In the video settings msgid "Fullscreen" -msgstr "Ecrã total" +msgstr "Ecrã inteiro" #. I18N: ./data/gui/options_video.stkgui #. I18N: In the video settings @@ -1711,7 +1713,7 @@ msgstr "Equipa Azul" #. I18N: In the track and grand prix selection screen #: src/states_screens/dialogs/select_challenge.cpp:147 msgid "Grand Prix" -msgstr "Grande prémio" +msgstr "Grande Prémio" #. I18N: ./data/gui/track_info.stkgui msgid "= Highscores =" @@ -1811,12 +1813,12 @@ msgstr "Sim, ele está no meu castelo e servir-me-á para sempre..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." -msgstr "Mas como sou uma criatura justa, proponho um acordo." +msgstr "Mas como sou uma criatura justa, proponho-te um acordo." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." -msgstr "Se me conseguires vencer na corrida, eu liberto-o." +msgstr "Se me conseguires vencer na corrida, eu liberto o teu líder." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml @@ -1935,7 +1937,7 @@ msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml msgid "Pidgin" -msgstr "Pombo" +msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml msgid "Puffy" @@ -1943,11 +1945,11 @@ msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml msgid "Sara the Racer" -msgstr "Sara a Corredora" +msgstr "Sara The Racer" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml msgid "Sara the Wizard" -msgstr "Sara a Feiticeira" +msgstr "Sara The Wizard" #. I18N: ../stk-assets/karts/suzanne/kart.xml msgid "Suzanne" @@ -1977,7 +1979,7 @@ msgstr "Não foi possível ligar ao servidor de extras do SuperTuxKart." #: src/addons/news_manager.cpp:179 #, c-format msgid "Error downloading news: '%s'." -msgstr "Erro ao descarregar notícias: '%s'." +msgstr "Erro ao descarregar as notícias: '%s'." #. I18N: number of laps to race in a challenge #: src/challenges/challenge_data.cpp:266 @@ -2139,7 +2141,7 @@ msgstr "Clear" #: src/input/binding.cpp:132 msgctxt "input_key" msgid "Return" -msgstr "Mudar de linha" +msgstr "Return" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:134 @@ -2169,7 +2171,7 @@ msgstr "Pausa" #: src/input/binding.cpp:142 msgctxt "input_key" msgid "Caps Lock" -msgstr "Maiúsculas" +msgstr "Caps Lock" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:144 @@ -2571,7 +2573,7 @@ msgstr "Configura os atalhos de teclado." #: src/input/device_manager.cpp:544 msgid "Your input config file is not compatible with this version of STK." -msgstr "O ficheiro de configuração não é compatível com esta versão do SuperTuxKart." +msgstr "O teu ficheiro de configuração não é compatível com esta versão do SuperTuxKart." #. I18N: Name of the black button on xbox controller #: src/input/gamepad_config.cpp:167 diff --git a/data/po/pt_BR.po b/data/po/pt_BR.po index 0a8ff8ef0..96322bdef 100644 --- a/data/po/pt_BR.po +++ b/data/po/pt_BR.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: -# André Marcelo Alvarenga , 2017 +# André Marcelo Alvarenga , 2017-2018 # flaviozavan , 2015-2017 # Laete Meireles , 2015 # Pablo do Amaral Ferreira , 2015 @@ -12,8 +12,8 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-01-18 01:12+0000\n" +"Last-Translator: André Marcelo Alvarenga \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/supertuxkart/supertuxkart/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1827,7 +1827,7 @@ msgstr " Mas você, pequeno patético imbecil, nunca será capaz de me derrotar #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Arena Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the lighthouse" @@ -2941,7 +2941,7 @@ msgstr "Nome do complemento" #: src/states_screens/addons_screen.cpp:116 msgid "Updated date" -msgstr "Atualizar data" +msgstr "Data de atualização" #: src/states_screens/addons_screen.cpp:147 msgid "" @@ -3918,7 +3918,7 @@ msgstr "Dificuldade: %s" #: src/states_screens/race_result_gui.cpp:1440 #, c-format msgid "Best lap time: %s" -msgstr "Melhor tempo de volta: %s" +msgstr "Tempo da melhor volta: %s" #: src/states_screens/race_setup_screen.cpp:87 msgid "All blows allowed, so catch weapons and make clever use of them!" @@ -4003,7 +4003,7 @@ msgstr "Bloqueado!" #: src/states_screens/tracks_and_gp_screen.cpp:278 #: src/states_screens/tracks_screen.cpp:227 msgid "Locked: solve active challenges to gain access to more!" -msgstr "Bloqueado : ganhe os desafios ativos para ter acesso a mais!" +msgstr "Bloqueado: ganhe os desafios ativos para ter acesso a mais!" #: src/states_screens/tracks_screen.cpp:194 msgid "Only official tracks are supported." @@ -4054,7 +4054,7 @@ msgstr "Entrando '%s'" #: src/states_screens/user_screen.cpp:595 #, c-format msgid "Do you really want to delete player '%s' ?" -msgstr "Você realmente quer exlcuir o jogador '%s' ?" +msgstr "Deseja realmente excluir o jogador '%s' ?" #. I18N: Format for dates (%d = day, %m = month, %Y = year). See #. http://www.cplusplus.com/reference/ctime/strftime/ for more info about date diff --git a/data/po/ro.po b/data/po/ro.po index 4cdfaf01a..bcb83b3bb 100644 --- a/data/po/ro.po +++ b/data/po/ro.po @@ -3,14 +3,14 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: -# Nicolae Crefelean, 2015,2017 +# Nicolae Crefelean, 2015,2017-2018 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-03-02 21:38+0000\n" +"Last-Translator: Nicolae Crefelean\n" "Language-Team: Romanian (http://www.transifex.com/supertuxkart/supertuxkart/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -100,13 +100,13 @@ msgstr "Serios... e secret." #. I18N: ./data/achievements.xml msgid "Mosquito Hunter" -msgstr "" +msgstr "Vânătoarea de țânțari" #. I18N: ./data/achievements.xml msgid "" "Take your opponents for mosquitos! With the swatter, squash at least 5 of " "them in a race." -msgstr "" +msgstr "Tratează adversarii ca pe țânțari! Lovește-i cu pliciul de cel puțin 5 ori într-o cursă." #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" diff --git a/data/po/ru.po b/data/po/ru.po index 3d27224ea..e109f4ebf 100644 --- a/data/po/ru.po +++ b/data/po/ru.po @@ -7,14 +7,15 @@ # Dmitry Dubrov , 2015 # Oleg , 2015 # Val Och , 2016 +# Vladislav Tananaev , 2018 # Олег Лазарев , 2017 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Олег Лазарев \n" +"PO-Revision-Date: 2018-03-07 14:35+0000\n" +"Last-Translator: Andrei Stepanov\n" "Language-Team: Russian (http://www.transifex.com/supertuxkart/supertuxkart/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -597,7 +598,7 @@ msgstr "Оружие" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Game Modes" -msgstr "Режим игры" +msgstr "Режимы игры" #. I18N: ./data/gui/help1.stkgui #. I18N: Tab in help menu @@ -744,7 +745,7 @@ msgstr "Следуйте за лидером: будьте на втором м #. I18N: In the help menu msgid "" "3 Strikes Battle: Hit others with weapons until they lose all their lives." -msgstr "Битва Трех Ударов: атакуйте других с помощью оружия до тех пор, пока они не потеряют все свои жизни." +msgstr "Битва трёх ударов: атакуйте других с помощью оружия до тех пор, пока они не потеряют все свои жизни." #. I18N: ./data/gui/help3.stkgui #. I18N: In the help menu @@ -1178,7 +1179,7 @@ msgstr "Вид" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: ./data/gui/online/profile_settings.stkgui msgid "..." -msgstr "..." +msgstr "…" #. I18N: ./data/gui/online/profile_friends.stkgui #. I18N: Section in the profile screen @@ -1334,7 +1335,7 @@ msgstr "Вы можете играть без создания сетевого #. I18N: ./data/gui/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Terms and Agreement" -msgstr "Условия и Соглашение" +msgstr "Условия и соглашение" #. I18N: ./data/gui/online/registration_terms.stkgui #. I18N: In the registration dialog @@ -1467,7 +1468,7 @@ msgstr "Вернуться к списку устройств" #. I18N: ./data/gui/options_input.stkgui #. I18N: In the input configuration screen msgid "Press enter or double-click on a device to configure it" -msgstr "Нажмите Enter или дважды кликните по устройству, чтобы настроить его" +msgstr "Нажмите «Enter» или дважды кликните по устройству, чтобы настроить его" #. I18N: ./data/gui/options_input.stkgui #. I18N: In the input configuration screen @@ -1479,7 +1480,7 @@ msgstr "Добавить устройство" msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." -msgstr "* Выбор конфигурации будет зависеть от того, с какого устройства нажата кнопка \"Выбрать\" при соединении к игре." +msgstr "* Выбор конфигурации будет зависеть от того, с какого устройства нажата кнопка «Выбрать» при соединении к игре." #. I18N: ./data/gui/options_players.stkgui #. I18N: Section in the settings menu @@ -1502,7 +1503,7 @@ msgstr "Вы играете за" #. I18N: ./data/gui/options_players.stkgui #. I18N: In the player configuration screen msgid "Press enter or double-click on a player to edit their settings" -msgstr "Нажмите Enter или дважды кликните по игроку для редактирования его настроек" +msgstr "Нажмите «Enter» или дважды кликните по игроку для редактирования его настроек" #. I18N: ./data/gui/options_players.stkgui #. I18N: In the player configuration screen @@ -1686,7 +1687,7 @@ msgstr "Количество голов для победы" #. I18N: ./data/gui/soccer_setup.stkgui #. I18N: In soccer setup screen msgid "Maximum time (min.)" -msgstr "Максимальное время (мин)" +msgstr "Максимальное время (мин.)" #. I18N: ./data/gui/soccer_setup.stkgui #. I18N: In soccer setup screen @@ -1824,7 +1825,7 @@ msgstr "Если ты победишь меня в гонке, то я осво msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" -msgstr "Но вы, жалкие дурачки, никогда не сможете победить меня — Короля Картов !" +msgstr "Но вы, жалкие дурачки, никогда не сможете победить меня — Короля Картов!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" @@ -1964,28 +1965,28 @@ msgstr "Вильбер" #. I18N: ../stk-assets/karts/xue/kart.xml msgid "Xue" -msgstr "XFCE-мышь" +msgstr "Ксю" #: src/achievements/achievement.cpp:209 #, c-format msgid "Completed achievement \"%s\"." -msgstr "Получено достижение \"%s\"." +msgstr "Получено достижение «%s»." #: src/addons/addons_manager.cpp:104 src/addons/news_manager.cpp:322 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "Не удалось подключиться к серверу аддонов SuperTuxKart." +msgstr "Не удалось подключиться к серверу дополнений SuperTuxKart." #: src/addons/news_manager.cpp:179 #, c-format msgid "Error downloading news: '%s'." -msgstr "Ошибка при получении новостей: %s." +msgstr "Ошибка при получении новостей: «%s»." #. I18N: number of laps to race in a challenge #: src/challenges/challenge_data.cpp:266 #: src/states_screens/race_result_gui.cpp:1424 #, c-format msgid "Laps: %i" -msgstr "Кругов: %i" +msgstr "Кол-во кругов: %i" #: src/challenges/challenge_data.cpp:272 msgid "Follow the leader" @@ -2050,7 +2051,7 @@ msgstr "Началась запись видео." #: src/graphics/irr_driver.cpp:541 #, c-format msgid "Video saved in \"%s\"." -msgstr "Видео сохранено в \"%s\"." +msgstr "Видео сохранено в «%s»." #: src/graphics/irr_driver.cpp:545 msgid "Encoding progress:" @@ -2698,13 +2699,13 @@ msgstr "Это может делать только хозяин игры!" msgid "" "Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " "instructions at supertuxkart.net/Wiimote" -msgstr "Подсоедините wiimote к менеджеру Bluetooth, затем нажмите Ок. Подробную инструкцию смотрите на supertuxkart.net/Wiimote" +msgstr "Подсоедините контроллер Wii к менеджеру Bluetooth, затем нажмите ОК. Подробную инструкцию смотрите на supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:391 msgid "" "Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " "mode, then click on Ok. Detailed instructions at supertuxkart.net/Wiimote" -msgstr "Чтобы попасть в меню поиска, одновременно нажмите кнопки 1+2 на своем wiimote, затем нажмите ОК. Подробную инструкцию смотрите на supertuxkart.net/Wiimote" +msgstr "Чтобы попасть в меню поиска, одновременно нажмите кнопки 1+2 на своём контроллере Wii, затем нажмите ОК. Подробную инструкцию смотрите на supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:414 #, c-format @@ -2725,7 +2726,7 @@ msgstr "Штрафное время!!!" #: src/karts/controller/local_player_controller.cpp:243 msgid "Don't accelerate before go" -msgstr "Не жмите газ до слова \"Вперёд\"!" +msgstr "Не жмите газ до слова «Вперёд»!" #: src/karts/controller/spare_tire_ai.cpp:147 msgid "You can have at most 3 lives!" @@ -2818,7 +2819,7 @@ msgstr "Вы дисквалифицированы!" #: src/modes/world.cpp:1205 #, c-format msgid "'%s' has been eliminated." -msgstr "'%s' выбыл из гонки." +msgstr "'%s' выбыл(-а) из гонки." #: src/network/protocols/server_lobby.cpp:318 #, c-format @@ -2886,12 +2887,12 @@ msgstr "Таблица результатов устарела,\nвсе резу #. I18N: Game mode #: src/race/race_manager.hpp:179 msgid "Follow the Leader" -msgstr "Следуйте за Лидером" +msgstr "Следуйте за лидером" #. I18N: Game mode #: src/race/race_manager.hpp:181 msgid "3 Strikes Battle" -msgstr "Битва Трёх Ударов" +msgstr "Битва трёх ударов" #. I18N: Game mode #: src/race/race_manager.hpp:183 @@ -2956,7 +2957,7 @@ msgstr "Дата обновления" msgid "" "Access to the Internet is disabled. (To enable it, go to options and select " "tab 'User Interface')" -msgstr "Доступ в Интернет отсутствует. (Для включения доступа, перейдите в настройки и выберите вкладку \"Интерфейс\")" +msgstr "Доступ в Интернет отсутствует. (Для включения доступа, перейдите в настройки и выберите вкладку «Интерфейс»)" #. I18N: as in: The Old Island by Johannes Sjolund #: src/states_screens/addons_screen.cpp:343 @@ -3052,13 +3053,13 @@ msgstr "избранное" #: src/states_screens/dialogs/addons_loading.cpp:166 #, c-format msgid "%s MB" -msgstr "%s Мбайт" +msgstr "%s МБ" #: src/states_screens/dialogs/addons_loading.cpp:173 #: src/states_screens/dialogs/addons_loading.cpp:177 #, c-format msgid "%s KB" -msgstr "%s Кбайт" +msgstr "%s КБ" #: src/states_screens/dialogs/addons_loading.cpp:178 #, c-format @@ -3089,7 +3090,7 @@ msgid "" "To add a new Gamepad/Joystick device, simply start SuperTuxKart with it connected and it will appear in the list.\n" "\n" "To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to the computer. Remember that everyone still needs different keybindings in this case.)" -msgstr "Для того, чтобы добавить Геймпад/Джойстик, просто запустите SuperTuxKart, когда он подключен. Он автоматически появится в списке устройств.\n\nЧтобы добавить настройки клавиатуры, вы можете нажать на кнопку, находящуюся ниже. Но учтите, что большинство клавиатур поддерживают только ограниченное количество одновременных нажатий клавиш и поэтому не подходят для многопользовательской игры. (Однако вы можете решить эту проблему подключением нескольких клавиатур к компьютеру. Но даже в этом случае нужно назначать различные сочетания клавиш.)" +msgstr "Для того, чтобы добавить Геймпад/Джойстик, просто запустите SuperTuxKart, когда он подключён. Он автоматически появится в списке устройств.\n\nЧтобы добавить настройки клавиатуры, вы можете нажать на кнопку, находящуюся ниже. Но учтите, что большинство клавиатур поддерживают только ограниченное количество одновременных нажатий клавиш и поэтому не подходят для многопользовательской игры. (Однако вы можете решить эту проблему подключением нескольких клавиатур к компьютеру. Но даже в этом случае нужно назначать различные сочетания клавиш.)" #. I18N: In the 'add new input device' dialog #: src/states_screens/dialogs/add_device_dialog.cpp:90 @@ -3434,7 +3435,7 @@ msgstr "Имя не задано." #: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." -msgstr "Уже существует Гран-при с таким же названием." +msgstr "Гран-при с таким же названием уже существует." #: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." @@ -3467,7 +3468,7 @@ msgstr "Заблокировано" msgid "" "Everyone:\n" "Press the 'Select' button to join the game" -msgstr "Всем:\nДля присоединения к игре нажмите клавишу \"Выбрать\" " +msgstr "Всем:\nДля присоединения к игре нажмите клавишу «Выбрать»" #: src/states_screens/main_menu_screen.cpp:510 msgid "" @@ -3512,7 +3513,7 @@ msgstr "Профиль %s" #: src/states_screens/online_profile_friends.cpp:75 msgid "Since" -msgstr "С" +msgstr " Дата" #: src/states_screens/online_profile_friends.cpp:76 msgid "Status" @@ -3683,7 +3684,7 @@ msgstr "Сенсорное устройство" msgid "" "In multiplayer mode, players can select handicapped (more difficult) " "profiles on the kart selection screen" -msgstr "В многопользовательском режиме игроки могут выбрать профили гандикапа (сложности) на экране выбора карта." +msgstr "В многопользовательском режиме игроки могут выбрать профили гандикапа (сложности) на экране выбора карта" #. I18N: in the language choice, to select the same language as the OS #: src/states_screens/options_screen_ui.cpp:191 @@ -3731,7 +3732,7 @@ msgstr "Динамическое освещение: %s" #: src/states_screens/options_screen_video.cpp:498 #, c-format msgid "Motion blur: %s" -msgstr "Размытие при движении: %s" +msgstr "Размытие в движении: %s" #. I18N: in graphical options #: src/states_screens/options_screen_video.cpp:501 @@ -3890,7 +3891,7 @@ msgstr "Вы действительно хотите прервать Гран- #: src/states_screens/race_result_gui.cpp:499 #: src/states_screens/race_result_gui.cpp:865 msgid "Eliminated" -msgstr "Выбыл из гонки" +msgstr "Выбыл(-а) из гонки" #: src/states_screens/race_result_gui.cpp:1012 msgid "Red Team Wins" @@ -3939,7 +3940,7 @@ msgstr "Все возможности доступны, так что собир #: src/states_screens/race_setup_screen.cpp:94 msgid "Contains no powerups, so only your driving skills matter!" -msgstr "Не содержит бонусов, только ваши навыки вождения имеют значение!" +msgstr "Никаких бонусов, важны только ваши навыки вождения!" #. I18N: short definition for follow-the-leader game mode #: src/states_screens/race_setup_screen.cpp:107 @@ -3986,7 +3987,7 @@ msgstr "Электронная почта должна содержать от 4 #: src/states_screens/register_screen.cpp:299 msgid "Email is invalid!" -msgstr "Недоступная электронная почта!" +msgstr "Недействительная электронная почта!" #: src/states_screens/register_screen.cpp:362 msgid "" @@ -4074,7 +4075,7 @@ msgstr "Вы действительно хотите удалить игрока #. formats. #: src/utils/time.cpp:50 msgid "%d/%m/%Y" -msgstr "%д.%м.%Г" +msgstr "%d.%m.%Y" #. I18N: Do NOT literally translate this string!! Please enter Y as the #. translation if your language is a RTL (right-to-left) language, diff --git a/data/po/sk.po b/data/po/sk.po index 54f9abc53..debca8cd1 100644 --- a/data/po/sk.po +++ b/data/po/sk.po @@ -7,13 +7,14 @@ # Dušan Kazik , 2015 # FIRST AUTHOR , 2010 # MiroslavR , 2015-2016 +# Vladimír Záhradník , 2018 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-01-05 11:47+0000\n" +"Last-Translator: Vladimír Záhradník \n" "Language-Team: Slovak (http://www.transifex.com/supertuxkart/supertuxkart/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -296,7 +297,7 @@ msgstr "Osvetlenie založené na obrázku" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Bloom" -msgstr "" +msgstr "Bloom (rozptýlené svetlo)" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -306,7 +307,7 @@ msgstr "Svetelné lúče" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient Occlusion" -msgstr "" +msgstr "Zatienenie okolím" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -356,12 +357,12 @@ msgstr "Animácia postáv" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Rendered image quality" -msgstr "" +msgstr "Kvalita vykresľovaného obrazu" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Geometry detail" -msgstr "" +msgstr "Geometrické podrobnosti" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -465,12 +466,12 @@ msgstr "Pokračovať" #. I18N: ./data/gui/track_info.stkgui #. I18N: In the track info screen msgid "Record the race for ghost replay" -msgstr "" +msgstr "Nahrať pretek pre opakovačku s duchom" #. I18N: ./data/gui/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action msgid "Watch replay only" -msgstr "" +msgstr "Iba pozrieť opakovačku" #. I18N: ./data/gui/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info screen action @@ -486,17 +487,17 @@ msgstr "Začať preteky" #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Ghost Replay Selection" -msgstr "" +msgstr "Výber opakovačky s duchom" #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show replays matching the current difficulty" -msgstr "" +msgstr "Zobrazovať iba opakovačky odpovedajúce aktuálnej obtiažnosti" #. I18N: ./data/gui/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Record ghost replay" -msgstr "" +msgstr "Nahrať pre opakovačku s duchom" #. I18N: ./data/gui/gp_info.stkgui #. I18N: In the grand prix info screen @@ -609,7 +610,7 @@ msgstr "Herné režimy" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Multi-player" -msgstr "" +msgstr "Hra viac hráčov" #. I18N: ./data/gui/help1.stkgui #. I18N: Tab in help menu @@ -622,11 +623,11 @@ msgstr "" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Bananas" -msgstr "" +msgstr "Banány" #. I18N: ./data/gui/help1.stkgui msgid "Start the tutorial" -msgstr "" +msgstr "Spustiť výuku" #. I18N: ./data/gui/help1.stkgui #. I18N: In the help menu @@ -729,7 +730,7 @@ msgstr "Obyčajné preteky: Povoľujú sa všetky údery, tak sa chopte zbraní msgid "" "Time Trial: Contains no powerups, so only your driving skills matter! This " "mode allows you to record the race for replaying." -msgstr "" +msgstr "Pretek na čas: Neobsahuje žiadne bonusy, záleží iba na vašich vodičských schopnostiach! Tento režim umožňuje nahrávať pretek pre neskoršie spätné prehrávanie." #. I18N: ./data/gui/help3.stkgui #. I18N: In the help menu @@ -748,7 +749,7 @@ msgstr "Bitka na 3 údery: Triafajte ostatných hráčov zbraňami, kým nepríd #. I18N: ./data/gui/help3.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." -msgstr "" +msgstr "Futbal: Použite svoju motokáru na natlačenie lopty do bránky." #. I18N: ./data/gui/help3.stkgui #. I18N: In the help menu @@ -798,24 +799,24 @@ msgstr "Po nakonfigurovaní vstupných zariadení môžete začať hrať. V hlav msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" -msgstr "" +msgstr "Náraz do banánu môže mať za následok, že sa pripojí k motokáre jedna z nasledujúcich položiek:" #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart." -msgstr "" +msgstr "Kotva - spomaľuje motokáru." #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Parachute - slows down the kart less than the anchor." -msgstr "" +msgstr "Padák - spomaľuje motokáru menej než kotva." #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after a short amount of time to throw the kart up in the " "air. Bump into another kart to transfer the bomb to another player." -msgstr "" +msgstr "Bomba - po chvíli vybuchne a vyhodí motokáru do vzduchu. Nárazom do inej motokáry prehodíte bombu inému hráčovi." #. I18N: ./data/gui/karts.stkgui #. I18N: In the kart selection (player setup) screen @@ -904,46 +905,46 @@ msgstr "Ukončiť" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Touch Device Settings" -msgstr "" +msgstr "Nastavenia dotykového zariadenia" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Device enabled" -msgstr "" +msgstr "Zariadenie je povolené" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Inverted buttons" -msgstr "" +msgstr "Prehodené tlačidlá" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "" +msgstr "Rozsah tlačidiel" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Accelerometer" -msgstr "" +msgstr "Akcelerometer" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "" +msgstr "Pokročilé" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Deadzone" -msgstr "" +msgstr "Zóna smrti" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Sensitivity" -msgstr "" +msgstr "Citlivosť" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Restore defaults" -msgstr "" +msgstr "Obnoviť predvolené nastavenia" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog @@ -1208,7 +1209,7 @@ msgstr "Servery" #. I18N: ./data/gui/online/profile_servers.stkgui msgid "Local Networking" -msgstr "" +msgstr "Lokálna sieť" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen @@ -1223,7 +1224,7 @@ msgstr "Vytvoriť server" #. I18N: ./data/gui/online/profile_servers.stkgui msgid "Global Networking" -msgstr "" +msgstr "Globálna sieť" #. I18N: ./data/gui/online/profile_servers.stkgui #. I18N: In the online multiplayer screen @@ -1501,7 +1502,7 @@ msgstr "Hráte ako" #. I18N: ./data/gui/options_players.stkgui #. I18N: In the player configuration screen msgid "Press enter or double-click on a player to edit their settings" -msgstr "" +msgstr "Stlačte enter alebo dvakrát rýchlo kliknite na hráča, aby ste upravili jeho nastavenia" #. I18N: ./data/gui/options_players.stkgui #. I18N: In the player configuration screen @@ -1756,7 +1757,7 @@ msgstr "Vymazať" #. I18N: ../stk-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" -msgstr "" +msgstr "Predpotopná priepasť" #. I18N: ../stk-assets/tracks/battleisland/track.xml msgid "Battle Island" @@ -1764,7 +1765,7 @@ msgstr "Boj na ostrove" #. I18N: ../stk-assets/tracks/candela_city/track.xml msgid "Candela City" -msgstr "" +msgstr "Mesto Candela" #. I18N: ../stk-assets/tracks/cave/track.xml msgid "Cave X" @@ -1776,7 +1777,7 @@ msgstr "Kakaový chrám" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" -msgstr "" +msgstr "Kros kukuričným poľom" #. I18N: ../stk-assets/tracks/fortmagma/track.xml msgid "Fort Magma" @@ -1796,7 +1797,7 @@ msgstr "Hacienda" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" -msgstr "" +msgstr "Ľadové futbalové ihrisko" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml @@ -1827,7 +1828,7 @@ msgstr "No poraziť mňa – kráľa motokár – sa vám úbohým krpcom nikdy #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Piesočné duny" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the lighthouse" @@ -1883,7 +1884,7 @@ msgstr "Chrám" #. I18N: ../stk-assets/tracks/volcano_island/track.xml msgid "Volcan Island" -msgstr "" +msgstr "Sopečný ostrov" #. I18N: ../stk-assets/tracks/xr591/track.xml msgid "XR591" @@ -1923,7 +1924,7 @@ msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" @@ -1972,7 +1973,7 @@ msgstr "Dokončili ste úspech „%s“." #: src/addons/addons_manager.cpp:104 src/addons/news_manager.cpp:322 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "" +msgstr "Nepodarilo sa pripojiť k serveru doplnkov SuperTuxKart." #: src/addons/news_manager.cpp:179 #, c-format @@ -2044,16 +2045,16 @@ msgstr "Váš konfiguračný súbor bol príliš starý, takže bol zmazaný a v #: src/graphics/irr_driver.cpp:535 msgid "Video recording started." -msgstr "" +msgstr "Začalo nahrávanie videa." #: src/graphics/irr_driver.cpp:541 #, c-format msgid "Video saved in \"%s\"." -msgstr "" +msgstr "Video uložené do „%s“." #: src/graphics/irr_driver.cpp:545 msgid "Encoding progress:" -msgstr "" +msgstr "Priebeh kódovania:" #: src/graphics/irr_driver.cpp:1682 #, c-format @@ -2593,25 +2594,25 @@ msgstr "Ľavá spúšť" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:181 src/input/gamepad_config.cpp:244 msgid "Right thumb right" -msgstr "" +msgstr "Pravý palec doprava" #. I18N: name of buttons on gamepads #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:183 src/input/gamepad_config.cpp:246 msgid "Right thumb left" -msgstr "" +msgstr "Pravý palec doľava" #. I18N: name of buttons on gamepads #. I18N: name of trigger on gamepads #: src/input/gamepad_config.cpp:185 src/input/gamepad_config.cpp:240 msgid "Right thumb down" -msgstr "" +msgstr "Pravý palec nadol" #. I18N: name of buttons on gamepads #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:187 src/input/gamepad_config.cpp:242 msgid "Right thumb up" -msgstr "" +msgstr "Pravý palec nahor" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:189 src/input/gamepad_config.cpp:248 @@ -2657,32 +2658,32 @@ msgstr "Start" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:220 msgid "Left thumb button" -msgstr "" +msgstr "Tlačidlo ľavého palca" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:222 msgid "Right thumb button" -msgstr "" +msgstr "Tlačidlo pravého palca" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:231 msgid "Left thumb right" -msgstr "" +msgstr "Ľavý palec doprava" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:233 msgid "Left thumb left" -msgstr "" +msgstr "Ľavý palec doľava" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:235 msgid "Left thumb down" -msgstr "" +msgstr "Ľavý palec nadol" #. I18N: name of stick on gamepads #: src/input/gamepad_config.cpp:237 msgid "Left thumb up" -msgstr "" +msgstr "Ľavý palec nahor" #: src/input/input_manager.cpp:807 #, c-format @@ -2697,13 +2698,13 @@ msgstr "V tejto chvíli môže vykonávať činnosť iba vlastník hry!" msgid "" "Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " "instructions at supertuxkart.net/Wiimote" -msgstr "" +msgstr "Pripojte svoj Wiimote ovládač v Správe Bluetooth zariadení a potom kliknite na tlačidlo OK. Podrobný návod je na supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:391 msgid "" "Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " "mode, then click on Ok. Detailed instructions at supertuxkart.net/Wiimote" -msgstr "" +msgstr "Súčasne na svojom Wiimote ovládači stlačte tlačidlá 1+2, čím ho prepnete do režimu vyhľadávania. Potom kliknite na tlačidlo Ok. Podrobný návod je na supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:414 #, c-format @@ -2727,11 +2728,11 @@ msgstr "Nepridávajte plyn pred štartom" #: src/karts/controller/spare_tire_ai.cpp:147 msgid "You can have at most 3 lives!" -msgstr "" +msgstr "Môžete mať najviac 3 životy!" #: src/karts/controller/spare_tire_ai.cpp:153 msgid "+1 life." -msgstr "" +msgstr "+1 život." #: src/karts/kart.cpp:908 src/karts/kart.cpp:913 msgid "You won the race!" @@ -2754,7 +2755,7 @@ msgstr "SuperTuxKart sa môže pripájať na server s cieľom sťahovať doplnky #: src/main.cpp:1654 msgid "Your screen resolution is too low to run STK." -msgstr "" +msgstr "Rozlíšenie vašej obrazovky je príliš nízke na spustenie STK." #: src/main.cpp:1668 msgid "" @@ -2766,7 +2767,7 @@ msgstr "Verzia ovládača grafickej karty je príliš stará. Prosím, nainštal msgid "" "Your OpenGL version appears to be too old. Please verify if an update for " "your video driver is available. SuperTuxKart requires %s or better." -msgstr "" +msgstr "Verzia vášho OpenGL sa zdá byť príliš stará. Overte, prosím, či nie je k dispozícii aktualizácia ovládača vašej grafickej karty. SuperTuxKart vyžaduje verziu %s alebo vyššiu." #: src/modes/easter_egg_hunt.cpp:202 #, c-format @@ -2804,9 +2805,9 @@ msgstr "ZLÁ CESTA!" #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "Vznikla %i náhradná pneumatika pre motokáru!" +msgstr[1] "Vznikli %i náhradné pneumatiky pre motokáru!" +msgstr[2] "Vzniklo %i náhradných pneumatík pre motokáru!" #: src/modes/world.cpp:1202 msgid "You have been eliminated!" @@ -2820,7 +2821,7 @@ msgstr "'%s' bol(a) vyradený(á)." #: src/network/protocols/server_lobby.cpp:318 #, c-format msgid "Failed to register server: %s" -msgstr "" +msgstr "Nepodarilo sa zaregistrovať server: %s" #: src/network/servers_manager.cpp:198 msgid "No LAN server detected" @@ -2900,12 +2901,12 @@ msgstr "Futbal" #: src/replay/replay_recorder.cpp:183 msgid "Incomplete replay file will not be saved." -msgstr "" +msgstr "Neúplný súbor s opakovačkou nebude uložený." #: src/replay/replay_recorder.cpp:219 #, c-format msgid "Replay saved in \"%s\"." -msgstr "" +msgstr "Opakovačka uložená do „%s\"." #: src/states_screens/addons_screen.cpp:50 msgid "1 week" @@ -2951,7 +2952,7 @@ msgstr "Dátum aktualizácie" msgid "" "Access to the Internet is disabled. (To enable it, go to options and select " "tab 'User Interface')" -msgstr "" +msgstr "Prístup k internetu je zakázaný. (Pokiaľ ho chcete povoliť, prejdite do ponuky Možnosti a vyberte kartu „Používateľské rozhranie“)" #. I18N: as in: The Old Island by Johannes Sjolund #: src/states_screens/addons_screen.cpp:343 @@ -3001,9 +3002,9 @@ msgstr "Náhodná aréna" #, c-format msgid "%d arena unavailable in single player." msgid_plural "%d arenas unavailable in single player." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "%d aréna nie je k dispozícii v režime jedného hráča." +msgstr[1] "%d arény nie sú k dispozícii v režime jedného hráča." +msgstr[2] "%d arén nie je k dispozícii v režime jedného hráča." #: src/states_screens/create_server_screen.cpp:82 msgid "Create LAN Server" @@ -3145,7 +3146,7 @@ msgstr "Zakázané" #: src/states_screens/dialogs/custom_video_settings.cpp:67 #: src/states_screens/options_screen_video.cpp:462 msgid "Important only" -msgstr "" +msgstr "Iba dôležité" #. I18N: animations setting (only karts with human players are animated) #: src/states_screens/dialogs/custom_video_settings.cpp:74 @@ -3164,7 +3165,7 @@ msgstr "Povolená pre všetky" #: src/states_screens/dialogs/custom_video_settings.cpp:102 #: src/states_screens/options_screen_video.cpp:469 msgid "Low" -msgstr "" +msgstr "Nízka" #. I18N: Geometry level high : everything is displayed #. I18N: in the graphical options tooltip; @@ -3174,21 +3175,21 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:103 #: src/states_screens/options_screen_video.cpp:472 msgid "High" -msgstr "" +msgstr "Vysoká" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very low #: src/states_screens/dialogs/custom_video_settings.cpp:94 #: src/states_screens/options_screen_video.cpp:466 msgid "Very Low" -msgstr "" +msgstr "Veľmi nízka" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very high #: src/states_screens/dialogs/custom_video_settings.cpp:97 #: src/states_screens/options_screen_video.cpp:475 msgid "Very High" -msgstr "" +msgstr "Veľmi vysoká" #: src/states_screens/dialogs/message_dialog.cpp:129 #: src/states_screens/edit_gp_screen.cpp:257 @@ -3198,11 +3199,11 @@ msgstr "Nie" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:60 msgid "Tablet" -msgstr "" +msgstr "Tablet" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:61 msgid "Phone" -msgstr "" +msgstr "Telefón" #: src/states_screens/dialogs/recovery_dialog.cpp:121 msgid "Username and/or email address invalid." @@ -3216,7 +3217,7 @@ msgid "" "the box below, you are confirming that you understand these terms. If you " "have any questions or comments regarding these terms, one of the members of " "the development team would gladly assist you." -msgstr "" +msgstr "Prečítajte si, prosím, zmluvné podmienky pre SuperTuxKart na adrese '%s'. S týmito podmienkami musíte súhlasiť, aby ste si mohli zaregistrovať účet pre STK. Zaškrtnutím políčka nižšie potvrdzujete, že týmto podmienkam rozumiete. Pokiaľ máte akékoľvek otázky alebo pripomienky k týmto podmienkam, niektorý z členov vývojového tímu vám rád pomôže." #: src/states_screens/dialogs/select_challenge.cpp:52 #, c-format @@ -3245,7 +3246,7 @@ msgstr "Zber nitra" #: src/states_screens/dialogs/select_challenge.cpp:151 #: src/states_screens/race_setup_screen.cpp:136 msgid "Ghost replay race" -msgstr "" +msgstr "Opakovaný pretek s duchom" #: src/states_screens/dialogs/server_info_dialog.cpp:75 msgid "Server successfully created. You can now join it." @@ -3382,11 +3383,11 @@ msgstr "Odomkli ste grand prix %0" #: src/states_screens/ghost_replay_selection.cpp:82 msgid "Finish Time" -msgstr "" +msgstr "Konečný čas" #: src/states_screens/ghost_replay_selection.cpp:83 msgid "User" -msgstr "" +msgstr "Používateľ" #: src/states_screens/gp_info_screen.cpp:74 msgid "Default" @@ -3405,7 +3406,7 @@ msgstr "Náhodné" #: src/states_screens/gp_info_screen.cpp:154 #: src/states_screens/gp_info_screen.cpp:179 msgid "Reload" -msgstr "" +msgstr "Znovu načítať" #: src/states_screens/grand_prix_cutscene.cpp:75 #: src/states_screens/grand_prix_editor_screen.cpp:101 @@ -3454,7 +3455,7 @@ msgstr "Náhodná motokára" #: src/states_screens/kart_selection.cpp:859 msgid "Locked" -msgstr "" +msgstr "Uzamknuté" #: src/states_screens/kart_selection.cpp:961 msgid "" @@ -3478,7 +3479,7 @@ msgstr "Bez prístupu k internetu nemožno sťahovať doplnky. Ak chcete sťahov #: src/states_screens/main_menu_screen.cpp:566 msgid "The add-ons module is currently disabled in the Options screen" -msgstr "" +msgstr "Modul „Doplnky“ je momentálne vypnutý v ponuke Možnosti" #: src/states_screens/main_menu_screen.cpp:578 msgid "Please wait while the add-ons are loading" @@ -3670,13 +3671,13 @@ msgstr "Klávesnica %i" #: src/states_screens/options_screen_input.cpp:138 msgid "Touch Device" -msgstr "" +msgstr "Dotykové zariadenie" #: src/states_screens/options_screen_ui.cpp:159 msgid "" "In multiplayer mode, players can select handicapped (more difficult) " "profiles on the kart selection screen" -msgstr "" +msgstr "V režime viac hráčov si hráči môžu vybrať profil „hendikepovaný“ (náročnejší) na obrazovke výberu motokár" #. I18N: in the language choice, to select the same language as the OS #: src/states_screens/options_screen_ui.cpp:191 @@ -3736,7 +3737,7 @@ msgstr "Antialiasing: %s" #: src/states_screens/options_screen_video.cpp:504 #, c-format msgid "Ambient occlusion: %s" -msgstr "" +msgstr "Zatienenie okolím: %s" #: src/states_screens/options_screen_video.cpp:508 #, c-format @@ -3752,7 +3753,7 @@ msgstr "Tiene: %i" #: src/states_screens/options_screen_video.cpp:513 #, c-format msgid "Bloom: %s" -msgstr "" +msgstr "Bloom (rozptýlené svetlo): %s" #. I18N: in graphical options #: src/states_screens/options_screen_video.cpp:517 @@ -3781,7 +3782,7 @@ msgstr "Globálne osvetlenie: %s" #: src/states_screens/options_screen_video.cpp:534 #, c-format msgid "Rendered image quality: %s" -msgstr "" +msgstr "Kvalita vykresľovaného obrazu: %s" #: src/states_screens/race_gui.cpp:358 src/states_screens/race_gui.cpp:360 msgid "Challenge Failed" @@ -3838,7 +3839,7 @@ msgstr "Poradie" #: src/states_screens/race_gui_overworld.cpp:518 msgid "Press fire to start the tutorial" -msgstr "" +msgstr "Stlačte tlačidlo streľby pre zahájenie výuky" #: src/states_screens/race_gui_overworld.cpp:557 msgid "Type: Grand Prix" @@ -3850,7 +3851,7 @@ msgstr "Výzvu začnete stlačením tlačidla na útok" #: src/states_screens/race_result_gui.cpp:175 msgid "Continue." -msgstr "" +msgstr "Pokračovať." #: src/states_screens/race_result_gui.cpp:178 msgid "Quit the server." @@ -3945,7 +3946,7 @@ msgstr "Triafajte ostatných hráčov zbraňami, kým neprídu o všetky životy #: src/states_screens/race_setup_screen.cpp:119 msgid "Push the ball into the opposite cage to score goals." -msgstr "" +msgstr "Dotlačte loptu do bránky protihráča." #: src/states_screens/race_setup_screen.cpp:129 msgid "Explore tracks to find all hidden eggs" @@ -3953,7 +3954,7 @@ msgstr "Nájdite všetky vajíčka poskrývané na tratiach" #: src/states_screens/race_setup_screen.cpp:137 msgid "Race against ghost karts and try to beat them!" -msgstr "" +msgstr "Pretekajte proti motokáram duchov a skúste ich poraziť!" #: src/states_screens/register_screen.cpp:218 #: src/states_screens/register_screen.cpp:225 @@ -4036,7 +4037,7 @@ msgstr "Jazda naopak" #. I18N: In the track info screen #: src/states_screens/track_info_screen.cpp:218 msgid "Random item location" -msgstr "" +msgstr "Náhodné rozmiestnenie položky" #: src/states_screens/user_screen.cpp:111 msgid "Exit game" diff --git a/data/po/sl.po b/data/po/sl.po index e8f2a369d..b9b18a6bd 100644 --- a/data/po/sl.po +++ b/data/po/sl.po @@ -4,13 +4,14 @@ # # Translators: # Andrej Znidarsic , 2015-2016 +# Sasa Batistic , 2018 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-02-28 13:25+0000\n" +"Last-Translator: Sasa Batistic \n" "Language-Team: Slovenian (http://www.transifex.com/supertuxkart/supertuxkart/language/sl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -619,11 +620,11 @@ msgstr "Več igralski način." #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Bananas" -msgstr "" +msgstr "Banane" #. I18N: ./data/gui/help1.stkgui msgid "Start the tutorial" -msgstr "" +msgstr "Začni z vodnikom" #. I18N: ./data/gui/help1.stkgui #. I18N: In the help menu @@ -800,12 +801,12 @@ msgstr "" #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart." -msgstr "" +msgstr "Sidro - upočasni vozilo." #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu msgid "Parachute - slows down the kart less than the anchor." -msgstr "" +msgstr "Padalo - manj upočasni dirkalnik kot sidro." #. I18N: ./data/gui/help5.stkgui #. I18N: In the help menu diff --git a/data/po/tr.po b/data/po/tr.po index de395e25d..b5760c4ee 100644 --- a/data/po/tr.po +++ b/data/po/tr.po @@ -12,7 +12,7 @@ msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" +"PO-Revision-Date: 2017-12-06 00:21+0000\n" "Last-Translator: yakup \n" "Language-Team: Turkish (http://www.transifex.com/supertuxkart/supertuxkart/language/tr/)\n" "MIME-Version: 1.0\n" @@ -1923,11 +1923,11 @@ msgstr "" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" -msgstr "" +msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml msgid "Nolok" @@ -1935,11 +1935,11 @@ msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml msgid "Pidgin" -msgstr "" +msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml msgid "Puffy" -msgstr "" +msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml msgid "Sara the Racer" @@ -1959,7 +1959,7 @@ msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml msgid "Wilber" -msgstr "" +msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml msgid "Xue" diff --git a/data/po/uk.po b/data/po/uk.po index 7d27471c9..3482693ce 100644 --- a/data/po/uk.po +++ b/data/po/uk.po @@ -5,13 +5,14 @@ # Translators: # fedik , 2015-2017 # Max Lyashuk , 2015-2016 +# Yaroslav Serhieiev , 2018 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2018-03-25 14:40+0000\n" +"Last-Translator: Yaroslav Serhieiev \n" "Language-Team: Ukrainian (http://www.transifex.com/supertuxkart/supertuxkart/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -912,7 +913,7 @@ msgstr "Пристрій увімкнено" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Inverted buttons" -msgstr "" +msgstr "Інвертовані кнопки" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -1825,7 +1826,7 @@ msgstr "Але ви, жалюгідні волоцюги, ніколи не зм #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Арена Лас Дунас" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the lighthouse" diff --git a/data/po/zh_CN.po b/data/po/zh_CN.po index db0aad8b2..cfdffa9be 100644 --- a/data/po/zh_CN.po +++ b/data/po/zh_CN.po @@ -7,13 +7,14 @@ # Benau, 2016 # Benau, 2015-2016 # Jin Zhang , 2015 +# Jz Pan , 2017 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-04 20:58-0400\n" -"PO-Revision-Date: 2017-11-13 00:19+0000\n" -"Last-Translator: Auria \n" +"PO-Revision-Date: 2017-11-14 04:13+0000\n" +"Last-Translator: Jz Pan \n" "Language-Team: Chinese (China) (http://www.transifex.com/supertuxkart/supertuxkart/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -356,12 +357,12 @@ msgstr "角色动画" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Rendered image quality" -msgstr "" +msgstr "渲染图像质量" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings msgid "Geometry detail" -msgstr "" +msgstr "几何细节" #. I18N: ./data/gui/custom_video_settings.stkgui #. I18N: Video settings @@ -622,11 +623,11 @@ msgstr "多人游戏" #. I18N: ./data/gui/help5.stkgui #. I18N: Tab in help menu msgid "Bananas" -msgstr "" +msgstr "香蕉" #. I18N: ./data/gui/help1.stkgui msgid "Start the tutorial" -msgstr "" +msgstr "开始教学关" #. I18N: ./data/gui/help1.stkgui #. I18N: In the help menu @@ -904,46 +905,46 @@ msgstr "退出" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Touch Device Settings" -msgstr "" +msgstr "触屏设备设置" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Device enabled" -msgstr "" +msgstr "设备启用" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Inverted buttons" -msgstr "" +msgstr "反转按键" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "" +msgstr "按键大小" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Accelerometer" -msgstr "" +msgstr "加速计" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "" +msgstr "高级" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Deadzone" -msgstr "" +msgstr "死区" #. I18N: ./data/gui/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Sensitivity" -msgstr "" +msgstr "灵敏度" #. I18N: ./data/gui/multitouch_settings.stkgui msgid "Restore defaults" -msgstr "" +msgstr "恢复默认" #. I18N: ./data/gui/online/change_password.stkgui #. I18N: In the change password dialog @@ -1764,7 +1765,7 @@ msgstr "战斗之岛" #. I18N: ../stk-assets/tracks/candela_city/track.xml msgid "Candela City" -msgstr "" +msgstr "坎德拉城" #. I18N: ../stk-assets/tracks/cave/track.xml msgid "Cave X" @@ -1776,7 +1777,7 @@ msgstr "可可寺院" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" -msgstr "" +msgstr "玉米地穿越" #. I18N: ../stk-assets/tracks/fortmagma/track.xml msgid "Fort Magma" @@ -1827,7 +1828,7 @@ msgstr " 不过你们这些可怜的小蠢货是永远不可能打败我这个 #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Las Dunas 竞技场" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the lighthouse" @@ -1923,7 +1924,7 @@ msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" @@ -1972,7 +1973,7 @@ msgstr "完成成就 “%s”。" #: src/addons/addons_manager.cpp:104 src/addons/news_manager.cpp:322 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "" +msgstr "无法连接到 SuperTuxKart 附加组件服务器。" #: src/addons/news_manager.cpp:179 #, c-format @@ -2044,16 +2045,16 @@ msgstr "你的配置文件太旧了,新的配置文件已经创建。" #: src/graphics/irr_driver.cpp:535 msgid "Video recording started." -msgstr "" +msgstr "视频录制开始。" #: src/graphics/irr_driver.cpp:541 #, c-format msgid "Video saved in \"%s\"." -msgstr "" +msgstr "视频已保存到 \"%s\"。" #: src/graphics/irr_driver.cpp:545 msgid "Encoding progress:" -msgstr "" +msgstr "编码进度:" #: src/graphics/irr_driver.cpp:1682 #, c-format @@ -2725,11 +2726,11 @@ msgstr "请不要在“开始”显示之前加速" #: src/karts/controller/spare_tire_ai.cpp:147 msgid "You can have at most 3 lives!" -msgstr "" +msgstr "你最多可以有 3 条命!" #: src/karts/controller/spare_tire_ai.cpp:153 msgid "+1 life." -msgstr "" +msgstr "+1 命" #: src/karts/kart.cpp:908 src/karts/kart.cpp:913 msgid "You won the race!" @@ -2752,7 +2753,7 @@ msgstr "SuperTuxKart 可能會连接到服务器下载插件并通知你更新 #: src/main.cpp:1654 msgid "Your screen resolution is too low to run STK." -msgstr "" +msgstr "你的屏幕分辨率太低, 无法运行 STK。" #: src/main.cpp:1668 msgid "" @@ -3133,7 +3134,7 @@ msgstr "已禁用" #: src/states_screens/dialogs/custom_video_settings.cpp:67 #: src/states_screens/options_screen_video.cpp:462 msgid "Important only" -msgstr "" +msgstr "只有重要的" #. I18N: animations setting (only karts with human players are animated) #: src/states_screens/dialogs/custom_video_settings.cpp:74 @@ -3152,7 +3153,7 @@ msgstr "启用所有" #: src/states_screens/dialogs/custom_video_settings.cpp:102 #: src/states_screens/options_screen_video.cpp:469 msgid "Low" -msgstr "" +msgstr "低" #. I18N: Geometry level high : everything is displayed #. I18N: in the graphical options tooltip; @@ -3162,21 +3163,21 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:103 #: src/states_screens/options_screen_video.cpp:472 msgid "High" -msgstr "" +msgstr "高" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very low #: src/states_screens/dialogs/custom_video_settings.cpp:94 #: src/states_screens/options_screen_video.cpp:466 msgid "Very Low" -msgstr "" +msgstr "非常低" #. I18N: in the graphical options tooltip; #. indicates the rendered image quality is very high #: src/states_screens/dialogs/custom_video_settings.cpp:97 #: src/states_screens/options_screen_video.cpp:475 msgid "Very High" -msgstr "" +msgstr "非常高" #: src/states_screens/dialogs/message_dialog.cpp:129 #: src/states_screens/edit_gp_screen.cpp:257 @@ -3186,11 +3187,11 @@ msgstr "否" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:60 msgid "Tablet" -msgstr "" +msgstr "平板电脑" #: src/states_screens/dialogs/multitouch_settings_dialog.cpp:61 msgid "Phone" -msgstr "" +msgstr "手机" #: src/states_screens/dialogs/recovery_dialog.cpp:121 msgid "Username and/or email address invalid." @@ -3374,7 +3375,7 @@ msgstr "完成时间" #: src/states_screens/ghost_replay_selection.cpp:83 msgid "User" -msgstr "" +msgstr "用户" #: src/states_screens/gp_info_screen.cpp:74 msgid "Default" @@ -3658,7 +3659,7 @@ msgstr "键盘 %i" #: src/states_screens/options_screen_input.cpp:138 msgid "Touch Device" -msgstr "" +msgstr "触屏设备" #: src/states_screens/options_screen_ui.cpp:159 msgid "" @@ -3769,7 +3770,7 @@ msgstr "全域照明:%s" #: src/states_screens/options_screen_video.cpp:534 #, c-format msgid "Rendered image quality: %s" -msgstr "" +msgstr "渲染图像质量: %s" #: src/states_screens/race_gui.cpp:358 src/states_screens/race_gui.cpp:360 msgid "Challenge Failed" @@ -3826,7 +3827,7 @@ msgstr "排名" #: src/states_screens/race_gui_overworld.cpp:518 msgid "Press fire to start the tutorial" -msgstr "" +msgstr "按使用道具键开始教学关" #: src/states_screens/race_gui_overworld.cpp:557 msgid "Type: Grand Prix" diff --git a/data/shaders/sp_grass_pass.vert b/data/shaders/sp_grass_pass.vert index 074754bea..768932f08 100644 --- a/data/shaders/sp_grass_pass.vert +++ b/data/shaders/sp_grass_pass.vert @@ -11,13 +11,7 @@ layout(location = 1) in vec4 i_normal; layout(location = 2) in vec4 i_color; layout(location = 3) in vec2 i_uv; layout(location = 8) in vec3 i_origin; - -#if defined(Converts_10bit_Vector) -layout(location = 9) in vec4 i_rotation_orig; -#else layout(location = 9) in vec4 i_rotation; -#endif - layout(location = 10) in vec4 i_scale; layout(location = 12) in ivec2 i_misc_data; @@ -32,16 +26,14 @@ void main() #if defined(Converts_10bit_Vector) vec4 i_normal = convert10BitVector(i_normal_orig); - vec4 i_rotation = convert10BitVector(i_rotation_orig); #endif vec3 test = sin(wind_direction * (i_position.y * 0.1)); test += cos(wind_direction) * 0.7; - vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w)); vec4 world_position = getWorldPosition(i_origin + test * i_color.r, - quaternion, i_scale.xyz, i_position); - vec3 world_normal = rotateVector(quaternion, i_normal.xyz); + i_rotation, i_scale.xyz, i_position); + vec3 world_normal = rotateVector(i_rotation, i_normal.xyz); normal = (u_view_matrix * vec4(world_normal, 0.0)).xyz; uv = i_uv; diff --git a/data/shaders/sp_grass_shadow.vert b/data/shaders/sp_grass_shadow.vert index af7db4ef2..b77bbddfc 100644 --- a/data/shaders/sp_grass_shadow.vert +++ b/data/shaders/sp_grass_shadow.vert @@ -5,13 +5,7 @@ layout(location = 0) in vec3 i_position; layout(location = 2) in vec4 i_color; layout(location = 3) in vec2 i_uv; layout(location = 8) in vec3 i_origin; - -#if defined(Converts_10bit_Vector) -layout(location = 9) in vec4 i_rotation_orig; -#else layout(location = 9) in vec4 i_rotation; -#endif - layout(location = 10) in vec4 i_scale; #stk_include "utils/get_world_location.vert" @@ -20,17 +14,10 @@ out vec2 uv; void main() { - -#if defined(Converts_10bit_Vector) - vec4 i_rotation = convert10BitVector(i_rotation_orig); -#endif - vec3 test = sin(wind_direction * (i_position.y * 0.1)); test += cos(wind_direction) * 0.7; - - vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w)); vec4 world_position = getWorldPosition(i_origin + test * i_color.r, - quaternion, i_scale.xyz, i_position); + i_rotation, i_scale.xyz, i_position); uv = i_uv; gl_Position = u_shadow_projection_view_matrices[layer] * world_position; diff --git a/data/shaders/sp_normal_visualizer.vert b/data/shaders/sp_normal_visualizer.vert index 83849ec86..38504e47a 100644 --- a/data/shaders/sp_normal_visualizer.vert +++ b/data/shaders/sp_normal_visualizer.vert @@ -17,13 +17,7 @@ layout(location = 5) in vec4 i_tangent; layout(location = 6) in ivec4 i_joint; layout(location = 7) in vec4 i_weight; layout(location = 8) in vec3 i_origin; - -#if defined(Converts_10bit_Vector) -layout(location = 9) in vec4 i_rotation_orig; -#else layout(location = 9) in vec4 i_rotation; -#endif - layout(location = 10) in vec4 i_scale; layout(location = 12) in ivec2 i_misc_data; @@ -39,7 +33,6 @@ void main() #if defined(Converts_10bit_Vector) vec4 i_normal = convert10BitVector(i_normal_orig); vec4 i_tangent = convert10BitVector(i_tangent_orig); - vec4 i_rotation = convert10BitVector(i_rotation_orig); #endif vec4 idle_position = vec4(i_position, 1.0); @@ -104,12 +97,11 @@ void main() skinned_position = mix(skinned_position, idle_position, step_mix); skinned_normal = mix(skinned_normal, idle_normal, step_mix); skinned_tangent = mix(skinned_tangent, idle_tangent, step_mix); - vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w)); - gl_Position = getWorldPosition(i_origin, quaternion, i_scale.xyz, + gl_Position = getWorldPosition(i_origin, i_rotation, i_scale.xyz, skinned_position.xyz); - o_normal = normalize(rotateVector(quaternion, skinned_normal.xyz)); - o_tangent = normalize(rotateVector(quaternion, skinned_tangent.xyz)); + o_normal = normalize(rotateVector(i_rotation, skinned_normal.xyz)); + o_tangent = normalize(rotateVector(i_rotation, skinned_tangent.xyz)); o_bitangent = cross(o_normal, o_tangent) * i_tangent.w; } diff --git a/data/shaders/sp_pass.vert b/data/shaders/sp_pass.vert index 1ce18e733..6f49469c8 100644 --- a/data/shaders/sp_pass.vert +++ b/data/shaders/sp_pass.vert @@ -17,13 +17,7 @@ layout(location = 5) in vec4 i_tangent; #endif layout(location = 8) in vec3 i_origin; - -#if defined(Converts_10bit_Vector) -layout(location = 9) in vec4 i_rotation_orig; -#else layout(location = 9) in vec4 i_rotation; -#endif - layout(location = 10) in vec4 i_scale; layout(location = 11) in vec2 i_texture_trans; layout(location = 12) in ivec2 i_misc_data; @@ -37,6 +31,7 @@ out vec2 uv; out vec2 uv_two; out vec4 color; out vec4 world_position; +out vec3 world_normal; out float camdist; out float hue_change; @@ -46,21 +41,19 @@ void main() #if defined(Converts_10bit_Vector) vec4 i_normal = convert10BitVector(i_normal_orig); vec4 i_tangent = convert10BitVector(i_tangent_orig); - vec4 i_rotation = convert10BitVector(i_rotation_orig); #endif - vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w)); - vec4 v_world_position = getWorldPosition(i_origin, quaternion, i_scale.xyz, + vec4 v_world_position = getWorldPosition(i_origin, i_rotation, i_scale.xyz, i_position); - vec3 world_normal = rotateVector(quaternion, i_normal.xyz); - vec3 world_tangent = rotateVector(quaternion, i_tangent.xyz); + vec3 v_world_normal = rotateVector(i_rotation, i_normal.xyz); + vec3 world_tangent = rotateVector(i_rotation, i_tangent.xyz); tangent = (u_view_matrix * vec4(world_tangent, 0.0)).xyz; bitangent = (u_view_matrix * // bitangent sign - vec4(cross(world_normal, world_tangent) * i_tangent.w, 0.0) + vec4(cross(v_world_normal, world_tangent) * i_tangent.w, 0.0) ).xyz; - normal = (u_view_matrix * vec4(world_normal, 0.0)).xyz; + normal = (u_view_matrix * vec4(v_world_normal, 0.0)).xyz; uv = vec2(i_uv.x + (i_texture_trans.x * i_normal.w), i_uv.y + (i_texture_trans.y * i_normal.w)); @@ -71,4 +64,5 @@ void main() hue_change = float(i_misc_data.y) * 0.01; gl_Position = u_projection_view_matrix * v_world_position; world_position = v_world_position; + world_normal = v_world_normal; } diff --git a/data/shaders/sp_road_blending.frag b/data/shaders/sp_road_blending.frag new file mode 100644 index 000000000..d6715dde6 --- /dev/null +++ b/data/shaders/sp_road_blending.frag @@ -0,0 +1,90 @@ +in vec3 bitangent; +in vec4 color; +in float hue_change; +in vec3 normal; +in vec3 tangent; +in vec2 uv; +in vec4 world_position; +in float camdist; + +layout(location = 0) out vec4 o_diffuse_color; +layout(location = 1) out vec4 o_normal_color; + +#stk_include "utils/encode_normal.frag" +#stk_include "utils/rgb_conversion.frag" +#stk_include "utils/sp_texture_sampling.frag" + +void main() +{ + vec2 uuv = vec2(world_position.x, world_position.z); + uuv *= 0.2; + vec4 col = multi_sampleTextureLayer0(uv, camdist); + + float mask = sampleTextureLayer4(uuv * 2.0).r; + + //* (1.0 - color.g) + mask = mix(1.0, mask, color.r); + mask = mix(0.0, mask, 1.0 - color.g); + if(mask < 0.5) + { + discard; + } + + // Adding some skidding marks to the road + float mask_2 = sampleTextureLayer4(uuv * 0.1).r; + float mask_3 = sampleTextureLayer4(uuv * 3.5).r; + mask_2 = pow(mask_2, 1.5); + mask_2 *= pow(mask_3, 0.5); + + float skidding_marks = sampleTextureLayer5(uv * 10).g; + skidding_marks *= mask_2; + col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), skidding_marks); + + float skidding_marks_2 = sampleTextureLayer5(uv * 15).g; + skidding_marks_2 *= mask_2; + col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), skidding_marks_2); + + // Add some cracks + float cracks_marks = sampleTextureLayer5(uv * 11).b; + float crack_mask = sampleTextureLayer4(uuv * 0.5).r; + cracks_marks *= crack_mask; + col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), cracks_marks); + + if (hue_change > 0.0) + { + float mask = col.a; + vec3 old_hsv = rgbToHsv(col.rgb); + float mask_step = step(mask, 0.5); +#if !defined(Advanced_Lighting_Enabled) + // For similar color + float saturation = mask * 1.825; // 2.5 * 0.5 ^ (1. / 2.2) +#else + float saturation = mask * 2.5; +#endif + vec2 new_xy = mix(vec2(old_hsv.x, old_hsv.y), vec2(hue_change, + max(old_hsv.y, saturation)), vec2(mask_step, mask_step)); + vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z)); + col = vec4(new_color.r, new_color.g, new_color.b, 1.0); + } + + vec3 final_color = col.xyz; // * color.xyz; + +#if defined(Advanced_Lighting_Enabled) + vec4 layer_2 = multi_sampleTextureLayer2(uv, camdist); + vec4 layer_3 = multi_sampleTextureLayer3(uv, camdist); + o_diffuse_color = vec4(final_color, layer_2.z); + + vec3 tangent_space_normal = 2.0 * layer_3.xyz - 1.0; + vec3 frag_tangent = normalize(tangent); + vec3 frag_bitangent = normalize(bitangent); + vec3 frag_normal = normalize(normal); + mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal); + + vec3 world_normal = t_b_n * tangent_space_normal; + + o_normal_color.xy = 0.5 * EncodeNormal(normalize(world_normal)) + 0.5; + o_normal_color.zw = layer_2.xy; +#else + o_diffuse_color = vec4(final_color, 1.0); +#endif +} diff --git a/data/shaders/sp_shadow.vert b/data/shaders/sp_shadow.vert index ec6f3c7bb..e9c7c9262 100644 --- a/data/shaders/sp_shadow.vert +++ b/data/shaders/sp_shadow.vert @@ -3,13 +3,7 @@ uniform int layer; layout(location = 0) in vec3 i_position; layout(location = 3) in vec2 i_uv; layout(location = 8) in vec3 i_origin; - -#if defined(Converts_10bit_Vector) -layout(location = 9) in vec4 i_rotation_orig; -#else layout(location = 9) in vec4 i_rotation; -#endif - layout(location = 10) in vec4 i_scale; #stk_include "utils/get_world_location.vert" @@ -18,13 +12,7 @@ out vec2 uv; void main() { - -#if defined(Converts_10bit_Vector) - vec4 i_rotation = convert10BitVector(i_rotation_orig); -#endif - - vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w)); - vec4 world_position = getWorldPosition(i_origin, quaternion, i_scale.xyz, + vec4 world_position = getWorldPosition(i_origin, i_rotation, i_scale.xyz, i_position); uv = i_uv; gl_Position = u_shadow_projection_view_matrices[layer] * world_position; diff --git a/data/shaders/sp_skinning.vert b/data/shaders/sp_skinning.vert index af8cf21a5..e8464dc13 100644 --- a/data/shaders/sp_skinning.vert +++ b/data/shaders/sp_skinning.vert @@ -24,13 +24,7 @@ layout(location = 5) in vec4 i_tangent; layout(location = 6) in ivec4 i_joint; layout(location = 7) in vec4 i_weight; layout(location = 8) in vec3 i_origin; - -#if defined(Converts_10bit_Vector) -layout(location = 9) in vec4 i_rotation_orig; -#else layout(location = 9) in vec4 i_rotation; -#endif - layout(location = 10) in vec4 i_scale; layout(location = 11) in vec2 i_texture_trans; layout(location = 12) in ivec2 i_misc_data; @@ -52,7 +46,6 @@ void main() #if defined(Converts_10bit_Vector) vec4 i_normal = convert10BitVector(i_normal_orig); vec4 i_tangent = convert10BitVector(i_tangent_orig); - vec4 i_rotation = convert10BitVector(i_rotation_orig); #endif vec4 idle_position = vec4(i_position, 1.0); @@ -113,11 +106,10 @@ void main() skinned_normal = joint_matrix * idle_normal; skinned_tangent = joint_matrix * idle_tangent; - vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w)); - vec4 world_position = getWorldPosition(i_origin, quaternion, i_scale.xyz, + vec4 world_position = getWorldPosition(i_origin, i_rotation, i_scale.xyz, skinned_position.xyz); - vec3 world_normal = rotateVector(quaternion, skinned_normal.xyz); - vec3 world_tangent = rotateVector(quaternion, skinned_tangent.xyz); + vec3 world_normal = rotateVector(i_rotation, skinned_normal.xyz); + vec3 world_tangent = rotateVector(i_rotation, skinned_tangent.xyz); tangent = (u_view_matrix * vec4(world_tangent, 0.0)).xyz; bitangent = (u_view_matrix * diff --git a/data/shaders/sp_skinning_shadow.vert b/data/shaders/sp_skinning_shadow.vert index 96d337fb7..7f76c01d2 100644 --- a/data/shaders/sp_skinning_shadow.vert +++ b/data/shaders/sp_skinning_shadow.vert @@ -11,13 +11,7 @@ layout(location = 3) in vec2 i_uv; layout(location = 6) in ivec4 i_joint; layout(location = 7) in vec4 i_weight; layout(location = 8) in vec3 i_origin; - -#if defined(Converts_10bit_Vector) -layout(location = 9) in vec4 i_rotation_orig; -#else layout(location = 9) in vec4 i_rotation; -#endif - layout(location = 10) in vec4 i_scale; layout(location = 12) in ivec2 i_misc_data; @@ -27,11 +21,6 @@ out vec2 uv; void main() { - -#if defined(Converts_10bit_Vector) - vec4 i_rotation = convert10BitVector(i_rotation_orig); -#endif - vec4 idle_position = vec4(i_position, 1.0); vec4 skinned_position = vec4(0.0); int skinning_offset = i_misc_data.x; @@ -83,9 +72,7 @@ void main() #endif skinned_position = joint_matrix * idle_position; - - vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w)); - vec4 world_position = getWorldPosition(i_origin, quaternion, i_scale.xyz, + vec4 world_position = getWorldPosition(i_origin, i_rotation, i_scale.xyz, skinned_position.xyz); uv = i_uv; gl_Position = u_shadow_projection_view_matrices[layer] * world_position; diff --git a/data/shaders/sp_tilling_mitigation.frag b/data/shaders/sp_tilling_mitigation.frag new file mode 100644 index 000000000..8a2f46d10 --- /dev/null +++ b/data/shaders/sp_tilling_mitigation.frag @@ -0,0 +1,57 @@ +in vec3 bitangent; +in vec4 color; +in float hue_change; +in vec3 normal; +in vec3 tangent; +in vec2 uv; +in float camdist; + +layout(location = 0) out vec4 o_diffuse_color; +layout(location = 1) out vec4 o_normal_color; + +#stk_include "utils/encode_normal.frag" +#stk_include "utils/rgb_conversion.frag" +#stk_include "utils/sp_texture_sampling.frag" + +void main() +{ + vec4 col = multi_sampleTextureLayer0(uv, camdist); + + if (hue_change > 0.0) + { + float mask = col.a; + vec3 old_hsv = rgbToHsv(col.rgb); + float mask_step = step(mask, 0.5); +#if !defined(Advanced_Lighting_Enabled) + // For similar color + float saturation = mask * 1.825; // 2.5 * 0.5 ^ (1. / 2.2) +#else + float saturation = mask * 2.5; +#endif + vec2 new_xy = mix(vec2(old_hsv.x, old_hsv.y), vec2(hue_change, + max(old_hsv.y, saturation)), vec2(mask_step, mask_step)); + vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z)); + col = vec4(new_color.r, new_color.g, new_color.b, 1.0); + } + + vec3 final_color = col.xyz * color.xyz; + +#if defined(Advanced_Lighting_Enabled) + vec4 layer_2 = multi_sampleTextureLayer2(uv, camdist); + vec4 layer_3 = multi_sampleTextureLayer3(uv, camdist); + o_diffuse_color = vec4(final_color, layer_2.z); + + vec3 tangent_space_normal = 2.0 * layer_3.xyz - 1.0; + vec3 frag_tangent = normalize(tangent); + vec3 frag_bitangent = normalize(bitangent); + vec3 frag_normal = normalize(normal); + mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal); + + vec3 world_normal = t_b_n * tangent_space_normal; + + o_normal_color.xy = 0.5 * EncodeNormal(normalize(world_normal)) + 0.5; + o_normal_color.zw = layer_2.xy; +#else + o_diffuse_color = vec4(final_color, 1.0); +#endif +} diff --git a/data/shaders/sp_vertical_mapping.frag b/data/shaders/sp_vertical_mapping.frag new file mode 100644 index 000000000..a2a1db36c --- /dev/null +++ b/data/shaders/sp_vertical_mapping.frag @@ -0,0 +1,63 @@ +in vec3 bitangent; +in vec4 color; +in float hue_change; +in vec3 normal; +in vec3 world_normal; +in vec3 tangent; +in vec2 uv; + +layout(location = 0) out vec4 o_diffuse_color; +layout(location = 1) out vec4 o_normal_color; + +#stk_include "utils/encode_normal.frag" +#stk_include "utils/rgb_conversion.frag" +#stk_include "utils/sp_texture_sampling.frag" + +void main() +{ + vec4 col = sampleTextureLayer4(uv * 2.0); + //col = vec4(1.0, 0.0, 0.0, 1.0); + vec4 col_2 = sampleTextureLayer5(uv * 2.0);//vec4(0.0, 1.0, 0.0, 1.0); + + float factor = dot(vec3(0.,1.,1.), world_normal); + factor = clamp(factor, 0.0, 1.0); + col = mix(col_2, col, factor); + + if (hue_change > 0.0) + { + float mask = col.a; + vec3 old_hsv = rgbToHsv(col.rgb); + float mask_step = step(mask, 0.5); +#if !defined(Advanced_Lighting_Enabled) + // For similar color + float saturation = mask * 1.825; // 2.5 * 0.5 ^ (1. / 2.2) +#else + float saturation = mask * 2.5; +#endif + vec2 new_xy = mix(vec2(old_hsv.x, old_hsv.y), vec2(hue_change, + max(old_hsv.y, saturation)), vec2(mask_step, mask_step)); + vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z)); + col = vec4(new_color.r, new_color.g, new_color.b, 1.0); + } + + vec3 final_color = col.xyz * color.xyz; + +#if defined(Advanced_Lighting_Enabled) + vec4 layer_2 = sampleTextureLayer2(uv); + vec4 layer_3 = sampleTextureLayer3(uv); + o_diffuse_color = vec4(final_color, layer_2.z); + + vec3 tangent_space_normal = 2.0 * layer_3.xyz - 1.0; + vec3 frag_tangent = normalize(tangent); + vec3 frag_bitangent = normalize(bitangent); + vec3 frag_normal = normalize(normal); + mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal); + + vec3 world_normal = t_b_n * tangent_space_normal; + + o_normal_color.xy = 0.5 * EncodeNormal(normalize(world_normal)) + 0.5; + o_normal_color.zw = layer_2.xy; +#else + o_diffuse_color = vec4(final_color, 1.0); +#endif +} diff --git a/data/shaders/sps_0_solid.xml b/data/shaders/sps_00_solid.xml similarity index 100% rename from data/shaders/sps_0_solid.xml rename to data/shaders/sps_00_solid.xml diff --git a/data/shaders/sps_1_normalmap.xml b/data/shaders/sps_01_normalmap.xml similarity index 100% rename from data/shaders/sps_1_normalmap.xml rename to data/shaders/sps_01_normalmap.xml diff --git a/data/shaders/sps_2_alphatest.xml b/data/shaders/sps_02_alphatest.xml similarity index 100% rename from data/shaders/sps_2_alphatest.xml rename to data/shaders/sps_02_alphatest.xml diff --git a/data/shaders/sps_3_decal.xml b/data/shaders/sps_03_decal.xml similarity index 100% rename from data/shaders/sps_3_decal.xml rename to data/shaders/sps_03_decal.xml diff --git a/data/shaders/sps_4_grass.xml b/data/shaders/sps_04_grass.xml similarity index 100% rename from data/shaders/sps_4_grass.xml rename to data/shaders/sps_04_grass.xml diff --git a/data/shaders/sps_5_unlit.xml b/data/shaders/sps_05_unlit.xml similarity index 100% rename from data/shaders/sps_5_unlit.xml rename to data/shaders/sps_05_unlit.xml diff --git a/data/shaders/sps_6_alphablend.xml b/data/shaders/sps_06_alphablend.xml similarity index 100% rename from data/shaders/sps_6_alphablend.xml rename to data/shaders/sps_06_alphablend.xml diff --git a/data/shaders/sps_7_additive.xml b/data/shaders/sps_07_additive.xml similarity index 100% rename from data/shaders/sps_7_additive.xml rename to data/shaders/sps_07_additive.xml diff --git a/data/shaders/sps_8_ghost.xml b/data/shaders/sps_08_ghost.xml similarity index 100% rename from data/shaders/sps_8_ghost.xml rename to data/shaders/sps_08_ghost.xml diff --git a/data/shaders/sps_9_dynamicNightBloom.xml b/data/shaders/sps_09_dynamic_night_bloom.xml similarity index 100% rename from data/shaders/sps_9_dynamicNightBloom.xml rename to data/shaders/sps_09_dynamic_night_bloom.xml diff --git a/data/shaders/sps_10_tillingMitigation.xml b/data/shaders/sps_10_tillingMitigation.xml new file mode 100644 index 000000000..fd58f7546 --- /dev/null +++ b/data/shaders/sps_10_tillingMitigation.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/data/shaders/sps_11_verticalMapping.xml b/data/shaders/sps_11_verticalMapping.xml new file mode 100644 index 000000000..a137627ca --- /dev/null +++ b/data/shaders/sps_11_verticalMapping.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/data/shaders/sps_12_roadBlending.xml b/data/shaders/sps_12_roadBlending.xml new file mode 100644 index 000000000..21af84585 --- /dev/null +++ b/data/shaders/sps_12_roadBlending.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/data/shaders/utils/sp_texture_sampling.frag b/data/shaders/utils/sp_texture_sampling.frag index 1dfbab0df..3ff725185 100644 --- a/data/shaders/utils/sp_texture_sampling.frag +++ b/data/shaders/utils/sp_texture_sampling.frag @@ -6,11 +6,43 @@ uniform sampler2D tex_layer_3; uniform sampler2D tex_layer_4; uniform sampler2D tex_layer_5; +#define HIGH_SAMPLING 4.0 +#define MEDIUM_SAMPLING 2.0 +#define LOW_SAMPLING 1.0 + vec4 sampleTextureLayer0(vec2 uv) { return texture(tex_layer_0, uv); } +vec4 multi_sampleTextureLayer0(vec2 uv, float distance) +{ + + vec4 l_col = sampleTextureLayer0(uv * LOW_SAMPLING); + vec4 m_col = sampleTextureLayer0(uv * MEDIUM_SAMPLING); + vec4 h_col = sampleTextureLayer0(uv * HIGH_SAMPLING); + + /* debug + l_col = vec4(1.0, 0.0, 0.0, 1.0); + m_col = vec4(0.0, 1.0, 0.0, 1.0); + h_col = vec4(0.0, 0.0, 1.0, 1.0);*/ + + // From Low to medium + float factor = distance * 0.02; + factor = pow(factor, 2.5); + factor = clamp(factor, 0.0, 1.0); + vec4 f_col = mix(m_col, l_col, factor); + + // From medium to high + factor = distance * 0.1; + factor = pow(factor, 2.5); + factor = clamp(factor, 0.0, 1.0); + + f_col = mix(h_col, f_col, factor); + + return f_col; +} + vec4 sampleTextureLayer1(vec2 uv) { return texture(tex_layer_1, uv); @@ -21,11 +53,57 @@ vec4 sampleTextureLayer2(vec2 uv) return texture(tex_layer_2, uv); } +vec4 multi_sampleTextureLayer2(vec2 uv, float distance) +{ + + vec4 l_col = sampleTextureLayer2(uv * LOW_SAMPLING); + vec4 m_col = sampleTextureLayer2(uv * MEDIUM_SAMPLING); + vec4 h_col = sampleTextureLayer2(uv * HIGH_SAMPLING); + + // From Low to medium + float factor = distance * 0.02; + factor = pow(factor, 2.5); + factor = clamp(factor, 0.0, 1.0); + vec4 f_col = mix(m_col, l_col, factor); + + // From medium to high + factor = distance * 0.1; + factor = pow(factor, 2.5); + factor = clamp(factor, 0.0, 1.0); + + f_col = mix(h_col, f_col, factor); + + return f_col; +} + vec4 sampleTextureLayer3(vec2 uv) { return texture(tex_layer_3, uv); } +vec4 multi_sampleTextureLayer3(vec2 uv, float distance) +{ + + vec4 l_col = sampleTextureLayer3(uv * LOW_SAMPLING); + vec4 m_col = sampleTextureLayer3(uv * MEDIUM_SAMPLING); + vec4 h_col = sampleTextureLayer3(uv * HIGH_SAMPLING); + + // From Low to medium + float factor = distance * 0.02; + factor = pow(factor, 2.5); + factor = clamp(factor, 0.0, 1.0); + vec4 f_col = mix(m_col, l_col, factor); + + // From medium to high + factor = distance * 0.1; + factor = pow(factor, 2.5); + factor = clamp(factor, 0.0, 1.0); + + f_col = mix(h_col, f_col, factor); + + return f_col; +} + vec4 sampleTextureLayer4(vec2 uv) { return texture(tex_layer_4, uv); diff --git a/data/stk_config.xml b/data/stk_config.xml index 0f22c66a3..03a53df04 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -42,29 +42,29 @@ - + - - + + - - - - + + + + - + - - - - - - - - - - + + + + + + + + + + \n\n"; + for(unsigned int n=0; nisAccelerometerActive()) { m_device_manager->updateMultitouchDevice(); - - for (unsigned int i = 0; i < device->getButtonsCount(); i++) - { - MultitouchButton* button = device->getButton(i); - - if (button->type != BUTTON_STEERING) - continue; - - float factor = UserConfigParams::m_multitouch_tilt_factor; - factor = std::max(factor, 0.1f); - button->axis_x = (float)event.AccelerometerEvent.Y / factor; - - device->handleControls(button); - } + + float factor = UserConfigParams::m_multitouch_tilt_factor; + factor = std::max(factor, 0.1f); + device->updateAxisX(float(event.AccelerometerEvent.Y) / factor); } } diff --git a/src/input/multitouch_device.cpp b/src/input/multitouch_device.cpp index 7ce754fcf..785e10681 100644 --- a/src/input/multitouch_device.cpp +++ b/src/input/multitouch_device.cpp @@ -36,7 +36,7 @@ MultitouchDevice::MultitouchDevice() m_type = DT_MULTITOUCH; m_name = "Multitouch"; m_player = NULL; - m_accelerometer_active = false; + m_controller = NULL; #ifdef ANDROID m_android_device = dynamic_cast( irr_driver->getDevice()); @@ -136,22 +136,6 @@ void MultitouchDevice::addButton(MultitouchButtonType type, int x, int y, } m_buttons.push_back(button); - -#ifdef ANDROID - if (button->type == MultitouchButtonType::BUTTON_STEERING) - { - if (UserConfigParams::m_multitouch_controls == 2 && - !m_android_device->isAccelerometerActive()) - { - m_android_device->activateAccelerometer(1.0f / 30); - - if (m_android_device->isAccelerometerActive()) - { - m_accelerometer_active = true; - } - } - } -#endif } // addButton // ---------------------------------------------------------------------------- @@ -159,15 +143,6 @@ void MultitouchDevice::addButton(MultitouchButtonType type, int x, int y, */ void MultitouchDevice::clearButtons() { -#ifdef ANDROID - if (m_accelerometer_active == true && - m_android_device->isAccelerometerActive()) - { - m_android_device->deactivateAccelerometer(); - m_accelerometer_active = false; - } -#endif - for (MultitouchButton* button : m_buttons) { delete button; @@ -198,6 +173,45 @@ void MultitouchDevice::reset() } } // reset +// ---------------------------------------------------------------------------- +/** Activates accelerometer + */ +void MultitouchDevice::activateAccelerometer() +{ +#ifdef ANDROID + if (!m_android_device->isAccelerometerActive()) + { + m_android_device->activateAccelerometer(1.0f / 30); + } +#endif +} + +// ---------------------------------------------------------------------------- +/** Deativates accelerometer + */ +void MultitouchDevice::deactivateAccelerometer() +{ +#ifdef ANDROID + if (m_android_device->isAccelerometerActive()) + { + m_android_device->deactivateAccelerometer(); + } +#endif +} + +// ---------------------------------------------------------------------------- +/** Get accelerometer state + * \return true if accelerometer is active + */ +bool MultitouchDevice::isAccelerometerActive() +{ +#ifdef ANDROID + return m_android_device->isAccelerometerActive(); +#endif + + return false; +} + // ---------------------------------------------------------------------------- /** The function that is executed when touch event occurs. It updates the * buttons state when it's needed. @@ -237,21 +251,39 @@ void MultitouchDevice::updateDeviceState(unsigned int event_id) if (button->type == MultitouchButtonType::BUTTON_STEERING) { float prev_axis_x = button->axis_x; + + if (button->pressed == true) + { + button->axis_x = + (float)(event.x - button->x) / (button->width/2) - 1; + } + else + { + button->axis_x = 0.0f; + } + + if (prev_axis_x != button->axis_x) + { + update_controls = true; + } + } + + if (button->type == MultitouchButtonType::BUTTON_STEERING || + button->type == MultitouchButtonType::BUTTON_UP_DOWN) + { float prev_axis_y = button->axis_y; if (button->pressed == true) { - updateButtonAxes(button, - (float)(event.x - button->x) / (button->width/2) - 1, - (float)(event.y - button->y) / (button->height/2) - 1); + button->axis_y = + (float)(event.y - button->y) / (button->height/2) - 1; } else { - updateButtonAxes(button, 0.0f, 0.0f); + button->axis_y = 0.0f; } - if (prev_axis_x != button->axis_x || - prev_axis_y != button->axis_y) + if (prev_axis_y != button->axis_y) { update_controls = true; } @@ -298,35 +330,93 @@ float MultitouchDevice::getSteeringFactor(float value) m_deadzone_center), 1.0f); } -/** Updates the button axes. It leaves X axis untouched if the accelerometer is - * used for turning left/right - * \param button A button that should be updated - * \param x A value from 0 to 1 - * \param y A value from 0 to 1 - */ -void MultitouchDevice::updateButtonAxes(MultitouchButton* button, float x, - float y) -{ - if (m_accelerometer_active == false) - { - button->axis_x = x; - } +// ---------------------------------------------------------------------------- - button->axis_y = y; +void MultitouchDevice::updateAxisX(float value) +{ + if (m_controller == NULL) + return; + + if (value < -m_deadzone_center) + { + float factor = getSteeringFactor(std::abs(value)); + m_controller->action(PA_STEER_LEFT, int(factor * Input::MAX_VALUE)); + } + else if (value > m_deadzone_center) + { + float factor = getSteeringFactor(std::abs(value)); + m_controller->action(PA_STEER_RIGHT, int(factor * Input::MAX_VALUE)); + } + else + { + m_controller->action(PA_STEER_LEFT, 0); + m_controller->action(PA_STEER_RIGHT, 0); + } } // ---------------------------------------------------------------------------- +void MultitouchDevice::updateAxisY(float value) +{ + if (m_controller == NULL) + return; + + if (value < -m_deadzone_center) + { + float factor = getSteeringFactor(std::abs(value)); + m_controller->action(PA_ACCEL, int(factor * Input::MAX_VALUE)); + } + else if (value > m_deadzone_center) + { + float factor = getSteeringFactor(std::abs(value)); + m_controller->action(PA_BRAKE, int(factor * Input::MAX_VALUE)); + } + else + { + m_controller->action(PA_BRAKE, 0); + m_controller->action(PA_ACCEL, 0); + } +} // ---------------------------------------------------------------------------- + /** Sends proper action for player controller depending on the button type * and state. * \param button The button that should be handled. */ void MultitouchDevice::handleControls(MultitouchButton* button) { - if (m_player == NULL) + if (m_controller == NULL) return; + + if (button->type == MultitouchButtonType::BUTTON_STEERING) + { + updateAxisX(button->axis_x); + updateAxisY(button->axis_y); + } + else if (button->type == MultitouchButtonType::BUTTON_UP_DOWN) + { + updateAxisY(button->axis_y); + } + else + { + if (button->action != PA_BEFORE_FIRST) + { + int value = button->pressed ? Input::MAX_VALUE : 0; + m_controller->action(button->action, value); + } + } +} + +// ---------------------------------------------------------------------------- + +void MultitouchDevice::updateController() +{ + if (m_player == NULL) + { + m_controller = NULL; + return; + } // Handle multitouch events only when race is running. It avoids to process // it when pause dialog is active during the race. And there is no reason @@ -335,60 +425,20 @@ void MultitouchDevice::handleControls(MultitouchButton* button) GUIEngine::ModalDialog::isADialogActive() || GUIEngine::ScreenKeyboard::isActive() || race_manager->isWatchingReplay()) + { + m_controller = NULL; return; + } AbstractKart* pk = m_player->getKart(); if (pk == NULL) - return; - - Controller* controller = pk->getController(); - - if (controller == NULL) - return; - - if (button->type == MultitouchButtonType::BUTTON_STEERING) { - if (button->axis_y < -m_deadzone_center) - { - float factor = getSteeringFactor(std::abs(button->axis_y)); - controller->action(PA_ACCEL, int(factor * Input::MAX_VALUE)); - } - else if (button->axis_y > m_deadzone_center) - { - float factor = getSteeringFactor(std::abs(button->axis_y)); - controller->action(PA_BRAKE, int(factor * Input::MAX_VALUE)); - } - else - { - controller->action(PA_BRAKE, 0); - controller->action(PA_ACCEL, 0); - } + m_controller = NULL; + return; + } - if (button->axis_x < -m_deadzone_center) - { - float factor = getSteeringFactor(std::abs(button->axis_x)); - controller->action(PA_STEER_LEFT, int(factor * Input::MAX_VALUE)); - } - else if (button->axis_x > m_deadzone_center) - { - float factor = getSteeringFactor(std::abs(button->axis_x)); - controller->action(PA_STEER_RIGHT, int(factor * Input::MAX_VALUE)); - } - else - { - controller->action(PA_STEER_LEFT, 0); - controller->action(PA_STEER_RIGHT, 0); - } - } - else - { - if (button->action != PA_BEFORE_FIRST) - { - int value = button->pressed ? Input::MAX_VALUE : 0; - controller->action(button->action, value); - } - } -} // handleControls + m_controller = pk->getController(); +} // ---------------------------------------------------------------------------- diff --git a/src/input/multitouch_device.hpp b/src/input/multitouch_device.hpp index 4cc6fd0ad..a7abf779e 100644 --- a/src/input/multitouch_device.hpp +++ b/src/input/multitouch_device.hpp @@ -34,6 +34,7 @@ enum MultitouchButtonType { BUTTON_STEERING, + BUTTON_UP_DOWN, BUTTON_FIRE, BUTTON_NITRO, BUTTON_SKIDDING, @@ -68,11 +69,15 @@ struct MultitouchButton float axis_y; }; +class Controller; + class MultitouchDevice : public InputDevice { private: /** The list of pointers to all created buttons */ std::vector m_buttons; + + Controller* m_controller; /** The parameter that is used for steering button and determines dead area * in a center of button */ @@ -82,16 +87,13 @@ private: * at the edge of button */ float m_deadzone_edge; - /** True if accelerometer is in use */ - bool m_accelerometer_active; - #ifdef ANDROID /** Pointer to the Android irrlicht device */ CIrrDeviceAndroid* m_android_device; #endif float getSteeringFactor(float value); - void updateButtonAxes(MultitouchButton* button, float x, float y); + void handleControls(MultitouchButton* button); public: /** The array that contains data for all multitouch input events */ @@ -119,12 +121,14 @@ public: /** Returns pointer to the selected button */ MultitouchButton* getButton(unsigned int i) {return m_buttons.at(i);} - /** True if accelerometer is in use */ - bool isAccelerometerActive() {return m_accelerometer_active;} - + void activateAccelerometer(); + void deactivateAccelerometer(); + bool isAccelerometerActive(); + + void updateAxisX(float value); + void updateAxisY(float value); void updateDeviceState(unsigned int event_id); - void handleControls(MultitouchButton* button); - + void updateController(); void updateConfigParams(); }; // MultitouchDevice diff --git a/src/io/assets_android.cpp b/src/io/assets_android.cpp index cf451b191..8d7a80853 100644 --- a/src/io/assets_android.cpp +++ b/src/io/assets_android.cpp @@ -58,13 +58,13 @@ void AssetsAndroid::init() if (getenv("SUPERTUXKART_DATADIR")) paths.push_back(getenv("SUPERTUXKART_DATADIR")); - + if (getenv("EXTERNAL_STORAGE")) paths.push_back(getenv("EXTERNAL_STORAGE")); if (getenv("SECONDARY_STORAGE")) paths.push_back(getenv("SECONDARY_STORAGE")); - + if (global_android_app->activity->externalDataPath) paths.push_back(global_android_app->activity->externalDataPath); @@ -88,6 +88,12 @@ void AssetsAndroid::init() for (std::string path : paths) { Log::info("AssetsAndroid", "Check data files in: %s", path.c_str()); + + if (!isWritable(path)) + { + Log::info("AssetsAndroid", "Path doesn't have write access."); + continue; + } if (m_file_manager->fileExists(path + "/" + app_dir_name + "/data/" + version)) { @@ -113,6 +119,12 @@ void AssetsAndroid::init() { Log::info("AssetsAndroid", "Check data files for different STK " "version in: %s", path.c_str()); + + if (!isWritable(path)) + { + Log::info("AssetsAndroid", "Path doesn't have write access."); + continue; + } if (m_file_manager->fileExists(path + "/" + app_dir_name + "/.extracted")) { @@ -498,6 +510,20 @@ void AssetsAndroid::touchFile(std::string path) #endif } +//----------------------------------------------------------------------------- +/** Checks if there is write access for selected path + * \param path A path that should be checked + * \return True if there is write access + */ +bool AssetsAndroid::isWritable(std::string path) +{ +#ifdef ANDROID + return access(path.c_str(), R_OK) == 0 && access(path.c_str(), W_OK) == 0; +#endif + + return false; +} + //----------------------------------------------------------------------------- /** Determines best path for extracting assets, depending on available disk * space. @@ -519,6 +545,9 @@ std::string AssetsAndroid::getPreferredPath(const std::vector& // to clean up device if (path.find("/data") == 0) continue; + + if (!isWritable(path)) + continue; struct statfs stat; diff --git a/src/io/assets_android.hpp b/src/io/assets_android.hpp index 031a7d0b8..a89788b5c 100644 --- a/src/io/assets_android.hpp +++ b/src/io/assets_android.hpp @@ -34,6 +34,7 @@ private: bool extractDir(std::string dir_name); void removeData(); void touchFile(std::string path); + bool isWritable(std::string path); std::string getPreferredPath(const std::vector& paths); public: diff --git a/src/items/flyable.cpp b/src/items/flyable.cpp index 3b0702f7c..bf873e767 100644 --- a/src/items/flyable.cpp +++ b/src/items/flyable.cpp @@ -371,6 +371,16 @@ void Flyable::setAnimation(AbstractKartAnimation *animation) m_animation = animation; } // addAnimation +//----------------------------------------------------------------------------- +/** Called once per rendered frame. It is used to only update any graphical + * effects. + * \param dt Time step size (since last call). + */ +void Flyable::updateGraphics(float dt) +{ + Moveable::updateGraphics(dt, Vec3(0, 0, 0), btQuaternion(0, 0, 0, 1)); +} // updateGraphics + //----------------------------------------------------------------------------- /** Updates this flyable. It calls Moveable::update. If this function returns * true, the flyable will be deleted by the projectile manager. diff --git a/src/items/flyable.hpp b/src/items/flyable.hpp index c1f1fe426..2c7288634 100644 --- a/src/items/flyable.hpp +++ b/src/items/flyable.hpp @@ -22,17 +22,18 @@ #ifndef HEADER_FLYABLE_HPP #define HEADER_FLYABLE_HPP +#include "items/powerup_manager.hpp" +#include "karts/moveable.hpp" +#include "tracks/terrain_info.hpp" +#include "utils/cpp2011.hpp" + +#include namespace irr { namespace scene { class IMesh; } } -#include using namespace irr; -#include "items/powerup_manager.hpp" -#include "karts/moveable.hpp" -#include "tracks/terrain_info.hpp" - class AbstractKart; class AbstractKartAnimation; class HitEffect; @@ -167,6 +168,7 @@ public: virtual ~Flyable (); static void init (const XMLNode &node, scene::IMesh *model, PowerupManager::PowerupType type); + void updateGraphics(float dt) OVERRIDE; virtual bool updateAndDelete(int ticks); virtual void setAnimation(AbstractKartAnimation *animation); virtual HitEffect* getHitEffect() const; diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index 89eec7ed5..f79f4c448 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -257,7 +257,7 @@ void Powerup::use() case PowerupManager::POWERUP_RUBBERBALL: case PowerupManager::POWERUP_BOWLING: case PowerupManager::POWERUP_PLUNGER: - if(stk_config->m_shield_restrict_weapos) + if(stk_config->m_shield_restrict_weapons) m_kart->setShieldTime(0.0f); // make weapon usage destroy the shield Powerup::adjustSound(); m_sound_use->play(); diff --git a/src/items/projectile_manager.cpp b/src/items/projectile_manager.cpp index 9ea86c4c4..907c77ca4 100644 --- a/src/items/projectile_manager.cpp +++ b/src/items/projectile_manager.cpp @@ -61,6 +61,21 @@ void ProjectileManager::cleanup() m_active_hit_effects.clear(); } // cleanup +// ----------------------------------------------------------------------------- +/** Called once per rendered frame. It is used to only update any graphical + * effects, and calls updateGraphics in any flyable objects. + * \param dt Time step size (since last call). + */ +void ProjectileManager::updateGraphics(float dt) +{ + for (auto p = m_active_projectiles.begin(); + p != m_active_projectiles.end(); ++p) + { + (*p)->updateGraphics(dt); + } + +} // updateGraphics + // ----------------------------------------------------------------------------- /** General projectile update call. */ void ProjectileManager::update(int ticks) @@ -153,3 +168,32 @@ bool ProjectileManager::projectileIsClose(const AbstractKart * const kart, } return false; } // projectileIsClose + +// ----------------------------------------------------------------------------- +/** Returns an int containing the numbers of a given flyable in a given radius + * around the kart + * \param kart The kart for which the test is done. + * \param radius Distance within which the projectile must be. + * \param type The type of projectile checked +*/ +int ProjectileManager::getNearbyProjectileCount(const AbstractKart * const kart, + float radius, PowerupManager::PowerupType type) +{ + float r2 = radius*radius; + int projectileCount = 0; + + for(Projectiles::iterator i = m_active_projectiles.begin(); + i != m_active_projectiles.end(); i++) + { + if ((*i)->getType() == type) + { + float dist2 = (*i)->getXYZ().distance2(kart->getXYZ()); + if(dist2(World::getWorld()); float target_distance = - world->getDistanceDownTrackForKart(m_target->getWorldKartId()); - float ball_distance = getDistanceFromStart(); + world->getDistanceDownTrackForKart(m_target->getWorldKartId(), true); + float ball_distance = getDistanceFromStart(true); m_distance_to_target = target_distance - ball_distance; if(m_distance_to_target < 0) diff --git a/src/karts/abstract_characteristic.cpp b/src/karts/abstract_characteristic.cpp index 3826e3bbc..af7ba896c 100644 --- a/src/karts/abstract_characteristic.cpp +++ b/src/karts/abstract_characteristic.cpp @@ -213,15 +213,19 @@ AbstractCharacteristic::ValueType AbstractCharacteristic::getType( return TYPE_FLOAT; case NITRO_MAX: return TYPE_FLOAT; - case SLIPSTREAM_DURATION: + case SLIPSTREAM_DURATION_FACTOR: + return TYPE_FLOAT; + case SLIPSTREAM_BASE_SPEED: return TYPE_FLOAT; case SLIPSTREAM_LENGTH: return TYPE_FLOAT; case SLIPSTREAM_WIDTH: return TYPE_FLOAT; - case SLIPSTREAM_COLLECT_TIME: + case SLIPSTREAM_INNER_FACTOR: return TYPE_FLOAT; - case SLIPSTREAM_USE_TIME: + case SLIPSTREAM_MIN_COLLECT_TIME: + return TYPE_FLOAT; + case SLIPSTREAM_MAX_COLLECT_TIME: return TYPE_FLOAT; case SLIPSTREAM_ADD_POWER: return TYPE_FLOAT; @@ -445,16 +449,20 @@ std::string AbstractCharacteristic::getName(CharacteristicType type) return "NITRO_FADE_OUT_TIME"; case NITRO_MAX: return "NITRO_MAX"; - case SLIPSTREAM_DURATION: - return "SLIPSTREAM_DURATION"; + case SLIPSTREAM_DURATION_FACTOR: + return "SLIPSTREAM_DURATION_FACTOR"; + case SLIPSTREAM_BASE_SPEED: + return "SLIPSTREAM_BASE_SPEED"; case SLIPSTREAM_LENGTH: return "SLIPSTREAM_LENGTH"; case SLIPSTREAM_WIDTH: return "SLIPSTREAM_WIDTH"; - case SLIPSTREAM_COLLECT_TIME: - return "SLIPSTREAM_COLLECT_TIME"; - case SLIPSTREAM_USE_TIME: - return "SLIPSTREAM_USE_TIME"; + case SLIPSTREAM_INNER_FACTOR: + return "SLIPSTREAM_INNER_FACTOR"; + case SLIPSTREAM_MIN_COLLECT_TIME: + return "SLIPSTREAM_MIN_COLLECT_TIME"; + case SLIPSTREAM_MAX_COLLECT_TIME: + return "SLIPSTREAM_MAX_COLLECT_TIME"; case SLIPSTREAM_ADD_POWER: return "SLIPSTREAM_ADD_POWER"; case SLIPSTREAM_MIN_SPEED: @@ -1460,16 +1468,28 @@ float AbstractCharacteristic::getNitroMax() const } // getNitroMax // ---------------------------------------------------------------------------- -float AbstractCharacteristic::getSlipstreamDuration() const +float AbstractCharacteristic::getSlipstreamDurationFactor() const { float result; bool is_set = false; - process(SLIPSTREAM_DURATION, &result, &is_set); + process(SLIPSTREAM_DURATION_FACTOR, &result, &is_set); if (!is_set) Log::fatal("AbstractCharacteristic", "Can't get characteristic %s", - getName(SLIPSTREAM_DURATION).c_str()); + getName(SLIPSTREAM_DURATION_FACTOR).c_str()); return result; -} // getSlipstreamDuration +} // getSlipstreamDurationFactor + +// ---------------------------------------------------------------------------- +float AbstractCharacteristic::getSlipstreamBaseSpeed() const +{ + float result; + bool is_set = false; + process(SLIPSTREAM_BASE_SPEED, &result, &is_set); + if (!is_set) + Log::fatal("AbstractCharacteristic", "Can't get characteristic %s", + getName(SLIPSTREAM_BASE_SPEED).c_str()); + return result; +} // getSlipstreamBaseSpeed // ---------------------------------------------------------------------------- float AbstractCharacteristic::getSlipstreamLength() const @@ -1496,28 +1516,40 @@ float AbstractCharacteristic::getSlipstreamWidth() const } // getSlipstreamWidth // ---------------------------------------------------------------------------- -int AbstractCharacteristic::getSlipstreamCollectTicks() const +float AbstractCharacteristic::getSlipstreamInnerFactor() const { float result; bool is_set = false; - process(SLIPSTREAM_COLLECT_TIME, &result, &is_set); + process(SLIPSTREAM_INNER_FACTOR, &result, &is_set); if (!is_set) Log::fatal("AbstractCharacteristic", "Can't get characteristic %s", - getName(SLIPSTREAM_COLLECT_TIME).c_str()); - return stk_config->time2Ticks(result); -} // getSlipstreamCollectTicks + getName(SLIPSTREAM_INNER_FACTOR).c_str()); + return result; +} // getSlipstreamInnerFactor // ---------------------------------------------------------------------------- -float AbstractCharacteristic::getSlipstreamUseTime() const +float AbstractCharacteristic::getSlipstreamMinCollectTime() const { float result; bool is_set = false; - process(SLIPSTREAM_USE_TIME, &result, &is_set); + process(SLIPSTREAM_MIN_COLLECT_TIME, &result, &is_set); if (!is_set) Log::fatal("AbstractCharacteristic", "Can't get characteristic %s", - getName(SLIPSTREAM_USE_TIME).c_str()); + getName(SLIPSTREAM_MIN_COLLECT_TIME).c_str()); return result; -} // getSlipstreamUseTime +} // getSlipstreamMinCollectTime + +// ---------------------------------------------------------------------------- +float AbstractCharacteristic::getSlipstreamMaxCollectTime() const +{ + float result; + bool is_set = false; + process(SLIPSTREAM_MAX_COLLECT_TIME, &result, &is_set); + if (!is_set) + Log::fatal("AbstractCharacteristic", "Can't get characteristic %s", + getName(SLIPSTREAM_MAX_COLLECT_TIME).c_str()); + return result; +} // getSlipstreamMaxCollecTime // ---------------------------------------------------------------------------- float AbstractCharacteristic::getSlipstreamAddPower() const @@ -1785,4 +1817,3 @@ bool AbstractCharacteristic::getSkidEnabled() const /* */ - diff --git a/src/karts/abstract_characteristic.hpp b/src/karts/abstract_characteristic.hpp index 9727f9231..f4fb2406c 100644 --- a/src/karts/abstract_characteristic.hpp +++ b/src/karts/abstract_characteristic.hpp @@ -193,11 +193,13 @@ public: NITRO_MAX, // Slipstream - SLIPSTREAM_DURATION, + SLIPSTREAM_DURATION_FACTOR, + SLIPSTREAM_BASE_SPEED, SLIPSTREAM_LENGTH, SLIPSTREAM_WIDTH, - SLIPSTREAM_COLLECT_TIME, - SLIPSTREAM_USE_TIME, + SLIPSTREAM_INNER_FACTOR, + SLIPSTREAM_MIN_COLLECT_TIME, + SLIPSTREAM_MAX_COLLECT_TIME, SLIPSTREAM_ADD_POWER, SLIPSTREAM_MIN_SPEED, SLIPSTREAM_MAX_SPEED_INCREASE, @@ -359,11 +361,13 @@ public: float getNitroFadeOutTime() const; float getNitroMax() const; - float getSlipstreamDuration() const; + float getSlipstreamDurationFactor() const; + float getSlipstreamBaseSpeed() const; float getSlipstreamLength() const; float getSlipstreamWidth() const; - int getSlipstreamCollectTicks() const; - float getSlipstreamUseTime() const; + float getSlipstreamInnerFactor() const; + float getSlipstreamMinCollectTime() const; + float getSlipstreamMaxCollectTime() const; float getSlipstreamAddPower() const; float getSlipstreamMinSpeed() const; float getSlipstreamMaxSpeedIncrease() const; @@ -392,4 +396,3 @@ public: }; #endif - diff --git a/src/karts/abstract_kart.hpp b/src/karts/abstract_kart.hpp index a6425a53c..4dbad3203 100644 --- a/src/karts/abstract_kart.hpp +++ b/src/karts/abstract_kart.hpp @@ -282,11 +282,23 @@ public: virtual float getCurrentMaxSpeed() const = 0; // ------------------------------------------------------------------------ /** Returns how much increased speed time is left over in the given - * category. Not pure abstract, since there is no need to implement this - * e.g. in Ghost. + * category. * \param category Which category to report on. */ virtual int getSpeedIncreaseTicksLeft(unsigned int category) const = 0; + // ------------------------------------------------------------------------ + /** Sets the kart AI boost state. + * Not pure abstract, since there is no need to implement this e.g. in Ghost. + * \param boosted True if a boost should be applied. */ + virtual void setBoostAI(bool boosted) = 0; + + // ------------------------------------------------------------------------ + /** Returns the kart AI boost state. + * Not pure abstract, since there is no need to implement this e.g. in Ghost. */ + virtual bool getBoostAI() const = 0; + + // ------------------------------------------------------------------------ + /** Sets an increased maximum speed for a category. * \param category The category for which to set the higher maximum speed. * \param add_speed How much speed (in m/s) is added to the maximum speed. @@ -295,8 +307,25 @@ public: * \param fade_out_time How long the maximum speed will fade out linearly. */ virtual void increaseMaxSpeed(unsigned int category, float add_speed, - float engine_force, int duration, - int fade_out_time) = 0; + float engine_force, float duration, + float fade_out_time) = 0; + + // ---------------------------------------------------------------------------- + /** This adjusts the top speed using increaseMaxSpeed, but additionally + * causes an instant speed boost, which can be smaller than add-max-speed. + * (e.g. a zipper can give an instant boost of 5 m/s, but over time would + * allow the speed to go up by 10 m/s). + * \param category The category for which the speed is increased. + * \param add_max_speed Increase of the maximum allowed speed. + * \param speed_boost An instant speed increase for this kart. + * \param engine_force Additional engine force. + * \param duration Duration of the increased speed. + * \param fade_out_time How long the maximum speed will fade out linearly. + */ + virtual void instantSpeedIncrease(unsigned int category, float add_max_speed, + float speed_boost, float engine_force, float duration, + float fade_out_time) = 0; + // ------------------------------------------------------------------------ /** Defines a slowdown, which is in fraction of top speed. * \param category The category for which the speed is increased. @@ -379,6 +408,9 @@ public: /** Returns the current powerup. */ virtual Powerup *getPowerup() = 0; // ------------------------------------------------------------------------ + /** Returns the last used powerup type. */ + virtual PowerupManager::PowerupType getLastUsedPowerup() = 0; + // ------------------------------------------------------------------------ /** Returns a points to this kart's graphical effects. */ virtual KartGFX* getKartGFX() = 0; // ------------------------------------------------------------------------ @@ -443,6 +475,12 @@ public: * defined even if the kart is flying. */ virtual const Vec3& getNormal() const = 0; // ------------------------------------------------------------------------ + /** Returns the position 0.25s before */ + virtual const Vec3& getPreviousXYZ() const = 0; + // ------------------------------------------------------------------------ + /** Returns the most recent different previous position */ + virtual const Vec3& getRecentPreviousXYZ() const = 0; + // ------------------------------------------------------------------------ /** Returns the height of the terrain. we're currently above */ virtual float getHoT() const = 0; // ------------------------------------------------------------------------ @@ -474,4 +512,3 @@ public: #endif /* EOF */ - diff --git a/src/karts/controller/ai_properties.cpp b/src/karts/controller/ai_properties.cpp index e60da3cf9..bc761fe67 100644 --- a/src/karts/controller/ai_properties.cpp +++ b/src/karts/controller/ai_properties.cpp @@ -43,9 +43,9 @@ AIProperties::AIProperties(RaceManager::Difficulty difficulty) m_make_use_of_slipstream = false; m_collect_avoid_items = false; m_handle_bomb = false; - m_item_usage_non_random = false; + m_item_usage_skill = 0; m_disable_slipstream_usage = false; - m_nitro_usage = NITRO_NONE; + m_nitro_usage = 0; } // AIProperties @@ -65,7 +65,7 @@ void AIProperties::load(const XMLNode *ai_node) ai_node->get("straight-length-for-zipper",&m_straight_length_for_zipper); ai_node->get("rb-skid-probability", &m_skid_probability ); ai_node->get("speed-cap", &m_speed_cap ); - ai_node->get("non-random-item-usage", &m_item_usage_non_random ); + ai_node->get("item-skill", &m_item_usage_skill ); ai_node->get("collect-avoid-items", &m_collect_avoid_items ); ai_node->get("handle-bomb", &m_handle_bomb ); ai_node->get("skidding-threshold", &m_skidding_threshold ); @@ -73,21 +73,8 @@ void AIProperties::load(const XMLNode *ai_node) ai_node->get("false-start-probability", &m_false_start_probability ); ai_node->get("min-start-delay", &m_min_start_delay ); ai_node->get("max-start-delay", &m_max_start_delay ); + ai_node->get("nitro-usage", &m_nitro_usage ); - std::string s; - ai_node->get("nitro-usage", &s); - if(s=="none") - m_nitro_usage = NITRO_NONE; - else if(s=="some") - m_nitro_usage = NITRO_SOME; - else if(s=="all") - m_nitro_usage = NITRO_ALL; - else - { - Log::fatal("AIProperties", - "Incorrect nitro-usage '%s' in AI '%s'.",s.c_str(), - m_ident.c_str()); - } // We actually need the square of the distance later m_bad_item_closeness_2 *= m_bad_item_closeness_2; diff --git a/src/karts/controller/ai_properties.hpp b/src/karts/controller/ai_properties.hpp index 9d67d9b9b..c25c62bdd 100644 --- a/src/karts/controller/ai_properties.hpp +++ b/src/karts/controller/ai_properties.hpp @@ -111,11 +111,15 @@ protected: /** If the AI should actively try to pass on a bomb. */ bool m_handle_bomb; - /** True if items should be used better (i.e. non random). */ - bool m_item_usage_non_random; + /** Determines the strategies used by the AI for items. 0 is no use, + 1 is random use ; 2 to 5 use varying tactics, with 2 having the worst + and 5 the best. */ + int m_item_usage_skill; - /** How the AI uses nitro. */ - enum {NITRO_NONE, NITRO_SOME, NITRO_ALL} m_nitro_usage; + /** How the AI uses nitro. 0 correspond to no use ; 1 to immediate use + 2 to 4 to various levels of mastery (the AI tries to accumulate a reserve + and to use bursts whose size/spacing varies according to the level). */ + int m_nitro_usage; /** TODO: ONLY USE FOR OLD SKIDDING! CAN BE REMOVED once the new skidding * works as expected. diff --git a/src/karts/controller/skidding_ai.cpp b/src/karts/controller/skidding_ai.cpp index fd01ac9cd..f0eb85927 100644 --- a/src/karts/controller/skidding_ai.cpp +++ b/src/karts/controller/skidding_ai.cpp @@ -319,38 +319,41 @@ void SkiddingAI::update(int ticks) // of us. bool commands_set = false; if(m_ai_properties->m_handle_bomb && - m_kart->getAttachment()->getType()==Attachment::ATTACH_BOMB && - m_kart_ahead ) + m_kart->getAttachment()->getType()==Attachment::ATTACH_BOMB) { - // Use nitro if the kart is far ahead, or faster than this kart - m_controls->setNitro(m_distance_ahead>10.0f || - m_kart_ahead->getSpeed() > m_kart->getSpeed()); - // If we are close enough, try to hit this kart - if(m_distance_ahead<=10) - { - Vec3 target = m_kart_ahead->getXYZ(); + //TODO : add logic to allow an AI kart to pass the bomb to a kart + // close behind by slowing/steering slightly + if ( m_kart_ahead != m_kart->getAttachment()->getPreviousOwner()) + { + // Use nitro if the kart is far ahead, or faster than this kart + handleNitroAndZipper(); + + // If we are close enough, try to hit this kart + if(m_distance_ahead<=10) + { + Vec3 target = m_kart_ahead->getXYZ(); - // If we are faster, try to predict the point where we will hit - // the other kart - if((m_kart_ahead->getSpeed() < m_kart->getSpeed()) && - !m_kart_ahead->isGhostKart()) - { - float time_till_hit = m_distance_ahead - / (m_kart->getSpeed()-m_kart_ahead->getSpeed()); - target += m_kart_ahead->getVelocity()*time_till_hit; - } - float steer_angle = steerToPoint(target); - setSteering(steer_angle, dt); - commands_set = true; - } - handleRescue(dt); + // If we are faster, try to predict the point where we will hit + // the other kart + if((m_kart_ahead->getSpeed() < m_kart->getSpeed()) && + !m_kart_ahead->isGhostKart()) + { + float time_till_hit = m_distance_ahead + / (m_kart->getSpeed()-m_kart_ahead->getSpeed()); + target += m_kart_ahead->getVelocity()*time_till_hit; + } + float steer_angle = steerToPoint(target); + setSteering(steer_angle, dt); + commands_set = true; + } + handleRescue(dt); + } } if(!commands_set) { /*Response handling functions*/ handleAcceleration(ticks); handleSteering(dt); - handleItems(dt); handleRescue(dt); handleBraking(); // If a bomb is attached, nitro might already be set. @@ -490,6 +493,8 @@ void SkiddingAI::handleSteering(float dt) } //If we are going to crash against a kart, avoid it if it doesn't //drives the kart out of the road + //TODO : adds item handling to use a cake if available to + //open the road else if( m_crashes.m_kart != -1 && !m_crashes.m_road ) { //-1 = left, 1 = right, 0 = no crash. @@ -551,6 +556,9 @@ void SkiddingAI::handleSteering(float dt) m_curve[CURVE_AIM]->addPoint(aim_point); #endif + //Manage item utilisation + handleItems(dt, &aim_point, last_node); + // Potentially adjust the point to aim for in order to either // aim to collect item, or steer to avoid a bad item. if(m_ai_properties->m_collect_avoid_items) @@ -1133,16 +1141,19 @@ void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction, //----------------------------------------------------------------------------- /** Handle all items depending on the chosen strategy. - * Either (low level AI) just use an item after 10 seconds, or do a much - * better job on higher level AI - e.g. aiming at karts ahead/behind, wait an - * appropriate time before using multiple items etc. + * Level 0 "AI" : do nothing (not used by default) + * Level 1 "AI" : use items after a random time + * Level 2 to 5 AI : strategy detailed before each item + * Each successive level is overall stronger (5 the strongest, 2 the weakest of + * non-random strategies), but two levels may share a strategy for a given item. + * (level 5 is not yet used ; meant for SuperTux GP preferred karts or boss races) * \param dt Time step size. * TODO: Implications of Bubble-Shield for AI's powerup-handling * STATE: shield on -> avoid usage of offensive items (with certain tolerance) * STATE: swatter on -> avoid usage of shield */ -void SkiddingAI::handleItems(const float dt) +void SkiddingAI::handleItems(const float dt, const Vec3 *aim_point, int last_node) { m_controls->setFire(false); if(m_kart->getKartAnimation() || @@ -1150,7 +1161,15 @@ void SkiddingAI::handleItems(const float dt) return; m_time_since_last_shot += dt; - + + //time since last shot is meant to avoid using the same item + //several times in rapid succession ; not to wait to use a useful + //collected item + if ( m_kart->getPowerup()->getType() != m_kart->getLastUsedPowerup() ) + { + m_time_since_last_shot = 50.0f; //The AI may wait if the value is low, so set a high value + } + if (m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS) { m_controls->setLookBack(m_kart->getPowerup()->getType() == @@ -1173,12 +1192,41 @@ void SkiddingAI::handleItems(const float dt) } return; } + + int ai_skill = 0; + if (m_ai_properties->m_item_usage_skill > 0) + { + if (m_ai_properties->m_item_usage_skill > 5) + { + ai_skill = 5; + } + else + { + ai_skill = m_ai_properties->m_item_usage_skill; + } + } + + if (m_kart->getBoostAI() == true && ai_skill < 5) + { + ai_skill++; //possible improvement : make the boost amplitude pulled from config + } - // Tactic 1: wait ten seconds, then use item + // Tactic 0: don't use item // ----------------------------------------- - if(!m_ai_properties->m_item_usage_non_random) + if(ai_skill == 0) { - if( m_time_since_last_shot > 10.0f ) + return; + } + + // Tactic 1: wait between 5 and 10 seconds, then use item + // ------------------------------------------------------ + if(ai_skill == 1) + { + int random_t = 0; + random_t = m_random_skid.get(6); //Reuse the random skid generator + random_t = random_t + 5; + + if( m_time_since_last_shot > random_t ) { m_controls->setFire(true); m_time_since_last_shot = 0.0f; @@ -1186,67 +1234,206 @@ void SkiddingAI::handleItems(const float dt) return; } - // Tactic 2: calculate - // ------------------- + // Tactics 2 to 5: calculate + // ----------------------------------------- float min_bubble_time = 2.0f; + int projectile_types[4]; //[3] basket, [2] cakes, [1] plunger, [0] bowling + projectile_types[0] = projectile_manager->getNearbyProjectileCount(m_kart, + m_ai_properties->m_shield_incoming_radius, PowerupManager::POWERUP_BOWLING); + projectile_types[1] = projectile_manager->getNearbyProjectileCount(m_kart, + m_ai_properties->m_shield_incoming_radius, PowerupManager::POWERUP_PLUNGER); + projectile_types[2] = projectile_manager->getNearbyProjectileCount(m_kart, + m_ai_properties->m_shield_incoming_radius, PowerupManager::POWERUP_CAKE); + projectile_types[3] = projectile_manager->getNearbyProjectileCount(m_kart, + m_ai_properties->m_shield_incoming_radius, PowerupManager::POWERUP_RUBBERBALL); + + bool projectile_is_close = false; + float shield_radius = m_ai_properties->m_shield_incoming_radius; + if (m_kart->getBoostAI() == true) + { + if (shield_radius == 0) + { + shield_radius = 15; + } + else if (shield_radius >= 3) + { + shield_radius = shield_radius - 2; + } + } + projectile_is_close = projectile_manager->projectileIsClose(m_kart, shield_radius); + + // Preparing item list for item aware actions + + // Angle to aim_point + Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ(); + + // Make sure we have a valid last_node + if(last_node==Graph::UNKNOWN_SECTOR) + last_node = m_next_node_index[m_track_node]; + + int node = m_track_node; + float distance = 0; + std::vector items_to_collect; + std::vector items_to_avoid; + + // 1) Filter and sort all items close by + // ------------------------------------- + const float max_item_lookahead_distance = 20.0f; + while(distance < max_item_lookahead_distance) + { + int n_index= DriveGraph::get()->getNode(node)->getIndex(); + const std::vector &items_ahead = + ItemManager::get()->getItemsInQuads(n_index); + for(unsigned int i=0; igetDistanceToNext(node, + m_successor_index[node]); + node = m_next_node_index[node]; + // Stop when we have reached the last quad + if(node==last_node) break; + } // while (distance < max_item_lookahead_distance) + + //items_to_avoid and items_to_collect now contain the closest item information needed after + //What matters is (a) if the lists are void ; (b) if they are not, what kind of item it is + switch( m_kart->getPowerup()->getType() ) { + // Level 2 : Use the shield immediately after a wait time + // Level 3 : Use the shield against flyables except cakes. Use the shield against bad attachments. + // Use the bubble gum against an enemy close behind, except if holding a swatter. + // Level 4 : Level 3, and protect against cakes too, and use before hitting gum/banana + // Level 5 : Level 4, and use before hitting item box, and let plunger hit + // (can use the shield after) case PowerupManager::POWERUP_BUBBLEGUM: { - Attachment::AttachmentType type = m_kart->getAttachment()->getType(); - // Don't use shield when we have a swatter. - if( type == Attachment::ATTACH_SWATTER) - break; + Attachment::AttachmentType type = m_kart->getAttachment()->getType(); + + if((ai_skill == 2) && (m_time_since_last_shot > 2.0f)) + { + m_controls->setFire(true); + m_controls->setLookBack(false); + break; + } + + // Check if a flyable (cake, ...) is close. If so, use bubblegum + // as shield + if(ai_skill == 3) //don't protect against cakes + { + if( !m_kart->isShielded() && projectile_is_close + && projectile_types[2] == 0) + { + //don't discard swatter against plunger + if( projectile_types[1] == 0 + || (projectile_types[1] >= 1 && type != Attachment::ATTACH_SWATTER)) + { + m_controls->setFire(true); + m_controls->setLookBack(false); + break; + } + } + } + else if(ai_skill == 4) + { + if( !m_kart->isShielded() && projectile_is_close) + { + //don't discard swatter against plunger + if( projectile_types[1] == 0 + || (projectile_types[1] >= 1 && type != Attachment::ATTACH_SWATTER)) + { + m_controls->setFire(true); + m_controls->setLookBack(false); + break; + } + } + } + else if (ai_skill == 5) //don't protect against plungers alone TODO : activate after plunger hit + { + if( !m_kart->isShielded() && projectile_is_close) + { + if (projectile_types[0] >=1 || projectile_types[2] >=1 || projectile_types[3] >=1 ) + { + m_controls->setFire(true); + m_controls->setLookBack(false); + break; + } + } + } - // Check if a flyable (cake, ...) is close. If so, use bubblegum - // as shield - if( !m_kart->isShielded() && - projectile_manager->projectileIsClose(m_kart, - m_ai_properties->m_shield_incoming_radius) ) - { - m_controls->setFire(true); - m_controls->setLookBack(false); - break; - } + // Use shield to remove bad attachments + if( type == Attachment::ATTACH_BOMB + || type == Attachment::ATTACH_PARACHUTE + || type == Attachment::ATTACH_ANVIL ) + { + m_controls->setFire(true); + m_controls->setLookBack(false); + break; + } + + // Use shield if kart is going to hit a bad item (banana or bubblegum) + if((ai_skill == 4) || (ai_skill == 5)) + { + if( !m_kart->isShielded() && items_to_avoid.size()>0) + { + float d = (items_to_avoid[0]->getXYZ() - m_kart->getXYZ()).length2(); + + if ((ai_skill == 4 && d < 1.5f) || (ai_skill == 5 && d < 0.7f)) + { + m_controls->setFire(true); + m_controls->setLookBack(false); + break; + } + } + } + + // Use shield if kart is going to hit an item box + if (ai_skill == 5) + { + if( !m_kart->isShielded() && items_to_collect.size()>0) + { + float d = (items_to_collect[0]->getXYZ() - m_kart->getXYZ()).length2(); + + if ((items_to_collect[0]->getType() == Item::ITEM_BONUS_BOX) && (d < 0.7f)) + { + m_controls->setFire(true); + m_controls->setLookBack(false); + break; + } + } + } + + // Avoid dropping all bubble gums one after another + if( m_time_since_last_shot < 2.0f) break; - // Avoid dropping all bubble gums one after another - if( m_time_since_last_shot < 3.0f) break; - - // Use bubblegum if the next kart behind is 'close' but not too close - // (too close likely means that the kart is not behind but more to the - // side of this kart and so won't be hit by the bubble gum anyway). - // Should we check the speed of the kart as well? I.e. only drop if - // the kart behind is faster? Otoh this approach helps preventing an - // overtaken kart to overtake us again. - if(m_distance_behind < 15.0f && m_distance_behind > 3.0f ) - { - m_controls->setFire(true); - m_controls->setLookBack(true); - break; - } - - // If this kart is in its last lap, drop bubble gums at every - // opportunity, since this kart won't envounter them anymore. - LinearWorld *lin_world = dynamic_cast(World::getWorld()); - if(m_time_since_last_shot > 3.0f && - lin_world && - lin_world->getFinishedLapsOfKart(m_kart->getWorldKartId()) - == race_manager->getNumLaps()-1) - { - m_controls->setFire(true); - m_controls->setLookBack(true); - break; - } - break; // POWERUP_BUBBLEGUM - } + // Use bubblegum if the next kart behind is 'close' but not too close + // (too close likely means that the kart is not behind but more to the + // side of this kart and so won't be hit by the bubble gum anyway). + // Should we check the speed of the kart as well? I.e. only drop if + // the kart behind is faster? Otoh this approach helps preventing an + // overtaken kart to overtake us again. + if(m_distance_behind < 10.0f && m_distance_behind > 3.0f ) + { + m_controls->setFire(true); + m_controls->setLookBack(true); + break; + } + break; // POWERUP_BUBBLEGUM + } + + // Level 2 : Use the cake against any close enemy, with priority to those ahead + // Level 3 : Don't fire on slower karts + // Level 4 : Same as level 3 TODO : Fire if the kart has a swatter which may hit us + // Level 5 : Same as level 4 TODO : Don't fire on a shielded kart if we're just behind (gum) case PowerupManager::POWERUP_CAKE: { // if the kart has a shield, do not break it by using a cake. - if(m_kart->getShieldTime() > min_bubble_time) + if((m_kart->getShieldTime() > min_bubble_time) && (stk_config->m_shield_restrict_weapons == true)) break; // Leave some time between shots - if(m_time_since_last_shot<3.0f) break; + if(m_time_since_last_shot<2.0f) break; // Do not fire if the kart is driving too slow bool kart_behind_is_slow = @@ -1268,9 +1455,12 @@ void SkiddingAI::handleItems(const float dt) // the kart anyway, or that this might force the kart ahead to // use its nitro/zipper (and then we will shoot since then the // kart is faster). - if ((fire_backwards && kart_behind_is_slow) || - (!fire_backwards && kart_ahead_is_slow) ) - break; + if(ai_skill >= 3) + { + if ((fire_backwards && kart_behind_is_slow) || + (!fire_backwards && kart_ahead_is_slow) ) + break; + } // Don't fire if the kart we are aiming at is invulnerable. if ((fire_backwards && m_kart_behind && m_kart_behind->isInvulnerable()) || @@ -1288,15 +1478,20 @@ void SkiddingAI::handleItems(const float dt) break; } // POWERUP_CAKE + // Level 2 : Use the bowling ball against enemies with a 5 second delay + // Level 3 : Only 3 seconds of delay + // Level 4 : Same as level 3 + // Level 5 : Same as level 4 case PowerupManager::POWERUP_BOWLING: { // if the kart has a shield, do not break it by using a bowling ball. - if(m_kart->getShieldTime() > min_bubble_time) + if((m_kart->getShieldTime() > min_bubble_time) && (stk_config->m_shield_restrict_weapons == true)) break; // Leave more time between bowling balls, since they are // slower, so it should take longer to hit something which // can result in changing our target. - if(m_time_since_last_shot < 5.0f) break; + if(ai_skill == 2 && m_time_since_last_shot < 5.0f) break; + if(ai_skill >= 3 && m_time_since_last_shot < 3.0f) break; // Consider angle towards karts bool straight_behind = false; bool straight_ahead = false; @@ -1348,7 +1543,7 @@ void SkiddingAI::handleItems(const float dt) case PowerupManager::POWERUP_PLUNGER: { // if the kart has a shield, do not break it by using a plunger. - if(m_kart->getShieldTime() > min_bubble_time) + if((m_kart->getShieldTime() > min_bubble_time) && (stk_config->m_shield_restrict_weapons == true)) break; // Leave more time after a plunger, since it will take some @@ -1369,15 +1564,131 @@ void SkiddingAI::handleItems(const float dt) break; } // POWERUP_PLUNGER + // Level 2 : Use the switch after a wait time + // Level 3 : Same as level 2 but don't fire if close to a good item + // Level 4 : Same as level 3 and fire if very close to a bad item + // Level 5 : Use if it makes a better item available, or if very close + // to a bad item. Don't use it if too close of a good item. case PowerupManager::POWERUP_SWITCH: - // For now don't use a switch if this kart is first (since it's more - // likely that this kart then gets a good iteam), otherwise use it - // after a waiting an appropriate time - if(m_kart->getPosition()>1 && - m_time_since_last_shot > - stk_config->ticks2Time(stk_config->m_item_switch_ticks)+2.0f) - m_controls->setFire(true); - break; // POWERUP_SWITCH + { + // It's extremely unlikely two switches are used close one after another + if(ai_skill == 2) + { + if (m_time_since_last_shot > 2.0f) + { + m_controls->setFire(true); + break; + } + } + + else if((ai_skill == 3) || (ai_skill == 4)) + { + if( (ai_skill == 4) && items_to_avoid.size() > 0) + { + float d = (items_to_avoid[0]->getXYZ() - m_kart->getXYZ()).length2(); + + if (d < 2.0f) + { + m_controls->setFire(true); + break; + } + } + else if (items_to_collect.size() > 0) + { + float d = (items_to_collect[0]->getXYZ() - m_kart->getXYZ()).length2(); + + if (d > 10.0f) + { + m_controls->setFire(true); + break; + } + } + else if (m_time_since_last_shot > 2.0f) + { + m_controls->setFire(true); + break; + } + } + + //TODO : retrieve ranking powerup class and use it to evaluate the best item + // available depending of if the switch is used or not + // In the mean time big nitro > item box > small nitro + //TODO : make steering switch-aware so that the kart goes towards a bad item + // and use the switch at the last moment + //It would also be possible but complicated to check if using the switch will + //cause another kart not far from taking a bad item instead of a good one + //It should also be possible but complicated to discard items when a good + //and a bad one are two close from one another + else if(ai_skill == 5) + { + //First step : identify the best available item + int i; + int bad = 0; + int good = 0; + + //Good will store 1 for nitro, big or small, 2 for item box + //Big nitro are usually hard to take for the AI + for(i=items_to_collect.size()-1; i>=0; i--) + { + if (items_to_collect[i]->getType() == Item::ITEM_BONUS_BOX) + { + good = 2; + i = -1; + } + else if ( (items_to_collect[i]->getType() == Item::ITEM_NITRO_BIG) || + (items_to_collect[i]->getType() == Item::ITEM_NITRO_SMALL) ) + { + good = 1; + } + } + + //Bad will store 2 for bananas, 3 for bubble gum + for(i=items_to_avoid.size()-1; i>=0; i--) + { + if (items_to_avoid[i]->getType() == Item::ITEM_BUBBLEGUM) + { + bad = 3; + i = -1; + } + else if ( items_to_avoid[i]->getType() == Item::ITEM_BANANA ) + { + bad = 2; + } + } + + //Second step : make sure a close item don't make the choice pointless + if( items_to_avoid.size()>0) + { + float d = (items_to_avoid[0]->getXYZ() - m_kart->getXYZ()).length2(); + + //fire if very close to a bad item + if (d < 2.0f) + { + m_controls->setFire(true); + break; + } + } + if( items_to_collect.size()>0) + { + float d = (items_to_collect[0]->getXYZ() - m_kart->getXYZ()).length2(); + + //don't fire if close to a good item + if (d < 5.0f) + { + break; + } + } + + //Third step : Use or don't use to get the best available item + if( bad > good) + { + m_controls->setFire(true); + break; + } + } //ai_skill == 5 + + break; + } // POWERUP_SWITCH case PowerupManager::POWERUP_PARACHUTE: // Wait one second more than a previous parachute @@ -1401,8 +1712,33 @@ void SkiddingAI::handleItems(const float dt) } break; // POWERUP_ANVIL + + // Level 2 : Use the swatter immediately after a wait time + // Level 3 : Use the swatter when enemies are close + // Level 4 : Level 3 and use the swatter to remove bad attachments + // Level 5 : Same as level 4. case PowerupManager::POWERUP_SWATTER: { + Attachment::AttachmentType type = m_kart->getAttachment()->getType(); + + if((ai_skill == 2) && (m_time_since_last_shot > 2.0f)) + { + m_controls->setFire(true); + break; + } + + // Use swatter to remove bad attachments + if((ai_skill == 4) || (ai_skill == 5)) + { + if( type == Attachment::ATTACH_BOMB + || type == Attachment::ATTACH_PARACHUTE + || type == Attachment::ATTACH_ANVIL ) + { + m_controls->setFire(true); + m_controls->setLookBack(false); + break; + } + } // Squared distance for which the swatter works float d2 = m_kart->getKartProperties()->getSwatterDistance(); // if the kart has a shield, do not break it by using a swatter. @@ -1423,7 +1759,7 @@ void SkiddingAI::handleItems(const float dt) } case PowerupManager::POWERUP_RUBBERBALL: // if the kart has a shield, do not break it by using a swatter. - if(m_kart->getShieldTime() > min_bubble_time) + if((m_kart->getShieldTime() > min_bubble_time) && (stk_config->m_shield_restrict_weapons == true)) break; // Perhaps some more sophisticated algorithm might be useful. // For now: fire if there is a kart ahead (which means that @@ -1585,107 +1921,236 @@ void SkiddingAI::handleRescue(const float dt) } // handleRescue //----------------------------------------------------------------------------- -/** Decides wether to use nitro or not. +/** Decides wether to use nitro and zipper or not. */ void SkiddingAI::handleNitroAndZipper() { + //Calculated here and not passed as parameter to not redo all the calls to the function + //May be better to change it + + int ai_skill = 0; + if (m_ai_properties->m_item_usage_skill > 0) + { + if (m_ai_properties->m_item_usage_skill > 5) + { + ai_skill = 5; + } + else + { + ai_skill = m_ai_properties->m_item_usage_skill; + } + } + + int nitro_skill = 0; + if (m_ai_properties->m_nitro_usage > 0) + { + if (m_ai_properties->m_nitro_usage > 4) + { + nitro_skill = 4; + } + else + { + nitro_skill = m_ai_properties->m_nitro_usage; + } + } + + if (m_kart->getBoostAI() == true) + { + if (ai_skill < 5) + { + ai_skill = ai_skill + 1; //possible improvement : make the boost amplitude pulled from config + } + if (nitro_skill < 4) + { + nitro_skill = nitro_skill + 1; //possible improvement : make the boost amplitude pulled from config + } + } + + if (m_kart->getPowerup()->getType()!=PowerupManager::POWERUP_ZIPPER) + { + ai_skill = 0; //don't try to use the zipper if there is none + } + + //Nitro continue to be advantageous during the fadeout + int nitro_ticks = m_kart->getSpeedIncreaseTicksLeft(MaxSpeed::MS_INCREASE_NITRO); + float nitro_time = ( stk_config->ticks2Time(nitro_ticks) + + m_kart->getKartProperties()->getNitroFadeOutTime() ); + float nitro_max_time = m_kart->getKartProperties()->getNitroDuration() + + m_kart->getKartProperties()->getNitroFadeOutTime(); + + //Nitro skill 0 : don't use + //Nitro skill 1 : don't use if the kart is braking, on the ground, has finished the race, has no nitro, + // has a parachute or an anvil attached, or has a plunger in the face. + // Otherwise, use it immediately + //Nitro skill 2 : Don't use nitro if there is more than 1,2 seconds of effect/fadeout left. Use it when at + // max speed or under 5 of speed (after rescue, etc.). Use it to pass bombs. + // Tries to builds a reserve of 4 energy to use towards the end + //Nitro skill 3 : Same as level 2, but don't use until 0.5 seconds of effect/fadeout left, and don't use close + // to bad items, and has a target reserve of 8 energy + //Nitro skill 4 : Same as level 3, but don't use until 0.05 seconds of effect/fadeout left and ignore the plunger + // and has a target reserve of 12 energy + m_controls->setNitro(false); - // If we are already very fast, save nitro. - if(m_kart->getSpeed() > 0.95f*m_kart->getCurrentMaxSpeed()) - return; - // Don't use nitro when the AI has a plunger in the face! - if(m_kart->getBlockedByPlungerTicks()>0) return; - - // Don't use nitro if we are braking + + float energy_reserve = 0; + + if (nitro_skill == 2) + { + energy_reserve = 4; + } + if (nitro_skill == 3) + { + energy_reserve = 8; + } + if (nitro_skill == 4) + { + energy_reserve = 12; + } + + // Don't use nitro or zipper if we are braking if(m_controls->getBrake()) return; - - // Don't use nitro if the kart is not on ground or has finished the race + + // Don't use nitro or zipper if the kart is not on ground or has finished the race if(!m_kart->isOnGround() || m_kart->hasFinishedRace()) return; + + // Don't use nitro or zipper when the AI has a plunger in the face! + if(m_kart->getBlockedByPlungerTicks()>0) + { + if ((nitro_skill < 4) && (ai_skill < 5)) + { + return; + } + else if (nitro_skill < 4) + { + nitro_skill = 0; + } + else if (ai_skill < 5) + { + ai_skill = 0; + } + } - // Don't compute nitro usage if we don't have nitro or are not supposed - // to use it, and we don't have a zipper or are not supposed to use - // it (calculated). - if( (m_kart->getEnergy()==0 || - m_ai_properties->m_nitro_usage==AIProperties::NITRO_NONE) && - (m_kart->getPowerup()->getType()!=PowerupManager::POWERUP_ZIPPER || - !m_ai_properties->m_item_usage_non_random ) ) - return; - - // If there are items to avoid close, and we only have zippers, don't - // use them (since this make it harder to avoid items). - if(m_avoid_item_close && - (m_kart->getEnergy()==0 || - m_ai_properties->m_nitro_usage==AIProperties::NITRO_NONE) ) - return; - // If a parachute or anvil is attached, the nitro doesn't give much + // If a parachute or anvil is attached, the nitro and zipper don't give much // benefit. Better wait till later. const bool has_slowdown_attachment = m_kart->getAttachment()->getType()==Attachment::ATTACH_PARACHUTE || m_kart->getAttachment()->getType()==Attachment::ATTACH_ANVIL; if(has_slowdown_attachment) return; - - // If the kart is very slow (e.g. after rescue), use nitro - if(m_kart->getSpeed()<5) + + // Don't compute nitro usage if we don't have nitro + if( m_kart->getEnergy()==0 ) + { + nitro_skill = 0; + } + + // Don't use nitro if there is already a nitro boost active + // Nitro effect and fadeout varies between karts type from 2 to 4 seconds + // So vary time according to kart properties + if ((nitro_skill == 4) && nitro_time >= (nitro_max_time*0.01f) ) + { + nitro_skill = 0; + } + else if ((nitro_skill == 3) && nitro_time >= (nitro_max_time*0.35f) ) + { + nitro_skill = 0; + } + else if ((nitro_skill == 2) && nitro_time >= (nitro_max_time*0.5f) ) + { + nitro_skill = 0; + } + + // If there are items to avoid close + // Don't use zippers + // Dont use nitro if nitro_skill is 3 or 4 + // (since going faster makes it harder to avoid items). + if(m_avoid_item_close && (m_kart->getEnergy()==0 || nitro_skill == 0 || nitro_skill >= 3) ) + return; + + // If basic AI, use nitro immediately + + if (nitro_skill == 1) { m_controls->setNitro(true); return; } - - // If this kart is the last kart, and we have enough - // (i.e. more than 2) nitro, use it. - // ------------------------------------------------- - const unsigned int num_karts = m_world->getCurrentNumKarts(); - if(m_kart->getPosition()== (int)num_karts && - num_karts>1 && m_kart->getEnergy()>2.0f) + + // Estimate time towards the end of the race. + // Decreases the reserve size when there is an estimate of time remaining + // to the end of less than 2,5 times the maximum nitro effect duration. + // This vary depending on kart characteristic. + // There is a margin because the kart will go a bit faster than predicted + // by the estimate, because the kart may collect more nitro and because + // there may be moments when it's not useful to use nitro (parachutes, etc). + if(nitro_skill >= 2 && energy_reserve > 0.0f) { - m_controls->setNitro(true); - return; - } - - // On the last track shortly before the finishing line, use nitro - // anyway. Since the kart is faster with nitro, estimate a 50% time - // decrease (additionally some nitro will be saved when top speed - // is reached). - if(m_world->getLapForKart(m_kart->getWorldKartId()) - ==race_manager->getNumLaps()-1 && - m_ai_properties->m_nitro_usage == AIProperties::NITRO_ALL) - { - float finish = - m_world->getEstimatedFinishTime(m_kart->getWorldKartId()); - if( 1.5f*m_kart->getEnergy() >= finish - m_world->getTime() ) + float finish = m_world->getEstimatedFinishTime(m_kart->getWorldKartId()) - m_world->getTime(); + float max_time_effect = nitro_max_time / m_kart->getKartProperties()->getNitroConsumption() + * m_kart->getEnergy()*2; //the minimum burst consumes around 0.5 energy + + // The burster forces the AI to consume its reserve by series of 2 bursts + // Otherwise the bursting differences of the various nitro skill wouldn't matter here + // In short races, most AI nitro usage may be at the end with the reserve + float burster; + + if ( nitro_time > 0) { - m_controls->setNitro(true); - return; + burster = 2*nitro_max_time; + } + else + { + burster = 0; + } + if( (2.5f*max_time_effect) >= (finish - burster) ) + { + // Absolute reduction to avoid small amount of unburned nitro at the end + energy_reserve = (finish - burster)/(2.5f*max_time_effect/m_kart->getEnergy()) - 0.5f ; } } - - // A kart within this distance is considered to be overtaking (or to be - // overtaken). - const float overtake_distance = 10.0f; - - // Try to overtake a kart that is close ahead, except - // when we are already much faster than that kart - // -------------------------------------------------- - if(m_kart_ahead && - m_distance_ahead < overtake_distance && - m_kart_ahead->getSpeed()+5.0f > m_kart->getSpeed() ) + + // If trying to pass a bomb to a kart faster or far ahead, use nitro reserve + if(m_kart->getAttachment()->getType() == Attachment::ATTACH_BOMB + && nitro_skill >= 2 && energy_reserve > 0.0f) { - m_controls->setNitro(true); - return; + if (m_distance_ahead>10.0f || m_kart_ahead->getSpeed() > m_kart->getSpeed() ) + { + energy_reserve = 0 ; + } + } + + // Don't use nitro if building an energy reserve + if (m_kart->getEnergy() <= energy_reserve) + { + nitro_skill = 0; } - if(m_kart_behind && - m_distance_behind < overtake_distance && - m_kart_behind->getSpeed() > m_kart->getSpeed() ) + // If the kart is very slow (e.g. after rescue), use nitro + if(nitro_skill > 0 && m_kart->getSpeed()<5 && m_kart->getSpeed()>2) { - // Only prevent overtaking on highest level - m_controls->setNitro(m_ai_properties->m_nitro_usage - == AIProperties::NITRO_ALL); + m_controls->setNitro(true); + return; + } + + // If kart is at max speed, use nitro + // This is to profit from the max speed increase + // And because it means there should be no slowing down from, e.g. plungers + if (nitro_skill > 0 && m_kart->getSpeed() > 0.99f*m_kart->getCurrentMaxSpeed() ) + { + m_controls->setNitro(true); return; } - if(m_kart->getPowerup()->getType()==PowerupManager::POWERUP_ZIPPER && - m_kart->getSpeed()>1.0f && + // If this kart is the last kart, and we have nitro, use it. + // ------------------------------------------------- + const unsigned int num_karts = m_world->getCurrentNumKarts(); + if(nitro_skill > 0 && m_kart->getPosition()== (int)num_karts && + num_karts > 1 ) + { + m_controls->setNitro(true); + return; + } + + // Use zipper + if(ai_skill >= 2 && m_kart->getSpeed()>1.0f && m_kart->getSpeedIncreaseTicksLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0) { DriveNode::DirectionType dir; diff --git a/src/karts/controller/skidding_ai.hpp b/src/karts/controller/skidding_ai.hpp index b13c4187f..8bdafacbd 100644 --- a/src/karts/controller/skidding_ai.hpp +++ b/src/karts/controller/skidding_ai.hpp @@ -242,7 +242,8 @@ private: void handleRaceStart(); void handleAcceleration(int ticks); void handleSteering(float dt); - void handleItems(const float dt); + void handleItems(const float dt, const Vec3 *aim_point, + int last_node); void handleRescue(const float dt); void handleBraking(); void handleNitroAndZipper(); diff --git a/src/karts/controller/test_ai.cpp b/src/karts/controller/test_ai.cpp index b8151739a..4dc023c1f 100644 --- a/src/karts/controller/test_ai.cpp +++ b/src/karts/controller/test_ai.cpp @@ -1182,7 +1182,7 @@ void SkiddingAI::handleItems(const float dt) // Tactic 1: wait ten seconds, then use item // ----------------------------------------- - if(!m_ai_properties->m_item_usage_non_random) + if(m_ai_properties->m_item_usage_skill <= 1) { if( m_time_since_last_shot > 10.0f ) { @@ -1655,16 +1655,16 @@ void SkiddingAI::handleNitroAndZipper() // to use it, and we don't have a zipper or are not supposed to use // it (calculated). if( (m_kart->getEnergy()==0 || - m_ai_properties->m_nitro_usage==AIProperties::NITRO_NONE) && + m_ai_properties->m_nitro_usage == 0) && (m_kart->getPowerup()->getType()!=PowerupManager::POWERUP_ZIPPER || - !m_ai_properties->m_item_usage_non_random ) ) + m_ai_properties->m_item_usage_skill <= 1 ) ) return; // If there are items to avoid close, and we only have zippers, don't // use them (since this make it harder to avoid items). if(m_avoid_item_close && (m_kart->getEnergy()==0 || - m_ai_properties->m_nitro_usage==AIProperties::NITRO_NONE) ) + m_ai_properties->m_nitro_usage == 0) ) return; // If a parachute or anvil is attached, the nitro doesn't give much // benefit. Better wait till later. @@ -1697,7 +1697,7 @@ void SkiddingAI::handleNitroAndZipper() // is reached). if(m_world->getLapForKart(m_kart->getWorldKartId()) ==race_manager->getNumLaps()-1 && - m_ai_properties->m_nitro_usage == AIProperties::NITRO_ALL) + m_ai_properties->m_nitro_usage >= 2) { float finish = m_world->getEstimatedFinishTime(m_kart->getWorldKartId()); @@ -1728,8 +1728,7 @@ void SkiddingAI::handleNitroAndZipper() m_kart_behind->getSpeed() > m_kart->getSpeed() ) { // Only prevent overtaking on highest level - m_controls->setNitro(m_ai_properties->m_nitro_usage - == AIProperties::NITRO_ALL); + m_controls->setNitro(m_ai_properties->m_nitro_usage >= 2 ); return; } diff --git a/src/karts/ghost_kart.cpp b/src/karts/ghost_kart.cpp index 43fc3c386..0d5cd9b37 100644 --- a/src/karts/ghost_kart.cpp +++ b/src/karts/ghost_kart.cpp @@ -68,6 +68,21 @@ void GhostKart::addReplayEvent(float time, } // addReplayEvent +// ---------------------------------------------------------------------------- +/** Called once per rendered frame. It is used to only update any graphical + * effects. + * \param dt Time step size (since last call). + */ +void GhostKart::updateGraphics(float dt) +{ + Vec3 center_shift(0, m_graphical_y_offset, 0); + center_shift = getTrans().getBasis() * center_shift; + + // Don't call Kart's updateGraphics, since it assumes physics. Instead + // immediately call Moveable's updateGraphics. + Moveable::updateGraphics(dt, center_shift, btQuaternion(0, 0, 0, 1)); +} // updateGraphics + // ---------------------------------------------------------------------------- /** Updates the current event of the ghost kart using interpolation * \param dt Time step size. @@ -109,11 +124,6 @@ void GhostKart::update(int ticks) .slerp(m_all_transform[idx + 1].getRotation(), rd); setRotation(q); - Vec3 center_shift(0, 0, 0); - center_shift.setY(m_graphical_y_offset); - center_shift = getTrans().getBasis() * center_shift; - - Moveable::updateGraphics(ticks, center_shift, btQuaternion(0, 0, 0, 1)); Moveable::updatePosition(); float dt = stk_config->ticks2Time(ticks); getKartModel()->update(dt, dt*(m_all_physic_info[idx].m_speed), diff --git a/src/karts/ghost_kart.hpp b/src/karts/ghost_kart.hpp index c0a29447c..308ddceed 100644 --- a/src/karts/ghost_kart.hpp +++ b/src/karts/ghost_kart.hpp @@ -21,6 +21,7 @@ #include "karts/kart.hpp" #include "replay/replay_base.hpp" +#include "utils/cpp2011.hpp" #include "LinearMath/btTransform.h" @@ -46,7 +47,8 @@ private: public: GhostKart(const std::string& ident, unsigned int world_kart_id, int position); - virtual void update(int ticks); + virtual void update(int ticks) OVERRIDE; + virtual void updateGraphics(float dt) OVERRIDE; virtual void reset(); // ------------------------------------------------------------------------ /** No physics body for ghost kart, so nothing to adjust. */ @@ -77,6 +79,6 @@ public: // ------------------------------------------------------------------------ virtual void kartIsInRestNow() {}; // ------------------------------------------------------------------------ - + }; // GhostKart #endif diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 56b3912a8..bf04315a0 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -118,6 +118,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id, m_max_speed = new MaxSpeed(this); m_terrain_info = new TerrainInfo(); m_powerup = new Powerup(this); + m_last_used_powerup = PowerupManager::POWERUP_NOTHING; m_vehicle = NULL; m_initial_position = position; m_race_position = position; @@ -142,8 +143,18 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id, m_is_jumping = false; m_min_nitro_ticks = 0; m_fire_clicked = 0; + m_boosted_ai = false; m_type = RaceManager::KT_AI; + m_xyz_history_size = stk_config->time2Ticks(XYZ_HISTORY_TIME); + + Vec3 initial_position = getXYZ(); + for (int i=0;iincreaseMaxSpeed(category, add_speed, engine_force, duration, - fade_out_time); + m_max_speed->increaseMaxSpeed(category, add_speed, engine_force, + stk_config->time2Ticks(duration), + stk_config->time2Ticks(fade_out_time)); } // increaseMaxSpeed +// ----------------------------------------------------------------------------- +void Kart::instantSpeedIncrease(unsigned int category, float add_max_speed, + float speed_boost, float engine_force, float duration, + float fade_out_time) +{ + m_max_speed->instantSpeedIncrease(category, add_max_speed, speed_boost, + engine_force, + stk_config->time2Ticks(duration), + stk_config->time2Ticks(fade_out_time) ); +} // instantSpeedIncrease + // ----------------------------------------------------------------------------- void Kart::setSlowdown(unsigned int category, float max_speed_fraction, int fade_in_time) { - m_max_speed->setSlowdown(category, max_speed_fraction, fade_in_time); + m_max_speed->setSlowdown(category, max_speed_fraction, fade_in_time); } // setSlowdown // ----------------------------------------------------------------------------- @@ -468,6 +497,17 @@ int Kart::getSpeedIncreaseTicksLeft(unsigned int category) const return m_max_speed->getSpeedIncreaseTicksLeft(category); } // getSpeedIncreaseTimeLeft +// ----------------------------------------------------------------------------- +void Kart::setBoostAI(bool boosted) +{ + m_boosted_ai = boosted; +} // setBoostAI +// ----------------------------------------------------------------------------- +bool Kart::getBoostAI() const +{ + return m_boosted_ai; +} // getBoostAI + // ----------------------------------------------------------------------------- /** Returns the current material the kart is on. */ const Material *Kart::getMaterial() const @@ -506,6 +546,15 @@ void Kart::setPowerup(PowerupManager::PowerupType t, int n) m_powerup->set(t, n); } // setPowerup +// ---------------------------------------------------------------------------- +/** Sets the powerup this kart has last used. Number is always 1. + * \param t Type of the powerup. + */ +void Kart::setLastUsedPowerup(PowerupManager::PowerupType t) +{ + m_last_used_powerup = t; +} // setLastUsedPowerup + // ----------------------------------------------------------------------------- int Kart::getNumPowerup() const { @@ -1188,6 +1237,11 @@ void Kart::eliminate() m_stars_effect->update(1); } + if (m_attachment) + { + m_attachment->clear(); + } + m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0); m_kart_gfx->setGFXInvisible(); if (m_engine_sound) @@ -1259,6 +1313,18 @@ void Kart::update(int ticks) { m_kart_animation->update(dt); } + + m_time_previous_counter += dt; + while (m_time_previous_counter > stk_config->ticks2Time(1)) + { + m_previous_xyz[0] = getXYZ(); + for (int i=m_xyz_history_size-1;i>0;i--) + { + m_previous_xyz[i] = m_previous_xyz[i-1]; + } + m_time_previous_counter -= stk_config->ticks2Time(1); + } + // Update the position and other data taken from the physics (or // an animation which calls setXYZ(), which also updates the kart // physical position). @@ -1359,6 +1425,10 @@ void Kart::update(int ticks) if(m_controls.getFire() && !m_fire_clicked && !m_kart_animation) { + if (m_powerup->getType() != PowerupManager::POWERUP_NOTHING) + { + setLastUsedPowerup(m_powerup->getType()); + } // use() needs to be called even if there currently is no collecteable // since use() can test if something needs to be switched on/off. m_powerup->use() ; @@ -1421,23 +1491,29 @@ void Kart::update(int ticks) old_group = m_body->getBroadphaseHandle()->m_collisionFilterGroup; m_body->getBroadphaseHandle()->m_collisionFilterGroup = 0; } +#undef XX #ifdef XX - Log::verbose("physicsafter", "%s t %f %f xyz(9-11) %f %f %f %f %f %f " + Log::verbose("physicsafter", "%s t %f %d xyz(9-11) %f %f %f %f %f %f " "v(16-18) %f %f %f steerf(20) %f maxangle(22) %f speed(24) %f " - "steering(26-27) %f %f clock(29) %lf", + "steering(26-27) %f %f clock(29) %lf skidstate(31) %d factor(33) %f " + "maxspeed(35) %f engf(37) %f", getIdent().c_str(), - World::getWorld()->getTime(), dt, + World::getWorld()->getTime(), World::getWorld()->getTimeTicks(), getXYZ().getX(), getXYZ().getY(), getXYZ().getZ(), m_body->getWorldTransform().getOrigin().getX(), m_body->getWorldTransform().getOrigin().getY(), m_body->getWorldTransform().getOrigin().getZ(), - getVelocity().getX(), getVelocity().getY(), getVelocity().getZ(), //13,14,15 - m_skidding->getSteeringFraction(), //19 - getMaxSteerAngle(), //20 - m_speed, //21 - m_vehicle->getWheelInfo(0).m_steering, //23 - m_vehicle->getWheelInfo(1).m_steering, //24 - StkTime::getRealTime() + getVelocity().getX(), getVelocity().getY(), getVelocity().getZ(), //16-18 + m_skidding->getSteeringFraction(), //20 + getMaxSteerAngle(), //22 + m_speed, //24 + m_vehicle->getWheelInfo(0).m_steering, //26 + m_vehicle->getWheelInfo(1).m_steering, //27 + StkTime::getRealTime(), //29 + m_skidding->getSkidState(), //31 + m_skidding->getSkidFactor(), //33 + m_max_speed->getCurrentMaxSpeed(), + m_max_speed->getCurrentAdditionalEngineForce() // 37 ); #endif // After the physics step was done, the position of the wheels (as stored @@ -1547,23 +1623,6 @@ void Kart::update(int ticks) NetworkConfig::get()->isServer() ) ItemManager::get()->checkItemHit(this); - static video::SColor pink(255, 255, 133, 253); - static video::SColor green(255, 61, 87, 23); - -#ifndef SERVER_ONLY - // draw skidmarks if relevant (we force pink skidmarks on when hitting - // a bubblegum) - if(m_kart_properties->getSkidEnabled() && m_skidmarks) - { - m_skidmarks->update(dt, - m_bubblegum_ticks > 0, - (m_bubblegum_ticks > 0 - ? (m_has_caught_nolok_bubblegum ? &green - : &pink) - : NULL ) ); - } -#endif - const bool emergency = getKartAnimation()!=NULL; if (emergency) @@ -1782,7 +1841,7 @@ void Kart::handleMaterialSFX(const Material *material) // terrain sound is not necessarily a looping sound so check its status before // setting its speed, to avoid 'ressuscitating' sounds that had already stopped - if(m_terrain_sound && main_loop->isLstSubstep() && + if(m_terrain_sound && main_loop->isLastSubstep() && (m_terrain_sound->getStatus()==SFXBase::SFX_PLAYING || m_terrain_sound->getStatus()==SFXBase::SFX_PAUSED)) { @@ -1998,14 +2057,16 @@ void Kart::updateNitro(int ticks) // when pressing the key, don't allow the min time to go under zero. // If it went under zero, it would be reset + // As the time deduction happens before, it can be an arbitrarily + // small number > 0. Smaller means more responsive controls. if (m_controls.getNitro() && m_min_nitro_ticks <= 0) m_min_nitro_ticks = 1; } - bool increase_speed = (m_controls.getNitro() && isOnGround()); + bool increase_speed = (m_min_nitro_ticks > 0 && isOnGround()); if (!increase_speed && m_min_nitro_ticks <= 0) { - if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING) + if (m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING) m_nitro_sound->stop(); return; } @@ -2420,7 +2481,7 @@ void Kart::updateEngineSFX(float dt) // Only update SFX during the last substep (otherwise too many SFX commands // in one frame), and if sfx are enabled if(!m_engine_sound || !SFXManager::get()->sfxAllowed() || - !main_loop->isLstSubstep() ) + !main_loop->isLastSubstep() ) return; // when going faster, use higher pitch for engine @@ -2854,18 +2915,32 @@ SFXBase* Kart::getNextEmitter() * to be lowered by X). * This function also takes additional graphical effects into account, e.g. * a (visual only) jump when skidding, and leaning of the kart. - * \param offset_xyz Offset to be added to the position. - * \param rotation Additional rotation. */ -void Kart::updateGraphics(int ticks, const Vec3& offset_xyz, - const btQuaternion& rotation) +void Kart::updateGraphics(float dt) { + static video::SColor pink(255, 255, 133, 253); + static video::SColor green(255, 61, 87, 23); + +#ifndef SERVER_ONLY + // draw skidmarks if relevant (we force pink skidmarks on when hitting + // a bubblegum) + if (m_kart_properties->getSkidEnabled() && m_skidmarks) + { + m_skidmarks->update(dt, + m_bubblegum_ticks > 0, + (m_bubblegum_ticks > 0 + ? (m_has_caught_nolok_bubblegum ? &green + : &pink) + : NULL)); + } +#endif + // Upate particle effects (creation rate, and emitter size // depending on speed) // -------------------------------------------------------- float nitro_frac = 0; if ( (m_controls.getNitro() || m_min_nitro_ticks > 0) && - isOnGround() && m_collected_energy > 0 ) + m_collected_energy > 0 ) { // fabs(speed) is important, otherwise the negative number will // become a huge unsigned number in the particle scene node! @@ -2893,7 +2968,6 @@ void Kart::updateGraphics(int ticks, const Vec3& offset_xyz, const float roll_speed = m_kart_properties->getLeanSpeed() * DEGREE_TO_RAD; - float dt = stk_config->ticks2Time(ticks); if(speed_frac > 0.8f && fabsf(steer_frac)>0.5f) { // Use steering ^ 7, which means less effect at lower @@ -2946,7 +3020,7 @@ void Kart::updateGraphics(int ticks, const Vec3& offset_xyz, center_shift = getTrans().getBasis() * center_shift; float heading = m_skidding->getVisualSkidRotation(); - Moveable::updateGraphics(ticks, center_shift, + Moveable::updateGraphics(dt, center_shift, btQuaternion(heading, 0, -m_current_lean)); // m_speed*dt is the distance the kart has moved, which determines @@ -3054,6 +3128,22 @@ const Vec3& Kart::getNormal() const return m_terrain_info->getNormal(); } // getNormal +// ------------------------------------------------------------------------ +/** Returns the position 0.25s before */ +const Vec3& Kart::getPreviousXYZ() const +{ + return m_previous_xyz[m_xyz_history_size-1]; +} // getPreviousXYZ + +// ------------------------------------------------------------------------ +/** Returns a more recent different previous position */ +const Vec3& Kart::getRecentPreviousXYZ() const +{ + //Not the most recent, because the angle variations would be too + //irregular on some tracks whose roads are not smooth enough + return m_previous_xyz[m_xyz_history_size/5]; +} // getRecentPreviousXYZ + // ------------------------------------------------------------------------ void Kart::playSound(SFXBuffer* buffer) { diff --git a/src/karts/kart.hpp b/src/karts/kart.hpp index d292f1381..a42c5f076 100644 --- a/src/karts/kart.hpp +++ b/src/karts/kart.hpp @@ -74,6 +74,18 @@ protected: * new lap is triggered. */ Vec3 m_xyz_front; + /* Determines the time covered by the history size, in seconds */ + const float XYZ_HISTORY_TIME = 0.25f; + + /* Determines the number of previous XYZ positions of the kart to remember + Initialized in the constructor and unchanged from then on */ + int m_xyz_history_size; + + /** The coordinates of the XYZ_HISTORY_SIZE previous positions */ + std::vector m_previous_xyz; + + float m_time_previous_counter; + /** Is time flying activated */ bool m_is_jumping; @@ -86,6 +98,9 @@ protected: /** Handles the powerup of a kart. */ Powerup *m_powerup; + + /** Remember the last **used** powerup type of a kart for AI purposes. */ + PowerupManager::PowerupType m_last_used_powerup; /** True if kart is flying (for debug purposes only). */ bool m_flying; @@ -158,6 +173,9 @@ protected: /** True if fire button was pushed and not released */ bool m_fire_clicked; + /** True if the kart has been selected to have a boosted ai */ + bool m_boosted_ai; + // Bullet physics parameters // ------------------------- btCompoundShape m_kart_chassis; @@ -246,8 +264,7 @@ public: virtual ~Kart(); virtual void init(RaceManager::KartType type); virtual void kartIsInRestNow(); - virtual void updateGraphics(int ticks, const Vec3& off_xyz, - const btQuaternion& off_rotation); + virtual void updateGraphics(float dt) OVERRIDE; virtual void createPhysics (); virtual void updateWeight (); virtual float getSpeedForTurnRadius(float radius) const; @@ -261,11 +278,16 @@ public: virtual void startEngineSFX (); virtual void adjustSpeed (float f); virtual void increaseMaxSpeed(unsigned int category, float add_speed, - float engine_force, int duration, - int fade_out_time); + float engine_force, float duration, + float fade_out_time); + virtual void instantSpeedIncrease(unsigned int category, float add_max_speed, + float speed_boost, float engine_force, float duration, + float fade_out_time); virtual void setSlowdown(unsigned int category, float max_speed_fraction, int fade_in_time); - virtual int getSpeedIncreaseTicksLeft(unsigned int category) const OVERRIDE; + virtual int getSpeedIncreaseTicksLeft(unsigned int category) const; + virtual void setBoostAI (bool boosted); + virtual bool getBoostAI () const; virtual void collectedItem(Item *item, int random_attachment); virtual float getStartupBoost() const; @@ -299,12 +321,18 @@ public: /** Sets a new powerup. */ virtual void setPowerup (PowerupManager::PowerupType t, int n); // ------------------------------------------------------------------------ + /** Sets the last used powerup. */ + virtual void setLastUsedPowerup (PowerupManager::PowerupType t); + // ------------------------------------------------------------------------ /** Returns the current powerup. */ virtual const Powerup* getPowerup() const { return m_powerup; } // ------------------------------------------------------------------------ /** Returns the current powerup. */ virtual Powerup* getPowerup() { return m_powerup; } // ------------------------------------------------------------------------ + /** Returns the last used powerup. */ + virtual PowerupManager::PowerupType getLastUsedPowerup() { return m_last_used_powerup; } + // ------------------------------------------------------------------------ /** Returns the number of powerups. */ virtual int getNumPowerup() const; // ------------------------------------------------------------------------ @@ -456,6 +484,12 @@ public: * defined even if the kart is flying. */ virtual const Vec3& getNormal() const; // ------------------------------------------------------------------------ + /** Returns the position 0.25s before */ + virtual const Vec3& getPreviousXYZ() const; + // ------------------------------------------------------------------------ + /** Returns a more recent different previous position */ + virtual const Vec3& getRecentPreviousXYZ() const; + // ------------------------------------------------------------------------ /** For debugging only: check if a kart is flying. */ bool isFlying() const { return m_flying; } // ------------------------------------------------------------------------ @@ -480,4 +514,3 @@ public: #endif /* EOF */ - diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index 14aae2ec0..c95271ea5 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -1026,10 +1026,10 @@ void KartModel::update(float dt, float distance, float steer, float speed, #endif core::vector3df pos = m_wheel_graphics_position[i].toIrrVector(); - float suspension_length = 0.0f; + float suspension_length = m_default_physics_suspension[i]; GhostKart* gk = dynamic_cast(m_kart); // Prevent using suspension length uninitialized - if (dt != 0.0f && !(gk && gt_replay_index == -1)) + if ( !gk || gt_replay_index != -1) { if (gk) { diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index ca4787ece..6c6b4bfc4 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -1048,11 +1048,16 @@ float KartProperties::getNitroMax() const } // getNitroMax // ---------------------------------------------------------------------------- -int KartProperties::getSlipstreamDuration() const +float KartProperties::getSlipstreamDurationFactor() const { - return stk_config->time2Ticks( m_cached_characteristic - ->getSlipstreamDuration() ); -} // getSlipstreamDuration + return m_cached_characteristic->getSlipstreamDurationFactor(); +} // getSlipstreamDurationFactor + +// ---------------------------------------------------------------------------- +float KartProperties::getSlipstreamBaseSpeed() const +{ + return m_cached_characteristic->getSlipstreamBaseSpeed(); +} // getSlipstreamBaseSpeed // ---------------------------------------------------------------------------- float KartProperties::getSlipstreamLength() const @@ -1067,16 +1072,22 @@ float KartProperties::getSlipstreamWidth() const } // getSlipstreamWidth // ---------------------------------------------------------------------------- -int KartProperties::getSlipstreamCollectTicks() const +float KartProperties::getSlipstreamInnerFactor() const { - return m_cached_characteristic->getSlipstreamCollectTicks(); -} // getSlipstreamCollectTime + return m_cached_characteristic->getSlipstreamInnerFactor(); +} // getSlipstreamInnerFactor // ---------------------------------------------------------------------------- -float KartProperties::getSlipstreamUseTime() const +float KartProperties::getSlipstreamMinCollectTime() const { - return m_cached_characteristic->getSlipstreamUseTime(); -} // getSlipstreamUseTime + return m_cached_characteristic->getSlipstreamMinCollectTime(); +} // getSlipstreamMinCollectTime + +// ---------------------------------------------------------------------------- +float KartProperties::getSlipstreamMaxCollectTime() const +{ + return m_cached_characteristic->getSlipstreamMaxCollectTime(); +} // getSlipstreamMaxCollectTime // ---------------------------------------------------------------------------- float KartProperties::getSlipstreamAddPower() const @@ -1212,4 +1223,3 @@ bool KartProperties::getSkidEnabled() const } // getSkidEnabled /* */ - diff --git a/src/karts/kart_properties.hpp b/src/karts/kart_properties.hpp index eaee98703..8253a28d8 100644 --- a/src/karts/kart_properties.hpp +++ b/src/karts/kart_properties.hpp @@ -478,11 +478,13 @@ public: int getNitroMinConsumptionTicks() const; // ------------------------------------------------------------------------ - int getSlipstreamDuration() const; + float getSlipstreamDurationFactor() const; + float getSlipstreamBaseSpeed() const; float getSlipstreamLength() const; float getSlipstreamWidth() const; - int getSlipstreamCollectTicks() const; - float getSlipstreamUseTime() const; + float getSlipstreamInnerFactor() const; + float getSlipstreamMinCollectTime() const; + float getSlipstreamMaxCollectTime() const; float getSlipstreamAddPower() const; float getSlipstreamMinSpeed() const; float getSlipstreamMaxSpeedIncrease() const; diff --git a/src/karts/kart_rewinder.cpp b/src/karts/kart_rewinder.cpp index 648b64303..679755214 100644 --- a/src/karts/kart_rewinder.cpp +++ b/src/karts/kart_rewinder.cpp @@ -81,7 +81,7 @@ void KartRewinder::computeError() */ BareNetworkString* KartRewinder::saveState() const { - const int MEMSIZE = 13*sizeof(float) + 9+3; + const int MEMSIZE = 17*sizeof(float) + 9+3; BareNetworkString *buffer = new BareNetworkString(MEMSIZE); const btRigidBody *body = getBody(); @@ -96,6 +96,8 @@ BareNetworkString* KartRewinder::saveState() const buffer->add(body->getAngularVelocity()); buffer->addUInt8(m_has_started); // necessary for startup speed boost buffer->addFloat(m_vehicle->getMinSpeed()); + buffer->addFloat(m_vehicle->getTimedRotationTime()); + buffer->add(m_vehicle->getTimedRotation()); // 2) Steering and other player controls // ------------------------------------- @@ -125,8 +127,6 @@ BareNetworkString* KartRewinder::saveState() const /** Actually rewind to the specified state. */ void KartRewinder::rewindToState(BareNetworkString *buffer) { - buffer->reset(); // make sure the buffer is read from the beginning - // 1) Physics values: transform and velocities // ------------------------------------------- btTransform t; @@ -134,16 +134,8 @@ void KartRewinder::rewindToState(BareNetworkString *buffer) t.setRotation(buffer->getQuat()); btRigidBody *body = getBody(); body->setLinearVelocity(buffer->getVec3()); - Log::info("KartRewinder", "t %f xyz %f %f %f v %f %f %f", - World::getWorld()->getTime(), - t.getOrigin().getX(), - t.getOrigin().getY(), - t.getOrigin().getZ(), - body->getLinearVelocity().getX(), - body->getLinearVelocity().getY(), - body->getLinearVelocity().getZ()); - body->setAngularVelocity(buffer->getVec3()); + // This function also reads the velocity, so it must be called // after the velocities are set body->proceedToTransform(t); @@ -152,6 +144,9 @@ void KartRewinder::rewindToState(BareNetworkString *buffer) setTrans(t); m_has_started = buffer->getUInt8()!=0; // necessary for startup speed boost m_vehicle->setMinSpeed(buffer->getFloat()); + float time_rot = buffer->getFloat(); + // Set timed rotation divides by time_rot + m_vehicle->setTimedRotation(time_rot, time_rot*buffer->getVec3()); // 2) Steering and other controls // ------------------------------ diff --git a/src/karts/max_speed.cpp b/src/karts/max_speed.cpp index 70692ed2c..21f95cc1f 100644 --- a/src/karts/max_speed.cpp +++ b/src/karts/max_speed.cpp @@ -397,6 +397,7 @@ void MaxSpeed::rewindTo(BareNetworkString *buffer) { m_speed_increase[i].rewindTo(buffer, (active_speedups & b) == b); } - + // Make sure to update the physics + update(0); } // rewindoTo diff --git a/src/karts/moveable.cpp b/src/karts/moveable.cpp index dde568126..0ca87bd8a 100644 --- a/src/karts/moveable.cpp +++ b/src/karts/moveable.cpp @@ -88,7 +88,7 @@ void Moveable::addError(const Vec3& pos_error, * \param offset_xyz Offset to be added to the position. * \param rotation Additional rotation. */ -void Moveable::updateGraphics(int ticks, const Vec3& offset_xyz, +void Moveable::updateGraphics(float dt, const Vec3& offset_xyz, const btQuaternion& rotation) { // If this is a client, don't smooth error during rewinds @@ -173,8 +173,6 @@ void Moveable::update(int ticks) m_motion_state->getWorldTransform(m_transform); m_velocityLC = getVelocity()*m_transform.getBasis(); updatePosition(); - - updateGraphics(ticks, Vec3(0,0,0), btQuaternion(0, 0, 0, 1)); } // update //----------------------------------------------------------------------------- diff --git a/src/karts/moveable.hpp b/src/karts/moveable.hpp index 435c968b5..9281ddabd 100644 --- a/src/karts/moveable.hpp +++ b/src/karts/moveable.hpp @@ -65,6 +65,9 @@ protected: btRigidBody *m_body; KartMotionState *m_motion_state; + virtual void updateGraphics(float dt, const Vec3& off_xyz, + const btQuaternion& off_rotation); + public: Moveable(); virtual ~Moveable(); @@ -116,8 +119,6 @@ public: m_motion_state->setWorldTransform(m_transform); } // setRotation(btQuaternion) // ------------------------------------------------------------------------ - virtual void updateGraphics(int ticks, const Vec3& off_xyz, - const btQuaternion& off_rotation); virtual void reset(); virtual void update(int ticks) ; btRigidBody *getBody() const {return m_body; } @@ -130,6 +131,12 @@ public: void updatePosition(); void addError(const Vec3& pos_error, const btQuaternion &rot_error); + // ------------------------------------------------------------------------ + /** Called once per rendered frame. It is used to only update any graphical + * effects. + * \param dt Time step size (since last call). + */ + virtual void updateGraphics(float dt) = 0; }; // class Moveable #endif diff --git a/src/karts/skidding.cpp b/src/karts/skidding.cpp index 4da216399..9754b7d53 100644 --- a/src/karts/skidding.cpp +++ b/src/karts/skidding.cpp @@ -97,10 +97,11 @@ void Skidding::reset() void Skidding::saveState(BareNetworkString *buffer) { buffer->addUInt8(m_skid_state); - if(m_skid_state == SKID_NONE) - return; + buffer->addFloat(m_remaining_jump_time); buffer->addFloat(m_skid_time); buffer->addFloat(m_skid_factor); + if(m_skid_state == SKID_NONE) + return; } // saveState // ---------------------------------------------------------------------------- @@ -110,9 +111,8 @@ void Skidding::saveState(BareNetworkString *buffer) void Skidding::rewindTo(BareNetworkString *buffer) { m_skid_state = (SkidState)buffer->getUInt8(); - if(m_skid_state == SKID_NONE) - return; - m_skid_time = buffer->getFloat(); + m_remaining_jump_time = buffer->getFloat(); + m_skid_time = buffer->getFloat(); m_skid_factor = buffer->getFloat(); } // rewindTo diff --git a/src/karts/xml_characteristic.cpp b/src/karts/xml_characteristic.cpp index 2a09aab37..2e9a34676 100644 --- a/src/karts/xml_characteristic.cpp +++ b/src/karts/xml_characteristic.cpp @@ -561,16 +561,20 @@ void XmlCharacteristic::load(const XMLNode *node) if (const XMLNode *sub_node = node->getNode("slipstream")) { - sub_node->get("duration", - &m_values[SLIPSTREAM_DURATION]); + sub_node->get("duration-factor", + &m_values[SLIPSTREAM_DURATION_FACTOR]); + sub_node->get("base-speed", + &m_values[SLIPSTREAM_BASE_SPEED]); sub_node->get("length", &m_values[SLIPSTREAM_LENGTH]); sub_node->get("width", &m_values[SLIPSTREAM_WIDTH]); - sub_node->get("collect-time", - &m_values[SLIPSTREAM_COLLECT_TIME]); - sub_node->get("use-time", - &m_values[SLIPSTREAM_USE_TIME]); + sub_node->get("inner-factor", + &m_values[SLIPSTREAM_INNER_FACTOR]); + sub_node->get("min-collect-time", + &m_values[SLIPSTREAM_MIN_COLLECT_TIME]); + sub_node->get("max-collect-time", + &m_values[SLIPSTREAM_MAX_COLLECT_TIME]); sub_node->get("add-power", &m_values[SLIPSTREAM_ADD_POWER]); sub_node->get("min-speed", @@ -624,4 +628,3 @@ void XmlCharacteristic::load(const XMLNode *node) /* */ } // load - diff --git a/src/main.cpp b/src/main.cpp index 5840042fe..cd7fe6a45 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -554,7 +554,8 @@ void cmdLineHelp() "./data/stk_config.xml\n" " -k, --numkarts=NUM Set number of karts on the racetrack.\n" " --kart=NAME Use kart NAME.\n" - " --ai=a,b,... Use the karts a, b, ... for the AI.\n" + " --ai=a,b,... Use the karts a, b, ... for the AI, and additional player kart.\n" + " --aiNP=a,b,... Use the karts a, b, ... for the AI, no additional player kart.\n" " --laps=N Define number of laps to N.\n" " --mode=N N=1 Beginner, N=2 Intermediate, N=3 Expert, N=4 SuperTux.\n" " --type=N N=0 Normal, N=1 Time trial, N=2 Follow The Leader\n" @@ -713,7 +714,7 @@ int handleCmdLinePreliminary() UserConfigParams::m_verbosity |= UserConfigParams::LOG_MISC; if(CommandLine::has("--debug=all") ) UserConfigParams::m_verbosity |= UserConfigParams::LOG_ALL; - //if(CommandLine::has("--online")) + if(CommandLine::has("--online")) MainMenuScreen::m_enable_online=true; #if !(defined(SERVER_ONLY) || defined(ANDROID)) if(CommandLine::has("--apitrace")) @@ -1242,6 +1243,38 @@ int handleCmdLine() race_manager->setNumKarts((int)l.size()+1); } // --ai + if(CommandLine::has("--aiNP", &s)) + { + const std::vector l=StringUtils::split(std::string(s),','); + race_manager->setDefaultAIKartList(l); + race_manager->setNumKarts((int)l.size()); + } // --aiNP + + if(CommandLine::has( "--mode", &s) || CommandLine::has( "--difficulty", &s)) + { + int n = atoi(s.c_str()); + if(n<0 || n>RaceManager::DIFFICULTY_LAST) + Log::warn("main", "Invalid difficulty '%s' - ignored.\n", + s.c_str()); + else + race_manager->setDifficulty(RaceManager::Difficulty(n)); + } // --mode + + if(CommandLine::has("--type", &n)) + { + switch (n) + { + case 0: race_manager->setMinorMode(RaceManager::MINOR_MODE_NORMAL_RACE); + break; + case 1: race_manager->setMinorMode(RaceManager::MINOR_MODE_TIME_TRIAL); + break; + case 2: race_manager->setMinorMode(RaceManager::MINOR_MODE_FOLLOW_LEADER); + break; + default: + Log::warn("main", "Invalid race type '%d' - ignored.", n); + } + } // --type + if(CommandLine::has("--track", &s) || CommandLine::has("-t", &s)) { race_manager->setTrack(s); diff --git a/src/main_android.cpp b/src/main_android.cpp index 0b9003c0b..7c0c2f906 100644 --- a/src/main_android.cpp +++ b/src/main_android.cpp @@ -49,6 +49,9 @@ void override_default_params() UserConfigParams::m_screen_keyboard = true; } + // Set bigger fonts and buttons + UserConfigParams::m_hidpi_enabled = true; + // It shouldn't matter, but STK is always run in fullscreen on android UserConfigParams::m_fullscreen = true; diff --git a/src/main_loop.cpp b/src/main_loop.cpp index d9b953ea9..79c7ad3f0 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -134,7 +134,7 @@ float MainLoop::getLimitedDt() { Log::verbose("fps", "time %f distance %f dt %f fps %f", lw->getTime(), - lw->getDistanceDownTrackForKart(0), + lw->getDistanceDownTrackForKart(0, true), dt*0.001f, 1000.0f / dt); } else diff --git a/src/main_loop.hpp b/src/main_loop.hpp index 7b05b439f..1ff05b73c 100644 --- a/src/main_loop.hpp +++ b/src/main_loop.hpp @@ -55,7 +55,7 @@ public: // ------------------------------------------------------------------------ /** Returns if this is the last substep. Used to reduce the amount * of updates (e.g. to sfx position) to once per rendered frame. */ - bool isLstSubstep() const { return m_is_last_substep; } + bool isLastSubstep() const { return m_is_last_substep; } }; // MainLoop extern MainLoop* main_loop; diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index b2c149268..13bfe720e 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -107,7 +107,7 @@ void LinearWorld::reset() for(unsigned int i=0; iupdate(kart->getFrontXYZ()); kart_info.m_overall_distance = kart_info.m_finished_laps * Track::getCurrentTrack()->getTrackLength() - + getDistanceDownTrackForKart(kart->getWorldKartId()); + + getDistanceDownTrackForKart(kart->getWorldKartId(), true); } // for n // Update all positions. This must be done after _all_ karts have @@ -198,13 +198,10 @@ void LinearWorld::update(int ticks) if (m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated() ) continue; - // During the last lap update the estimated finish time. - // This is used to play the faster music, and by the AI - if (m_kart_info[i].m_finished_laps == race_manager->getNumLaps()-1) - { - m_kart_info[i].m_estimated_finish = + // Update the estimated finish time. + // This is used by the AI + m_kart_info[i].m_estimated_finish = estimateFinishTimeForKart(m_karts[i]); - } } #ifdef DEBUG @@ -222,7 +219,7 @@ void LinearWorld::update(int ticks) j, m_karts[j]->getPosition(), m_karts[j]->hasFinishedRace(), m_kart_info[j].m_finished_laps, - getDistanceDownTrackForKart(m_karts[j]->getWorldKartId()), + getDistanceDownTrackForKart(m_karts[j]->getWorldKartId(), true), m_kart_info[j].m_overall_distance, (m_karts[j]->getPosition() == m_karts[i]->getPosition() ? "<--- !!!" : "") ); @@ -240,6 +237,7 @@ void LinearWorld::update(int ticks) */ void LinearWorld::updateGraphics(float dt) { + WorldWithRank::updateGraphics(dt); if (m_last_lap_sfx_playing && m_last_lap_sfx->getStatus() != SFXBase::SFX_PLAYING) { @@ -299,7 +297,7 @@ void LinearWorld::newLap(unsigned int kart_index) m_kart_info[kart_index].m_overall_distance = m_kart_info[kart_index].m_finished_laps * Track::getCurrentTrack()->getTrackLength() - + getDistanceDownTrackForKart(kart->getWorldKartId()); + + getDistanceDownTrackForKart(kart->getWorldKartId(), true); } // Last lap message (kart_index's assert in previous block already) if (raceHasLaps() && kart_info.m_finished_laps+1 == lap_count) @@ -408,9 +406,9 @@ void LinearWorld::newLap(unsigned int kart_index) * crossing the start line.. * \param kart_id Index of the kart. */ -float LinearWorld::getDistanceDownTrackForKart(const int kart_id) const +float LinearWorld::getDistanceDownTrackForKart(const int kart_id, bool account_for_checklines) const { - return getTrackSector(kart_id)->getDistanceFromStart(); + return getTrackSector(kart_id)->getDistanceFromStart(account_for_checklines); } // getDistanceDownTrackForKart //----------------------------------------------------------------------------- @@ -431,13 +429,12 @@ int LinearWorld::getLapForKart(const int kart_id) const } // getLapForKart //----------------------------------------------------------------------------- -/** Returns the estimated finishing time. Only valid during the last lap! +/** Returns the estimated finishing time. * \param kart_id Id of the kart. */ float LinearWorld::getEstimatedFinishTime(const int kart_id) const { assert(kart_id < (int)m_kart_info.size()); - assert(m_kart_info[kart_id].m_finished_laps == race_manager->getNumLaps()-1); return m_kart_info[kart_id].m_estimated_finish; } // getEstimatedFinishTime diff --git a/src/modes/linear_world.hpp b/src/modes/linear_world.hpp index b8aa0ced2..e1577fc5b 100644 --- a/src/modes/linear_world.hpp +++ b/src/modes/linear_world.hpp @@ -121,6 +121,8 @@ public: virtual void update(int ticks) OVERRIDE; virtual void updateGraphics(float dt) OVERRIDE; float getDistanceDownTrackForKart(const int kart_id) const; + float getDistanceDownTrackForKart(const int kart_id, + bool account_for_checklines) const; float getDistanceToCenterForKart(const int kart_id) const; float getEstimatedFinishTime(const int kart_id) const; int getLapForKart(const int kart_id) const; diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 9cde81766..5e2ea6b09 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -972,6 +972,18 @@ void World::updateGraphics(float dt) Weather::getInstance()->update(dt); } PROFILER_POP_CPU_MARKER(); + + // Update graphics of karts, e.g. visual suspension, skid marks + const int kart_amount = (int)m_karts.size(); + for (int i = 0; i < kart_amount; ++i) + { + // Update all karts that are not eliminated + if (!m_karts[i]->isEliminated() ) + m_karts[i]->updateGraphics(dt); + } + + projectile_manager->updateGraphics(dt); + Track::getCurrentTrack()->updateGraphics(dt); } // updateGraphics //----------------------------------------------------------------------------- diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 4991b4d49..b761824b2 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -305,6 +305,15 @@ void WorldStatus::updateTime(int ticks) { // set phase is over, go to the next one m_phase = GO_PHASE; + // Save one initial state on a client, in case that an event + // is received from a client (trieggering a rollback) before + // a state from the server has been received. + if (NetworkConfig::get()->isNetworking() && + NetworkConfig::get()->isClient() ) + { + RewindManager::get()->saveLocalState(); + // FIXME TODO: save state in rewind queue! + } if (m_play_ready_set_go_sounds) { m_start_sound->play(); diff --git a/src/network/protocols/game_protocol.cpp b/src/network/protocols/game_protocol.cpp index ef8bc243f..31edacd78 100644 --- a/src/network/protocols/game_protocol.cpp +++ b/src/network/protocols/game_protocol.cpp @@ -245,14 +245,22 @@ void GameProtocol::handleAdjustTime(Event *event) // ---------------------------------------------------------------------------- /** Called by the server before assembling a new message containing the full * state of the race to be sent to a client. + * \param local_save If set it allows a state to be saved on a client. + * This only happens at the very first time step to ensure each client + * has a state in case it receives an event before a server state. */ -void GameProtocol::startNewState() +void GameProtocol::startNewState(bool local_save) { - assert(NetworkConfig::get()->isServer()); + assert(local_save || NetworkConfig::get()->isServer()); + m_data_to_send->clear(); - m_data_to_send->addUInt8(GP_STATE).addUInt32(World::getWorld()->getTimeTicks()); - Log::info("GameProtocol", "Sending new state at %d.", - World::getWorld()->getTimeTicks()); + // Local saves don't neet this info, they pass time directly to the + // RewindInfo in RewindManager::saveLocalState. + if (!local_save) + { + m_data_to_send->addUInt8(GP_STATE) + .addUInt32(World::getWorld()->getTimeTicks()); + } } // startNewState // ---------------------------------------------------------------------------- @@ -262,7 +270,6 @@ void GameProtocol::startNewState() */ void GameProtocol::addState(BareNetworkString *buffer) { - assert(NetworkConfig::get()->isServer()); m_data_to_send->addUInt16(buffer->size()); (*m_data_to_send) += *buffer; } // addState @@ -273,6 +280,8 @@ void GameProtocol::addState(BareNetworkString *buffer) */ void GameProtocol::sendState() { + Log::info("GameProtocol", "Sending new state at %d.", + World::getWorld()->getTimeTicks()); assert(NetworkConfig::get()->isServer()); sendMessageToPeersChangingToken(m_data_to_send, /*reliable*/true); } // sendState @@ -287,20 +296,19 @@ void GameProtocol::handleState(Event *event) return; assert(NetworkConfig::get()->isClient()); - NetworkString &data = event->data(); - int ticks = data.getUInt32(); + const NetworkString &data = event->data(); + int ticks = data.getUInt32(); + // Now copy the state data (without ticks etc) to a new + // string, so it can be reset to the beginning easily + // when restoring the state: + BareNetworkString *bns = new BareNetworkString(data.getCurrentData(), + data.size()); + + // The memory for bns will be handled in the RewindInfoState object + RewindManager::get()->addNetworkState(bns, ticks); + Log::info("GameProtocol", "Received at %d state from %d", World::getWorld()->getTimeTicks(), ticks); - int index = 0; - while (data.size() > 0) - { - uint16_t count = data.getUInt16(); - BareNetworkString *state = new BareNetworkString(data.getCurrentData(), - count); - data.skip(count); - RewindManager::get()->addNetworkState(index, state, ticks); - index++; - } // while data.size()>0 } // handleState // ---------------------------------------------------------------------------- diff --git a/src/network/protocols/game_protocol.hpp b/src/network/protocols/game_protocol.hpp index ad40535e6..5e3af2f72 100644 --- a/src/network/protocols/game_protocol.hpp +++ b/src/network/protocols/game_protocol.hpp @@ -78,7 +78,7 @@ public: void controllerAction(int kart_id, PlayerAction action, int value, int val_l, int val_r); - void startNewState(); + void startNewState(bool local_save); void addState(BareNetworkString *buffer); void sendState(); void adjustTimeForClient(STKPeer *peer, int ticks); @@ -101,6 +101,9 @@ public: { return m_game_protocol.lock(); } // lock + // ------------------------------------------------------------------------ + /** Returns the NetworkString in which a state was saved. */ + NetworkString* getState() const { return m_data_to_send; } }; // class GameProtocol diff --git a/src/network/protocols/lobby_protocol.cpp b/src/network/protocols/lobby_protocol.cpp index d69e318e4..644ac035a 100644 --- a/src/network/protocols/lobby_protocol.cpp +++ b/src/network/protocols/lobby_protocol.cpp @@ -71,7 +71,6 @@ void LobbyProtocol::loadWorld() StateManager::ActivePlayer *ap = race_manager->getNumLocalPlayers()>1 ? NULL : StateManager::get()->getActivePlayer(0); - input_manager->getDeviceManager()->setSinglePlayer(ap); // Load the actual world. diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 729973a8b..a8922ce6d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -375,12 +375,12 @@ void ServerLobby::update(int ticks) STKHost::get()->getPeerCount() == 0 && NetworkConfig::get()->getServerIdFile().empty()) { - std::lock_guard lock(m_connection_mutex); if (RaceEventManager::getInstance() && RaceEventManager::getInstance()->isRunning()) { stopCurrentRace(); } + std::lock_guard lock(m_connection_mutex); m_state = NetworkConfig::get()->isLAN() ? ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS; setup(); diff --git a/src/network/rewind_info.cpp b/src/network/rewind_info.cpp index 96ba9c402..98223d05f 100644 --- a/src/network/rewind_info.cpp +++ b/src/network/rewind_info.cpp @@ -19,6 +19,7 @@ #include "network/rewind_info.hpp" #include "network/network_config.hpp" +#include "network/rewind_manager.hpp" #include "physics/physics.hpp" /** Constructor for a state: it only takes the size, and allocates a buffer @@ -44,12 +45,23 @@ void RewindInfo::setTicks(int ticks) } // setTicks // ============================================================================ -RewindInfoState::RewindInfoState(int ticks, Rewinder *rewinder, - BareNetworkString *buffer, bool is_confirmed) - : RewindInfoRewinder(ticks, rewinder, buffer, is_confirmed) +RewindInfoState::RewindInfoState(int ticks, BareNetworkString *buffer, + bool is_confirmed) + : RewindInfo(ticks, is_confirmed) { + m_buffer = buffer; } // RewindInfoState +// ------------------------------------------------------------------------ +/** Rewinds to this state. This is called while going forwards in time + * again to reach current time. It will call rewindToState(). + * if the state is a confirmed state. + */ +void RewindInfoState::rewind() +{ + RewindManager::get()->restoreState(m_buffer); +} // rewind + // ============================================================================ RewindInfoEvent::RewindInfoEvent(int ticks, EventRewinder *event_rewinder, BareNetworkString *buffer, bool is_confirmed) diff --git a/src/network/rewind_info.hpp b/src/network/rewind_info.hpp index b3e6d01da..dd9ca00d0 100644 --- a/src/network/rewind_info.hpp +++ b/src/network/rewind_info.hpp @@ -84,45 +84,22 @@ public: }; // RewindInfo // ============================================================================ -/** A rewind info abstract class that keeps track of a rewinder object, and - * has a BareNetworkString buffer which is used to store a state or event. +/** A class that stores a game state and can rewind it. */ -class RewindInfoRewinder : public RewindInfo +class RewindInfoState: public RewindInfo { private: /** Pointer to the buffer which stores all states. */ BareNetworkString *m_buffer; - -protected: - /** The Rewinder instance for which this data is. */ - Rewinder *m_rewinder; - public: - RewindInfoRewinder(int ticks, Rewinder *rewinder, - BareNetworkString *buffer, bool is_confirmed) - : RewindInfo(ticks, is_confirmed) - { - m_rewinder = rewinder; - m_buffer = buffer; - } // RewindInfoRewinder - // ------------------------------------------------------------------------ - virtual ~RewindInfoRewinder() - { - delete m_buffer; - } // ~RewindInfoRewinder + RewindInfoState(int ticks, BareNetworkString *buffer, + bool is_confirmed); + virtual ~RewindInfoState() { delete m_buffer; }; + virtual void rewind(); + // ------------------------------------------------------------------------ /** Returns a pointer to the state buffer. */ BareNetworkString *getBuffer() const { return m_buffer; } -}; // RewindInfoRewinder - -// ============================================================================ -class RewindInfoState: public RewindInfoRewinder -{ -public: - RewindInfoState(int ticks, Rewinder *rewinder, - BareNetworkString *buffer, bool is_confirmed); - virtual ~RewindInfoState() {}; - // ------------------------------------------------------------------------ virtual bool isState() const { return true; } // ------------------------------------------------------------------------ @@ -130,23 +107,8 @@ public: * It calls undoState in the rewinder. */ virtual void undo() { - if(m_rewinder) // Unit testing uses NULL as rewinder - m_rewinder->undoState(getBuffer()); + // Nothing being done in case of an undo that goes further back } // undo - // ------------------------------------------------------------------------ - /** Rewinds to this state. This is called while going forwards in time - * again to reach current time. It will call rewindToState(). - * if the state is a confirmed state. */ - virtual void rewind() - { - if (isConfirmed()) - m_rewinder->rewindToState(getBuffer()); - else - { - // TODO - // Handle replacing of stored states. - } - } // rewind }; // class RewindInfoState // ============================================================================ @@ -178,7 +140,7 @@ public: } // undo // ------------------------------------------------------------------------ /** This is called while going forwards in time again to reach current - * time. Calls rewindEvent(). + * time. Calls rewind() in the event rewinder. */ virtual void rewind() { diff --git a/src/network/rewind_manager.cpp b/src/network/rewind_manager.cpp index 6eb20ed39..08ea6211f 100755 --- a/src/network/rewind_manager.cpp +++ b/src/network/rewind_manager.cpp @@ -158,16 +158,82 @@ void RewindManager::addNetworkEvent(EventRewinder *event_rewinder, * \param time Time at which the event was recorded. * \param buffer Pointer to the event data. */ -void RewindManager::addNetworkState(int rewinder_index, BareNetworkString *buffer, - int ticks) +void RewindManager::addNetworkState(BareNetworkString *buffer, int ticks) { assert(NetworkConfig::get()->isClient()); - // On a client dt from a state is never used, it maintains - // its own dt information (using TimeEvents). - m_rewind_queue.addNetworkState(m_all_rewinder[rewinder_index], buffer, - ticks); + m_rewind_queue.addNetworkState(buffer, ticks); } // addNetworkState +// ---------------------------------------------------------------------------- +/** Saves a local state using the GameProtocol function to combine several + * independent rewinders to write one state. Typically only the server needs + * to save a state (which is then send to the clients), except that each + * client needs one initial state (in case that it receives an event from + * a client before a state from the serer). + * \param allow_local_save Do a local save. + */ +void RewindManager::saveState(bool local_save) +{ + PROFILER_PUSH_CPU_MARKER("RewindManager - save state", 0x20, 0x7F, 0x20); + GameProtocol::lock()->startNewState(local_save); + AllRewinder::const_iterator rewinder; + for (rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end(); ++rewinder) + { + // TODO: check if it's worth passing in a sufficiently large buffer from + // GameProtocol - this would save the copy operation. + BareNetworkString *buffer = (*rewinder)->saveState(); + if (buffer && buffer->size() >= 0) + { + m_overall_state_size += buffer->size(); + GameProtocol::lock()->addState(buffer); + } // size >= 0 + delete buffer; // buffer can be freed + } + PROFILER_POP_CPU_MARKER(); +} // saveState + +// ---------------------------------------------------------------------------- +/** Saves a state on the client. Used to save an initial state at t=0 for each + * client in case that we receive an event from another client (which will + * trigger a rewind) before a state from the server. + */ +void RewindManager::saveLocalState() +{ + int ticks = World::getWorld()->getTimeTicks(); + + saveState(/*local_state*/true); + NetworkString *state = GameProtocol::lock()->getState(); + + // Copy the data to a new string, making the buffer in + // GameProtocol availble for again. + BareNetworkString *bns = + new BareNetworkString(state->getCurrentData(), + state->size() ); + m_rewind_queue.addLocalState(bns, /*confirmed*/true, ticks); +} // saveLocalState + +// ---------------------------------------------------------------------------- +/** Restores a given state by calling rewindToState for each available rewinder + * with its correct data. + * \param data The data string used to store the whole game state. + * + */ +void RewindManager::restoreState(BareNetworkString *data) +{ + data->reset(); + int index = 0; + //AllRewinder::const_iterator rewinder; + for (auto rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end(); + ++rewinder) + { + uint16_t count = data->getUInt16(); + if (count > 0) + { + (*rewinder)->rewindToState(data); + } + } // for all rewinder +} // restoreState + // ---------------------------------------------------------------------------- /** Determines if a new state snapshot should be taken, and if so calls all * rewinder to do so. @@ -192,31 +258,14 @@ void RewindManager::update(int ticks_not_used) return; } - // Save state - PROFILER_PUSH_CPU_MARKER("RewindManager - save state", 0x20, 0x7F, 0x20); - GameProtocol::lock()->startNewState(); - AllRewinder::const_iterator rewinder; - for (rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end(); ++rewinder) - { - // TODO: check if it's worth passing in a sufficiently large buffer from - // GameProtocol - this would save the copy operation. - BareNetworkString *buffer = (*rewinder)->saveState(); - if (buffer && buffer->size() >= 0) - { - m_overall_state_size += buffer->size(); - GameProtocol::lock()->addState(buffer); - } // size >= 0 - delete buffer; // buffer can be freed - } - PROFILER_POP_CPU_MARKER(); + saveState(/**allow_local_save*/false); PROFILER_PUSH_CPU_MARKER("RewindManager - send state", 0x20, 0x7F, 0x40); GameProtocol::lock()->sendState(); PROFILER_POP_CPU_MARKER(); m_last_saved_state = ticks; } // update -#include "karts/abstract_kart.hpp" // ---------------------------------------------------------------------------- /** Replays all events from the last event played till the specified time. * \param world_ticks Up to (and inclusive) which time events will be replayed. @@ -237,8 +286,6 @@ void RewindManager::playEventsTill(int world_ticks, int *ticks) { Log::setPrefix("Rewind"); PROFILER_PUSH_CPU_MARKER("Rewind", 128, 128, 128); - if (World::getWorld()->getKart(0)->getControls().getAccel() > 0) - printf(""); rewindTo(rewind_ticks, world_ticks); // This should replay everything up to 'now' assert(World::getWorld()->getTimeTicks() == world_ticks); @@ -348,5 +395,3 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks) history->setReplayHistory(is_history); m_is_rewinding = false; } // rewindTo - -// ---------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/rewind_manager.hpp b/src/network/rewind_manager.hpp index d5fdce6be..2662f0d78 100644 --- a/src/network/rewind_manager.hpp +++ b/src/network/rewind_manager.hpp @@ -144,9 +144,11 @@ public: bool confirmed, int ticks = -1); void addNetworkEvent(EventRewinder *event_rewinder, BareNetworkString *buffer, int ticks); - void addNetworkState(int rewinder_index, BareNetworkString *buffer, - int ticks); + void addNetworkState(BareNetworkString *buffer, int ticks); void addNextTimeStep(int ticks, float dt); + void saveState(bool local_save); + void saveLocalState(); + void restoreState(BareNetworkString *buffer); // ------------------------------------------------------------------------ /** Adds a Rewinder to the list of all rewinders. * \return true If rewinding is enabled, false otherwise. diff --git a/src/network/rewind_queue.cpp b/src/network/rewind_queue.cpp index b01409f18..e1251cfbe 100755 --- a/src/network/rewind_queue.cpp +++ b/src/network/rewind_queue.cpp @@ -77,6 +77,7 @@ void RewindQueue::reset() m_all_rewind_info.clear(); m_current = m_all_rewind_info.end(); + m_latest_confirmed_state_time = -1; } // reset // ---------------------------------------------------------------------------- @@ -100,7 +101,7 @@ void RewindQueue::insertRewindInfo(RewindInfo *ri) // previous element, i.e. before the current element: if ((*i_prev)->getTicks() < ri->getTicks()) break; if ((*i_prev)->getTicks() == ri->getTicks() && - (*i_prev)->isState() && ri->isEvent() ) break; + ri->isEvent() ) break; i = i_prev; } if(m_current == m_all_rewind_info.end()) @@ -135,12 +136,16 @@ void RewindQueue::addLocalEvent(EventRewinder *event_rewinder, * faster rewinds. * \param ticks Time at which the event happened. */ -void RewindQueue::addLocalState(Rewinder *rewinder, BareNetworkString *buffer, +void RewindQueue::addLocalState(BareNetworkString *buffer, bool confirmed, int ticks) { - RewindInfo *ri = new RewindInfoState(ticks, rewinder, buffer, confirmed); + RewindInfo *ri = new RewindInfoState(ticks, buffer, confirmed); assert(ri); insertRewindInfo(ri); + if (confirmed && m_latest_confirmed_state_time < ticks) + { + cleanupOldRewindInfo(ticks); + } } // addLocalState // ---------------------------------------------------------------------------- @@ -170,11 +175,9 @@ void RewindQueue::addNetworkEvent(EventRewinder *event_rewinder, * \param buffer Pointer to the event data. * \param ticks Time at which the event happened. */ -void RewindQueue::addNetworkState(Rewinder *rewinder, BareNetworkString *buffer, - int ticks) +void RewindQueue::addNetworkState(BareNetworkString *buffer, int ticks) { - RewindInfo *ri = new RewindInfoState(ticks, rewinder, - buffer, /*confirmed*/true); + RewindInfo *ri = new RewindInfoState(ticks, buffer, /*confirmed*/true); m_network_events.lock(); m_network_events.getData().push_back(ri); @@ -211,6 +214,7 @@ void RewindQueue::mergeNetworkData(int world_ticks, bool *needs_rewind, // FIXME: making m_network_events sorted would prevent the need to // go through the whole list of events + int latest_confirmed_state = -1; AllNetworkRewindInfo::iterator i = m_network_events.getData().begin(); while (i != m_network_events.getData().end()) { @@ -258,13 +262,41 @@ void RewindQueue::mergeNetworkData(int world_ticks, bool *needs_rewind, *rewind_ticks = (*i)->getTicks(); } // if client and ticks < world_ticks + if ((*i)->isState() && (*i)->getTicks() > latest_confirmed_state && + (*i)->isConfirmed()) + { + latest_confirmed_state = (*i)->getTicks(); + } + i = m_network_events.getData().erase(i); } // for i in m_network_events m_network_events.unlock(); + if (latest_confirmed_state > m_latest_confirmed_state_time) + { + cleanupOldRewindInfo(latest_confirmed_state); + } + } // mergeNetworkData +// ---------------------------------------------------------------------------- +/** Deletes all states and event before the given time. + * \param ticks Time (in ticks). + */ +void RewindQueue::cleanupOldRewindInfo(int ticks) +{ + auto i = m_all_rewind_info.begin(); + + while ( (*i)->getTicks() < ticks) + { + if (m_current == i) next(); + delete *i; + i = m_all_rewind_info.erase(i); + } + +} // cleanupOldRewindInfo + // ---------------------------------------------------------------------------- bool RewindQueue::isEmpty() const { @@ -288,28 +320,19 @@ bool RewindQueue::hasMoreRewindInfo() const */ int RewindQueue::undoUntil(int undo_ticks) { - // m_current points to the next not yet executed event (or state) - // or end() if nothing else is in the queue - if (m_current != m_all_rewind_info.begin()) - m_current--; - - do + // A rewind is done after a state in the past is inserted. This function + // makes sure that m_current is not end() + assert(m_current != m_all_rewind_info.end()); + + while((*m_current)->getTicks() > undo_ticks || + (*m_current)->isEvent() || !(*m_current)->isConfirmed()) { // Undo all events and states from the current time (*m_current)->undo(); - - if ( (*m_current)->getTicks() <= undo_ticks && - (*m_current)->isState() && (*m_current)->isConfirmed() ) - { - return (*m_current)->getTicks(); - } m_current--; - } while (m_current != m_all_rewind_info.end()); + } - // Shouldn't happen - Log::error("RewindManager", "No state for rewind to %d", - undo_ticks); - return -1; + return (*m_current)->getTicks(); } // undoUntil // ---------------------------------------------------------------------------- @@ -319,13 +342,11 @@ int RewindQueue::undoUntil(int undo_ticks) void RewindQueue::replayAllEvents(int ticks) { // Replay all events that happened at the current time step - while ( m_current != m_all_rewind_info.end() && - (*m_current)->getTicks() == ticks ) + while ( hasMoreRewindInfo() && (*m_current)->getTicks() == ticks ) { if ((*m_current)->isEvent()) (*m_current)->rewind(); m_current++; - if (!hasMoreRewindInfo()) break; } // while current->getTIcks == ticks } // replayAllEvents @@ -367,7 +388,7 @@ void RewindQueue::unitTesting() assert(q0.isEmpty()); assert(!q0.hasMoreRewindInfo()); - q0.addLocalState(NULL, NULL, /*confirmed*/true, 0); + q0.addLocalState(NULL, /*confirmed*/true, 0); assert(q0.m_all_rewind_info.front()->isState()); assert(!q0.m_all_rewind_info.front()->isEvent()); assert(q0.hasMoreRewindInfo()); @@ -389,7 +410,7 @@ void RewindQueue::unitTesting() assert((*rii)->isEvent()); // Another state must be sorted before the event: - q0.addNetworkState(dummy_rewinder, NULL, 0); + q0.addNetworkState(NULL, 0); assert(q0.hasMoreRewindInfo()); q0.mergeNetworkData(world_ticks, &needs_rewind, &rewind_ticks); assert(q0.m_all_rewind_info.size() == 3); @@ -414,7 +435,7 @@ void RewindQueue::unitTesting() // Now test inserting an event first, then the state RewindQueue q1; q1.addLocalEvent(NULL, NULL, true, 5); - q1.addLocalState(NULL, NULL, true, 5); + q1.addLocalState(NULL, true, 5); rii = q1.m_all_rewind_info.begin(); assert((*rii)->isState()); rii++; @@ -431,4 +452,33 @@ void RewindQueue::unitTesting() b1.addLocalEvent(NULL, NULL, true, 2); RewindInfo *ri = b1.getCurrent(); assert(ri->getTicks() == 2); + + // 2) Make sure when adding an event at the same time as an existing + // event, that m_current pooints to the first event, otherwise + // events with same time stamp will not be handled correctly. + // At this stage current points to the event at time 2 from above + AllRewindInfo::iterator current_old = b1.m_current; + b1.addLocalEvent(NULL, NULL, true, 2); + // Make sure that current was not modified, i.e. the new event at time + // 2 was added at the end of the list: + assert(current_old == b1.m_current); + + // This should not trigger an exception, now current points to the + // second event at the same time: + b1.next(); + assert(ri->getTicks() == 2); + assert(ri->isEvent()); + b1.next(); + assert(b1.m_current == b1.m_all_rewind_info.end()); + + // 3) Test that if cleanupOldRewindInfo is called, it will if necessary + // adjust m_current to point to the latest confirmed state. + RewindQueue b2; + b2.addNetworkState(NULL, 1); + b2.addNetworkState(NULL, 2); + b2.addNetworkState(NULL, 3); + b2.mergeNetworkData(4, &needs_rewind, &rewind_ticks); + assert((*b2.m_current)->getTicks() == 3); + + } // unitTesting diff --git a/src/network/rewind_queue.hpp b/src/network/rewind_queue.hpp index 8a7180fcd..0680ccd71 100755 --- a/src/network/rewind_queue.hpp +++ b/src/network/rewind_queue.hpp @@ -53,7 +53,12 @@ private: /** Iterator to the curren time step info to be handled. */ AllRewindInfo::iterator m_current; + /** Time at which the latest confirmed state is at. */ + int m_latest_confirmed_state_time; + + void insertRewindInfo(RewindInfo *ri); + void cleanupOldRewindInfo(int ticks); public: static void unitTesting(); @@ -63,12 +68,10 @@ public: void reset(); void addLocalEvent(EventRewinder *event_rewinder, BareNetworkString *buffer, bool confirmed, int ticks); - void addLocalState(Rewinder *rewinder, BareNetworkString *buffer, - bool confirmed, int ticks); + void addLocalState(BareNetworkString *buffer, bool confirmed, int ticks); void addNetworkEvent(EventRewinder *event_rewinder, BareNetworkString *buffer, int ticks); - void addNetworkState(Rewinder *rewinder, BareNetworkString *buffer, - int ticks); + void addNetworkState(BareNetworkString *buffer, int ticks); void mergeNetworkData(int world_ticks, bool *needs_rewind, int *rewind_ticks); void replayAllEvents(int ticks); diff --git a/src/network/transport_address.cpp b/src/network/transport_address.cpp index ee5b5fc61..8a0fee3fb 100644 --- a/src/network/transport_address.cpp +++ b/src/network/transport_address.cpp @@ -203,4 +203,17 @@ void TransportAddress::unitTesting() assert(t17.getIP() == (128u << 24)); assert(!t17.isLAN()); + // Test constructors + TransportAddress t18("128.0.0.0"); + assert(t18.getIP() == (128u << 24)); + assert(t18.getPort() == 0); + + TransportAddress t19("128.0.0.0:1"); + assert(t19.getIP() == (128u << 24)); + assert(t19.getPort() == 1); + + TransportAddress t20("128.0.0.0", 123); + assert(t20.getIP() == (128u << 24)); + assert(t20.getPort() == 123); + } // unitTesting diff --git a/src/network/transport_address.hpp b/src/network/transport_address.hpp index 4a9237e8c..fbe827094 100644 --- a/src/network/transport_address.hpp +++ b/src/network/transport_address.hpp @@ -58,7 +58,21 @@ public: } // TransportAddress(EnetAddress) // ------------------------------------------------------------------------ - /** Construct an IO address from a string in the format x.x.x.x:xxx. */ + /** Construct an IO address from a string in the format x.x.x.x with a + * port number. */ + TransportAddress(const std::string& str, uint16_t port_number) + { + std::vector ip = StringUtils::splitToUInt(str, '.'); + m_ip = 0; + m_port = 0; + if (ip.size() >= 4) + m_ip = (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3]; + + m_port = port_number; + } // TransportAddress(string of ip, port number) + + // ------------------------------------------------------------------------ + /** Construct an IO address from a string in the format x.x.x.x:x. */ TransportAddress(const std::string& str) { std::string combined = StringUtils::replace(str, ":", "."); diff --git a/src/physics/btKart.cpp b/src/physics/btKart.cpp index 4d32ae01c..3b985f498 100644 --- a/src/physics/btKart.cpp +++ b/src/physics/btKart.cpp @@ -118,8 +118,6 @@ void btKart::reset() updateWheelTransform(i, true); } m_visual_wheels_touch_ground = false; - m_skid_angular_velocity = 0; - m_is_skidding = false; m_allow_sliding = false; m_num_wheels_on_ground = 0; m_additional_impulse = btVector3(0,0,0); @@ -831,34 +829,7 @@ void btKart::updateFriction(btScalar timeStep) // Note: don't reset zipper speed, or the kart rewinder will // get incorrect zipper information. - // The kart just stopped skidding. Adjust the velocity so that - // it points in the right direction. - // FIXME: this is not good enough, we need some smooth interpolation here. - if(m_is_skidding && m_skid_angular_velocity == 0) - { - btVector3 v = m_chassisBody->getLinearVelocity(); - v.setZ(sqrt(v.getX()*v.getX()+v.getZ()*v.getZ())); - v.setX(0); - btVector3 v_new = m_chassisBody->getWorldTransform().getBasis()*v; - m_chassisBody->setLinearVelocity(v_new); - m_is_skidding = false; - } - - if(m_skid_angular_velocity!=0) - { - m_is_skidding = true; - // Skidding is implemented by not having any forward impulse, - // but only add a side impulse - for(unsigned int i=0; i<4; i++) - { - m_forwardImpulse[i] = 0; - m_sideImpulse[i] = 0; - } - btVector3 av = m_chassisBody->getAngularVelocity(); - av.setY(m_skid_angular_velocity); - m_chassisBody->setAngularVelocity(av); - } - else if (sliding && (m_allow_sliding || m_time_additional_impulse>0) ) + if (sliding && (m_allow_sliding || m_time_additional_impulse>0) ) { for (int wheel = 0; wheel < getNumWheels(); wheel++) { diff --git a/src/physics/btKart.hpp b/src/physics/btKart.hpp index 69eb071ea..c04d11d27 100644 --- a/src/physics/btKart.hpp +++ b/src/physics/btKart.hpp @@ -69,16 +69,6 @@ private: btScalar m_damping; btVehicleRaycaster *m_vehicleRaycaster; - /** The angular velocity to be applied when the kart skids. - * 0 means no skidding. */ - btScalar m_skid_angular_velocity; - - /** True if the kart is currently skidding. This is used to detect - * the end of skidding (i.e. m_skid_angular_velocity=0 and - * m_is_skidding=true), and triggers adjusting of the velocity - * direction. */ - bool m_is_skidding; - /** Sliding (skidding) will only be permited when this is true. Also check * the friction parameter in the wheels since friction directly affects * skidding. @@ -239,10 +229,6 @@ public: // ------------------------------------------------------------------------ int getUserConstraintId() const { return m_userConstraintId; } // ------------------------------------------------------------------------ - /** Sets the angular velocity to be used when skidding - * (0 means no skidding). */ - void setSkidAngularVelocity(float v) {m_skid_angular_velocity = v; } - // ------------------------------------------------------------------------ /** Returns the number of wheels on the ground. */ unsigned int getNumWheelsOnGround() const {return m_num_wheels_on_ground;} // ------------------------------------------------------------------------ @@ -274,10 +260,14 @@ public: * \param torque The rotation to apply. */ void setTimedRotation(float t, const btVector3 &rot) { - m_additional_rotation = rot/t; + if(t>0) m_additional_rotation = rot/t; m_time_additional_rotation = t; } // setTimedTorque // ------------------------------------------------------------------------ + const btVector3& getTimedRotation() const { return m_additional_rotation; } + // ------------------------------------------------------------------------ + float getTimedRotationTime() const { return m_time_additional_rotation; } + // ------------------------------------------------------------------------ /** Sets the maximum speed for this kart. */ void setMaxSpeed(float new_max_speed) { diff --git a/src/physics/physical_object.cpp b/src/physics/physical_object.cpp index d787cbc1c..30ecd328b 100644 --- a/src/physics/physical_object.cpp +++ b/src/physics/physical_object.cpp @@ -163,6 +163,10 @@ PhysicalObject::PhysicalObject(bool is_dynamic, m_reset_height = settings.m_reset_height; m_on_kart_collision = settings.m_on_kart_collision; m_on_item_collision = settings.m_on_item_collision; + m_current_transform.setOrigin(Vec3()); + m_current_transform.setRotation( + btQuaternion(0.0f, 0.0f, 0.0f, 1.0f)); + m_body_added = false; m_init_pos.setIdentity(); @@ -596,31 +600,48 @@ void PhysicalObject::init(const PhysicalObject::Settings& settings) } // init // ---------------------------------------------------------------------------- +/** This updates all only graphical elements. It is only called once per + * rendered frame, not once per time step. + * float dt Time since last rame. + */ + +void PhysicalObject::updateGraphics(float dt) +{ + if (!m_is_dynamic) + return; + Vec3 xyz = m_current_transform.getOrigin(); + + // Offset the graphical position correctly: + xyz += m_current_transform.getBasis()*m_graphical_offset; + + Vec3 hpr; + hpr.setHPR(m_current_transform.getRotation()); + + // This will only update the visual position, so it can be + // called in updateGraphics() + m_object->move(xyz.toIrrVector(), hpr.toIrrVector()*RAD_TO_DEGREE, + m_init_scale, /*updateRigidBody*/false, + /* isAbsoluteCoord */true); +} // updateGraphics + +// ---------------------------------------------------------------------------- +/** Update, called once per physics time step. + * \param dt Timestep. + */ void PhysicalObject::update(float dt) { if (!m_is_dynamic) return; - btTransform t; - m_motion_state->getWorldTransform(t); + m_motion_state->getWorldTransform(m_current_transform); - Vec3 xyz = t.getOrigin(); + const Vec3 &xyz = m_current_transform.getOrigin(); if(m_reset_when_too_low && xyz.getY()setCenterOfMassTransform(m_init_pos); m_body->setLinearVelocity (btVector3(0,0,0)); m_body->setAngularVelocity(btVector3(0,0,0)); - xyz = Vec3(m_init_pos.getOrigin()); } - // Offset the graphical position correctly: - xyz += t.getBasis()*m_graphical_offset; - //m_node->setPosition(xyz.toIrrVector()); - Vec3 hpr; - hpr.setHPR(t.getRotation()); - //m_node->setRotation(hpr.toIrrHPR()); - - m_object->move(xyz.toIrrVector(), hpr.toIrrVector()*RAD_TO_DEGREE, - m_init_scale, false, true /* isAbsoluteCoord */); } // update // ---------------------------------------------------------------------------- @@ -673,9 +694,8 @@ void PhysicalObject::handleExplosion(const Vec3& pos, bool direct_hit) } else // only affected by a distant explosion { - btTransform t; - m_motion_state->getWorldTransform(t); - btVector3 diff=t.getOrigin()-pos; + + btVector3 diff=m_current_transform.getOrigin()-pos; float len2=diff.length2(); diff --git a/src/physics/physical_object.hpp b/src/physics/physical_object.hpp index b7a6414b0..2e1d40db7 100644 --- a/src/physics/physical_object.hpp +++ b/src/physics/physical_object.hpp @@ -137,6 +137,10 @@ private: /** This is the initial position of the object for the physics. */ btTransform m_init_pos; + /** Save current transform to avoid frequent lookup from + * world transform. */ + btTransform m_current_transform; + /** The mesh might not have the same center as bullet does. This * offset is used to offset the location of the graphical mesh * so that the graphics are aligned with the bullet collision shape. */ @@ -192,6 +196,7 @@ public: virtual void reset (); virtual void handleExplosion(const Vec3& pos, bool directHit); void update (float dt); + void updateGraphics (float dt); void init (const Settings &settings); void move (const Vec3& xyz, const core::vector3df& hpr); void hit (const Material *m, const Vec3 &normal); diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 0501ce06f..d2e224947 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -280,7 +280,9 @@ void RaceManager::computeRandomKartList() } m_ai_kart_list.clear(); - unsigned int m = std::min( (unsigned) n, (unsigned)m_default_ai_list.size()); + + //Use the command line options AI list. + unsigned int m = std::min( (unsigned) m_num_karts, (unsigned)m_default_ai_list.size()); for(unsigned int i=0; igetMaterial("speedback.png"); - m_speed_meter_icon->getTexture(); + m_speed_meter_icon->getTexture(false,false); m_speed_bar_icon = material_manager->getMaterial("speedfore.png"); - m_speed_bar_icon->getTexture(); + m_speed_bar_icon->getTexture(false,false); //createMarkerTexture(); } // RaceGUI @@ -276,6 +276,7 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt) drawLap(kart, viewport, scaling); } // renderPlayerView + //----------------------------------------------------------------------------- /** Shows the current soccer result. */ @@ -460,7 +461,7 @@ void RaceGUI::drawGlobalMiniMap() //----------------------------------------------------------------------------- /** Energy meter that gets filled with nitro. This function is called from - * drawSpeedAndEnergy, which defines the correct position of the energy + * drawSpeedEnergyRank, which defines the correct position of the energy * meter. * \param x X position of the meter. * \param y Y position of the meter. @@ -473,7 +474,7 @@ void RaceGUI::drawEnergyMeter(int x, int y, const AbstractKart *kart, { #ifndef SERVER_ONLY float min_ratio = std::min(scaling.X, scaling.Y); - const int GAUGEWIDTH = 78; + const int GAUGEWIDTH = 94;//same inner radius as the inner speedometer circle int gauge_width = (int)(GAUGEWIDTH*min_ratio); int gauge_height = (int)(GAUGEWIDTH*min_ratio); @@ -483,8 +484,8 @@ void RaceGUI::drawEnergyMeter(int x, int y, const AbstractKart *kart, else if (state > 1.0f) state = 1.0f; core::vector2df offset; - offset.X = (float)(x-gauge_width) - 9.0f*scaling.X; - offset.Y = (float)y-30.0f*scaling.Y; + offset.X = (float)(x-gauge_width) - 9.5f*scaling.X; + offset.Y = (float)y-11.5f*scaling.Y; // Background @@ -497,6 +498,69 @@ void RaceGUI::drawEnergyMeter(int x, int y, const AbstractKart *kart, NULL /* clip rect */, NULL /* colors */, true /* alpha */); + // The positions for A to G are defined here. + // They are calculated from gauge_full.png + // They are further than the nitrometer farther position because + // the lines between them would otherwise cut through the outside circle. + + const int vertices_count = 9; + + core::vector2df position[vertices_count]; + position[0].X = 0.324f;//A + position[0].Y = 0.35f;//A + position[1].X = 0.01f;//B1 (margin for gauge goal) + position[1].Y = 0.88f;//B1 + position[2].X = 0.029f;//B2 + position[2].Y = 0.918f;//B2 + position[3].X = 0.307f;//C + position[3].Y = 0.99f;//C + position[4].X = 0.589f;//D + position[4].Y = 0.932f;//D + position[5].X = 0.818f;//E + position[5].Y = 0.755f;//E + position[6].X = 0.945f;//F + position[6].Y = 0.497f;//F + position[7].X = 0.948f;//G1 + position[7].Y = 0.211f;//G1 + position[8].X = 0.94f;//G2 (margin for gauge goal) + position[8].Y = 0.17f;//G2 + + // The states at which different polygons must be used. + + float threshold[vertices_count-2]; + threshold[0] = 0.0001f; //for gauge drawing + threshold[1] = 0.2f; + threshold[2] = 0.4f; + threshold[3] = 0.6f; + threshold[4] = 0.8f; + threshold[5] = 0.9999f; + threshold[6] = 1.0f; + + // Filling (current state) + + if (state > 0.0f) + { + video::S3DVertex vertices[vertices_count]; + + //3D effect : wait for the full border to appear before drawing + for (int i=0;i<5;i++) + { + if ((state-0.2f*i < 0.006f && state-0.2f*i >= 0.0f) || (0.2f*i-state < 0.003f && 0.2f*i-state >= 0.0f) ) + { + state = 0.2f*i-0.003f; + break; + } + } + + unsigned int count = computeVerticesForMeter(position, threshold, vertices, vertices_count, + state, gauge_width, gauge_height, offset); + + if(kart->getControls().getNitro() || kart->isOnMinNitroTime()) + drawMeterTexture(m_gauge_full_bright, vertices, count); + else + drawMeterTexture(m_gauge_full, vertices, count); + } + // Target if (race_manager->getCoinTarget() > 0) @@ -504,167 +568,12 @@ void RaceGUI::drawEnergyMeter(int x, int y, const AbstractKart *kart, float coin_target = (float)race_manager->getCoinTarget() / kart->getKartProperties()->getNitroMax(); - video::S3DVertex vertices[5]; - unsigned int count=2; + video::S3DVertex vertices[vertices_count]; - // There are three different polygons used, depending on - // the target. Consider the nitro-display texture: - // - // ----E-x--D (position of v,w,x vary depending on - // | nitro) - // A w - // | - // -B--v----C - // For nitro state <= r1 the triangle ABv is used, with v between B and C. - // For nitro state <= r2 the quad ABCw is used, with w between C and D. - // For nitro state > r2 the poly ABCDx is used, with x between D and E. - - vertices[0].TCoords = core::vector2df(0.3f, 0.4f); - vertices[0].Pos = core::vector3df(offset.X+0.3f*gauge_width, - offset.Y-(1-0.4f)*gauge_height, 0); - vertices[1].TCoords = core::vector2df(0, 1.0f); - vertices[1].Pos = core::vector3df(offset.X, offset.Y, 0); - // The targets at which different polygons must be used. - - const float r1 = 0.4f; - const float r2 = 0.65f; - if(coin_target<=r1) - { - count = 3; - float f = coin_target/r1; - vertices[2].TCoords = core::vector2df(0.08f + (1.0f-0.08f)*f, 1.0f); - vertices[2].Pos = core::vector3df(offset.X + (0.08f*gauge_width) - + (1.0f - 0.08f)*f*gauge_width, - offset.Y,0); - } - else if(coin_target<=r2) - { - count = 4; - float f = (coin_target - r1)/(r2-r1); - vertices[2].TCoords = core::vector2df(1.0f, 1.0f); - vertices[2].Pos = core::vector3df(offset.X + gauge_width, - offset.Y, 0); - vertices[3].TCoords = core::vector2df(1.0f, (1.0f-f)); - vertices[3].Pos = core::vector3df(offset.X + gauge_width, - offset.Y-f*gauge_height,0); - } - else - { - count = 5; - float f = (coin_target - r2)/(1-r2); - vertices[2].TCoords = core::vector2df(1.0, 1.0f); - vertices[2].Pos = core::vector3df(offset.X + gauge_width, - offset.Y, 0); - vertices[3].TCoords = core::vector2df(1.0,0); - vertices[3].Pos = core::vector3df(offset.X + gauge_width, - offset.Y-gauge_height, 0); - vertices[4].TCoords = core::vector2df(1.0f - f*(1-0.61f), 0); - vertices[4].Pos = core::vector3df(offset.X + gauge_width - - (1.0f-0.61f)*f*gauge_width, - offset.Y-gauge_height, 0); - } - short int index[5]={0}; - for(unsigned int i=0; igetVideoDriver()->setMaterial(m); - draw2DVertexPrimitiveList(m_gauge_goal, vertices, count, - index, count-2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN); - - } - - - - // Filling (current state) - - if(state <=0) return; //Nothing to do - - if (state > 0.0f) - { - video::S3DVertex vertices[5]; - unsigned int count=2; - - // There are three different polygons used, depending on - // the nitro state. Consider the nitro-display texture: - // - // ----E-x--D (position of v,w,x vary depending on - // | nitro) - // A w - // | - // -B--v----C - // For nitro state <= r1 the triangle ABv is used, with v between B and C. - // For nitro state <= r2 the quad ABCw is used, with w between C and D. - // For nitro state > r2 the poly ABCDx is used, with x between D and E. - - vertices[0].TCoords = core::vector2df(0.3f, 0.4f); - vertices[0].Pos = core::vector3df(offset.X+0.3f*gauge_width, - offset.Y-(1-0.4f)*gauge_height, 0); - vertices[1].TCoords = core::vector2df(0, 1.0f); - vertices[1].Pos = core::vector3df(offset.X, offset.Y, 0); - // The states at which different polygons must be used. - - const float r1 = 0.4f; - const float r2 = 0.65f; - if(state<=r1) - { - count = 3; - float f = state/r1; - vertices[2].TCoords = core::vector2df(0.08f + (1.0f-0.08f)*f, 1.0f); - vertices[2].Pos = core::vector3df(offset.X + (0.08f*gauge_width) - + (1.0f - 0.08f) - *f*gauge_width, - offset.Y,0); - } - else if(state<=r2) - { - count = 4; - float f = (state - r1)/(r2-r1); - vertices[2].TCoords = core::vector2df(1.0f, 1.0f); - vertices[2].Pos = core::vector3df(offset.X + gauge_width, - offset.Y, 0); - vertices[3].TCoords = core::vector2df(1.0f, (1.0f-f)); - vertices[3].Pos = core::vector3df(offset.X + gauge_width, - offset.Y-f*gauge_height,0); - } - else - { - count = 5; - float f = (state - r2)/(1-r2); - vertices[2].TCoords = core::vector2df(1.0, 1.0f); - vertices[2].Pos = core::vector3df(offset.X + gauge_width, - offset.Y, 0); - vertices[3].TCoords = core::vector2df(1.0,0); - vertices[3].Pos = core::vector3df(offset.X + gauge_width, - offset.Y-gauge_height, 0); - vertices[4].TCoords = core::vector2df(1.0f - f*(1-0.61f), 0); - vertices[4].Pos = - core::vector3df(offset.X + gauge_width - (1.0f-0.61f)*f*gauge_width, - offset.Y-gauge_height, 0); - } - short int index[5]={0}; - for(unsigned int i=0; igetControls().getNitro() || kart->isOnMinNitroTime()) - m.setTexture(0, m_gauge_full_bright); - else - m.setTexture(0, m_gauge_full); - m.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - irr_driver->getVideoDriver()->setMaterial(m); - draw2DVertexPrimitiveList(m.getTexture(0), vertices, count, - index, count-2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN); + unsigned int count = computeVerticesForMeter(position, threshold, vertices, vertices_count, + coin_target, gauge_width, gauge_height, offset); + drawMeterTexture(m_gauge_goal, vertices, count); } #endif } // drawEnergyMeter @@ -743,10 +652,10 @@ void RaceGUI::drawRank(const AbstractKart *kart, oss << rank; // the current font has no . :( << "."; core::recti pos; - pos.LowerRightCorner = core::vector2di(int(offset.X + 0.65f*meter_width), - int(offset.Y - 0.55f*meter_height)); - pos.UpperLeftCorner = core::vector2di(int(offset.X + 0.65f*meter_width), - int(offset.Y - 0.55f*meter_height)); + pos.LowerRightCorner = core::vector2di(int(offset.X + 0.64f*meter_width), + int(offset.Y - 0.49f*meter_height)); + pos.UpperLeftCorner = core::vector2di(int(offset.X + 0.64f*meter_width), + int(offset.Y - 0.49f*meter_height)); static video::SColor color = video::SColor(255, 255, 255, 255); font->draw(oss.str().c_str(), pos, color, true, true); @@ -803,78 +712,204 @@ void RaceGUI::drawSpeedEnergyRank(const AbstractKart* kart, // Draw the actual speed bar (if the speed is >0) // ---------------------------------------------- - float speed_ratio = speed/KILOMETERS_PER_HOUR/110.0f; + float speed_ratio = speed/40.0f; //max displayed speed of 40 if(speed_ratio>1) speed_ratio = 1; - video::S3DVertex vertices[5]; - unsigned int count; + // see computeVerticesForMeter for the detail of the drawing + // If increasing this, update drawMeterTexture - // There are three different polygons used, depending on - // the speed ratio. Consider the speed-display texture: - // - // D----x----D (position of v,w,x vary depending on - // | speed) - // w A - // | - // C--v-B----E - // For speed ratio <= r1 the triangle ABv is used, with v between B and C. - // For speed ratio <= r2 the quad ABCw is used, with w between C and D. - // For speed ratio > r2 the poly ABCDx is used, with x between D and E. + const int vertices_count = 12; + + video::S3DVertex vertices[vertices_count]; + + // The positions for A to J2 are defined here. + + // They are calculated from speedometer.png + // A is the center of the speedometer's circle + // B2, C, D, E, F, G, H, I and J1 are points on the line + // from A to their respective 1/8th threshold division + // B2 is 36,9° clockwise from the vertical (on bottom-left) + // J1 s 70,7° clockwise from the vertical (on upper-right) + // B1 and J2 are used for correct display of the 3D effect + // They are 1,13* further than the speedometer farther position because + // the lines between them would otherwise cut through the outside circle. + + core::vector2df position[vertices_count]; + + position[0].X = 0.546f;//A + position[0].Y = 0.566f;//A + position[1].X = 0.216f;//B1 + position[1].Y = 1.036f;//B1 + position[2].X = 0.201f;//B2 + position[2].Y = 1.023f;//B2 + position[3].X = 0.036f;//C + position[3].Y = 0.831f;//C + position[4].X = -0.029f;//D + position[4].Y = 0.589f;//D + position[5].X = 0.018f;//E + position[5].Y = 0.337f;//E + position[6].X = 0.169f;//F + position[6].Y = 0.134f;//F + position[7].X = 0.391f;//G + position[7].Y = 0.014f;//G + position[8].X = 0.642f;//H + position[8].Y = 0.0f;//H + position[9].X = 0.878f;//I + position[9].Y = 0.098f;//I + position[10].X = 1.046f;//J1 + position[10].Y = 0.285f;//J1 + position[11].X = 1.052f;//J2 + position[11].Y = 0.297f;//J2 - vertices[0].TCoords = core::vector2df(0.7f, 0.5f); - vertices[0].Pos = core::vector3df(offset.X+0.7f*meter_width, - offset.Y-0.5f*meter_height, 0); - vertices[1].TCoords = core::vector2df(0.52f, 1.0f); - vertices[1].Pos = core::vector3df(offset.X+0.52f*meter_width, offset.Y, 0); // The speed ratios at which different triangles must be used. - // These values should be adjusted in case that the speed display - // is not linear enough. Mostly the speed values are below 0.7, it - // needs some zipper to get closer to 1. - const float r1 = 0.2f; - const float r2 = 0.6f; - if(speed_ratio<=r1) + + float threshold[vertices_count-2]; + threshold[0] = 0.00001f;//for the 3D margin + threshold[1] = 0.125f; + threshold[2] = 0.25f; + threshold[3] = 0.375f; + threshold[4] = 0.50f; + threshold[5] = 0.625f; + threshold[6] = 0.750f; + threshold[7] = 0.875f; + threshold[8] = 0.99999f;//for the 3D margin + threshold[9] = 1.0f; + + //3D effect : wait for the full border to appear before drawing + for (int i=0;i<8;i++) { - count = 3; - float f = speed_ratio/r1; - vertices[2].TCoords = core::vector2df(0.52f*(1-f), 1.0f); - vertices[2].Pos = core::vector3df(offset.X+ (0.52f*(1.0f-f)*meter_width), - offset.Y,0); + if ((speed_ratio-0.125f*i < 0.00625f && speed_ratio-0.125f*i >= 0.0f) || (0.125f*i-speed_ratio < 0.0045f && 0.125f*i-speed_ratio >= 0.0f) ) + { + speed_ratio = 0.125f*i-0.0045f; + break; + } } - else if(speed_ratio<=r2) - { - count = 4; - float f = (speed_ratio - r1)/(r2-r1); - vertices[2].TCoords = core::vector2df(0, 1.0f); - vertices[2].Pos = core::vector3df(offset.X, offset.Y, 0); - vertices[3].TCoords = core::vector2df(0, (1-f)); - vertices[3].Pos = core::vector3df(offset.X, offset.Y-f*meter_height,0); - } - else - { - count = 5; - float f = (speed_ratio - r2)/(1-r2); - vertices[2].TCoords = core::vector2df(0, 1.0f); - vertices[2].Pos = core::vector3df(offset.X, offset.Y, 0); - vertices[3].TCoords = core::vector2df(0,0); - vertices[3].Pos = core::vector3df(offset.X, offset.Y-meter_height, 0); - vertices[4].TCoords = core::vector2df(f, 0); - vertices[4].Pos = core::vector3df(offset.X+f*meter_width, - offset.Y-meter_height, 0); - } - short int index[5]; + + unsigned int count = computeVerticesForMeter(position, threshold, vertices, vertices_count, + speed_ratio, meter_width, meter_height, offset); + + + drawMeterTexture(m_speed_bar_icon->getTexture(), vertices, count); +#endif +} // drawSpeedEnergyRank + +void RaceGUI::drawMeterTexture(video::ITexture *meter_texture, video::S3DVertex vertices[], unsigned int count) +{ +#ifndef SERVER_ONLY + //Should be greater or equal than the greatest vertices_count used by the meter functions + short int index[12]; for(unsigned int i=0; igetTexture()); + m.setTexture(0, meter_texture); m.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; irr_driver->getVideoDriver()->setMaterial(m); - draw2DVertexPrimitiveList(m_speed_bar_icon->getTexture(), vertices, count, + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + draw2DVertexPrimitiveList(m.getTexture(0), vertices, count, index, count-2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN); + glDisable(GL_BLEND); #endif -} // drawSpeedEnergyRank +} // drawMeterTexture + + + +//----------------------------------------------------------------------------- +/** This function computes a polygon used for drawing the measure for a meter (speedometer, etc.) + * The variable measured by the meter is compared to the thresholds, and is then used to + * compute a point between the two points associated with the lower and upper threshold + * Then, a polygon is calculated linking all the previous points and the variable point + * which link back to the first point. This polygon is used for drawing. + * + * Consider the following example : + * + * A E + * -| + * x + * | + * -D-| + * -w-| + * |-C--| + * -B--v-| + * + * If the measure is inferior to the first threshold, the function will create a triangle ABv + * with the position of v varying proportionally on a line between B and C ; + * at B with 0 and at C when it reaches the first threshold. + * If the measure is between the first and second thresholds, the function will create a quad ABCw, + * with w varying in the same way than v. + * If the measure exceds the higher threshold, the function will return the poly ABCDE. + * + * \param position The relative positions of the vertices. + * \param threshold The thresholds at which the variable point switch from a segment to the next. + * The size of this array should be smaller by two than the position array. + * The last threshold determines the measure over which the meter is full + * \param vertices Where the results of the computation are put, for use by the calling function. + * \param vertices_count The maximum number of vertices to use. Should be superior or equal to the + * size of the arrays. + * \param measure The value of the variable measured by the meter. + * \param gauge_width The width of the meter + * \param gauge_height The height of the meter + * \param offset The offset to position the meter + */ +unsigned int RaceGUI::computeVerticesForMeter(core::vector2df position[], float threshold[], video::S3DVertex vertices[], unsigned int vertices_count, + float measure, int gauge_width, int gauge_height, core::vector2df offset) +{ + //Nothing to draw ; we need at least three points to draw a triangle + if (vertices_count <= 2 || measure < 0) + { + return 0; + } + + unsigned int count=2; + float f = 1.0f; + + for (unsigned int i=2 ; i < vertices_count ; i++) + { + count++; + + //Stop when we have found between which thresholds the measure is + if (measure < threshold[i-2]) + { + if (i-2 == 0) + { + f = measure/threshold[i-2]; + } + else + { + f = (measure - threshold[i-3])/(threshold[i-2]-threshold[i-3]); + } + + break; + } + } + + for (unsigned int i=0 ; i < count ; i++) + { + //if the measure don't fall in this segment, use the next predefined point + if (idrawMultitouchSteering(kart, viewport, scaling); + m_multitouch_gui->draw(kart, viewport, scaling); } } // renderPlayerView @@ -770,7 +770,7 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin) { LinearWorld *linear_world = (LinearWorld*)(World::getWorld()); - float distance = linear_world->getDistanceDownTrackForKart(kart_id) + float distance = linear_world->getDistanceDownTrackForKart(kart_id, true) + Track::getCurrentTrack()->getTrackLength()*lap; if ((position>1) && (previous_distance-distancegetDeviceManager()->getMultitouchDevice(); @@ -63,7 +65,7 @@ RaceGUIMultitouch::RaceGUIMultitouch(RaceGUIBase* race_gui) UserConfigParams::m_multitouch_scale = 0.5f; } - initMultitouchSteering(); + init(); } // RaceGUIMultitouch @@ -72,7 +74,7 @@ RaceGUIMultitouch::RaceGUIMultitouch(RaceGUIBase* race_gui) */ RaceGUIMultitouch::~RaceGUIMultitouch() { - closeMultitouchSteering(); + close(); } // ~RaceGUIMultitouch @@ -91,23 +93,33 @@ void RaceGUIMultitouch::reset() //----------------------------------------------------------------------------- /** Clears all previously created buttons in the multitouch device */ -void RaceGUIMultitouch::closeMultitouchSteering() +void RaceGUIMultitouch::close() { if (m_device != NULL) { m_device->clearButtons(); } -} // closeMultitouchSteering + + if (m_device->isAccelerometerActive()) + { + m_device->deactivateAccelerometer(); + } +} // close //----------------------------------------------------------------------------- -/** Makes some initializations and determines the look of multitouch steering +/** Makes some initializations and determines the look of multitouch race GUI * interface */ -void RaceGUIMultitouch::initMultitouchSteering() +void RaceGUIMultitouch::init() { if (m_device == NULL) return; + + if (UserConfigParams::m_multitouch_controls == 2) + { + m_device->activateAccelerometer(); + } const float scale = UserConfigParams::m_multitouch_scale; @@ -138,10 +150,20 @@ void RaceGUIMultitouch::initMultitouchSteering() } m_minimap_bottom = (unsigned int)(h - 2 * col_size); + + if (m_device->isAccelerometerActive()) + { + m_device->addButton(BUTTON_UP_DOWN, + int(steering_btn_x + btn2_size / 4), int(steering_btn_y), + int(btn2_size / 2), int(btn2_size)); + } + else + { + m_device->addButton(BUTTON_STEERING, + int(steering_btn_x), int(steering_btn_y), + int(btn2_size), int(btn2_size)); + } - m_device->addButton(BUTTON_STEERING, - int(steering_btn_x), int(steering_btn_y), - int(btn2_size), int(btn2_size)); m_device->addButton(BUTTON_ESCAPE, int(margin_top), int(margin_small), int(btn_small_size), int(btn_small_size)); @@ -161,8 +183,10 @@ void RaceGUIMultitouch::initMultitouchSteering() int(first_column_x), int(h - 1 * col_size), int(btn_size), int(btn_size)); - m_directionnal_wheel_tex = irr_driver->getTexture(FileManager::GUI, - "android/directionnal_wheel.png"); + m_steering_wheel_tex = irr_driver->getTexture(FileManager::GUI, + "android/steering_wheel.png"); + m_up_down_tex = irr_driver->getTexture(FileManager::GUI, + "android/up_down.png"); m_pause_tex = irr_driver->getTexture(FileManager::GUI, "android/pause.png"); m_nitro_tex = irr_driver->getTexture(FileManager::GUI, "android/nitro.png"); m_nitro_empty_tex = irr_driver->getTexture(FileManager::GUI, @@ -178,17 +202,17 @@ void RaceGUIMultitouch::initMultitouchSteering() "android/blur_bg_button_focus.png"); m_gui_action_tex = irr_driver->getTexture(FileManager::GUI,"challenge.png"); -} // initMultitouchSteering +} // init //----------------------------------------------------------------------------- -/** Draws the buttons for multitouch steering. +/** Draws the buttons for multitouch race GUI. * \param kart The kart for which to show the data. * \param viewport The viewport to use. * \param scaling Which scaling to apply to the buttons. */ -void RaceGUIMultitouch::drawMultitouchSteering(const AbstractKart* kart, - const core::recti &viewport, - const core::vector2df &scaling) +void RaceGUIMultitouch::draw(const AbstractKart* kart, + const core::recti &viewport, + const core::vector2df &scaling) { #ifndef SERVER_ONLY if (m_device == NULL) @@ -210,7 +234,7 @@ void RaceGUIMultitouch::drawMultitouchSteering(const AbstractKart* kart, if (button->type == MultitouchButtonType::BUTTON_STEERING) { - video::ITexture* btn_texture = m_directionnal_wheel_tex; + video::ITexture* btn_texture = m_steering_wheel_tex; core::rect coords(pos_zero, btn_texture->getSize()); draw2DImage(btn_texture, btn_pos, coords, NULL, NULL, true); @@ -226,6 +250,12 @@ void RaceGUIMultitouch::drawMultitouchSteering(const AbstractKart* kart, // draw2DImage(btn_texture, pos2, coords, NULL, NULL, true); } + if (button->type == MultitouchButtonType::BUTTON_UP_DOWN) + { + video::ITexture* btn_texture = m_up_down_tex; + core::rect coords(pos_zero, btn_texture->getSize()); + draw2DImage(btn_texture, btn_pos, coords, NULL, NULL, true); + } else { bool can_be_pressed = true; @@ -297,10 +327,10 @@ void RaceGUIMultitouch::drawMultitouchSteering(const AbstractKart* kart, m_race_gui != NULL) { float scale = UserConfigParams::m_multitouch_scale * - (float)(irr_driver->getActualScreenSize().Height) / 720.0f; + (float)(irr_driver->getActualScreenSize().Height) / 760.0f; m_race_gui->drawEnergyMeter(int(button->x + button->width * 1.15f), - int(button->y + button->height * 1.35f), + int(button->y + button->height * 1.15f), kart, viewport, core::vector2df(scale, scale)); } @@ -321,4 +351,4 @@ void RaceGUIMultitouch::drawMultitouchSteering(const AbstractKart* kart, } } #endif -} // drawMultitouchSteering +} // draw diff --git a/src/states_screens/race_gui_multitouch.hpp b/src/states_screens/race_gui_multitouch.hpp index c691ca078..cbc593942 100644 --- a/src/states_screens/race_gui_multitouch.hpp +++ b/src/states_screens/race_gui_multitouch.hpp @@ -38,7 +38,8 @@ private: bool m_gui_action; unsigned int m_minimap_bottom; - video::ITexture* m_directionnal_wheel_tex; + video::ITexture* m_steering_wheel_tex; + video::ITexture* m_up_down_tex; video::ITexture* m_pause_tex; video::ITexture* m_nitro_tex; video::ITexture* m_nitro_empty_tex; @@ -49,16 +50,15 @@ private: video::ITexture* m_bg_button_focus_tex; video::ITexture* m_gui_action_tex; - void initMultitouchSteering(); - void closeMultitouchSteering(); + void init(); + void close(); public: RaceGUIMultitouch(RaceGUIBase* race_gui); ~RaceGUIMultitouch(); - void drawMultitouchSteering(const AbstractKart* kart, - const core::recti &viewport, - const core::vector2df &scaling); + void draw(const AbstractKart* kart, const core::recti &viewport, + const core::vector2df &scaling); unsigned int getMinimapBottom() {return m_minimap_bottom;} void setGuiAction(bool enabled = true) {m_gui_action = enabled;} diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 945513cb7..b54f80a93 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -379,17 +379,25 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, return; } - // This is a normal race, nothing was unlocked - // ------------------------------------------- StateManager::get()->popMenu(); if (name == "top") // Setup new race { race_manager->exitRace(); race_manager->setAIKartOverride(""); - Screen* newStack[] = { MainMenuScreen::getInstance(), - RaceSetupScreen::getInstance(), - NULL }; - StateManager::get()->resetAndSetStack(newStack); + + //If pressing continue quickly in a losing challenge + if (race_manager->raceWasStartedFromOverworld()) + { + StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); + OverWorld::enterOverWorld(); + } + else + { + Screen* newStack[] = { MainMenuScreen::getInstance(), + RaceSetupScreen::getInstance(), + NULL }; + StateManager::get()->resetAndSetStack(newStack); + } } else if (name == "middle") // Restart { diff --git a/src/tracks/check_lap.cpp b/src/tracks/check_lap.cpp index ee0f8ce8a..e7274c8d9 100644 --- a/src/tracks/check_lap.cpp +++ b/src/tracks/check_lap.cpp @@ -69,7 +69,7 @@ bool CheckLap::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, // has check defined. if(!lin_world) return false; - float current_distance = lin_world->getDistanceDownTrackForKart(kart_index); + float current_distance = lin_world->getDistanceDownTrackForKart(kart_index, false); bool result = (m_previous_distance[kart_index]>0.95f*track_length && current_distance<7.0f); diff --git a/src/tracks/quad.cpp b/src/tracks/quad.cpp index e0dc115e4..71b8defd1 100644 --- a/src/tracks/quad.cpp +++ b/src/tracks/quad.cpp @@ -42,6 +42,20 @@ Quad::Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, m_max_height_testing = Graph::MAX_HEIGHT_TESTING; } // Quad +/** Takes 4 points. */ +void Quad::setQuad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3) +{ + m_p[0]=p0; m_p[1]=p1; m_p[2]=p2; m_p[3]=p3; + + m_center = 0.25f*(p0+p1+p2+p3); + m_min_height = std::min ( std::min(p0.getY(), p1.getY()), + std::min(p2.getY(), p3.getY()) ); + m_max_height = std::max ( std::max(p0.getY(), p1.getY()), + std::max(p2.getY(), p3.getY()) ); + m_min_height_testing = Graph::MIN_HEIGHT_TESTING; + m_max_height_testing = Graph::MAX_HEIGHT_TESTING; +} // setQuad + // ---------------------------------------------------------------------------- /** Sets the vertices in a irrlicht vertex array to the 4 points of this quad. * \param v The vertex array in which to set the vertices. diff --git a/src/tracks/quad.hpp b/src/tracks/quad.hpp index b33d637f9..c346c7949 100644 --- a/src/tracks/quad.hpp +++ b/src/tracks/quad.hpp @@ -84,6 +84,9 @@ public: /** Returns the center of a quad. */ const Vec3& getCenter () const { return m_center; } // ------------------------------------------------------------------------ + /** Set new quad coordinates. */ + void setQuad (const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3); + // ------------------------------------------------------------------------ void setHeightTesting(float min, float max) { m_min_height_testing = min; diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 6fca0871a..c33288a6f 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -1521,7 +1521,22 @@ void Track::handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml) } // handleAnimatedTextures // ---------------------------------------------------------------------------- -/** Update, called once per frame. +/** This updates all only graphical elements. It is only called once per + * rendered frame, not once per time step. + * float dt Time since last rame. + */ +void Track::updateGraphics(float dt) +{ + m_track_object_manager->updateGraphics(dt); + + for (unsigned int i = 0; iupdate(dt); + } +} // updateGraphics + +// ---------------------------------------------------------------------------- +/** Update, called once per physics time step. * \param dt Timestep. */ void Track::update(int ticks) @@ -1533,11 +1548,6 @@ void Track::update(int ticks) } float dt = stk_config->ticks2Time(ticks); m_track_object_manager->update(dt); - - for(unsigned int i=0; iupdate(dt); - } CheckManager::get()->update(dt); ItemManager::get()->update(ticks); diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index 8bcecec5e..fa2bc0b8d 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -421,6 +421,7 @@ public: void startMusic () const; void createPhysicsModel(unsigned int main_track_count); + void updateGraphics(float dt); void update(int ticks); void reset(); void itemCommand(const XMLNode *node); diff --git a/src/tracks/track_object.cpp b/src/tracks/track_object.cpp index 650fe4521..9169392c1 100644 --- a/src/tracks/track_object.cpp +++ b/src/tracks/track_object.cpp @@ -521,10 +521,28 @@ void TrackObject::resetEnabled() { m_movable_children[i]->resetEnabled(); } -} +} // resetEnabled // ---------------------------------------------------------------------------- +/** This updates all only graphical elements. It is only called once per + * rendered frame, not once per time step. + * float dt Time since last rame. + */ +void TrackObject::updateGraphics(float dt) +{ + // FIXME: At this stage neither m_presentation nor m_animator + // have been converted to use separate updateGraphics() calls. + + if (m_physical_object) m_physical_object->updateGraphics(dt); + +} // update + +// ---------------------------------------------------------------------------- +/** This updates all only graphical elements. It is only called once per + * rendered frame, not once per time step. + * float dt Time since last rame. + */ void TrackObject::update(float dt) { if (m_presentation) m_presentation->update(dt); @@ -534,7 +552,6 @@ void TrackObject::update(float dt) if (m_animator) m_animator->update(dt); } // update - // ---------------------------------------------------------------------------- /** Does a raycast against the track object. The object must have a physical * object. @@ -580,7 +597,8 @@ void TrackObject::move(const core::vector3df& xyz, const core::vector3df& hpr, // ---------------------------------------------------------------------------- -void TrackObject::movePhysicalBodyToGraphicalNode(const core::vector3df& xyz, const core::vector3df& hpr) +void TrackObject::movePhysicalBodyToGraphicalNode(const core::vector3df& xyz, + const core::vector3df& hpr) { // If we set a bullet position from an irrlicht position, we need to // get the absolute transform from the presentation object (as set in @@ -598,7 +616,7 @@ void TrackObject::movePhysicalBodyToGraphicalNode(const core::vector3df& xyz, co { m_physical_object->move(xyz, hpr); } -} +} // movePhysicalBodyToGraphicalNode // ---------------------------------------------------------------------------- const core::vector3df& TrackObject::getPosition() const @@ -619,7 +637,6 @@ const core::vector3df TrackObject::getAbsoluteCenterPosition() const return m_init_xyz; } // getAbsolutePosition - // ---------------------------------------------------------------------------- const core::vector3df TrackObject::getAbsolutePosition() const diff --git a/src/tracks/track_object.hpp b/src/tracks/track_object.hpp index 6b7496f9e..04e1e17cd 100644 --- a/src/tracks/track_object.hpp +++ b/src/tracks/track_object.hpp @@ -119,6 +119,7 @@ public: const PhysicalObject::Settings* physicsSettings); virtual ~TrackObject(); virtual void update(float dt); + virtual void updateGraphics(float dt); void move(const core::vector3df& xyz, const core::vector3df& hpr, const core::vector3df& scale, bool updateRigidBody, bool isAbsoluteCoord); diff --git a/src/tracks/track_object_manager.cpp b/src/tracks/track_object_manager.cpp index ba8934b25..89a7a5032 100644 --- a/src/tracks/track_object_manager.cpp +++ b/src/tracks/track_object_manager.cpp @@ -137,6 +137,19 @@ void TrackObjectManager::handleExplosion(const Vec3 &pos, const PhysicalObject * } } // handleExplosion +// ---------------------------------------------------------------------------- +/** Updates all track objects. + * \param dt Time step size. + */ +void TrackObjectManager::updateGraphics(float dt) +{ + TrackObject* curr; + for_in(curr, m_all_objects) + { + curr->updateGraphics(dt); + } +} // updateGraphics + // ---------------------------------------------------------------------------- /** Updates all track objects. * \param dt Time step size. diff --git a/src/tracks/track_object_manager.hpp b/src/tracks/track_object_manager.hpp index d66a629cf..979401057 100644 --- a/src/tracks/track_object_manager.hpp +++ b/src/tracks/track_object_manager.hpp @@ -59,6 +59,7 @@ public: void add(const XMLNode &xml_node, scene::ISceneNode* parent, ModelDefinitionLoader& model_def_loader, TrackObject* parent_library); + void updateGraphics(float dt); void update(float dt); void handleExplosion(const Vec3 &pos, const PhysicalObject *mp, bool secondary_hits=true); diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index efe9731a8..c6c8ae32b 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -38,6 +38,7 @@ #include "input/input_manager.hpp" #include "items/item_manager.hpp" #include "karts/abstract_kart.hpp" +#include "modes/profile_world.hpp" #include "modes/world.hpp" #include "scriptengine/script_engine.hpp" #include "states_screens/dialogs/tutorial_message_dialog.hpp" @@ -817,6 +818,8 @@ TrackObjectPresentationBillboard::TrackObjectPresentationBillboard( // ---------------------------------------------------------------------------- void TrackObjectPresentationBillboard::update(float dt) { + if (ProfileWorld::isNoGraphics()) return; +#ifndef SERVER_ONLY if (m_fade_out_when_close) { scene::ICameraSceneNode* curr_cam = irr_driver->getSceneManager() @@ -841,6 +844,7 @@ void TrackObjectPresentationBillboard::update(float dt) node->setColor(video::SColor(a, 255, 255, 255)); } } // m_fade_out_when_close +#endif } // update // ---------------------------------------------------------------------------- diff --git a/src/tracks/track_sector.cpp b/src/tracks/track_sector.cpp index d42e82d89..b57fe5fb5 100644 --- a/src/tracks/track_sector.cpp +++ b/src/tracks/track_sector.cpp @@ -68,48 +68,55 @@ void TrackSector::update(const Vec3 &xyz, bool ignore_vertical) // If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of // the road, so we have to use search for the closest graph node. - if(m_current_graph_node == Graph::UNKNOWN_SECTOR) + if (m_current_graph_node == Graph::UNKNOWN_SECTOR) { m_current_graph_node = Graph::get()->findOutOfRoadSector(xyz, prev_sector, test_nodes, ignore_vertical); - // ArenaGraph (battle and soccer mode) doesn't need the code below - if (ag) return; + } + + // ArenaGraph (battle and soccer mode) doesn't need the code below + if (ag) return; + + // keep the current quad as the latest valid one IF the player has one + // of the required checklines + const DriveNode* dn = DriveGraph::get()->getNode(m_current_graph_node); + const std::vector& checkline_requirements = dn->getChecklineRequirements(); + + bool isValidQuad = false; + if (checkline_requirements.size() == 0) + { + isValidQuad = true; + if (m_on_road) + m_last_valid_graph_node = m_current_graph_node; } else { - if (ag) return; - // keep the current quad as the latest valid one IF the player has one - // of the required checklines - const DriveNode* dn = DriveGraph::get()->getNode(m_current_graph_node); - const std::vector& checkline_requirements = dn->getChecklineRequirements(); - - if (checkline_requirements.size() == 0) + for (unsigned int i=0; ispatialToTrack(&m_current_track_coords, xyz, - m_current_graph_node); + m_current_graph_node); + + if (m_last_valid_graph_node != Graph::UNKNOWN_SECTOR) + { + DriveGraph::get()->spatialToTrack(&m_latest_valid_track_coords, xyz, + m_last_valid_graph_node); + } } // update // ---------------------------------------------------------------------------- diff --git a/src/tracks/track_sector.hpp b/src/tracks/track_sector.hpp index f10716dd0..08e60ef32 100644 --- a/src/tracks/track_sector.hpp +++ b/src/tracks/track_sector.hpp @@ -48,6 +48,8 @@ private: * of the center driveline. */ Vec3 m_current_track_coords; + Vec3 m_latest_valid_track_coords; + /** True if the object is on the road (driveline), or not. */ bool m_on_road; @@ -61,7 +63,13 @@ public: float getRelativeDistanceToCenter() const; // ------------------------------------------------------------------------ /** Returns how far the the object is from the start line. */ - float getDistanceFromStart() const { return m_current_track_coords.getZ();} + float getDistanceFromStart(bool account_for_checklines) const + { + if (account_for_checklines) + return m_latest_valid_track_coords.getZ(); + else + return m_current_track_coords.getZ(); + } // ------------------------------------------------------------------------ /** Returns the distance to the centre driveline. */ float getDistanceToCenter() const { return m_current_track_coords.getX(); } diff --git a/src/utils/constants.cpp b/src/utils/constants.cpp index 34e4e12d4..3f623ad3c 100644 --- a/src/utils/constants.cpp +++ b/src/utils/constants.cpp @@ -29,4 +29,5 @@ static const char* endianness_test_ptr = (const char*)&endianness_test; // in little-endian, byte 0 will be 0. in big endian, byte 0 will be 1 const bool IS_LITTLE_ENDIAN = (endianness_test_ptr[0] == 0); -const char STK_VERSION[] = "git"; +// "SUPERTUXKART_VERSION" is defined from CMakeLists.txt from the project version +const char STK_VERSION[] = SUPERTUXKART_VERSION; diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index a8aed45d4..94c578fe8 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -246,7 +246,12 @@ LightNode* findNearestLight() bool handleContextMenuAction(s32 cmd_id) { - unsigned int kart_num = Camera::getActiveCamera()->getKart()->getWorldKartId(); + Camera* camera = Camera::getActiveCamera(); + unsigned int kart_num = 0; + if (camera != NULL && camera->getKart() != NULL) + { + kart_num = camera->getKart()->getWorldKartId(); + } World *world = World::getWorld(); Physics *physics = Physics::getInstance(); @@ -550,21 +555,25 @@ bool handleContextMenuAction(s32 cmd_id) case DEBUG_GUI_CAM_TOP: CameraDebug::setDebugType(CameraDebug::CM_DEBUG_TOP_OF_KART); Camera::changeCamera(0, Camera::CM_TYPE_DEBUG); + Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num)); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; case DEBUG_GUI_CAM_WHEEL: CameraDebug::setDebugType(CameraDebug::CM_DEBUG_GROUND); Camera::changeCamera(0, Camera::CM_TYPE_DEBUG); + Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num)); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; case DEBUG_GUI_CAM_BEHIND_KART: CameraDebug::setDebugType(CameraDebug::CM_DEBUG_BEHIND_KART); Camera::changeCamera(0, Camera::CM_TYPE_DEBUG); + Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num)); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; case DEBUG_GUI_CAM_SIDE_OF_KART: CameraDebug::setDebugType(CameraDebug::CM_DEBUG_SIDE_OF_KART); Camera::changeCamera(0, Camera::CM_TYPE_DEBUG); + Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num)); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; case DEBUG_GUI_CAM_FREE: @@ -585,6 +594,7 @@ bool handleContextMenuAction(s32 cmd_id) { Camera *camera = Camera::getActiveCamera(); Camera::changeCamera(camera->getIndex(), Camera::CM_TYPE_NORMAL); + Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num)); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; } diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index 8a801e19d..62cddd1b7 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -788,6 +788,23 @@ namespace StringUtils return version; } // versionToInt + // ------------------------------------------------------------------------ + /** Searches for text in a string and replaces it with the desired text */ + std::string findAndReplace(const std::string& source, const std::string& find, const std::string& replace) + { + std::string destination = source; + std::string::size_type found_position = 0; + + // Replace until we can't find anymore the find string + while ((found_position = destination.find(find, found_position)) != std::string::npos) + { + destination.replace(found_position, find.length(), replace); + // Advanced pass the replaced string + found_position += replace.length(); + } + return destination; + } //findAndReplace + } // namespace StringUtils diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 4f93a6a44..f8842258b 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -231,6 +231,7 @@ namespace StringUtils irr::core::stringw utf8ToWide(const std::string &input); std::string wideToUtf8(const wchar_t* input); std::string wideToUtf8(const irr::core::stringw& input); + std::string findAndReplace(const std::string& source, const std::string& find, const std::string& replace); } // namespace StringUtils diff --git a/tools/ai_test/test_track.sh b/tools/ai_test/test_track.sh index 06937c880..9f65e6dd6 100755 --- a/tools/ai_test/test_track.sh +++ b/tools/ai_test/test_track.sh @@ -3,7 +3,7 @@ for track in abyss candela_city cocoa_temple cornfield_crossing fortmagma gran_paradiso_island greenvalley hacienda lighthouse mansion mines minigolf olivermath sandtrack scotland snowmountain snowtuxpeak stk_enterprise volcano_island xr591 zengarden; do echo "Testing $track" $1 --log=0 -R \ - --ai=nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok \ - --track=$track --difficulty=2 --type=1 --test-ai=2 \ + --aiNP=nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok \ + --track=$track --difficulty=3 --type=1 --test-ai=2 \ --profile-laps=10 --no-graphics > stdout.$track done diff --git a/tools/create_kart_properties.py b/tools/create_kart_properties.py index 307078fff..a40ccd2a1 100755 --- a/tools/create_kart_properties.py +++ b/tools/create_kart_properties.py @@ -48,7 +48,7 @@ Startup: time(std::vector/floatVector), boost(std::vector/floatVec Rescue: duration, vertOffset, height Explosion: duration, radius, invulnerabilityTime Nitro: duration, engineForce, consumption, smallContainer, bigContainer, maxSpeedIncrease, fadeOutTime, max -Slipstream: duration, length, width, collectTime, useTime, addPower, minSpeed, maxSpeedIncrease, fadeOutTime +Slipstream: durationFactor, baseSpeed, length, width, innerFactor, minCollectTime, maxCollectTime, addPower, minSpeed, maxSpeedIncrease, fadeOutTime Skid: increase, decrease, max, timeTillMax, visual, visualTime, revertVisualTime, minSpeed, timeTillBonus(std::vector/floatVector), bonusSpeed(std::vector/floatVector), bonusTime(std::vector/floatVector), bonusForce(std::vector/floatVector), physicalJumpTime, graphicalJumpTime, postSkidRotateFactor, reduceTurnMin, reduceTurnMax, enabled(bool)""" """ A GroupMember is an attribute of a group. @@ -283,4 +283,3 @@ Operations:""") if __name__ == '__main__': main() -