diff --git a/TODO.txt b/TODO.txt index 19b4940..82d2ae9 100644 --- a/TODO.txt +++ b/TODO.txt @@ -2,6 +2,7 @@ fuck issue trackers :D =========== GENERAL ============== +- menu: key repeat? - controller supports? analog input could be "tapping" the keys with varying frequency - frontends: @@ -44,6 +45,7 @@ fuck issue trackers :D =========== HANDLED ============== - should drifting make a sound? NO NEED +- replay validation? maybe yes? - ghost color - make reverse maps - remake TM maps in the third party repo @@ -71,8 +73,6 @@ fuck issue trackers :D again (reshape iterations, tension, ...); seem acceptable now maybe? - in tiny resolution the sky jumps when rotating - car particles seem too big in low res -- replay validation? MAYBE NOT, make a separate tool if needed, shouldn't likely - be part of the game - at high resolution (like 1920) buggy triangles sometimes appeard, tried to fix this in S3L now but needs to be tested - shift the car texture a bit to align the wheels? KINDA DOESN'T GETT BETTER NOW diff --git a/game.h b/game.h index 452b4a2..37a3bf3 100644 --- a/game.h +++ b/game.h @@ -853,8 +853,8 @@ uint8_t LCR_gameLoadMap(unsigned int mapIndex) /** Loads replay by its index, returns index of a map for the replay (and the map will be loaded as with LCR_mapLoadFromStr) or -1 if the map wasn't found or -2 - if the replay couldn't be loaded. This function potentially reloads current - map! + if the replay couldn't be loaded or -3 if the replay is invalid. This function + potentially reloads current map! */ unsigned int LCR_gameLoadReplay(unsigned int replayIndex) { @@ -900,7 +900,7 @@ unsigned int LCR_gameLoadReplay(unsigned int replayIndex) LCR_LOG2("map name hash matches"); if (LCR_gameLoadMap(mapIndex) && mapHash == LCR_currentMap.hash) - return mapIndex; + return LCR_replayValidate() ? mapIndex : -3; else { LCR_LOG2("bad map"); @@ -1243,7 +1243,7 @@ void LCR_gameDraw3DView(void) LCR_GameUnit carTransform[6]; LCR_GameUnit physicsInterpolationParam = - !(LCR_racing.playingReplay && LCR_replayHasFinished()) ? + !(LCR_racing.replay.on && LCR_replayHasFinished()) ? LCR_GAME_UNIT - ((LCR_game.nextRacingTickTime - LCR_game.time) * LCR_GAME_UNIT) / LCR_RACING_TICK_MS @@ -1388,7 +1388,7 @@ void LCR_gameHandleInput(void) LCR_currentMap.targetTime = LCR_game.runTime; } - LCR_gameResetRun(LCR_racing.playingReplay,LCR_game.ghost.active); + LCR_gameResetRun(LCR_racing.replay.on,LCR_game.ghost.active); } } else if (LCR_game.state == LCR_GAME_STATE_RUN_STARTING) @@ -1448,7 +1448,7 @@ void LCR_gameHandleInput(void) LCR_rendererMoveCamera(offsets,offsets + 3); } else if (LCR_game.keyStates[LCR_KEY_A] == 1) - LCR_gameResetRun(LCR_racing.playingReplay,LCR_game.ghost.active); + LCR_gameResetRun(LCR_racing.replay.on,LCR_game.ghost.active); } else // LCR_GAME_STATE_MENU { @@ -1549,7 +1549,7 @@ void LCR_gameHandleInput(void) case 3: if (LCR_game.statePrev == LCR_GAME_STATE_RUN_FINISHED && - !LCR_racing.playingReplay) + !LCR_racing.replay.on) LCR_gameSaveReplay(); else LCR_gamePopupMessage(LCR_texts[LCR_TEXTS_FAIL]); @@ -1719,12 +1719,12 @@ uint8_t LCR_gameStep(uint32_t time) LCR_LOG1_NUM(LCR_game.runTime); if (LCR_game.runTime <= LCR_currentMap.targetTime && - !LCR_racing.playingReplay) + !LCR_racing.replay.on) { LCR_gameSaveReplay(); if (!LCR_game.mapBeaten && !LCR_game.ghost.active && - !LCR_racing.playingReplay) + !LCR_racing.replay.on) { LCR_LOG1("map beaten"); LCR_game.mapBeaten = 1; diff --git a/racing.h b/racing.h index bcc47a3..375e1df 100644 --- a/racing.h +++ b/racing.h @@ -168,10 +168,9 @@ struct uint16_t crashState; - uint8_t playingReplay; - struct { + uint8_t on; ///< Currently playing replay? uint16_t eventCount; uint16_t events[LCR_SETTING_REPLAY_MAX_SIZE]; @@ -376,7 +375,7 @@ int LCR_replayHasFinished(void) for (int i = 0; i < LCR_racing.replay.eventCount; ++i) totalTime += LCR_racing.replay.events[i] >> 4; - return totalTime >= LCR_racing.replay.achievedTime; + return totalTime > LCR_racing.replay.achievedTime; } return LCR_racing.replay.currentEvent > LCR_racing.replay.eventCount; @@ -445,7 +444,8 @@ int LCR_replayRecordEvent(uint32_t frame, uint8_t input) frame -= previousFrame; // convert to offset - while (frame > 4095 && LCR_racing.replay.eventCount < LCR_SETTING_REPLAY_MAX_SIZE) + while (frame > 4095 && LCR_racing.replay.eventCount < + LCR_SETTING_REPLAY_MAX_SIZE) { // add intermediate events frame -= 4095; @@ -982,7 +982,7 @@ void LCR_racingRestart(uint8_t replay) LCR_racing.tick = 0; LCR_racing.fanForce = 0; - LCR_racing.playingReplay = replay; + LCR_racing.replay.on = replay; TPE_bodyActivate(&(LCR_racing.carBody)); LCR_racing.wheelCollisions = 0; @@ -1066,7 +1066,7 @@ void LCR_racingInit(void) TPE_worldInit(&(LCR_racing.physicsWorld), &(LCR_racing.carBody),1,_LCR_racingEnvironmentFunction); - LCR_racing.playingReplay = 0; + LCR_racing.replay.on = 0; LCR_racing.physicsWorld.collisionCallback = _LCR_racingCollisionHandler; } @@ -1217,7 +1217,7 @@ uint32_t LCR_racingStep(unsigned int input) LCR_racing.groundMaterial = LCR_BLOCK_MATERIAL_CONCRETE; - if (LCR_racing.playingReplay) + if (LCR_racing.replay.on) { if (LCR_racing.tick == 0) LCR_replayInitPlaying(); @@ -1637,7 +1637,7 @@ uint32_t LCR_racingStep(unsigned int input) { result |= LCR_RACING_EVENT_FINISHED; - if (!LCR_racing.playingReplay) + if (!LCR_racing.replay.on) LCR_replayRecordEvent(LCR_racing.tick,LCR_REPLAY_EVENT_END); } } @@ -1677,5 +1677,63 @@ void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2], cPos,cRot,cView,16,LCR_PHYSICS_UNIT / 4,LCR_racing.tick * 4); #endif } - + +/** + Validates replay, i.e. checks if it finishes and whether its achieved time + agrees with the stored time. The function can only be called when both the + replay and the correct map are loaded. The loaded replay's playing position + will be reset after this function returns. +*/ +int LCR_replayValidate(void) +{ + LCR_LOG1("validating replay"); + + int result = 0; + + LCR_racingRestart(1); + + while (LCR_racing.tick < 0x00f00000 // no infinite loops + && LCR_racing.tick <= LCR_racing.replay.achievedTime) + { + int coords[3]; + + LCR_racingStep(0); + LCR_racingGetCarBlockCoords(coords); + + coords[0] = LCR_mapGetBlockAt(coords[0],coords[1],coords[2]); + + if (coords[0] && LCR_currentMap.blocks[coords[0] * LCR_BLOCK_SIZE] == + LCR_BLOCK_FINISH) + { + uint8_t allCPsTaken = 1; // reuse as variable + + for (int i = 0; i < LCR_currentMap.blockCount; ++i) + if (LCR_currentMap.blocks[i * LCR_BLOCK_SIZE] == LCR_BLOCK_CHECKPOINT_0) + { + allCPsTaken = 0; + break; + } + + if (allCPsTaken) + { + result = LCR_racing.tick == (LCR_racing.replay.achievedTime + 1); + break; + } + } + } + + if (result) + { + LCR_LOG1("replay valid"); + } + else + { + LCR_LOG1("replay invalid!"); + } + + LCR_racingRestart(1); + + return result; +} + #endif // guard