aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorEugene Sandulenko2011-08-27 10:23:19 -0700
committerEugene Sandulenko2011-08-27 10:23:19 -0700
commit064ab0fd628f660d8565512dfbffb0c11a82f046 (patch)
treeac553523b5442af31bad9a1a3fa80bb3af85682f /engines
parent35aa235e4b4c4212b59d00adb77d2e3d00dd440e (diff)
parentcd45d63e064c5f45e911256de75c3efef156337d (diff)
downloadscummvm-rg350-064ab0fd628f660d8565512dfbffb0c11a82f046.tar.gz
scummvm-rg350-064ab0fd628f660d8565512dfbffb0c11a82f046.tar.bz2
scummvm-rg350-064ab0fd628f660d8565512dfbffb0c11a82f046.zip
Merge pull request #77 from lordhoto/indy4amiga
SCUMM: Implement proper Indy4 Amiga palette handling.
Diffstat (limited to 'engines')
-rw-r--r--engines/scumm/charset.cpp26
-rw-r--r--engines/scumm/charset.h3
-rw-r--r--engines/scumm/costume.cpp12
-rw-r--r--engines/scumm/cursor.cpp11
-rw-r--r--engines/scumm/gfx.cpp30
-rw-r--r--engines/scumm/palette.cpp444
-rw-r--r--engines/scumm/room.cpp7
-rw-r--r--engines/scumm/saveload.cpp17
-rw-r--r--engines/scumm/saveload.h2
-rw-r--r--engines/scumm/scumm.cpp6
-rw-r--r--engines/scumm/scumm.h12
11 files changed, 479 insertions, 91 deletions
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 8558da397e..f7b98e2451 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -767,6 +767,13 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
_textScreenID = vs->number;
}
+ // We need to know the virtual screen we draw on for Indy 4 Amiga, since
+ // it selects the palette map according to this. We furthermore can not
+ // use _textScreenID here, since that will cause inventory graphics
+ // glitches.
+ if (_vm->_game.platform == Common::kPlatformAmiga && _vm->_game.id == GID_INDY4)
+ _drawScreen = vs->number;
+
printCharIntern(is2byte, _charPtr, _origWidth, _origHeight, _width, _height, vs, ignoreCharsetMask);
_left += _origWidth;
@@ -917,12 +924,27 @@ void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, co
numbits = 8;
byte *cmap = _vm->_charsetColorMap;
+ // Indy4 Amiga always uses the room or verb palette map to match colors to
+ // the currently setup palette, thus we need to select it over here too.
+ // Done like the original interpreter.
+ byte *amigaMap = 0;
+ if (_vm->_game.platform == Common::kPlatformAmiga && _vm->_game.id == GID_INDY4) {
+ if (_drawScreen == kVerbVirtScreen)
+ amigaMap = _vm->_verbPalette;
+ else
+ amigaMap = _vm->_roomPalette;
+ }
+
for (y = 0; y < height && y + drawTop < s.h; y++) {
for (x = 0; x < width; x++) {
color = (bits >> (8 - bpp)) & 0xFF;
- if (color && y + drawTop >= 0)
- *dst = cmap[color];
+ if (color && y + drawTop >= 0) {
+ if (amigaMap)
+ *dst = amigaMap[cmap[color]];
+ else
+ *dst = cmap[color];
+ }
dst++;
bits <<= bpp;
numbits -= bpp;
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index b23ec996f5..fabb82b389 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -119,6 +119,9 @@ protected:
int _offsX, _offsY;
const byte *_charPtr;
+ // On which virtual screen will be drawn right now
+ VirtScreenNumber _drawScreen;
+
public:
CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {}
diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp
index 4ca4988605..eb3cc3262c 100644
--- a/engines/scumm/costume.cpp
+++ b/engines/scumm/costume.cpp
@@ -545,6 +545,13 @@ void ClassicCostumeRenderer::proc3_ami(Codec1 &v1) {
oldXpos = v1.x;
oldScaleIndexX = _scaleIndexX;
+ // Indy4 Amiga always uses the room map to match colors to the currently
+ // setup palette in the actor code in the original, thus we need to do this
+ // mapping over here too.
+ byte *amigaMap = 0;
+ if (_vm->_game.platform == Common::kPlatformAmiga && _vm->_game.id == GID_INDY4)
+ amigaMap = _vm->_roomPalette;
+
do {
len = *src++;
color = len >> v1.shr;
@@ -556,7 +563,10 @@ void ClassicCostumeRenderer::proc3_ami(Codec1 &v1) {
masked = (y < 0 || y >= _out.h) || (v1.x < 0 || v1.x >= _out.w) || (v1.mask_ptr && (mask[0] & maskbit));
if (color && !masked) {
- *dst = _palette[color];
+ if (amigaMap)
+ *dst = amigaMap[_palette[color]];
+ else
+ *dst = _palette[color];
}
if (_scaleX == 255 || v1.scaletable[_scaleIndexX] < _scaleX) {
diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index 6739282c9d..36f06a4889 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -609,7 +609,16 @@ void ScummEngine_v5::setBuiltinCursor(int idx) {
for (i = 0; i < 1024; i++)
WRITE_UINT16(_grabbedCursor + i * 2, 0xFF);
} else {
- color = default_cursor_colors[idx];
+ // Indy4 Amiga uses its own color set for the cursor image.
+ // This is patchwork code to make the cursor flash in correct colors.
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ static const uint8 indy4AmigaColors[4] = {
+ 252, 252, 253, 254
+ };
+ color = indy4AmigaColors[idx];
+ } else {
+ color = default_cursor_colors[idx];
+ }
memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor));
}
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 8a32b963cd..a22aa1802f 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -1025,6 +1025,16 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) {
if (rect.left > vs->w)
return;
+ // Indy4 Amiga always uses the room or verb palette map to match colors to
+ // the currently setup palette, thus we need to select it over here too.
+ // Done like the original interpreter.
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ if (vs->number == kVerbVirtScreen)
+ backColor = _verbPalette[backColor];
+ else
+ backColor = _roomPalette[backColor];
+ }
+
// Convert 'rect' to local (virtual screen) coordinates
rect.top -= vs->topline;
rect.bottom -= vs->topline;
@@ -1235,6 +1245,16 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) {
if ((vs = findVirtScreen(y)) == NULL)
return;
+ // Indy4 Amiga always uses the room or verb palette map to match colors to
+ // the currently setup palette, thus we need to select it over here too.
+ // Done like the original interpreter.
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ if (vs->number == kVerbVirtScreen)
+ color = _verbPalette[color];
+ else
+ color = _roomPalette[color];
+ }
+
if (x > x2)
SWAP(x, x2);
@@ -1872,6 +1892,16 @@ bool Gdi::drawStrip(byte *dstPtr, VirtScreen *vs, int x, int y, const int width,
}
assertRange(0, offset, smapLen-1, "screen strip");
+ // Indy4 Amiga always uses the room or verb palette map to match colors to
+ // the currently setup palette, thus we need to select it over here too.
+ // Done like the original interpreter.
+ if (_vm->_game.platform == Common::kPlatformAmiga && _vm->_game.id == GID_INDY4) {
+ if (vs->number == kVerbVirtScreen)
+ _roomPalette = _vm->_verbPalette;
+ else
+ _roomPalette = _vm->_roomPalette;
+ }
+
return decompressBitmap(dstPtr, vs->pitch, smap_ptr + offset, height);
}
diff --git a/engines/scumm/palette.cpp b/engines/scumm/palette.cpp
index 30096000ce..9977436dc6 100644
--- a/engines/scumm/palette.cpp
+++ b/engines/scumm/palette.cpp
@@ -372,6 +372,140 @@ void ScummEngine::setPaletteFromPtr(const byte *ptr, int numcolor) {
setDirtyColors(firstIndex, numcolor - 1);
}
+void ScummEngine::setAmigaPaletteFromPtr(const byte *ptr) {
+ memcpy(_currentPalette, ptr, 768);
+
+ for (int i = 0; i < 32; ++i) {
+ _shadowPalette[i] = i;
+ _colorUsedByCycle[i] = 0;
+ }
+
+ _amigaFirstUsedColor = 80;
+ for (; _amigaFirstUsedColor < 256; ++_amigaFirstUsedColor) {
+ // We look for the first used color here. If all color components are
+ // >= 252 the color seems to be unused. Check remapPaletteColor for
+ // the same behavior.
+ if (ptr[_amigaFirstUsedColor * 3 + 0] <= 251
+ || ptr[_amigaFirstUsedColor * 3 + 1] <= 251
+ || ptr[_amigaFirstUsedColor * 3 + 2] <= 251)
+ break;
+ }
+
+ for (int i = 0; i < 64; ++i) {
+ _amigaPalette[i * 3 + 0] = _currentPalette[(i + 16) * 3 + 0] >> 4;
+ _amigaPalette[i * 3 + 1] = _currentPalette[(i + 16) * 3 + 1] >> 4;
+ _amigaPalette[i * 3 + 2] = _currentPalette[(i + 16) * 3 + 2] >> 4;
+ }
+
+ for (int i = 0; i < 256; ++i) {
+ if (i < 16 || i >= _amigaFirstUsedColor) {
+ mapRoomPalette(i);
+ mapVerbPalette(i);
+ } else {
+ int idx = (i - 16) & 31;
+ // We adjust our verb palette map from [0, 31] to [32, 63], since unlike
+ // the original we set up the verb palette at colors [32, 63].
+ // The original instead used two different palettes for the verb virtual
+ // screen and all the rest.
+ if (idx != 17) {
+ _roomPalette[i] = idx;
+ _verbPalette[i] = idx + 32;
+ } else {
+ // In all my tests it seems the colors 0 and 32 in
+ // _amigaPalette are in fact black. Thus 17 is probably black.
+ // For the room map the color 17 is 33 (17+16), for the verb
+ // map it is 65 (17+32).
+ _roomPalette[i] = 0;
+ _verbPalette[i] = 32;
+ }
+ }
+ }
+
+ setDirtyColors(0, 255);
+}
+
+void ScummEngine::mapRoomPalette(int idx) {
+ // For Color 33 (which is in fact 17+16) see the special case in
+ // setAmigaPaletteFromPtr.
+ if (idx >= 16 && idx < 48 && idx != 33)
+ _roomPalette[idx] = idx - 16;
+ else
+ _roomPalette[idx] = remapRoomPaletteColor(_currentPalette[idx * 3 + 0] >> 4,
+ _currentPalette[idx * 3 + 1] >> 4,
+ _currentPalette[idx * 3 + 2] >> 4);
+}
+
+static const uint8 amigaWeightTable[16] = {
+ 0, 1, 4, 9, 16, 25, 36, 49,
+ 64, 81, 100, 121, 144, 169, 196, 225
+};
+
+int ScummEngine::remapRoomPaletteColor(int r, int g, int b) {
+ int idx = 0;
+ uint16 minValue = 0xFFFF;
+
+ const byte *pal = _amigaPalette;
+ const byte *cycle = _colorUsedByCycle;
+
+ for (int i = 0; i < 32; ++i) {
+ if (!*cycle++ && i != 17) {
+ int rD = ABS<int>(*pal++ - r);
+ int gD = ABS<int>(*pal++ - g);
+ int bD = ABS<int>(*pal++ - b);
+
+ const uint16 weight = amigaWeightTable[rD] + amigaWeightTable[gD] + amigaWeightTable[bD];
+ if (weight < minValue) {
+ minValue = weight;
+ idx = i;
+ }
+ } else {
+ pal += 3;
+ }
+ }
+
+ return idx;
+}
+
+void ScummEngine::mapVerbPalette(int idx) {
+ // We adjust our verb palette map from [0, 31] to [32, 63], since unlike
+ // the original we set up the verb palette at colors [32, 63].
+ // The original instead used two different palettes for the verb virtual
+ // screen and all the rest.
+ // For Color 65 (which is in fact 17+32) see the special case in
+ // setAmigaPaletteFromPtr.
+ if (idx >= 48 && idx < 80 && idx != 65)
+ _verbPalette[idx] = idx - 16;
+ else
+ _verbPalette[idx] = remapVerbPaletteColor(_currentPalette[idx * 3 + 0] >> 4,
+ _currentPalette[idx * 3 + 1] >> 4,
+ _currentPalette[idx * 3 + 2] >> 4) + 32;
+}
+
+int ScummEngine::remapVerbPaletteColor(int r, int g, int b) {
+ int idx = 0;
+ uint16 minValue = 0xFFFF;
+
+ const byte *pal = _amigaPalette + 32 * 3;
+
+ for (int i = 0; i < 32; ++i) {
+ if (i != 17) {
+ int rD = ABS<int>(*pal++ - r);
+ int gD = ABS<int>(*pal++ - g);
+ int bD = ABS<int>(*pal++ - b);
+
+ const uint16 weight = amigaWeightTable[rD] + amigaWeightTable[gD] + amigaWeightTable[bD];
+ if (weight < minValue) {
+ minValue = weight;
+ idx = i;
+ }
+ } else {
+ pal += 3;
+ }
+ }
+
+ return idx;
+}
+
void ScummEngine::setDirtyColors(int min, int max) {
if (_palDirtyMin > min)
_palDirtyMin = min;
@@ -419,11 +553,26 @@ void ScummEngine::initCycl(const byte *ptr) {
cycl->start = *ptr++;
cycl->end = *ptr++;
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ cycl->start = CLIP(cycl->start - 16, 0, 31);
+ cycl->end = CLIP(cycl->end - 16, 0, 31);
+ }
+
for (int i = cycl->start; i <= cycl->end; ++i) {
_colorUsedByCycle[i] = 1;
}
}
}
+
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ for (int i = 0; i < 256; ++i) {
+ if (i >= 16 && i < _amigaFirstUsedColor)
+ continue;
+
+ if (_colorUsedByCycle[_roomPalette[i]])
+ mapRoomPalette(i);
+ }
+ }
}
void ScummEngine::stopCycle(int i) {
@@ -432,11 +581,23 @@ void ScummEngine::stopCycle(int i) {
assertRange(0, i, 16, "stopCycle: cycle");
if (i != 0) {
_colorCycle[i - 1].delay = 0;
+ cycl = &_colorCycle[i - 1];
+ for (int j = cycl->start; j <= cycl->end && j < 32; ++j) {
+ _shadowPalette[j] = j;
+ _colorUsedByCycle[j] = 0;
+ }
return;
}
- for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++)
+ for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) {
cycl->delay = 0;
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ for (int j = cycl->start; j <= cycl->end && j < 32; ++j) {
+ _shadowPalette[j] = j;
+ _colorUsedByCycle[j] = 0;
+ }
+ }
+ }
}
/**
@@ -512,14 +673,18 @@ void ScummEngine::cyclePalette() {
setDirtyColors(cycl->start, cycl->end);
moveMemInPalRes(cycl->start, cycl->end, cycl->flags & 2);
- doCyclePalette(_currentPalette, cycl->start, cycl->end, 3, !(cycl->flags & 2));
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ doCyclePalette(_shadowPalette, cycl->start, cycl->end, 1, !(cycl->flags & 2));
+ } else {
+ doCyclePalette(_currentPalette, cycl->start, cycl->end, 3, !(cycl->flags & 2));
- if (_shadowPalette) {
- if (_game.version >= 7) {
- for (j = 0; j < NUM_SHADOW_PALETTE; j++)
+ if (_shadowPalette) {
+ if (_game.version >= 7) {
+ for (j = 0; j < NUM_SHADOW_PALETTE; j++)
doCycleIndirectPalette(_shadowPalette + j * 256, cycl->start, cycl->end, !(cycl->flags & 2));
- } else {
- doCycleIndirectPalette(_shadowPalette, cycl->start, cycl->end, !(cycl->flags & 2));
+ } else {
+ doCycleIndirectPalette(_shadowPalette, cycl->start, cycl->end, !(cycl->flags & 2));
+ }
}
}
}
@@ -733,62 +898,106 @@ void ScummEngine::setShadowPalette(int redScale, int greenScale, int blueScale,
}
void ScummEngine::darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor) {
- int max;
- if (_game.version >= 5 && _game.version <= 6 && _game.heversion <= 60) {
- max = 252;
- } else {
- max = 255;
- }
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ startColor = CLIP(startColor, 0, 255);
- if (startColor <= endColor) {
- const byte *cptr;
- const byte *palptr;
- int color, idx, j;
+ //bool remappedVerbColors = false;
+ bool remappedRoomColors = false;
+ bool cycleFlag = (blueScale >= 250 && greenScale >= 250 && redScale >= 250);
+
+ const byte *palptr = getPalettePtr(_curPalIndex, _roomResource) + startColor * 3;
+
+ for (int i = startColor; i <= endColor; ++i) {
+ if (i >= 16 && i < 48) {
+ if (cycleFlag)
+ _colorUsedByCycle[i - 16] &= ~2;
+ else
+ _colorUsedByCycle[i - 16] |= 2;
+ }
+
+ _currentPalette[i * 3 + 0] = (*palptr++ * redScale) >> 8;
+ _currentPalette[i * 3 + 1] = (*palptr++ * greenScale) >> 8;
+ _currentPalette[i * 3 + 2] = (*palptr++ * blueScale) >> 8;
+ }
+
+ for (int i = startColor; i <= endColor; ++i) {
+ // Colors 33 (17+16) and 65 (17+32) will never get changed. For
+ // more information about these check setAmigaPaletteFromPtr.
+ if (i >= 16 && i < 48 && i != 33) {
+ remappedRoomColors = true;
+ _amigaPalette[(i - 16) * 3 + 0] = _currentPalette[i * 3 + 0] >> 4;
+ _amigaPalette[(i - 16) * 3 + 1] = _currentPalette[i * 3 + 1] >> 4;
+ _amigaPalette[(i - 16) * 3 + 2] = _currentPalette[i * 3 + 2] >> 4;
+ } else if (i >= 48 && i < 80 && i != 65) {
+ //remappedVerbColors = true;
+ _amigaPalette[(i - 16) * 3 + 0] = _currentPalette[i * 3 + 0] >> 4;
+ _amigaPalette[(i - 16) * 3 + 1] = _currentPalette[i * 3 + 1] >> 4;
+ _amigaPalette[(i - 16) * 3 + 2] = _currentPalette[i * 3 + 2] >> 4;
+ }
+ }
+
+ for (int i = 0; i < 256; ++i) {
+ if (i >= 16 && i < _amigaFirstUsedColor)
+ continue;
+
+ bool inRange = (startColor <= i && i <= endColor);
+ int idx = _roomPalette[i] + 16;
+ bool mappedInRange = (startColor <= idx && idx <= endColor);
- if (_game.heversion >= 90 || _game.version == 8) {
- palptr = _darkenPalette;
+ if (inRange != mappedInRange || (remappedRoomColors && cycleFlag))
+ mapRoomPalette(i);
+ }
+
+ setDirtyColors(startColor, endColor);
+ } else {
+ int max;
+ if (_game.version >= 5 && _game.version <= 6 && _game.heversion <= 60) {
+ max = 252;
} else {
- palptr = getPalettePtr(_curPalIndex, _roomResource);
+ max = 255;
}
- for (j = startColor; j <= endColor; j++) {
- idx = (_game.heversion == 70) ? _HEV7ActorPalette[j] : j;
- cptr = palptr + idx * 3;
- if (_game.heversion == 70)
- setDirtyColors(idx, idx);
+ if (startColor <= endColor) {
+ const byte *cptr;
+ const byte *palptr;
+ int color, idx, j;
- // Original FOA Amiga version skips these colors
- // Fixes bug #1206994: "FOA AMIGA: Black cursor and text in Dig Site"
- if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
- if (j < 16) {
- cptr += 3;
- continue;
- }
+ if (_game.heversion >= 90 || _game.version == 8) {
+ palptr = _darkenPalette;
+ } else {
+ palptr = getPalettePtr(_curPalIndex, _roomResource);
}
-
- color = *cptr++;
- color = color * redScale / 0xFF;
- if (color > max)
- color = max;
- _currentPalette[idx * 3 + 0] = color;
-
- color = *cptr++;
- color = color * greenScale / 0xFF;
- if (color > max)
- color = max;
- _currentPalette[idx * 3 + 1] = color;
-
- color = *cptr++;
- color = color * blueScale / 0xFF;
- if (color > max)
- color = max;
- _currentPalette[idx * 3 + 2] = color;
-
- if (_game.features & GF_16BIT_COLOR)
- _16BitPalette[idx] = get16BitColor(_currentPalette[idx * 3 + 0], _currentPalette[idx * 3 + 1], _currentPalette[idx * 3 + 2]);
+ for (j = startColor; j <= endColor; j++) {
+ idx = (_game.heversion == 70) ? _HEV7ActorPalette[j] : j;
+ cptr = palptr + idx * 3;
+
+ if (_game.heversion == 70)
+ setDirtyColors(idx, idx);
+
+ color = *cptr++;
+ color = color * redScale / 0xFF;
+ if (color > max)
+ color = max;
+ _currentPalette[idx * 3 + 0] = color;
+
+ color = *cptr++;
+ color = color * greenScale / 0xFF;
+ if (color > max)
+ color = max;
+ _currentPalette[idx * 3 + 1] = color;
+
+ color = *cptr++;
+ color = color * blueScale / 0xFF;
+ if (color > max)
+ color = max;
+ _currentPalette[idx * 3 + 2] = color;
+
+ if (_game.features & GF_16BIT_COLOR)
+ _16BitPalette[idx] = get16BitColor(_currentPalette[idx * 3 + 0], _currentPalette[idx * 3 + 1], _currentPalette[idx * 3 + 2]);
+ }
+ if (_game.heversion != 70)
+ setDirtyColors(startColor, endColor);
}
- if (_game.heversion != 70)
- setDirtyColors(startColor, endColor);
}
}
@@ -1007,6 +1216,41 @@ void ScummEngine::setPalColor(int idx, int r, int g, int b) {
_darkenPalette[idx * 3 + 2] = b;
}
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ // Colors 33 (17+16) and 65 (17+32) will never get changed. For
+ // more information about these check setAmigaPaletteFromPtr.
+ if (idx < 16 || idx >= _amigaFirstUsedColor) {
+ mapRoomPalette(idx);
+ mapVerbPalette(idx);
+ } else if (idx >= 16 && idx < 48 && idx != 33) {
+ _amigaPalette[(idx - 16) * 3 + 0] = _currentPalette[idx * 3 + 0] >> 4;
+ _amigaPalette[(idx - 16) * 3 + 1] = _currentPalette[idx * 3 + 1] >> 4;
+ _amigaPalette[(idx - 16) * 3 + 2] = _currentPalette[idx * 3 + 2] >> 4;
+
+ for (int i = 0; i < 256; ++i) {
+ if (i >= 16 && i < _amigaFirstUsedColor)
+ continue;
+
+ if (idx - 16 == _roomPalette[i])
+ mapRoomPalette(i);
+ }
+ } else if (idx >= 48 && idx < 80 && idx != 65) {
+ _amigaPalette[(idx - 16) * 3 + 0] = _currentPalette[idx * 3 + 0] >> 4;
+ _amigaPalette[(idx - 16) * 3 + 1] = _currentPalette[idx * 3 + 1] >> 4;
+ _amigaPalette[(idx - 16) * 3 + 2] = _currentPalette[idx * 3 + 2] >> 4;
+
+ for (int i = 0; i < 256; ++i) {
+ if (i >= 16 && i < _amigaFirstUsedColor)
+ continue;
+
+ // We do - 16 instead of - 48 like the original, since our
+ // verb palette map is using [32, 63] instead of [0, 31].
+ if (idx - 16 == _verbPalette[i])
+ mapVerbPalette(i);
+ }
+ }
+ }
+
if (_game.features & GF_16BIT_COLOR)
_16BitPalette[idx] = get16BitColor(r, g, b);
@@ -1026,6 +1270,8 @@ void ScummEngine::setCurrentPalette(int palindex) {
towns_setPaletteFromPtr(pals);
#endif
#endif
+ } else if (_game.id == GID_INDY4 && _game.platform == Common::kPlatformAmiga) {
+ setAmigaPaletteFromPtr(pals);
} else {
setPaletteFromPtr(pals);
}
@@ -1081,42 +1327,74 @@ void ScummEngine::updatePalette() {
if (_palDirtyMax == -1)
return;
- bool noir_mode = (_game.id == GID_SAMNMAX && readVar(0x8000));
- int first = _palDirtyMin;
- int num = _palDirtyMax - first + 1;
- int i;
-
byte palette_colors[3 * 256];
byte *p = palette_colors;
+ int first;
+ int num;
- for (i = _palDirtyMin; i <= _palDirtyMax; i++) {
- byte *data;
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ // Indy4 Amiga has a special palette handling scheme
+ first = 0;
+ num = 64;
- if (_game.features & GF_SMALL_HEADER && _game.version > 2)
- data = _currentPalette + _shadowPalette[i] * 3;
- else
- data = _currentPalette + i * 3;
+ for (int i = 0; i < 64; ++i) {
+ byte *data;
- // Sam & Max film noir mode. Convert the colors to grayscale
- // before uploading them to the backend.
+ if (i < 32)
+ data = _amigaPalette + _shadowPalette[i] * 3;
+ else
+ data = _amigaPalette + i * 3;
- if (noir_mode) {
- int r, g, b;
- byte brightness;
+ *p++ = data[0] * 255 / 15;
+ *p++ = data[1] * 255 / 15;
+ *p++ = data[2] * 255 / 15;
+ }
- r = data[0];
- g = data[1];
- b = data[2];
+ // Setup colors for the mouse cursor
+ // Color values taken from Indy4 DOS
+ static const uint8 mouseCursorPalette[] = {
+ 255, 255, 255,
+ 171, 171, 171,
+ 87, 87, 87
+ };
- brightness = (byte)((0.299 * r + 0.587 * g + 0.114 * b) + 0.5);
+ _system->getPaletteManager()->setPalette(mouseCursorPalette, 252, 3);
+ } else {
+ bool noir_mode = (_game.id == GID_SAMNMAX && readVar(0x8000));
+ int i;
- *p++ = brightness;
- *p++ = brightness;
- *p++ = brightness;
- } else {
- *p++ = data[0];
- *p++ = data[1];
- *p++ = data[2];
+ first = _palDirtyMin;
+ num = _palDirtyMax - first + 1;
+
+ for (i = _palDirtyMin; i <= _palDirtyMax; i++) {
+ byte *data;
+
+ if (_game.features & GF_SMALL_HEADER && _game.version > 2)
+ data = _currentPalette + _shadowPalette[i] * 3;
+ else
+ data = _currentPalette + i * 3;
+
+ // Sam & Max film noir mode. Convert the colors to grayscale
+ // before uploading them to the backend.
+
+ if (noir_mode) {
+ int r, g, b;
+ byte brightness;
+
+ r = data[0];
+ g = data[1];
+ b = data[2];
+
+ brightness = (byte)((0.299 * r + 0.587 * g + 0.114 * b) + 0.5);
+
+ *p++ = brightness;
+ *p++ = brightness;
+ *p++ = brightness;
+ } else {
+ *p++ = data[0];
+ *p++ = data[1];
+ *p++ = data[2];
+ }
}
}
@@ -1127,7 +1405,7 @@ void ScummEngine::updatePalette() {
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
if (_game.platform == Common::kPlatformFMTowns) {
p = palette_colors;
- for (i = first; i < first + num; ++i) {
+ for (int i = first; i < first + num; ++i) {
_16BitPalette[i] = get16BitColor(p[0], p[1], p[2]);
p += 3;
}
diff --git a/engines/scumm/room.cpp b/engines/scumm/room.cpp
index 8962a0e971..63cbef8944 100644
--- a/engines/scumm/room.cpp
+++ b/engines/scumm/room.cpp
@@ -552,6 +552,10 @@ void ScummEngine::resetRoomSubBlocks() {
}
}
+ // We need to setup the current palette before initCycl for Indy4 Amiga.
+ if (_PALS_offs || _CLUT_offs)
+ setCurrentPalette(0);
+
// Color cycling
// HE 7.0 games load resources but don't use them.
if (_game.version >= 4 && _game.heversion <= 62) {
@@ -570,9 +574,6 @@ void ScummEngine::resetRoomSubBlocks() {
}
}
#endif
-
- if (_PALS_offs || _CLUT_offs)
- setCurrentPalette(0);
}
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 870ec8cdf7..e0eba99cce 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -1322,6 +1322,9 @@ void ScummEngine::saveOrLoad(Serializer *s) {
if (_shadowPaletteSize) {
s->saveLoadArrayOf(_shadowPalette, _shadowPaletteSize, 1, sleByte);
// _roomPalette didn't show up until V21 save games
+ // Note that we also save the room palette for Indy4 Amiga, since it
+ // is used as palette map there too, but we do so slightly a bit
+ // further down to group it with the other special palettes needed.
if (s->getVersion() >= VER(21) && _game.version < 5)
s->saveLoadArrayOf(_roomPalette, sizeof(_roomPalette), 1, sleByte);
}
@@ -1348,6 +1351,20 @@ void ScummEngine::saveOrLoad(Serializer *s) {
memset(_colorUsedByCycle, 0, sizeof(_colorUsedByCycle));
}
+ // Indy4 Amiga specific palette tables were not saved before V85
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ if (s->getVersion() >= 85) {
+ s->saveLoadArrayOf(_roomPalette, 256, 1, sleByte);
+ s->saveLoadArrayOf(_verbPalette, 256, 1, sleByte);
+ s->saveLoadArrayOf(_amigaPalette, 3 * 64, 1, sleByte);
+ } else {
+ warning("Save with old Indiana Jones 4 Amiga palette handling detected");
+ // We need to restore the internal state of the Amiga palette for Indy4
+ // Amiga. This might lead to graphics glitches!
+ setAmigaPaletteFromPtr(_currentPalette);
+ }
+ }
+
//
// Save/load more global object state
//
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
index 776f40e12b..792a31d067 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -47,7 +47,7 @@ namespace Scumm {
* only saves/loads those which are valid for the version of the savegame
* which is being loaded/saved currently.
*/
-#define CURRENT_VER 84
+#define CURRENT_VER 85
/**
* An auxillary macro, used to specify savegame versions. We use this instead
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 3b83019275..81f6af453c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -290,6 +290,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
#endif
_shadowPalette = NULL;
_shadowPaletteSize = 0;
+ _verbPalette = NULL;
memset(_currentPalette, 0, sizeof(_currentPalette));
memset(_darkenPalette, 0, sizeof(_darkenPalette));
memset(_HEV7ActorPalette, 0, sizeof(_HEV7ActorPalette));
@@ -610,6 +611,7 @@ ScummEngine::~ScummEngine() {
_textSurface.free();
free(_shadowPalette);
+ free(_verbPalette);
free(_palManipPalette);
free(_palManipIntermediatePal);
@@ -1408,6 +1410,10 @@ void ScummEngine::resetScumm() {
_16BitPalette = (uint16 *)calloc(512, sizeof(uint16));
#endif
+ // Indy4 Amiga needs another palette map for the verb area.
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4 && !_verbPalette)
+ _verbPalette = (uint8 *)calloc(256, 1);
+
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
if (_game.platform == Common::kPlatformFMTowns) {
delete _townsScreen;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 04a175e732..0af8264a58 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -970,6 +970,7 @@ protected:
void setCurrentPalette(int pal);
void setRoomPalette(int pal, int room);
void setPCEPaletteFromPtr(const byte *ptr);
+ void setAmigaPaletteFromPtr(const byte *ptr);
virtual void setPaletteFromPtr(const byte *ptr, int numcolor = -1);
virtual void setPalColor(int index, int r, int g, int b);
@@ -1065,6 +1066,9 @@ public:
uint16 _hePaletteSlot;
uint16 *_16BitPalette;
+ // Indy4 Amiga specific
+ byte *_verbPalette;
+
protected:
int _shadowPaletteSize;
byte _currentPalette[3 * 256];
@@ -1085,6 +1089,14 @@ protected:
bool _enable_gs;
bool _copyProtection;
+ // Indy4 Amiga specific
+ uint16 _amigaFirstUsedColor;
+ byte _amigaPalette[3 * 64];
+ void mapRoomPalette(int idx);
+ int remapRoomPaletteColor(int r, int g, int b);
+ void mapVerbPalette(int idx);
+ int remapVerbPaletteColor(int r, int g, int b);
+
public:
uint16 _extraBoxFlags[65];