1#include "RaceManager.hh"
3#include "game/system/CourseMap.hh"
4#include "game/system/KPadDirector.hh"
5#include "game/system/map/MapdataCheckPath.hh"
6#include "game/system/map/MapdataStartPoint.hh"
8#include "game/kart/KartObjectManager.hh"
9#include "game/kart/KartState.hh"
14void RaceManager::init() {
23 u32 startPointIdx = 0;
25 MapdataStartPoint *kartpoint = CourseMap::Instance()->getStartPoint(startPointIdx);
31 angles = EGG::Vector3f::ex;
36void RaceManager::endPlayerRace(
u32 ) {
38 m_stage = Stage::FinishGlobal;
42void RaceManager::calc() {
43 constexpr u16 STAGE_INTRO_DURATION = 172;
45 m_timerManager.calc();
50 if (++m_introTimer >= STAGE_INTRO_DURATION) {
51 m_stage = Stage::Countdown;
52 KPadDirector::Instance()->startGhostProxies();
55 case Stage::Countdown:
56 if (++m_timer >= STAGE_COUNTDOWN_DURATION) {
57 m_timerManager.setStarted(
true);
58 m_stage = Stage::Race;
70MapdataJugemPoint *RaceManager::jugemPoint()
const {
71 s8 jugemId = std::max<s8>(m_player.jugemId(), 0);
72 return System::CourseMap::Instance()->getJugemPoint(
static_cast<u16>(jugemId));
76RaceManager *RaceManager::CreateInstance() {
78 s_instance =
new RaceManager;
83void RaceManager::DestroyInstance() {
85 auto *instance = s_instance;
91RaceManager::RaceManager()
92 : m_random(RNG_SEED), m_stage(Stage::Intro), m_introTimer(0), m_timer(0) {}
95RaceManager::~RaceManager() {
98 WARN(
"RaceManager instance not explicitly handled!");
103RaceManager::Player::Player() {
105 m_raceCompletion = 0.0f;
107 m_checkpointStartLapCompletion = 0.0f;
108 m_lapCompletion = 0.999999f;
110 auto *courseMap = CourseMap::Instance();
112 if (courseMap->getCheckPointCount() > 0 && courseMap->getCheckPathCount() > 0) {
113 m_maxKcp = courseMap->checkPoint()->lastKcpType();
120 m_inputs = &KPadDirector::Instance()->playerInput();
124void RaceManager::Player::init() {
125 auto *courseMap = CourseMap::Instance();
127 if (courseMap->getCheckPointCount() != 0 && courseMap->getCheckPathCount() != 0) {
128 const EGG::Vector3f &pos = Kart::KartObjectManager::Instance()->object(0)->pos();
130 s16 checkpointId = courseMap->findSector(pos, 0, distanceRatio);
132 m_checkpointId = std::max<s16>(0, checkpointId);
133 m_jugemId = courseMap->getCheckPoint(m_checkpointId)->jugemIndex();
140void RaceManager::Player::calc() {
141 auto *courseMap = CourseMap::Instance();
142 const auto *kart = Kart::KartObjectManager::Instance()->object(0);
144 if (courseMap->getCheckPointCount() == 0 || courseMap->getCheckPathCount() == 0 ||
145 kart->state()->isBeforeRespawn()) {
150 s16 checkpointId = courseMap->findSector(kart->pos(), m_checkpointId, distanceRatio);
152 if (checkpointId == -1) {
156 if (m_checkpointFactor < 0.0f || m_checkpointId != checkpointId) {
157 calcCheckpoint(checkpointId, distanceRatio);
160 m_raceCompletion =
static_cast<f32
>(m_currentLap) +
161 (m_checkpointStartLapCompletion + m_checkpointFactor * distanceRatio);
162 m_raceCompletion = std::min(m_raceCompletion,
static_cast<f32
>(m_currentLap) + 0.99999f);
170 ASSERT(lap <= m_lapTimers.size());
173 return m_lapTimers[0];
176 const Timer ¤tLap = m_lapTimers[lap - 1];
177 const Timer &previousLap = m_lapTimers[lap - 2];
178 if (!currentLap.valid || !previousLap.valid) {
179 return Timer(std::numeric_limits<u16>::max(), 0, 0);
182 return currentLap - previousLap;
187 auto *courseMap = CourseMap::Instance();
189 u16 oldCheckpointId = m_checkpointId;
190 m_checkpointId = checkpointId;
192 f32 lapProportion = courseMap->checkPath()->lapProportion();
193 MapdataCheckPath *checkPath = courseMap->checkPath()->findCheckpathForCheckpoint(checkpointId);
194 m_checkpointFactor = checkPath->oneOverCount() * lapProportion;
196 m_checkpointStartLapCompletion =
static_cast<f32
>(checkPath->depth()) * lapProportion +
197 (m_checkpointFactor *
static_cast<f32
>(checkpointId - checkPath->start()));
199 f32 newLapCompletion = m_checkpointStartLapCompletion + distanceRatio * m_checkpointFactor;
200 f32 deltaLapCompletion = m_lapCompletion - newLapCompletion;
203 const MapdataCheckPoint *oldCheckpoint = courseMap->getCheckPoint(oldCheckpointId);
205 s8 newJugemIdx = newCheckpoint->jugemIndex();
206 if (newJugemIdx >= 0) {
207 m_jugemId = newJugemIdx;
210 if (!newCheckpoint->isNormalCheckpoint()) {
211 if (newCheckpoint->checkArea() > m_maxKcp) {
212 m_maxKcp = newCheckpoint->checkArea();
213 }
else if (m_maxKcp == courseMap->checkPoint()->lastKcpType()) {
214 if ((newCheckpoint->isFinishLine() &&
215 areCheckpointsSubsequent(oldCheckpoint, checkpointId)) ||
216 deltaLapCompletion > 0.95f) {
222 if ((oldCheckpoint->isFinishLine() &&
223 areCheckpointsSubsequent(newCheckpoint, oldCheckpointId)) ||
224 deltaLapCompletion < -0.95f) {
228 m_lapCompletion = newLapCompletion;
230 return newCheckpoint;
234bool RaceManager::Player::areCheckpointsSubsequent(
const MapdataCheckPoint *checkpoint,
235 u16 nextCheckpointId)
const {
236 for (
size_t i = 0; i < checkpoint->nextCount(); ++i) {
237 if (nextCheckpointId == checkpoint->nextPoint(i)->id()) {
246void RaceManager::Player::decrementLap() {
247 auto *courseMap = CourseMap::Instance();
249 if (courseMap->getCheckPointCount() > 0 && courseMap->getCheckPathCount() > 0) {
250 m_maxKcp = courseMap->checkPoint()->lastKcpType();
259void RaceManager::Player::incrementLap() {
261 if (++m_currentLap <= m_maxLap) {
265 const auto *kart = Kart::KartObjectManager::Instance()->object(0);
266 u16 addMs = CourseMap::Instance()->getCheckPointEntryOffsetMs(m_checkpointId, kart->pos(),
269 const Timer ¤tTimer = RaceManager::Instance()->timerManager().currentTimer();
270 Timer timer = currentTimer +
static_cast<f32
>(addMs);
273 ASSERT(
static_cast<size_t>(m_maxLap - 1) < m_lapTimers.size());
274 m_lapTimers[m_maxLap - 1] = timer;
279 m_maxLap = m_currentLap;
284void RaceManager::Player::endRace(
const Timer &finishTime) {
285 m_raceTimer = finishTime;
286 RaceManager::Instance()->endPlayerRace(0);
289RaceManager *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)
High-level handling for generic system operations, such as input reading, race configuration,...
A simple struct to represent a lap or race finish time.