diff --git a/.gitignore b/.gitignore index 6a4a4c428d6..057e8029cb3 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ android/bin android/build android/libs android/obj +android/res android/.gradle android-* *.apk diff --git a/android/README.ANDROID b/android/README.ANDROID index 689d0992821..4dda169857d 100644 --- a/android/README.ANDROID +++ b/android/README.ANDROID @@ -143,38 +143,3 @@ you have to run: and then: zipalign -v 4 SuperTuxKart-release-unsigned.apk SuperTuxKart-release.apk - - - --------------------------------------------------------------------------------- - KNOWN ISSUES --------------------------------------------------------------------------------- - -1. It's not possible to compile STK for Android < 4.4 due to missing GLES 3.0 - functions. It is technically possible to do - check GLES context version, - load OpenGL functions dynamically using EGL, and if they are not loaded - properly, then fallback to GLES 2.0. - -2. It never ocurred for me, but it's possible that EGL context is lost in some - cases. SuperTuxKart is not designed to re-create all textures at any moment, - so this is a "Wontfix", at least for now. - -3. We use "exit(0)" at the end of main function. We shouldn't do it and we - should just return from the main function. But STK uses some global - variables and their values are remembered when the game is restarted. We - should properly clear them or re-initialize on startup. Using the "exit(0)" - is not-that-bad workaround, but it may cause a crash on exit sometimes. - It seems to affect only Android 5.0. More information about the crash: - https://code.google.com/p/android/issues/detail?id=160824 - -4. STK crashes on startup on some devices when aarch64 build is made using - Android r13 NDK. The r13 version has rather big modifications (it uses clang - instead of gcc by default). This is probably a bug in NDK/compiler/OS, but - for this reason using NDK r12 for 64-bit arm compilation is preferred. - -5. Angelscript doesn't have full support for aarch64 builds, so that scripting - won't work on this platform. - -6. Turning left/right using accelerometer is available, but at this stage the - default screen orientation is not automatically detected and user must - manually choose if he needs "phone" or "tablet" accelerometer. diff --git a/android/icon-dbg.png b/android/icon-dbg.png new file mode 100644 index 00000000000..cc9799a64a1 Binary files /dev/null and b/android/icon-dbg.png differ diff --git a/android/res/drawable/icon.png b/android/icon.png similarity index 100% rename from android/res/drawable/icon.png rename to android/icon.png diff --git a/android/make.sh b/android/make.sh index 95a905d3dbe..7fac9f3c69e 100755 --- a/android/make.sh +++ b/android/make.sh @@ -36,6 +36,13 @@ export HOST_AARCH64=aarch64-linux-android export NDK_PLATFORM_AARCH64=android-21 export SDK_VERSION_AARCH64=21 +export APP_NAME_RELEASE="SuperTuxKart" +export APP_NAME_DEBUG="SuperTuxKart Debug" +export PACKAGE_NAME_RELEASE="org.supertuxkart.stk" +export PACKAGE_NAME_DEBUG="org.supertuxkart.stk_dev" +export APP_ICON_RELEASE="$DIRNAME/icon.png" +export APP_ICON_DEBUG="$DIRNAME/icon-dbg.png" + # A helper function that checks if error ocurred check_error() @@ -52,6 +59,7 @@ if [ ! -z "$1" ] && [ "$1" = "clean" ]; then rm -rf build rm -rf libs rm -rf obj + rm -rf res rm -rf .gradle exit fi @@ -108,10 +116,16 @@ if [ "$BUILD_TYPE" = "debug" ] || [ "$BUILD_TYPE" = "Debug" ]; then export ANT_BUILD_TYPE="debug" export GRADLE_BUILD_TYPE="assembleDebug" export IS_DEBUG_BUILD=1 + export APP_NAME="$APP_NAME_DEBUG" + export PACKAGE_NAME="$PACKAGE_NAME_DEBUG" + export APP_ICON="$APP_ICON_DEBUG" elif [ "$BUILD_TYPE" = "release" ] || [ "$BUILD_TYPE" = "Release" ]; then export ANT_BUILD_TYPE="release" export GRADLE_BUILD_TYPE="assembleRelease" export IS_DEBUG_BUILD=0 + export APP_NAME="$APP_NAME_RELEASE" + export PACKAGE_NAME="$PACKAGE_NAME_RELEASE" + export APP_ICON="$APP_ICON_RELEASE" else echo "Unsupported BUILD_TYPE: $BUILD_TYPE. Possible values are: " \ "debug, release" @@ -342,8 +356,31 @@ check_error # Build apk echo "Building APK" +mkdir -p "$DIRNAME/res/drawable/" +mkdir -p "$DIRNAME/res/drawable-hdpi/" +mkdir -p "$DIRNAME/res/drawable-mdpi/" +mkdir -p "$DIRNAME/res/drawable-xhdpi/" +mkdir -p "$DIRNAME/res/drawable-xxhdpi/" +mkdir -p "$DIRNAME/res/values/" + +STRINGS_FILE="$DIRNAME/res/values/strings.xml" + +echo "" > "$STRINGS_FILE" +echo "" >> "$STRINGS_FILE" +echo " $APP_NAME" >> "$STRINGS_FILE" +echo "" >> "$STRINGS_FILE" + sed -i "s/minSdkVersion=\".*\"/minSdkVersion=\"$SDK_VERSION\"/g" \ "$DIRNAME/AndroidManifest.xml" + +sed -i "s/package=\".*\"/package=\"$PACKAGE_NAME\"/g" \ + "$DIRNAME/AndroidManifest.xml" + +cp "$APP_ICON" "$DIRNAME/res/drawable/icon.png" +convert -scale 72x72 "$APP_ICON" "$DIRNAME/res/drawable-hdpi/icon.png" +convert -scale 48x48 "$APP_ICON" "$DIRNAME/res/drawable-mdpi/icon.png" +convert -scale 96x96 "$APP_ICON" "$DIRNAME/res/drawable-xhdpi/icon.png" +convert -scale 144x144 "$APP_ICON" "$DIRNAME/res/drawable-xxhdpi/icon.png" if [ "$BUILD_TOOL" = "gradle" ]; then diff --git a/android/res/drawable-hdpi/icon.png b/android/res/drawable-hdpi/icon.png deleted file mode 100644 index 33de3e8038e..00000000000 Binary files a/android/res/drawable-hdpi/icon.png and /dev/null differ diff --git a/android/res/drawable-mdpi/icon.png b/android/res/drawable-mdpi/icon.png deleted file mode 100644 index 0a8f484e6bf..00000000000 Binary files a/android/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/android/res/drawable-xhdpi/icon.png b/android/res/drawable-xhdpi/icon.png deleted file mode 100644 index 6f4383226af..00000000000 Binary files a/android/res/drawable-xhdpi/icon.png and /dev/null differ diff --git a/android/res/drawable-xxhdpi/icon.png b/android/res/drawable-xxhdpi/icon.png deleted file mode 100644 index 7bbbc461b34..00000000000 Binary files a/android/res/drawable-xxhdpi/icon.png and /dev/null differ diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml deleted file mode 100644 index 931a3c2c9c4..00000000000 --- a/android/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - SuperTuxKart - diff --git a/data/gui/online/lan.stkgui b/data/gui/online/lan.stkgui new file mode 100644 index 00000000000..c94e6082a01 --- /dev/null +++ b/data/gui/online/lan.stkgui @@ -0,0 +1,29 @@ + + + + +
+
+ + +
+
diff --git a/data/gui/online/online.stkgui b/data/gui/online/online.stkgui new file mode 100644 index 00000000000..3572916bc52 --- /dev/null +++ b/data/gui/online/online.stkgui @@ -0,0 +1,29 @@ + + +
+
+ +
+ + +
diff --git a/data/gui/online/profile_achievements_tab.stkgui b/data/gui/online/profile_achievements_tab.stkgui index dbf3256b503..7d519d6612c 100644 --- a/data/gui/online/profile_achievements_tab.stkgui +++ b/data/gui/online/profile_achievements_tab.stkgui @@ -9,7 +9,6 @@ - diff --git a/data/gui/online/profile_friends.stkgui b/data/gui/online/profile_friends.stkgui index 0e1213c61e6..e0e49473b41 100644 --- a/data/gui/online/profile_friends.stkgui +++ b/data/gui/online/profile_friends.stkgui @@ -9,7 +9,6 @@ - diff --git a/data/gui/online/profile_servers.stkgui b/data/gui/online/profile_servers.stkgui index 25ca99ffaa8..88de78d8c05 100644 --- a/data/gui/online/profile_servers.stkgui +++ b/data/gui/online/profile_servers.stkgui @@ -3,59 +3,25 @@
-
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
-
+
+ + +
diff --git a/data/gui/online/profile_settings.stkgui b/data/gui/online/profile_settings.stkgui index 126519d9f1e..d89d52c23a1 100644 --- a/data/gui/online/profile_settings.stkgui +++ b/data/gui/online/profile_settings.stkgui @@ -8,7 +8,6 @@ - BoundingBox; - f32 AnimationFrames; f32 FramesPerSecond; f32 LastAnimatedFrame; diff --git a/sources.cmake b/sources.cmake index d4f28ae4de4..13db008ff50 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/challenges/challenge_data.cpp b/src/challenges/challenge_data.cpp index 994a243dd57..b0c8efd15b0 100644 --- a/src/challenges/challenge_data.cpp +++ b/src/challenges/challenge_data.cpp @@ -47,7 +47,7 @@ ChallengeData::ChallengeData(const std::string& filename) for (int d=0; dget("number", &num_karts)) error("karts"); - m_num_karts[d] = num_karts; + m_default_num_karts[d] = num_karts; std::string replay_file; if (karts_node->get("replay_file", &replay_file)) @@ -385,7 +385,7 @@ void ChallengeData::setRace(RaceManager::Difficulty d) const race_manager->setMinorMode(m_minor); race_manager->setTrack(m_track_id); race_manager->setNumLaps(m_num_laps); - race_manager->setNumKarts(m_num_karts[d]); + race_manager->setNumKarts(m_default_num_karts[d]); race_manager->setNumPlayers(1); race_manager->setCoinTarget(m_energy[d]); race_manager->setDifficulty(d); @@ -404,7 +404,7 @@ void ChallengeData::setRace(RaceManager::Difficulty d) const race_manager->setMinorMode(m_minor); race_manager->setGrandPrix(*grand_prix_manager->getGrandPrix(m_gp_id)); race_manager->setDifficulty(d); - race_manager->setNumKarts(m_num_karts[d]); + race_manager->setNumKarts(m_default_num_karts[d]); race_manager->setNumPlayers(1); } @@ -448,7 +448,7 @@ bool ChallengeData::isChallengeFulfilled() const if (kart->isEliminated() ) return false; if (track_name != m_track_id ) return false; - if ((int)world->getNumKarts() < m_num_karts[d] ) return false; + if ((int)world->getNumKarts() < m_default_num_karts[d] ) return false; if (m_energy[d] > 0 && kart->getEnergy() < m_energy[d] ) return false; if (m_position[d] > 0 && kart->getPosition() > m_position[d]) return false; @@ -495,7 +495,7 @@ bool ChallengeData::isGPFulfilled() const if (race_manager->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX || race_manager->getMinorMode() != m_minor || race_manager->getGrandPrix().getId() != m_gp_id || - race_manager->getNumberOfKarts() < (unsigned int)m_num_karts[d] || + race_manager->getNumberOfKarts() < (unsigned int)m_default_num_karts[d] || race_manager->getNumPlayers() > 1) return false; // check if the player came first. diff --git a/src/challenges/challenge_data.hpp b/src/challenges/challenge_data.hpp index 0cebc45568f..6e45f23c24d 100644 --- a/src/challenges/challenge_data.hpp +++ b/src/challenges/challenge_data.hpp @@ -84,7 +84,7 @@ class ChallengeData int m_num_laps; int m_position[RaceManager::DIFFICULTY_COUNT]; - int m_num_karts[RaceManager::DIFFICULTY_COUNT]; + int m_default_num_karts[RaceManager::DIFFICULTY_COUNT]; std::string m_ai_kart_ident[RaceManager::DIFFICULTY_COUNT]; std::string m_replay_files[RaceManager::DIFFICULTY_COUNT]; float m_time[RaceManager::DIFFICULTY_COUNT]; @@ -208,7 +208,7 @@ class ChallengeData */ int getNumKarts(RaceManager::Difficulty difficulty) const { - return m_num_karts[difficulty]; + return m_default_num_karts[difficulty]; } // getNumKarts // ------------------------------------------------------------------------ /** Returns the maximum time in which the kart must finish. diff --git a/src/config/user_config.cpp b/src/config/user_config.cpp index c4aa910ab59..788efc0dceb 100644 --- a/src/config/user_config.cpp +++ b/src/config/user_config.cpp @@ -321,9 +321,129 @@ core::stringc ListUserConfigParam::toString() const return ""; } // toString +// ---------------------------------------------------------------------------- +template +MapUserConfigParam::MapUserConfigParam(const char* param_name, + const char* comment) +{ + m_param_name = param_name; + all_params.push_back(this); + if (comment != NULL) m_comment = comment; +} // MapUserConfigParam + +// ---------------------------------------------------------------------------- +template +MapUserConfigParam::MapUserConfigParam(const char* param_name, + const char* comment, + int nb_elements, + ...) +{ + m_param_name = param_name; + all_params.push_back(this); + if (comment != NULL) m_comment = comment; + // add the default list + va_list arguments; + va_start(arguments, nb_elements); -// ============================================================================ + struct pair_type { T key; U value; }; + + for (int i = 0; i < nb_elements; i++) + { + pair_type key_value_pair = va_arg(arguments, pair_type); + m_elements.insert(std::pair(key_value_pair.key, key_value_pair.value)); + } + va_end(arguments); // Cleans up the list +} // MapUserConfigParam + +// ---------------------------------------------------------------------------- +template +MapUserConfigParam::MapUserConfigParam(const char* param_name, + GroupUserConfigParam* group, + const char* comment) +{ + m_param_name = param_name; + group->addChild(this); + if (comment != NULL) m_comment = comment; +} // MapUserConfigParam + +// ---------------------------------------------------------------------------- +template +MapUserConfigParam::MapUserConfigParam(const char* param_name, + GroupUserConfigParam* group, + const char* comment, + int nb_elements, + ...) +{ + m_param_name = param_name; + group->addChild(this); + if (comment != NULL) m_comment = comment; + + // add the default list + va_list arguments; + va_start(arguments, nb_elements); + + struct pair_type { T key; U value; }; + + for (int i = 0; i < nb_elements; i++) + { + pair_type key_value_pair = va_arg(arguments, pair_type); + m_elements.insert(std::pair(key_value_pair.key, key_value_pair.value)); + } + va_end(arguments); // Cleans up the list +} // MapUserConfigParam + +// ---------------------------------------------------------------------------- +template +void MapUserConfigParam::write(std::ofstream& stream) const +{ + // comment + if (m_comment.size() > 0) stream << " \n <" << m_param_name.c_str() << "\n"; + + for (const auto& kv : m_elements) + { + stream << " " << kv.first << "=\"" << kv.second << "\"\n"; + } + stream << " >\n"; + stream << " \n\n"; +} // write + +// ---------------------------------------------------------------------------- + +template +void MapUserConfigParam::findYourDataInAChildOf(const XMLNode* node) +{ + const XMLNode* child = node->getNode(m_param_name); + if (child == NULL) + { + //Log::error("User Config", "Couldn't find parameter group %s", m_param_name.c_str()); + return; + } + child->get(&m_elements); +} // findYourDataInAChildOf + +// ---------------------------------------------------------------------------- +template +void MapUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node) +{ +} // findYourDataInAnAttributeOf + +// ---------------------------------------------------------------------------- +template +void MapUserConfigParam::addElement(T element, U value) +{ + m_elements[element] = value; +} // findYourDataInAnAttributeOf + +// ---------------------------------------------------------------------------- +template +core::stringc MapUserConfigParam::toString() const +{ + return ""; +} // toString + +// ---------------------------------------------------------------------------- IntUserConfigParam::IntUserConfigParam(int default_value, const char* param_name, const char* comment) diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 166ceccf228..53b0cf1c610 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -136,6 +136,55 @@ class ListUserConfigParam : public UserConfigParam }; // ListUserConfigParam typedef ListUserConfigParam StringListUserConfigParam; +template +class MapUserConfigParam : public UserConfigParam +{ + std::map m_elements; + +public: + MapUserConfigParam(const char* param_name, + const char* comment = NULL); + MapUserConfigParam(const char* param_name, + const char* comment, + int nb_elts, + ...); + MapUserConfigParam(const char* param_name, + GroupUserConfigParam* group, + const char* comment = NULL); + MapUserConfigParam(const char* param_name, + GroupUserConfigParam* group, + const char* comment, + int nb_elts, + ...); + + void write(std::ofstream& stream) const; + void findYourDataInAChildOf(const XMLNode* node); + void findYourDataInAnAttributeOf(const XMLNode* node); + + void addElement(T element, U value); + + irr::core::stringc toString() const; + + operator std::map() const + { + return m_elements; + } + std::map& operator=(const std::map& v) + { + m_elements = std::map(v); + return m_elements; + } + std::map& operator=(const MapUserConfigParam& v) + { + m_elements = std::map(v); + return m_elements; + } + U& operator[] (const T key) + { + return m_elements[key]; + } +}; // ListUserConfigParam +typedef MapUserConfigParam IntToIntUserConfigParam; // ============================================================================ class IntUserConfigParam : public UserConfigParam { @@ -335,7 +384,7 @@ namespace UserConfigParams PARAM_DEFAULT( GroupUserConfigParam("RaceSetup", "Race Setup Settings") ); - PARAM_PREFIX IntUserConfigParam m_num_karts + PARAM_PREFIX IntUserConfigParam m_default_num_karts PARAM_DEFAULT( IntUserConfigParam(4, "numkarts", &m_race_setup_group, "Default number of karts. -1 means use all") ); @@ -369,7 +418,7 @@ namespace UserConfigParams PARAM_PREFIX StringUserConfigParam m_last_used_kart_group PARAM_DEFAULT( StringUserConfigParam("all", "last_kart_group", "Last selected kart group") ); - + // ---- Wiimote data PARAM_PREFIX GroupUserConfigParam m_wiimote_group PARAM_DEFAULT( GroupUserConfigParam("WiiMote", @@ -706,6 +755,14 @@ namespace UserConfigParams "stun.voxgratia.org", "stun.xten.com") ); + // ---- Gamemode setup + PARAM_PREFIX IntToIntUserConfigParam m_num_karts_per_gamemode + PARAM_DEFAULT(IntToIntUserConfigParam("num_karts_per_gamemode", + "The Number of karts per gamemode.", + 1, + std::make_pair(1100, 4) + )); + PARAM_PREFIX BoolUserConfigParam m_log_packets PARAM_DEFAULT( BoolUserConfigParam(false, "log-network-packets", "If all network packets should be logged") ); diff --git a/src/graphics/command_buffer.cpp b/src/graphics/command_buffer.cpp index 761ae122bc9..3c5e9762cfe 100644 --- a/src/graphics/command_buffer.cpp +++ b/src/graphics/command_buffer.cpp @@ -166,7 +166,6 @@ void SolidCommandBuffer::fill(MeshMap *mesh_map) fillInstanceData (mesh_map, four_tex_material_list, InstanceTypeFourTex); - if (!CVS->supportsAsyncInstanceUpload()) glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); } //SolidCommandBuffer::fill diff --git a/src/graphics/command_buffer.hpp b/src/graphics/command_buffer.hpp index 35021a8f4ac..2706b9239c7 100644 --- a/src/graphics/command_buffer.hpp +++ b/src/graphics/command_buffer.hpp @@ -218,7 +218,6 @@ class CommandBuffer mesh_map, instance_buffer); } - if (!CVS->supportsAsyncInstanceUpload()) { glUnmapBuffer(GL_ARRAY_BUFFER); diff --git a/src/graphics/sp_mesh_loader.cpp b/src/graphics/sp_mesh_loader.cpp index fec1a8e2ce2..57c1cd614c6 100644 --- a/src/graphics/sp_mesh_loader.cpp +++ b/src/graphics/sp_mesh_loader.cpp @@ -20,6 +20,7 @@ #include "utils/constants.hpp" #include "utils/mini_glm.hpp" +#include "../../lib/irrlicht/source/Irrlicht/CSkinnedMesh.h" const uint8_t VERSION_NOW = 1; #include @@ -47,7 +48,7 @@ scene::IAnimatedMesh* SPMeshLoader::createMesh(io::IReadFile* f) } m_bind_frame = 0; m_joint_count = 0; - //m_frame_count = 0; + m_frame_count = 0; m_mesh = NULL; m_mesh = m_scene_manager->createSkinnedMesh(); io::IFileSystem* fs = m_scene_manager->getFileSystem(); @@ -196,6 +197,9 @@ scene::IAnimatedMesh* SPMeshLoader::createMesh(io::IReadFile* f) f->read(&pre_computed_size, 2); } m_mesh->finalize(); + // Because the last frame in spm is usable + static_cast(m_mesh)->AnimationFrames = + (float)m_frame_count + 1.0f; m_all_armatures.clear(); m_to_bind_pose_matrices.clear(); m_joints.clear(); @@ -366,8 +370,8 @@ void SPMeshLoader::createAnimationData(irr::io::IReadFile* spm) } for (unsigned i = 0; i < armature_size; i++) { - //m_frame_count = std::max(m_frame_count, - // (unsigned)m_all_armatures[i].m_frame_pose_matrices.back().first); + m_frame_count = std::max(m_frame_count, + (unsigned)m_all_armatures[i].m_frame_pose_matrices.back().first); m_joint_count += m_all_armatures[i].m_joint_used; } diff --git a/src/graphics/sp_mesh_loader.hpp b/src/graphics/sp_mesh_loader.hpp index 64e257bf85b..55fc031ae5a 100644 --- a/src/graphics/sp_mesh_loader.hpp +++ b/src/graphics/sp_mesh_loader.hpp @@ -79,7 +79,7 @@ class SPMeshLoader : public scene::IMeshLoader unsigned id); }; // ------------------------------------------------------------------------ - unsigned m_bind_frame, m_joint_count;//, m_frame_count; + unsigned m_bind_frame, m_joint_count, m_frame_count; // ------------------------------------------------------------------------ std::vector m_all_armatures; // ------------------------------------------------------------------------ diff --git a/src/io/xml_node.cpp b/src/io/xml_node.cpp index cbc8dc21a2d..12d38c1e710 100644 --- a/src/io/xml_node.cpp +++ b/src/io/xml_node.cpp @@ -18,7 +18,6 @@ #include "io/file_manager.hpp" #include "io/xml_node.hpp" -#include "utils/string_utils.hpp" #include "utils/interpolation_array.hpp" #include "utils/vec3.hpp" diff --git a/src/io/xml_node.hpp b/src/io/xml_node.hpp index ed990dab4cf..66baea9db11 100644 --- a/src/io/xml_node.hpp +++ b/src/io/xml_node.hpp @@ -33,9 +33,11 @@ using namespace irr; #include "utils/leak_check.hpp" #include "utils/no_copy.hpp" +#include "utils/string_utils.hpp" #include "utils/time.hpp" #include "utils/types.hpp" + class InterpolationArray; class Vec3; @@ -95,6 +97,27 @@ class XMLNode : public NoCopy int getHPR(core::vector3df *value) const; int getHPR(Vec3 *value) const; + template + int get(std::map* out_map) const + { + using namespace StringUtils; + for (auto& p : m_attributes) + { + T val_1; + if (!fromString(p.first, val_1)) + { + return 0; + } + U val_2; + if (!fromString(wideToUtf8(p.second), val_2)) + { + return 0; + } + (*out_map)[val_1] = val_2; + } + return (int)m_attributes.size(); + } + bool hasChildNamed(const char* name) const; /** Handy functions to test the bit pattern returned by get(vector3df*).*/ diff --git a/src/items/attachment.cpp b/src/items/attachment.cpp index b4b1dfd9f80..dbaeaf35550 100644 --- a/src/items/attachment.cpp +++ b/src/items/attachment.cpp @@ -497,6 +497,28 @@ void Attachment::update(float dt) bool is_shield = (m_type == ATTACH_BUBBLEGUM_SHIELD|| m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD); float m_wanted_node_scale = is_shield ? std::max(1.0f, m_kart->getHighestPoint()*1.1f) : 1.0f; + int slow_flashes = 3; + if (is_shield & m_time_left < slow_flashes) + { + int flashes_per_second = 4; + int divisor = 2; + + float fast_flashes = 0.5F; + if (m_time_left < fast_flashes) + { + flashes_per_second = 12; + } + + float mod = (int)(m_time_left * flashes_per_second * 2) % divisor; + if (mod < divisor / 2) + { + m_node->setVisible(false); + } + else + { + m_node->setVisible(true); + } + } if (m_node_scale < m_wanted_node_scale) { diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 938273ad7e9..79edf6f9331 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -2181,7 +2181,7 @@ void Kart::playCrashSFX(const Material* m, AbstractKart *k) { const float speed_for_max_volume = 15; //The speed at which the sound plays at maximum volume const float max_volume = 1; //The maximum volume a sound is played at - const float min_volume = 0.2; //The minimum volume a sound is played at + const float min_volume = 0.2f; //The minimum volume a sound is played at float volume; //The volume the crash sound will be played at diff --git a/src/main.cpp b/src/main.cpp index 9f8b27d8edd..28ba7201e4d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -594,6 +594,7 @@ void cmdLineHelp() " -h, --help Show this help.\n" " --log=N Set the verbosity to a value between\n" " 0 (Debug) and 5 (Only Fatal messages)\n" + " --logbuffer=N Buffers up to N lines log lines before writing.\n" " --root=DIR Path to add to the list of STK root directories.\n" " You can specify more than one by separating them\n" " with colons (:).\n" @@ -664,6 +665,8 @@ int handleCmdLineOutputModifier() int n; if(CommandLine::has("--log", &n)) Log::setLogLevel(n); + if (CommandLine::has("--logbuffer", &n)) + Log::setBufferSize(n); if(CommandLine::has("--log=nocolor")) { @@ -1189,16 +1192,16 @@ int handleCmdLine() if(CommandLine::has("--numkarts", &n) ||CommandLine::has("-k", &n)) { - UserConfigParams::m_num_karts = n; - if(UserConfigParams::m_num_karts > stk_config->m_max_karts) + UserConfigParams::m_default_num_karts = n; + if(UserConfigParams::m_default_num_karts > stk_config->m_max_karts) { Log::warn("main", "Number of karts reset to maximum number %d.", stk_config->m_max_karts); - UserConfigParams::m_num_karts = stk_config->m_max_karts; + UserConfigParams::m_default_num_karts = stk_config->m_max_karts; } - race_manager->setNumKarts( UserConfigParams::m_num_karts ); + race_manager->setNumKarts( UserConfigParams::m_default_num_karts ); Log::verbose("main", "%d karts will be used.", - (int)UserConfigParams::m_num_karts); + (int)UserConfigParams::m_default_num_karts); } // --numkarts if(CommandLine::has( "--no-start-screen") || @@ -1807,8 +1810,10 @@ int main(int argc, char *argv[] ) } // try catch (std::exception &e) { + Log::flushBuffers(); Log::error("main", "Exception caught : %s.",e.what()); Log::error("main", "Aborting SuperTuxKart."); + Log::flushBuffers(); } /* Program closing...*/ @@ -1832,6 +1837,8 @@ int main(int argc, char *argv[] ) MemoryLeaks::checkForLeaks(); #endif + Log::flushBuffers(); + #ifndef WIN32 if (user_config) //close logfiles { diff --git a/src/modes/demo_world.cpp b/src/modes/demo_world.cpp index 867b6ad151b..078ba126888 100644 --- a/src/modes/demo_world.cpp +++ b/src/modes/demo_world.cpp @@ -29,7 +29,7 @@ #include "tracks/track_manager.hpp" std::vector DemoWorld::m_demo_tracks; -int DemoWorld::m_num_karts = 2; +int DemoWorld::m_default_num_karts = 2; float DemoWorld::m_max_idle_time = 99999.0f; float DemoWorld::m_current_idle_time = 0; bool DemoWorld::m_do_demo = false; @@ -49,7 +49,7 @@ DemoWorld::DemoWorld() race_manager->setReverseTrack(false); race_manager->setMinorMode (RaceManager::MINOR_MODE_NORMAL_RACE); race_manager->setDifficulty(RaceManager::DIFFICULTY_HARD); - race_manager->setNumKarts(m_num_karts); + race_manager->setNumKarts(m_default_num_karts); race_manager->setNumPlayers(1); race_manager->setPlayerKart(0, UserConfigParams::m_default_kart); @@ -149,7 +149,7 @@ bool DemoWorld::updateIdleTimeAndStartDemo(float dt) input_manager->getDeviceManager()->setAssignMode(ASSIGN); m_do_demo = true; - race_manager->setNumKarts(m_num_karts); + race_manager->setNumKarts(m_default_num_karts); race_manager->setPlayerKart(0, "tux"); race_manager->setupPlayerKartInfo(); race_manager->startSingleRace(m_demo_tracks[0], m_num_laps, false); diff --git a/src/modes/demo_world.hpp b/src/modes/demo_world.hpp index a2d047a2f52..bce6940bed3 100644 --- a/src/modes/demo_world.hpp +++ b/src/modes/demo_world.hpp @@ -40,7 +40,7 @@ class DemoWorld : public ProfileWorld static std::vector m_demo_tracks; /** Number of karts to use in demo mode. */ - static int m_num_karts; + static int m_default_num_karts; /** Idle time after which demo mode should be started. */ static float m_max_idle_time; @@ -66,7 +66,7 @@ class DemoWorld : public ProfileWorld static void setNumLaps(unsigned int num_laps) { m_num_laps = num_laps; } // ------------------------------------------------------------------------ /** Sets the number of karts to use in demo mode. */ - static void setNumKarts(unsigned int num_karts) { m_num_karts = num_karts;} + static void setNumKarts(unsigned int num_karts) { m_default_num_karts = num_karts;} // ------------------------------------------------------------------------ static void setTracks(const std::vector &tracks); // ------------------------------------------------------------------------ diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 8ac4863146a..c1251dfd88d 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -66,7 +66,7 @@ RaceManager::RaceManager() { // Several code depends on this, e.g. kart_properties assert(DIFFICULTY_FIRST == 0); - m_num_karts = UserConfigParams::m_num_karts; + m_num_karts = UserConfigParams::m_default_num_karts; m_difficulty = DIFFICULTY_HARD; m_major_mode = MAJOR_MODE_SINGLE; m_minor_mode = MINOR_MODE_NORMAL_RACE; diff --git a/src/scriptengine/script_track.cpp b/src/scriptengine/script_track.cpp index 2ca00ea0ca9..a221e0ce414 100644 --- a/src/scriptengine/script_track.cpp +++ b/src/scriptengine/script_track.cpp @@ -295,6 +295,33 @@ namespace Scripting return -1; } + /** Remove all animation set for a skeletal animation */ + void removeAllAnimationSet(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */) + { + if (memory) + { + ((scene::IAnimatedMeshSceneNode*)(memory))->removeAllAnimationSet(); + } + } + + /** Add an animation set for a skeletal animation */ + void addAnimationSet(int start/** \cond DOXYGEN_IGNORE */, int end/** \cond DOXYGEN_IGNORE */, /** \cond DOXYGEN_IGNORE */void *memory /** \endcond */) + { + if (memory) + { + ((scene::IAnimatedMeshSceneNode*)(memory))->addAnimationSet(start, end); + } + } + + /** use an current frame for a skeletal animation */ + void useAnimationSet(int set_num /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */) + { + if (memory) + { + ((scene::IAnimatedMeshSceneNode*)(memory))->useAnimationSet(set_num); + } + } + /** Sets the current frame for a skeletal animation */ void setCurrentFrame(int frame /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */) { @@ -465,6 +492,8 @@ namespace Scripting r = engine->RegisterObjectMethod("TrackObject", "void moveTo(const Vec3 &in, bool)", asMETHOD(::TrackObject, moveTo), asCALL_THISCALL); assert(r >= 0); r = engine->RegisterObjectMethod("TrackObject", "Vec3 getCenterPosition()", asFUNCTION(TrackObject::getCenterPosition), asCALL_CDECL_OBJLAST); assert(r >= 0); r = engine->RegisterObjectMethod("TrackObject", "Vec3 getOrigin()", asFUNCTION(TrackObject::getOrigin), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("TrackObject", "TrackObject@ getParentLibrary()", asMETHOD(::TrackObject, getParentLibrary), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("TrackObject", "string getName()", asMETHOD(::TrackObject, getName), asCALL_THISCALL); assert(r >= 0); // PhysicalObject r = engine->RegisterObjectMethod("PhysicalObject", "bool isFlattenKartObject()", asMETHOD(PhysicalObject, isFlattenKartObject), asCALL_THISCALL); assert(r >= 0); @@ -476,6 +505,9 @@ namespace Scripting r = engine->RegisterObjectMethod("Mesh", "void setFrameLoopOnce(int start, int end)", asFUNCTION(Mesh::setFrameLoopOnce), asCALL_CDECL_OBJLAST); assert(r >= 0); r = engine->RegisterObjectMethod("Mesh", "int getFrameNr()", asFUNCTION(Mesh::getFrameNr), asCALL_CDECL_OBJLAST); assert(r >= 0); r = engine->RegisterObjectMethod("Mesh", "int getAnimationSet()", asFUNCTION(Mesh::getAnimationSet), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("Mesh", "void useAnimationSet(int set_num)", asFUNCTION(Mesh::useAnimationSet), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("Mesh", "void addAnimationSet(int start, int end)", asFUNCTION(Mesh::addAnimationSet), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("Mesh", "void removeAllAnimationSet()", asFUNCTION(Mesh::removeAllAnimationSet), asCALL_CDECL_OBJLAST); assert(r >= 0); r = engine->RegisterObjectMethod("Mesh", "void setCurrentFrame(int frame)", asFUNCTION(Mesh::setCurrentFrame), asCALL_CDECL_OBJLAST); assert(r >= 0); //r = engine->RegisterObjectMethod("Mesh", "void move(Vec3 &in)", asFUNCTION(movePresentation), asCALL_CDECL_OBJLAST); assert(r >= 0); diff --git a/src/states_screens/feature_unlocked.cpp b/src/states_screens/feature_unlocked.cpp index 8ae059181f0..eb69539b491 100644 --- a/src/states_screens/feature_unlocked.cpp +++ b/src/states_screens/feature_unlocked.cpp @@ -581,20 +581,20 @@ bool FeatureUnlockedCutScene::onEscapePressed() void FeatureUnlockedCutScene::continueButtonPressed() { - //if (m_global_time < GIFT_EXIT_TO) - //{ - // // If animation was not over yet, the button is used to skip the animation - // while (m_global_time < GIFT_EXIT_TO) - // { - // // simulate all the steps of the animation until we reach the end - // onUpdate(0.4f); - // World::getWorld()->updateWorld(0.4f); - // } - //} - //else - //{ + if (m_global_time < GIFT_EXIT_TO) + { + // If animation was not over yet, the button is used to skip the animation + while (m_global_time < GIFT_EXIT_TO) + { + // simulate all the steps of the animation until we reach the end + onUpdate(0.4f); + World::getWorld()->updateWorld(0.4f); + } + } + else + { ((CutsceneWorld*)World::getWorld())->abortCutscene(); - //} + } } // continueButtonPressed diff --git a/src/states_screens/ghost_replay_selection.cpp b/src/states_screens/ghost_replay_selection.cpp index c5e90191b7a..3205ce9182d 100644 --- a/src/states_screens/ghost_replay_selection.cpp +++ b/src/states_screens/ghost_replay_selection.cpp @@ -128,7 +128,7 @@ void GhostReplaySelection::loadList() row.push_back(GUIEngine::ListWidget::ListCell (StringUtils::toWString(rd.m_min_time) + L"s", -1, 1, true)); row.push_back(GUIEngine::ListWidget::ListCell - (rd.m_user_name, -1, 1, true)); + (rd.m_user_name.empty() ? " " : rd.m_user_name, -1, 1, true)); m_replay_list_widget->addItem(StringUtils::toString(i), row); } } // loadList diff --git a/src/states_screens/gp_info_screen.cpp b/src/states_screens/gp_info_screen.cpp index 1a5169d5b9a..5db857f98fd 100644 --- a/src/states_screens/gp_info_screen.cpp +++ b/src/states_screens/gp_info_screen.cpp @@ -234,8 +234,9 @@ void GPInfoScreen::init() { const int local_players = race_manager->getNumLocalPlayers(); int min_ai = 0; - int num_ai = UserConfigParams::m_num_karts - local_players; - + int num_ai = UserConfigParams::m_num_karts_per_gamemode[RaceManager::MAJOR_MODE_GRAND_PRIX] + - local_players; + // A ftl reace needs at least three karts to make any sense if (race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER) { @@ -243,9 +244,7 @@ void GPInfoScreen::init() } num_ai = std::max(min_ai, num_ai); - UserConfigParams::m_num_karts = num_ai + local_players; - race_manager->setNumKarts(num_ai + local_players); - + m_ai_kart_spinner->setActive(true); m_ai_kart_spinner->setValue(num_ai); m_ai_kart_spinner->setMax(stk_config->m_max_karts - local_players); @@ -315,11 +314,24 @@ void GPInfoScreen::eventCallback(Widget *, const std::string &name, /*new tracks*/ true ); addTracks(); } - else if (button == "start" || button == "continue") + else if (button == "start") + { + // Normal GP: start GP + const int local_players = race_manager->getNumLocalPlayers(); + const bool has_AI = race_manager->hasAI(); + const int num_ai = has_AI ? m_ai_kart_spinner->getValue() : 0; + + race_manager->setNumKarts(local_players + num_ai); + UserConfigParams::m_num_karts_per_gamemode[RaceManager::MAJOR_MODE_GRAND_PRIX] = local_players + num_ai; + + m_gp.changeReverse(getReverse()); + race_manager->startGP(m_gp, false, false); + } + else if (button == "continue") { - // Normal GP: start/continue a saved GP + // Normal GP: continue a saved GP m_gp.changeReverse(getReverse()); - race_manager->startGP(m_gp, false, (button == "continue")); + race_manager->startGP(m_gp, false, true); } } // name=="buttons" else if (name=="group-spinner") @@ -347,7 +359,7 @@ void GPInfoScreen::eventCallback(Widget *, const std::string &name, { const int num_ai = m_ai_kart_spinner->getValue(); race_manager->setNumKarts( race_manager->getNumLocalPlayers() + num_ai ); - UserConfigParams::m_num_karts = race_manager->getNumLocalPlayers() + num_ai; + UserConfigParams::m_num_karts_per_gamemode[RaceManager::MAJOR_MODE_GRAND_PRIX] = race_manager->getNumLocalPlayers() + num_ai; } else if(name=="back") { diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index 35523b85dd0..17f1d325710 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -46,6 +46,7 @@ #include "states_screens/offline_kart_selection.hpp" #include "states_screens/online_profile_achievements.hpp" #include "states_screens/online_profile_servers.hpp" +#include "states_screens/online_screen.hpp" #include "states_screens/options_screen_video.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/user_screen.hpp" @@ -75,9 +76,6 @@ bool MainMenuScreen::m_enable_online = false; MainMenuScreen::MainMenuScreen() : Screen("main_menu.stkgui") { - m_online_string = _("Online"); - //I18N: Used as a verb, appears on the main menu (login button) - m_login_string = _("Login"); } // MainMenuScreen // ---------------------------------------------------------------------------- @@ -151,10 +149,7 @@ void MainMenuScreen::init() w->setBadge(LOADING_BADGE); } - m_online = getWidget("online"); - - if(!m_enable_online) - m_online->setActive(false); + IconButtonWidget* online = getWidget("online"); LabelWidget* w = getWidget("info_addons"); const core::stringw &news_text = NewsManager::get()->getNextNewsMessage(); @@ -179,32 +174,25 @@ void MainMenuScreen::init() } // init // ---------------------------------------------------------------------------- -void MainMenuScreen::onUpdate(float delta) +void MainMenuScreen::onUpdate(float delta) { PlayerProfile *player = PlayerManager::getCurrentPlayer(); if(PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_GUEST || PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_IN) { m_user_id->setText(player->getLastOnlineName() + "@stk"); - m_online->setActive(true); - m_online->setLabel(m_online_string); } else if (PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_OUT) { - m_online->setActive(true); - m_online->setLabel(m_login_string); m_user_id->setText(player->getName()); } else { // now must be either logging in or logging out - m_online->setActive(false); m_user_id->setText(player->getName()); } - m_online->setLabel(PlayerManager::getCurrentOnlineId() ? m_online_string - : m_login_string); IconButtonWidget* addons_icon = getWidget("addons"); if (addons_icon != NULL) { @@ -472,6 +460,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, } else if (selection == "story") { + NetworkConfig::get()->unsetNetworking(); PlayerProfile *player = PlayerManager::getCurrentPlayer(); if (player->isFirstTime()) { @@ -505,23 +494,30 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, } else if (selection == "online") { - if(UserConfigParams::m_internet_status!=RequestManager::IPERM_ALLOWED) - { - new MessageDialog(_("You can not play online without internet access. " - "If you want to play online, go to options, select " - " tab 'User Interface', and edit " - "\"Connect to the Internet\".")); - return; - } - - if (PlayerManager::getCurrentOnlineId()) + if (MainMenuScreen::m_enable_online) { - ProfileManager::get()->setVisiting(PlayerManager::getCurrentOnlineId()); - OnlineProfileServers::getInstance()->push(); + OnlineScreen::getInstance()->push(); } else { - UserScreen::getInstance()->push(); + if (UserConfigParams::m_internet_status != RequestManager::IPERM_ALLOWED) + { + new MessageDialog(_("You can not play online without internet access. " + "If you want to play online, go to options, select " + " tab 'User Interface', and edit " + "\"Connect to the Internet\".")); + return; + } + + if (PlayerManager::getCurrentOnlineId()) + { + ProfileManager::get()->setVisiting(PlayerManager::getCurrentOnlineId()); + TabOnlineProfileAchievements::getInstance()->push(); + } + else + { + UserScreen::getInstance()->push(); + } } } else if (selection == "addons") diff --git a/src/states_screens/main_menu_screen.hpp b/src/states_screens/main_menu_screen.hpp index 4e79c453264..8da6c94ab4c 100644 --- a/src/states_screens/main_menu_screen.hpp +++ b/src/states_screens/main_menu_screen.hpp @@ -32,13 +32,6 @@ class MainMenuScreen : public GUIEngine::Screen, public GUIEngine::ScreenSinglet private: friend class GUIEngine::ScreenSingleton; - core::stringw m_online_string; - - core::stringw m_login_string; - - /** Keep the widget to avoid looking it up every frame. */ - GUIEngine::IconButtonWidget* m_online; - /** Keep the widget to to the user name. */ GUIEngine::ButtonWidget *m_user_id; diff --git a/src/states_screens/online_lan.cpp b/src/states_screens/online_lan.cpp new file mode 100644 index 00000000000..9e22fa10447 --- /dev/null +++ b/src/states_screens/online_lan.cpp @@ -0,0 +1,112 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2010-2015 Glenn De Jonghe +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "states_screens/online_profile_servers.hpp" + +#include "audio/sfx_manager.hpp" +#include "config/player_manager.hpp" +#include "guiengine/engine.hpp" +#include "guiengine/scalable_font.hpp" +#include "guiengine/screen.hpp" +#include "guiengine/widget.hpp" +#include "network/network_config.hpp" +#include "network/protocol_manager.hpp" +#include "network/protocols/connect_to_server.hpp" +#include "network/protocols/request_connection.hpp" +#include "network/servers_manager.hpp" +#include "states_screens/state_manager.hpp" +#include "states_screens/create_server_screen.hpp" +#include "states_screens/networking_lobby.hpp" +#include "states_screens/online_lan.hpp" +#include "states_screens/server_selection.hpp" +#include "utils/translation.hpp" + +#include + +#include +#include + +using namespace GUIEngine; +using namespace irr::core; +using namespace irr::gui; +using namespace Online; + +DEFINE_SCREEN_SINGLETON( OnlineLanScreen ); + +// ----------------------------------------------------------------------------- + +OnlineLanScreen::OnlineLanScreen() : GUIEngine::Screen("online/lan.stkgui") +{ +} // OnlineLanScreen + +// ----------------------------------------------------------------------------- + +void OnlineLanScreen::loadedFromFile() +{ +} // loadedFromFile + +// ----------------------------------------------------------------------------- + +void OnlineLanScreen::init() +{ + RibbonWidget* ribbon = getWidget("lan"); + assert(ribbon != NULL); + ribbon->select("find_lan_server", PLAYER_ID_GAME_MASTER); + ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER); +} // init + +// ----------------------------------------------------------------------------- + +void OnlineLanScreen::eventCallback(Widget* widget, const std::string& name, const int playerID) +{ + if (name == "back") + { + StateManager::get()->popMenu(); + return; + } + if (name == "lan") + { + RibbonWidget* ribbon = dynamic_cast(widget); + std::string selection = ribbon->getSelectionIDString(PLAYER_ID_GAME_MASTER); + if (selection == "create_lan_server") + { + NetworkConfig::get()->setIsLAN(); + NetworkConfig::get()->setIsServer(true); + CreateServerScreen::getInstance()->push(); + // TODO: create lan server + } + else if (selection == "find_lan_server") + { + NetworkConfig::get()->setIsLAN(); + NetworkConfig::get()->setIsServer(false); + ServerSelection::getInstance()->push(); + } + } + +} // eventCallback + +// ---------------------------------------------------------------------------- +/** Also called when pressing the back button. It resets the flags to indicate + * a networked game. + */ +bool OnlineLanScreen::onEscapePressed() +{ + NetworkConfig::get()->unsetNetworking(); + //StateManager::get()->popMenu(); + return true; +} // onEscapePressed + diff --git a/src/states_screens/online_lan.hpp b/src/states_screens/online_lan.hpp new file mode 100644 index 00000000000..615cb9e3751 --- /dev/null +++ b/src/states_screens/online_lan.hpp @@ -0,0 +1,57 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013-2015 Glenn De Jonghe +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef __HEADER_OLAN_HPP__ +#define __HEADER_OLAN_HPP__ + +#include +#include + +#include "guiengine/screen.hpp" +#include "guiengine/widgets.hpp" +#include "states_screens/online_profile_base.hpp" + +namespace GUIEngine { class Widget; } + + +/** + * \brief Online profiel overview screen + * \ingroup states_screens + */ +class OnlineLanScreen : public GUIEngine::Screen, public GUIEngine::ScreenSingleton +{ +protected: + OnlineLanScreen(); + +public: + friend class GUIEngine::ScreenSingleton; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void loadedFromFile() OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name, + const int playerID) OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void init() OVERRIDE; + virtual bool onEscapePressed() OVERRIDE; + +}; // class OnlineProfileServers + +#endif diff --git a/src/states_screens/online_profile_base.cpp b/src/states_screens/online_profile_base.cpp index 20812375098..0088cdaf3b0 100644 --- a/src/states_screens/online_profile_base.cpp +++ b/src/states_screens/online_profile_base.cpp @@ -42,7 +42,6 @@ using namespace Online; OnlineProfileBase::OnlineProfileBase(const std::string &filename) : Screen(filename.c_str()) { - m_servers_tab = NULL; m_friends_tab = NULL; m_achievements_tab = NULL; m_settings_tab = NULL; @@ -63,9 +62,6 @@ void OnlineProfileBase::loadedFromFile() m_friends_tab = (IconButtonWidget *)m_profile_tabs->findWidgetNamed("tab_friends"); assert(m_friends_tab != NULL); - m_servers_tab = (IconButtonWidget *)m_profile_tabs->findWidgetNamed("tab_servers"); - assert(m_servers_tab != NULL); - m_achievements_tab = (IconButtonWidget*)m_profile_tabs->findWidgetNamed("tab_achievements"); assert(m_profile_tabs == NULL || m_achievements_tab != NULL); @@ -107,7 +103,6 @@ void OnlineProfileBase::init() if (m_profile_tabs) { - m_servers_tab->setTooltip(_("Servers")); m_friends_tab->setTooltip(_("Friends")); m_achievements_tab->setTooltip(_("Achievements")); m_settings_tab->setTooltip(_("Account Settings")); @@ -159,8 +154,6 @@ void OnlineProfileBase::eventCallback(Widget* widget, const std::string& name, sm->replaceTopMostScreen(TabOnlineProfileAchievements::getInstance()); else if (selection == m_settings_tab->m_properties[PROP_ID]) sm->replaceTopMostScreen(OnlineProfileSettings::getInstance()); - else if (selection == m_servers_tab->m_properties[PROP_ID]) - sm->replaceTopMostScreen(OnlineProfileServers::getInstance()); } else if (name == "back") { diff --git a/src/states_screens/online_profile_base.hpp b/src/states_screens/online_profile_base.hpp index 95a6906fac6..0285edb4b5a 100644 --- a/src/states_screens/online_profile_base.hpp +++ b/src/states_screens/online_profile_base.hpp @@ -42,7 +42,6 @@ class OnlineProfileBase : public GUIEngine::Screen /** Pointer to the various widgets on the screen. */ GUIEngine::LabelWidget * m_header; GUIEngine::RibbonWidget* m_profile_tabs; - GUIEngine::IconButtonWidget * m_servers_tab; GUIEngine::IconButtonWidget * m_friends_tab; GUIEngine::IconButtonWidget * m_achievements_tab; GUIEngine::IconButtonWidget * m_settings_tab; diff --git a/src/states_screens/online_profile_servers.cpp b/src/states_screens/online_profile_servers.cpp index 7d3400b0fce..0787d2fefab 100644 --- a/src/states_screens/online_profile_servers.cpp +++ b/src/states_screens/online_profile_servers.cpp @@ -48,7 +48,7 @@ DEFINE_SCREEN_SINGLETON( OnlineProfileServers ); // ----------------------------------------------------------------------------- -OnlineProfileServers::OnlineProfileServers() : OnlineProfileBase("online/profile_servers.stkgui") +OnlineProfileServers::OnlineProfileServers() : GUIEngine::Screen("online/profile_servers.stkgui") { } // OnlineProfileServers @@ -56,44 +56,28 @@ OnlineProfileServers::OnlineProfileServers() : OnlineProfileBase("online/profile void OnlineProfileServers::loadedFromFile() { - OnlineProfileBase::loadedFromFile(); } // loadedFromFile // ----------------------------------------------------------------------------- void OnlineProfileServers::init() { - OnlineProfileBase::init(); - m_profile_tabs->select( m_servers_tab->m_properties[PROP_ID], PLAYER_ID_GAME_MASTER ); - m_servers_tab->setFocusForPlayer(PLAYER_ID_GAME_MASTER); - // OnlineScreen::getInstance()->push(); + RibbonWidget* ribbon = getWidget("wan"); + assert(ribbon != NULL); + ribbon->select("find_wan_server", PLAYER_ID_GAME_MASTER); + ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER); } // init // ----------------------------------------------------------------------------- void OnlineProfileServers::eventCallback(Widget* widget, const std::string& name, const int playerID) { - OnlineProfileBase::eventCallback( widget, name, playerID); - - if (name == "lan") + if (name == "back") { - RibbonWidget* ribbon = dynamic_cast(widget); - std::string selection = ribbon->getSelectionIDString(PLAYER_ID_GAME_MASTER); - if (selection == "create_lan_server") - { - NetworkConfig::get()->setIsLAN(); - NetworkConfig::get()->setIsServer(true); - CreateServerScreen::getInstance()->push(); - // TODO: create lan server - } - else if (selection == "find_lan_server") - { - NetworkConfig::get()->setIsLAN(); - NetworkConfig::get()->setIsServer(false); - ServerSelection::getInstance()->push(); - } + StateManager::get()->popMenu(); + return; } - else if (name == "wan") + if (name == "wan") { RibbonWidget* ribbon = dynamic_cast(widget); std::string selection = ribbon->getSelectionIDString(PLAYER_ID_GAME_MASTER); @@ -176,6 +160,6 @@ void OnlineProfileServers::doQuickPlay() bool OnlineProfileServers::onEscapePressed() { NetworkConfig::get()->unsetNetworking(); - return OnlineProfileBase::onEscapePressed(); + return true; } // onEscapePressed diff --git a/src/states_screens/online_profile_servers.hpp b/src/states_screens/online_profile_servers.hpp index b840f103e2d..0d30b6fe6ed 100644 --- a/src/states_screens/online_profile_servers.hpp +++ b/src/states_screens/online_profile_servers.hpp @@ -33,7 +33,7 @@ namespace GUIEngine { class Widget; } * \brief Online profiel overview screen * \ingroup states_screens */ -class OnlineProfileServers : public OnlineProfileBase, public GUIEngine::ScreenSingleton +class OnlineProfileServers : public GUIEngine::Screen, public GUIEngine::ScreenSingleton { protected: OnlineProfileServers(); diff --git a/src/states_screens/online_screen.cpp b/src/states_screens/online_screen.cpp new file mode 100644 index 00000000000..e0601c56ee9 --- /dev/null +++ b/src/states_screens/online_screen.cpp @@ -0,0 +1,198 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2015 Marianne Gagnon +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#include "states_screens/main_menu_screen.hpp" + +#include "config/player_manager.hpp" +#include "config/user_config.hpp" +#include "graphics/irr_driver.hpp" +#include "guiengine/scalable_font.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "input/device_manager.hpp" +#include "input/input_manager.hpp" +#include "input/keyboard_device.hpp" +#include "io/file_manager.hpp" +#include "main_loop.hpp" +#include "network/network_config.hpp" +#include "online/request_manager.hpp" +#include "states_screens/online_lan.hpp" +#include "states_screens/online_profile_achievements.hpp" +#include "states_screens/online_profile_servers.hpp" +#include "states_screens/online_screen.hpp" +#include "states_screens/state_manager.hpp" +#include "states_screens/user_screen.hpp" +#include "states_screens/dialogs/message_dialog.hpp" +#include "tracks/track_manager.hpp" +#include "utils/string_utils.hpp" + + +#include + + +using namespace GUIEngine; +using namespace Online; + +DEFINE_SCREEN_SINGLETON( OnlineScreen ); + +// ---------------------------------------------------------------------------- + +OnlineScreen::OnlineScreen() : Screen("online/online.stkgui") +{ + m_online_string = _("Your profile"); + //I18N: Used as a verb, appears on the main networking menu (login button) + m_login_string = _("Login"); +} // OnlineScreen + +// ---------------------------------------------------------------------------- + +void OnlineScreen::loadedFromFile() +{ +} // loadedFromFile + +// ---------------------------------------------------------------------------- + +void OnlineScreen::beforeAddingWidget() +{ + bool is_logged_in = false; + PlayerProfile *player = PlayerManager::getCurrentPlayer(); + if (PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_GUEST || + PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_IN) + { + is_logged_in = true; + } + + IconButtonWidget* wan = getWidget("wan"); + wan->setActive(is_logged_in); + wan->setVisible(is_logged_in); +} // beforeAddingWidget + +// ---------------------------------------------------------------------------- +// +void OnlineScreen::init() +{ + Screen::init(); + + m_online = getWidget("online"); + + if (!MainMenuScreen::m_enable_online) + m_online->setActive(false); + + m_user_id = getWidget("user-id"); + assert(m_user_id); + + RibbonWidget* r = getWidget("menu_toprow"); + r->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + +} // init + +// ---------------------------------------------------------------------------- + +void OnlineScreen::onUpdate(float delta) +{ + PlayerProfile *player = PlayerManager::getCurrentPlayer(); + if (PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_GUEST || + PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_IN) + { + m_online->setActive(true); + m_online->setLabel(m_online_string); + m_user_id->setText(player->getLastOnlineName() + "@stk"); + } + else if (PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_OUT) + { + m_online->setActive(true); + m_online->setLabel(m_login_string); + m_user_id->setText(player->getName()); + } + else + { + // now must be either logging in or logging out + m_online->setActive(false); + m_user_id->setText(player->getName()); + } + + m_online->setLabel(PlayerManager::getCurrentOnlineId() ? m_online_string + : m_login_string); +} // onUpdate + +// ---------------------------------------------------------------------------- + +void OnlineScreen::eventCallback(Widget* widget, const std::string& name, + const int playerID) +{ + if (name == "user-id") + { + UserScreen::getInstance()->push(); + return; + } + else if (name == "back") + { + StateManager::get()->popMenu(); + return; + } + + RibbonWidget* ribbon = dynamic_cast(widget); + if (ribbon == NULL) return; // what's that event?? + + // ---- A ribbon icon was clicked + std::string selection = + ribbon->getSelectionIDString(PLAYER_ID_GAME_MASTER); + + if (selection == "lan") + { + OnlineLanScreen::getInstance()->push(); + } + else if (selection == "wan") + { + OnlineProfileServers::getInstance()->push(); + } + else if (selection == "online") + { + if (UserConfigParams::m_internet_status != RequestManager::IPERM_ALLOWED) + { + new MessageDialog(_("You can not play online without internet access. " + "If you want to play online, go to options, select " + " tab 'User Interface', and edit " + "\"Connect to the Internet\".")); + return; + } + + if (PlayerManager::getCurrentOnlineId()) + { + ProfileManager::get()->setVisiting(PlayerManager::getCurrentOnlineId()); + TabOnlineProfileAchievements::getInstance()->push(); + } + else + { + UserScreen::getInstance()->push(); + } + } +} // eventCallback + +// ---------------------------------------------------------------------------- + +void OnlineScreen::tearDown() +{ +} // tearDown + +// ---------------------------------------------------------------------------- + +void OnlineScreen::onDisabledItemClicked(const std::string& item) +{ +} // onDisabledItemClicked diff --git a/src/states_screens/online_screen.hpp b/src/states_screens/online_screen.hpp new file mode 100644 index 00000000000..69f2b371b1d --- /dev/null +++ b/src/states_screens/online_screen.hpp @@ -0,0 +1,71 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2015 Marianne Gagnon +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_ONLINE_SCREEN_HPP +#define HEADER_ONLINE_SCREEN_HPP + +#include "guiengine/screen.hpp" + +namespace GUIEngine { class Widget; class ListWidget; + class ButtonWidget; class IconButtonWidget; } + +/** + * \brief Handles the networking main menu + * \ingroup states_screens + */ +class OnlineScreen : public GUIEngine::Screen, public GUIEngine::ScreenSingleton +{ +private: + friend class GUIEngine::ScreenSingleton; + + core::stringw m_online_string; + + core::stringw m_login_string; + + /** Keep the widget to to the user name. */ + GUIEngine::ButtonWidget *m_user_id; + + /** Keep the widget to avoid looking it up every frame. */ + GUIEngine::IconButtonWidget* m_online; + + OnlineScreen(); + +public: + + virtual void onUpdate(float delta) OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void loadedFromFile() OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void beforeAddingWidget() OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name, + const int playerID) OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void init() OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void tearDown() OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void onDisabledItemClicked(const std::string& item) OVERRIDE; +}; + +#endif diff --git a/src/states_screens/track_info_screen.cpp b/src/states_screens/track_info_screen.cpp index d4e16338df1..adfa9959cdb 100644 --- a/src/states_screens/track_info_screen.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -163,15 +163,19 @@ void TrackInfoScreen::init() race_manager->hasAI()); m_ai_kart_spinner->setVisible(has_AI); getWidget("ai-text")->setVisible(has_AI); + if (has_AI) { m_ai_kart_spinner->setActive(true); - + + int num_ai = UserConfigParams::m_num_karts_per_gamemode[race_manager->getMinorMode()] - local_players; + // Avoid negative numbers (which can happen if e.g. the number of karts // in a previous race was lower than the number of players now. - int num_ai = UserConfigParams::m_num_karts - local_players; + if (num_ai < 0) num_ai = 0; m_ai_kart_spinner->setValue(num_ai); + race_manager->setNumKarts(num_ai + local_players); // Set the max karts supported based on the battle arena selected if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES || @@ -240,7 +244,8 @@ void TrackInfoScreen::init() m_ai_kart_spinner->setValue(0); m_ai_kart_spinner->setActive(false); race_manager->setNumKarts(race_manager->getNumLocalPlayers()); - UserConfigParams::m_num_karts = race_manager->getNumLocalPlayers(); + + UserConfigParams::m_num_karts_per_gamemode[race_manager->getMinorMode()] = race_manager->getNumLocalPlayers(); } else if (record_available) { @@ -367,10 +372,11 @@ void TrackInfoScreen::onEnterPressedInternal() if (has_AI) num_ai = m_ai_kart_spinner->getValue(); - if (UserConfigParams::m_num_karts != (local_players + num_ai)) + + if (UserConfigParams::m_num_karts_per_gamemode[race_manager->getMinorMode()] != (local_players + num_ai)) { race_manager->setNumKarts(local_players + num_ai); - UserConfigParams::m_num_karts = local_players + num_ai; + UserConfigParams::m_num_karts_per_gamemode[race_manager->getMinorMode()] = local_players + num_ai; } // Disable accidentally unlocking of a challenge @@ -420,7 +426,7 @@ void TrackInfoScreen::eventCallback(Widget* widget, const std::string& name, { m_ai_kart_spinner->setActive(false); race_manager->setNumKarts(race_manager->getNumLocalPlayers()); - UserConfigParams::m_num_karts = race_manager->getNumLocalPlayers(); + UserConfigParams::m_num_karts_per_gamemode[race_manager->getMinorMode()] = race_manager->getNumLocalPlayers(); } else { @@ -439,7 +445,7 @@ void TrackInfoScreen::eventCallback(Widget* widget, const std::string& name, { const int num_ai = m_ai_kart_spinner->getValue(); race_manager->setNumKarts( race_manager->getNumLocalPlayers() + num_ai ); - UserConfigParams::m_num_karts = race_manager->getNumLocalPlayers() + num_ai; + UserConfigParams::m_num_karts_per_gamemode[race_manager->getMinorMode()] = race_manager->getNumLocalPlayers() + num_ai; updateHighScores(); } } // eventCallback diff --git a/src/states_screens/user_screen.cpp b/src/states_screens/user_screen.cpp index 91071c59709..c9ef957ee41 100644 --- a/src/states_screens/user_screen.cpp +++ b/src/states_screens/user_screen.cpp @@ -400,7 +400,7 @@ void BaseUserScreen::eventCallback(Widget* widget, */ void BaseUserScreen::closeScreen() { - StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); + StateManager::get()->popMenu(); } // closeScreen // ---------------------------------------------------------------------------- diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index f29266e268c..48818f4bd17 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -466,6 +466,7 @@ void Track::cleanup() } #endif + m_meta_library.clear(); Scripting::ScriptEngine::getInstance()->cleanupCache(); m_current_track = NULL; @@ -1570,6 +1571,39 @@ void Track::createWater(const XMLNode &node) scene_node->getMaterial(0).setFlag(video::EMF_GOURAUD_SHADING, true); } // createWater +// ---------------------------------------------------------------------------- +static void recursiveUpdatePosition(scene::ISceneNode *node) +{ + node->updateAbsolutePosition(); + + scene::ISceneNodeList::ConstIterator it = node->getChildren().begin(); + for (; it != node->getChildren().end(); ++it) + { + recursiveUpdatePosition(*it); + } +} // recursiveUpdatePosition + +// ---------------------------------------------------------------------------- +static void recursiveUpdatePhysics(std::vector& tos) +{ + for (TrackObject* to : tos) + { + if (to->getPhysicalObject()) + { + TrackObjectPresentationSceneNode* sn = to + ->getPresentation(); + if (sn) + { + to->getPhysicalObject()->move( + sn->getNode()->getAbsoluteTransformation().getTranslation(), + sn->getNode()->getAbsoluteTransformation() + .getRotationDegrees()); + } + } + recursiveUpdatePhysics(to->getChildren()); + } +} // recursiveUpdatePhysics + // ---------------------------------------------------------------------------- /** This function load the actual scene, i.e. all parts of the track, * animations, items, ... It is called from world during initialisation. @@ -1757,6 +1791,19 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) loadObjects(root, path, model_def_loader, true, NULL, NULL); + // Correct the parenting of meta library + for (auto& p : m_meta_library) + { + auto* ln = p.first->getPresentation(); + assert(ln); + TrackObjectPresentationLibraryNode* meta_ln = p.second + ->getPresentation(); + assert(meta_ln); + meta_ln->getNode()->setParent(ln->getNode()); + recursiveUpdatePosition(meta_ln->getNode()); + recursiveUpdatePhysics(p.second->getChildren()); + } + model_def_loader.cleanLibraryNodesAfterLoad(); Scripting::ScriptEngine::getInstance()->compileLoadedScripts(); diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index a0d5a5adb6a..f050f5959f6 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -374,6 +374,8 @@ class Track /** List of all bezier curves in the track - for e.g. camera, ... */ std::vector m_all_curves; + std::vector > m_meta_library; + /** The number of laps the track will be raced in a random GP. * m_actual_number_of_laps is initialised with this value.*/ int m_default_number_of_laps; @@ -672,6 +674,10 @@ class Track // ------------------------------------------------------------------------ /** Adds mesh to cleanup list */ void addCachedMesh(scene::IMesh* mesh) { m_all_cached_meshes.push_back(mesh); } + // ------------------------------------------------------------------------ + /** Adds the parent of the meta library for correction later */ + void addMetaLibrary(TrackObject* parent, TrackObject* meta_library) + { m_meta_library.emplace_back(parent, meta_library); } }; // class Track #endif diff --git a/src/tracks/track_object.cpp b/src/tracks/track_object.cpp index 0d441d12341..255f001297c 100644 --- a/src/tracks/track_object.cpp +++ b/src/tracks/track_object.cpp @@ -31,6 +31,7 @@ #include "physics/physical_object.hpp" #include "race/race_manager.hpp" #include "scriptengine/script_engine.hpp" +#include "tracks/track.hpp" #include "tracks/model_definition_loader.hpp" #include @@ -160,6 +161,10 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent, { xml_node.get("name", &m_name); m_presentation = new TrackObjectPresentationLibraryNode(this, xml_node, model_def_loader); + if (parent_library != NULL) + { + Track::getCurrentTrack()->addMetaLibrary(parent_library, this); + } } else if (type == "sfx-emitter") { diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 414106b1b6f..5fe1e839c0f 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -180,6 +180,7 @@ TrackObjectPresentationLibraryNode::TrackObjectPresentationLibraryNode( { m_parent = NULL; m_start_executed = false; + m_reset_executed = false; std::string name; xml_node.get("name", &name); @@ -289,6 +290,22 @@ void TrackObjectPresentationLibraryNode::update(float dt) m_start_executed = true; std::string fn_name = StringUtils::insertValues("void %s::onStart(const string)", m_name.c_str()); + if (m_parent != NULL) + { + std::string lib_id = m_parent->getID(); + std::string* lib_id_ptr = &lib_id; + + Scripting::ScriptEngine::getInstance()->runFunction(false, fn_name, + [&](asIScriptContext* ctx) { + ctx->SetArgObject(0, lib_id_ptr); + }); + } + } + if (!m_reset_executed) + { + m_reset_executed = true; + std::string fn_name = StringUtils::insertValues("void %s::onReset(const string)", m_name.c_str()); + if (m_parent != NULL) { std::string lib_id = m_parent->getID(); diff --git a/src/tracks/track_object_presentation.hpp b/src/tracks/track_object_presentation.hpp index a2eedf32ac2..4a990b29650 100644 --- a/src/tracks/track_object_presentation.hpp +++ b/src/tracks/track_object_presentation.hpp @@ -187,13 +187,18 @@ class TrackObjectPresentationLibraryNode : public TrackObjectPresentationSceneNo TrackObject* m_parent; using TrackObjectPresentationSceneNode::move; std::string m_name; - bool m_start_executed; + bool m_start_executed, m_reset_executed; public: TrackObjectPresentationLibraryNode(TrackObject* parent, const XMLNode& xml_node, ModelDefinitionLoader& model_def_loader); virtual ~TrackObjectPresentationLibraryNode(); - virtual void update(float dt); + virtual void update(float dt) OVERRIDE; + virtual void reset() OVERRIDE + { + m_reset_executed = false; + TrackObjectPresentationSceneNode::reset(); + } void move(const core::vector3df& xyz, const core::vector3df& hpr, const core::vector3df& scale, bool isAbsoluteCoord, bool moveChildrenPhysicalBodies); }; // TrackObjectPresentationLibraryNode diff --git a/src/utils/log.cpp b/src/utils/log.cpp index e5d39167e83..d9c25e7bf53 100644 --- a/src/utils/log.cpp +++ b/src/utils/log.cpp @@ -35,6 +35,9 @@ Log::LogLevel Log::m_min_log_level = Log::LL_VERBOSE; bool Log::m_no_colors = false; FILE* Log::m_file_stdout = NULL; +std::string Log::m_prefix = ""; +size_t Log::m_buffer_size = 1; +Synchronised > Log::m_line_buffer; // ---------------------------------------------------------------------------- /** Selects background/foreground colors for the message depending on @@ -106,25 +109,22 @@ void Log::setTerminalColor(LogLevel level) */ void Log::resetTerminalColor() { - if(m_no_colors) - { - printf("\n"); - return; - } - + if(m_no_colors) return; #ifdef WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), /*TERM_BLACK*/0 << 4 | /*TERM_LIGHTGRAY*/7); - printf("\n"); #else - printf("%c[0;;m\n", 0x1B); + printf("%c[0;;m", 0x1B); #endif } // resetTerminalColor // ---------------------------------------------------------------------------- -/** This actually prints the log message. If log messages are not redirected - * to a file, it tries to select a terminal colour. +/** This actually creates a log message. If the messages are to be buffered, + * it will be appended to the output buffer. If the buffer is full, it will + * be flushed. If the message is not to be buffered, it will be immediately + * written using writeLine(). + * \param level Log level of the message to print. * \param format A printf-like format string. * \param va_list The values to be printed for the format. @@ -132,105 +132,119 @@ void Log::resetTerminalColor() void Log::printMessage(int level, const char *component, const char *format, VALIST args) { - assert(level>=0 && level <=LL_FATAL); + assert(level >= 0 && level <= LL_FATAL); - if(level= LL_WARN || + if (!m_file_stdout || level >= LL_WARN || UserConfigParams::m_log_errors_to_console) // log to console & file { - VALIST out; - va_copy(out, args); - setTerminalColor((LogLevel)level); - #ifdef ANDROID - __android_log_vprint(alp, "SuperTuxKart", format, out); - #else - printf("[%s] %s: ", names[level], component); - vprintf(format, out); - #endif +#ifdef ANDROID + android_LogPriority alp; + switch (level) + { + // STK is using the levels slightly different from android + // (debug lowest, verbose above it; while android reverses + // this order. So to get the same behaviour (e.g. filter + // out debug message, but still get verbose, we swap + // the order here. + case LL_VERBOSE: alp = ANDROID_LOG_DEBUG; break; + case LL_DEBUG: alp = ANDROID_LOG_VERBOSE; break; + case LL_INFO: alp = ANDROID_LOG_INFO; break; + case LL_WARN: alp = ANDROID_LOG_WARN; break; + case LL_ERROR: alp = ANDROID_LOG_ERROR; break; + case LL_FATAL: alp = ANDROID_LOG_FATAL; break; + default: alp = ANDROID_LOG_FATAL; + } + __android_log_print(alp, "SuperTuxKart", "%s", line); +#else + printf(line); +#endif resetTerminalColor(); // this prints a \n - - va_end(out); } #if defined(_MSC_FULL_VER) && defined(_DEBUG) - static char szBuff[2048]; - vsnprintf(szBuff, sizeof(szBuff), format, copy2); - - OutputDebugString("["); - OutputDebugString(names[level]); - OutputDebugString("] "); - OutputDebugString(component); - OutputDebugString(": "); - OutputDebugString(szBuff); - OutputDebugString("\r\n"); + OutputDebugString(line); #endif - - if(m_file_stdout) - { - fprintf (m_file_stdout, "[%s] %s: ", names[level], component); - vfprintf(m_file_stdout, format, copy); - fprintf (m_file_stdout, "\n"); - va_end(copy); - } + if (m_file_stdout) fprintf(m_file_stdout, "%s", line); #ifdef WIN32 if (level >= LL_FATAL) { - std::string message; - - char tmp[2048]; - sprintf(tmp, "[%s] %s: ", names[level], component); - message += tmp; - - VALIST out; - va_copy(out, args); - vsprintf(tmp, format, out); - message += tmp; - va_end(out); - - MessageBoxA(NULL, message.c_str(), "SuperTuxKart - Fatal error", MB_OK); + MessageBoxA(NULL, line, "SuperTuxKart - Fatal error", MB_OK); } #endif -} // printMessage +} // _fluhBuffers +// ---------------------------------------------------------------------------- +/** Flushes all stored log messages to the various output devices (thread safe). + */ +void Log::flushBuffers() +{ + m_line_buffer.lock(); + for (unsigned int i = 0; i < m_line_buffer.getData().size(); i++) + { + const LineInfo &li = m_line_buffer.getData()[i]; + writeLine(li.m_line.c_str(), li.m_level); + } + m_line_buffer.getData().clear(); + m_line_buffer.unlock(); +} // flushBuffers // ---------------------------------------------------------------------------- /** This function opens the files that will contain the output. diff --git a/src/utils/log.hpp b/src/utils/log.hpp index 61726cb8b5f..1d5ceb5bcdb 100644 --- a/src/utils/log.hpp +++ b/src/utils/log.hpp @@ -20,11 +20,15 @@ #ifndef HEADER_LOG_HPP #define HEADER_LOG_HPP +#include "utils/synchronised.hpp" + #include #include #include #include #include +#include + #ifdef __GNUC__ # define VALIST __gnuc_va_list @@ -59,13 +63,30 @@ class Log /** The file where stdout output will be written */ static FILE* m_file_stdout; + /** An optional buffer for lines to be output. */ + struct LineInfo + { + std::string m_line; + int m_level; + }; + static Synchronised > m_line_buffer; + + /** <0 if no buffered logging is to be used, otherwise this is + ** the maximum number of lines the buffer should hold. */ + static size_t m_buffer_size; + + /** An optional prefix to be printed. */ + static std::string m_prefix; + static void setTerminalColor(LogLevel level); static void resetTerminalColor(); - -public: + static void writeLine(const char *line, int level); static void printMessage(int level, const char *component, const char *format, VALIST va_list); + +public: + // ------------------------------------------------------------------------ /** A simple macro to define the various log functions. * Note that an assert is added so that a debugger is triggered @@ -95,7 +116,12 @@ class Log static void openOutputFiles(const std::string &logout); static void closeOutputFiles(); + static void flushBuffers(); + // ------------------------------------------------------------------------ + /** Sets the number of lines to buffer. Setting the buffer size to a + * a value <=1 means no buffering, lines will be immediately printed. */ + static void setBufferSize(size_t n) { m_buffer_size = n; } // ------------------------------------------------------------------------ /** Defines the minimum log level to be displayed. */ static void setLogLevel(int n) @@ -120,5 +146,9 @@ class Log { m_no_colors = true; } // disableColor + // ------------------------------------------------------------------------ + /** Sets a prefix to be printed before each line. To disable the prefix, + * set it to "". */ + static void setPrefix(const std::string &prefix) { m_prefix = prefix; } }; // Log #endif diff --git a/tools/windows_installer/supertuxkart-64bit.nsi b/tools/windows_installer/supertuxkart-64bit.nsi index 5d4f5aaad83..c53a1d4ea30 100755 --- a/tools/windows_installer/supertuxkart-64bit.nsi +++ b/tools/windows_installer/supertuxkart-64bit.nsi @@ -43,7 +43,7 @@ !define DESCRIPTION "3D open-source arcade racer with a variety characters, tracks, and modes to play" Name "${APPNAMEANDVERSION}" - OutFile "${APPNAMEANDVERSION} installer.exe" + OutFile "${APPNAMEANDVERSION} installer-64bit.exe" # These will be displayed by the "Click here for support information" link in "Add/Remove Programs" # It is possible to use "mailto:" links in here to open the email client @@ -174,12 +174,12 @@ Section "Install" SecMain ; Try to find the binary directory in a list of 'typical' names: ; The first found directory is used - ${!setIfUndefinedAndExists} EXEC_PATH ..\..\bld\bin\RelWithDebInfo\*.* - ${!setIfUndefinedAndExists} EXEC_PATH ..\..\bld\bin\Release\*.* - ${!setIfUndefinedAndExists} EXEC_PATH ..\..\build\bin\RelWithDebInfo\*.* - ${!setIfUndefinedAndExists} EXEC_PATH ..\..\build\bin\Release\*.* - ${!setIfUndefinedAndExists} EXEC_PATH ..\..\cmake_build\bin\RelWithDebInfo\*.* - ${!setIfUndefinedAndExists} EXEC_PATH ..\..\cmake_build\bin\Release\*.* + ${!setIfUndefinedAndExists} EXEC_PATH ..\..\bld-64\bin\RelWithDebInfo\*.* + ${!setIfUndefinedAndExists} EXEC_PATH ..\..\bld-64\bin\Release\*.* + ${!setIfUndefinedAndExists} EXEC_PATH ..\..\build-64\bin\RelWithDebInfo\*.* + ${!setIfUndefinedAndExists} EXEC_PATH ..\..\build-64\bin\Release\*.* + ${!setIfUndefinedAndExists} EXEC_PATH ..\..\cmake_build-64\bin\RelWithDebInfo\*.* + ${!setIfUndefinedAndExists} EXEC_PATH ..\..\cmake_build-64\bin\Release\*.* File /x *.ilk ${EXEC_PATH} @@ -206,7 +206,7 @@ Section "Install" SecMain File *.ico ; prereqs SetOutPath "$INSTDIR\prerequisites" - File /r prerequisites\*.* + File /r prerequisites\vcredist_x64.exe ; data + assets SetOutPath "$INSTDIR\data\" @@ -281,7 +281,6 @@ Section "Uninstall" redist DELETE /REBOOTOK "$INSTDIR\icon.ico" DELETE /REBOOTOK "$INSTDIR\libcurl-4.dll" DELETE /REBOOTOK "$INSTDIR\libeay32.dll" - DELETE /REBOOTOK "$INSTDIR\libidn-11.dll" DELETE /REBOOTOK "$INSTDIR\License.txt" DELETE /REBOOTOK "$INSTDIR\libfreetype.dll" DELETE /REBOOTOK "$INSTDIR\libfribidi-0.dll" diff --git a/tools/windows_installer/supertuxkart.nsi b/tools/windows_installer/supertuxkart.nsi index 4b9aefb22fb..89e4e498f8d 100755 --- a/tools/windows_installer/supertuxkart.nsi +++ b/tools/windows_installer/supertuxkart.nsi @@ -35,7 +35,7 @@ !define VERSION_MINOR 9 !define VERSION_REVISION 3 ; Empty means stable, could be -git, -rc1 - !define VERSION_BUILD "-rc1" + !define VERSION_BUILD "-git" ;Name and file !define APPNAME "SuperTuxKart" @@ -43,7 +43,7 @@ !define DESCRIPTION "3D open-source arcade racer with a variety characters, tracks, and modes to play" Name "${APPNAMEANDVERSION}" - OutFile "${APPNAMEANDVERSION} installer.exe" + OutFile "${APPNAMEANDVERSION} installer-32bit.exe" # These will be displayed by the "Click here for support information" link in "Add/Remove Programs" # It is possible to use "mailto:" links in here to open the email client @@ -206,7 +206,7 @@ Section "Install" SecMain File *.ico ; prereqs SetOutPath "$INSTDIR\prerequisites" - File /r prerequisites\*.* + File /r prerequisites\vcredist_x86.exe ; data + assets SetOutPath "$INSTDIR\data\"