1#include "RaceManager.hh"
3#include "game/system/CourseMap.hh"
4#include "game/system/KPadDirector.hh"
5#include "game/system/RaceConfig.hh"
6#include "game/system/map/MapdataCheckPath.hh"
7#include "game/system/map/MapdataStartPoint.hh"
9#include "game/kart/KartObjectManager.hh"
10#include "game/kart/KartState.hh"
15void RaceManager::init() {
24 u32 startPointIdx = 0;
26 MapdataStartPoint *kartpoint = CourseMap::Instance()->getStartPoint(startPointIdx);
32 angles = EGG::Vector3f::ex;
37void RaceManager::endPlayerRace(u32 ) {
39 m_stage = Stage::FinishGlobal;
43void RaceManager::calc() {
44 constexpr u16 STAGE_INTRO_DURATION = 172;
46 m_timerManager.calc();
51 if (++m_introTimer >= STAGE_INTRO_DURATION) {
52 m_stage = Stage::Countdown;
53 KPadDirector::Instance()->startGhostProxies();
56 case Stage::Countdown:
57 if (++m_timer >= STAGE_COUNTDOWN_DURATION) {
58 m_timerManager.setStarted(
true);
59 m_stage = Stage::Race;
71MapdataJugemPoint *RaceManager::jugemPoint()
const {
72 s8 jugemId = std::max<s8>(m_player.jugemId(), 0);
73 return System::CourseMap::Instance()->getJugemPoint(
static_cast<u16>(jugemId));
77RaceManager *RaceManager::CreateInstance() {
79 s_instance =
new RaceManager;
84void RaceManager::DestroyInstance() {
86 auto *instance = s_instance;
92RaceManager::RaceManager()
93 : m_random(RNG_SEED), m_stage(Stage::Intro), m_introTimer(0), m_timer(0) {}
96RaceManager::~RaceManager() {
99 WARN(
"RaceManager instance not explicitly handled!");
104RaceManager::Player::Player() {
106 m_raceCompletion = 0.0f;
108 m_checkpointStartLapCompletion = 0.0f;
109 m_lapCompletion = 0.999999f;
111 auto *courseMap = CourseMap::Instance();
113 if (courseMap->getCheckPointCount() > 0 && courseMap->getCheckPathCount() > 0) {
114 m_maxKcp = courseMap->checkPoint()->lastKcpType();
121 m_inputs = &KPadDirector::Instance()->playerInput();
125void RaceManager::Player::init() {
126 auto *courseMap = CourseMap::Instance();
128 if (courseMap->getCheckPointCount() != 0 && courseMap->getCheckPathCount() != 0) {
129 const EGG::Vector3f &pos = Kart::KartObjectManager::Instance()->object(0)->pos();
131 s16 checkpointId = courseMap->findSector(pos, 0, distanceRatio);
133 m_checkpointId = std::max<s16>(0, checkpointId);
134 m_jugemId = courseMap->getCheckPoint(m_checkpointId)->jugemIndex();
141void RaceManager::Player::calc() {
142 auto *courseMap = CourseMap::Instance();
143 const auto *kart = Kart::KartObjectManager::Instance()->object(0);
145 if (courseMap->getCheckPointCount() == 0 || courseMap->getCheckPathCount() == 0 ||
151 s16 checkpointId = courseMap->findSector(kart->pos(), m_checkpointId, distanceRatio);
153 if (checkpointId == -1) {
157 if (m_checkpointFactor < 0.0f || m_checkpointId != checkpointId) {
158 calcCheckpoint(checkpointId, distanceRatio);
161 m_raceCompletion =
static_cast<f32
>(m_currentLap) +
162 (m_checkpointStartLapCompletion + m_checkpointFactor * distanceRatio);
163 m_raceCompletion = std::min(m_raceCompletion,
static_cast<f32
>(m_currentLap) + 0.99999f);
171 ASSERT(lap <= m_lapTimers.size());
174 return m_lapTimers[0];
177 const Timer ¤tLap = m_lapTimers[lap - 1];
178 const Timer &previousLap = m_lapTimers[lap - 2];
179 if (!currentLap.valid || !previousLap.valid) {
180 return Timer(std::numeric_limits<u16>::max(), 0, 0);
183 return currentLap - previousLap;
188 auto *courseMap = CourseMap::Instance();
190 u16 oldCheckpointId = m_checkpointId;
191 m_checkpointId = checkpointId;
193 f32 lapProportion = courseMap->checkPath()->lapProportion();
194 MapdataCheckPath *checkPath = courseMap->checkPath()->findCheckpathForCheckpoint(checkpointId);
195 m_checkpointFactor = checkPath->oneOverCount() * lapProportion;
197 m_checkpointStartLapCompletion =
static_cast<f32
>(checkPath->depth()) * lapProportion +
198 (m_checkpointFactor *
static_cast<f32
>(checkpointId - checkPath->start()));
200 f32 newLapCompletion = m_checkpointStartLapCompletion + distanceRatio * m_checkpointFactor;
201 f32 deltaLapCompletion = m_lapCompletion - newLapCompletion;
204 const MapdataCheckPoint *oldCheckpoint = courseMap->getCheckPoint(oldCheckpointId);
206 s8 newJugemIdx = newCheckpoint->jugemIndex();
207 if (newJugemIdx >= 0) {
208 m_jugemId = newJugemIdx;
211 if (!newCheckpoint->isNormalCheckpoint()) {
212 if (newCheckpoint->checkArea() > m_maxKcp) {
213 m_maxKcp = newCheckpoint->checkArea();
214 }
else if (m_maxKcp == courseMap->checkPoint()->lastKcpType()) {
215 if ((newCheckpoint->isFinishLine() &&
216 areCheckpointsSubsequent(oldCheckpoint, checkpointId)) ||
217 deltaLapCompletion > 0.95f) {
223 if ((oldCheckpoint->isFinishLine() &&
224 areCheckpointsSubsequent(newCheckpoint, oldCheckpointId)) ||
225 deltaLapCompletion < -0.95f) {
229 m_lapCompletion = newLapCompletion;
231 return newCheckpoint;
235bool RaceManager::Player::areCheckpointsSubsequent(
const MapdataCheckPoint *checkpoint,
236 u16 nextCheckpointId)
const {
237 for (
size_t i = 0; i < checkpoint->nextCount(); ++i) {
238 if (nextCheckpointId == checkpoint->nextPoint(i)->id()) {
247void RaceManager::Player::decrementLap() {
248 auto *courseMap = CourseMap::Instance();
250 if (courseMap->getCheckPointCount() > 0 && courseMap->getCheckPathCount() > 0) {
251 m_maxKcp = courseMap->checkPoint()->lastKcpType();
260void RaceManager::Player::incrementLap() {
262 if (++m_currentLap <= m_maxLap) {
266 const auto *kart = Kart::KartObjectManager::Instance()->object(0);
267 u16 addMs = CourseMap::Instance()->getCheckPointEntryOffsetMs(m_checkpointId, kart->pos(),
270 const Timer ¤tTimer = RaceManager::Instance()->timerManager().currentTimer();
271 Timer timer = currentTimer +
static_cast<f32
>(addMs);
274 ASSERT(
static_cast<size_t>(m_maxLap - 1) < m_lapTimers.size());
275 m_lapTimers[m_maxLap - 1] = timer;
280 m_maxLap = m_currentLap;
285void RaceManager::Player::endRace(
const Timer &finishTime) {
286 m_raceTimer = finishTime;
287 RaceManager::Instance()->endPlayerRace(0);
290RaceManager *RaceManager::s_instance =
nullptr;
void findKartStartPoint(EGG::Vector3f &pos, EGG::Vector3f &angles, u8 placement, u8 playerCount)
f32 m_checkpointFactor
The proportion of a lap for the current checkpoint.
Timer getLapSplit(size_t idx) const
Gets the lap split, which is the difference between the given lap and the previous one.
void findKartStartPoint(EGG::Vector3f &pos, EGG::Vector3f &angles)
@ BeforeRespawn
Set on respawn collision, cleared on position snap.
High-level handling for generic system operations, such as input reading, race configuration,...
A simple struct to represent a lap or race finish time.