From 7799e9835dfc056df5bf4a2ddd747e5bf638bdbd Mon Sep 17 00:00:00 2001
From: hiker <henrichsjoerg@gmail.com>
Date: Thu, 30 Jul 2015 17:12:48 +1000
Subject: [PATCH 1/8] Added a getStartTransform function to World. Use this to
 change the start position of the non-leader karts in a FTL race, so that
 those karts now start at the end of all start positions, and not directly
 behind the leader.

---
 src/modes/cutscene_world.cpp       |  5 -----
 src/modes/follow_the_leader.cpp    | 14 +++++++++++++-
 src/modes/follow_the_leader.hpp    |  9 +++++++--
 src/modes/profile_world.cpp        |  2 +-
 src/modes/soccer_world.cpp         |  6 +++---
 src/modes/three_strikes_battle.cpp |  2 +-
 src/modes/world.cpp                | 12 ++++++++++--
 src/modes/world.hpp                |  1 +
 src/modes/world_with_rank.cpp      |  2 +-
 src/tracks/track.cpp               |  9 ++++++++-
 src/tracks/track.hpp               |  2 +-
 11 files changed, 46 insertions(+), 18 deletions(-)

diff --git a/src/modes/cutscene_world.cpp b/src/modes/cutscene_world.cpp
index a10ec95af..e3f12e79d 100644
--- a/src/modes/cutscene_world.cpp
+++ b/src/modes/cutscene_world.cpp
@@ -77,13 +77,8 @@ void CutsceneWorld::init()
 
     m_duration = -1.0f;
 
-    //const btTransform &s = getTrack()->getStartTransform(0);
-    //const Vec3 &v = s.getOrigin();
     Camera* stk_cam = Camera::createCamera(NULL);
     m_camera = stk_cam->getCameraSceneNode();
-    //m_camera = irr_driver->getSceneManager()
-    //         ->addCameraSceneNode(NULL, core::vector3df(0.0f, 0.0f, 0.0f),
-    //                              core::vector3df(0.0f, 0.0f, 0.0f));
     m_camera->setFOV(0.61f);
     m_camera->bindTargetAndRotation(true); // no "look-at"
 
diff --git a/src/modes/follow_the_leader.cpp b/src/modes/follow_the_leader.cpp
index 00ca1e942..7b29a8653 100644
--- a/src/modes/follow_the_leader.cpp
+++ b/src/modes/follow_the_leader.cpp
@@ -101,11 +101,23 @@ int FollowTheLeaderRace::getScoreForPosition(int p)
     return m_score_for_position[p - 2];
 }   // getScoreForPosition
 
+//-----------------------------------------------------------------------------
+const btTransform &FollowTheLeaderRace::getStartTransform(int index)
+{
+    if (index == 0)   // Leader start position
+        return m_track->getStartTransform(index);
+
+    // Otherwise the karts will start at the rear starting positions
+    int start_index = stk_config->m_max_karts
+                    - race_manager->getNumberOfKarts() + index;
+    return m_track->getStartTransform(start_index);
+}   // getStartTransform
+
 //-----------------------------------------------------------------------------
 /** Returns the original time at which the countdown timer started. This is
  *  used by the race_gui to display the music credits in FTL mode correctly.
  */
-float FollowTheLeaderRace::getClockStartTime()
+float FollowTheLeaderRace::getClockStartTime() const
 {
     return m_leader_intervals[0];
 }   // getClockStartTime
diff --git a/src/modes/follow_the_leader.hpp b/src/modes/follow_the_leader.hpp
index 939f54129..da5fe1f6d 100644
--- a/src/modes/follow_the_leader.hpp
+++ b/src/modes/follow_the_leader.hpp
@@ -48,14 +48,19 @@ public:
     // overriding World methods
     virtual void reset() OVERRIDE;
     virtual const std::string& getIdent() const OVERRIDE;
-    virtual float getClockStartTime();
-    virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
+    virtual const btTransform &getStartTransform(int index);
+    virtual float getClockStartTime() const;
     virtual void getKartsDisplayInfo(
                  std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
     virtual void init() OVERRIDE;
     virtual void terminateRace() OVERRIDE;
     virtual bool isRaceOver() OVERRIDE;
+    // ------------------------------------------------------------------------
+    /** Returns if this type of race has laps. */
     virtual bool raceHasLaps() OVERRIDE { return false; }
+    // ------------------------------------------------------------------------
+    /** Returns if faster music should be used at the end. */
+    virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
 };   // FollowTheLeader
 
 
