[Scummvm-git-logs] scummvm master -> ce2410f7a3241ed4e7da15049be8ae6c96327b8c

sluicebox noreply at scummvm.org
Tue Oct 29 04:04:38 UTC 2024


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

Summary:
7c46ab8ce8 AGI: Cleanup GfxMgr, PictureMgr
a5909e5f60 AGI: Move AGI256 picture opcode into function
f15c08bfb6 AGI: Remove extra AGI256 picture render
ce2410f7a3 AGI: Update Apple IIgs opcodes


Commit: 7c46ab8ce86e367f285a3bbbb6164cd4015e7fea
    https://github.com/scummvm/scummvm/commit/7c46ab8ce86e367f285a3bbbb6164cd4015e7fea
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-10-28T21:02:51-07:00

Commit Message:
AGI: Cleanup GfxMgr, PictureMgr

Changed paths:
    engines/agi/graphics.cpp
    engines/agi/graphics.h
    engines/agi/picture.cpp
    engines/agi/picture.h
    engines/agi/preagi/mickey.cpp
    engines/agi/preagi/winnie.cpp
    engines/agi/sound_coco3.cpp


diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index e8c457b9aa1..1bb1d202320 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -235,14 +235,15 @@ void GfxMgr::setRenderStartOffset(uint16 offsetY) {
 	_renderStartVisualOffsetY = offsetY;
 	_renderStartDisplayOffsetY = offsetY * (1 + _displayHeightMulAdjust);
 }
