From a96763cd1d6cfb06016a64eeb01ea93899b4aea5 Mon Sep 17 00:00:00 2001 From: Benau Date: Mon, 13 Sep 2021 16:54:29 +0800 Subject: [PATCH] Make sure starting position is valid for spare tire karts Fix #4615 --- src/modes/three_strikes_battle.cpp | 63 +++++++++++++++++++++++------- src/tracks/track.cpp | 29 +++++++++----- src/tracks/track.hpp | 2 +- 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp index 557c1a821..5436bd0bb 100644 --- a/src/modes/three_strikes_battle.cpp +++ b/src/modes/three_strikes_battle.cpp @@ -33,6 +33,7 @@ #include "states_screens/race_gui_base.hpp" #include "tracks/arena_graph.hpp" #include "tracks/arena_node.hpp" +#include "tracks/terrain_info.hpp" #include "tracks/track.hpp" #include "tracks/track_object_manager.hpp" #include "utils/constants.hpp" @@ -40,6 +41,7 @@ #include "utils/translation.hpp" #include +#include #include #include @@ -669,7 +671,9 @@ void ThreeStrikesBattle::loadCustomModels() // Don't create too many spare tire karts const unsigned int max_sta_num = unsigned(m_karts.size() * 0.8f); unsigned int pos_created = 0; - std::vector used; + std::deque sta_possible_nodes; + for (int i = 0; i < all_nodes; i++) + sta_possible_nodes.push_back(i); std::vector pos; // Fill all current starting position into used first @@ -679,31 +683,62 @@ void ThreeStrikesBattle::loadCustomModels() ag->findRoadSector(getRescueTransform(i).getOrigin(), &node, NULL, true); assert(node != -1); - used.push_back(node); + sta_possible_nodes.erase(std::remove_if( + sta_possible_nodes.begin(), sta_possible_nodes.end(), + [node](const int n) { return n == node; }), + sta_possible_nodes.end()); } // Find random nodes to pre-spawn spare tire karts - RandomGenerator random; - while (true) + std::random_shuffle(sta_possible_nodes.begin(), + sta_possible_nodes.end()); + + // Compute a random kart list + std::vector sta_list; + kart_properties_manager->getRandomKartList(max_sta_num, NULL, + &sta_list); + if (sta_list.size() != max_sta_num) + return; + + TerrainInfo terrain; + while (!sta_possible_nodes.empty()) { - const int node = random.get(all_nodes); - if (std::find(used.begin(), used.end(), node) != used.end()) - continue; + const int node = sta_possible_nodes.front(); const ArenaNode* n = ag->getNode(node); btTransform t; t.setOrigin(n->getCenter()); t.setRotation(shortestArcQuat(Vec3(0, 1, 0), n->getNormal())); + + // Make sure starting position is valid for spare tire karts, + // see #4615 + terrain.update(t.getBasis(), + t.getOrigin() + t.getBasis() * Vec3(0, 0.3f, 0)); + Vec3 from = (Vec3)t.getOrigin(); + const KartProperties* kp = kart_properties_manager->getKart( + sta_list[pos.size()]); + if (!kp) + return; + float kh = kp->getMasterKartModel().getHeight(); + //start projection from top of kart + Vec3 up_offset = terrain.getNormal() * (0.5f * kh); + from += up_offset; + Vec3 down = t.getBasis() * Vec3(0, -10000.0f, 0); + + Vec3 hit_point, normal; + if (!Track::getCurrentTrack()->isOnGround(from, down, + &hit_point, &normal, false/*print_warning*/)) + { + sta_possible_nodes.pop_front(); + continue; + } pos.push_back(t); pos_created++; - used.push_back(node); - if (pos_created >= max_sta_num) break; + sta_possible_nodes.pop_front(); + if (pos_created == max_sta_num) break; } - // Compute a random kart list - std::vector sta_list; - kart_properties_manager->getRandomKartList((int)pos.size(), NULL, - &sta_list); - + if (pos_created != max_sta_num) + return; assert(sta_list.size() == pos.size()); // Now add them for (unsigned int i = 0; i < pos.size(); i++) diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index bd3e853dd..bdb537f62 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -2735,7 +2735,7 @@ const core::vector3df& Track::getSunRotation() //----------------------------------------------------------------------------- bool Track::isOnGround(const Vec3& xyz, const Vec3& down, Vec3* hit_point, - Vec3* normal) + Vec3* normal, bool print_warning) { // Material and hit point are not needed; const Material *m; @@ -2751,8 +2751,11 @@ bool Track::isOnGround(const Vec3& xyz, const Vec3& down, Vec3* hit_point, if (!over_ground && !over_driveable) { - Log::warn("physics", "Kart at (%f %f %f) can not be dropped.", - xyz.getX(),xyz.getY(),xyz.getZ()); + if (print_warning) + { + Log::warn("physics", "Kart at (%f %f %f) can not be dropped.", + xyz.getX(),xyz.getY(),xyz.getZ()); + } return false; } @@ -2760,9 +2763,12 @@ bool Track::isOnGround(const Vec3& xyz, const Vec3& down, Vec3* hit_point, // a reset. If so, this is not a valid position. if(m && m->isDriveReset()) { - Log::warn("physics","Kart at (%f %f %f) over reset terrain '%s'", - xyz.getX(),xyz.getY(),xyz.getZ(), - m->getTexFname().c_str()); + if (print_warning) + { + Log::warn("physics","Kart at (%f %f %f) over reset terrain '%s'", + xyz.getX(),xyz.getY(),xyz.getZ(), + m->getTexFname().c_str()); + } return false; } @@ -2770,10 +2776,13 @@ bool Track::isOnGround(const Vec3& xyz, const Vec3& down, Vec3* hit_point, // too long. if(xyz.getY() - hit_point->getY() > 5) { - Log::warn("physics", - "Kart at (%f %f %f) is too high above ground at (%f %f %f)", - xyz.getX(),xyz.getY(),xyz.getZ(), - hit_point->getX(),hit_point->getY(),hit_point->getZ()); + if (print_warning) + { + Log::warn("physics", + "Kart at (%f %f %f) is too high above ground at (%f %f %f)", + xyz.getX(),xyz.getY(),xyz.getZ(), + hit_point->getX(),hit_point->getY(),hit_point->getZ()); + } return false; } return true; diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index c9b913345..8b3767529 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -731,7 +731,7 @@ public: ItemManager* getItemManager() const { return m_item_manager.get(); } // ------------------------------------------------------------------------ bool isOnGround(const Vec3& xyz, const Vec3& down, Vec3* hit_point, - Vec3* normal); + Vec3* normal, bool print_warning = true); }; // class Track #endif