diff --git a/.gitignore b/.gitignore index fbffad63..87691ac0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,12 @@ build build.ninja +compile_commands.json +.cache/** __pycache__ out .vs .vscode +.zed *.szs statusTestCases.json .env diff --git a/source/game/system/GhostFile.cc b/source/game/system/GhostFile.cc index b2d38a02..4d579c19 100644 --- a/source/game/system/GhostFile.cc +++ b/source/game/system/GhostFile.cc @@ -141,20 +141,36 @@ bool RawGhostFile::decompress(const u8 *rkg) { } /// @addr{0x8051C120} -/// @todo Check for valid controller type? -/// @todo Check lap times sum to race time? bool RawGhostFile::isValid(const u8 *rkg) const { if (strncmp(reinterpret_cast(rkg), "RKGD", 4) != 0) { PANIC("RKG header malformed"); return false; } + + u8 laps = *(rkg+0x10); + + if (laps > 5) { + return false; + } + + Timer finalTime = Timer(parse(*reinterpret_cast(rkg+0x4))); + Timer lapSum = Timer(); + for (u8 i = 0; i < laps; i++) { + Timer lapTime = Timer(parse(*reinterpret_cast(rkg + 0x11 + (i*3)))); + lapSum += lapTime; + } + if (finalTime != lapSum) { + return false; + } + u32 ids = parse(*reinterpret_cast(rkg + 0x8)); Vehicle vehicle = static_cast(ids >> 0x1a); Character character = static_cast((ids >> 0x14) & 0x3f); u8 year = (ids >> 0xd) & 0x7f; - u8 day = (ids >> 0x4) & 0x1f; u8 month = (ids >> 0x9) & 0xf; + u8 day = (ids >> 0x4) & 0x1f; + u8 controllerType = ids & 0xf; if (vehicle >= Vehicle::Max || character >= Character::Max) { return false; @@ -163,6 +179,10 @@ bool RawGhostFile::isValid(const u8 *rkg) const { if (year >= 100 || day >= 32 || month > 12) { return false; } + + if (controllerType > 3) { + return false; + } // Validate weight class match WeightClass charWeight = CharacterToWeight(character); diff --git a/source/game/system/TimerManager.hh b/source/game/system/TimerManager.hh index 154351b3..f2b9fc84 100644 --- a/source/game/system/TimerManager.hh +++ b/source/game/system/TimerManager.hh @@ -6,7 +6,7 @@ namespace System { /// @brief A simple struct to represent a lap or race finish time. struct Timer { - Timer(); ///< @unused Creates a zero'd timer. + Timer(); /// Creates a zero'd timer. Timer(u16 min_, u8 sec_, u16 mil_); Timer(u32 data); ~Timer(); @@ -82,7 +82,37 @@ struct Timer { return Timer(newMin, newSec, newMs); } + + Timer operator+(const Timer &rhs) const { + s16 addMin = 0; + s16 addSec = 0; + s16 newMs = rhs.mil + mil; + if (newMs > 999) { + addSec = 1; + newMs -= 1000; + } + + s16 newSec = rhs.sec + sec + addSec; + if (newSec > 59) { + addMin = 1; + newSec -= 60; + } + + s16 newMin = rhs.min + min + addMin; + if (newMin > 999) { + newMin = 999; + newSec = 59; + newMs = 999; + } + + return Timer(newMin, newSec, newMs); + } + + Timer &operator+=(const Timer &rhs) { + return *this = *this + rhs; + } + u16 min; u8 sec; u16 mil; ///< @todo We will likely want to expand this to a float for more precise finish times.