Initial work on supporting real race with ghost karts
To test, you need to pass --ghost to supertuxkart with choosing a track that has replay recorded, you can record one with artist debug mode. TODO: correct position handling
This commit is contained in:
@@ -226,7 +226,8 @@ void Flyable::getClosestKart(const AbstractKart **minKart,
|
||||
// it is not considered a target anymore.
|
||||
if(kart->isEliminated() || kart == m_owner ||
|
||||
kart->isInvulnerable() ||
|
||||
kart->getKartAnimation() ) continue;
|
||||
kart->getKartAnimation() ||
|
||||
kart->isGhostKart() ) continue;
|
||||
|
||||
const SoccerWorld* sw = dynamic_cast<SoccerWorld*>(World::getWorld());
|
||||
if (sw)
|
||||
@@ -480,6 +481,7 @@ void Flyable::explode(AbstractKart *kart_hit, PhysicalObject *object,
|
||||
->getKartTeam(m_owner->getWorldKartId()))
|
||||
continue;
|
||||
}
|
||||
if (kart->isGhostKart()) continue;
|
||||
|
||||
// If no secondary hits should be done, only hit the
|
||||
// direct hit kart.
|
||||
|
||||
@@ -295,7 +295,7 @@ void Powerup::use()
|
||||
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
|
||||
{
|
||||
AbstractKart *kart=world->getKart(i);
|
||||
if(kart->isEliminated()) continue;
|
||||
if(kart->isEliminated() || kart->isGhostKart()) continue;
|
||||
if(kart == m_owner) continue;
|
||||
if(kart->getPosition() == 1)
|
||||
{
|
||||
@@ -329,7 +329,7 @@ void Powerup::use()
|
||||
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
|
||||
{
|
||||
AbstractKart *kart=world->getKart(i);
|
||||
if(kart->isEliminated() || kart== m_owner) continue;
|
||||
if(kart->isEliminated() || kart== m_owner || kart->isGhostKart()) continue;
|
||||
if(kart->isShielded())
|
||||
{
|
||||
kart->decreaseShieldTime();
|
||||
|
||||
@@ -243,7 +243,7 @@ void Swatter::chooseTarget()
|
||||
{
|
||||
AbstractKart *kart = world->getKart(i);
|
||||
// TODO: isSwatterReady(), isSquashable()?
|
||||
if(kart->isEliminated() || kart==m_kart)
|
||||
if(kart->isEliminated() || kart == m_kart || kart->isGhostKart())
|
||||
continue;
|
||||
// don't squash an already hurt kart
|
||||
if (kart->isInvulnerable() || kart->isSquashed())
|
||||
|
||||
@@ -454,6 +454,9 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart wins or loses. */
|
||||
virtual bool getRaceResult() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart is a ghost (replay) kart. */
|
||||
virtual bool isGhostKart() const = 0;
|
||||
|
||||
}; // AbstractKart
|
||||
|
||||
|
||||
@@ -1757,7 +1757,7 @@ void SkiddingAI::checkCrashes(const Vec3& pos )
|
||||
{
|
||||
const AbstractKart* kart = m_world->getKart(j);
|
||||
// Ignore eliminated karts
|
||||
if(kart==m_kart||kart->isEliminated()) continue;
|
||||
if(kart==m_kart||kart->isEliminated()||kart->isGhostKart()) continue;
|
||||
const AbstractKart *other_kart = m_world->getKart(j);
|
||||
// Ignore karts ahead that are faster than this kart.
|
||||
if(m_kart->getVelocityLC().getZ() < other_kart->getVelocityLC().getZ())
|
||||
|
||||
@@ -24,9 +24,11 @@
|
||||
#include "LinearMath/btQuaternion.h"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
GhostKart::GhostKart(const std::string& ident)
|
||||
: Kart(ident, /*world kart id*/99999,
|
||||
/*position*/-1, btTransform(), PLAYER_DIFFICULTY_NORMAL)
|
||||
GhostKart::GhostKart(const std::string& ident, unsigned int world_kart_id,
|
||||
int position)
|
||||
: Kart(ident, world_kart_id,
|
||||
position, btTransform(btQuaternion(0, 0, 0, 1)),
|
||||
PLAYER_DIFFICULTY_NORMAL)
|
||||
{
|
||||
m_all_times.clear();
|
||||
m_all_transform.clear();
|
||||
@@ -131,5 +133,7 @@ void GhostKart::update(float dt)
|
||||
m_all_physic_info[m_current_transform].m_speed,
|
||||
m_current_transform);
|
||||
|
||||
Vec3 front(0, 0, getKartLength()*0.5f);
|
||||
m_xyz_front = getTrans()(front);
|
||||
getKartGFX()->update(dt);
|
||||
} // update
|
||||
|
||||
@@ -51,7 +51,8 @@ private:
|
||||
unsigned int m_current_transform;
|
||||
|
||||
public:
|
||||
GhostKart(const std::string& ident);
|
||||
GhostKart(const std::string& ident,
|
||||
unsigned int world_kart_id, int position);
|
||||
virtual void update (float dt);
|
||||
virtual void reset();
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -72,5 +73,8 @@ public:
|
||||
const ReplayBase::PhysicInfo &pi,
|
||||
const ReplayBase::KartReplayEvent &kre);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart is a ghost (replay) kart. */
|
||||
virtual bool isGhostKart() const { return true; }
|
||||
|
||||
}; // GhostKart
|
||||
#endif
|
||||
|
||||
@@ -512,7 +512,8 @@ void Kart::setController(Controller *controller)
|
||||
*/
|
||||
void Kart::setPosition(int p)
|
||||
{
|
||||
m_controller->setPosition(p);
|
||||
if (m_controller)
|
||||
m_controller->setPosition(p);
|
||||
m_race_position = p;
|
||||
} // setPosition
|
||||
|
||||
@@ -834,14 +835,15 @@ void Kart::finishedRace(float time)
|
||||
if(m_finished_race) return;
|
||||
m_finished_race = true;
|
||||
m_finish_time = time;
|
||||
m_controller->finishedRace(time);
|
||||
if(!isGhostKart())
|
||||
m_controller->finishedRace(time);
|
||||
m_kart_model->finishedRace();
|
||||
race_manager->kartFinishedRace(this, time);
|
||||
|
||||
if ((race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
&& m_controller->isPlayerController())
|
||||
&& (isGhostKart() ? false : m_controller->isPlayerController()))
|
||||
{
|
||||
RaceGUIBase* m = World::getWorld()->getRaceGUI();
|
||||
if (m)
|
||||
@@ -869,10 +871,13 @@ void Kart::finishedRace(float time)
|
||||
{
|
||||
// Save for music handling in race result gui
|
||||
setRaceResult();
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
if(!isGhostKart())
|
||||
{
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
}
|
||||
// Skip animation if this kart is eliminated
|
||||
if (m_eliminated) return;
|
||||
if (m_eliminated || isGhostKart()) return;
|
||||
|
||||
m_kart_model->setAnimation(m_race_result ?
|
||||
KartModel::AF_WIN_START : KartModel::AF_LOSE_START);
|
||||
@@ -885,8 +890,9 @@ void Kart::setRaceResult()
|
||||
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
{
|
||||
if (m_controller->isLocalPlayerController()) // if player is on this computer
|
||||
if (isGhostKart() ? false : m_controller->isPlayerController())
|
||||
{
|
||||
// if player is on this computer
|
||||
PlayerProfile *player = PlayerManager::getCurrentPlayer();
|
||||
const ChallengeStatus *challenge = player->getCurrentChallengeStatus();
|
||||
// In case of a GP challenge don't make the end animation depend
|
||||
@@ -1487,7 +1493,7 @@ void Kart::showZipperFire()
|
||||
*/
|
||||
void Kart::setSquash(float time, float slowdown)
|
||||
{
|
||||
if (isInvulnerable()) return;
|
||||
if (isInvulnerable() || isGhostKart()) return;
|
||||
|
||||
if (isShielded())
|
||||
{
|
||||
|
||||
@@ -68,6 +68,10 @@ protected:
|
||||
/** Offset of the graphical kart chassis from the physical chassis. */
|
||||
float m_graphical_y_offset;
|
||||
|
||||
/** The coordinates of the front of the kart, used to determine when a
|
||||
* new lap is triggered. */
|
||||
Vec3 m_xyz_front;
|
||||
|
||||
private:
|
||||
/** Handles speed increase and capping due to powerup, terrain, ... */
|
||||
MaxSpeed *m_max_speed;
|
||||
@@ -106,10 +110,6 @@ private:
|
||||
/** Current race position (1-num_karts). */
|
||||
int m_race_position;
|
||||
|
||||
/** The coordinates of the front of the kart, used to determine when a
|
||||
* new lap is triggered. */
|
||||
Vec3 m_xyz_front;
|
||||
|
||||
/** True if the kart wins, false otherwise. */
|
||||
bool m_race_result;
|
||||
|
||||
@@ -448,6 +448,9 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set this kart race result. */
|
||||
void setRaceResult();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart is a ghost (replay) kart. */
|
||||
virtual bool isGhostKart() const { return false; }
|
||||
|
||||
}; // Kart
|
||||
|
||||
|
||||
@@ -806,7 +806,7 @@ void KartModel::update(float dt, float distance, float steer, float speed,
|
||||
if (!m_kart || !m_wheel_node[i]) continue;
|
||||
#ifdef DEBUG
|
||||
if (UserConfigParams::m_physics_debug &&
|
||||
!dynamic_cast<GhostKart*>(m_kart) )
|
||||
!m_kart->isGhostKart())
|
||||
{
|
||||
const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i);
|
||||
// Make wheels that are not touching the ground invisible
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#endif
|
||||
#include "achievements/achievement_info.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "karts/ghost_kart.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/kart_gfx.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
@@ -82,7 +81,7 @@ void Skidding::reset()
|
||||
|
||||
btVector3 rot(0, 0, 0);
|
||||
// Only access the vehicle if the kart is not a ghost
|
||||
if (dynamic_cast<GhostKart*>(m_kart)==NULL)
|
||||
if (!m_kart->isGhostKart())
|
||||
m_kart->getVehicle()->setTimedRotation(0, rot);
|
||||
} // reset
|
||||
|
||||
|
||||
@@ -245,20 +245,24 @@ void LinearWorld::newLap(unsigned int kart_index)
|
||||
{
|
||||
KartInfo &kart_info = m_kart_info[kart_index];
|
||||
AbstractKart *kart = m_karts[kart_index];
|
||||
const bool is_gk = kart->isGhostKart();
|
||||
|
||||
// Reset reset-after-lap achievements
|
||||
StateManager::ActivePlayer *c = kart->getController()->getPlayer();
|
||||
PlayerProfile *p = PlayerManager::getCurrentPlayer();
|
||||
if (c && c->getConstProfile() == p)
|
||||
if (!is_gk)
|
||||
{
|
||||
p->getAchievementsStatus()->onLapEnd();
|
||||
StateManager::ActivePlayer *c = kart->getController()->getPlayer();
|
||||
PlayerProfile *p = PlayerManager::getCurrentPlayer();
|
||||
if (c && c->getConstProfile() == p)
|
||||
{
|
||||
p->getAchievementsStatus()->onLapEnd();
|
||||
}
|
||||
}
|
||||
|
||||
// Only update the kart controller if a kart that has already finished
|
||||
// the race crosses the start line again. This avoids 'fastest lap'
|
||||
// messages if the end controller does a fastest lap, but especially
|
||||
// allows the end controller to switch end cameras
|
||||
if(kart->hasFinishedRace())
|
||||
if(kart->hasFinishedRace() && !is_gk)
|
||||
{
|
||||
kart->getController()->newLap(kart_info.m_race_lap);
|
||||
return;
|
||||
@@ -374,7 +378,8 @@ void LinearWorld::newLap(unsigned int kart_index)
|
||||
} // end if new fastest lap
|
||||
|
||||
kart_info.m_lap_start_time = getTime();
|
||||
kart->getController()->newLap(kart_info.m_race_lap);
|
||||
if (!is_gk)
|
||||
kart->getController()->newLap(kart_info.m_race_lap);
|
||||
} // newLap
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -840,6 +845,8 @@ void LinearWorld::updateRacePosition()
|
||||
*/
|
||||
void LinearWorld::checkForWrongDirection(unsigned int i, float dt)
|
||||
{
|
||||
if (m_karts[i]->isGhostKart()) return;
|
||||
|
||||
if (!m_karts[i]->getController()->isLocalPlayerController())
|
||||
return;
|
||||
|
||||
|
||||
@@ -102,10 +102,11 @@ void StandardRace::endRaceEarly()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (kart->getController()->isPlayerController())
|
||||
if (!kart->isGhostKart())
|
||||
{
|
||||
// Keep active players apart for now
|
||||
active_players.push_back(kartid);
|
||||
if (kart->getController()->isPlayerController())
|
||||
active_players.push_back(kartid);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -146,6 +146,9 @@ void World::init()
|
||||
m_eliminated_karts = 0;
|
||||
m_eliminated_players = 0;
|
||||
m_num_players = 0;
|
||||
unsigned int gk = 0;
|
||||
if (ReplayPlay::get())
|
||||
gk = ReplayPlay::get()->getNumGhostKart();
|
||||
|
||||
// Create the race gui before anything else is attached to the scene node
|
||||
// (which happens when the track is loaded). This allows the race gui to
|
||||
@@ -179,8 +182,16 @@ void World::init()
|
||||
// karts can be positioned properly on (and not in) the tracks.
|
||||
m_track->loadTrackModel(race_manager->getReverseTrack());
|
||||
|
||||
if (gk > 0)
|
||||
{
|
||||
ReplayPlay::get()->load();
|
||||
for (unsigned int k = 0; k < gk; k++)
|
||||
m_karts.push_back(ReplayPlay::get()->getGhostKart(k));
|
||||
}
|
||||
|
||||
for(unsigned int i=0; i<num_karts; i++)
|
||||
{
|
||||
if (race_manager->getKartType(i) == RaceManager::KT_GHOST) continue;
|
||||
std::string kart_ident = history->replayHistory()
|
||||
? history->getKartIdent(i)
|
||||
: race_manager->getKartIdent(i);
|
||||
@@ -201,11 +212,8 @@ void World::init()
|
||||
// Must be called after all karts are created
|
||||
m_race_gui->init();
|
||||
|
||||
if(ReplayPlay::get())
|
||||
ReplayPlay::get()->Load();
|
||||
|
||||
powerup_manager->updateWeightsForRace(num_karts);
|
||||
|
||||
|
||||
if (UserConfigParams::m_weather_effects)
|
||||
{
|
||||
m_weather = new Weather(m_track->getWeatherLightning(),
|
||||
@@ -382,16 +390,6 @@ World::~World()
|
||||
{
|
||||
irr_driver->onUnloadWorld();
|
||||
|
||||
if(ReplayPlay::get())
|
||||
{
|
||||
// Destroy the old replay object, which also stored the ghost
|
||||
// karts, and create a new one (which means that in further
|
||||
// races the usage of ghosts will still be enabled).
|
||||
ReplayPlay::destroy();
|
||||
ReplayPlay::create();
|
||||
}
|
||||
|
||||
|
||||
// In case that a race is aborted (e.g. track not found) m_track is 0.
|
||||
if(m_track)
|
||||
m_track->cleanup();
|
||||
@@ -416,9 +414,22 @@ World::~World()
|
||||
delete m_weather;
|
||||
|
||||
for ( unsigned int i = 0 ; i < m_karts.size() ; i++ )
|
||||
{
|
||||
// Let ReplayPlay destroy the ghost karts
|
||||
if (m_karts[i]->isGhostKart()) continue;
|
||||
delete m_karts[i];
|
||||
}
|
||||
|
||||
if(ReplayPlay::get())
|
||||
{
|
||||
// Destroy the old replay object, which also stored the ghost
|
||||
// karts, and create a new one (which means that in further
|
||||
// races the usage of ghosts will still be enabled).
|
||||
ReplayPlay::destroy();
|
||||
ReplayPlay::create();
|
||||
}
|
||||
m_karts.clear();
|
||||
|
||||
Camera::removeAllCameras();
|
||||
|
||||
projectile_manager->cleanup();
|
||||
@@ -447,6 +458,7 @@ void World::onGo()
|
||||
// from sliding downhill)
|
||||
for(unsigned int i=0; i<m_karts.size(); i++)
|
||||
{
|
||||
if (m_karts[i]->isGhostKart()) continue;
|
||||
m_karts[i]->getVehicle()->setAllBrakes(0);
|
||||
}
|
||||
} // onGo
|
||||
@@ -508,6 +520,7 @@ void World::terminateRace()
|
||||
}
|
||||
for(unsigned int i = 0; i < kart_amount; i++)
|
||||
{
|
||||
if (m_karts[i]->isGhostKart()) continue;
|
||||
// Retrieve the current player
|
||||
StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer();
|
||||
if (p && p->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
@@ -533,6 +546,7 @@ void World::terminateRace()
|
||||
{
|
||||
for(unsigned int i = 0; i < kart_amount; i++)
|
||||
{
|
||||
if (m_karts[i]->isGhostKart()) continue;
|
||||
// Retrieve the current player
|
||||
StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer();
|
||||
if (p && p->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
@@ -593,12 +607,13 @@ void World::resetAllKarts()
|
||||
getPhysics()->getPhysicsWorld()->resetLocalTime();
|
||||
|
||||
// If track checking is requested, check all rescue positions if
|
||||
// they are heigh enough.
|
||||
// they are high enough.
|
||||
if(UserConfigParams::m_track_debug)
|
||||
{
|
||||
// Loop over all karts, in case that some karts are dfferent
|
||||
for(unsigned int kart_id=0; kart_id<(unsigned int)m_karts.size(); kart_id++)
|
||||
{
|
||||
if (m_karts[kart_id]->isGhostKart()) continue;
|
||||
for(unsigned int rescue_pos=0;
|
||||
rescue_pos<getNumberOfRescuePositions();
|
||||
rescue_pos++)
|
||||
@@ -626,6 +641,7 @@ void World::resetAllKarts()
|
||||
//that at least one of its wheel will be on the surface of the track
|
||||
for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++)
|
||||
{
|
||||
if ((*i)->isGhostKart()) continue;
|
||||
Vec3 xyz = (*i)->getXYZ();
|
||||
//start projection from top of kart
|
||||
Vec3 up_offset(0, 0.5f * ((*i)->getKartHeight()), 0);
|
||||
@@ -674,6 +690,7 @@ void World::resetAllKarts()
|
||||
all_finished=true;
|
||||
for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++)
|
||||
{
|
||||
if ((*i)->isGhostKart()) continue;
|
||||
if(!(*i)->isInRest())
|
||||
{
|
||||
Vec3 normal;
|
||||
@@ -716,6 +733,7 @@ void World::resetAllKarts()
|
||||
|
||||
for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++)
|
||||
{
|
||||
if ((*i)->isGhostKart()) continue;
|
||||
(*i)->kartIsInRestNow();
|
||||
}
|
||||
|
||||
@@ -1073,6 +1091,7 @@ void World::updateHighscores(int* best_highscore_rank, int* best_finish_time,
|
||||
|
||||
for (unsigned int pos=0; pos<kart_amount; pos++)
|
||||
{
|
||||
if (m_karts[index[pos]]->isGhostKart()) continue;
|
||||
if(index[pos] == 999)
|
||||
{
|
||||
// no kart claimed to be in this position, most likely means
|
||||
@@ -1137,11 +1156,14 @@ AbstractKart *World::getPlayerKart(unsigned int n) const
|
||||
unsigned int count=-1;
|
||||
|
||||
for(unsigned int i=0; i<m_karts.size(); i++)
|
||||
{
|
||||
if(m_karts[i]->isGhostKart()) continue;
|
||||
if(m_karts[i]->getController()->isPlayerController())
|
||||
{
|
||||
count++;
|
||||
if(count==n) return m_karts[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
} // getPlayerKart
|
||||
|
||||
@@ -1162,6 +1184,7 @@ AbstractKart *World::getLocalPlayerKart(unsigned int n) const
|
||||
void World::eliminateKart(int kart_id, bool notify_of_elimination)
|
||||
{
|
||||
AbstractKart *kart = m_karts[kart_id];
|
||||
if (kart->isGhostKart()) return;
|
||||
|
||||
// Display a message about the eliminated kart in the race guia
|
||||
if (notify_of_elimination)
|
||||
@@ -1238,6 +1261,7 @@ void World::unpause()
|
||||
|
||||
for(unsigned int i=0; i<m_karts.size(); i++)
|
||||
{
|
||||
if (m_karts[i]->isGhostKart()) continue;
|
||||
// Note that we can not test for isPlayerController here, since
|
||||
// an EndController will also return 'isPlayerController' if the
|
||||
// kart belonged to a player.
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/protocols/start_game_protocol.hpp"
|
||||
#include "replay/replay_play.hpp"
|
||||
#include "scriptengine/property_animator.hpp"
|
||||
#include "states_screens/grand_prix_cutscene.hpp"
|
||||
#include "states_screens/grand_prix_lose.hpp"
|
||||
@@ -308,6 +309,13 @@ void RaceManager::computeRandomKartList()
|
||||
*/
|
||||
void RaceManager::startNew(bool from_overworld)
|
||||
{
|
||||
unsigned int gk = 0;
|
||||
if (ReplayPlay::get())
|
||||
{
|
||||
ReplayPlay::get()->loadKartInfo();
|
||||
gk = ReplayPlay::get()->getNumGhostKart();
|
||||
}
|
||||
|
||||
m_started_from_overworld = from_overworld;
|
||||
m_saved_gp = NULL; // There will be checks for this being NULL done later
|
||||
|
||||
@@ -359,16 +367,30 @@ void RaceManager::startNew(bool from_overworld)
|
||||
// Create the kart status data structure to keep track of scores, times, ...
|
||||
// ==========================================================================
|
||||
m_kart_status.clear();
|
||||
Log::verbose("RaceManager", "Nb of karts=%u, ai:%lu players:%lu\n",
|
||||
(unsigned int) m_num_karts, m_ai_kart_list.size(), m_player_karts.size());
|
||||
if (gk > 0)
|
||||
m_num_karts += gk;
|
||||
|
||||
assert((unsigned int)m_num_karts == m_ai_kart_list.size()+m_player_karts.size());
|
||||
Log::verbose("RaceManager", "Nb of karts=%u, ghost karts:%u ai:%lu players:%lu\n",
|
||||
(unsigned int) m_num_karts, gk, m_ai_kart_list.size(), m_player_karts.size());
|
||||
|
||||
// First add the AI karts (randomly chosen)
|
||||
assert((unsigned int)m_num_karts == gk+m_ai_kart_list.size()+m_player_karts.size());
|
||||
|
||||
// First add the ghost karts (if any)
|
||||
// ----------------------------------------
|
||||
|
||||
// GP ranks start with -1 for the leader.
|
||||
int init_gp_rank = getMinorMode()==MINOR_MODE_FOLLOW_LEADER ? -1 : 0;
|
||||
if (gk > 0)
|
||||
{
|
||||
for(unsigned int i = 0; i < gk; i++)
|
||||
{
|
||||
m_kart_status.push_back(KartStatus(ReplayPlay::get()->getGhostKartName(i),
|
||||
i, -1, -1, init_gp_rank, KT_GHOST, PLAYER_DIFFICULTY_NORMAL));
|
||||
init_gp_rank ++;
|
||||
}
|
||||
}
|
||||
|
||||
// Then add the AI karts (randomly chosen)
|
||||
// ----------------------------------------
|
||||
const unsigned int ai_kart_count = m_ai_kart_list.size();
|
||||
for(unsigned int i = 0; i < ai_kart_count; i++)
|
||||
{
|
||||
@@ -382,7 +404,7 @@ void RaceManager::startNew(bool from_overworld)
|
||||
}
|
||||
}
|
||||
|
||||
// Then add the players, which start behind the AI karts
|
||||
// Finally add the players, which start behind the AI karts
|
||||
// -----------------------------------------------------
|
||||
for(unsigned int i = 0; i < m_player_karts.size(); i++)
|
||||
{
|
||||
@@ -836,6 +858,7 @@ void RaceManager::kartFinishedRace(const AbstractKart *kart, float time)
|
||||
m_kart_status[id].m_overall_time += time;
|
||||
m_kart_status[id].m_last_time = time;
|
||||
m_num_finished_karts ++;
|
||||
if(kart->isGhostKart()) return;
|
||||
if(kart->getController()->isPlayerController())
|
||||
m_num_finished_players++;
|
||||
} // kartFinishedRace
|
||||
|
||||
@@ -35,7 +35,8 @@ ReplayPlay *ReplayPlay::m_replay_play = NULL;
|
||||
*/
|
||||
ReplayPlay::ReplayPlay()
|
||||
{
|
||||
m_next = 0;
|
||||
m_next = 0;
|
||||
m_ghost_karts_list.clear();
|
||||
} // ReplayPlay
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -44,21 +45,13 @@ ReplayPlay::~ReplayPlay()
|
||||
{
|
||||
} // ~Replay
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Starts replay from the replay file in the current directory.
|
||||
*/
|
||||
void ReplayPlay::init()
|
||||
{
|
||||
m_next = 0;
|
||||
Load();
|
||||
} // init
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Resets all ghost karts back to start position.
|
||||
*/
|
||||
void ReplayPlay::reset()
|
||||
{
|
||||
m_next = 0;
|
||||
m_ghost_karts_list.clear();
|
||||
for(unsigned int i=0; i<(unsigned int)m_ghost_karts.size(); i++)
|
||||
{
|
||||
m_ghost_karts[i].reset();
|
||||
@@ -77,10 +70,43 @@ void ReplayPlay::update(float dt)
|
||||
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Loads the ghost karts info in the replay file, required by race manager.
|
||||
*/
|
||||
void ReplayPlay::loadKartInfo()
|
||||
{
|
||||
char s[1024];
|
||||
|
||||
FILE *fd = openReplayFile(/*writeable*/false);
|
||||
if(!fd)
|
||||
{
|
||||
Log::error("Replay", "Can't read '%s', ghost replay disabled.",
|
||||
getReplayFilename().c_str());
|
||||
destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
Log::info("Replay", "Reading ghost karts info");
|
||||
while(true)
|
||||
{
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
std::string is_end = std::string(s);
|
||||
if (is_end == "kart_list_end\n" || is_end == "kart_list_end\r\n") break;
|
||||
char s1[1024];
|
||||
|
||||
if (sscanf(s,"kart: %s", s1) != 1)
|
||||
Log::fatal("Replay", "Could not read ghost karts info!");
|
||||
|
||||
m_ghost_karts_list.push_back(std::string(s1));
|
||||
}
|
||||
fclose(fd);
|
||||
} // loadKartInfo
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Loads a replay data from file called 'trackname'.replay.
|
||||
*/
|
||||
void ReplayPlay::Load()
|
||||
void ReplayPlay::load()
|
||||
{
|
||||
m_ghost_karts.clearAndDeleteAll();
|
||||
char s[1024], s1[1024];
|
||||
@@ -95,12 +121,21 @@ void ReplayPlay::Load()
|
||||
}
|
||||
|
||||
Log::info("Replay", "Reading replay file '%s'.", getReplayFilename().c_str());
|
||||
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
|
||||
for (unsigned int i = 0; i < m_ghost_karts_list.size(); i++)
|
||||
{
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
// Skip kart info which is already read.
|
||||
}
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
// Skip kart_list_end
|
||||
|
||||
unsigned int version;
|
||||
if (sscanf(s,"Version: %u", &version) != 1)
|
||||
if (sscanf(s,"version: %u", &version) != 1)
|
||||
Log::fatal("Replay", "No Version information found in replay file (bogus replay file).");
|
||||
|
||||
if (version != getReplayVersion())
|
||||
@@ -113,7 +148,7 @@ void ReplayPlay::Load()
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
|
||||
int n;
|
||||
int n;
|
||||
if(sscanf(s, "difficulty: %d", &n) != 1)
|
||||
Log::fatal("Replay", " No difficulty found in replay file.");
|
||||
|
||||
@@ -130,7 +165,7 @@ void ReplayPlay::Load()
|
||||
|
||||
unsigned int num_laps;
|
||||
fgets(s, 1023, fd);
|
||||
if(sscanf(s, "Laps: %u", &num_laps) != 1)
|
||||
if(sscanf(s, "laps: %u", &num_laps) != 1)
|
||||
Log::fatal("Replay", "No number of laps found in replay file.");
|
||||
|
||||
race_manager->setNumLaps(num_laps);
|
||||
@@ -142,11 +177,11 @@ void ReplayPlay::Load()
|
||||
if(fgets(s, 1023, fd)==NULL) // eof reached
|
||||
break;
|
||||
readKartData(fd, s);
|
||||
} // for k<num_ghost_karts
|
||||
}
|
||||
|
||||
fprintf(fd, "Replay file end.\n");
|
||||
fclose(fd);
|
||||
} // Load
|
||||
} // load
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Reads all data from a replay file for a specific kart.
|
||||
@@ -155,16 +190,13 @@ void ReplayPlay::Load()
|
||||
void ReplayPlay::readKartData(FILE *fd, char *next_line)
|
||||
{
|
||||
char s[1024];
|
||||
if(sscanf(next_line, "model: %s", s)!=1)
|
||||
Log::fatal("Replay", "No model information for kart %d found.",
|
||||
m_ghost_karts.size());
|
||||
const unsigned int kart_num = m_ghost_karts.size();
|
||||
m_ghost_karts.push_back(new GhostKart(m_ghost_karts_list.at(kart_num),
|
||||
kart_num, kart_num + 1));
|
||||
m_ghost_karts[kart_num].init(RaceManager::KT_GHOST);
|
||||
|
||||
m_ghost_karts.push_back(new GhostKart(std::string(s)));
|
||||
m_ghost_karts[m_ghost_karts.size()-1].init(RaceManager::KT_GHOST);
|
||||
|
||||
fgets(s, 1023, fd);
|
||||
unsigned int size;
|
||||
if(sscanf(s,"size: %u",&size)!=1)
|
||||
if(sscanf(next_line,"size: %u",&size)!=1)
|
||||
Log::fatal("Replay", "Number of records not found in replay file "
|
||||
"for kart %d.",
|
||||
m_ghost_karts.size()-1);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#ifndef HEADER_REPLAY__PLAY_HPP
|
||||
#define HEADER_REPLAY__PLAY_HPP
|
||||
|
||||
#include "karts/ghost_kart.hpp"
|
||||
#include "replay/replay_base.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
@@ -38,6 +39,8 @@ private:
|
||||
/** Points to the next free entry. */
|
||||
unsigned int m_next;
|
||||
|
||||
std::vector<std::string> m_ghost_karts_list;
|
||||
|
||||
/** All ghost karts. */
|
||||
PtrVector<GhostKart> m_ghost_karts;
|
||||
|
||||
@@ -45,20 +48,30 @@ private:
|
||||
~ReplayPlay();
|
||||
void readKartData(FILE *fd, char *next_line);
|
||||
public:
|
||||
void init();
|
||||
void update(float dt);
|
||||
void reset();
|
||||
void Load();
|
||||
void load();
|
||||
void loadKartInfo();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
GhostKart* getGhostKart(int n) { return m_ghost_karts.get(n); }
|
||||
// ------------------------------------------------------------------------
|
||||
const unsigned int getNumGhostKart() const
|
||||
{ return m_ghost_karts_list.size(); }
|
||||
// ------------------------------------------------------------------------
|
||||
const std::string& getGhostKartName(int n) const
|
||||
{ return m_ghost_karts_list.at(n); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Creates a new instance of the replay object. */
|
||||
static void create() { m_replay_play = new ReplayPlay(); }
|
||||
static void create() { m_replay_play = new ReplayPlay(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the instance of the replay object. */
|
||||
static ReplayPlay *get() { return m_replay_play; }
|
||||
static ReplayPlay *get() { return m_replay_play; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Delete the instance of the replay object. */
|
||||
static void destroy() { delete m_replay_play; m_replay_play=NULL; }
|
||||
static void destroy()
|
||||
{ delete m_replay_play; m_replay_play = NULL; }
|
||||
// ------------------------------------------------------------------------
|
||||
}; // Replay
|
||||
|
||||
#endif
|
||||
|
||||
@@ -104,6 +104,7 @@ void ReplayRecorder::update(float dt)
|
||||
for(unsigned int i=0; i<num_karts; i++)
|
||||
{
|
||||
const AbstractKart *kart = world->getKart(i);
|
||||
if (kart->isGhostKart()) continue;
|
||||
#ifdef DEBUG
|
||||
m_count++;
|
||||
#endif
|
||||
@@ -195,16 +196,24 @@ void ReplayRecorder::Save()
|
||||
|
||||
World *world = World::getWorld();
|
||||
unsigned int num_karts = world->getNumKarts();
|
||||
fprintf(fd, "Version: %d\n", getReplayVersion());
|
||||
for (unsigned int real_karts = 0; real_karts < num_karts; real_karts++)
|
||||
{
|
||||
if (world->getKart(real_karts)->isGhostKart()) continue;
|
||||
fprintf(fd, "kart: %s\n",
|
||||
world->getKart(real_karts)->getIdent().c_str());
|
||||
}
|
||||
|
||||
fprintf(fd, "kart_list_end\n");
|
||||
fprintf(fd, "version: %d\n", getReplayVersion());
|
||||
fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty());
|
||||
fprintf(fd, "track: %s\n", world->getTrack()->getIdent().c_str());
|
||||
fprintf(fd, "Laps: %d\n", race_manager->getNumLaps());
|
||||
fprintf(fd, "laps: %d\n", race_manager->getNumLaps());
|
||||
|
||||
unsigned int max_frames = (unsigned int)( stk_config->m_replay_max_time
|
||||
/ stk_config->m_replay_dt );
|
||||
for (unsigned int k = 0; k < num_karts; k++)
|
||||
{
|
||||
fprintf(fd, "model: %s\n", world->getKart(k)->getIdent().c_str());
|
||||
if (world->getKart(k)->isGhostKart()) continue;
|
||||
fprintf(fd, "size: %d\n", m_count_transforms[k]);
|
||||
|
||||
unsigned int num_transforms = std::min(max_frames,
|
||||
|
||||
@@ -378,9 +378,9 @@ void RaceGUI::drawGlobalMiniMap()
|
||||
|
||||
// int marker_height = m_marker->getSize().Height;
|
||||
core::rect<s32> source(core::position2di(0, 0), icon->getSize());
|
||||
int marker_half_size = (kart->getController()->isLocalPlayerController()
|
||||
? m_minimap_player_size
|
||||
: m_minimap_ai_size )>>1;
|
||||
int marker_half_size = (kart->isGhostKart() ? m_minimap_ai_size :
|
||||
(kart->getController()->isLocalPlayerController() ? m_minimap_player_size :
|
||||
m_minimap_ai_size))>>1;
|
||||
core::rect<s32> position(m_map_left+(int)(draw_at.getX()-marker_half_size),
|
||||
lower_y -(int)(draw_at.getY()+marker_half_size),
|
||||
m_map_left+(int)(draw_at.getX()+marker_half_size),
|
||||
|
||||
@@ -802,13 +802,14 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
|
||||
// draw icon
|
||||
video::ITexture *icon =
|
||||
kart->getKartProperties()->getIconMaterial()->getTexture();
|
||||
int w = kart->getController()
|
||||
int w = kart->isGhostKart() ? ICON_WIDTH : (kart->getController()
|
||||
->isLocalPlayerController() ? ICON_PLAYER_WIDTH
|
||||
: ICON_WIDTH;
|
||||
: ICON_WIDTH);
|
||||
const core::rect<s32> pos(x, y, x+w, y+w);
|
||||
|
||||
//to bring to light the player's icon: add a background
|
||||
if (kart->getController()->isLocalPlayerController())
|
||||
if (kart->isGhostKart() ?
|
||||
false : kart->getController()->isLocalPlayerController())
|
||||
{
|
||||
video::SColor colors[4];
|
||||
for (unsigned int i=0;i<4;i++)
|
||||
|
||||
@@ -89,6 +89,7 @@ void RaceResultGUI::init()
|
||||
for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++)
|
||||
{
|
||||
const AbstractKart *kart = World::getWorld()->getKart(kart_id);
|
||||
if (kart->isGhostKart()) continue;
|
||||
if (kart->getController()->isPlayerController())
|
||||
human_win = human_win && kart->getRaceResult();
|
||||
}
|
||||
@@ -474,7 +475,8 @@ void RaceResultGUI::determineTableLayout()
|
||||
|
||||
// Save a pointer to the current row_info entry
|
||||
RowInfo *ri = &(m_all_row_infos[position-first_position]);
|
||||
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
|
||||
ri->m_is_player_kart = kart->isGhostKart() ? false :
|
||||
kart->getController()->isLocalPlayerController();
|
||||
|
||||
// Identify Human player, if so display real name other than kart name
|
||||
const int rm_id = kart->getWorldKartId() -
|
||||
@@ -860,7 +862,8 @@ void RaceResultGUI::determineGPLayout()
|
||||
else
|
||||
ri->m_kart_name = translations->fribidize(kart->getName());
|
||||
|
||||
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
|
||||
ri->m_is_player_kart = kart->isGhostKart() ? false :
|
||||
kart->getController()->isLocalPlayerController();
|
||||
ri->m_player = ri->m_is_player_kart
|
||||
? kart->getController()->getPlayer() : NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user