Skip to content

Commit 85c50b3

Browse files
committed
Some replay logic changes
1 parent 0ca01b1 commit 85c50b3

File tree

4 files changed

+105
-5
lines changed

4 files changed

+105
-5
lines changed

source/code/main.cpp

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,10 @@ static bool registerEndlessHighscore = false;
773773
static bool registerTTHighscorePlayer1 = false;
774774
static bool registerTTHighscorePlayer2 = false;
775775
static bool saveReplay = false;
776+
static std::deque<BlockGameAction> replayQueue;
777+
static size_t replayActionIndex = 0;
778+
static bool isReplayMode = false;
779+
static unsigned int replayTimeOffset = 0; // Offset between original game time and replay time
776780

777781
/**
778782
* startSpeed is a value from 0 to 4
@@ -1463,6 +1467,10 @@ int runGame(Gametype gametype, int level) {
14631467
registerEndlessHighscore = false;
14641468
registerTTHighscorePlayer1 = false;
14651469
registerTTHighscorePlayer2 = false;
1470+
isReplayMode = false;
1471+
replayQueue.clear();
1472+
replayActionIndex = 0;
1473+
replayTimeOffset = 0;
14661474
switch (gametype) {
14671475
case Gametype::SinglePlayerTimeTrial:
14681476
StartSinglePlayerTimeTrial();
@@ -1515,6 +1523,35 @@ int runGame(Gametype gametype, int level) {
15151523
case Gametype::TwoPlayerVs:
15161524
StartTwoPlayerVs();
15171525
break;
1526+
case Gametype::Replay: {
1527+
BlockGameInfo replayInfo;
1528+
if (!LoadLatestSinglePlayerReplay(replayInfo)) {
1529+
// No replay available, exit
1530+
return 1;
1531+
}
1532+
// Calculate time offset: current time - original start time
1533+
unsigned int currentStartTime = SDL_GetTicks();
1534+
unsigned int originalStartTime = replayInfo.startInfo.ticks;
1535+
replayTimeOffset = currentStartTime - originalStartTime;
1536+
1537+
// Adjust startInfo ticks to current time
1538+
replayInfo.startInfo.ticks = currentStartTime;
1539+
theGame.NewGame(replayInfo.startInfo);
1540+
twoPlayers = false;
1541+
BlockGameAction a;
1542+
a.action = BlockGameAction::Action::SET_GAME_OVER;
1543+
theGame2.DoAction(a);
1544+
theGame.name = replayInfo.extra.name;
1545+
theGame2.name = globalData.player2name;
1546+
// Set up replay queue and adjust all action timestamps
1547+
replayQueue = replayInfo.actions;
1548+
for (BlockGameAction& action : replayQueue) {
1549+
action.tick += replayTimeOffset;
1550+
}
1551+
replayActionIndex = 0;
1552+
isReplayMode = true;
1553+
}
1554+
break;
15181555
case Gametype::SinglePlayerEndless:
15191556
default:
15201557
StartSinglePlayerEndless(level);
@@ -1606,7 +1643,7 @@ int runGame(Gametype gametype, int level) {
16061643
done=1;
16071644
DrawBackground(globalData.screen);
16081645
}
1609-
if (!theGame.GetAIenabled()) {
1646+
if (!theGame.GetAIenabled() && !isReplayMode) {
16101647
//player1:
16111648
if ( event.key.keysym.sym == keySettings[player1keys].up ) {
16121649
a.action = BlockGameAction::Action::MOVE;
@@ -1923,9 +1960,34 @@ int runGame(Gametype gametype, int level) {
19231960

19241961
//set bNearDeath to false theGame*.Update() will change to true as needed
19251962
bNearDeath = theGame.IsNearDeath() || theGame2.IsNearDeath();
1926-
//Updates the objects
1963+
1964+
// Process replay actions if in replay mode
1965+
if (isReplayMode) {
1966+
unsigned int currentTick = SDL_GetTicks();
1967+
while (replayActionIndex < replayQueue.size()) {
1968+
const BlockGameAction& replayAction = replayQueue[replayActionIndex];
1969+
// Process all actions up to the current tick
1970+
if (replayAction.action == BlockGameAction::Action::UPDATE) {
1971+
if (replayAction.tick > currentTick) {
1972+
break; // Wait for the right time
1973+
}
1974+
theGame.DoAction(replayAction);
1975+
replayActionIndex++;
1976+
break; // Only process one UPDATE per frame
1977+
} else {
1978+
// Non-UPDATE actions can be processed immediately
1979+
theGame.DoAction(replayAction);
1980+
replayActionIndex++;
1981+
}
1982+
}
1983+
} else {
1984+
//Updates the objects (only when not in replay mode)
1985+
a.action = BlockGameAction::Action::UPDATE;
1986+
theGame.DoAction(a);
1987+
}
1988+
1989+
// Always update player 2
19271990
a.action = BlockGameAction::Action::UPDATE;
1928-
theGame.DoAction(a);
19291991
theGame2.DoAction(a);
19301992

19311993
//see if anyone has won (two players only)
@@ -2021,6 +2083,10 @@ int runGame(Gametype gametype, int level) {
20212083
}
20222084
}
20232085
#endif
2086+
// Save latest single player replay for replay feature
2087+
if (theGame.isGameOver() && !twoPlayers && !theGame.GetAIenabled()) {
2088+
SaveLatestSinglePlayerReplay(theGame.GetBlockGameInfo());
2089+
}
20242090

20252091
//Once evrything has been checked, update graphics
20262092
MoveBlockGameSdls(theGame, theGame2);

source/code/menudef.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,9 +616,13 @@ static void HelpMenu() {
616616
RunGameState(m);
617617
}
618618

619+
static void runReplayLastGame() {
620+
runGame(Gametype::Replay, 0);
621+
}
622+
619623
static void SinglePlayerMenu() {
620624
Menu m(globalData.screen, _("Single player"), true);
621-
Button bHi,bTimetrial1, bStageClear, bPuzzle, bVs1;
625+
Button bHi,bTimetrial1, bStageClear, bPuzzle, bVs1, bReplay;
622626
bHi.setLabel(_("Single player - endless") );
623627
bHi.setAction(runSinglePlayerEndless);
624628
bTimetrial1.setLabel(_("Single player - time trial") );
@@ -629,11 +633,15 @@ static void SinglePlayerMenu() {
629633
bPuzzle.setAction(runSinglePlayerPuzzle);
630634
bVs1.setLabel(_("Single player - vs") );
631635
bVs1.setAction(SinglePlayerVsMenu);
636+
bReplay.setLabel(_("Replay last game") );
637+
bReplay.setAction(runReplayLastGame);
638+
bReplay.setPopOnRun(true);
632639
m.addButton(&bHi);
633640
m.addButton(&bTimetrial1);
634641
m.addButton(&bStageClear);
635642
m.addButton(&bPuzzle);
636643
m.addButton(&bVs1);
644+
m.addButton(&bReplay);
637645
RunGameState(m);
638646
}
639647

source/code/replayhandler.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,26 @@ void SaveReplay(const BlockGameInfo& game1, const BlockGameInfo& game2) {
8383
std::tm t = GetLocalTime();
8484
std::string filename = CreateFileName(t);
8585
SaveReplayToFile(sr, filename);
86+
}
87+
88+
void SaveLatestSinglePlayerReplay(const BlockGameInfo& game1) {
89+
SavedReplayStruct sr;
90+
sr.numberOfPlayers = 1;
91+
sr.playerInfo.push_back(game1);
92+
std::string filename = "replays/latest_single_player_replay.json";
93+
SaveReplayToFile(sr, filename);
94+
}
95+
96+
bool LoadLatestSinglePlayerReplay(BlockGameInfo& game1) {
97+
try {
98+
SavedReplayStruct sr;
99+
LoadReplayFromPhysFile(sr, "replays/latest_single_player_replay.json");
100+
if (sr.playerInfo.size() > 0) {
101+
game1 = sr.playerInfo.at(0);
102+
return true;
103+
}
104+
} catch (const std::exception& e) {
105+
return false;
106+
}
107+
return false;
86108
}

source/code/replayhandler.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,8 @@ struct SavedReplayStruct {
3232

3333
void SaveReplay(const BlockGameInfo& game1);
3434

35-
void SaveReplay(const BlockGameInfo& game1, const BlockGameInfo& game2);
35+
void SaveReplay(const BlockGameInfo& game1, const BlockGameInfo& game2);
36+
37+
void SaveLatestSinglePlayerReplay(const BlockGameInfo& game1);
38+
39+
bool LoadLatestSinglePlayerReplay(BlockGameInfo& game1);

0 commit comments

Comments
 (0)