#pragma once #include "StageRuntime.hpp" #include namespace openroller::psp { enum class Judgment : std::uint8_t { // Values 0..3 match the original game's recovered enum. Miss = 0, Good = 1, Cool = 2, Great = 3, Pending = 0xff, }; struct GameplayState { struct NoteRuntime { std::uint8_t judgment = static_cast(Judgment::Pending); std::uint8_t holding = 0; std::uint8_t shotMuteApplied = 0; std::uint8_t reserved = 0; float inputStartTimeMs = -1.0f; float lastInputTimeMs = -1.0f; std::uint32_t inputMask = 0; std::uint32_t lastInputBit = 0; }; NoteRuntime* notes = nullptr; std::uint32_t noteCount = 0; std::uint32_t nextPending = 0; std::uint32_t combo = 0; std::uint32_t maximumCombo = 0; std::uint32_t greatCount = 0; std::uint32_t coolCount = 0; std::uint32_t goodCount = 0; std::uint32_t missCount = 0; float previousClockMs = 0.0f; float lastJudgmentClockMs = -10000.0f; std::int32_t lastJudgedNote = -1; Judgment lastJudgment = Judgment::Pending; bool shotMuted = false; }; bool initializeGameplay(const StageView& stage, GameplayState* gameplay); void destroyGameplay(GameplayState* gameplay); void seekGameplay(const StageView& stage, GameplayState* gameplay, float clockMs); void updateGameplay(const StageView& stage, GameplayState* gameplay, float clockMs); Judgment tapGameplay(const StageView& stage, GameplayState* gameplay, float clockMs); Judgment pressGameplay( const StageView& stage, GameplayState* gameplay, float clockMs, std::uint32_t inputBit); Judgment releaseGameplay( const StageView& stage, GameplayState* gameplay, float clockMs, std::uint32_t inputBit); Judgment noteJudgment(const GameplayState& gameplay, std::uint32_t noteIndex); } // namespace openroller::psp