Mammoth patch to try and encapsulate sector and lap code better in modes. Still work in progress so expect suboptimal implementations and breakage. Known to be broken at this stage : opponents' times at the end of a lap, rescue button and rescuing in general, shortcut detection
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2303 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -146,6 +146,7 @@ supertuxkart_SOURCES = main.cpp \
|
||||
modes/standard_race.cpp modes/standard_race.hpp \
|
||||
modes/clock.cpp modes/clock.hpp \
|
||||
modes/world.cpp modes/world.hpp \
|
||||
modes/linear_world.cpp modes/linear_world.hpp \
|
||||
replay_buffer_tpl.hpp \
|
||||
replay_buffers.hpp replay_buffers.cpp \
|
||||
replay_base.hpp replay_base.cpp \
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "grand_prix_manager.hpp"
|
||||
#include "kart.hpp"
|
||||
#include "track.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
# define snprintf _snprintf
|
||||
@@ -234,7 +235,13 @@ bool ChallengeData::raceFinished()
|
||||
}
|
||||
// Quickrace / Timetrial
|
||||
// ---------------------
|
||||
if(kart->getLap()!=m_num_laps) return false; // wrong number of laps
|
||||
// FIXME - encapsulate this better, each race mode needs to be able to specify
|
||||
// its own challenges and deal with them
|
||||
LinearWorld* lworld = dynamic_cast<LinearWorld*>(RaceManager::getWorld());
|
||||
if(lworld != NULL)
|
||||
{
|
||||
if(lworld->getLapForKart( kart->getWorldKartId() ) != m_num_laps) return false; // wrong number of laps
|
||||
}
|
||||
if(m_time>0.0f && kart->getFinishTime()>m_time) return false; // too slow
|
||||
return true;
|
||||
} // raceFinished
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "utils/ssg_help.hpp"
|
||||
#include "race_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
|
||||
// static variables:
|
||||
float Flyable::m_st_speed[COLLECT_MAX];
|
||||
@@ -145,9 +146,15 @@ void Flyable::getClosestKart(const Kart **minKart, float *minDistSquared,
|
||||
if(inFrontOf != NULL)
|
||||
{
|
||||
// Ignore karts behind the current one
|
||||
float distance = kart->getDistanceDownTrack() - inFrontOf->getDistanceDownTrack();
|
||||
if(distance<0) distance += RaceManager::getTrack()->getTrackLength();
|
||||
if(distance > 50){ continue; }
|
||||
// FIXME - needs an implementation that doesn't rely on drivelines
|
||||
LinearWorld* lworld = dynamic_cast<LinearWorld*>(RaceManager::getWorld());
|
||||
if(lworld != NULL)
|
||||
{
|
||||
float distance = lworld->getDistanceDownTrackForKart( kart->getWorldKartId() ) -
|
||||
lworld->getDistanceDownTrackForKart( inFrontOf->getWorldKartId() );
|
||||
if(distance<0) distance += RaceManager::getTrack()->getTrackLength();
|
||||
if(distance > 50){ continue; }
|
||||
}
|
||||
}
|
||||
|
||||
if(distance2 < *minDistSquared || *minDistSquared < 0 /* not yet set */)
|
||||
|
||||
@@ -126,7 +126,7 @@ BaseGUI::update(float dt)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
BaseGUI::TimeToString(const double TIME, char *s)
|
||||
BaseGUI::TimeToString(const double TIME, char *s) const
|
||||
{
|
||||
int min = (int) floor ( TIME / 60.0 ) ;
|
||||
int sec = (int) floor ( TIME - (double) ( 60 * min ) ) ;
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
void lockInput() { m_locked = true; }
|
||||
void unlockInput() { m_locked = false; }
|
||||
|
||||
void TimeToString(const double time, char *s);
|
||||
void TimeToString(const double time, char *s) const;
|
||||
protected:
|
||||
|
||||
bool m_locked;
|
||||
|
||||
@@ -318,7 +318,7 @@ void RaceGUI::drawMap ()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Draw players position on the race
|
||||
void RaceGUI::drawPlayerIcons ()
|
||||
void RaceGUI::drawPlayerIcons (const KartIconDisplayInfo* info)
|
||||
{
|
||||
assert(RaceManager::getWorld() != NULL);
|
||||
|
||||
@@ -329,83 +329,26 @@ void RaceGUI::drawPlayerIcons ()
|
||||
|
||||
//glEnable(GL_TEXTURE_2D);
|
||||
Material *last_players_gst = 0;
|
||||
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
|
||||
for(unsigned int i = 0; i < race_manager->getNumKarts() ; i++)
|
||||
{
|
||||
Kart* kart = RaceManager::getKart(i);
|
||||
if(kart->isEliminated()) continue;
|
||||
float lap_time = kart->getTimeAtLap();
|
||||
int laps = kart->getLap();
|
||||
|
||||
if(laps > laps_of_leader)
|
||||
{
|
||||
// more laps than current leader --> new leader and new time computation
|
||||
laps_of_leader = laps;
|
||||
time_of_leader = lap_time;
|
||||
} else if(laps == laps_of_leader)
|
||||
{
|
||||
// Same number of laps as leader: use fastest time
|
||||
time_of_leader=std::min(time_of_leader,lap_time);
|
||||
}
|
||||
} // for i<getNumKarts
|
||||
|
||||
int bFirst = 1;
|
||||
for(unsigned int i = 0; i < race_manager->getNumKarts() ; i++)
|
||||
const int kart_amount = race_manager->getNumKarts();
|
||||
for(unsigned int i = 0; i < kart_amount ; i++)
|
||||
{
|
||||
Kart* kart = RaceManager::getKart(i);
|
||||
if(kart->isEliminated()) continue;
|
||||
int position = kart->getPosition();
|
||||
int lap = kart->getLap();
|
||||
|
||||
y = user_config->m_height*3/4-20 - ((position-1)*(ICON_PLAYER_WIDHT+2));
|
||||
|
||||
// draw text
|
||||
GLfloat COLORS[] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
int numLaps = race_manager->getNumLaps();
|
||||
|
||||
if(lap>=numLaps)
|
||||
{ // kart is finished, display in green
|
||||
COLORS[1] = COLORS[2] = 0;
|
||||
}
|
||||
else if(lap>=0 && numLaps>1)
|
||||
{
|
||||
COLORS[1] = COLORS[2] = 1.0f-(float)lap/((float)numLaps-1.0f);
|
||||
}
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if(laps_of_leader>0 && // Display position during first lap
|
||||
(RaceManager::getWorld()->getTime() - kart->getTimeAtLap()<5.0f || lap!=laps_of_leader) &&
|
||||
race_manager->raceHasLaps())
|
||||
{ // Display for 5 seconds
|
||||
char str[256];
|
||||
if(position==1)
|
||||
{
|
||||
str[0]=' '; str[1]=0;
|
||||
TimeToString(kart->getTimeAtLap(), str+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
float timeBehind;
|
||||
timeBehind = (lap==laps_of_leader ? kart->getTimeAtLap() : RaceManager::getWorld()->getTime())
|
||||
- time_of_leader;
|
||||
str[0]='+'; str[1]=0;
|
||||
TimeToString(timeBehind, str+1);
|
||||
}
|
||||
font_race->PrintShadow(str, 30, ICON_PLAYER_WIDHT+x, y+5,
|
||||
COLORS);
|
||||
}
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER && i==0)
|
||||
GLfloat COLOR[] = {info[i].r, info[i].g, info[i].b, 1.0f};
|
||||
font_race->PrintShadow(info[i].time.c_str(), 30, ICON_PLAYER_WIDHT+x, y+5, COLOR);
|
||||
|
||||
if(info[i].special_title.length() >0)
|
||||
{
|
||||
GLfloat const RED[] = { 1.0f, 0, 0, 1.0f};
|
||||
font_race->PrintShadow(_("Leader"), 30, ICON_PLAYER_WIDHT+x, y+5,
|
||||
RED );
|
||||
font_race->PrintShadow(info[i].special_title.c_str(), 30, ICON_PLAYER_WIDHT+x, y+5, RED );
|
||||
}
|
||||
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
bFirst = 0;
|
||||
@@ -780,12 +723,15 @@ void RaceGUI::drawSpeed(Kart* kart, int offset_x, int offset_y,
|
||||
} // drawSpeed
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void RaceGUI::drawLap(Kart* kart, int offset_x, int offset_y,
|
||||
float ratio_x, float ratio_y )
|
||||
void RaceGUI::drawLap(const KartIconDisplayInfo* info, Kart* kart, int offset_x,
|
||||
int offset_y, float ratio_x, float ratio_y )
|
||||
{
|
||||
// Don't display laps in follow the leader mode
|
||||
if(!race_manager->raceHasLaps()) return;
|
||||
if(kart->getLap()<0) return; // don't display 'lap 0/...'
|
||||
|
||||
const int lap = info[kart->getWorldKartId()].lap;
|
||||
|
||||
if(lap<0) return; // don't display 'lap 0/...', or do nothing if laps are disabled (-1)
|
||||
float maxRatio = std::max(ratio_x, ratio_y);
|
||||
char str[256];
|
||||
offset_x += (int)(120*ratio_x);
|
||||
@@ -802,7 +748,7 @@ void RaceGUI::drawLap(Kart* kart, int offset_x, int offset_y,
|
||||
|
||||
offset_y -= (int)(50*ratio_y);
|
||||
|
||||
sprintf(str, "%d/%d", kart->getLap()<0?0:kart->getLap()+1,
|
||||
sprintf(str, "%d/%d", lap < 0 ? 0 : lap+1,
|
||||
race_manager->getNumLaps());
|
||||
font_race->PrintShadow(str, (int)(48*maxRatio), offset_x, offset_y);
|
||||
}
|
||||
@@ -989,6 +935,8 @@ void RaceGUI::drawStatusText(const float dt)
|
||||
|
||||
if ( RaceManager::getWorld()->getClock().isRacePhase() )
|
||||
{
|
||||
KartIconDisplayInfo* info = RaceManager::getWorld()->getKartsDisplayInfo(this);
|
||||
|
||||
const int numPlayers = race_manager->getNumLocalPlayers();
|
||||
|
||||
for(int pla = 0; pla < numPlayers; pla++)
|
||||
@@ -1034,7 +982,7 @@ void RaceGUI::drawStatusText(const float dt)
|
||||
split_screen_ratio_x, split_screen_ratio_y );
|
||||
drawSpeed (player_kart, offset_x, offset_y,
|
||||
split_screen_ratio_x, split_screen_ratio_y );
|
||||
drawLap (player_kart, offset_x, offset_y,
|
||||
drawLap (info, player_kart, offset_x, offset_y,
|
||||
split_screen_ratio_x, split_screen_ratio_y );
|
||||
drawAllMessages (player_kart, offset_x, offset_y,
|
||||
split_screen_ratio_x, split_screen_ratio_y );
|
||||
@@ -1051,7 +999,7 @@ void RaceGUI::drawStatusText(const float dt)
|
||||
|
||||
drawMap ();
|
||||
if ( user_config->m_display_fps ) drawFPS ();
|
||||
drawPlayerIcons ();
|
||||
drawPlayerIcons (info);
|
||||
} // if RACE_PHASE
|
||||
|
||||
glPopAttrib () ;
|
||||
|
||||
@@ -35,6 +35,21 @@
|
||||
class InputMap;
|
||||
class RaceSetup;
|
||||
|
||||
/**
|
||||
* Used to display the list of karts and their times or
|
||||
* whatever other info is relevant to the current mode.
|
||||
*/
|
||||
struct KartIconDisplayInfo
|
||||
{
|
||||
std::string time;
|
||||
// int rank;
|
||||
float r, g, b;
|
||||
std::string special_title;
|
||||
/** Current lap of this kart, or -1 if irrelevant
|
||||
*/
|
||||
int lap;
|
||||
};
|
||||
|
||||
class RaceGUI: public BaseGUI
|
||||
{
|
||||
|
||||
@@ -104,7 +119,7 @@ private:
|
||||
void drawAllMessages (Kart* player_kart,
|
||||
int offset_x, int offset_y,
|
||||
float ratio_x, float ratio_y );
|
||||
void drawPlayerIcons ();
|
||||
void drawPlayerIcons (const KartIconDisplayInfo* info);
|
||||
void oldDrawPlayerIcons ();
|
||||
void drawMap ();
|
||||
void drawTimer ();
|
||||
@@ -122,8 +137,8 @@ private:
|
||||
float ratio_x, float ratio_y );
|
||||
void drawSpeed (Kart* kart, int offset_x, int offset_y,
|
||||
float ratio_x, float ratio_y );
|
||||
void drawLap (Kart* kart, int offset_x, int offset_y,
|
||||
float ratio_x, float ratio_y );
|
||||
void drawLap (const KartIconDisplayInfo* info, Kart* kart, int offset_x,
|
||||
int offset_y, float ratio_x, float ratio_y );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
9519653D0E8C592F001BB888 /* linear_world.hpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9519653B0E8C592F001BB888 /* linear_world.hpp */; };
|
||||
9519653E0E8C592F001BB888 /* linear_world.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9519653C0E8C592F001BB888 /* linear_world.cpp */; };
|
||||
95F0F25A0E85C054005F6693 /* callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = 95923F8B0E808EDC00388BDC /* callbacks.c */; };
|
||||
95F0F25B0E85C054005F6693 /* list.c in Sources */ = {isa = PBXBuildFile; fileRef = 95923FAF0E808EDC00388BDC /* list.c */; };
|
||||
95F0F25C0E85C054005F6693 /* host.c in Sources */ = {isa = PBXBuildFile; fileRef = 95923F9B0E808EDC00388BDC /* host.c */; };
|
||||
@@ -248,12 +250,15 @@
|
||||
files = (
|
||||
95F0F36E0E85C6A6005F6693 /* clock.hpp in CopyFiles */,
|
||||
95F0F3830E85C76B005F6693 /* world.hpp in CopyFiles */,
|
||||
9519653D0E8C592F001BB888 /* linear_world.hpp in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
9519653B0E8C592F001BB888 /* linear_world.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = linear_world.hpp; path = modes/linear_world.hpp; sourceTree = "<group>"; };
|
||||
9519653C0E8C592F001BB888 /* linear_world.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = linear_world.cpp; path = modes/linear_world.cpp; sourceTree = "<group>"; };
|
||||
956F3FAB0E85BE0E006F93B0 /* random_generator.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = random_generator.cpp; sourceTree = "<group>"; };
|
||||
956F3FAC0E85BE0E006F93B0 /* random_generator.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = random_generator.hpp; sourceTree = "<group>"; };
|
||||
956F3FAD0E85BE0E006F93B0 /* ssg_help.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ssg_help.cpp; sourceTree = "<group>"; };
|
||||
@@ -2055,6 +2060,8 @@
|
||||
957B11D70E8320CD002A69EA /* follow_the_leader.hpp */,
|
||||
957B11D80E8320CD002A69EA /* follow_the_leader.cpp */,
|
||||
957B11B30E831DA8002A69EA /* standard_race.hpp */,
|
||||
9519653B0E8C592F001BB888 /* linear_world.hpp */,
|
||||
9519653C0E8C592F001BB888 /* linear_world.cpp */,
|
||||
957B11B40E831DA8002A69EA /* standard_race.cpp */,
|
||||
);
|
||||
name = modes;
|
||||
@@ -2323,6 +2330,7 @@
|
||||
95F0F35D0E85C140005F6693 /* random_generator.cpp in Sources */,
|
||||
95F0F36F0E85C6A6005F6693 /* clock.cpp in Sources */,
|
||||
95F0F3840E85C76B005F6693 /* world.cpp in Sources */,
|
||||
9519653E0E8C592F001BB888 /* linear_world.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2461,6 +2469,7 @@
|
||||
"-lplibssgaux",
|
||||
);
|
||||
PRODUCT_NAME = SuperTuxKart;
|
||||
SDKROOT = "";
|
||||
ZERO_LINK = NO;
|
||||
};
|
||||
name = Release;
|
||||
|
||||
232
src/kart.cpp
232
src/kart.cpp
@@ -66,7 +66,7 @@ Kart::Kart (const std::string& kart_name, int position,
|
||||
#endif
|
||||
{
|
||||
m_kart_properties = kart_properties_manager->getKart(kart_name);
|
||||
m_grid_position = position;
|
||||
//m_grid_position = position;
|
||||
m_initial_position = position;
|
||||
m_num_herrings_gobbled = 0;
|
||||
m_eliminated = false;
|
||||
@@ -78,7 +78,7 @@ Kart::Kart (const std::string& kart_name, int position,
|
||||
m_exhaust_pipe = NULL;
|
||||
m_skidmark_left = NULL;
|
||||
m_skidmark_right = NULL;
|
||||
m_track_sector = Track::UNKNOWN_SECTOR;
|
||||
|
||||
|
||||
// Set position and heading:
|
||||
m_reset_transform = init_transform;
|
||||
@@ -102,7 +102,6 @@ Kart::Kart (const std::string& kart_name, int position,
|
||||
m_wheel_front_r = NULL;
|
||||
m_wheel_rear_l = NULL;
|
||||
m_wheel_rear_r = NULL;
|
||||
m_lap_start_time = -1.0f;
|
||||
|
||||
m_engine_sound = sfx_manager->newSFX(SFXManager::SOUND_ENGINE);
|
||||
|
||||
@@ -346,10 +345,6 @@ void Kart::reset()
|
||||
m_attachment.clear();
|
||||
m_collectable.reset();
|
||||
|
||||
m_race_lap = -1;
|
||||
m_lap_start_time = -1.0f;
|
||||
m_time_at_last_lap = 99999.9f;
|
||||
m_shortcut_sector = Track::UNKNOWN_SECTOR;
|
||||
m_race_position = 9;
|
||||
m_finished_race = false;
|
||||
m_eliminated = false;
|
||||
@@ -372,24 +367,6 @@ void Kart::reset()
|
||||
|
||||
setTrans(m_reset_transform);
|
||||
|
||||
RaceManager::getTrack()->findRoadSector(getXYZ(), &m_track_sector);
|
||||
|
||||
//If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of
|
||||
//the road, so we have to use another function to find the sector.
|
||||
if (m_track_sector == Track::UNKNOWN_SECTOR )
|
||||
{
|
||||
m_on_road = false;
|
||||
m_track_sector = RaceManager::getTrack()->findOutOfRoadSector(
|
||||
getXYZ(), Track::RS_DONT_KNOW, Track::UNKNOWN_SECTOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_on_road = true;
|
||||
}
|
||||
|
||||
RaceManager::getTrack()->spatialToTrack(m_curr_track_coords, getXYZ(),
|
||||
m_track_sector );
|
||||
|
||||
m_vehicle->applyEngineForce (0.0f, 2);
|
||||
m_vehicle->applyEngineForce (0.0f, 3);
|
||||
|
||||
@@ -408,107 +385,6 @@ void Kart::reset()
|
||||
m_rescue = false;
|
||||
TerrainInfo::update(getXYZ());
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int Kart::getSector() const
|
||||
{
|
||||
// this method only makes sense for linear races
|
||||
assert(RaceManager::getWorld()->isLinearRace());
|
||||
return m_track_sector;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
float Kart::getDistanceDownTrack() const
|
||||
{
|
||||
// this method only makes sense for linear races
|
||||
assert(RaceManager::getWorld()->isLinearRace());
|
||||
return m_curr_track_coords.getY();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
float Kart::getDistanceToCenter () const
|
||||
{
|
||||
// this method only makes sense for linear races
|
||||
assert(RaceManager::getWorld()->isLinearRace());
|
||||
return m_curr_track_coords.getX();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Kart::doLapCounting ()
|
||||
{
|
||||
// this method only makes sense for linear races
|
||||
assert(RaceManager::getWorld()->isLinearRace());
|
||||
|
||||
bool newLap = m_last_track_coords[1] > 300.0f && m_curr_track_coords.getY() < 20.0f;
|
||||
if ( newLap )
|
||||
{
|
||||
// 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).
|
||||
if(m_race_lap+1<=race_manager->getNumLaps())
|
||||
{
|
||||
setTimeAtLap(RaceManager::getWorld()->getTime());
|
||||
m_race_lap++ ;
|
||||
}
|
||||
// Race finished
|
||||
// =============
|
||||
if(m_race_lap>=race_manager->getNumLaps() &&
|
||||
race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
raceFinished(RaceManager::getWorld()->getTime());
|
||||
}
|
||||
// Only do timings if original time was set properly. Driving backwards
|
||||
// over the start line will cause the lap start time to be set to -1.
|
||||
if(m_lap_start_time>=0.0)
|
||||
{
|
||||
float time_per_lap;
|
||||
if (m_race_lap == 1) // just completed first lap
|
||||
{
|
||||
time_per_lap=RaceManager::getWorld()->getTime();
|
||||
}
|
||||
else //completing subsequent laps
|
||||
{
|
||||
time_per_lap=RaceManager::getWorld()->getTime()-m_lap_start_time;
|
||||
}
|
||||
|
||||
if(time_per_lap < RaceManager::getWorld()->getFastestLapTime() &&
|
||||
race_manager->raceHasLaps())
|
||||
{
|
||||
RaceManager::getWorld()->setFastestLap(this, time_per_lap);
|
||||
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
|
||||
if(m)
|
||||
{
|
||||
m->addMessage(_("New fastest lap"), NULL,
|
||||
2.0f, 40, 100, 210, 100);
|
||||
char s[20];
|
||||
m->TimeToString(time_per_lap, s);
|
||||
snprintf(m_fastest_lap_message, sizeof(m_fastest_lap_message),
|
||||
"%s: %s",s, getName().c_str());
|
||||
m->addMessage(m_fastest_lap_message, NULL,
|
||||
2.0f, 40, 100, 210, 100);
|
||||
} // if m
|
||||
} // if time_per_lap < RaceManager::getWorld()->getFasterstLapTime()
|
||||
if(isPlayerKart())
|
||||
{
|
||||
// Put in in the highscore list???
|
||||
//printf("Time per lap: %s %f\n", getName().c_str(), time_per_lap);
|
||||
}
|
||||
}
|
||||
m_lap_start_time = RaceManager::getWorld()->getTime();
|
||||
}
|
||||
else if ( m_curr_track_coords.getY() > 300.0f && m_last_track_coords[1] < 20.0f)
|
||||
{
|
||||
m_race_lap-- ;
|
||||
// Prevent cheating by setting time to a negative number, indicating
|
||||
// that the line wasn't crossed properly.
|
||||
m_lap_start_time = -1.0f;
|
||||
} else
|
||||
{ // Switch to fast music in case of follow the leader when only 3 karts are left
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
RaceManager::getWorld()->getCurrentNumKarts()==3)
|
||||
{
|
||||
sound_manager->switchToFastMusic();
|
||||
}
|
||||
}
|
||||
} // doLapCounting
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Kart::raceFinished(float time)
|
||||
{
|
||||
@@ -660,7 +536,7 @@ void Kart::update(float dt)
|
||||
} // if m_rescue
|
||||
m_attachment.update(dt);
|
||||
|
||||
/*smoke drawing control point*/
|
||||
//smoke drawing control point
|
||||
if ( user_config->m_smoke )
|
||||
{
|
||||
if (m_smoke_system != NULL)
|
||||
@@ -668,7 +544,7 @@ void Kart::update(float dt)
|
||||
} // user_config->smoke
|
||||
updatePhysics(dt);
|
||||
|
||||
m_last_track_coords = m_curr_track_coords;
|
||||
//kart_info.m_last_track_coords = kart_info.m_curr_track_coords;
|
||||
|
||||
Moveable::update(dt);
|
||||
|
||||
@@ -720,61 +596,11 @@ void Kart::update(float dt)
|
||||
// Check if any herring was hit.
|
||||
herring_manager->hitHerring(this);
|
||||
|
||||
if(RaceManager::getWorld()->isLinearRace()) updateSectorProgression();
|
||||
//if(RaceManager::getWorld()->isLinearRace()) updateSectorProgression();
|
||||
|
||||
if(!m_finished_race && RaceManager::getWorld()->isLinearRace()) doLapCounting();
|
||||
//if(!m_finished_race && RaceManager::getWorld()->isLinearRace()) doLapCounting();
|
||||
processSkidMarks();
|
||||
}
|
||||
void Kart::updateSectorProgression()
|
||||
{
|
||||
// this method only makes sense for linear races
|
||||
assert(RaceManager::getWorld()->isLinearRace());
|
||||
|
||||
// Save the last valid sector for forced rescue on shortcuts
|
||||
if(m_track_sector != Track::UNKNOWN_SECTOR &&
|
||||
!m_rescue )
|
||||
{
|
||||
m_shortcut_sector = m_track_sector;
|
||||
}
|
||||
|
||||
int prev_sector = m_track_sector;
|
||||
if(!m_rescue)
|
||||
RaceManager::getTrack()->findRoadSector(getXYZ(), &m_track_sector);
|
||||
|
||||
// Check if the kart is taking a shortcut (if it's not already doing one):
|
||||
if(!m_rescue && RaceManager::getTrack()->isShortcut(prev_sector, m_track_sector))
|
||||
{
|
||||
forceRescue(/*is rescue*/ true); // bring karts back to where they left the track.
|
||||
if(isPlayerKart())
|
||||
{
|
||||
|
||||
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
|
||||
// Can happen if the option menu is called
|
||||
if(m)
|
||||
m->addMessage(_("Invalid short-cut!!"), this, 2.0f, 60);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_track_sector == Track::UNKNOWN_SECTOR && !m_rescue)
|
||||
{
|
||||
m_on_road = false;
|
||||
if( m_curr_track_coords[0] > 0.0 )
|
||||
m_track_sector = RaceManager::getTrack()->findOutOfRoadSector(
|
||||
getXYZ(), Track::RS_RIGHT, prev_sector );
|
||||
else
|
||||
m_track_sector = RaceManager::getTrack()->findOutOfRoadSector(
|
||||
getXYZ(), Track::RS_LEFT, prev_sector );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_on_road = true;
|
||||
}
|
||||
|
||||
RaceManager::getTrack()->spatialToTrack( m_curr_track_coords,
|
||||
getXYZ(),
|
||||
m_track_sector );
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set zipper time, and apply one time additional speed boost
|
||||
void Kart::handleZipper()
|
||||
@@ -998,27 +824,17 @@ void Kart::updatePhysics (float dt)
|
||||
} // updatePhysics
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Kart::forceRescue(bool is_shortcut)
|
||||
void Kart::forceRescue()
|
||||
{
|
||||
m_rescue=true;
|
||||
// If rescue is triggered while doing a shortcut, reset the kart to the
|
||||
// segment where the shortcut started!! And then reset the shortcut
|
||||
// flag, so that this shortcut is not counted!
|
||||
if(is_shortcut)
|
||||
{
|
||||
m_track_sector = m_shortcut_sector;
|
||||
}
|
||||
} // forceRescue
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Drops a kart which was rescued back on the track.
|
||||
*/
|
||||
void Kart::endRescue()
|
||||
{
|
||||
if ( m_track_sector > 0 ) m_track_sector-- ;
|
||||
setXYZ( RaceManager::getTrack()->trackToSpatial(m_track_sector) );
|
||||
btQuaternion heading(btVector3(0.0f, 0.0f, 1.0f),
|
||||
DEGREE_TO_RAD(RaceManager::getTrack()->m_angle[m_track_sector]) );
|
||||
setRotation(heading);
|
||||
RaceManager::getWorld()->moveKartAfterRescue(this);
|
||||
|
||||
m_rescue = false ;
|
||||
|
||||
m_body->setLinearVelocity (btVector3(0.0f,0.0f,0.0f));
|
||||
@@ -1028,17 +844,18 @@ void Kart::endRescue()
|
||||
// it feels better if the kart is left where it was. Perhaps
|
||||
// this code should only be used if a rescue was not triggered
|
||||
// by the kart being upside down??
|
||||
// FIXME - why is transform set twice?
|
||||
/*
|
||||
btTransform pos;
|
||||
// A certain epsilon is added here to the Z coordinate (0.1), in case
|
||||
// that the drivelines are somewhat under the track. Otherwise, the
|
||||
// kart will be placed a little bit under the track, triggering
|
||||
// a rescue, ...
|
||||
pos.setOrigin(getXYZ()+btVector3(0, 0, 0.5f*getKartHeight()+0.1f));
|
||||
pos.setRotation(btQuaternion(btVector3(0.0f, 0.0f, 1.0f),
|
||||
DEGREE_TO_RAD(RaceManager::getTrack()->m_angle[m_track_sector])));
|
||||
m_body->setCenterOfMassTransform(pos);
|
||||
*/
|
||||
RaceManager::getWorld()->getPhysics()->addKart(this, m_vehicle);
|
||||
setTrans(pos);
|
||||
//setTrans(pos);
|
||||
} // endRescue
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1199,27 +1016,4 @@ void Kart::updateGraphics(const Vec3& off_xyz, const Vec3& off_hpr)
|
||||
Moveable::updateGraphics(center_shift, Vec3(0, offset_pitch, 0));
|
||||
} // updateGraphics
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float Kart::estimateFinishTime ()
|
||||
{
|
||||
// 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 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 scoring.
|
||||
float distance_covered = getLap()*RaceManager::getTrack()->getTrackLength()
|
||||
+ getDistanceDownTrack();
|
||||
// In case that a kart is rescued behind start line, or ...
|
||||
if(distance_covered<0) distance_covered =1.0f;
|
||||
|
||||
float average_speed = distance_covered/RaceManager::getWorld()->getTime();
|
||||
|
||||
// Finish time is the time needed for the whole race with
|
||||
// the average speed computed above.
|
||||
return race_manager->getNumLaps()*RaceManager::getTrack()->getTrackLength()
|
||||
/ average_speed;
|
||||
|
||||
} // estimateFinishTime
|
||||
/* EOF */
|
||||
|
||||
35
src/kart.hpp
35
src/kart.hpp
@@ -41,34 +41,25 @@ class Kart : public TerrainInfo, public Moveable
|
||||
{
|
||||
private:
|
||||
btTransform m_reset_transform; // reset position
|
||||
Vec3 m_curr_track_coords;
|
||||
Vec3 m_last_track_coords;
|
||||
unsigned int m_world_kart_id; // index of kart in world
|
||||
|
||||
protected:
|
||||
bool m_on_road; // true if the kart is on top of the
|
||||
// road path drawn by the drivelines
|
||||
Attachment m_attachment;
|
||||
Collectable m_collectable;
|
||||
|
||||
int m_grid_position;
|
||||
int m_race_position; // current race position (1-numKarts)
|
||||
int m_initial_position; // initial position of kart
|
||||
|
||||
KartControl m_controls; // The position of the karts controls
|
||||
int m_track_sector; // index in driveline, special values
|
||||
// e.g. UNKNOWN_SECTOR can be negative!
|
||||
|
||||
float m_max_speed; // maximum speed of the kart, computed from
|
||||
float m_max_gear_rpm; //maximum engine rpm's for the current gear
|
||||
float m_max_speed_reverse_ratio;
|
||||
float m_wheelie_angle;
|
||||
float m_zipper_time_left; // zipper time left
|
||||
float m_lap_start_time; // Time at start of a new lap
|
||||
char m_fastest_lap_message[255];
|
||||
//char m_fastest_lap_message[255];
|
||||
float m_bounce_back_time; // a short time after a collision acceleration
|
||||
// is disabled to allow the karts to bounce back
|
||||
|
||||
int m_shortcut_sector; // segment on which the shortcut was started
|
||||
|
||||
// physics parameters, storing it saves time
|
||||
btRaycastVehicle::btVehicleTuning *m_tuning;
|
||||
btCompoundShape m_kart_chassis;
|
||||
@@ -92,8 +83,7 @@ private:
|
||||
SkidMark* m_skidmark_left;
|
||||
SkidMark* m_skidmark_right;
|
||||
|
||||
int m_race_lap; // number of finished(!) laps
|
||||
float m_time_at_last_lap; // time at finishing last lap
|
||||
|
||||
float m_finish_time;
|
||||
bool m_finished_race;
|
||||
|
||||
@@ -113,7 +103,7 @@ protected:
|
||||
and if so assign them to wheel_* variables */
|
||||
void load_wheels (ssgBranch* obj);
|
||||
|
||||
virtual void doLapCounting ();
|
||||
//virtual void doLapCounting ();
|
||||
|
||||
public:
|
||||
Kart(const std::string& kart_name, int position,
|
||||
@@ -135,9 +125,9 @@ public:
|
||||
{ m_race_position = p; }
|
||||
|
||||
// these methods only makes sense for linear races
|
||||
int getSector () const;
|
||||
float getDistanceDownTrack() const;
|
||||
float getDistanceToCenter () const;
|
||||
//int getSector () const;
|
||||
//float getDistanceDownTrack() const;
|
||||
//float getDistanceToCenter () const;
|
||||
|
||||
Attachment *getAttachment () { return &m_attachment; }
|
||||
void setAttachmentType (attachmentType t, float time_left=0.0f,
|
||||
@@ -146,13 +136,12 @@ public:
|
||||
Collectable *getCollectable () { return &m_collectable; }
|
||||
int getNumCollectables () const { return m_collectable.getNum();}
|
||||
int getNumHerring () const { return m_num_herrings_gobbled;}
|
||||
int getLap () const { return m_race_lap; }
|
||||
int getPosition () const { return m_race_position; }
|
||||
int getInitialPosition () const { return m_initial_position; }
|
||||
float getFinishTime () const { return m_finish_time; }
|
||||
bool hasFinishedRace () const { return m_finished_race; }
|
||||
void endRescue ();
|
||||
float estimateFinishTime ();
|
||||
//float estimateFinishTime ();
|
||||
void processSkidMarks ();
|
||||
void getClosestKart (float *cdist, int *closest);
|
||||
void updatePhysics (float dt);
|
||||
@@ -197,8 +186,6 @@ public:
|
||||
const KartControl&
|
||||
getControls () const {return m_controls; }
|
||||
float getMaxSpeed () const {return m_max_speed; }
|
||||
void setTimeAtLap (float t){m_time_at_last_lap=t; }
|
||||
float getTimeAtLap () const {return m_time_at_last_lap; }
|
||||
void createPhysics (ssgEntity *obj);
|
||||
float getKartLength () const {return m_kart_properties->getKartLength();}
|
||||
float getKartHeight () const {return m_kart_properties->getKartHeight();}
|
||||
@@ -220,7 +207,7 @@ public:
|
||||
bool isRescue () const {return m_rescue;}
|
||||
void resetBrakes ();
|
||||
void adjustSpeedWeight(float f);
|
||||
void forceRescue (bool is_rescue=false);
|
||||
void forceRescue ();
|
||||
void handleExplosion (const Vec3& pos, bool direct_hit);
|
||||
const std::string& getName () const {return m_kart_properties->getName();}
|
||||
const std::string& getIdent () const {return m_kart_properties->getIdent();}
|
||||
@@ -233,7 +220,7 @@ public:
|
||||
virtual void crashed (Kart *k);
|
||||
|
||||
virtual void update (float dt);
|
||||
void updateSectorProgression();
|
||||
//void updateSectorProgression();
|
||||
virtual void raceFinished (float time);
|
||||
};
|
||||
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
#include "unlock_manager.hpp"
|
||||
#include "gui/menu_manager.hpp"
|
||||
#include "user_config.hpp"
|
||||
#include "translation.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
FollowTheLeaderRace::FollowTheLeaderRace() : World(), Clock::ClockListener()
|
||||
FollowTheLeaderRace::FollowTheLeaderRace() : LinearWorld(), Clock::ClockListener()
|
||||
{
|
||||
m_leader_intervals = stk_config->m_leader_intervals;
|
||||
|
||||
@@ -67,7 +68,7 @@ void FollowTheLeaderRace::update(float delta)
|
||||
{
|
||||
m_clock.updateClock(delta);
|
||||
|
||||
World::update(delta);
|
||||
LinearWorld::update(delta);
|
||||
if(!m_clock.isRacePhase()) return;
|
||||
|
||||
if(m_clock.getTime() < 0.0f)
|
||||
@@ -125,4 +126,10 @@ void FollowTheLeaderRace::restartRace()
|
||||
std::string FollowTheLeaderRace::getInternalCode() const
|
||||
{
|
||||
return "FOLLOW_LEADER";
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
KartIconDisplayInfo* FollowTheLeaderRace::getKartsDisplayInfo(const RaceGUI* caller)
|
||||
{
|
||||
LinearWorld::getKartsDisplayInfo(caller);
|
||||
m_kart_display_info[0].special_title = _("Leader");
|
||||
}
|
||||
@@ -18,9 +18,9 @@
|
||||
#ifndef _follow_the_leader_hpp_
|
||||
#define _follow_the_leader_hpp_
|
||||
|
||||
#include "modes/world.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
|
||||
class FollowTheLeaderRace : public World, public Clock::ClockListener
|
||||
class FollowTheLeaderRace : public LinearWorld, public Clock::ClockListener
|
||||
{
|
||||
std::vector<float> m_leader_intervals; // time till elimination in follow leader
|
||||
public:
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
virtual void restartRace();
|
||||
virtual std::string getInternalCode() const;
|
||||
virtual bool useFastMusicNearEnd() const { return false; }
|
||||
virtual KartIconDisplayInfo* getKartsDisplayInfo(const RaceGUI* caller);
|
||||
};
|
||||
|
||||
|
||||
|
||||
469
src/modes/linear_world.cpp
Normal file
469
src/modes/linear_world.cpp
Normal file
@@ -0,0 +1,469 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004 SuperTuxKart-Team
|
||||
//
|
||||
// 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"
|
||||
#include "gui/race_gui.hpp"
|
||||
|
||||
#include "track.hpp"
|
||||
#include "gui/menu_manager.hpp"
|
||||
#include "translation.hpp"
|
||||
#include "audio/sound_manager.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
LinearWorld::LinearWorld() : World()
|
||||
{
|
||||
const unsigned int kart_amount = m_kart.size();
|
||||
|
||||
m_kart_display_info = new KartIconDisplayInfo[kart_amount];
|
||||
|
||||
for(unsigned int n=0; n<kart_amount; n++)
|
||||
{
|
||||
KartInfo info;
|
||||
info.m_track_sector = Track::UNKNOWN_SECTOR;
|
||||
info.m_lap_start_time = -1.0f;
|
||||
info.m_shortcut_sector = Track::UNKNOWN_SECTOR;
|
||||
RaceManager::getTrack()->findRoadSector(m_kart[n]->getXYZ(), &info.m_track_sector);
|
||||
|
||||
//If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of
|
||||
//the road, so we have to use another function to find the sector.
|
||||
if (info.m_track_sector == Track::UNKNOWN_SECTOR )
|
||||
{
|
||||
info.m_on_road = false;
|
||||
info.m_track_sector =
|
||||
RaceManager::getTrack()->findOutOfRoadSector(m_kart[n]->getXYZ(),
|
||||
Track::RS_DONT_KNOW,
|
||||
Track::UNKNOWN_SECTOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
info.m_on_road = true;
|
||||
}
|
||||
|
||||
RaceManager::getTrack()->spatialToTrack(info.m_curr_track_coords,
|
||||
m_kart[n]->getXYZ(),
|
||||
info.m_track_sector );
|
||||
|
||||
info.m_race_lap = -1;
|
||||
info.m_lap_start_time = -1.0f;
|
||||
info.m_time_at_last_lap = 99999.9f;
|
||||
|
||||
m_kart_info.push_back(info);
|
||||
|
||||
}// next kart
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void LinearWorld::update(float delta)
|
||||
{
|
||||
// store previous kart locations
|
||||
const unsigned int kart_amount = m_kart_info.size();
|
||||
for(unsigned int n=0; n<kart_amount; n++)
|
||||
{
|
||||
m_kart_info[n].m_last_track_coords = m_kart_info[n].m_curr_track_coords;
|
||||
}
|
||||
|
||||
// run generic parent stuff that applies to all modes
|
||||
World::update(delta);
|
||||
|
||||
// ------------- do stuff specific to this subtype of race -----
|
||||
|
||||
for(unsigned int n=0; n<kart_amount; n++)
|
||||
{
|
||||
KartInfo& kart_info = m_kart_info[n];
|
||||
Kart* kart = m_kart[n];
|
||||
|
||||
// ---------- update rank ------
|
||||
if(!m_kart[n]->hasFinishedRace()) updateRacePosition(kart, kart_info);
|
||||
}
|
||||
for(unsigned int n=0; n<kart_amount; n++)
|
||||
{
|
||||
KartInfo& kart_info = m_kart_info[n];
|
||||
Kart* kart = m_kart[n];
|
||||
|
||||
// ---------- deal with sector data ---------
|
||||
// Save the last valid sector for forced rescue on shortcuts
|
||||
if(kart_info.m_track_sector != Track::UNKNOWN_SECTOR &&
|
||||
!kart->isRescue() )
|
||||
{
|
||||
kart_info.m_shortcut_sector = kart_info.m_track_sector;
|
||||
}
|
||||
|
||||
int prev_sector = kart_info.m_track_sector;
|
||||
if(!kart->isRescue())
|
||||
RaceManager::getTrack()->findRoadSector( kart->getXYZ(), &kart_info.m_track_sector);
|
||||
|
||||
// Check if the kart is taking a shortcut (if it's not already doing one):
|
||||
if(!kart->isRescue() && RaceManager::getTrack()->isShortcut(prev_sector, kart_info.m_track_sector))
|
||||
{
|
||||
forceRescue(kart, kart_info, /*is rescue*/ true); // bring karts back to where they left the track.
|
||||
if(kart->isPlayerKart())
|
||||
{
|
||||
|
||||
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
|
||||
// Can happen if the option menu is called
|
||||
if(m)
|
||||
m->addMessage(_("Invalid short-cut!!"), kart, 2.0f, 60);
|
||||
}
|
||||
}
|
||||
|
||||
if (kart_info.m_track_sector == Track::UNKNOWN_SECTOR && !kart->isRescue())
|
||||
{
|
||||
kart_info.m_on_road = false;
|
||||
if( kart_info.m_curr_track_coords[0] > 0.0 )
|
||||
kart_info.m_track_sector =
|
||||
RaceManager::getTrack()->findOutOfRoadSector( kart->getXYZ(),
|
||||
Track::RS_RIGHT,
|
||||
prev_sector );
|
||||
else
|
||||
kart_info.m_track_sector =
|
||||
RaceManager::getTrack()->findOutOfRoadSector( kart->getXYZ(),
|
||||
Track::RS_LEFT,
|
||||
prev_sector );
|
||||
}
|
||||
else
|
||||
{
|
||||
kart_info.m_on_road = true;
|
||||
}
|
||||
|
||||
RaceManager::getTrack()->spatialToTrack( kart_info.m_curr_track_coords /* out */,
|
||||
kart->getXYZ(),
|
||||
kart_info.m_track_sector );
|
||||
|
||||
// ------- check the kart isn't going in the wrong way ------
|
||||
// only relevant for player karts
|
||||
if(m_kart[n]->isPlayerKart())
|
||||
{
|
||||
RaceGUI* m=menu_manager->getRaceMenu();
|
||||
// This can happen if the option menu is called, since the
|
||||
// racegui gets deleted
|
||||
if(!m) return;
|
||||
|
||||
// check if the player is going in the wrong direction
|
||||
if(race_manager->getDifficulty()==RaceManager::RD_EASY)
|
||||
{
|
||||
float angle_diff = RAD_TO_DEGREE(kart->getHPR().getHeading()) -
|
||||
RaceManager::getTrack()->m_angle[kart_info.m_track_sector];
|
||||
if(angle_diff > 180.0f) angle_diff -= 360.0f;
|
||||
else if (angle_diff < -180.0f) angle_diff += 360.0f;
|
||||
// Display a warning message if the kart is going back way (unless
|
||||
// the kart has already finished the race).
|
||||
if ((angle_diff > 120.0f || angle_diff < -120.0f) &&
|
||||
kart->getVelocity().getY() > 0.0f && !kart->hasFinishedRace() )
|
||||
{
|
||||
m->addMessage(_("WRONG WAY!"), kart, -1.0f, 60);
|
||||
} // if angle is too big
|
||||
} // if difficulty easy
|
||||
}// end if is player kart
|
||||
|
||||
// --------- do lap counting ------
|
||||
doLapCounting(kart_info, kart);
|
||||
}// next kart
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void LinearWorld::doLapCounting ( KartInfo& kart_info, Kart* kart )
|
||||
{
|
||||
bool newLap = kart_info.m_last_track_coords[1] > 300.0f &&
|
||||
kart_info.m_curr_track_coords.getY() < 20.0f;
|
||||
if ( newLap )
|
||||
{
|
||||
// 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).
|
||||
if(kart_info.m_race_lap+1 <= race_manager->getNumLaps())
|
||||
{
|
||||
setTimeAtLapForKart( RaceManager::getWorld()->getTime(), kart->getWorldKartId() );
|
||||
kart_info.m_race_lap++ ;
|
||||
}
|
||||
// Race finished
|
||||
// =============
|
||||
if(kart_info.m_race_lap >= race_manager->getNumLaps() &&
|
||||
race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
kart->raceFinished(RaceManager::getWorld()->getTime());
|
||||
}
|
||||
// Only do timings if original time was set properly. Driving backwards
|
||||
// over the start line will cause the lap start time to be set to -1.
|
||||
if(kart_info.m_lap_start_time>=0.0)
|
||||
{
|
||||
float time_per_lap;
|
||||
if (kart_info.m_race_lap == 1) // just completed first lap
|
||||
{
|
||||
time_per_lap=RaceManager::getWorld()->getTime();
|
||||
}
|
||||
else //completing subsequent laps
|
||||
{
|
||||
time_per_lap=RaceManager::getWorld()->getTime() - kart_info.m_lap_start_time;
|
||||
}
|
||||
|
||||
if(time_per_lap < RaceManager::getWorld()->getFastestLapTime() &&
|
||||
race_manager->raceHasLaps())
|
||||
{
|
||||
RaceManager::getWorld()->setFastestLap(kart, time_per_lap);
|
||||
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
|
||||
if(m)
|
||||
{
|
||||
m->addMessage(_("New fastest lap"), NULL,
|
||||
2.0f, 40, 100, 210, 100);
|
||||
char s[20];
|
||||
m->TimeToString(time_per_lap, s);
|
||||
|
||||
char m_fastest_lap_message[255];
|
||||
snprintf(m_fastest_lap_message, sizeof(m_fastest_lap_message),
|
||||
"%s: %s",s, kart->getName().c_str());
|
||||
m->addMessage(m_fastest_lap_message, NULL,
|
||||
2.0f, 40, 100, 210, 100);
|
||||
} // if m
|
||||
} // if time_per_lap < RaceManager::getWorld()->getFasterstLapTime()
|
||||
//if(kart->isPlayerKart())
|
||||
//{
|
||||
// Put in in the highscore list???
|
||||
//printf("Time per lap: %s %f\n", getName().c_str(), time_per_lap);
|
||||
//}
|
||||
}
|
||||
kart_info.m_lap_start_time = RaceManager::getWorld()->getTime();
|
||||
}
|
||||
else if ( kart_info.m_curr_track_coords.getY() > 300.0f && kart_info.m_last_track_coords[1] < 20.0f)
|
||||
{
|
||||
kart_info.m_race_lap-- ;
|
||||
// Prevent cheating by setting time to a negative number, indicating
|
||||
// that the line wasn't crossed properly.
|
||||
kart_info.m_lap_start_time = -1.0f;
|
||||
} else
|
||||
{ // Switch to fast music in case of follow the leader when only 3 karts are left
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
RaceManager::getWorld()->getCurrentNumKarts()==3)
|
||||
{
|
||||
sound_manager->switchToFastMusic();
|
||||
}
|
||||
}
|
||||
} // doLapCounting
|
||||
//-----------------------------------------------------------------------------
|
||||
int LinearWorld::getSectorForKart(const int kart_id) const
|
||||
{
|
||||
return m_kart_info[kart_id].m_track_sector;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
float LinearWorld::getDistanceDownTrackForKart(const int kart_id) const
|
||||
{
|
||||
return m_kart_info[kart_id].m_curr_track_coords.getY();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
float LinearWorld::getDistanceToCenterForKart(const int kart_id) const
|
||||
{
|
||||
return m_kart_info[kart_id].m_curr_track_coords.getX();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
int LinearWorld::getLapForKart(const int kart_id) const
|
||||
{
|
||||
return m_kart_info[kart_id].m_race_lap;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void LinearWorld::setTimeAtLapForKart(float t, const int kart_id)
|
||||
{
|
||||
m_kart_info[kart_id].m_time_at_last_lap=t;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
float LinearWorld::getTimeAtLapForKart(const int kart_id) const
|
||||
{
|
||||
return m_kart_info[kart_id].m_time_at_last_lap;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
KartIconDisplayInfo* LinearWorld::getKartsDisplayInfo(const RaceGUI* caller)
|
||||
{
|
||||
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
|
||||
const int kart_amount = race_manager->getNumKarts();
|
||||
for(unsigned int i = 0; i < kart_amount ; i++)
|
||||
{
|
||||
KartIconDisplayInfo& rank_info = m_kart_display_info[i];
|
||||
KartInfo& kart_info = m_kart_info[i];
|
||||
Kart* kart = m_kart[i];
|
||||
|
||||
// reset color
|
||||
rank_info.r = 1.0;
|
||||
rank_info.g = 1.0;
|
||||
rank_info.b = 1.0;
|
||||
rank_info.lap = -1;
|
||||
|
||||
if(kart->isEliminated()) continue;
|
||||
const float lap_time = getTimeAtLapForKart(kart->getWorldKartId());
|
||||
const int current_lap = getLapForKart( kart->getWorldKartId() );
|
||||
rank_info.lap = current_lap;
|
||||
//rank_info.rank = kart->getPosition();
|
||||
const int position = kart->getPosition();
|
||||
|
||||
if(current_lap > laps_of_leader)
|
||||
{
|
||||
// more laps than current leader --> new leader and new time computation
|
||||
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);
|
||||
}
|
||||
|
||||
if(laps_of_leader>0 && // Display position during first lap
|
||||
(getTime() - getTimeAtLapForKart(kart->getWorldKartId())<5.0f || current_lap!=laps_of_leader) &&
|
||||
race_manager->raceHasLaps())
|
||||
{ // Display for 5 seconds
|
||||
char str[256];
|
||||
if(position==1)
|
||||
{
|
||||
str[0]=' '; str[1]=0;
|
||||
caller->TimeToString(getTimeAtLapForKart(kart->getWorldKartId()), str+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
float timeBehind;
|
||||
timeBehind = (kart_info.m_race_lap==laps_of_leader ? getTimeAtLapForKart(kart->getWorldKartId()) : RaceManager::getWorld()->getTime())
|
||||
- time_of_leader;
|
||||
str[0]='+'; str[1]=0;
|
||||
caller->TimeToString(timeBehind, str+1);
|
||||
}
|
||||
rank_info.time = str;
|
||||
}
|
||||
else
|
||||
{
|
||||
rank_info.time = "";
|
||||
}
|
||||
|
||||
int numLaps = race_manager->getNumLaps();
|
||||
|
||||
if(kart_info.m_race_lap>=numLaps)
|
||||
{ // kart is finished, display in green
|
||||
rank_info.g = rank_info.b = 0;
|
||||
}
|
||||
else if(kart_info.m_race_lap>=0 && numLaps>1)
|
||||
{
|
||||
rank_info.g = rank_info.b = 1.0f-(float)kart_info.m_race_lap/((float)numLaps-1.0f);
|
||||
}
|
||||
|
||||
} // next kart
|
||||
|
||||
|
||||
return m_kart_display_info;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void LinearWorld::terminateRace()
|
||||
{
|
||||
World::terminateRace();
|
||||
|
||||
// if some karts have not yet finished the race yet, estimate
|
||||
// their times and use these values to proceed without waiting
|
||||
const int kart_amount = m_kart.size();
|
||||
for ( Karts::size_type i = 0; i < kart_amount; ++i)
|
||||
{
|
||||
if(!m_kart[i]->hasFinishedRace())
|
||||
{
|
||||
const float est_finish_time = estimateFinishTimeForKart(m_kart[i], m_kart_info[i]);
|
||||
m_kart[i]->raceFinished(est_finish_time);
|
||||
} // if !hasFinishedRace
|
||||
} // for i
|
||||
}
|
||||
float LinearWorld::estimateFinishTimeForKart (Kart* kart, KartInfo& kart_info)
|
||||
{
|
||||
// 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 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 scoring.
|
||||
float distance_covered = kart_info.m_race_lap * RaceManager::getTrack()->getTrackLength()
|
||||
+ getDistanceDownTrackForKart(kart->getWorldKartId());
|
||||
// In case that a kart is rescued behind start line, or ...
|
||||
if(distance_covered<0) distance_covered =1.0f;
|
||||
|
||||
float average_speed = distance_covered/RaceManager::getWorld()->getTime();
|
||||
|
||||
// Finish time is the time needed for the whole race with
|
||||
// the average speed computed above.
|
||||
return race_manager->getNumLaps()*RaceManager::getTrack()->getTrackLength()
|
||||
/ average_speed;
|
||||
|
||||
} // estimateFinishTime
|
||||
//-----------------------------------------------------------------------------
|
||||
void LinearWorld::forceRescue(Kart* kart, KartInfo& kart_info, bool shortcut)
|
||||
{
|
||||
// If rescue is triggered while doing a shortcut, reset the kart to the
|
||||
// segment where the shortcut started!! And then reset the shortcut
|
||||
// flag, so that this shortcut is not counted!
|
||||
if(shortcut)
|
||||
{
|
||||
kart_info.m_track_sector = kart_info.m_shortcut_sector;
|
||||
}
|
||||
|
||||
kart->forceRescue();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void LinearWorld::moveKartAfterRescue(Kart* kart)
|
||||
{
|
||||
KartInfo& info = m_kart_info[kart->getWorldKartId()];
|
||||
|
||||
if ( info.m_track_sector > 0 ) info.m_track_sector-- ;
|
||||
kart->setXYZ( RaceManager::getTrack()->trackToSpatial(info.m_track_sector) );
|
||||
|
||||
btQuaternion heading(btVector3(0.0f, 0.0f, 1.0f),
|
||||
DEGREE_TO_RAD(RaceManager::getTrack()->m_angle[info.m_track_sector]) );
|
||||
kart->setRotation(heading);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Find the position (rank) of 'kart'
|
||||
*
|
||||
*/
|
||||
void LinearWorld::updateRacePosition ( Kart* kart, KartInfo& kart_info )
|
||||
{
|
||||
int p = 1 ;
|
||||
|
||||
const unsigned int kart_amount = m_kart.size();
|
||||
for ( int j = 0 ; j < kart_amount ; j++ )
|
||||
{
|
||||
if(int(j) == kart->getWorldKartId()) continue; // don't compare a kart with itself
|
||||
if(m_kart[j]->isEliminated()) continue; // dismiss eliminated karts
|
||||
|
||||
// Count karts ahead of the current kart, i.e. kart that are already
|
||||
// finished (the current kart k has not yet finished!!), have done more
|
||||
// laps, or the same number of laps, but a greater distance.
|
||||
if (
|
||||
/* has already finished */
|
||||
m_kart[j]->hasFinishedRace() ||
|
||||
/* has done more lapses */
|
||||
getLapForKart(m_kart[j]->getWorldKartId()) > getLapForKart(kart->getWorldKartId()) ||
|
||||
/* is at the same lap but further in it */
|
||||
(getLapForKart(m_kart[j]->getWorldKartId()) == getLapForKart(kart->getWorldKartId()) &&
|
||||
getDistanceDownTrackForKart(m_kart[j]->getWorldKartId()) > getDistanceDownTrackForKart(kart->getWorldKartId()) )
|
||||
)
|
||||
p++ ;
|
||||
}//next kart
|
||||
|
||||
kart->setPosition(p);
|
||||
// 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() &&
|
||||
estimateFinishTimeForKart( kart, m_kart_info[kart->getWorldKartId()] )-getTime()<30.0f )
|
||||
{
|
||||
sound_manager->switchToFastMusic();
|
||||
m_faster_music_active=true;
|
||||
}
|
||||
} // updateRacePosition
|
||||
89
src/modes/linear_world.hpp
Normal file
89
src/modes/linear_world.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef _LINEAR_WORLD_H_
|
||||
#define _LINEAR_WORLD_H_
|
||||
|
||||
#include "modes/world.hpp"
|
||||
#include <vector>
|
||||
|
||||
struct KartIconDisplayInfo;
|
||||
class RaceGUI;
|
||||
|
||||
/** Some additional info that needs to be kept for each kart
|
||||
* in this kind of race.
|
||||
*/
|
||||
struct KartInfo
|
||||
{
|
||||
int m_race_lap; // number of finished(!) laps
|
||||
float m_time_at_last_lap; // time at finishing last lap
|
||||
float m_lap_start_time; // Time at start of a new lap
|
||||
int m_shortcut_sector; // segment on which the shortcut was started
|
||||
int m_track_sector; // index in driveline, special values
|
||||
// e.g. UNKNOWN_SECTOR can be negative!
|
||||
Vec3 m_curr_track_coords;
|
||||
Vec3 m_last_track_coords;
|
||||
|
||||
bool m_on_road; // true if the kart is on top of the
|
||||
// road path drawn by the drivelines
|
||||
};
|
||||
|
||||
/*
|
||||
* A 'linear world' is a subcategory of world used in 'standard' races, i.e.
|
||||
* with a start line and a road that loops. This includes management of drivelines
|
||||
* and lap counting.
|
||||
*/
|
||||
class LinearWorld : public World
|
||||
{
|
||||
protected:
|
||||
KartIconDisplayInfo* m_kart_display_info;
|
||||
|
||||
/** Linear races can trigger rescues for one additional reason : shortcuts.
|
||||
* It may need to do some specific world before calling the generic Kart::forceRescue
|
||||
*/
|
||||
void forceRescue(Kart* kart, KartInfo& kart_info, bool shortcut);
|
||||
|
||||
void doLapCounting ( KartInfo& kart_info, Kart* kart );
|
||||
|
||||
public:
|
||||
LinearWorld();
|
||||
|
||||
/** This vector contains an 'KartInfo' struct for every kart in the race.
|
||||
* This member is not strictly private but try not to use it directly outside
|
||||
* tightly related classes (e.g. AI)
|
||||
*/
|
||||
std::vector<KartInfo> m_kart_info;
|
||||
|
||||
virtual void update(float delta);
|
||||
|
||||
int getSectorForKart(const int kart_id) const;
|
||||
float getDistanceDownTrackForKart(const int kart_id) const;
|
||||
float getDistanceToCenterForKart(const int kart_id) const;
|
||||
int getLapForKart(const int kart_id) const;
|
||||
void setTimeAtLapForKart(float t, const int kart_id);
|
||||
float getTimeAtLapForKart(const int kart_id) const;
|
||||
|
||||
virtual KartIconDisplayInfo* getKartsDisplayInfo(const RaceGUI* caller);
|
||||
virtual void moveKartAfterRescue(Kart* kart);
|
||||
|
||||
virtual void terminateRace();
|
||||
|
||||
float estimateFinishTimeForKart (Kart* kart, KartInfo& kart_info);
|
||||
void updateRacePosition ( Kart* kart, KartInfo& kart_info );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "gui/menu_manager.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
StandardRace::StandardRace() : World(), Clock::ClockListener()
|
||||
StandardRace::StandardRace() : LinearWorld(), Clock::ClockListener()
|
||||
{
|
||||
m_clock.registerEventListener(this);
|
||||
m_clock.setMode(CHRONO);
|
||||
@@ -67,7 +67,7 @@ void StandardRace::update(float delta)
|
||||
{
|
||||
m_clock.updateClock(delta);
|
||||
|
||||
World::update(delta);
|
||||
LinearWorld::update(delta);
|
||||
if(!m_clock.isRacePhase()) return;
|
||||
|
||||
// All karts are finished
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
#ifndef _standard_race_
|
||||
#define _standard_race_
|
||||
|
||||
#include "modes/world.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
|
||||
/**
|
||||
* Represents a standard race, i.e. with a start, end and laps.
|
||||
* Used in Grand Prix, Quick Race and Time Trial.
|
||||
*/
|
||||
class StandardRace : public World, public Clock::ClockListener
|
||||
class StandardRace : public LinearWorld, public Clock::ClockListener
|
||||
{
|
||||
public:
|
||||
StandardRace();
|
||||
|
||||
@@ -203,7 +203,6 @@ void World::terminateRace()
|
||||
updateHighscores();
|
||||
m_clock.pause();
|
||||
menu_manager->pushMenu(MENUID_RACERESULT);
|
||||
estimateFinishTimes();
|
||||
unlock_manager->raceFinished();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -276,14 +275,14 @@ void World::update(float dt)
|
||||
|
||||
projectile_manager->update(dt);
|
||||
herring_manager->update(dt);
|
||||
|
||||
/*
|
||||
for ( Karts::size_type i = 0 ; i < kart_amount; ++i)
|
||||
{
|
||||
if(m_kart[i]->isEliminated()) continue; // ignore eliminated kart
|
||||
if(!m_kart[i]->hasFinishedRace()) updateRacePosition((int)i);
|
||||
if(m_kart[i]->isPlayerKart()) m_kart[i]->addMessages(); // add 'wrong direction'
|
||||
//if(isLinearRace() && !m_kart[i]->hasFinishedRace()) updateRacePosition((int)i);
|
||||
//if(m_kart[i]->isPlayerKart()) m_kart[i]->addMessages(); // add 'wrong direction'
|
||||
}
|
||||
|
||||
*/
|
||||
/* Routine stuff we do even when paused */
|
||||
callback_manager->update(dt);
|
||||
}
|
||||
@@ -354,22 +353,6 @@ void World::updateHighscores()
|
||||
}
|
||||
delete []index;
|
||||
} // updateHighscores
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::estimateFinishTimes()
|
||||
{
|
||||
const int kart_amount = m_kart.size();
|
||||
for ( Karts::size_type i = 0; i < kart_amount; ++i)
|
||||
{
|
||||
if(!m_kart[i]->hasFinishedRace())
|
||||
{
|
||||
const float est_finish_time = m_kart[i]->estimateFinishTime();
|
||||
m_kart[i]->raceFinished(est_finish_time);
|
||||
} // if !hasFinishedRace
|
||||
} // for i
|
||||
} // estimateFinishTimes
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::printProfileResultAndExit()
|
||||
{
|
||||
@@ -433,45 +416,6 @@ void World::removeKart(int kart_number)
|
||||
m_eliminated_karts++;
|
||||
|
||||
} // removeKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::updateRacePosition ( int k )
|
||||
{
|
||||
int p = 1 ;
|
||||
|
||||
/* Find position of kart 'k' */
|
||||
|
||||
const unsigned int kart_amount = m_kart.size();
|
||||
for ( Karts::size_type j = 0 ; j < kart_amount ; ++j )
|
||||
{
|
||||
if(int(j) == k) continue;
|
||||
if(m_kart[j]->isEliminated()) continue; // eliminated karts
|
||||
|
||||
// Count karts ahead of the current kart, i.e. kart that are already
|
||||
// finished (the current kart k has not yet finished!!), have done more
|
||||
// laps, or the same number of laps, but a greater distance.
|
||||
if (m_kart[j]->hasFinishedRace() ||
|
||||
m_kart[j]->getLap() > m_kart[k]->getLap() ||
|
||||
(m_kart[j]->getLap() == m_kart[k]->getLap() &&
|
||||
m_kart[j]->getDistanceDownTrack() > m_kart[k]->getDistanceDownTrack()) )
|
||||
p++ ;
|
||||
}
|
||||
|
||||
m_kart[k]->setPosition(p);
|
||||
// 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 &&
|
||||
m_kart[k]->getLap()==race_manager->getNumLaps()-1 &&
|
||||
p==1 &&
|
||||
useFastMusicNearEnd() &&
|
||||
m_kart[k]->estimateFinishTime()-getTime()<30.0f )
|
||||
{
|
||||
sound_manager->switchToFastMusic();
|
||||
m_faster_music_active=true;
|
||||
}
|
||||
} // updateRacePosition
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Cleans up old herrings (from a previous race), removes old track specific
|
||||
* herring models, and loads the actual track.
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include "modes/clock.hpp"
|
||||
|
||||
class SFXBase;
|
||||
struct KartIconDisplayInfo;
|
||||
class RaceGUI;
|
||||
|
||||
/** This class is responsible for running the actual race. A world is created
|
||||
* by the race manager on the start of each race (so a new world is created
|
||||
@@ -75,7 +77,6 @@ class SFXBase;
|
||||
* RaceManager).
|
||||
*/
|
||||
|
||||
|
||||
class World
|
||||
{
|
||||
public:
|
||||
@@ -109,7 +110,7 @@ protected:
|
||||
*/
|
||||
bool m_use_highscores;
|
||||
|
||||
void updateRacePosition(int k);
|
||||
//void updateRacePosition(int k);
|
||||
void updateHighscores ();
|
||||
void loadTrack ();
|
||||
void resetAllKarts ();
|
||||
@@ -156,7 +157,7 @@ public:
|
||||
|
||||
/** Called when race is over and should be terminated (mostly called by the clock).
|
||||
*/
|
||||
void terminateRace();
|
||||
virtual void terminateRace();
|
||||
|
||||
/** Called to determine the default collectibles to give each player for this
|
||||
* kind of race. Both parameters are of 'out' type.
|
||||
@@ -191,6 +192,16 @@ public:
|
||||
* sectors and drivelines are used, etc. This will be off for e.g. battle mode.
|
||||
*/
|
||||
bool isLinearRace() const { return m_linear_race; }
|
||||
|
||||
/** Called by the code that draws the list of karts on the race GUI
|
||||
* to know what needs to be drawn in the current mode
|
||||
*/
|
||||
virtual KartIconDisplayInfo* getKartsDisplayInfo(const RaceGUI* caller) = 0;
|
||||
|
||||
/** Since each mode will have a different way of deciding where a rescued
|
||||
* kart is dropped, this method will be called and each mode can implement it.
|
||||
*/
|
||||
virtual void moveKartAfterRescue(Kart* kart) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -307,34 +307,3 @@ void PlayerKart::collectedHerring(const Herring &herring, int add_info)
|
||||
}
|
||||
} // collectedHerring
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function is called by world to add any messages to the race gui. This
|
||||
* can't be done (in some cases) in the update() function, since update can be
|
||||
* called several times per frame, resulting in messages being displayed more
|
||||
* than once.
|
||||
**/
|
||||
void PlayerKart::addMessages()
|
||||
{
|
||||
RaceGUI* m=menu_manager->getRaceMenu();
|
||||
// This can happen if the option menu is called, since the
|
||||
// racegui gets deleted
|
||||
if(!m) return;
|
||||
|
||||
// 1) check if the player is going in the wrong direction
|
||||
// ------------------------------------------------------
|
||||
if(race_manager->getDifficulty()==RaceManager::RD_EASY)
|
||||
{
|
||||
float angle_diff = RAD_TO_DEGREE(getHPR().getHeading()) - RaceManager::getTrack()->m_angle[getSector()];
|
||||
if(angle_diff > 180.0f) angle_diff -= 360.0f;
|
||||
else if (angle_diff < -180.0f) angle_diff += 360.0f;
|
||||
// Display a warning message if the kart is going back way (unless
|
||||
// the kart has already finished the race).
|
||||
if ((angle_diff > 120.0f || angle_diff < -120.0f) &&
|
||||
getVelocity().getY() > 0.0f && !hasFinishedRace() )
|
||||
{
|
||||
m->addMessage(_("WRONG WAY!"), this, -1.0f, 60);
|
||||
} // if angle is too big
|
||||
} // if difficulty easy
|
||||
|
||||
} // addMessages
|
||||
/* EOF */
|
||||
|
||||
@@ -58,7 +58,6 @@ public:
|
||||
int earlyStartPenalty () {return m_penalty_time>0; }
|
||||
Player *getPlayer () {return m_player; }
|
||||
void update (float);
|
||||
void addMessages ();
|
||||
void action (KartAction action, int value);
|
||||
void handleZipper ();
|
||||
void collectedHerring (const Herring &herring, int add_info=-1);
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <iostream>
|
||||
#include "constants.hpp"
|
||||
#include "scene.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "race_manager.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
|
||||
@@ -162,14 +162,20 @@ void DefaultRobot::handle_braking()
|
||||
m_controls.brake = true;
|
||||
return;
|
||||
}
|
||||
const float MIN_SPEED = RaceManager::getTrack()->getWidth()[m_track_sector];
|
||||
|
||||
// FIXME - don't re-create everytime, store at least the lworld
|
||||
LinearWorld* lworld = dynamic_cast<LinearWorld*>(RaceManager::getWorld());
|
||||
assert(lworld != NULL);
|
||||
KartInfo& kart_info = lworld->m_kart_info[ getWorldKartId() ];
|
||||
|
||||
const float MIN_SPEED = RaceManager::getTrack()->getWidth()[kart_info.m_track_sector];
|
||||
|
||||
//We may brake if we are about to get out of the road, but only if the
|
||||
//kart is on top of the road, and if we won't slow down below a certain
|
||||
//limit.
|
||||
if ( m_crashes.m_road && m_on_road && getVelocityLC().getY() > MIN_SPEED)
|
||||
if ( m_crashes.m_road && kart_info.m_on_road && getVelocityLC().getY() > MIN_SPEED)
|
||||
{
|
||||
float kart_ang_diff = RaceManager::getTrack()->m_angle[m_track_sector] -
|
||||
float kart_ang_diff = RaceManager::getTrack()->m_angle[kart_info.m_track_sector] -
|
||||
RAD_TO_DEGREE(getHPR().getHeading());
|
||||
kart_ang_diff = normalize_angle(kart_ang_diff);
|
||||
kart_ang_diff = fabsf(kart_ang_diff);
|
||||
@@ -184,7 +190,7 @@ void DefaultRobot::handle_braking()
|
||||
//if the curve angle is bigger than what the kart can steer, brake
|
||||
//even if we are in the inside, because the kart would be 'thrown'
|
||||
//out of the curve.
|
||||
if(!(getDistanceToCenter() > RaceManager::getTrack()->getWidth()[m_track_sector] *
|
||||
if(!(lworld->getDistanceToCenterForKart(getWorldKartId()) > RaceManager::getTrack()->getWidth()[kart_info.m_track_sector] *
|
||||
-CURVE_INSIDE_PERC || m_curve_angle > getMaxSteerAngle()))
|
||||
{
|
||||
m_controls.brake = false;
|
||||
@@ -193,7 +199,7 @@ void DefaultRobot::handle_braking()
|
||||
}
|
||||
else if( m_curve_angle < -MIN_TRACK_ANGLE ) //Next curve is right
|
||||
{
|
||||
if(!(getDistanceToCenter() < RaceManager::getTrack()->getWidth()[m_track_sector] *
|
||||
if(!(lworld->getDistanceToCenterForKart( getWorldKartId() ) < RaceManager::getTrack()->getWidth()[kart_info.m_track_sector] *
|
||||
CURVE_INSIDE_PERC || m_curve_angle < -getMaxSteerAngle()))
|
||||
{
|
||||
m_controls.brake = false;
|
||||
@@ -224,17 +230,22 @@ void DefaultRobot::handle_braking()
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::handle_steering()
|
||||
{
|
||||
// FIXME - don't re-create everytime, store at least the lworld
|
||||
LinearWorld* lworld = dynamic_cast<LinearWorld*>(RaceManager::getWorld());
|
||||
assert(lworld != NULL);
|
||||
KartInfo& kart_info = lworld->m_kart_info[ getWorldKartId() ];
|
||||
|
||||
const unsigned int DRIVELINE_SIZE = (unsigned int)RaceManager::getTrack()->m_driveline.size();
|
||||
const size_t NEXT_SECTOR = (unsigned int)m_track_sector + 1 < DRIVELINE_SIZE ?
|
||||
m_track_sector + 1 : 0;
|
||||
const size_t NEXT_SECTOR = (unsigned int)kart_info.m_track_sector + 1 < DRIVELINE_SIZE ?
|
||||
kart_info.m_track_sector + 1 : 0;
|
||||
float steer_angle = 0.0f;
|
||||
|
||||
/*The AI responds based on the information we just gathered, using a
|
||||
*finite state machine.
|
||||
*/
|
||||
//Reaction to being outside of the road
|
||||
if( fabsf(getDistanceToCenter()) + 0.5 >
|
||||
RaceManager::getTrack()->getWidth()[m_track_sector] )
|
||||
if( fabsf(lworld->getDistanceToCenterForKart( getWorldKartId() )) + 0.5 >
|
||||
RaceManager::getTrack()->getWidth()[kart_info.m_track_sector] )
|
||||
{
|
||||
steer_angle = steer_to_point( RaceManager::getTrack()->
|
||||
m_driveline[NEXT_SECTOR] );
|
||||
@@ -261,8 +272,8 @@ void DefaultRobot::handle_steering()
|
||||
}
|
||||
else
|
||||
{
|
||||
if(getDistanceToCenter() > RaceManager::getKart(m_crashes.m_kart)->
|
||||
getDistanceToCenter())
|
||||
if(lworld->getDistanceToCenterForKart( getWorldKartId() ) >
|
||||
lworld->getDistanceToCenterForKart( m_crashes.m_kart ))
|
||||
{
|
||||
steer_angle = steer_to_angle( NEXT_SECTOR, -90.0f );
|
||||
m_start_kart_crash_direction = 1;
|
||||
@@ -300,7 +311,7 @@ void DefaultRobot::handle_steering()
|
||||
case FT_AVOID_TRACK_CRASH:
|
||||
if( m_crashes.m_road )
|
||||
{
|
||||
steer_angle = steer_to_angle( m_track_sector, 0.0f );
|
||||
steer_angle = steer_to_angle( kart_info.m_track_sector, 0.0f );
|
||||
}
|
||||
else steer_angle = 0.0f;
|
||||
|
||||
@@ -329,6 +340,11 @@ void DefaultRobot::handle_items( const float DELTA, const int STEPS )
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME - don't re-create everytime, store at least the lworld
|
||||
LinearWorld* lworld = dynamic_cast<LinearWorld*>(RaceManager::getWorld());
|
||||
assert(lworld != NULL);
|
||||
KartInfo& kart_info = lworld->m_kart_info[ getWorldKartId() ];
|
||||
|
||||
m_time_since_last_shot += DELTA;
|
||||
if( m_collectable.getType() != COLLECT_NOTHING )
|
||||
{
|
||||
@@ -347,7 +363,7 @@ void DefaultRobot::handle_items( const float DELTA, const int STEPS )
|
||||
case COLLECT_ZIPPER:
|
||||
{
|
||||
const float ANGLE_DIFF = fabsf( normalize_angle(
|
||||
RaceManager::getTrack()->m_angle[m_track_sector]-
|
||||
RaceManager::getTrack()->m_angle[kart_info.m_track_sector]-
|
||||
RAD_TO_DEGREE(getHPR().getHeading()) ) );
|
||||
|
||||
if( m_time_since_last_shot > 10.0f && ANGLE_DIFF <
|
||||
@@ -434,6 +450,11 @@ bool DefaultRobot::do_wheelie ( const int STEPS )
|
||||
if( m_crashes.m_road ) return false;
|
||||
if( m_crashes.m_kart != -1 ) return false;
|
||||
|
||||
// FIXME - don't re-create everytime, store at least the lworld
|
||||
LinearWorld* lworld = dynamic_cast<LinearWorld*>(RaceManager::getWorld());
|
||||
assert(lworld != NULL);
|
||||
KartInfo& kart_info = lworld->m_kart_info[ getWorldKartId() ];
|
||||
|
||||
//We have to be careful with normalizing, because if the source argument
|
||||
//has both the X and Y axis set to 0, it returns nan to the destiny.
|
||||
const Vec3 &VEL = getVelocity();
|
||||
@@ -467,7 +488,7 @@ bool DefaultRobot::do_wheelie ( const int STEPS )
|
||||
distance = step_track_coord[0] > 0.0f ? step_track_coord[0]
|
||||
: -step_track_coord[0];
|
||||
|
||||
if( distance > RaceManager::getTrack()->getWidth()[m_track_sector] )
|
||||
if( distance > RaceManager::getTrack()->getWidth()[kart_info.m_track_sector] )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -688,8 +709,13 @@ void DefaultRobot::find_non_crashing_point( sgVec2 result )
|
||||
{
|
||||
const unsigned int DRIVELINE_SIZE = (unsigned int)RaceManager::getTrack()->m_driveline.size();
|
||||
|
||||
unsigned int sector = (unsigned int)m_track_sector + 1 < DRIVELINE_SIZE ?
|
||||
m_track_sector + 1 : 0;
|
||||
// FIXME - don't re-create everytime, store at least the lworld
|
||||
LinearWorld* lworld = dynamic_cast<LinearWorld*>(RaceManager::getWorld());
|
||||
assert(lworld != NULL);
|
||||
KartInfo& kart_info = lworld->m_kart_info[ getWorldKartId() ];
|
||||
|
||||
unsigned int sector = (unsigned int)kart_info.m_track_sector + 1 < DRIVELINE_SIZE ?
|
||||
kart_info.m_track_sector + 1 : 0;
|
||||
int target_sector;
|
||||
|
||||
Vec3 direction;
|
||||
@@ -925,22 +951,27 @@ float DefaultRobot::get_approx_radius(const int START, const int END) const
|
||||
*/
|
||||
void DefaultRobot::find_curve()
|
||||
{
|
||||
// FIXME - don't re-create everytime, store at least the lworld
|
||||
LinearWorld* lworld = dynamic_cast<LinearWorld*>(RaceManager::getWorld());
|
||||
assert(lworld != NULL);
|
||||
KartInfo& kart_info = lworld->m_kart_info[ getWorldKartId() ];
|
||||
|
||||
const int DRIVELINE_SIZE = (unsigned int)RaceManager::getTrack()->m_driveline.size();
|
||||
float total_dist = 0.0f;
|
||||
int next_hint = m_track_sector;
|
||||
int next_hint = kart_info.m_track_sector;
|
||||
int i;
|
||||
|
||||
for(i = m_track_sector; total_dist < getVelocityLC().getY(); i = next_hint)
|
||||
for(i = kart_info.m_track_sector; total_dist < getVelocityLC().getY(); i = next_hint)
|
||||
{
|
||||
next_hint = i + 1 < DRIVELINE_SIZE ? i + 1 : 0;
|
||||
total_dist += sgDistanceVec2(RaceManager::getTrack()->m_driveline[i], RaceManager::getTrack()->m_driveline[next_hint]);
|
||||
}
|
||||
|
||||
|
||||
m_curve_angle = normalize_angle(RaceManager::getTrack()->m_angle[i] - RaceManager::getTrack()->m_angle[m_track_sector]);
|
||||
m_curve_angle = normalize_angle(RaceManager::getTrack()->m_angle[i] - RaceManager::getTrack()->m_angle[kart_info.m_track_sector]);
|
||||
m_inner_curve = m_curve_angle > 0.0 ? -1 : 1;
|
||||
// FIXME: 0.9 is the tire grip - but this was never used. For now this
|
||||
// 0.9 is left in place to reproduce the same results and AI behaviour,
|
||||
// but this function should be updated to bullet physics
|
||||
m_curve_target_speed = sgSqrt(get_approx_radius(m_track_sector, i) * RaceManager::getTrack()->getGravity() * 0.9f);
|
||||
m_curve_target_speed = sgSqrt(get_approx_radius(kart_info.m_track_sector, i) * RaceManager::getTrack()->getGravity() * 0.9f);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user