aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/agi/agi.h4
-rw-r--r--engines/agi/global.cpp90
2 files changed, 77 insertions, 17 deletions
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index fe70c4ebc2..c5db1dfc1d 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -870,6 +870,10 @@ private:
uint32 _getVarSecondsHeuristicLastInstructionCounter; /**< last time VM_VAR_SECONDS were read */
uint16 _getVarSecondsHeuristicCounter; /**< how many times heuristic was triggered */
+ uint32 _playTimeInSecondsAdjust; /**< milliseconds to adjust for calculating current play time in seconds, see setVarSecondsTrigger() */
+
+ void setVarSecondsTrigger(byte newSeconds);
+
public:
// Some submethods of testIfCode
void skipInstruction(byte op);
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index a7a39e9767..48e1c224ce 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -54,8 +54,13 @@ void AgiBase::flipFlag(int16 flagNr) {
void AgiEngine::setVar(int16 varNr, byte newValue) {
_game.vars[varNr] = newValue;
- if (varNr == VM_VAR_VOLUME) {
+ switch (varNr) {
+ case VM_VAR_SECONDS:
+ setVarSecondsTrigger(newValue);
+ break;
+ case VM_VAR_VOLUME:
setVolumeViaScripts(newValue);
+ break;
}
}
@@ -173,6 +178,7 @@ void AgiEngine::getVarSecondsHeuristicTrigger() {
void AgiEngine::inGameTimerReset(uint32 newPlayTime) {
_lastUsedPlayTimeInCycles = newPlayTime / 50;
_lastUsedPlayTimeInSeconds = newPlayTime / 1000;
+ _playTimeInSecondsAdjust = 0; // no adjust for now
setTotalPlayTime(newPlayTime);
inGameTimerResetPassedCycles();
}
@@ -192,6 +198,24 @@ uint32 AgiEngine::inGameTimerGetPassedCycles() {
return _passedPlayTimeCycles;
}
+// Seconds got set by the game
+// This happens in Mixed Up Mother Goose. The game syncs the songs to VM_VAR_SECONDS, but instead
+// of only reading them, it sets it to 0 and then checks if it reached a certain second.
+// The original interpreter didn't reset the internal cycles counter. Which means the timing was never accurate,
+// because the cycles counter may just overflow right after setting the seconds, which means a second
+// increase almost immediately happened. We even fix this issue by adjusting for it.
+void AgiEngine::setVarSecondsTrigger(byte newSeconds) {
+ // Adjust in game timer, so that VM timer variables are accurate
+ inGameTimerUpdate();
+
+ // Adjust VM seconds again
+ _game.vars[VM_VAR_SECONDS] = newSeconds;
+
+ // Calculate milliseconds adjust (see comment above)
+ uint32 curPlayTimeMilliseconds = inGameTimerGet();
+ _playTimeInSecondsAdjust = curPlayTimeMilliseconds % 1000;
+}
+
// This is called, when one of the timer variables is read
// We calculate the latest variables, according to current official playtime
// This is also called in the main loop, because the game needs to be sync'd to 20 cycles per second
@@ -212,6 +236,14 @@ void AgiEngine::inGameTimerUpdate() {
_lastUsedPlayTimeInCycles = curPlayTimeCycles;
// Now calculate current play time in seconds
+ if (_playTimeInSecondsAdjust) {
+ // Apply adjust from setVarSecondsTrigger()
+ if (curPlayTimeMilliseconds >= _playTimeInSecondsAdjust) {
+ curPlayTimeMilliseconds -= _playTimeInSecondsAdjust;
+ } else {
+ curPlayTimeMilliseconds = 0;
+ }
+ }
uint32 curPlayTimeSeconds = curPlayTimeMilliseconds / 1000;
if (curPlayTimeSeconds == _lastUsedPlayTimeInSeconds) {
@@ -219,26 +251,50 @@ void AgiEngine::inGameTimerUpdate() {
return;
}
- uint32 secondsLeft = 0;
- byte curDays = 0;
- byte curHours = 0;
- byte curMinutes = 0;
- byte curSeconds = 0;
+ int32 playTimeSecondsDelta = curPlayTimeSeconds - _lastUsedPlayTimeInSeconds;
- curDays = curPlayTimeSeconds / 86400;
- secondsLeft = curPlayTimeSeconds % 86400;
+ if (playTimeSecondsDelta > 0) {
+ // Read and write to VM vars directly to avoid endless loop
+ uint32 secondsLeft = playTimeSecondsDelta;
+ byte curSeconds = _game.vars[VM_VAR_SECONDS];
+ byte curMinutes = _game.vars[VM_VAR_MINUTES];
+ byte curHours = _game.vars[VM_VAR_HOURS];
+ byte curDays = _game.vars[VM_VAR_DAYS];
- curHours = secondsLeft / 3600;
- secondsLeft = secondsLeft % 3600;
+ // Add delta to VM variables
+ if (secondsLeft >= 86400) {
+ curDays += secondsLeft / 86400;
+ secondsLeft = secondsLeft % 86400;
+ }
+ if (secondsLeft >= 3600) {
+ curHours += secondsLeft / 3600;
+ secondsLeft = secondsLeft % 3600;
+ }
+ if (secondsLeft >= 60) {
+ curMinutes += secondsLeft / 60;
+ secondsLeft = secondsLeft % 60;
+ }
+ curSeconds += secondsLeft;
- curMinutes = secondsLeft / 60;
- curSeconds = secondsLeft % 60;
+ while (curSeconds > 59) {
+ curSeconds -= 60;
+ curMinutes++;
+ }
+ while (curMinutes > 59) {
+ curMinutes -= 60;
+ curHours++;
+ }
+ while (curHours > 23) {
+ curHours -= 24;
+ curDays++;
+ }
- // directly set them, otherwise we would go into an endless loop
- _game.vars[VM_VAR_SECONDS] = curSeconds;
- _game.vars[VM_VAR_MINUTES] = curMinutes;
- _game.vars[VM_VAR_HOURS] = curHours;
- _game.vars[VM_VAR_DAYS] = curDays;
+ // directly set them
+ _game.vars[VM_VAR_SECONDS] = curSeconds;
+ _game.vars[VM_VAR_MINUTES] = curMinutes;
+ _game.vars[VM_VAR_HOURS] = curHours;
+ _game.vars[VM_VAR_DAYS] = curDays;
+ }
_lastUsedPlayTimeInSeconds = curPlayTimeSeconds;
}