From 5484f0bc58b77bf7dd28debf1b7a53bd138ba28c Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Fri, 19 Feb 2016 10:34:37 +0100 Subject: AGI: Add detection+workaround for endofloop+motion at the same time Detects when end.of.loop + motions are used on the same screen object at the same time, which would have resulted in flag corruption in the original interpreter. We detect this situation now, show a warning and disable the cycler in case cycler was activated first. This solves a new issue in kq1, when grabbing the eagle in room 22, that was previously hidden just like in the original AGI. Fixes bug #7046 --- engines/agi/motion.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'engines/agi/motion.cpp') diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp index 7f49028701..8aae0e5924 100644 --- a/engines/agi/motion.cpp +++ b/engines/agi/motion.cpp @@ -62,6 +62,57 @@ void AgiEngine::changePos(ScreenObjEntry *screenObj) { } } +// WORKAROUND: +// A motion was just activated, check if "end.of.loop"/"reverse.loop" is currently active for the same screen object +// If this is the case, it would result in some random flag getting overwritten in original AGI after the loop was +// completed, because in original AGI loop_flag + move_flag shared the same memory location. +// This is basically an implementation error in the original interpreter. +// Happens in at least KQ1, when grabbing the eagle (room 22). +void AgiEngine::motionActivated(ScreenObjEntry *screenObj) { + if (screenObj->flags & fCycling) { + // Cycling active too + switch (screenObj->cycle) { + case kCycleEndOfLoop: // "end.of.loop" + case kCycleRevLoop: // "reverse.loop" + // Disable it + screenObj->flags &= ~fCycling; + screenObj->cycle = kCycleNormal; + + warning("Motion activated for screen object %d, but cycler also active", screenObj->objectNr); + warning("This would have resulted in flag corruption in original AGI. Cycler disabled."); + break; + default: + break; + } + } +} + +// WORKAROUND: +// See comment for motionActivated() +// This way no flag would have been overwritten, but certain other variables of the motions. +void AgiEngine::cyclerActivated(ScreenObjEntry *screenObj) { + switch (screenObj->motionType) { + case kMotionWander: + // this would have resulted in wander_count to get corrupted + // We don't stop it. + break; + case kMotionFollowEgo: + // this would have resulted in follow_stepSize to get corrupted + // do not stop motion atm - screenObj->direction = 0; + // do not stop motion atm - screenObj->motionType = kMotionNormal; + break; + case kMotionMoveObj: + // this would have resulted in move_x to get corrupted + // do not stop motion atm - motionMoveObjStop(screenObj); + break; + default: + return; + break; + } + warning("Cycler activated for screen object %d, but motion also active", screenObj->objectNr); + warning("This would have resulted in corruption in original AGI. Motion disabled."); +} + void AgiEngine::motionWander(ScreenObjEntry *screenObj) { uint8 originalWanderCount = screenObj->wander_count; -- cgit v1.2.3