2008-09-27 15:43:57 -04:00
|
|
|
// SuperTuxKart - a fun racing game with go-kart
|
2013-12-01 23:27:55 -05:00
|
|
|
// Copyright (C) 2004-2013 SuperTuxKart-Team
|
2008-09-27 15:43:57 -04:00
|
|
|
//
|
|
|
|
// 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 "modes/linear_world.hpp"
|
2009-03-13 09:50:24 -04:00
|
|
|
|
2014-03-17 17:07:55 -04:00
|
|
|
#include "achievements/achievements_manager.hpp"
|
|
|
|
#include "config/player_manager.hpp"
|
2010-04-21 13:24:02 -04:00
|
|
|
#include "audio/music_manager.hpp"
|
2010-07-05 20:11:42 -04:00
|
|
|
#include "audio/sfx_base.hpp"
|
|
|
|
#include "audio/sfx_manager.hpp"
|
2014-02-25 20:52:16 -05:00
|
|
|
#include "config/user_config.hpp"
|
2012-03-19 16:21:11 -04:00
|
|
|
#include "karts/abstract_kart.hpp"
|
2012-03-08 17:56:33 -05:00
|
|
|
#include "karts/controller/controller.hpp"
|
2012-03-19 16:21:11 -04:00
|
|
|
#include "karts/kart_properties.hpp"
|
2012-05-08 03:07:15 -04:00
|
|
|
#include "physics/physics.hpp"
|
2010-03-29 18:21:34 -04:00
|
|
|
#include "race/history.hpp"
|
2012-03-19 16:21:11 -04:00
|
|
|
#include "states_screens/race_gui_base.hpp"
|
2011-08-04 19:33:41 -04:00
|
|
|
#include "tracks/track_sector.hpp"
|
2009-01-22 17:27:13 -05:00
|
|
|
#include "tracks/track.hpp"
|
|
|
|
#include "utils/constants.hpp"
|
2009-07-08 08:34:39 -04:00
|
|
|
#include "utils/string_utils.hpp"
|
2009-01-23 00:23:22 -05:00
|
|
|
#include "utils/translation.hpp"
|
2008-09-27 15:43:57 -04:00
|
|
|
|
2014-02-25 20:52:16 -05:00
|
|
|
#include <iostream>
|
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2010-09-01 20:44:11 -04:00
|
|
|
/** Constructs the linear world. Note that here no functions can be called
|
|
|
|
* that use World::getWorld(), since it is not yet defined.
|
|
|
|
*/
|
2010-09-02 09:14:07 -04:00
|
|
|
LinearWorld::LinearWorld() : WorldWithRank()
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
2011-09-15 21:49:38 -04:00
|
|
|
m_last_lap_sfx = sfx_manager->createSoundSource("last_lap_fanfare");
|
|
|
|
m_last_lap_sfx_played = false;
|
2010-10-11 21:24:26 -04:00
|
|
|
m_last_lap_sfx_playing = false;
|
2011-09-15 21:49:38 -04:00
|
|
|
m_fastest_lap = 9999999.9f;
|
2008-12-15 18:37:25 -05:00
|
|
|
} // LinearWorld
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2010-09-01 20:44:11 -04:00
|
|
|
/** Actually initialises the world, i.e. creates all data structures to
|
|
|
|
* for all karts etc. In init functions can be called that use
|
|
|
|
* World::getWorld().
|
|
|
|
*/
|
2008-11-07 21:07:54 -05:00
|
|
|
void LinearWorld::init()
|
|
|
|
{
|
2010-09-02 09:14:07 -04:00
|
|
|
WorldWithRank::init();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-06-26 18:49:09 -04:00
|
|
|
assert(!m_track->isArena());
|
2012-12-22 17:33:15 -05:00
|
|
|
assert(!m_track->isSoccer());
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2010-09-01 23:03:37 -04:00
|
|
|
m_last_lap_sfx_played = false;
|
2010-10-11 21:24:26 -04:00
|
|
|
m_last_lap_sfx_playing = false;
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2013-04-03 17:15:13 -04:00
|
|
|
// The values are initialised in reset()
|
|
|
|
m_kart_info.resize(m_karts.size());
|
2008-12-15 18:37:25 -05:00
|
|
|
} // init
|
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2013-04-03 17:15:13 -04:00
|
|
|
/** The destructor frees al data structures.
|
|
|
|
*/
|
2008-09-30 16:38:11 -04:00
|
|
|
LinearWorld::~LinearWorld()
|
|
|
|
{
|
2010-07-05 20:11:42 -04:00
|
|
|
sfx_manager->deleteSFX(m_last_lap_sfx);
|
2008-12-15 18:37:25 -05:00
|
|
|
} // ~LinearWorld
|
|
|
|
|
2008-09-30 16:38:11 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2013-05-29 18:04:35 -04:00
|
|
|
/** Called before a race is started (or restarted). It resets the data
|
|
|
|
* structures that keep track of position and distance long track of
|
2013-04-03 17:15:13 -04:00
|
|
|
* all karts.
|
|
|
|
*/
|
2013-04-03 02:05:34 -04:00
|
|
|
void LinearWorld::reset()
|
2008-09-29 11:14:14 -04:00
|
|
|
{
|
2013-04-03 02:05:34 -04:00
|
|
|
WorldWithRank::reset();
|
2010-09-01 23:03:37 -04:00
|
|
|
m_last_lap_sfx_played = false;
|
2010-10-11 21:24:26 -04:00
|
|
|
m_last_lap_sfx_playing = false;
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2010-02-10 17:59:17 -05:00
|
|
|
const unsigned int kart_amount = m_karts.size();
|
2010-02-14 19:54:28 -05:00
|
|
|
for(unsigned int i=0; i<kart_amount; i++)
|
2008-09-29 11:14:14 -04:00
|
|
|
{
|
2011-08-04 19:33:41 -04:00
|
|
|
m_kart_info[i].reset();
|
2013-07-10 18:47:12 -04:00
|
|
|
m_kart_info[i].getTrackSector()->update(m_karts[i]->getXYZ());
|
2008-11-30 22:58:58 -05:00
|
|
|
} // next kart
|
2010-02-14 19:54:28 -05:00
|
|
|
|
2013-04-04 17:17:39 -04:00
|
|
|
// At the moment the last kart would be the one that is furthest away
|
2013-05-29 18:04:35 -04:00
|
|
|
// from the start line, i.e. it would determine the amount by which
|
2013-04-04 17:17:39 -04:00
|
|
|
// the track length must be extended (to avoid negative numbers in
|
|
|
|
// estimateFinishTimeForKart()). On the other hand future game modes
|
|
|
|
// might not follow this rule, so check the distance for all karts here:
|
|
|
|
m_distance_increase = m_track->getTrackLength();
|
|
|
|
for(unsigned int i=0; i<kart_amount; i++)
|
|
|
|
{
|
2013-05-29 18:04:35 -04:00
|
|
|
m_distance_increase = std::min(m_distance_increase,
|
2013-04-04 17:17:39 -04:00
|
|
|
getDistanceDownTrackForKart(i));
|
|
|
|
}
|
|
|
|
// Track length - minimum distance is how much the track length must
|
|
|
|
// be increased to avoid negative values in estimateFinishTimeForKart
|
2013-05-29 18:04:35 -04:00
|
|
|
// Increase this value somewhat in case that a kart drivess/slides
|
2013-04-04 17:17:39 -04:00
|
|
|
// backwards a little bit at start.
|
2013-05-29 18:04:35 -04:00
|
|
|
m_distance_increase = m_track->getTrackLength() - m_distance_increase
|
2013-04-04 17:17:39 -04:00
|
|
|
+ 5.0f;
|
|
|
|
|
|
|
|
if(m_distance_increase<0) m_distance_increase = 1.0f; // shouldn't happen
|
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
// First all kart infos must be updated before the kart position can be
|
2010-02-14 19:54:28 -05:00
|
|
|
// recomputed, since otherwise 'new' (initialised) valued will be compared
|
|
|
|
// with old values.
|
2010-03-08 13:39:05 -05:00
|
|
|
updateRacePosition();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2010-03-07 11:52:20 -05:00
|
|
|
#ifdef DEBUG
|
2013-05-29 18:04:35 -04:00
|
|
|
//FIXME: this could be defined somewhere in a central header so it can
|
2011-09-15 21:49:38 -04:00
|
|
|
// be used everywhere
|
2010-03-07 11:52:20 -05:00
|
|
|
#define assertExpr( ARG1, OP, ARG2 ) if (!(ARG1 OP ARG2)) \
|
|
|
|
{ \
|
2013-04-03 17:15:13 -04:00
|
|
|
std::cerr << "Failed assert " << #ARG1 << #OP << #ARG2 << " @ " \
|
|
|
|
<< __FILE__ << ":" << __LINE__ \
|
2010-03-07 11:52:20 -05:00
|
|
|
<< "; values are (" << ARG1 << #OP << ARG2 << ")\n"; \
|
|
|
|
assert(false); \
|
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2010-03-07 11:52:20 -05:00
|
|
|
for (unsigned int i=0; i<kart_amount; i++)
|
|
|
|
{
|
|
|
|
for (unsigned int j=i+1; j<kart_amount; j++)
|
|
|
|
{
|
2011-09-15 21:49:38 -04:00
|
|
|
assertExpr( m_karts[i]->getPosition(), !=,
|
|
|
|
m_karts[j]->getPosition() );
|
2010-03-07 11:52:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2013-04-03 02:05:34 -04:00
|
|
|
} // reset
|
2008-12-15 18:37:25 -05:00
|
|
|
|
2008-09-29 11:14:14 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2010-05-06 19:26:49 -04:00
|
|
|
/** General update function called once per frame. This updates the kart
|
|
|
|
* sectors, which are then used to determine the kart positions.
|
|
|
|
* \param dt Time step size.
|
|
|
|
*/
|
2010-11-29 17:01:59 -05:00
|
|
|
void LinearWorld::update(float dt)
|
2009-08-18 06:33:21 -04:00
|
|
|
{
|
2008-12-15 18:37:25 -05:00
|
|
|
// run generic parent stuff that applies to all modes. It
|
|
|
|
// especially updates the kart positions.
|
2010-11-29 17:01:59 -05:00
|
|
|
WorldWithRank::update(dt);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
|
|
|
if (m_last_lap_sfx_playing &&
|
2011-09-15 21:49:38 -04:00
|
|
|
m_last_lap_sfx->getStatus() != SFXManager::SFX_PLAYING)
|
2010-10-11 21:24:26 -04:00
|
|
|
{
|
2012-11-14 21:04:03 -05:00
|
|
|
if(music_manager->getCurrentMusic())
|
|
|
|
music_manager->getCurrentMusic()->resetTemporaryVolume();
|
2010-10-11 21:24:26 -04:00
|
|
|
m_last_lap_sfx_playing = false;
|
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2010-02-10 06:40:33 -05:00
|
|
|
const unsigned int kart_amount = getNumKarts();
|
2008-12-15 01:35:17 -05:00
|
|
|
|
2008-12-15 18:37:25 -05:00
|
|
|
// Do stuff specific to this subtype of race.
|
|
|
|
// ------------------------------------------
|
2008-09-27 15:43:57 -04:00
|
|
|
for(unsigned int n=0; n<kart_amount; n++)
|
|
|
|
{
|
|
|
|
KartInfo& kart_info = m_kart_info[n];
|
2012-03-19 16:21:11 -04:00
|
|
|
AbstractKart* kart = m_karts[n];
|
2008-12-21 02:43:41 -05:00
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
// Nothing to do for karts that are currently being
|
2011-09-15 21:49:38 -04:00
|
|
|
// rescued or eliminated
|
2012-04-01 18:57:41 -04:00
|
|
|
if(kart->getKartAnimation()) continue;
|
2008-12-21 02:43:41 -05:00
|
|
|
|
2013-07-10 18:47:12 -04:00
|
|
|
kart_info.getTrackSector()->update(kart->getXYZ());
|
2013-05-29 18:04:35 -04:00
|
|
|
kart_info.m_overall_distance = kart_info.m_race_lap
|
2012-11-29 06:59:33 -05:00
|
|
|
* m_track->getTrackLength()
|
|
|
|
+ getDistanceDownTrackForKart(kart->getWorldKartId());
|
2008-12-15 18:37:25 -05:00
|
|
|
} // for n
|
|
|
|
|
|
|
|
// Update all positions. This must be done after _all_ karts have
|
|
|
|
// updated their position and laps etc, otherwise inconsistencies
|
|
|
|
// (like two karts at same position) can occur.
|
|
|
|
// ---------------------------------------------------------------
|
2010-11-29 17:01:59 -05:00
|
|
|
WorldWithRank::updateTrack(dt);
|
2010-03-08 13:39:05 -05:00
|
|
|
updateRacePosition();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2010-03-08 13:39:05 -05:00
|
|
|
for (unsigned int i=0; i<kart_amount; i++)
|
2008-12-15 18:37:25 -05:00
|
|
|
{
|
|
|
|
// ---------- update rank ------
|
2013-05-29 18:04:35 -04:00
|
|
|
if (m_karts[i]->hasFinishedRace() ||
|
2011-09-15 21:49:38 -04:00
|
|
|
m_karts[i]->isEliminated() ) continue;
|
2010-03-08 13:39:05 -05:00
|
|
|
|
2010-02-17 06:59:51 -05:00
|
|
|
// During the last lap update the estimated finish time.
|
|
|
|
// This is used to play the faster music, and by the AI
|
2010-03-08 13:39:05 -05:00
|
|
|
if (m_kart_info[i].m_race_lap == race_manager->getNumLaps()-1)
|
|
|
|
{
|
2013-05-29 18:04:35 -04:00
|
|
|
m_kart_info[i].m_estimated_finish =
|
2011-09-15 21:49:38 -04:00
|
|
|
estimateFinishTimeForKart(m_karts[i]);
|
2010-03-08 13:39:05 -05:00
|
|
|
}
|
2010-02-17 06:59:51 -05:00
|
|
|
checkForWrongDirection(i);
|
2008-12-15 18:37:25 -05:00
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2008-12-15 18:37:25 -05:00
|
|
|
#ifdef DEBUG
|
2011-01-24 15:33:14 -05:00
|
|
|
// Debug output in case that the double position error occurs again.
|
2010-05-09 23:20:42 -04:00
|
|
|
std::vector<int> pos_used;
|
|
|
|
pos_used.resize(kart_amount+1, -99);
|
2008-12-15 18:37:25 -05:00
|
|
|
for(unsigned int i=0; i<kart_amount; i++)
|
|
|
|
{
|
2010-02-10 17:59:17 -05:00
|
|
|
if(pos_used[m_karts[i]->getPosition()]!=-99)
|
2008-12-15 18:37:25 -05:00
|
|
|
{
|
2014-02-06 17:17:49 -05:00
|
|
|
for(unsigned int j=0; j<kart_amount; j++)
|
2008-12-15 18:37:25 -05:00
|
|
|
{
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::verbose("[LinearWorld]", "kart id=%u, position=%d, finished=%d, laps=%d, "
|
|
|
|
"distanceDownTrack=%f overallDistance=%f %s",
|
2010-02-10 17:59:17 -05:00
|
|
|
j, m_karts[j]->getPosition(),
|
|
|
|
m_karts[j]->hasFinishedRace(),
|
2008-12-15 18:37:25 -05:00
|
|
|
m_kart_info[j].m_race_lap,
|
2010-05-07 14:39:07 -04:00
|
|
|
getDistanceDownTrackForKart(m_karts[j]->getWorldKartId()),
|
2012-11-26 05:14:53 -05:00
|
|
|
m_kart_info[j].m_overall_distance,
|
2013-05-29 18:04:35 -04:00
|
|
|
(m_karts[j]->getPosition() == m_karts[i]->getPosition()
|
2011-09-15 21:49:38 -04:00
|
|
|
? "<--- !!!" : "") );
|
2008-12-15 18:37:25 -05:00
|
|
|
}
|
|
|
|
}
|
2010-02-10 17:59:17 -05:00
|
|
|
pos_used[m_karts[i]->getPosition()]=i;
|
2008-12-15 18:37:25 -05:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} // update
|
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2009-09-09 23:25:42 -04:00
|
|
|
/** Is called by check structures if a kart starts a new lap.
|
2009-07-07 20:44:55 -04:00
|
|
|
* \param kart_index Index of the kart.
|
|
|
|
*/
|
|
|
|
void LinearWorld::newLap(unsigned int kart_index)
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
2009-07-13 08:22:27 -04:00
|
|
|
KartInfo &kart_info = m_kart_info[kart_index];
|
2012-03-19 16:21:11 -04:00
|
|
|
AbstractKart *kart = m_karts[kart_index];
|
2010-09-08 21:46:05 -04:00
|
|
|
|
2014-03-17 17:07:55 -04:00
|
|
|
// Reset reset-after-lap achievements
|
|
|
|
StateManager::ActivePlayer *c = kart->getController()->getPlayer();
|
2014-04-07 18:06:52 -04:00
|
|
|
PlayerProfile *p = PlayerManager::getCurrentPlayer();
|
2014-03-17 17:07:55 -04:00
|
|
|
if (c && c->getConstProfile() == p)
|
|
|
|
{
|
2014-03-17 17:30:17 -04:00
|
|
|
p->getAchievementsStatus()->onLapEnd();
|
2014-03-17 17:07:55 -04:00
|
|
|
}
|
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
// Only update the kart controller if a kart that has already finished
|
|
|
|
// the race crosses the start line again. This avoids 'fastest lap'
|
2012-02-15 00:23:21 -05:00
|
|
|
// messages if the end controller does a fastest lap, but especially
|
|
|
|
// allows the end controller to switch end cameras
|
2013-05-29 18:04:35 -04:00
|
|
|
if(kart->hasFinishedRace())
|
2012-02-15 00:23:21 -05:00
|
|
|
{
|
|
|
|
kart->getController()->newLap(kart_info.m_race_lap);
|
|
|
|
return;
|
|
|
|
}
|
2010-09-08 21:46:05 -04:00
|
|
|
|
2010-10-11 21:24:26 -04:00
|
|
|
const int lap_count = race_manager->getNumLaps();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2009-07-07 20:44:55 -04:00
|
|
|
// Only increase the lap counter and set the new time if the
|
|
|
|
// kart hasn't already finished the race (otherwise the race_gui
|
|
|
|
// will begin another countdown).
|
2010-10-11 21:24:26 -04:00
|
|
|
if(kart_info.m_race_lap+1 <= lap_count)
|
2009-07-07 20:44:55 -04:00
|
|
|
{
|
2009-09-09 23:25:42 -04:00
|
|
|
assert(kart->getWorldKartId()==kart_index);
|
2011-02-12 02:35:34 -05:00
|
|
|
kart_info.m_time_at_last_lap=getTime();
|
2012-10-14 18:23:07 -04:00
|
|
|
kart_info.m_race_lap++;
|
2013-05-29 18:04:35 -04:00
|
|
|
m_kart_info[kart_index].m_overall_distance =
|
2012-10-14 18:23:07 -04:00
|
|
|
m_kart_info[kart_index].m_race_lap * m_track->getTrackLength()
|
|
|
|
+ getDistanceDownTrackForKart(kart->getWorldKartId());
|
2009-07-07 20:44:55 -04:00
|
|
|
}
|
2009-12-23 11:58:10 -05:00
|
|
|
// Last lap message (kart_index's assert in previous block already)
|
2012-04-01 11:45:10 -04:00
|
|
|
if (raceHasLaps() && kart_info.m_race_lap+1 == lap_count)
|
2009-12-23 11:58:10 -05:00
|
|
|
{
|
2011-02-12 02:35:34 -05:00
|
|
|
m_race_gui->addMessage(_("Final lap!"), kart,
|
2011-09-03 16:23:55 -04:00
|
|
|
3.0f, video::SColor(255, 210, 100, 50), true);
|
2010-10-11 21:24:26 -04:00
|
|
|
if(!m_last_lap_sfx_played && lap_count > 1)
|
2010-07-05 20:11:42 -04:00
|
|
|
{
|
2011-02-28 11:19:43 -05:00
|
|
|
if (UserConfigParams::m_music)
|
|
|
|
{
|
|
|
|
m_last_lap_sfx->play();
|
|
|
|
m_last_lap_sfx_played = true;
|
|
|
|
m_last_lap_sfx_playing = true;
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-02-28 11:19:43 -05:00
|
|
|
// In case that no music is defined
|
2011-09-15 21:49:38 -04:00
|
|
|
if(music_manager->getCurrentMusic() &&
|
|
|
|
music_manager->getMasterMusicVolume() > 0.2f)
|
2011-02-28 11:19:43 -05:00
|
|
|
{
|
|
|
|
music_manager->getCurrentMusic()->setTemporaryVolume(0.2f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2010-11-05 15:19:39 -04:00
|
|
|
{
|
2011-02-28 11:19:43 -05:00
|
|
|
m_last_lap_sfx_played = true;
|
|
|
|
m_last_lap_sfx_playing = false;
|
2010-11-05 15:19:39 -04:00
|
|
|
}
|
2010-07-05 20:11:42 -04:00
|
|
|
}
|
2009-12-23 11:58:10 -05:00
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
else if (raceHasLaps() && kart_info.m_race_lap > 0 &&
|
2013-04-03 17:15:13 -04:00
|
|
|
kart_info.m_race_lap+1 < lap_count)
|
2010-11-29 21:04:18 -05:00
|
|
|
{
|
2011-01-23 18:39:10 -05:00
|
|
|
m_race_gui->addMessage(_("Lap %i", kart_info.m_race_lap+1),
|
2013-05-29 18:04:35 -04:00
|
|
|
kart, 3.0f, video::SColor(255, 210, 100, 50),
|
2011-09-15 21:49:38 -04:00
|
|
|
true);
|
2010-11-29 21:04:18 -05:00
|
|
|
}
|
2010-04-13 20:06:10 -04:00
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
// The race positions must be updated here: consider the situation where
|
2011-09-15 21:49:38 -04:00
|
|
|
// the first kart does not cross the finish line in its last lap, instead
|
2013-05-29 18:04:35 -04:00
|
|
|
// it passes it, the kart reverses and crosses the finishing line
|
2010-04-13 20:06:10 -04:00
|
|
|
// backwards. Just before crossing the finishing line the kart will be on
|
2013-05-29 18:04:35 -04:00
|
|
|
// the last lap, but with a distance along the track close to zero.
|
2010-04-13 20:06:10 -04:00
|
|
|
// Therefore its position will be wrong. If the race position gets updated
|
|
|
|
// after increasing the number of laps (but before tagging the kart to have
|
|
|
|
// finished the race) the position will be correct (since the kart now
|
|
|
|
// has one additional lap it will be ahead of the other karts).
|
|
|
|
// Without this call the incorrect position for this kart would remain
|
|
|
|
// (since a kart that has finished the race does not get its position
|
|
|
|
// changed anymore), potentially resulting in a duplicated race position
|
|
|
|
// (since the first kart does not have position 1, no other kart can get
|
|
|
|
// position 1, so one rank will be duplicated).
|
|
|
|
// Similarly the situation can happen if the distance along track should
|
|
|
|
// go back to zero before actually crossing the finishing line. While this
|
|
|
|
// should not happen, it could potentially be caused by floating point
|
2013-05-29 18:04:35 -04:00
|
|
|
// errors. In this case the call to updateRacePosition will avoid
|
2010-10-13 18:37:41 -04:00
|
|
|
// duplicated race positions as well.
|
2010-04-13 20:06:10 -04:00
|
|
|
updateRacePosition();
|
|
|
|
|
2009-07-07 20:44:55 -04:00
|
|
|
// Race finished
|
|
|
|
if(kart_info.m_race_lap >= race_manager->getNumLaps() && raceHasLaps())
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
2013-07-05 08:01:29 -04:00
|
|
|
kart->finishedRace(getTime());
|
2009-07-07 20:44:55 -04:00
|
|
|
}
|
2011-02-12 02:35:34 -05:00
|
|
|
float time_per_lap;
|
|
|
|
if (kart_info.m_race_lap == 1) // just completed first lap
|
2009-07-07 20:44:55 -04:00
|
|
|
{
|
2011-02-12 02:35:34 -05:00
|
|
|
time_per_lap=getTime();
|
|
|
|
}
|
|
|
|
else //completing subsequent laps
|
|
|
|
{
|
|
|
|
time_per_lap=getTime() - kart_info.m_lap_start_time;
|
2008-09-27 15:43:57 -04:00
|
|
|
}
|
2011-02-12 02:35:34 -05:00
|
|
|
|
|
|
|
// if new fastest lap
|
2011-09-15 21:49:38 -04:00
|
|
|
if(time_per_lap < m_fastest_lap && raceHasLaps() &&
|
2011-02-12 02:35:34 -05:00
|
|
|
kart_info.m_race_lap>0)
|
|
|
|
{
|
2011-09-15 21:49:38 -04:00
|
|
|
m_fastest_lap = time_per_lap;
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-02-12 02:35:34 -05:00
|
|
|
std::string s = StringUtils::timeToString(time_per_lap);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-02-12 02:35:34 -05:00
|
|
|
irr::core::stringw m_fastest_lap_message;
|
|
|
|
//I18N: as in "fastest lap: 60 seconds by Wilber"
|
2013-05-29 18:04:35 -04:00
|
|
|
m_fastest_lap_message += _C("fastest_lap", "%s by %s", s.c_str(),
|
2011-09-15 21:49:38 -04:00
|
|
|
core::stringw(kart->getName()));
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-02-12 02:35:34 -05:00
|
|
|
m_race_gui->addMessage(m_fastest_lap_message, NULL,
|
2011-09-03 16:23:55 -04:00
|
|
|
3.0f, video::SColor(255, 255, 255, 255), false);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-06-03 20:12:38 -04:00
|
|
|
m_race_gui->addMessage(_("New fastest lap"), NULL,
|
2011-09-03 16:23:55 -04:00
|
|
|
3.0f, video::SColor(255, 255, 255, 255), false);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-02-12 02:35:34 -05:00
|
|
|
} // end if new fastest lap
|
|
|
|
|
2009-07-07 20:44:55 -04:00
|
|
|
kart_info.m_lap_start_time = getTime();
|
2011-02-12 02:35:34 -05:00
|
|
|
kart->getController()->newLap(kart_info.m_race_lap);
|
2009-07-07 20:44:55 -04:00
|
|
|
} // newLap
|
2008-12-15 18:37:25 -05:00
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2013-05-29 18:04:35 -04:00
|
|
|
/** Gets the sector a kart is on. This function returns UNKNOWN_SECTOR if the
|
2013-04-03 02:05:34 -04:00
|
|
|
* kart_id is larger than the current kart info. This is necessary in the case
|
2013-05-29 18:04:35 -04:00
|
|
|
* that a collision with the track happens during resetAllKarts: at this time
|
2012-02-27 22:36:18 -05:00
|
|
|
* m_kart_info is not initialised (and has size 0), so it would trigger this
|
2013-05-29 18:04:35 -04:00
|
|
|
* assert. While this normally does not happen, it is useful for track
|
2012-02-27 22:36:18 -05:00
|
|
|
* designers that STK does not crash.
|
2013-05-29 18:04:35 -04:00
|
|
|
* \param kart_id The world kart id of the kart for which to return
|
2012-02-27 22:36:18 -05:00
|
|
|
* the sector.
|
|
|
|
*/
|
2012-03-19 16:21:11 -04:00
|
|
|
int LinearWorld::getSectorForKart(const AbstractKart *kart) const
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
2012-03-25 19:56:25 -04:00
|
|
|
if(kart->getWorldKartId()>=m_kart_info.size())
|
2012-02-27 22:36:18 -05:00
|
|
|
return QuadGraph::UNKNOWN_SECTOR;
|
2013-07-10 18:47:12 -04:00
|
|
|
return m_kart_info[kart->getWorldKartId()].getTrackSector()
|
2012-03-19 16:21:11 -04:00
|
|
|
->getCurrentGraphNode();
|
2008-12-16 08:21:55 -05:00
|
|
|
} // getSectorForKart
|
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2013-05-29 18:04:35 -04:00
|
|
|
/** Returns the distance the kart has travelled along the track since
|
2010-02-23 08:27:01 -05:00
|
|
|
* crossing the start line..
|
|
|
|
* \param kart_id Index of the kart.
|
|
|
|
*/
|
2008-09-27 15:43:57 -04:00
|
|
|
float LinearWorld::getDistanceDownTrackForKart(const int kart_id) const
|
|
|
|
{
|
2011-09-11 15:46:51 -04:00
|
|
|
assert(kart_id < (int)m_kart_info.size());
|
2013-07-10 18:47:12 -04:00
|
|
|
return m_kart_info[kart_id].getTrackSector()->getDistanceFromStart();
|
2008-12-16 08:21:55 -05:00
|
|
|
} // getDistanceDownTrackForKart
|
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2010-02-23 08:27:01 -05:00
|
|
|
/** Gets the distance of the kart from the center of the driveline. Positive
|
|
|
|
* is to the right of the center, negative values to the left.
|
|
|
|
* \param kart_id Index of kart.
|
|
|
|
*/
|
2008-09-27 15:43:57 -04:00
|
|
|
float LinearWorld::getDistanceToCenterForKart(const int kart_id) const
|
|
|
|
{
|
2011-09-11 15:46:51 -04:00
|
|
|
assert(kart_id < (int)m_kart_info.size());
|
2013-07-10 18:47:12 -04:00
|
|
|
return m_kart_info[kart_id].getTrackSector()->getDistanceToCenter();
|
2008-12-16 08:21:55 -05:00
|
|
|
} // getDistanceToCenterForKart
|
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int LinearWorld::getLapForKart(const int kart_id) const
|
|
|
|
{
|
2011-09-11 15:46:51 -04:00
|
|
|
assert(kart_id < (int)m_kart_info.size());
|
2008-09-27 15:43:57 -04:00
|
|
|
return m_kart_info[kart_id].m_race_lap;
|
2008-12-16 08:21:55 -05:00
|
|
|
} // getLapForKart
|
|
|
|
|
2008-12-08 18:23:33 -05:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Returns the estimated finishing time. Only valid during the last lap!
|
|
|
|
* \param kart_id Id of the kart.
|
|
|
|
*/
|
|
|
|
float LinearWorld::getEstimatedFinishTime(const int kart_id) const
|
|
|
|
{
|
2011-09-11 15:46:51 -04:00
|
|
|
assert(kart_id < (int)m_kart_info.size());
|
2008-12-08 18:23:33 -05:00
|
|
|
assert(m_kart_info[kart_id].m_race_lap == race_manager->getNumLaps()-1);
|
|
|
|
return m_kart_info[kart_id].m_estimated_finish;
|
|
|
|
} // getEstimatedFinishTime
|
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
float LinearWorld::getTimeAtLapForKart(const int kart_id) const
|
|
|
|
{
|
2011-09-11 15:46:51 -04:00
|
|
|
assert(kart_id < (int)m_kart_info.size());
|
2008-09-27 15:43:57 -04:00
|
|
|
return m_kart_info[kart_id].m_time_at_last_lap;
|
2008-12-16 08:21:55 -05:00
|
|
|
} // getTimeAtLapForKart
|
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-12-04 23:04:01 -05:00
|
|
|
void LinearWorld::getKartsDisplayInfo(
|
|
|
|
std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
|
|
|
int laps_of_leader = -1;
|
|
|
|
float time_of_leader = -1;
|
|
|
|
// Find the best time for the lap. We can't simply use
|
|
|
|
// the time of the kart at position 1, since the kart
|
|
|
|
// might have been overtaken by now
|
2010-02-10 06:40:33 -05:00
|
|
|
const unsigned int kart_amount = getNumKarts();
|
2008-09-27 15:43:57 -04:00
|
|
|
for(unsigned int i = 0; i < kart_amount ; i++)
|
|
|
|
{
|
2012-12-04 23:04:01 -05:00
|
|
|
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
|
2012-03-19 16:21:11 -04:00
|
|
|
AbstractKart* kart = m_karts[i];
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
// reset color
|
2012-12-16 19:33:47 -05:00
|
|
|
rank_info.m_color = video::SColor(255, 255, 255, 255);
|
2008-09-27 15:43:57 -04:00
|
|
|
rank_info.lap = -1;
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
if(kart->isEliminated()) continue;
|
|
|
|
const float lap_time = getTimeAtLapForKart(kart->getWorldKartId());
|
|
|
|
const int current_lap = getLapForKart( kart->getWorldKartId() );
|
|
|
|
rank_info.lap = current_lap;
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
if(current_lap > laps_of_leader)
|
|
|
|
{
|
2013-05-29 18:04:35 -04:00
|
|
|
// more laps than current leader --> new leader and
|
2011-09-15 21:49:38 -04:00
|
|
|
// new time computation
|
2008-09-27 15:43:57 -04:00
|
|
|
laps_of_leader = current_lap;
|
|
|
|
time_of_leader = lap_time;
|
|
|
|
} else if(current_lap == laps_of_leader)
|
|
|
|
{
|
|
|
|
// Same number of laps as leader: use fastest time
|
|
|
|
time_of_leader=std::min(time_of_leader,lap_time);
|
|
|
|
}
|
2008-09-30 21:15:34 -04:00
|
|
|
}
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2008-09-30 21:15:34 -04:00
|
|
|
// we now know the best time of the lap. fill the remaining bits of info
|
|
|
|
for(unsigned int i = 0; i < kart_amount ; i++)
|
2009-08-18 06:33:21 -04:00
|
|
|
{
|
2012-12-04 23:04:01 -05:00
|
|
|
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
|
2008-09-30 21:15:34 -04:00
|
|
|
KartInfo& kart_info = m_kart_info[i];
|
2012-03-19 16:21:11 -04:00
|
|
|
AbstractKart* kart = m_karts[i];
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2008-09-30 21:15:34 -04:00
|
|
|
const int position = kart->getPosition();
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2011-09-15 21:49:38 -04:00
|
|
|
// Don't compare times when crossing the start line first
|
|
|
|
if(laps_of_leader>0 &&
|
2013-05-29 18:04:35 -04:00
|
|
|
(getTime() - getTimeAtLapForKart(kart->getWorldKartId())<5.0f ||
|
2011-09-15 21:49:38 -04:00
|
|
|
rank_info.lap != laps_of_leader) &&
|
|
|
|
raceHasLaps())
|
2008-09-27 15:43:57 -04:00
|
|
|
{ // Display for 5 seconds
|
2009-07-08 08:34:39 -04:00
|
|
|
std::string str;
|
2009-08-30 14:21:59 -04:00
|
|
|
if(position == 1)
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
2013-05-29 18:04:35 -04:00
|
|
|
str = " " + StringUtils::timeToString(
|
2011-09-15 21:49:38 -04:00
|
|
|
getTimeAtLapForKart(kart->getWorldKartId()) );
|
2008-09-27 15:43:57 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float timeBehind;
|
2009-08-18 06:33:21 -04:00
|
|
|
timeBehind = (kart_info.m_race_lap==laps_of_leader
|
|
|
|
? getTimeAtLapForKart(kart->getWorldKartId())
|
2008-12-16 04:02:14 -05:00
|
|
|
: getTime())
|
|
|
|
- time_of_leader;
|
2009-08-30 14:21:59 -04:00
|
|
|
str = "+" + StringUtils::timeToString(timeBehind);
|
2008-09-27 15:43:57 -04:00
|
|
|
}
|
2010-03-31 19:49:42 -04:00
|
|
|
rank_info.m_text = irr::core::stringw(str.c_str());
|
2008-09-27 15:43:57 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-31 19:49:42 -04:00
|
|
|
rank_info.m_text = "";
|
2008-09-27 15:43:57 -04:00
|
|
|
}
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
int numLaps = race_manager->getNumLaps();
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
if(kart_info.m_race_lap>=numLaps)
|
|
|
|
{ // kart is finished, display in green
|
2012-12-16 19:33:47 -05:00
|
|
|
rank_info.m_color.setGreen(0);
|
|
|
|
rank_info.m_color.setBlue(0);
|
2008-09-27 15:43:57 -04:00
|
|
|
}
|
|
|
|
else if(kart_info.m_race_lap>=0 && numLaps>1)
|
|
|
|
{
|
2012-12-16 19:33:47 -05:00
|
|
|
int col = (int)(255*(1.0f-(float)kart_info.m_race_lap
|
|
|
|
/((float)numLaps-1.0f) ));
|
|
|
|
rank_info.m_color.setBlue(col);
|
|
|
|
rank_info.m_color.setGreen(col);
|
2008-09-27 15:43:57 -04:00
|
|
|
}
|
|
|
|
} // next kart
|
2009-08-18 06:33:21 -04:00
|
|
|
|
|
|
|
|
2008-12-16 08:21:55 -05:00
|
|
|
} // getKartsDisplayInfo
|
|
|
|
|
2008-09-27 16:49:11 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2013-05-29 18:04:35 -04:00
|
|
|
/** Estimate the arrival time of any karts that haven't arrived yet by using
|
|
|
|
* their average speed up to now and the distance still to race. This
|
|
|
|
* approach guarantees that the order of the karts won't change anymore
|
|
|
|
* (karts ahead will have covered more distance and have therefore a higher
|
|
|
|
* average speed and therefore finish the race earlier than karts further
|
|
|
|
* behind), so the position doesn't have to be updated to get the correct
|
2013-04-04 17:17:39 -04:00
|
|
|
* scoring.
|
|
|
|
* As so often the devil is in the details: a kart that hasn't crossed the
|
|
|
|
* starting line has a negative distance (when it is crossing the start line
|
2013-05-29 18:04:35 -04:00
|
|
|
* its distance becomes 0), which can result in a negative average speed
|
2013-04-04 17:17:39 -04:00
|
|
|
* (and therefore incorrect estimates). This is partly taken care of by
|
|
|
|
* adding m_distance_increase to the distance covered by a kart. The value
|
|
|
|
* of m_distance_increase is a bit more than the distance the last kart
|
|
|
|
* has from the start line at start time. This guarantees that the distance
|
2013-05-29 18:04:35 -04:00
|
|
|
* used in computing the average speed is positive in most cases. Only
|
|
|
|
* exception is if a kart is driving backwards on purpose. While this
|
2013-04-04 17:17:39 -04:00
|
|
|
* shouldn't happen (the AI doesn't do it, and if it's a player the game
|
|
|
|
* won't finish so the time estimation won't be called and so the incorrect
|
|
|
|
* result won't be displayed), this is still taken care of: if the average
|
|
|
|
* speed is negative, the estimated arrival time of the kart is set to
|
|
|
|
* 99:00 plus kart position. This means that even in this case all karts
|
|
|
|
* will have a different arrival time.
|
|
|
|
* \pre The position of the karts are set according to the distance they
|
|
|
|
* have covered.
|
2010-02-07 16:57:10 -05:00
|
|
|
* \param kart The kart for which to estimate the finishing times.
|
|
|
|
*/
|
2012-03-19 16:21:11 -04:00
|
|
|
float LinearWorld::estimateFinishTimeForKart(AbstractKart* kart)
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
2008-12-08 18:23:33 -05:00
|
|
|
const KartInfo &kart_info = m_kart_info[kart->getWorldKartId()];
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2012-02-14 18:25:43 -05:00
|
|
|
float full_distance = race_manager->getNumLaps()
|
|
|
|
* m_track->getTrackLength();
|
2013-04-04 17:17:39 -04:00
|
|
|
|
2012-02-14 18:25:43 -05:00
|
|
|
if(full_distance == 0)
|
2013-04-04 17:17:39 -04:00
|
|
|
full_distance = 1.0f; // For 0 lap races avoid warning below
|
|
|
|
|
2011-08-03 02:21:26 -04:00
|
|
|
#ifdef DEBUG
|
2013-04-04 17:17:39 -04:00
|
|
|
if(kart_info.m_overall_distance > full_distance)
|
2011-08-03 02:21:26 -04:00
|
|
|
{
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", "Full distance < distance covered for kart '%s':",
|
2011-08-03 02:21:26 -04:00
|
|
|
kart->getIdent().c_str());
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", "%f < %f", full_distance, kart_info.m_overall_distance);
|
2011-08-03 02:21:26 -04:00
|
|
|
}
|
|
|
|
#endif
|
2013-05-29 18:04:35 -04:00
|
|
|
// Avoid potential problems (floating point issues, coding bug?) if a
|
2012-02-14 18:25:43 -05:00
|
|
|
// kart has driven more than the full distance, but not finished:
|
|
|
|
// Return the current time plus initial position to spread arrival
|
|
|
|
// times a bit. This code should generally not be used at all, it's
|
|
|
|
// just here to avoid invalid finishing times.
|
2013-04-04 17:17:39 -04:00
|
|
|
if(kart_info.m_overall_distance > full_distance)
|
2011-08-03 02:21:26 -04:00
|
|
|
return getTime() + kart->getInitialPosition();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2012-02-14 18:25:43 -05:00
|
|
|
// Finish time is the time needed for the whole race with
|
2013-04-04 17:17:39 -04:00
|
|
|
// the computed average speed computed. The distance is always positive
|
|
|
|
// due to the way m_distance_increase was computed, so average speed
|
|
|
|
// is also always positive.
|
2013-05-29 18:04:35 -04:00
|
|
|
float average_speed = getTime()==0
|
|
|
|
? 1.0f
|
2013-04-04 17:17:39 -04:00
|
|
|
: (m_distance_increase + kart_info.m_overall_distance)
|
|
|
|
/ getTime();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2013-04-04 17:17:39 -04:00
|
|
|
// Avoid NAN or invalid results when average_speed is very low
|
2013-05-29 18:04:35 -04:00
|
|
|
// or negative (which can happen if a kart drives backwards and
|
2013-04-04 17:17:39 -04:00
|
|
|
// m_overall distance becomes smaller than -m_distance_increase).
|
|
|
|
// In this case set the time to 99 minutes, offset by kart
|
|
|
|
// position (to spread arrival times for all karts that arrive
|
|
|
|
// even later). This works for up to 60 karts (otherwise the
|
|
|
|
// time displayed would become too long: 100:xx:yy).
|
|
|
|
if(average_speed<0.01f)
|
|
|
|
return 99*60.0f + kart->getPosition();
|
|
|
|
|
|
|
|
float est_time = getTime() + (full_distance - kart_info.m_overall_distance)
|
|
|
|
/ average_speed;
|
|
|
|
|
|
|
|
// Avoid times > 99:00 - in this case use kart position to spread
|
|
|
|
// arrival time so that each kart has a unique value. The pre-condition
|
|
|
|
// guarantees that this works correctly (higher position -> less distance
|
|
|
|
// covered -> later arrival time).
|
|
|
|
if(est_time>99*60.0f)
|
|
|
|
return 99*60.0f + kart->getPosition();
|
|
|
|
|
|
|
|
return est_time;
|
2010-02-17 06:59:51 -05:00
|
|
|
} // estimateFinishTimeForKart
|
2008-12-21 19:21:43 -05:00
|
|
|
|
2013-07-10 18:47:12 -04:00
|
|
|
// ------------------------------------------------------------------------
|
2014-03-29 06:33:43 -04:00
|
|
|
/** Returns the number of rescue positions on a given track, which in
|
2013-07-10 18:47:12 -04:00
|
|
|
* linear races is just the number of driveline quads.
|
2008-09-27 16:49:11 -04:00
|
|
|
*/
|
2013-07-10 18:47:12 -04:00
|
|
|
unsigned int LinearWorld::getNumberOfRescuePositions() const
|
|
|
|
{
|
|
|
|
return QuadGraph::get()->getNumNodes();
|
|
|
|
} // getNumberOfRescuePositions
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
unsigned int LinearWorld::getRescuePositionIndex(AbstractKart *kart)
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
|
|
|
KartInfo& info = m_kart_info[kart->getWorldKartId()];
|
2008-12-15 20:42:22 -05:00
|
|
|
|
2013-07-10 18:47:12 -04:00
|
|
|
info.getTrackSector()->rescue();
|
2013-01-02 06:37:29 -05:00
|
|
|
// Setting XYZ for the kart is important since otherwise the kart
|
|
|
|
// will not detect the right material again when doing the next
|
|
|
|
// raycast to detect where it is driving on (--> potential rescue loop)
|
2013-07-10 18:47:12 -04:00
|
|
|
return info.getTrackSector()->getCurrentGraphNode();
|
|
|
|
} // getRescuePositionIndex
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
btTransform LinearWorld::getRescueTransform(unsigned int index) const
|
|
|
|
{
|
|
|
|
const Vec3 &xyz = QuadGraph::get()->getQuadOfNode(index).getCenter();
|
2008-09-27 16:32:07 -04:00
|
|
|
btTransform pos;
|
2013-07-10 18:47:12 -04:00
|
|
|
pos.setOrigin(xyz);
|
2010-02-25 08:20:22 -05:00
|
|
|
pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f),
|
2013-07-10 18:47:12 -04:00
|
|
|
m_track->getAngle(index)));
|
|
|
|
return pos;
|
|
|
|
} // getRescueTransform
|
2008-12-07 20:29:02 -05:00
|
|
|
|
2008-09-27 15:43:57 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2013-05-29 18:04:35 -04:00
|
|
|
/** Find the position (rank) of every kart. ATM it uses a stable O(n^2)
|
2012-11-29 06:59:33 -05:00
|
|
|
* algorithm by counting for each kart how many other karts are ahead of
|
|
|
|
* it.
|
|
|
|
*/
|
2010-03-08 13:39:05 -05:00
|
|
|
void LinearWorld::updateRacePosition()
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
2010-09-05 10:05:59 -04:00
|
|
|
// Mostly for debugging:
|
|
|
|
beginSetKartPositions();
|
2010-02-10 17:59:17 -05:00
|
|
|
const unsigned int kart_amount = m_karts.size();
|
2010-03-08 13:39:05 -05:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2010-08-01 19:30:13 -04:00
|
|
|
bool rank_changed = false;
|
2010-03-08 13:39:05 -05:00
|
|
|
#endif
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2010-08-01 19:30:13 -04:00
|
|
|
// NOTE: if you do any changes to this loop, the next loop (see
|
|
|
|
// DEBUG_KART_RANK below) needs to have the same changes applied
|
|
|
|
// so that debug output is still correct!!!!!!!!!!!
|
2010-03-08 13:39:05 -05:00
|
|
|
for (unsigned int i=0; i<kart_amount; i++)
|
2008-09-27 15:43:57 -04:00
|
|
|
{
|
2012-03-19 16:21:11 -04:00
|
|
|
AbstractKart* kart = m_karts[i];
|
2010-03-15 07:25:01 -04:00
|
|
|
// Karts that are either eliminated or have finished the
|
|
|
|
// race already have their (final) position assigned. If
|
|
|
|
// these karts would get their rank updated, it could happen
|
|
|
|
// that a kart that finished first will be overtaken after
|
|
|
|
// crossing the finishing line and become second!
|
2010-04-11 15:28:53 -04:00
|
|
|
if(kart->isEliminated() || kart->hasFinishedRace())
|
|
|
|
{
|
2010-09-05 10:05:59 -04:00
|
|
|
// This is only necessary to support debugging inconsistencies
|
|
|
|
// in kart position parameters.
|
|
|
|
setKartPosition(i, kart->getPosition());
|
2010-04-11 15:28:53 -04:00
|
|
|
continue;
|
|
|
|
}
|
2010-03-08 13:39:05 -05:00
|
|
|
KartInfo& kart_info = m_kart_info[i];
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2010-03-08 13:39:05 -05:00
|
|
|
int p = 1 ;
|
|
|
|
|
2012-10-21 19:03:08 -04:00
|
|
|
const unsigned int my_id = kart->getWorldKartId();
|
|
|
|
const float my_distance = m_kart_info[my_id].m_overall_distance;
|
2012-10-14 18:23:07 -04:00
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
// Count karts ahead of the current kart, i.e. kart that are
|
2012-10-14 18:23:07 -04:00
|
|
|
// already finished or have covered a larger overall distance.
|
2010-03-08 13:39:05 -05:00
|
|
|
for (unsigned int j = 0 ; j < kart_amount ; j++)
|
2008-12-15 18:37:25 -05:00
|
|
|
{
|
2012-10-14 18:23:07 -04:00
|
|
|
// don't compare a kart with itself and ignore eliminated karts
|
|
|
|
if(j == my_id || m_karts[j]->isEliminated())
|
2013-05-29 18:04:35 -04:00
|
|
|
continue;
|
2012-10-14 18:23:07 -04:00
|
|
|
|
|
|
|
// If the other kart has:
|
2012-10-21 19:03:08 -04:00
|
|
|
// - finished the race (but this kart hasn't)
|
|
|
|
// - or is ahead
|
|
|
|
// - or has the same distance (very unlikely) but started earlier
|
|
|
|
// it is ahead --> increase position
|
|
|
|
if((!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) ||
|
|
|
|
m_kart_info[j].m_overall_distance > my_distance ||
|
|
|
|
(m_kart_info[j].m_overall_distance == my_distance &&
|
|
|
|
m_karts[j]->getInitialPosition()<kart->getInitialPosition() ) )
|
2010-04-11 15:44:52 -04:00
|
|
|
{
|
|
|
|
p++;
|
|
|
|
}
|
2010-03-08 13:39:05 -05:00
|
|
|
|
|
|
|
} //next kart
|
2010-09-05 10:05:59 -04:00
|
|
|
|
|
|
|
#ifndef DEBUG
|
|
|
|
setKartPosition(i, p);
|
|
|
|
#else
|
2010-10-10 22:29:50 -04:00
|
|
|
rank_changed |= kart->getPosition()!=p;
|
2010-09-05 10:05:59 -04:00
|
|
|
if (!setKartPosition(i,p))
|
2010-03-08 13:39:05 -05:00
|
|
|
{
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::error("[LinearWorld]", "Same rank used twice!!");
|
2010-03-08 13:39:05 -05:00
|
|
|
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", "Info used to decide ranking :");
|
2010-03-08 13:39:05 -05:00
|
|
|
for (unsigned int d=0; d<kart_amount; d++)
|
|
|
|
{
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", "Kart %s has finished (%d), is at lap (%u),"
|
|
|
|
"is at distance (%u), is eliminated(%d)",
|
|
|
|
m_karts[d]->getIdent().c_str(),
|
|
|
|
m_karts[d]->hasFinishedRace(),
|
|
|
|
getLapForKart(d),
|
|
|
|
m_kart_info[d].m_overall_distance,
|
|
|
|
m_karts[d]->isEliminated());
|
2010-03-08 13:39:05 -05:00
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", "Who has each ranking so far :");
|
2010-03-08 13:39:05 -05:00
|
|
|
for (unsigned int d=0; d<i; d++)
|
|
|
|
{
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", "%s has rank %d", m_karts[d]->getIdent().c_str(),
|
|
|
|
m_karts[d]->getPosition());
|
2010-03-08 13:39:05 -05:00
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", " --> And %s is being set at rank %d",
|
|
|
|
kart->getIdent().c_str(), p);
|
2010-04-11 15:28:53 -04:00
|
|
|
history->Save();
|
2010-03-08 13:39:05 -05:00
|
|
|
assert(false);
|
2008-12-15 18:37:25 -05:00
|
|
|
}
|
2010-03-08 13:39:05 -05:00
|
|
|
#endif
|
2010-08-01 19:30:13 -04:00
|
|
|
|
2010-03-08 13:39:05 -05:00
|
|
|
// Switch on faster music if not already done so, if the
|
|
|
|
// first kart is doing its last lap, and if the estimated
|
|
|
|
// remaining time is less than 30 seconds.
|
|
|
|
if(!m_faster_music_active &&
|
|
|
|
kart_info.m_race_lap == race_manager->getNumLaps()-1 &&
|
|
|
|
p==1 &&
|
|
|
|
useFastMusicNearEnd() &&
|
|
|
|
kart_info.m_estimated_finish > 0 &&
|
|
|
|
kart_info.m_estimated_finish - getTime() < 30.0f )
|
2008-12-15 18:37:25 -05:00
|
|
|
{
|
2010-04-21 13:24:02 -04:00
|
|
|
music_manager->switchToFastMusic();
|
2010-03-08 13:39:05 -05:00
|
|
|
m_faster_music_active=true;
|
|
|
|
}
|
2010-03-11 21:16:11 -05:00
|
|
|
} // for i<kart_amount
|
2010-08-01 19:30:13 -04:00
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
// Define this to get a detailled analyses each time a race position
|
2010-08-01 19:30:13 -04:00
|
|
|
// changes.
|
2010-10-10 22:49:35 -04:00
|
|
|
#ifdef DEBUG
|
2010-08-01 19:30:13 -04:00
|
|
|
#undef DEBUG_KART_RANK
|
|
|
|
#ifdef DEBUG_KART_RANK
|
|
|
|
if(rank_changed)
|
|
|
|
{
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", "Counting laps at %u seconds.", getTime());
|
2010-08-01 19:30:13 -04:00
|
|
|
for (unsigned int i=0; i<kart_amount; i++)
|
|
|
|
{
|
2012-10-14 18:23:07 -04:00
|
|
|
AbstractKart* kart = m_karts[i];
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", "counting karts ahead of %s (laps %u,"
|
|
|
|
" progress %u, finished %d, eliminated %d, initial position %u.",
|
|
|
|
kart->getIdent().c_str(),
|
|
|
|
m_kart_info[i].m_race_lap,
|
|
|
|
m_kart_info[i].m_overall_distance,
|
|
|
|
kart->hasFinishedRace(),
|
|
|
|
kart->isEliminated(),
|
|
|
|
kart->getInitialPosition());
|
2012-10-14 18:23:07 -04:00
|
|
|
// Karts that are either eliminated or have finished the
|
|
|
|
// race already have their (final) position assigned. If
|
|
|
|
// these karts would get their rank updated, it could happen
|
|
|
|
// that a kart that finished first will be overtaken after
|
|
|
|
// crossing the finishing line and become second!
|
2010-08-01 19:30:13 -04:00
|
|
|
if(kart->isEliminated() || kart->hasFinishedRace()) continue;
|
|
|
|
KartInfo& kart_info = m_kart_info[i];
|
|
|
|
int p = 1 ;
|
2012-10-14 18:23:07 -04:00
|
|
|
const int my_id = kart->getWorldKartId();
|
|
|
|
const float my_distance = m_kart_info[my_id].m_overall_distance;
|
|
|
|
|
2010-08-01 19:30:13 -04:00
|
|
|
for (unsigned int j = 0 ; j < kart_amount ; j++)
|
|
|
|
{
|
2012-10-14 18:23:07 -04:00
|
|
|
if(j == my_id) continue;
|
|
|
|
if(m_karts[j]->isEliminated())
|
|
|
|
{
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", " %u: %s because it is eliminated.",
|
|
|
|
p, m_karts[j]->getIdent().c_str());
|
2013-05-29 18:04:35 -04:00
|
|
|
continue;
|
2012-10-14 18:23:07 -04:00
|
|
|
}
|
2010-08-01 19:30:13 -04:00
|
|
|
if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace())
|
|
|
|
{
|
|
|
|
p++;
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", " %u: %s because it has finished the race.",
|
|
|
|
p, m_karts[j]->getIdent().c_str());
|
2010-08-01 19:30:13 -04:00
|
|
|
continue;
|
|
|
|
}
|
2012-10-14 18:23:07 -04:00
|
|
|
if(m_kart_info[j].m_overall_distance > my_distance)
|
2010-08-01 19:30:13 -04:00
|
|
|
{
|
2012-10-14 18:23:07 -04:00
|
|
|
p++;
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]", " %u: %s because it is ahead %u.",
|
|
|
|
p, m_karts[j]->getIdent().c_str(),
|
|
|
|
m_kart_info[j].m_overall_distance);
|
2010-08-01 19:30:13 -04:00
|
|
|
continue;
|
|
|
|
}
|
2012-10-14 18:23:07 -04:00
|
|
|
if(m_kart_info[j].m_overall_distance == my_distance &&
|
2013-04-03 17:15:13 -04:00
|
|
|
m_karts[j]->getInitialPosition()<kart->getInitialPosition())
|
2010-08-01 19:30:13 -04:00
|
|
|
{
|
|
|
|
p++;
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("[LinearWorld]"," %u: %s has same distance, but started ahead %d",
|
|
|
|
p, m_karts[j]->getIdent().c_str(),
|
|
|
|
m_karts[j]->getInitialPosition());
|
2010-08-01 19:30:13 -04:00
|
|
|
}
|
2012-10-14 18:23:07 -04:00
|
|
|
} // next kart j
|
2010-08-01 19:30:13 -04:00
|
|
|
} // for i<kart_amount
|
2014-02-06 17:17:49 -05:00
|
|
|
Log::debug("LinearWorld]", "-------------------------------------------");
|
2010-08-01 19:30:13 -04:00
|
|
|
} // if rank_changed
|
2010-10-10 22:49:35 -04:00
|
|
|
#endif
|
2010-08-01 19:30:13 -04:00
|
|
|
#endif
|
|
|
|
|
2010-09-05 10:05:59 -04:00
|
|
|
endSetKartPositions();
|
2008-09-27 15:43:57 -04:00
|
|
|
} // updateRacePosition
|
2008-12-21 19:33:25 -05:00
|
|
|
|
2008-12-21 19:21:43 -05:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Checks if a kart is going in the wrong direction. This is done only for
|
|
|
|
* player karts to display a message to the player.
|
|
|
|
* \param i Kart id.
|
|
|
|
*/
|
|
|
|
void LinearWorld::checkForWrongDirection(unsigned int i)
|
|
|
|
{
|
2010-02-14 19:54:28 -05:00
|
|
|
if(!m_karts[i]->getController()->isPlayerController()) return;
|
2013-07-10 18:47:12 -04:00
|
|
|
if(!m_kart_info[i].getTrackSector()->isOnRoad()||
|
2012-04-01 18:57:41 -04:00
|
|
|
m_karts[i]->getKartAnimation()) return;
|
2008-12-21 19:21:43 -05:00
|
|
|
|
2012-03-19 16:21:11 -04:00
|
|
|
const AbstractKart *kart=m_karts[i];
|
2009-05-18 00:08:00 -04:00
|
|
|
// If the kart can go in more than one directions from the current track
|
|
|
|
// don't do any reverse message handling, since it is likely that there
|
|
|
|
// will be one direction in which it isn't going backwards anyway.
|
2013-07-10 18:47:12 -04:00
|
|
|
int sector = m_kart_info[i].getTrackSector()->getCurrentGraphNode();
|
2011-08-04 19:33:41 -04:00
|
|
|
if(QuadGraph::get()->getNumberOfSuccessors(sector)>1)
|
2009-05-18 00:08:00 -04:00
|
|
|
return;
|
2009-08-18 06:33:21 -04:00
|
|
|
|
2008-12-21 19:21:43 -05:00
|
|
|
// check if the player is going in the wrong direction
|
2010-02-25 08:20:22 -05:00
|
|
|
float angle_diff = kart->getHeading() -
|
2011-08-04 19:33:41 -04:00
|
|
|
m_track->getAngle(sector);
|
2008-12-21 19:21:43 -05:00
|
|
|
if(angle_diff > M_PI) angle_diff -= 2*M_PI;
|
|
|
|
else if (angle_diff < -M_PI) angle_diff += 2*M_PI;
|
|
|
|
// Display a warning message if the kart is going back way (unless
|
|
|
|
// the kart has already finished the race).
|
2009-07-02 20:51:31 -04:00
|
|
|
if (( angle_diff > DEGREE_TO_RAD* 120.0f ||
|
|
|
|
angle_diff < -DEGREE_TO_RAD*120.0f) &&
|
2008-12-21 19:21:43 -05:00
|
|
|
kart->getVelocityLC().getY() > 0.0f &&
|
|
|
|
!kart->hasFinishedRace() )
|
|
|
|
{
|
2011-09-15 21:49:38 -04:00
|
|
|
m_race_gui->addMessage(_("WRONG WAY!"), kart,
|
|
|
|
/* time */ -1.0f,
|
|
|
|
video::SColor(255,255,255,255),
|
|
|
|
/*important*/ true,
|
|
|
|
/*big font*/ true);
|
2008-12-21 19:21:43 -05:00
|
|
|
} // if angle is too big
|
|
|
|
} // checkForWrongDirection
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|