[Scummvm-cvs-logs] scummvm master -> 7b75936f56fc5ea089e3fc957a113dc7577e832f

m-kiewitz m_kiewitz at users.sourceforge.net
Sun Feb 14 22:43:50 CET 2016


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
7b75936f56 AGI: Add heuristic to detect delay loops within scripts


Commit: 7b75936f56fc5ea089e3fc957a113dc7577e832f
    https://github.com/scummvm/scummvm/commit/7b75936f56fc5ea089e3fc957a113dc7577e832f
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-02-14T22:43:52+01:00

Commit Message:
AGI: Add heuristic to detect delay loops within scripts

And in that case poll events, delay for a few milliseconds and
update screen.
This somewhat worked before the graphics rewrite because of
a timer hack.
This one tries to detect actual inner loops.
Happens in at least Police Quest 1 when playing poker.

Changed paths:
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/cycle.cpp
    engines/agi/global.cpp
    engines/agi/op_cmd.cpp



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index fdc294a..f149b0b 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -401,6 +401,8 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
 
 	setupOpcodes();
 	_game._curLogic = NULL;
+	_instructionCounter = 0;
+	resetGetVarSecondsHeuristic();
 
 	_lastSaveTime = 0;
 
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 627b18e..ad5d320 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -862,6 +862,12 @@ public:
 	int testIfCode(int);
 	void executeAgiCommand(uint8, uint8 *);
 
+private:
+	void resetGetVarSecondsHeuristic();
+	uint32 _instructionCounter; /**< counts every instruction, that got executed, can wrap around */
+	uint32 _getVarSecondsHeuristicLastInstructionCounter; /**< last time VM_VAR_SECONDS were read */
+	uint16 _getVarSecondsHeuristicCounter; /**< how many times heuristic was triggered */
+
 public:
 	// Some submethods of testIfCode
 	void skipInstruction(byte op);
@@ -955,6 +961,8 @@ private:
 public:
 	void redrawScreen();
 
+	void getVarSecondsTrigger();
+
 	void inGameTimerReset(uint32 newPlayTime = 0);
 	void inGameTimerResetPassedCycles();
 	void inGameTimerPause();
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index a3873a0..9b7dc63 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -142,6 +142,9 @@ void AgiEngine::interpretCycle() {
 	oldScore = getVar(VM_VAR_SCORE);
 	oldSound = getFlag(VM_FLAG_SOUND_ON);
 
+	// Reset script heuristic here
+	resetGetVarSecondsHeuristic();
+
 	_game.exitAllLogics = false;
 	while (runLogic(0) == 0 && !(shouldQuit() || _restartGame)) {
 		setVar(VM_VAR_WORD_NOT_FOUND, 0);
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 0f10976..fe3becc 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -23,6 +23,7 @@
 #include "common/config-manager.h"
 
 #include "agi/agi.h"
+#include "agi/graphics.h"
 
 namespace Agi {
 
@@ -61,6 +62,8 @@ void AgiEngine::setVar(int16 varNr, byte newValue) {
 byte AgiEngine::getVar(int16 varNr) {
 	switch (varNr) {
 	case VM_VAR_SECONDS:
+		getVarSecondsTrigger();
+		// is supposed to fall through
 	case VM_VAR_MINUTES:
 	case VM_VAR_HOURS:
 	case VM_VAR_DAYS:
@@ -135,6 +138,35 @@ void AgiEngine::setVolumeViaSystemSetting() {
 	_game.vars[VM_VAR_VOLUME] = internalVolume;
 }
 
+void AgiEngine::resetGetVarSecondsHeuristic() {
+	_getVarSecondsHeuristicLastInstructionCounter = 0;
+	_getVarSecondsHeuristicCounter = 0;
+}
+
+// Called, when the scripts read VM_VAR_SECONDS
+void AgiEngine::getVarSecondsTrigger() {
+	uint32 counterDifference = _instructionCounter - _getVarSecondsHeuristicLastInstructionCounter;
+
+	if (counterDifference <= 3) {
+		// Seconds were read within 3 instructions
+		_getVarSecondsHeuristicCounter++;
+		if (_getVarSecondsHeuristicCounter > 20) {
+			// More than 20 times in a row? This really seems to be an inner loop waiting for seconds to change
+			// This happens in at least:
+			// Police Quest 1 - Poker game
+
+			// Wait a few milliseconds, get events and update screen
+			// We MUST NOT process AGI events in here
+			wait(10);
+			processScummVMEvents();
+			_gfx->updateScreen();
+
+			_getVarSecondsHeuristicCounter = 0;
+		}
+	}
+	_getVarSecondsHeuristicLastInstructionCounter = _instructionCounter;
+}
+
 // In-Game timer, used for timer VM Variables
 void AgiEngine::inGameTimerReset(uint32 newPlayTime) {
 	_lastUsedPlayTimeInCycles = newPlayTime / 50;
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 61ef20a..29e0066 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -2327,6 +2327,9 @@ int AgiEngine::runLogic(int16 logicNr) {
 		}
 #endif
 
+		// Just a counter for every instruction, that got executed
+		_instructionCounter++;
+
 		_game.execStack.back().curIP = state->_curLogic->cIP;
 
 		char st[101];






More information about the Scummvm-git-logs mailing list