diff options
-rw-r--r-- | engines/scumm/charset.cpp | 26 | ||||
-rw-r--r-- | engines/scumm/charset.h | 3 | ||||
-rw-r--r-- | engines/scumm/costume.cpp | 12 | ||||
-rw-r--r-- | engines/scumm/cursor.cpp | 11 | ||||
-rw-r--r-- | engines/scumm/gfx.cpp | 30 | ||||
-rw-r--r-- | engines/scumm/palette.cpp | 444 | ||||
-rw-r--r-- | engines/scumm/room.cpp | 7 | ||||
-rw-r--r-- | engines/scumm/saveload.cpp | 17 | ||||
-rw-r--r-- | engines/scumm/saveload.h | 2 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 6 | ||||
-rw-r--r-- | engines/scumm/scumm.h | 12 |
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]; |