-uint16 GfxMgr::getRenderStartDisplayOffsetY() {
+
+uint16 GfxMgr::getRenderStartDisplayOffsetY() const {
 	return _renderStartDisplayOffsetY;
 }
 
 // Translates a game screen coordinate to a display screen coordinate
 // Game screen to 320x200 -> x * 2, y + renderStart
 // Game screen to 640x400 -> x * 4, (y * 2) + renderStart
-void GfxMgr::translateGamePosToDisplayScreen(int16 &x, int16 &y) {
+void GfxMgr::translateGamePosToDisplayScreen(int16 &x, int16 &y) const {
 	x = x * (2 + _displayWidthMulAdjust);
 	y = y * (1 + _displayHeightMulAdjust) + _renderStartDisplayOffsetY;
 }
@@ -250,7 +251,7 @@ void GfxMgr::translateGamePosToDisplayScreen(int16 &x, int16 &y) {
 // Translates a visual coordinate to a display screen coordinate
 // Visual to 320x200 -> x * 2, y
 // Visual to 640x400 -> x * 4, y * 2
-void GfxMgr::translateVisualPosToDisplayScreen(int16 &x, int16 &y) {
+void GfxMgr::translateVisualPosToDisplayScreen(int16 &x, int16 &y) const {
 	x = x * (2 + _displayWidthMulAdjust);
 	y = y * (1 + _displayHeightMulAdjust);
 }
@@ -258,7 +259,7 @@ void GfxMgr::translateVisualPosToDisplayScreen(int16 &x, int16 &y) {
 // Translates a display screen coordinate to a game screen coordinate
 // Display screen to 320x200 -> x / 2, y - renderStart
 // Display screen to 640x400 -> x / 4, (y / 2) - renderStart
-void GfxMgr::translateDisplayPosToGameScreen(int16 &x, int16 &y) {
+void GfxMgr::translateDisplayPosToGameScreen(int16 &x, int16 &y) const {
 	y -= _renderStartDisplayOffsetY; // remove status bar line
 	x = x / (2 + _displayWidthMulAdjust);
 	y = y / (1 + _displayHeightMulAdjust);
@@ -269,35 +270,35 @@ void GfxMgr::translateDisplayPosToGameScreen(int16 &x, int16 &y) {
 }
 
 // Translates dimension from visual screen to display screen
-void GfxMgr::translateVisualDimensionToDisplayScreen(int16 &width, int16 &height) {
+void GfxMgr::translateVisualDimensionToDisplayScreen(int16 &width, int16 &height) const {
 	width = width * (2 + _displayWidthMulAdjust);
 	height = height * (1 + _displayHeightMulAdjust);
 }
 
 // Translates dimension from display screen to visual screen
-void GfxMgr::translateDisplayDimensionToVisualScreen(int16 &width, int16 &height) {
+void GfxMgr::translateDisplayDimensionToVisualScreen(int16 &width, int16 &height) const {
 	width = width / (2 + _displayWidthMulAdjust);
 	height = height / (1 + _displayHeightMulAdjust);
 }
 
 // Translates a rect from game screen to display screen
-void GfxMgr::translateGameRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) {
+void GfxMgr::translateGameRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) const {
 	translateGamePosToDisplayScreen(x, y);
 	translateVisualDimensionToDisplayScreen(width, height);
 }
 
 // Translates a rect from visual screen to display screen
-void GfxMgr::translateVisualRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) {
+void GfxMgr::translateVisualRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) const {
 	translateVisualPosToDisplayScreen(x, y);
 	translateVisualDimensionToDisplayScreen(width, height);
 }
 
-uint32 GfxMgr::getDisplayOffsetToGameScreenPos(int16 x, int16 y) {
+uint32 GfxMgr::getDisplayOffsetToGameScreenPos(int16 x, int16 y) const {
 	translateGamePosToDisplayScreen(x, y);
 	return (y * _displayScreenWidth) + x;
 }
 
-uint32 GfxMgr::getDisplayOffsetToVisualScreenPos(int16 x, int16 y) {
+uint32 GfxMgr::getDisplayOffsetToVisualScreenPos(int16 x, int16 y) const {
 	translateVisualPosToDisplayScreen(x, y);
 	return (y * _displayScreenWidth) + x;
 }
@@ -313,6 +314,7 @@ void GfxMgr::copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height
 
 	_vm->_system->copyRectToScreen(_displayScreen + y * _displayScreenWidth + x, _displayScreenWidth, x, y, width, height);
 }
+
 void GfxMgr::copyDisplayRectToScreen(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight) {
 	switch (_upscaledHires) {
 	case DISPLAY_UPSCALED_DISABLED:
@@ -329,35 +331,42 @@ void GfxMgr::copyDisplayRectToScreen(int16 x, int16 adjX, int16 y, int16 adjY, i
 	width += adjWidth; height += adjHeight;
 	_vm->_system->copyRectToScreen(_displayScreen + y * _displayScreenWidth + x, _displayScreenWidth, x, y, width, height);
 }
+
 void GfxMgr::copyDisplayRectToScreenUsingGamePos(int16 x, int16 y, int16 width, int16 height) {
 	translateGameRectToDisplayScreen(x, y, width, height);
 	_vm->_system->copyRectToScreen(_displayScreen + (y * _displayScreenWidth) + x, _displayScreenWidth, x, y, width, height);
 }
+
 void GfxMgr::copyDisplayRectToScreenUsingVisualPos(int16 x, int16 y, int16 width, int16 height) {
 	translateVisualRectToDisplayScreen(x, y, width, height);
 	_vm->_system->copyRectToScreen(_displayScreen + (y * _displayScreenWidth) + x, _displayScreenWidth, x, y, width, height);
 }
+
 void GfxMgr::copyDisplayToScreen() {
 	_vm->_system->copyRectToScreen(_displayScreen, _displayScreenWidth, 0, 0, _displayScreenWidth, _displayScreenHeight);
 }
 
-void GfxMgr::translateFontPosToDisplayScreen(int16 &x, int16 &y) {
+void GfxMgr::translateFontPosToDisplayScreen(int16 &x, int16 &y) const {
 	x *= _displayFontWidth;
 	y *= _displayFontHeight;
 }
-void GfxMgr::translateDisplayPosToFontScreen(int16 &x, int16 &y) {
+
+void GfxMgr::translateDisplayPosToFontScreen(int16 &x, int16 &y) const {
 	x /= _displayFontWidth;
 	y /= _displayFontHeight;
 }
-void GfxMgr::translateFontDimensionToDisplayScreen(int16 &width, int16 &height) {
+
+void GfxMgr::translateFontDimensionToDisplayScreen(int16 &width, int16 &height) const {
 	width *= _displayFontWidth;
 	height *= _displayFontHeight;
 }
-void GfxMgr::translateFontRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) {
+
+void GfxMgr::translateFontRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) const {
 	translateFontPosToDisplayScreen(x, y);
 	translateFontDimensionToDisplayScreen(width, height);
 }
-Common::Rect GfxMgr::getFontRectForDisplayScreen(int16 column, int16 row, int16 width, int16 height) {
+
+Common::Rect GfxMgr::getFontRectForDisplayScreen(int16 column, int16 row, int16 width, int16 height) const {
 	Common::Rect displayRect(width * _displayFontWidth, height * _displayFontHeight);
 	displayRect.moveTo(column * _displayFontWidth, row * _displayFontHeight);
 	return displayRect;
@@ -378,11 +387,17 @@ void GfxMgr::debugShowMap(int mapNr) {
 	render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT);
 }
 
+/**
+ * Clears the game and priority screens
+ */
 void GfxMgr::clear(byte color, byte priority) {
 	memset(_gameScreen, color, _pixels);
 	memset(_priorityScreen, priority, _pixels);
 }
 
+/**
+ * Clears the display screen and copies it to screen
+ */
 void GfxMgr::clearDisplay(byte color, bool copyToScreen) {
 	memset(_displayScreen, color, _displayPixels);
 
@@ -391,6 +406,9 @@ void GfxMgr::clearDisplay(byte color, bool copyToScreen) {
 	}
 }
 
+/**
+ * Puts a pixel on the game and/or priority screens
+ */
 void GfxMgr::putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority) {
 	int offset = y * SCRIPT_WIDTH + x;
 
@@ -402,6 +420,10 @@ void GfxMgr::putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority
 	}
 }
 
+/**
+ * Puts a pixel on the display screen.
+ * If upscaling is enabled then the pixel and coordinates are upscaled.
+ */
 void GfxMgr::putPixelOnDisplay(int16 x, int16 y, byte color) {
 	uint32 offset = 0;
 
@@ -424,6 +446,10 @@ void GfxMgr::putPixelOnDisplay(int16 x, int16 y, byte color) {
 	}
 }
 
+/**
+ * Puts a pixel on the display screen.
+ * If upscaling is enabled then the pixel and coordinates are upscaled.
+ */
 void GfxMgr::putPixelOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, byte color) {
 	switch (_upscaledHires) {
 	case DISPLAY_UPSCALED_DISABLED:
@@ -440,6 +466,11 @@ void GfxMgr::putPixelOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, byte co
 	putPixelOnDisplay(x, y, color);
 }
 
+/**
+ * Puts a font pixel on the display screen.
+ * If upscaling is enabled then isHires determines if the pixel and coordinates
+ * are to be used as is or upscaled.
+ */
 void GfxMgr::putFontPixelOnDisplay(int16 baseX, int16 baseY, int16 addX, int16 addY, byte color, bool isHires) {
 	uint32 offset = 0;
 
@@ -465,13 +496,19 @@ void GfxMgr::putFontPixelOnDisplay(int16 baseX, int16 baseY, int16 addX, int16 a
 	}
 }
 
-byte GfxMgr::getColor(int16 x, int16 y) {
+/**
+ * Returns a color from the game screen
+ */
+byte GfxMgr::getColor(int16 x, int16 y) const {
 	int offset = y * SCRIPT_WIDTH + x;
 
 	return _gameScreen[offset];
 }
 
-byte GfxMgr::getPriority(int16 x, int16 y) {
+/**
+ * Returns a priority from the priority screen
+ */
+byte GfxMgr::getPriority(int16 x, int16 y) const {
 	int offset = y * SCRIPT_WIDTH + x;
 
 	return _priorityScreen[offset];
@@ -479,7 +516,7 @@ byte GfxMgr::getPriority(int16 x, int16 y) {
 
 // used, when a control pixel is found
 // will search downwards and compare priority in case any is found
-bool GfxMgr::checkControlPixel(int16 x, int16 y, byte viewPriority) {
+bool GfxMgr::checkControlPixel(int16 x, int16 y, byte viewPriority) const {
 	int offset = y * SCRIPT_WIDTH + x;
 	byte curPriority;
 
@@ -499,19 +536,23 @@ bool GfxMgr::checkControlPixel(int16 x, int16 y, byte viewPriority) {
 	return false; // view priority is lower, don't draw
 }
 
-static byte CGA_MixtureColorTable[] = {
+static const byte CGA_MixtureColorTable[] = {
 	0x00, 0x08, 0x04, 0x0C, 0x01, 0x09, 0x02, 0x05,
 	0x0A, 0x0D, 0x06, 0x0E, 0x0B, 0x03, 0x07, 0x0F
 };
 
-byte GfxMgr::getCGAMixtureColor(byte color) {
+byte GfxMgr::getCGAMixtureColor(byte color) const {
 	return CGA_MixtureColorTable[color & 0x0F];
 }
 
+/**
+ * Renders a block of the game screen on to the display screen.
+ * Optionally copies the display block to screen immediately.
+ */
 // Attention: in our implementation, y-coordinate is upper left.
 // Sierra passed the lower left instead. We changed it to make upscaling easier.
 void GfxMgr::render_Block(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
-	if (!render_Clip(x, y, width, height)) {
+	if (!render_Clip(x, y, width, height, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT)) {
 		warning("render_Block ignored by clipping. x: %d, y: %d, w: %d, h: %d", x, y, width, height);
 		return;
 	}
@@ -912,8 +953,11 @@ void GfxMgr::transition_AtariSt() {
 	_vm->_system->updateScreen();
 }
 
+/**
+ * Copies a block of the game and priority screens to a buffer
+ */
 // Attention: y coordinate is here supposed to be the upper one!
-void GfxMgr::block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr) {
+void GfxMgr::block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr) const {
 	int16 startOffset = y * SCRIPT_WIDTH + x;
 	int16 offset = startOffset;
 	int16 remainingHeight = height;
@@ -938,6 +982,9 @@ void GfxMgr::block_save(int16 x, int16 y, int16 width, int16 height, byte *buffe
 	}
 }
 
+/**
+ * Copies a buffer filled by block_save back to the game and priority screens
+ */
 // Attention: y coordinate is here supposed to be the upper one!
 void GfxMgr::block_restore(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr) {
 	int16 startOffset = y * SCRIPT_WIDTH + x;
@@ -964,18 +1011,23 @@ void GfxMgr::block_restore(int16 x, int16 y, int16 width, int16 height, byte *bu
 	}
 }
 
-// coordinates are for visual screen, but are supposed to point somewhere inside the playscreen
-// x, y is the upper left. Sierra passed them as lower left. We change that to make upscaling easier.
-// attention: Clipping is done here against 160x200 instead of 160x168
-//            Original interpreter didn't do any clipping, we do it for security.
-//            Clipping against the regular script width/height must not be done,
-//            because at least during the intro one message box goes beyond playscreen
-//            Going beyond 160x168 will result in messageboxes not getting fully removed
-//            In KQ4's case, the scripts clear the screen that's why it works.
+/**
+ * Draw a box with a border on the display screen.
+ * Currently only used when drawing a message box or an expanded menu.
+ * Coordinates are for the visual screen instead of the game screen, because
+ * while boxes are generally within the game area, there are exceptions:
+ * - KQ4 intro displays a message box that extends below the game area.
+ *   This would normally result in the message box not being fully removed,
+ *   but the script clears the screen afterwards so it works.
+ * - MMMG nursery rhyme message boxes appear over the menu bar.
+ *   The scripts pass a y-coordinate of zero to print.at(). Bug #13820
+ * The original interpreter didn't do any clipping; we clip against the visual
+ * screen to prevent out of bounds writes while allowing boxes to be drawn outside
+ * of the game area. The visual screen is 160x200 normally, 140x192 for Apple II.
+ * The x, y parameters are the upper left of the box in our implementation.
+ * Sierra passed the lower left. We change that to make upscaling easier.
+ */
 void GfxMgr::drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroundColor, byte lineColor) {
-	// Allow rendering all the way to the top of the visual screen, even if there
-	// is a menu bar. MMMG nursery rhyme message boxes appear over the menu bar
-	// when the scripts pass a y-coordinate of zero to print.at(). Bug #13820
 	const int16 minY = 0 - _renderStartDisplayOffsetY;
 	if (!render_Clip(x, y, width, height, minY, VISUAL_WIDTH, VISUAL_HEIGHT - _renderStartVisualOffsetY)) {
 		warning("drawBox ignored by clipping. x: %d, y: %d, w: %d, h: %d", x, y, width, height);
@@ -1024,7 +1076,9 @@ void GfxMgr::drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroun
 	}
 }
 
-// coordinates are directly for display screen
+/**
+ * Draw a rectangle to the display screen
+ */
 void GfxMgr::drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte color, bool copyToScreen) {
 	switch (_vm->_renderMode) {
 	case Common::kRenderCGA:
@@ -1100,7 +1154,9 @@ void GfxMgr::drawDisplayRectCGA(int16 x, int16 y, int16 width, int16 height, byt
 	}
 }
 
-// row + column are text-coordinates
+/**
+ * Draw a character to the display screen using text row and column coordinates
+ */
 void GfxMgr::drawCharacter(int16 row, int16 column, byte character, byte foreground, byte background, bool disabledLook) {
 	int16 x = column;
 	int16 y = row;
@@ -1124,7 +1180,10 @@ void GfxMgr::drawCharacter(int16 row, int16 column, byte character, byte foregro
 	drawCharacterOnDisplay(x, y, character, foreground, background, transformXOR, transformOR);
 }
 
-// only meant for internal use (SystemUI)
+/**
+ * Draw a string to the display screen using display coordinates.
+ * For internal use by SystemUI.
+ */
 void GfxMgr::drawStringOnDisplay(int16 x, int16 y, const char *text, byte foregroundColor, byte backgroundColor) {
 	while (*text) {
 		drawCharacterOnDisplay(x, y, *text, foregroundColor, backgroundColor);
@@ -1133,6 +1192,10 @@ void GfxMgr::drawStringOnDisplay(int16 x, int16 y, const char *text, byte foregr
 	}
 }
 
+/**
+ * Draw a string to the display screen using display coordinates.
+ * For internal use by SystemUI.
+ */
 void GfxMgr::drawStringOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, const char *text, byte foregroundColor, byte backgroundColor) {
 	switch (_upscaledHires) {
 	case DISPLAY_UPSCALED_DISABLED:
@@ -1150,6 +1213,9 @@ void GfxMgr::drawStringOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, const
 	drawStringOnDisplay(x, y, text, foregroundColor, backgroundColor);
 }
 
+/**
+ * Draw a character to the display screen using text row and column coordinates
+ */
 void GfxMgr::drawCharacterOnDisplay(int16 x, int16 y, const byte character, byte foreground, byte background, byte transformXOR, byte transformOR) {
 	int16       curX, curY;
 	const byte *fontData;
@@ -1249,11 +1315,12 @@ void GfxMgr::setPriorityTable(int16 priorityBase) {
 }
 
 // used for saving
-int16 GfxMgr::saveLoadGetPriority(int16 yPos) {
+int16 GfxMgr::saveLoadGetPriority(int16 yPos) const {
 	assert(yPos < SCRIPT_HEIGHT);
 	return _priorityTable[yPos];
 }
-bool GfxMgr::saveLoadWasPriorityTableModified() {
+
+bool GfxMgr::saveLoadWasPriorityTableModified() const {
 	return _priorityTableSet;
 }
 
@@ -1262,9 +1329,11 @@ void GfxMgr::saveLoadSetPriority(int16 yPos, int16 priority) {
 	assert(yPos < SCRIPT_HEIGHT);
 	_priorityTable[yPos] = priority;
 }
+
 void GfxMgr::saveLoadSetPriorityTableModifiedBool(bool wasModified) {
 	_priorityTableSet = wasModified;
 }
+
 void GfxMgr::saveLoadFigureOutPriorityTableModifiedBool() {
 	uint8 defaultPriorityTable[SCRIPT_HEIGHT]; /**< priority table */
 
@@ -1281,7 +1350,7 @@ void GfxMgr::saveLoadFigureOutPriorityTableModifiedBool() {
 /**
  * Convert sprite priority to y value.
  */
-int16 GfxMgr::priorityToY(int16 priority) {
+int16 GfxMgr::priorityToY(int16 priority) const {
 	if (!_priorityTableSet) {
 		// priority table wasn't set by scripts? calculate directly
 		return (priority - 5) * 12 + 48;
@@ -1317,7 +1386,7 @@ int16 GfxMgr::priorityToY(int16 priority) {
 	return currentY;
 }
 
-int16 GfxMgr::priorityFromY(int16 yPos) {
+int16 GfxMgr::priorityFromY(int16 yPos) const {
 	assert(yPos < SCRIPT_HEIGHT);
 	return _priorityTable[yPos];
 }
@@ -1417,7 +1486,7 @@ void GfxMgr::setAGIPal(int p0) {
 	debug(1, "Using AGIPAL palette from '%s'", filename);
 }
 
-int GfxMgr::getAGIPalFileNum() {
+int GfxMgr::getAGIPalFileNum() const {
 	return _agipalFileNum;
 }
 
diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h
index 9ef4e438750..320019fa50c 100644
--- a/engines/agi/graphics.h
+++ b/engines/agi/graphics.h
@@ -71,30 +71,30 @@ public:
 
 	void initVideo();
 	void deinitVideo();
-	void initPalette(uint8 *destPalette, const uint8 *paletteData, uint colorCount = 16, uint fromBits = 6, uint toBits = 8);
-	void initPaletteCLUT(uint8 *destPalette, const uint16 *paletteCLUTData, uint colorCount = 16);
+	static void initPalette(uint8 *destPalette, const uint8 *paletteData, uint colorCount = 16, uint fromBits = 6, uint toBits = 8);
+	static void initPaletteCLUT(uint8 *destPalette, const uint16 *paletteCLUTData, uint colorCount = 16);
 	void setAGIPal(int);
-	int getAGIPalFileNum();
+	int getAGIPalFileNum() const;
 	void setPalette(bool GfxModePalette);
 
 	void initMouseCursor(MouseCursorData *mouseCursor, const byte *bitmapData, uint16 width, uint16 height, int hotspotX, int hotspotY);
 	void setMouseCursor(bool busy = false);
 
 	void setRenderStartOffset(uint16 offsetY);
-	uint16 getRenderStartDisplayOffsetY();
+	uint16 getRenderStartDisplayOffsetY() const;
 
-	void translateGamePosToDisplayScreen(int16 &x, int16 &y);
-	void translateVisualPosToDisplayScreen(int16 &x, int16 &y);
-	void translateDisplayPosToGameScreen(int16 &x, int16 &y);
+	void translateGamePosToDisplayScreen(int16 &x, int16 &y) const;
+	void translateVisualPosToDisplayScreen(int16 &x, int16 &y) const;
+	void translateDisplayPosToGameScreen(int16 &x, int16 &y) const;
 
-	void translateVisualDimensionToDisplayScreen(int16 &width, int16 &height);
-	void translateDisplayDimensionToVisualScreen(int16 &width, int16 &height);
+	void translateVisualDimensionToDisplayScreen(int16 &width, int16 &height) const;
+	void translateDisplayDimensionToVisualScreen(int16 &width, int16 &height) const;
 
-	void translateGameRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height);
-	void translateVisualRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height);
+	void translateGameRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) const;
+	void translateVisualRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) const;
 
-	uint32 getDisplayOffsetToGameScreenPos(int16 x, int16 y);
-	uint32 getDisplayOffsetToVisualScreenPos(int16 x, int16 y);
+	uint32 getDisplayOffsetToGameScreenPos(int16 x, int16 y) const;
+	uint32 getDisplayOffsetToVisualScreenPos(int16 x, int16 y) const;
 
 	void copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height);
 	void copyDisplayRectToScreen(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight);
@@ -102,11 +102,11 @@ public:
 	void copyDisplayRectToScreenUsingVisualPos(int16 x, int16 y, int16 width, int16 height);
 	void copyDisplayToScreen();
 
-	void translateFontPosToDisplayScreen(int16 &x, int16 &y);
-	void translateDisplayPosToFontScreen(int16 &x, int16 &y);
-	void translateFontDimensionToDisplayScreen(int16 &width, int16 &height);
-	void translateFontRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height);
-	Common::Rect getFontRectForDisplayScreen(int16 column, int16 row, int16 width, int16 height);
+	void translateFontPosToDisplayScreen(int16 &x, int16 &y) const;
+	void translateDisplayPosToFontScreen(int16 &x, int16 &y) const;
+	void translateFontDimensionToDisplayScreen(int16 &width, int16 &height) const;
+	void translateFontRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) const;
+	Common::Rect getFontRectForDisplayScreen(int16 column, int16 row, int16 width, int16 height) const;
 
 private:
 	uint _pixels;
@@ -143,17 +143,17 @@ private:
 	uint16 _renderStartDisplayOffsetY;
 
 public:
-	uint16 getDisplayScreenWidth() {
+	uint16 getDisplayScreenWidth() const {
 		return _displayScreenWidth;
 	}
-	uint16 getDisplayFontWidth() {
+	uint16 getDisplayFontWidth() const {
 		return _displayFontWidth;
 	}
-	uint16 getDisplayFontHeight() {
+	uint16 getDisplayFontHeight() const {
 		return _displayFontHeight;
 	}
 
-	GfxScreenUpscaledMode getUpscaledHires() {
+	GfxScreenUpscaledMode getUpscaledHires() const {
 		return _upscaledHires;
 	}
 
@@ -166,16 +166,16 @@ public:
 	void putPixelOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, byte color);
 	void putFontPixelOnDisplay(int16 baseX, int16 baseY, int16 addX, int16 addY, byte color, bool isHires);
 
-	byte getColor(int16 x, int16 y);
-	byte getPriority(int16 x, int16 y);
-	bool checkControlPixel(int16 x, int16 y, byte newPriority);
+	byte getColor(int16 x, int16 y) const;
+	byte getPriority(int16 x, int16 y) const;
+	bool checkControlPixel(int16 x, int16 y, byte newPriority) const;
 
-	byte getCGAMixtureColor(byte color);
+	byte getCGAMixtureColor(byte color) const;
 
 	void render_Block(int16 x, int16 y, int16 width, int16 height, bool copyToScreen = true);
-	bool render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, const int16 minY = 0, const int16 clipAgainstWidth = SCRIPT_WIDTH, const int16 clipAgainstHeight = SCRIPT_HEIGHT);
 
 private:
+	static bool render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, const int16 minY, const int16 clipAgainstWidth, const int16 clipAgainstHeight);
 	void render_BlockEGA(int16 x, int16 y, int16 width, int16 height);
 	void render_BlockCGA(int16 x, int16 y, int16 width, int16 height);
 	void render_BlockHercules(int16 x, int16 y, int16 width, int16 height);
@@ -184,7 +184,7 @@ public:
 	void transition_Amiga();
 	void transition_AtariSt();
 
-	void block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr);
+	void block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr) const;
 	void block_restore(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr);
 
 	void drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroundColor, byte lineColor);
@@ -204,16 +204,16 @@ public:
 	void updateScreen();
 
 	void initPriorityTable();
-	void createDefaultPriorityTable(uint8 *priorityTable);
+	static void createDefaultPriorityTable(uint8 *priorityTable);
 	void setPriorityTable(int16 priorityBase);
-	bool saveLoadWasPriorityTableModified();
-	int16 saveLoadGetPriority(int16 yPos);
+	bool saveLoadWasPriorityTableModified() const;
+	int16 saveLoadGetPriority(int16 yPos) const;
 	void saveLoadSetPriorityTableModifiedBool(bool wasModified);
 	void saveLoadSetPriority(int16 yPos, int16 priority);
 	void saveLoadFigureOutPriorityTableModifiedBool();
 
-	int16 priorityToY(int16 priority);
-	int16 priorityFromY(int16 yPos);
+	int16 priorityToY(int16 priority) const;
+	int16 priorityFromY(int16 yPos) const;
 };
 
 } // End of namespace Agi
diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index a42e4d5afd5..d226c52a790 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -36,15 +36,23 @@ PictureMgr::PictureMgr(AgiBase *agi, GfxMgr *gfx) {
 	_dataOffset = 0;
 	_dataOffsetNibble = false;
 
-	_patCode = _patNum = _priOn = _scrOn = _scrColor = _priColor = 0;
-	_xOffset = _yOffset = 0;
+	_patCode = 0;
+	_patNum = 0;
+	_priOn = 0;
+	_scrOn = 0;
+	_scrColor = 0;
+	_priColor = 0;
 
-	_pictureVersion = AGIPIC_V2;
 	_minCommand = 0xf0;
+
+	_pictureVersion = AGIPIC_V2;
+	_width = 0;
+	_height = 0;
+	_xOffset = 0;
+	_yOffset = 0;
+
 	_flags = 0;
 	_currentStep = 0;
-
-	_width = _height = 0;
 }
 
 void PictureMgr::putVirtPixel(int x, int y) {
@@ -98,7 +106,7 @@ byte PictureMgr::getNextNibble() {
 **
 ** Draws an xCorner  (drawing action 0xF5)
 **************************************************************************/
-void PictureMgr::draw_xCorner(bool skipOtherCoords) {
+void PictureMgr::xCorner(bool skipOtherCoords) {
 	byte x1, x2, y1, y2, dummy;
 
 	if (!(getNextParamByte(x1) && getNextParamByte(y1)))
@@ -342,14 +350,12 @@ void PictureMgr::drawPicture() {
 }
 
 void PictureMgr::drawPictureC64() {
-	byte curByte;
-
 	debugC(8, kDebugLevelMain, "Drawing C64 picture");
 
 	_scrColor = 0x0;
 
 	while (_dataOffset < _dataSize) {
-		curByte = getNextByte();
+		byte curByte = getNextByte();
 
 		if ((curByte >= 0xF0) && (curByte <= 0xFE)) {
 			_scrColor = curByte & 0x0F;
@@ -358,7 +364,7 @@ void PictureMgr::drawPictureC64() {
 
 		switch (curByte) {
 		case 0xe0:  // x-corner
-			draw_xCorner();
+			xCorner();
 			break;
 		case 0xe1:  // y-corner
 			yCorner();
@@ -391,12 +397,10 @@ void PictureMgr::drawPictureC64() {
 }
 
 void PictureMgr::drawPictureV1() {
-	byte curByte;
-
 	debugC(8, kDebugLevelMain, "Drawing V1 picture");
 
 	while (_dataOffset < _dataSize) {
-		curByte = getNextByte();
+		byte curByte = getNextByte();
 
 		switch (curByte) {
 		case 0xf1:
@@ -430,12 +434,10 @@ void PictureMgr::drawPictureV1() {
 }
 
 void PictureMgr::drawPictureV15() {
-	byte curByte;
-
 	debugC(8, kDebugLevelMain, "Drawing V1.5 picture");
 
 	while (_dataOffset < _dataSize) {
-		curByte = getNextByte();
+		byte curByte = getNextByte();
 
 		switch (curByte) {
 		case 0xf0:
@@ -454,7 +456,7 @@ void PictureMgr::drawPictureV15() {
 			yCorner(true);
 			break;
 		case 0xf9:
-			draw_xCorner(true);
+			xCorner(true);
 			break;
 		case 0xfa:
 			// TODO: is this really correct?
@@ -479,7 +481,6 @@ void PictureMgr::drawPictureV15() {
 }
 
 void PictureMgr::drawPictureV2() {
-	byte curByte;
 	bool nibbleMode = false;
 	bool mickeyCrystalAnimation = false;
 	int  mickeyIteration = 0;
@@ -496,7 +497,7 @@ void PictureMgr::drawPictureV2() {
 	}
 
 	while (_dataOffset < _dataSize) {
-		curByte = getNextByte();
+		byte curByte = getNextByte();
 
 		switch (curByte) {
 		case 0xf0:
@@ -525,7 +526,7 @@ void PictureMgr::drawPictureV2() {
 			yCorner();
 			break;
 		case 0xf5:
-			draw_xCorner();
+			xCorner();
 			break;
 		case 0xf6:
 			draw_LineAbsolute();
@@ -562,8 +563,8 @@ void PictureMgr::drawPictureV2() {
 		// One frame of the crystal animation is shown on each iteration, based on _currentStep
 		if (mickeyCrystalAnimation) {
 			if (_currentStep == mickeyIteration) {
-				int storedXOffset = _xOffset;
-				int storedYOffset = _yOffset;
+				int16 storedXOffset = _xOffset;
+				int16 storedYOffset = _yOffset;
 				// Note that picture coordinates are correct for Mickey only
 				showPic(10, 0, _width, _height);
 				_xOffset = storedXOffset;
@@ -586,12 +587,11 @@ void PictureMgr::drawPictureAGI256() {
 	int16 y = 0;
 	byte *dataPtr = _data;
 	byte *dataEndPtr = _data + _dataSize;
-	byte color = 0;
 
 	debugC(8, kDebugLevelMain, "Drawing AGI256 picture");
 
 	while (dataPtr < dataEndPtr) {
-		color = *dataPtr++;
+		byte color = *dataPtr++;
 		_gfx->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0);
 
 		x++;
@@ -625,12 +625,8 @@ void PictureMgr::draw_SetColor() {
 		return;
 
 	// For CGA, replace the color with its mixture color
-	switch (_vm->_renderMode) {
-	case Common::kRenderCGA:
+	if (_vm->_renderMode == Common::kRenderCGA) {
 		_scrColor = _gfx->getCGAMixtureColor(_scrColor);
-		break;
-	default:
-		break;
 	}
 }
 
@@ -644,12 +640,8 @@ void PictureMgr::draw_SetNibbleColor() {
 	_scrColor = getNextNibble();
 
 	// For CGA, replace the color with its mixture color
-	switch (_vm->_renderMode) {
-	case Common::kRenderCGA:
+	if (_vm->_renderMode == Common::kRenderCGA) {
 		_scrColor = _gfx->getCGAMixtureColor(_scrColor);
-		break;
-	default:
-		break;
 	}
 }
 
@@ -672,8 +664,6 @@ void PictureMgr::draw_Line(int16 x1, int16 y1, int16 x2, int16 y2) {
 	y1 = CLIP<int16>(y1, 0, _height - 1);
 	y2 = CLIP<int16>(y2, 0, _height - 1);
 
-	int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta;
-
 	// Vertical line
 
 	if (x1 == x2) {
@@ -698,23 +688,21 @@ void PictureMgr::draw_Line(int16 x1, int16 y1, int16 x2, int16 y2) {
 		return;
 	}
 
-	y = y1;
-	x = x1;
+	int stepX = 1;
+	int deltaX = x2 - x1;
+	if (deltaX < 0) {
+		stepX = -1;
+		deltaX = -deltaX;
+	}
 
-	stepY = 1;
-	deltaY = y2 - y1;
+	int stepY = 1;
+	int deltaY = y2 - y1;
 	if (deltaY < 0) {
 		stepY = -1;
 		deltaY = -deltaY;
 	}
 
-	stepX = 1;
-	deltaX = x2 - x1;
-	if (deltaX < 0) {
-		stepX = -1;
-		deltaX = -deltaX;
-	}
-
+	int i, detdelta, errorX, errorY;
 	if (deltaY > deltaX) {
 		i = deltaY;
 		detdelta = deltaY;
@@ -727,6 +715,8 @@ void PictureMgr::draw_Line(int16 x1, int16 y1, int16 x2, int16 y2) {
 		errorY = deltaX / 2;
 	}
 
+	int x = x1;
+	int y = y1;
 	putVirtPixel(x, y);
 
 	do {
@@ -819,17 +809,17 @@ void PictureMgr::draw_Fill(int16 x, int16 y) {
 	// Exit if stack is empty
 	while (!stack.empty()) {
 		Common::Point p = stack.pop();
-		unsigned int c;
-		bool newspanUp, newspanDown;
 
 		if (!draw_FillCheck(p.x, p.y))
 			continue;
 
 		// Scan for left border
+		uint c;
 		for (c = p.x - 1; draw_FillCheck(c, p.y); c--)
 			;
 
-		newspanUp = newspanDown = true;
+		bool newspanUp = true;
+		bool newspanDown = true;
 		for (c++; draw_FillCheck(c, p.y); c++) {
 			putVirtPixel(c, p.y);
 			if (draw_FillCheck(c, p.y - 1)) {
@@ -853,18 +843,15 @@ void PictureMgr::draw_Fill(int16 x, int16 y) {
 	}
 }
 
-int PictureMgr::draw_FillCheck(int16 x, int16 y) {
-	byte screenColor;
-	byte screenPriority;
-
+bool PictureMgr::draw_FillCheck(int16 x, int16 y) {
 	if (x < 0 || x >= _width || y < 0 || y >= _height)
 		return false;
 
 	x += _xOffset;
 	y += _yOffset;
 
-	screenColor = _gfx->getColor(x, y);
-	screenPriority = _gfx->getPriority(x, y);
+	byte screenColor = _gfx->getColor(x, y);
+	byte screenPriority = _gfx->getPriority(x, y);
 
 	if (_flags & kPicFTrollMode)
 		return ((screenColor != 11) && (screenColor != _scrColor));
@@ -873,7 +860,7 @@ int PictureMgr::draw_FillCheck(int16 x, int16 y) {
 		return (screenColor == 15);
 
 	if (_priOn && !_scrOn && _priColor != 4)
-		return screenPriority == 4;
+		return (screenPriority == 4);
 
 	return (_scrOn && screenColor == 15 && _scrColor != 15);
 }
@@ -887,9 +874,7 @@ int PictureMgr::draw_FillCheck(int16 x, int16 y) {
  * @param clear  clear AGI screen before drawing
  * @param agi256 load an AGI256 picture resource
  */
-int PictureMgr::decodePicture(int16 resourceNr, bool clearScreen, bool agi256, int16 pic_width, int16 pic_height) {
-	debugC(8, kDebugLevelResources, "(%d)", resourceNr);
-
+void PictureMgr::decodePicture(int16 resourceNr, bool clearScreen, bool agi256, int16 width, int16 height) {
 	_patCode = 0;
 	_patNum = 0;
 	_priOn = _scrOn = false;
@@ -902,8 +887,8 @@ int PictureMgr::decodePicture(int16 resourceNr, bool clearScreen, bool agi256, i
 	_dataOffset = 0;
 	_dataOffsetNibble = false;
 
-	_width = pic_width;
-	_height = pic_height;
+	_width = width;
+	_height = height;
 
 	if (clearScreen && !agi256) { // 256 color pictures should always fill the whole screen, so no clearing for them.
 		_gfx->clear(15, 4); // Clear 16 color AGI screen (Priority 4, color white).
@@ -915,11 +900,10 @@ int PictureMgr::decodePicture(int16 resourceNr, bool clearScreen, bool agi256, i
 		drawPictureAGI256();
 	}
 
-	if (clearScreen)
+	if (clearScreen) {
 		_vm->clearImageStack();
+	}
 	_vm->recordImageStackCall(ADD_PIC, resourceNr, clearScreen, agi256, 0, 0, 0, 0);
-
-	return errOK;
 }
 
 /**
@@ -931,7 +915,7 @@ int PictureMgr::decodePicture(int16 resourceNr, bool clearScreen, bool agi256, i
  * @param length the size of the picture data buffer
  * @param clear  clear AGI screen before drawing
  */
-int PictureMgr::decodePicture(byte *data, uint32 length, int clr, int pic_width, int pic_height) {
+void PictureMgr::decodePictureFromBuffer(byte *data, uint32 length, bool clearScreen, int16 width, int16 height) {
 	_patCode = 0;
 	_patNum = 0;
 	_priOn = _scrOn = false;
@@ -943,15 +927,14 @@ int PictureMgr::decodePicture(byte *data, uint32 length, int clr, int pic_width,
 	_dataOffset = 0;
 	_dataOffsetNibble = false;
 
-	_width = pic_width;
-	_height = pic_height;
+	_width = width;
+	_height = height;
 
-	if (clr) // 256 color pictures should always fill the whole screen, so no clearing for them.
+	if (clearScreen) {
 		clear();
+	}
 
 	drawPicture(); // Draw 16 color picture.
-
-	return errOK;
 }
 
 /**
diff --git a/engines/agi/picture.h b/engines/agi/picture.h
index a00016da113..37d19237f8e 100644
--- a/engines/agi/picture.h
+++ b/engines/agi/picture.h
@@ -70,10 +70,10 @@ class PictureMgr {
 public:
 	PictureMgr(AgiBase *agi, GfxMgr *gfx);
 
-	int16 getResourceNr() { return _resourceNr; };
+	int16 getResourceNr() const { return _resourceNr; };
 
 private:
-	void draw_xCorner(bool skipOtherCoords = false);
+	void xCorner(bool skipOtherCoords = false);
 	void yCorner(bool skipOtherCoords = false);
 	void plotBrush();
 
@@ -84,8 +84,8 @@ private:
 public:
 	void putVirtPixel(int x, int y);
 
-	int decodePicture(int16 resourceNr, bool clearScreen, bool agi256 = false, int16 pic_width = _DEFAULT_WIDTH, int16 pic_height = _DEFAULT_HEIGHT);
-	int decodePicture(byte *data, uint32 length, int clear, int pic_width = _DEFAULT_WIDTH, int pic_height = _DEFAULT_HEIGHT);
+	void decodePicture(int16 resourceNr, bool clearScreen, bool agi256 = false, int16 width = _DEFAULT_WIDTH, int16 height = _DEFAULT_HEIGHT);
+	void decodePictureFromBuffer(byte *data, uint32 length, bool clearScreen, int16 width = _DEFAULT_WIDTH, int16 height = _DEFAULT_HEIGHT);
 	void unloadPicture(int picNr);
 	void drawPicture();
 private:
@@ -104,7 +104,7 @@ private:
 	void draw_LineShort();
 	void draw_LineAbsolute();
 
-	int  draw_FillCheck(int16 x, int16 y);
+	bool draw_FillCheck(int16 x, int16 y);
 	void draw_Fill(int16 x, int16 y);
 	void draw_Fill();
 
@@ -151,8 +151,10 @@ private:
 	uint8 _minCommand;
 
 	AgiPictureVersion _pictureVersion;
-	int16 _width, _height;
-	int16 _xOffset, _yOffset;
+	int16 _width;
+	int16 _height;
+	int16 _xOffset;
+	int16 _yOffset;
 
 	int _flags;
 	int _currentStep;
diff --git a/engines/agi/preagi/mickey.cpp b/engines/agi/preagi/mickey.cpp
index 6230ddc893e..49db9570240 100644
--- a/engines/agi/preagi/mickey.cpp
+++ b/engines/agi/preagi/mickey.cpp
@@ -739,7 +739,7 @@ void MickeyEngine::drawObj(ENUM_MSA_OBJECT iObj, int x0, int y0) {
 		_picture->setPictureFlags(kPicFStep);
 
 	_picture->setOffset(x0, y0);
-	_picture->decodePicture(buffer, size, false, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
+	_picture->decodePictureFromBuffer(buffer, size, false, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
 	_picture->setOffset(0, 0);
 	_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
 }
@@ -759,7 +759,7 @@ void MickeyEngine::drawPic(int iPic) {
 
 	// Note that decodePicture clears the screen
 	_picture->setOffset(10, 0);
-	_picture->decodePicture(buffer, size, true, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
+	_picture->decodePictureFromBuffer(buffer, size, true, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
 	_picture->setOffset(0, 0);
 	_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);
 }
diff --git a/engines/agi/preagi/winnie.cpp b/engines/agi/preagi/winnie.cpp
index 0e4103e4175..918896fa130 100644
--- a/engines/agi/preagi/winnie.cpp
+++ b/engines/agi/preagi/winnie.cpp
@@ -1082,7 +1082,7 @@ void WinnieEngine::drawPic(const char *szName) {
 	file.close();
 
 	_picture->setOffset(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0);
-	_picture->decodePicture(buffer, size, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
+	_picture->decodePictureFromBuffer(buffer, size, true, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
 	_picture->setOffset(0, 0);
 	_picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
 
@@ -1099,7 +1099,7 @@ void WinnieEngine::drawObjPic(int iObj, int x0, int y0) {
 	parseObjHeader(&objhdr, buffer, sizeof(WTP_OBJ_HDR));
 
 	_picture->setOffset(x0, y0);
-	_picture->decodePicture(buffer + objhdr.ofsPic - _objOffset, objSize, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
+	_picture->decodePictureFromBuffer(buffer + objhdr.ofsPic - _objOffset, objSize, false, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
 	_picture->setOffset(0, 0);
 	_picture->showPic(10, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
 
@@ -1119,7 +1119,7 @@ void WinnieEngine::drawRoomPic() {
 
 	// draw room picture
 	_picture->setOffset(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0);
-	_picture->decodePicture(buffer + roomhdr.ofsPic - _roomOffset, 4096, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
+	_picture->decodePictureFromBuffer(buffer + roomhdr.ofsPic - _roomOffset, 4096, false, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
 	_picture->setOffset(0, 0);
 	_picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
 
diff --git a/engines/agi/sound_coco3.cpp b/engines/agi/sound_coco3.cpp
index 3fcc1797008..1da61e3929d 100644
--- a/engines/agi/sound_coco3.cpp
+++ b/engines/agi/sound_coco3.cpp
@@ -78,7 +78,7 @@ void SoundGenCoCo3::play(int resnum) {
 	// LSL1 (Int, 2.072) stored the duration in 1/60 of a second.
 	// Fan ports have been made using both interpreters, but our
 	// detection table doesn't capture this. For now, treat KQ3
-	// as the early interpreter all others as the later one.
+	// as the early interpreter and all others as the later one.
 	// TODO: create detection heuristic
 	bool isEarlySound = (_vm->getGameID() == GID_KQ3);
 


Commit: a5909e5f60c0ab87a962e47b1e997ece3ab12bb1
    https://github.com/scummvm/scummvm/commit/a5909e5f60c0ab87a962e47b1e997ece3ab12bb1
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-10-28T21:02:51-07:00

Commit Message:
AGI: Move AGI256 picture opcode into function

Changed paths:
    engines/agi/op_cmd.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h


diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index eb6efdb42fe..47272e4bb19 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -756,7 +756,7 @@ void cmdResetScanStart(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 
 void cmdSaveGame(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	if (vm->getVersion() >= 0x2272) {
-		// this was only donce since 2.272
+		// this was only done since 2.272
 		vm->_sound->stopSound();
 	}
 
@@ -950,56 +950,28 @@ void cmdObjStatusF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 // unk_177: Disable menus completely -- j5
 // unk_181: Deactivate keypressed control (default control of ego)
 void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
-	if (!(vm->getFeatures() & GF_AGI256)) {
-		// set.simple is called by Larry 1 on Apple IIgs at the store, after answering the 555-6969 phone.
-		// load.sound(16) is called right before it. Interpreter is 2.440-like.
-		// it's called with parameter 16.
-		// Original interpreter doesn't seem to play any sound.
-		// TODO: Figure out what's going on. It can't be automatic saving of course.
-		// Also getting called in KQ1, when planting beans - parameter 12.
-		// And when killing the witch - parameter 40.
-		if ((vm->getVersion() < 0x2425) || (vm->getVersion() == 0x2440)) {
-			// was not available before 2.2425, but also not available in 2.440
-			warning("set.simple called, although not available for current AGI version");
-			return;
-		}
-
-		int16 stringNr = parameter[0];
-		state->automaticSave = false;
+	// set.simple is called by Larry 1 on Apple IIgs at the store, after answering the 555-6969 phone.
+	// load.sound(16) is called right before it. Interpreter is 2.440-like.
+	// it's called with parameter 16.
+	// Original interpreter doesn't seem to play any sound.
+	// TODO: Figure out what's going on. It can't be automatic saving of course.
+	// Also getting called in KQ1, when planting beans - parameter 12.
+	// And when killing the witch - parameter 40.
+	if ((vm->getVersion() < 0x2425) || (vm->getVersion() == 0x2440)) {
+		// was not available before 2.2425, but also not available in 2.440
+		warning("set.simple called, although not available for current AGI version");
+		return;
+	}
 
-		// Try to get description for automatic saves
-		const char *textPtr = state->getString(stringNr);
+	int16 stringNr = parameter[0];
 
-		strncpy(state->automaticSaveDescription, textPtr, sizeof(state->automaticSaveDescription));
-		state->automaticSaveDescription[sizeof(state->automaticSaveDescription) - 1] = 0;
+	// Try to get description for automatic saves
+	const char *textPtr = state->getString(stringNr);
+	strncpy(state->automaticSaveDescription, textPtr, sizeof(state->automaticSaveDescription));
+	state->automaticSaveDescription[sizeof(state->automaticSaveDescription) - 1] = '\0';
 
-		if (state->automaticSaveDescription[0]) {
-			// We got it and it's set, so enable automatic saving
-			state->automaticSave = true;
-		}
-	} else { // AGI256 and AGI256-2 use this unknown170 command to load 256 color pictures.
-		// Load the picture. Similar to void cmdLoad_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
-		SpritesMgr *spritesMgr = vm->_sprites;
-		uint16 varNr = parameter[0];
-		uint16 resourceNr = vm->getVar(varNr);
-
-		spritesMgr->eraseSprites();
-		vm->loadResource(RESOURCETYPE_PICTURE, resourceNr);
-
-		// Draw the picture. Similar to void cmdDraw_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
-		vm->_picture->decodePicture(resourceNr, false, true);
-		spritesMgr->drawAllSpriteLists();
-		state->pictureShown = false;
-
-		// Loading trigger
-		vm->artificialDelayTrigger_DrawPicture(resourceNr);
-
-		// Show the picture. Similar to void cmdShow_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
-		vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
-		vm->_text->closeWindow();
-		vm->_picture->showPic();
-		state->pictureShown = true;
-	}
+	// enable automatic saving if description isn't empty
+	state->automaticSave = (state->automaticSaveDescription[0] != '\0');
 }
 
 // pop.script was not available until 2.425, and also not available in 2.440
@@ -2242,13 +2214,6 @@ void cmdPushScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	debug(0, "push.script");
 }
 
-// The AGIMOUSE interpreter modified push.script to set variables 27-29 to mouse state
-void cmdAgiMousePushScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
-	vm->setVar(VM_VAR_MOUSE_BUTTONSTATE, vm->_mouse.button);
-	vm->setVar(VM_VAR_MOUSE_X, vm->_mouse.pos.x / 2);
-	vm->setVar(VM_VAR_MOUSE_Y, vm->_mouse.pos.y);
-}
-
 void cmdSetPriBase(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	if ((vm->getVersion() != 0x2425) && (vm->getVersion() < 0x2936)) {
 		// was only available in the 2.425 interpreter and from 2.936 (last AGI2 version) onwards
@@ -2342,6 +2307,38 @@ void cmdNewRoomVV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	vm->setVar(13, 1);
 }
 
+// The AGI256 interpreter modified opcode 170 to load 256 color pictures
+void cmdAgi256LoadPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+	// Load the picture. Similar to void cmdLoadPic.
+	SpritesMgr *spritesMgr = vm->_sprites;
+	uint16 varNr = parameter[0];
+	uint16 resourceNr = vm->getVar(varNr);
+
+	spritesMgr->eraseSprites();
+	vm->loadResource(RESOURCETYPE_PICTURE, resourceNr);
+
+	// Draw the picture. Similar to void cmdDrawPic.
+	vm->_picture->decodePicture(resourceNr, false, true);
+	spritesMgr->drawAllSpriteLists();
+	state->pictureShown = false;
+
+	// Loading trigger
+	vm->artificialDelayTrigger_DrawPicture(resourceNr);
+
+	// Show the picture. Similar to void cmdShowPic.
+	vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
+	vm->_text->closeWindow();
+	vm->_picture->showPic();
+	state->pictureShown = true;
+}
+
+// The AGIMOUSE interpreter modified opcode 171 to set variables 27-29 to mouse state
+void cmdAgiMouseGetMouseState(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+	vm->setVar(VM_VAR_MOUSE_BUTTONSTATE, vm->_mouse.button);
+	vm->setVar(VM_VAR_MOUSE_X, vm->_mouse.pos.x / 2);
+	vm->setVar(VM_VAR_MOUSE_Y, vm->_mouse.pos.y);
+}
+
 void cmdUnknown(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	byte opcode = *(state->_curLogic->data + state->_curLogic->cIP - 1);
 	Common::String parameterString;
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index fb3f159ea96..12a805d631f 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -463,9 +463,14 @@ void AgiEngine::setupOpCodes(uint16 version) {
 		}
 	}
 
-	// AGIMOUSE games use a modified push.script that updates mouse state
+	// AGI256 games use a modified opcode (set.simple) that loads 256 color pictures
+	if (getFeatures() & GF_AGI256) {
+		_opCodes[0xaa].functionPtr = &cmdAgi256LoadPic;
+	}
+
+	// AGIMOUSE games use a modified opcode (push.script) that gets mouse state
 	if (getFeatures() & GF_AGIMOUSE) {
-		_opCodes[0xab].functionPtr = &cmdAgiMousePushScript;
+		_opCodes[0xab].functionPtr = &cmdAgiMouseGetMouseState;
 	}
 
 	// add invalid entries for every opcode, that is not defined at all
@@ -485,11 +490,11 @@ void AgiEngine::setupOpCodes(uint16 version) {
 
 	// calculate parameter size
 	for (int opCodeNr = 0; opCodeNr < opCodesTableSize; opCodeNr++) {
-		_opCodes[opCodeNr].parameterSize = strlen( _opCodes[opCodeNr].parameters);
+		_opCodes[opCodeNr].parameterSize = strlen(_opCodes[opCodeNr].parameters);
 	}
 
 	for (int opCodeNr = 0; opCodeNr < opCodesCondTableSize; opCodeNr++) {
-		_opCodesCond[opCodeNr].parameterSize = strlen( _opCodesCond[opCodeNr].parameters);
+		_opCodesCond[opCodeNr].parameterSize = strlen(_opCodesCond[opCodeNr].parameters);
 	}
 }
 
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index a52e5d2bdc5..4d3f745736e 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -207,8 +207,9 @@ void cmdDivN(AgiGame *state, AgiEngine *vm, uint8 *p);
 void cmdDivV(AgiGame *state, AgiEngine *vm, uint8 *p);  // 0xa8
 void cmdCloseWindow(AgiGame *state, AgiEngine *vm, uint8 *p);
 void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *p);
+void cmdAgi256LoadPic(AgiGame *state, AgiEngine *vm, uint8 *p); // modified 0xaa
 void cmdPushScript(AgiGame *state, AgiEngine *vm, uint8 *p);
-void cmdAgiMousePushScript(AgiGame *state, AgiEngine *vm, uint8 *p); // modified 0xab
+void cmdAgiMouseGetMouseState(AgiGame *state, AgiEngine *vm, uint8 *p); // modified 0xab
 void cmdPopScript(AgiGame *state, AgiEngine *vm, uint8 *p);
 void cmdHoldKey(AgiGame *state, AgiEngine *vm, uint8 *p);
 void cmdSetPriBase(AgiGame *state, AgiEngine *vm, uint8 *p);


Commit: f15c08bfb6fb53e56574317bebe36f72e5626097
    https://github.com/scummvm/scummvm/commit/f15c08bfb6fb53e56574317bebe36f72e5626097
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-10-28T21:02:51-07:00

Commit Message:
AGI: Remove extra AGI256 picture render

We duplicated show.pic in the AGI256 opcode for loading pictures,
but AGI256 already required scripts to call show.pic after loading.

Changed paths:
    engines/agi/op_cmd.cpp


diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 47272e4bb19..fde780ae627 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -2324,12 +2324,6 @@ void cmdAgi256LoadPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 
 	// Loading trigger
 	vm->artificialDelayTrigger_DrawPicture(resourceNr);
-
-	// Show the picture. Similar to void cmdShowPic.
-	vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
-	vm->_text->closeWindow();
-	vm->_picture->showPic();
-	state->pictureShown = true;
 }
 
 // The AGIMOUSE interpreter modified opcode 171 to set variables 27-29 to mouse state


Commit: ce2410f7a3241ed4e7da15049be8ae6c96327b8c
    https://github.com/scummvm/scummvm/commit/ce2410f7a3241ed4e7da15049be8ae6c96327b8c
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-10-28T21:02:52-07:00

Commit Message:
AGI: Update Apple IIgs opcodes

- discard.sound has three potential opcode values depending on the
  interpreter version; this is now handled and documented.
- Unknown opcode 175 is now handled and its presence is documented.
- Fixes AGIDEMO and PQ1 calling set.simple instead of discard.sound.
- Reverted SQ2 workaround now that its discard.sound calls are
  correctly handled: 736d7cd533255d1fa9b3a6d20158ed7c917ac4a6

Changed paths:
    engines/agi/detection_tables.h
    engines/agi/op_cmd.cpp
    engines/agi/opcodes.cpp


diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index 7c89d847f8f..2e2a24ee708 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -184,7 +184,7 @@ static const AGIGameDescription gameDescriptions[] = {
 	A2("agidemo", "Demo 1987", "1abef8018f42dc21a59e03f3d227024f", 0x2917, GID_AGIDEMO),
 
 	// AGI Demo 2 (IIgs) 1.0C (Censored)
-	GAME_P("agidemo", "Demo 2 1987-11-24 1.0C", "580ffdc569ff158f56fb92761604f70e", 0x2917, GID_AGIDEMO, Common::kPlatformApple2GS),
+	GAME_P("agidemo", "Demo 2 1987-11-24 1.0C", "580ffdc569ff158f56fb92761604f70e", 0x2440, GID_AGIDEMO, Common::kPlatformApple2GS),
 
 	// AGI Demo 2 (PC 3.5") 11/87 [AGI 2.915]
 	GAME("agidemo", "Demo 2 1987-11-24 3.5\"", "e8ebeb0bbe978172fe166f91f51598c7", 0x2917, GID_AGIDEMO),
@@ -662,7 +662,7 @@ static const AGIGameDescription gameDescriptions[] = {
 	GAME_P("pq1", "2.0G 1987-12-03", "805750b66c1c5b88a214e67bfdca17a1", 0x2440, GID_PQ1, Common::kPlatformMacintosh),
 
 	// Police Quest 1 (Apple II) 1.0I 11/23/88 (A2 Int. 0.099)
-	A2("pq1", "1.0I 1988-11-23", "581e54c4d89bd53e775482cee9cd3ea0", 0x2917, GID_PQ1),
+	A2("pq1", "1.0I 1988-11-23", "581e54c4d89bd53e775482cee9cd3ea0", 0x2440, GID_PQ1),
 
 	// Police Quest 1 (IIgs) 2.0B-88421
 	GAME_PO("pq1", "2.0B 1988-04-21", "e7c175918372336461e3811d594f482f", 0x2917, GID_PQ1, Common::kPlatformApple2GS, GAMEOPTIONS_APPLE2GS),
@@ -760,14 +760,7 @@ static const AGIGameDescription gameDescriptions[] = {
 	A2("sq2", "2.0F", "5ca2c0e49918acb2517742922717201c", 0x2917, GID_SQ2),
 
 	// Space Quest 2 (IIgs) 2.0A 7/25/88 (CE)
-	// We have to see this as AGI < 2.936, because otherwise a set.pri.base call would somewhat break
-	// priority in SQ2, when entering Vohaul's vault.
-	// The Apple IIgs AGI included with SQ2 is the same as the one included with KQ3.
-	// We currently consider KQ3 IIgs to be a 2.917-equivalent.
-	// The SQ2 IIgs AGI definitely has 177 kernel functions, but it seems that Sierra shuffled the last few around / added a few extras at the end.
-	// For KQ3 set.pri.base is called with parameters that seem to be sound resources, which means
-	// set.pri.base was possibly discard.sound. For KQ4 onwards it seems this was cleaned up.
-	GAME_PO("sq2", "2.0A 1988-07-25 (CE)", "5dfdac98dd3c01fcfb166529f917e911", 0x2917, GID_SQ2, Common::kPlatformApple2GS, GAMEOPTIONS_APPLE2GS),
+	GAME_PO("sq2", "2.0A 1988-07-25 (CE)", "5dfdac98dd3c01fcfb166529f917e911", 0x2936, GID_SQ2, Common::kPlatformApple2GS, GAMEOPTIONS_APPLE2GS),
 
 	{
 		// Space Quest 2 (Amiga) 2.0F
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index fde780ae627..d403d771288 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -941,22 +941,8 @@ void cmdObjStatusF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	vm->_text->messageBox(msg);
 }
 
-// unknown commands:
-// unk_170: Force savegame name -- j5
-// unk_171: script save -- j5
-// unk_172: script restore -- j5
-// unk_173: Activate keypressed control (ego only moves while key is pressed)
-// unk_174: Change priority table (used in KQ4) -- j5
-// unk_177: Disable menus completely -- j5
-// unk_181: Deactivate keypressed control (default control of ego)
+// only known to used by MMMG for setting the player's name as the save description
 void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
-	// set.simple is called by Larry 1 on Apple IIgs at the store, after answering the 555-6969 phone.
-	// load.sound(16) is called right before it. Interpreter is 2.440-like.
-	// it's called with parameter 16.
-	// Original interpreter doesn't seem to play any sound.
-	// TODO: Figure out what's going on. It can't be automatic saving of course.
-	// Also getting called in KQ1, when planting beans - parameter 12.
-	// And when killing the witch - parameter 40.
 	if ((vm->getVersion() < 0x2425) || (vm->getVersion() == 0x2440)) {
 		// was not available before 2.2425, but also not available in 2.440
 		warning("set.simple called, although not available for current AGI version");
@@ -985,10 +971,10 @@ void cmdPopScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	debug(0, "pop.script");
 }
 
+// discard.sound only existed on Apple IIgs. Apple IIgs sound resources were
+// relatively large, so scripts would unload them from memory when finished.
 void cmdDiscardSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
-	if (vm->getVersion() >= 0x2936) {
-		debug(0, "discard.sound");
-	}
+	debug(0, "discard.sound");
 }
 
 void cmdShowMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
@@ -1075,6 +1061,9 @@ void cmdAdjEgoMoveToXY(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	const AgiOpCodeEntry *opCodeTable = vm->getOpCodesTable();
 	int8 x, y;
 
+	// There are apparently two versions of this opcode: one that takes
+	// two parameters and one that takes none. The only games that call
+	// this opcode use the two parameter version.
 	switch (opCodeTable[182].parameterSize) {
 	// The 2 parameter version is used in:
 	// Amiga/Atari ST Gold Rush!   - Logic 130, 150
@@ -1103,8 +1092,8 @@ void cmdAdjEgoMoveToXY(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 
 		debugC(4, kDebugLevelScripts, "adj.ego.move.to.x.y(%d, %d)", x, y);
 		break;
-	// TODO: Check where (if anywhere) the 0 arguments version is used
-	case 0:
+
+	// No games call this; all games call the 2 parameter version
 	default:
 		state->screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags |= fAdjEgoXY;
 		break;
@@ -2217,14 +2206,6 @@ void cmdPushScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 void cmdSetPriBase(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
 	if ((vm->getVersion() != 0x2425) && (vm->getVersion() < 0x2936)) {
 		// was only available in the 2.425 interpreter and from 2.936 (last AGI2 version) onwards
-		// Called during KQ3 (Apple IIgs):
-		//  - picking up chicken (parameter = 50)
-		//  - opening store/tavern door (parameter = 19)
-		//  - when pirates say "Land Ho" (parameter = 16)
-		//  - when killing the dragon (parameter = 4)
-		// Also called by SQ2 (Apple IIgs):
-		//  - in Vohaul's lair (SQ2 currently gets this call through, which breaks some priority)
-		// TODO: Figure out what's going on
 		warning("set.pri.base called, although not available for current AGI version");
 		return;
 	}
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index 12a805d631f..1ad3b709cb1 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -347,12 +347,12 @@ static const AgiOpCodeDefinitionEntry opCodesV2[] = {
 	{ "div.n",              "vn",       &cmdDivN },             // A7
 	{ "div.v",              "vv",       &cmdDivV },             // A8
 	{ "close.window",       "",         &cmdCloseWindow },      // A9
-	{ "set.simple",         "n",        &cmdSetSimple },        // AA AGI2.425+, *BUT* not included in AGI2.440
+	{ "set.simple",         "n",        &cmdSetSimple },        // AA AGI2.425+, *BUT* not included in AGI2.440, discard.sound in some Apple IIgs
 	{ "push.script",        "",         &cmdPushScript },       // AB
 	{ "pop.script",         "",         &cmdPopScript },        // AC
 	{ "hold.key",           "",         &cmdHoldKey },          // AD
-	{ "set.pri.base",       "n",        &cmdSetPriBase },       // AE AGI2.936+ *AND* also inside AGI2.425
-	{ "discard.sound",      "n",        &cmdDiscardSound },     // AF was skip for PC
+	{ "set.pri.base",       "n",        &cmdSetPriBase },       // AE AGI2.936+ *AND* also inside AGI2.425, discard.sound in some Apple IIgs
+	{ "discard.sound",      "n",        &cmdDiscardSound },     // AF Apple IIGS only
 	{ "hide.mouse",         "",         &cmdHideMouse },        // B0 1 arg for AGI3 Apple IIGS and AGI 3.002.086. AGI3+ only starts here
 	{ "allow.menu",         "n",        &cmdAllowMenu },        // B1
 	{ "show.mouse",         "",         &cmdShowMouse },        // B2 1 arg for AGI3 Apple IIGS
@@ -403,7 +403,7 @@ void AgiEngine::setupOpCodes(uint16 version) {
 	}
 
 	// Alter opcode parameters for specific games
-	if ((version >= 0x2000) && (version < 0x3000)) {
+	if (0x2000 <= version && version < 0x3000) {
 		// AGI2 adjustments
 
 		// 'quit' takes 0 args for 2.089
@@ -418,22 +418,12 @@ void AgiEngine::setupOpCodes(uint16 version) {
 			_opCodes[0x97].parameters = "vvv";
 			_opCodes[0x98].parameters = "vvv";
 		}
-
-		// TODO: Opcode B0 is used by SQ2 Apple IIgs, but its purpose is
-		// currently unknown. It takes one parameter, and that parameter
- 		// appears to be a variable number. It is not hide.mouse from AGI3.
-		// No other AGI2 games have been discovered that call this opcode.
-		// Logic 1: during the spaceship cutscene in the intro, called with 53
-		// Logic 23: called twice with 39.
-		_opCodes[0xb0].name = "unknown";
-		_opCodes[0xb0].parameters = "v";
-		_opCodes[0xb0].functionPtr = &cmdUnknown;
 	}
 
 	if (version >= 0x3000) {
 		// AGI3 adjustments
 
-		// hide.mouse and hide.key take 1 parameter for 3.002.086.
+		// hide.mouse and hold.key take 1 parameter for 3.002.086.
 		// KQ4 is the only known game with this interpreter and
 		// its scripts do not call either opcode. no game scripts
 		// have been discovered that call hold.key with 1 parameter.
@@ -463,6 +453,46 @@ void AgiEngine::setupOpCodes(uint16 version) {
 		}
 	}
 
+	// Apple IIgs adjustments
+	if (getPlatform() == Common::kPlatformApple2GS) {
+		// A2GS has platform-specific opcodes whose values changed over time.
+		// Our A2GS version numbering isn't as precise as for DOS interpreters,
+		// so the following version checks are just meant to separate A2GS games
+		// into three broad groups. The use of these opcodes has been audited in
+		// all known A2GS games and versions. Although all of these are currently
+		// no-ops in our implementation, what's important is that they prevent
+		// the "normal" opcodes from being unexpectedly called.
+
+		if (version <= 0x2440) {
+			// opcode 170: discard.sound.
+			// called by AGIDEMO, KQ1, LSL1, PQ1.
+			memcpy(&_opCodes[0xaa], &_opCodes[0xaf], sizeof(AgiOpCodeDefinitionEntry));
+		} else if (version < 0x3000) {
+			// opcode 174: discard.sound.
+			// called by MMMG, KQ2, KQ3, SQ2.
+			memcpy(&_opCodes[0xae], &_opCodes[0xaf], sizeof(AgiOpCodeDefinitionEntry));
+
+			// TODO: opcode 175: unknown opcode that takes one unknown parameter.
+			// called by KQ3 and SQ2. possibly related to sound. example:
+			// SQ2 Logic 20: called once during music after kicking spores
+			_opCodes[0xaf].name = "unknown";
+			_opCodes[0xaf].parameters = "n";
+			_opCodes[0xaf].functionPtr = &cmdUnknown;
+
+			// TODO: opcode 176: unknown opcode that takes one variable parameter.
+			// called by SQ2 in only two places:
+			// Logic 1: during the spaceship cutscene in the intro, called with 53
+			// Logic 23: called twice with 39.
+			_opCodes[0xb0].name = "unknown";
+			_opCodes[0xb0].parameters = "v";
+			_opCodes[0xb0].functionPtr = &cmdUnknown;
+		} else {
+			// AGI3 opcodes are already in the table:
+			// opcode 175: discard sound.
+			// called by KQ4 and MH1.
+		}
+	}
+
 	// AGI256 games use a modified opcode (set.simple) that loads 256 color pictures
 	if (getFeatures() & GF_AGI256) {
 		_opCodes[0xaa].functionPtr = &cmdAgi256LoadPic;




More information about the Scummvm-git-logs mailing list