diff --git a/src/modes/profile_world.cpp b/src/modes/profile_world.cpp
index 0fef5edc7..7015a7b13 100644
--- a/src/modes/profile_world.cpp
+++ b/src/modes/profile_world.cpp
@@ -108,7 +108,7 @@ AbstractKart *ProfileWorld::createKart(const std::string &kart_ident, int index,
                                        RaceManager::KartType type,
                                        const PlayerDifficulty *difficulty)
 {
-    btTransform init_pos   = m_track->getStartTransform(index);
+    btTransform init_pos   = getStartTransform(index);
 
     Kart *new_kart         = new KartWithStats(kart_ident,
                                                /*world kart id*/ index,
diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp
index dcba80e8c..0fc8f553c 100644
--- a/src/modes/soccer_world.cpp
+++ b/src/modes/soccer_world.cpp
@@ -336,7 +336,7 @@ void SoccerWorld::moveKartAfterRescue(AbstractKart* kart)
     {
         // no need for the overhead to compute exact distance with sqrt(),
         // so using the 'manhattan' heuristic which will do fine enough.
-        const btTransform &s = world->getTrack()->getStartTransform(n);
+        const btTransform &s = getStartTransform(n);
         const Vec3 &v=s.getOrigin();
         float accumulatedDistance = .0f;
         bool spawnPointClear = true;
@@ -368,7 +368,7 @@ void SoccerWorld::moveKartAfterRescue(AbstractKart* kart)
     }
 
     assert(furthest_id_found != -1);
-    const btTransform &s = world->getTrack()->getStartTransform(furthest_id_found);
+    const btTransform &s = getStartTransform(furthest_id_found);
     const Vec3 &xyz = s.getOrigin();
     kart->setXYZ(xyz);
     kart->setRotation(s.getRotation());
@@ -481,7 +481,7 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
         if(index % 2 != 0) posIndex += 1;
     }
 
-    btTransform init_pos = m_track->getStartTransform(posIndex);
+    btTransform init_pos = getStartTransform(posIndex);
 
     AbstractKart *new_kart = new Kart(kart_ident, index, position, init_pos,
             difficulty);
diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp
index aa95da191..d24555bf8 100644
--- a/src/modes/three_strikes_battle.cpp
+++ b/src/modes/three_strikes_battle.cpp
@@ -497,7 +497,7 @@ unsigned int ThreeStrikesBattle::getRescuePositionIndex(AbstractKart *kart)
 
     for(int n=0; n<start_spots_amount; n++)
     {
-        const btTransform &s = getTrack()->getStartTransform(n);
+        const btTransform &s = getStartTransform(n);
         const Vec3 &v=s.getOrigin();
         float accumulated_distance = .0f;
         bool spawn_point_clear = true;
diff --git a/src/modes/world.cpp b/src/modes/world.cpp
index f636fe2f2..4224b1763 100644
--- a/src/modes/world.cpp
+++ b/src/modes/world.cpp
@@ -305,9 +305,9 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
                                 const PlayerDifficulty *difficulty)
 {
     int position           = index+1;
-    btTransform init_pos   = m_track->getStartTransform(index);
+    btTransform init_pos   = getStartTransform(index);
     AbstractKart *new_kart = new Kart(kart_ident, index, position, init_pos,
-            difficulty);
+                                      difficulty);
     new_kart->init(race_manager->getKartType(index));
     Controller *controller = NULL;
     switch(kart_type)
@@ -337,6 +337,14 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
     return new_kart;
 }   // createKart
 
+//-----------------------------------------------------------------------------
+/** Returns the start coordinates for a kart with a given index.
+ *  \param index Index of kart ranging from 0 to kart_num-1. */
+const btTransform &World::getStartTransform(int index)
+{
+    return m_track->getStartTransform(index);
+}   // getStartTransform
+
 //-----------------------------------------------------------------------------
 /** Creates an AI controller for the kart.
  *  \param kart The kart to be controlled by an AI.
diff --git a/src/modes/world.hpp b/src/modes/world.hpp
index fef41591b..94c6ccb39 100644
--- a/src/modes/world.hpp
+++ b/src/modes/world.hpp
@@ -294,6 +294,7 @@ public:
                                     PhysicalObject *object);
     AbstractKart*   getPlayerKart(unsigned int player) const;
     AbstractKart*   getLocalPlayerKart(unsigned int n) const;
+    virtual const btTransform &getStartTransform(int index);
     // ------------------------------------------------------------------------
     /** Returns a pointer to the race gui. */
     RaceGUIBase    *getRaceGUI() const { return m_race_gui;}
diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp
index e34a4fe91..9482d1f95 100644
--- a/src/modes/world_with_rank.cpp
+++ b/src/modes/world_with_rank.cpp
@@ -149,7 +149,7 @@ unsigned int WorldWithRank::getRescuePositionIndex(AbstractKart *kart)
 
     for (int n=0; n<start_spots_amount; n++)
     {
-        const btTransform &s = getTrack()->getStartTransform(n);
+        const btTransform &s = getStartTransform(n);
         const Vec3 &v = s.getOrigin();
 
         float abs_distance = (v - kart->getXYZ()).length();
diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp
index 89b3aa614..9880be647 100644
--- a/src/tracks/track.cpp
+++ b/src/tracks/track.cpp
@@ -1736,7 +1736,14 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
 
     if (!m_is_arena && !m_is_soccer && !m_is_cutscene)
     {
-        m_start_transforms.resize(race_manager->getNumberOfKarts());
+        if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
+        {
+            // In a FTL race the non-leader karts are placed at the end of the
+            // field, so we need all start positions.
+            m_start_transforms.resize(stk_config->m_max_karts);
+        }
+        else
+            m_start_transforms.resize(race_manager->getNumberOfKarts());
         QuadGraph::get()->setDefaultStartPositions(&m_start_transforms,
                                                    karts_per_row,
                                                    forwards_distance,
diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp
index 23b88e997..5ac4daa79 100644
--- a/src/tracks/track.hpp
+++ b/src/tracks/track.hpp
@@ -523,7 +523,7 @@ public:
     // ------------------------------------------------------------------------
     /** Returns the start coordinates for a kart with a given index.
      *  \param index Index of kart ranging from 0 to kart_num-1. */
-    btTransform        getStartTransform (unsigned int index) const
+    const btTransform& getStartTransform (unsigned int index) const
     {
         if (index >= m_start_transforms.size())
             Log::fatal("Track", "No start position for kart %i.", index);

From bf858dd3ff84c43fde59b2aa5055e75257f871bb Mon Sep 17 00:00:00 2001
From: hiker <henrichsjoerg@gmail.com>
Date: Thu, 30 Jul 2015 17:14:18 +1000
Subject: [PATCH 2/8] Fixed compiler warning.

---
 src/guiengine/widgets/icon_button_widget.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp
index 587527738..9093ec7e6 100644
--- a/src/guiengine/widgets/icon_button_widget.cpp
+++ b/src/guiengine/widgets/icon_button_widget.cpp
@@ -182,7 +182,7 @@ void IconButtonWidget::add()
                 x1 += diff;
                 x2 += diff;
             }
-            else if (x2 > irr_driver->getActualScreenSize().Width)
+            else if (x2 > (int)irr_driver->getActualScreenSize().Width)
             {
                 int diff = x2 - irr_driver->getActualScreenSize().Width;
                 x2 -= diff;

From a9761e30da60abc1576182cf9863f480c23106e8 Mon Sep 17 00:00:00 2001
From: Tobias Markus <tobbi.bugs@googlemail.com>
Date: Thu, 30 Jul 2015 18:46:01 +0200
Subject: [PATCH 3/8] Fix various issues reported by coverity

---
 src/states_screens/options_screen_audio.cpp  | 3 ++-
 src/states_screens/options_screen_input.cpp  | 3 ++-
 src/states_screens/options_screen_input2.cpp | 4 ++--
 src/states_screens/options_screen_ui.cpp     | 3 ++-
 src/states_screens/options_screen_video.cpp  | 3 ++-
 src/states_screens/user_screen.cpp           | 3 ++-
 6 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/states_screens/options_screen_audio.cpp b/src/states_screens/options_screen_audio.cpp
index 734c12a2d..799bab896 100644
--- a/src/states_screens/options_screen_audio.cpp
+++ b/src/states_screens/options_screen_audio.cpp
@@ -59,7 +59,8 @@ void OptionsScreenAudio::init()
 {
     Screen::init();
     RibbonWidget* ribbon = this->getWidget<RibbonWidget>("options_choice");
-    if (ribbon != NULL)  ribbon->select( "tab_audio", PLAYER_ID_GAME_MASTER );
+    assert(ribbon != NULL);
+    ribbon->select( "tab_audio", PLAYER_ID_GAME_MASTER );
 
     ribbon->getRibbonChildren()[0].setTooltip( _("Graphics") );
     ribbon->getRibbonChildren()[2].setTooltip( _("User Interface") );
diff --git a/src/states_screens/options_screen_input.cpp b/src/states_screens/options_screen_input.cpp
index 98aec63d1..7b8e970b6 100644
--- a/src/states_screens/options_screen_input.cpp
+++ b/src/states_screens/options_screen_input.cpp
@@ -133,7 +133,8 @@ void OptionsScreenInput::init()
 {
     Screen::init();
     RibbonWidget* tabBar = this->getWidget<RibbonWidget>("options_choice");
-    if (tabBar != NULL)  tabBar->select( "tab_controls", PLAYER_ID_GAME_MASTER );
+    assert(tabBar != NULL);
+    tabBar->select( "tab_controls", PLAYER_ID_GAME_MASTER );
 
     tabBar->getRibbonChildren()[0].setTooltip( _("Graphics") );
     tabBar->getRibbonChildren()[1].setTooltip( _("Audio") );
diff --git a/src/states_screens/options_screen_input2.cpp b/src/states_screens/options_screen_input2.cpp
index 3832765d2..363860e07 100644
--- a/src/states_screens/options_screen_input2.cpp
+++ b/src/states_screens/options_screen_input2.cpp
@@ -79,8 +79,8 @@ void OptionsScreenInput2::init()
 {
     Screen::init();
     RibbonWidget* tabBar = getWidget<RibbonWidget>("options_choice");
-    if (tabBar != NULL)  tabBar->select( "tab_controls",
-                                        PLAYER_ID_GAME_MASTER );
+    assert(tabBar != NULL);
+    tabBar->select( "tab_controls", PLAYER_ID_GAME_MASTER );
 
     tabBar->getRibbonChildren()[0].setTooltip( _("Graphics") );
     tabBar->getRibbonChildren()[1].setTooltip( _("Audio") );
diff --git a/src/states_screens/options_screen_ui.cpp b/src/states_screens/options_screen_ui.cpp
index 2358035d4..8d301eeaf 100644
--- a/src/states_screens/options_screen_ui.cpp
+++ b/src/states_screens/options_screen_ui.cpp
@@ -112,7 +112,8 @@ void OptionsScreenUI::init()
 {
     Screen::init();
     RibbonWidget* ribbon = getWidget<RibbonWidget>("options_choice");
-    if (ribbon != NULL)  ribbon->select( "tab_ui", PLAYER_ID_GAME_MASTER );
+    assert(ribbon != NULL);
+    ribbon->select( "tab_ui", PLAYER_ID_GAME_MASTER );
 
     ribbon->getRibbonChildren()[0].setTooltip( _("Graphics") );
     ribbon->getRibbonChildren()[1].setTooltip( _("Audio") );
diff --git a/src/states_screens/options_screen_video.cpp b/src/states_screens/options_screen_video.cpp
index 5981a9cce..6939a9e15 100644
--- a/src/states_screens/options_screen_video.cpp
+++ b/src/states_screens/options_screen_video.cpp
@@ -159,7 +159,8 @@ void OptionsScreenVideo::init()
 {
     Screen::init();
     RibbonWidget* ribbon = getWidget<RibbonWidget>("options_choice");
-    if (ribbon != NULL)  ribbon->select( "tab_video", PLAYER_ID_GAME_MASTER );
+    assert(ribbon != NULL);
+    ribbon->select( "tab_video", PLAYER_ID_GAME_MASTER );
 
     ribbon->getRibbonChildren()[1].setTooltip( _("Audio") );
     ribbon->getRibbonChildren()[2].setTooltip( _("User Interface") );
diff --git a/src/states_screens/user_screen.cpp b/src/states_screens/user_screen.cpp
index 7c7e7d3c0..64e846f4f 100644
--- a/src/states_screens/user_screen.cpp
+++ b/src/states_screens/user_screen.cpp
@@ -631,7 +631,8 @@ void BaseUserScreen::unloaded()
 void TabbedUserScreen::init()
 {
     RibbonWidget* tab_bar = getWidget<RibbonWidget>("options_choice");
-    if (tab_bar) tab_bar->select("tab_players", PLAYER_ID_GAME_MASTER);
+    assert(tab_bar != NULL);
+    tab_bar->select("tab_players", PLAYER_ID_GAME_MASTER);
     tab_bar->getRibbonChildren()[0].setTooltip( _("Graphics") );
     tab_bar->getRibbonChildren()[1].setTooltip( _("Audio") );
     tab_bar->getRibbonChildren()[2].setTooltip( _("User Interface") );

From 25c1880c183c0cb18ef4ae5bad7014e1a5d3f333 Mon Sep 17 00:00:00 2001
From: hiker <henrichsjoerg@gmail.com>
Date: Fri, 31 Jul 2015 07:49:54 +1000
Subject: [PATCH 4/8] Fixed rescue in soccer mode (which would previously used
 World's moveKartAfterRescue, not its own custom function).

---
 src/modes/world.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/modes/world.hpp b/src/modes/world.hpp
index 94c6ccb39..69e5bf538 100644
--- a/src/modes/world.hpp
+++ b/src/modes/world.hpp
@@ -231,7 +231,7 @@ public:
     /** Returns the bullet transformation for the specified rescue index. */
     virtual btTransform getRescueTransform(unsigned int index) const = 0;
     // ------------------------------------------------------------------------
-    void moveKartAfterRescue(AbstractKart* kart);
+    virtual void moveKartAfterRescue(AbstractKart* kart);
     // ------------------------------------------------------------------------
     /** Called when it is needed to know whether this kind of race involves
      *  counting laps. */

From 431853b451ee8e91ab6c207cd476509b6835957f Mon Sep 17 00:00:00 2001
From: hiker <henrichsjoerg@gmail.com>
Date: Fri, 31 Jul 2015 15:45:25 +1000
Subject: [PATCH 5/8] Removed some unused code, added better error message in
 case stk_config.xml could not be found.

---
 src/io/file_manager.cpp | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp
index ef193ae13..1ddf9271c 100644
--- a/src/io/file_manager.cpp
+++ b/src/io/file_manager.cpp
@@ -181,14 +181,22 @@ FileManager::FileManager()
     {
 #ifdef SUPERTUXKART_DATADIR
         root_dir = SUPERTUXKART_DATADIR"/data/";
-        if(root_dir.size()==0 || root_dir[root_dir.size()-1]!='/')
-            root_dir+='/';
-
 #else
         root_dir = "/usr/local/share/games/supertuxkart/";
 #endif
     }
 
+    if (!m_file_system->existFile((root_dir + "stk_config.xml").c_str()))
+    {
+        Log::error("FileManager", "Could not file stk_config.xml in any "
+                                  "standard location (esp. ../data).");
+        Log::error("FileManager", 
+                   "Last location checked '%s'.", root_dir.c_str());
+        Log::fatal("FileManager", 
+                   "Set $SUPERTUXKART_DATADIR to point to the data directory.");
+        // fatal will exit the application
+    }
+
     addRootDirs(root_dir);
     if( fileExists(root_dir+"../../stk-assets"))
         addRootDirs(root_dir+"../../stk-assets");

From a81366c4140ec5610c9d8fbfaf4b1b23720980e5 Mon Sep 17 00:00:00 2001
From: hiker <henrichsjoerg@gmail.com>
Date: Fri, 31 Jul 2015 16:27:52 +1000
Subject: [PATCH 6/8] Removed rescue-code duplication in battle mode and soccer
 mode.

---
 src/modes/overworld.cpp            | 31 +++++++++++
 src/modes/overworld.hpp            |  1 +
 src/modes/soccer_world.cpp         | 82 ------------------------------
 src/modes/soccer_world.hpp         |  3 +-
 src/modes/three_strikes_battle.cpp | 50 ------------------
 src/modes/three_strikes_battle.hpp |  1 -
 src/modes/world_with_rank.cpp      | 51 +++++++++++++------
 7 files changed, 68 insertions(+), 151 deletions(-)

diff --git a/src/modes/overworld.cpp b/src/modes/overworld.cpp
index 0f5166caa..ba7e7df2d 100644
--- a/src/modes/overworld.cpp
+++ b/src/modes/overworld.cpp
@@ -160,6 +160,37 @@ void OverWorld::update(float dt)
     }
 }   // update
 
+// ----------------------------------------------------------------------------
+/** Finds the starting position which is closest to the kart.
+ *  \param kart The kart for which a rescue position needs to be determined.
+ */
+unsigned int OverWorld::getRescuePositionIndex(AbstractKart *kart)
+{
+    // find closest point to drop kart on
+    const int start_spots_amount = getNumberOfRescuePositions();
+    assert(start_spots_amount > 0);
+
+    int closest_id = -1;
+    float closest_distance = 999999999.0f;
+
+    for (int n=0; n<start_spots_amount; n++)
+    {
+        const btTransform &s = getStartTransform(n);
+        const Vec3 &v = s.getOrigin();
+
+        float abs_distance = (v - kart->getXYZ()).length();
+
+        if (abs_distance < closest_distance)
+        {
+            closest_distance = abs_distance;
+            closest_id = n;
+        }
+    }
+
+    assert(closest_id != -1);
+    return closest_id;
+}   // getRescuePositionIndex
+
 //-----------------------------------------------------------------------------
 /** This function is not used in the overworld race gui.
  */
diff --git a/src/modes/overworld.hpp b/src/modes/overworld.hpp
index 4001f0faa..62d510994 100644
--- a/src/modes/overworld.hpp
+++ b/src/modes/overworld.hpp
@@ -48,6 +48,7 @@ public:
     static void enterOverWorld();
 
     virtual void  update(float delta) OVERRIDE;
+    unsigned int  getRescuePositionIndex(AbstractKart *kart) OVERRIDE;
     virtual void  getKartsDisplayInfo(
                  std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
     // ------------------------------------------------------------------------
diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp
index 0fc8f553c..2b18d14f6 100644
--- a/src/modes/soccer_world.cpp
+++ b/src/modes/soccer_world.cpp
@@ -315,88 +315,6 @@ void SoccerWorld::getKartsDisplayInfo(
     */
 }   // getKartsDisplayInfo
 
-//-----------------------------------------------------------------------------
-/** Moves a kart to its rescue position.
- *  \param kart The kart that was rescued.
- */
-void SoccerWorld::moveKartAfterRescue(AbstractKart* kart)
-{
-    // find closest point to drop kart on
-    World *world = World::getWorld();
-    const int start_spots_amount = world->getTrack()->getNumberOfStartPositions();
-    assert(start_spots_amount > 0);
-
-    float largest_accumulated_distance_found = -1;
-    int furthest_id_found = -1;
-
-    const float kart_x = kart->getXYZ().getX();
-    const float kart_z = kart->getXYZ().getZ();
-
-    for(int n=0; n<start_spots_amount; n++)
-    {
-        // no need for the overhead to compute exact distance with sqrt(),
-        // so using the 'manhattan' heuristic which will do fine enough.
-        const btTransform &s = getStartTransform(n);
-        const Vec3 &v=s.getOrigin();
-        float accumulatedDistance = .0f;
-        bool spawnPointClear = true;
-
-        for(unsigned int k=0; k<getCurrentNumKarts(); k++)
-        {
-            const AbstractKart *currentKart = World::getWorld()->getKart(k);
-            const float currentKart_x = currentKart->getXYZ().getX();
-            const float currentKartk_z = currentKart->getXYZ().getZ();
-
-            if(kart_x!=currentKart_x && kart_z !=currentKartk_z)
-            {
-                float absDistance = fabs(currentKart_x - v.getX()) +
-                                         fabs(currentKartk_z - v.getZ());
-                if(absDistance < CLEAR_SPAWN_RANGE)
-                {
-                    spawnPointClear = false;
-                    break;
-                }
-                accumulatedDistance += absDistance;
-            }
-        }
-
-        if(largest_accumulated_distance_found < accumulatedDistance && spawnPointClear)
-        {
-            furthest_id_found = n;
-            largest_accumulated_distance_found = accumulatedDistance;
-        }
-    }
-
-    assert(furthest_id_found != -1);
-    const btTransform &s = getStartTransform(furthest_id_found);
-    const Vec3 &xyz = s.getOrigin();
-    kart->setXYZ(xyz);
-    kart->setRotation(s.getRotation());
-
-    //position kart from same height as in World::resetAllKarts
-    btTransform pos;
-    pos.setOrigin(kart->getXYZ()+btVector3(0, 0.5f*kart->getKartHeight(), 0.0f));
-    pos.setRotation( btQuaternion(btVector3(0.0f, 1.0f, 0.0f), 0 /* angle */) );
-
-    kart->getBody()->setCenterOfMassTransform(pos);
-
-    //project kart to surface of track
-    bool kart_over_ground = m_track->findGround(kart);
-
-    if (kart_over_ground)
-    {
-        //add vertical offset so that the kart starts off above the track
-        float vertical_offset = kart->getKartProperties()->getVertRescueOffset() *
-                                kart->getKartHeight();
-        kart->getBody()->translate(btVector3(0, vertical_offset, 0));
-    }
-    else
-    {
-        Log::warn("[SoccerWorld]", " Invalid position after rescue for kart %s on track %s.",
-                kart->getIdent().c_str(), m_track->getIdent().c_str());
-    }
-}   // moveKartAfterRescue
-
 //-----------------------------------------------------------------------------
 /** Set position and team for the karts */
 void SoccerWorld::initKartList()
diff --git a/src/modes/soccer_world.hpp b/src/modes/soccer_world.hpp
index d33f1dd74..8d896d47c 100644
--- a/src/modes/soccer_world.hpp
+++ b/src/modes/soccer_world.hpp
@@ -76,8 +76,7 @@ public:
     virtual void getKartsDisplayInfo(
                           std::vector<RaceGUIBase::KartIconDisplayInfo> *info);
     int getScore(unsigned int i);
-    virtual bool raceHasLaps(){ return false; }
-    virtual void moveKartAfterRescue(AbstractKart* kart);
+    virtual bool raceHasLaps() { return false; }
 
     virtual const std::string& getIdent() const;
 
diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp
index d24555bf8..6fa48f882 100644
--- a/src/modes/three_strikes_battle.cpp
+++ b/src/modes/three_strikes_battle.cpp
@@ -477,53 +477,3 @@ void ThreeStrikesBattle::getKartsDisplayInfo(
     }
 }   // getKartsDisplayInfo
 
-//-----------------------------------------------------------------------------
-/** Determines the rescue position for a kart. The rescue position is the
- *  start position which is has the biggest accumulated distance to all other
- *  karts, and which has no other kart very close. The latter avoids dropping
- *  a kart on top of another kart.
- *  \param kart The kart that is going to be rescued.
- *  \returns The index of the start position to which the rescued kart
- *           should be moved to.
- */
-
-unsigned int ThreeStrikesBattle::getRescuePositionIndex(AbstractKart *kart)
-{
-    const int start_spots_amount = getTrack()->getNumberOfStartPositions();
-    assert(start_spots_amount > 0);
-
-    float largest_accumulated_distance_found = -1;
-    int   furthest_id_found                  = -1;
-
-    for(int n=0; n<start_spots_amount; n++)
-    {
-        const btTransform &s = getStartTransform(n);
-        const Vec3 &v=s.getOrigin();
-        float accumulated_distance = .0f;
-        bool spawn_point_clear = true;
-
-        for(unsigned int k=0; k<getCurrentNumKarts(); k++)
-        {
-            if(kart->getWorldKartId()==k) continue;
-            float abs_distance2 = (getKart(k)->getXYZ()-v).length2_2d();
-            const float CLEAR_SPAWN_RANGE2 = 5*5;
-            if( abs_distance2 < CLEAR_SPAWN_RANGE2)
-            {
-                spawn_point_clear = false;
-                break;
-            }
-            accumulated_distance += sqrt(abs_distance2);
-        }
-
-        if(accumulated_distance > largest_accumulated_distance_found &&
-            spawn_point_clear)
-        {
-            furthest_id_found = n;
-            largest_accumulated_distance_found = accumulated_distance;
-        }
-    }
-
-    assert(furthest_id_found != -1);
-    return furthest_id_found;
-}   // getRescuePositionIndex
-
diff --git a/src/modes/three_strikes_battle.hpp b/src/modes/three_strikes_battle.hpp
index 46a18674c..fe09b9340 100644
--- a/src/modes/three_strikes_battle.hpp
+++ b/src/modes/three_strikes_battle.hpp
@@ -97,7 +97,6 @@ public:
     virtual void getKartsDisplayInfo(
                           std::vector<RaceGUIBase::KartIconDisplayInfo> *info);
     virtual bool raceHasLaps(){ return false; }
-    virtual unsigned int getRescuePositionIndex(AbstractKart *kart);
 
     virtual const std::string& getIdent() const;
 
diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp
index 9482d1f95..f24ef58c3 100644
--- a/src/modes/world_with_rank.cpp
+++ b/src/modes/world_with_rank.cpp
@@ -134,35 +134,54 @@ unsigned int WorldWithRank::getNumberOfRescuePositions() const
     return getTrack()->getNumberOfStartPositions();
 }   // getNumberOfRescuePositions
 
-// ----------------------------------------------------------------------------
-/** Finds the starting position which is closest to the kart.
- *  \param kart The kart for which a rescue position needs to be determined.
+//-----------------------------------------------------------------------------
+/** Determines the rescue position for a kart. The rescue position is the
+ *  start position which is has the biggest accumulated distance to all other
+ *  karts, and which has no other kart very close. The latter avoids dropping
+ *  a kart on top of another kart. This is the method used 
+ *  \param kart The kart that is going to be rescued.
+ *  \returns The index of the start position to which the rescued kart
+ *           should be moved to.
  */
+
 unsigned int WorldWithRank::getRescuePositionIndex(AbstractKart *kart)
 {
-    // find closest point to drop kart on
-    const int start_spots_amount = getNumberOfRescuePositions();
+    const int start_spots_amount = getTrack()->getNumberOfStartPositions();
     assert(start_spots_amount > 0);
 
-    int closest_id = -1;
-    float closest_distance = 999999999.0f;
+    float largest_accumulated_distance_found = -1;
+    int   furthest_id_found                  = -1;
 
-    for (int n=0; n<start_spots_amount; n++)
+    for(int n=0; n<start_spots_amount; n++)
     {
         const btTransform &s = getStartTransform(n);
-        const Vec3 &v = s.getOrigin();
+        const Vec3 &v=s.getOrigin();
+        float accumulated_distance = .0f;
+        bool spawn_point_clear = true;
 
-        float abs_distance = (v - kart->getXYZ()).length();
-
-        if (abs_distance < closest_distance)
+        for(unsigned int k=0; k<getCurrentNumKarts(); k++)
         {
-            closest_distance = abs_distance;
-            closest_id = n;
+            if(kart->getWorldKartId()==k) continue;
+            float abs_distance2 = (getKart(k)->getXYZ()-v).length2_2d();
+            const float CLEAR_SPAWN_RANGE2 = 5*5;
+            if( abs_distance2 < CLEAR_SPAWN_RANGE2)
+            {
+                spawn_point_clear = false;
+                break;
+            }
+            accumulated_distance += sqrt(abs_distance2);
+        }
+
+        if(accumulated_distance > largest_accumulated_distance_found &&
+            spawn_point_clear)
+        {
+            furthest_id_found = n;
+            largest_accumulated_distance_found = accumulated_distance;
         }
     }
 
-    assert(closest_id != -1);
-    return closest_id;
+    assert(furthest_id_found != -1);
+    return furthest_id_found;
 }   // getRescuePositionIndex
 
 // ----------------------------------------------------------------------------

From 78c592e4e5b816d02afea137e7f4021fd852db1e Mon Sep 17 00:00:00 2001
From: hiker <henrichsjoerg@gmail.com>
Date: Fri, 31 Jul 2015 22:06:21 +1000
Subject: [PATCH 7/8] Added a file with a 'unique filename' with version number
 which is used by STK to detect that stk is reading the right data files (and
 therefore avoids #2073, in which stk finds the wrong data directory).

---
 data/supertuxkart.git   |  2 ++
 src/io/file_manager.cpp | 29 ++++++++++++++++-------------
 src/io/file_manager.hpp |  8 ++++++++
 src/main.cpp            |  2 +-
 4 files changed, 27 insertions(+), 14 deletions(-)
 create mode 100644 data/supertuxkart.git

diff --git a/data/supertuxkart.git b/data/supertuxkart.git
new file mode 100644
index 000000000..b37a12b9c
--- /dev/null
+++ b/data/supertuxkart.git
@@ -0,0 +1,2 @@
+This file is only here to help STK finding the right directory,
+and to avoid problems with other directories called 'data'.
diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp
index 1ddf9271c..e969b87b9 100644
--- a/src/io/file_manager.cpp
+++ b/src/io/file_manager.cpp
@@ -142,7 +142,7 @@ FileManager::FileManager()
 
     m_file_system = irr::io::createFileSystem();
 
-    irr::io::path exe_path;
+    std::string exe_path;
 
     // Search for the root directory
     // =============================
@@ -151,8 +151,11 @@ FileManager::FileManager()
     // This is esp. useful for Visual Studio, since it's not necessary
     // to define the working directory when debugging, it works automatically.
     std::string root_dir;
-    if(m_file_system->existFile(CommandLine::getExecName().c_str()))
-        exe_path = m_file_system->getFileDir(CommandLine::getExecName().c_str());
+    const std::string version = std::string("supertuxkart.") + STK_VERSION;
+    if (fileExists(CommandLine::getExecName()))
+    {
+        exe_path = StringUtils::getPath(CommandLine::getExecName());
+    }
     if(exe_path.size()==0 || exe_path[exe_path.size()-1]!='/')
         exe_path += "/";
     if ( getenv ( "SUPERTUXKART_DATADIR" ) != NULL )
@@ -160,19 +163,19 @@ FileManager::FileManager()
 #ifdef __APPLE__
     else if( macSetBundlePathIfRelevant( root_dir ) ) { root_dir = root_dir + "data/"; }
 #endif
-    else if(m_file_system->existFile("data/stk_config.xml"))
+    else if(fileExists("data/", version))
         root_dir = "data/" ;
-    else if(m_file_system->existFile("../data/stk_config.xml"))
+    else if(fileExists("../data/", version))
         root_dir = "../data/" ;
-    else if(m_file_system->existFile("../../data/stk_config.xml"))
+    else if(fileExists("../../data/", version))
         root_dir = "../../data/" ;
     // Test for old style build environment, with executable in root of stk
-    else if(m_file_system->existFile(exe_path+"data/stk_config.xml"))
+    else if(fileExists(exe_path+"data/"+version))
         root_dir = (exe_path+"data/").c_str();
     // Check for windows cmake style: bld/Debug/bin/supertuxkart.exe
-    else if (m_file_system->existFile(exe_path + "../../../data/stk_config.xml"))
-        root_dir = (exe_path + "../../../data/").c_str();
-    else if (m_file_system->existFile(exe_path + "../data/stk_config.xml"))
+    else if (fileExists(exe_path + "../../../data/"+version))
+        root_dir = exe_path + "../../../data/";
+    else if (fileExists(exe_path + "../data/"+version))
     {
         root_dir = exe_path.c_str();
         root_dir += "../data/";
@@ -186,10 +189,10 @@ FileManager::FileManager()
 #endif
     }
 
-    if (!m_file_system->existFile((root_dir + "stk_config.xml").c_str()))
+    if (!m_file_system->existFile((root_dir + version).c_str()))
     {
-        Log::error("FileManager", "Could not file stk_config.xml in any "
-                                  "standard location (esp. ../data).");
+        Log::error("FileManager", "Could not file '%s'in any "
+                   "standard location (esp. ../data).", version.c_str());
         Log::error("FileManager", 
                    "Last location checked '%s'.", root_dir.c_str());
         Log::fatal("FileManager", 
diff --git a/src/io/file_manager.hpp b/src/io/file_manager.hpp
index 1c0e7a6b6..0231365e0 100644
--- a/src/io/file_manager.hpp
+++ b/src/io/file_manager.hpp
@@ -134,6 +134,14 @@ public:
     std::string searchTexture(const std::string& fname) const;
     std::string getUserConfigFile(const std::string& fname) const;
     bool        fileExists(const std::string& path) const;
+    // ------------------------------------------------------------------------
+    /** Convenience function to save some typing in the 
+     *  file manager constructor. */
+    bool        fileExists(const char *prefix, const std::string& path) const
+    {
+        return fileExists(std::string(prefix) + path);
+    }
+    // ------------------------------------------------------------------------
     void        listFiles        (std::set<std::string>& result,
                                   const std::string& dir,
                                   bool make_full_path=false) const;
diff --git a/src/main.cpp b/src/main.cpp
index 3c6975a2e..9d6e1088c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1078,7 +1078,7 @@ int handleCmdLine()
 void initUserConfig()
 {
     file_manager = new FileManager();
-    user_config             = new UserConfig();     // needs file_manager
+    user_config  = new UserConfig();     // needs file_manager
     user_config->loadConfig();
     // Some parts of the file manager needs user config (paths for models
     // depend on artist debug flag). So init the rest of the file manager

From 2f902f769d29867ef33e1521f8016b575c373144 Mon Sep 17 00:00:00 2001
From: hiker <henrichsjoerg@gmail.com>
Date: Sat, 1 Aug 2015 22:02:00 +1000
Subject: [PATCH 8/8] Fixed minor memory leak.

---
 src/states_screens/dialogs/addons_loading.cpp | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/states_screens/dialogs/addons_loading.cpp b/src/states_screens/dialogs/addons_loading.cpp
index 723460fba..3f0f0d8ec 100644
--- a/src/states_screens/dialogs/addons_loading.cpp
+++ b/src/states_screens/dialogs/addons_loading.cpp
@@ -331,12 +331,15 @@ void AddonsLoading::stopDownload()
     // (and not uninstalling an installed one):
     if(m_download_request)
     {
-        // In case of a cancel we can't free the memory, since
-        // network_http will potentially update the request. So in
-        // order to avoid a memory leak, we let network_http free
-        // the request.
-        //m_download_request->setManageMemory(true);
+        // In case of a cancel we can't free the memory, since the 
+        // request manager thread is potentially working on this request. So 
+        // in order to avoid a memory leak, we let the request manager
+        // free the data. This is thread safe since freeing the data is done
+        // when the request manager handles the result queue - and this is
+        // done by the main thread (i.e. this thread).
+        m_download_request->setManageMemory(true);
         m_download_request->cancel();
+        m_download_request = NULL;
     };
 }   // startDownload