diff --git a/dists/engine-data/freescape.dat b/dists/engine-data/freescape.dat index 01ee7e2e1fb..d43efd48fb4 100644 Binary files a/dists/engine-data/freescape.dat and b/dists/engine-data/freescape.dat differ diff --git a/engines/freescape/detection.cpp b/engines/freescape/detection.cpp index 03a8b985b8e..be8737da048 100644 --- a/engines/freescape/detection.cpp +++ b/engines/freescape/detection.cpp @@ -512,6 +512,15 @@ static const ADGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO2(GUIO_NOMIDI, GUIO_RENDERCPC) }, + { + "darkside", // Tape relese + "", + AD_ENTRY1s("DARKSIDE.C64.DATA", "c0d271d86cf4434ef7c3d823a32c0df5", 61290), + Common::EN_ANY, + Common::kPlatformC64, + ADGF_UNSTABLE, + GUIO2(GUIO_NOMIDI, GAMEOPTION_AUTOMATIC_DRILLING) + }, // Total Eclipse { "totaleclipse", diff --git a/engines/freescape/games/dark/c64.cpp b/engines/freescape/games/dark/c64.cpp new file mode 100644 index 00000000000..531ff0d3f19 --- /dev/null +++ b/engines/freescape/games/dark/c64.cpp @@ -0,0 +1,125 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "common/file.h" + +#include "freescape/freescape.h" +#include "freescape/games/dark/dark.h" +#include "freescape/language/8bitDetokeniser.h" + +namespace Freescape { + +void DarkEngine::initC64() { + _viewArea = Common::Rect(32, 24, 288, 127); +} + +void DarkEngine::loadAssetsC64FullGame() { + Common::File file; + file.open("darkside.c64.data"); + loadMessagesFixedSize(&file, 0x1edf, 14, 20); + //loadFonts(&file, 0xae54); + //loadFonts(&file, 0x4ee); + loadGlobalObjects(&file, 0x20bd, 23); + load8bitBinary(&file, 0x9b3e, 16); + + Graphics::Surface *surf = loadBundledImage("dark_border"); + surf->convertToInPlace(_gfx->_texturePixelFormat); + _border = new Graphics::ManagedSurface(); + _border->copyFrom(*surf); +} + + +void DarkEngine::drawC64UI(Graphics::Surface *surface) { + return; + uint8 r, g, b; + uint32 front = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0xAA, 0xAA, 0xAA); + + Common::Rect cover; + + uint32 color = 0; + if (_gfx->_colorRemaps && _gfx->_colorRemaps->contains(color)) { + color = (*_gfx->_colorRemaps)[color]; + } + + _gfx->readFromPalette(color, r, g, b); + uint32 back = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b); + + int score = _gameStateVars[k8bitVariableScore]; + drawStringInSurface(_currentArea->_name, 200, 184, front, back, surface); + cover = Common::Rect(150, 143, 183, 167); + + surface->fillRect(cover, back); + drawStringInSurface(Common::String::format("%04d", int(2 * _position.x())), 150, 148 - 4, front, back, surface); + drawStringInSurface(Common::String::format("%04d", int(2 * _position.z())), 150, 156 - 4, front, back, surface); + drawStringInSurface(Common::String::format("%04d", int(2 * _position.y())), 150, 164 - 4, front, back, surface); + if (_playerHeightNumber >= 0) + drawStringInSurface(Common::String::format("%d", _playerHeightNumber), 54 + 6, 164 - 3, front, back, surface); + else + drawStringInSurface(Common::String::format("%s", "J"), 54 + 6, 164 - 3, front, back, surface); + + drawStringInSurface(Common::String::format("%02d", int(_angleRotations[_angleRotationIndex])), 46, 148 - 3, front, back, surface); + drawStringInSurface(Common::String::format("%3d", _playerSteps[_playerStepIndex]), 46, 156 - 3, front, back, surface); + drawStringInSurface(Common::String::format("%07d", score), 239, 128, front, back, surface); + + int seconds, minutes, hours; + getTimeFromCountdown(seconds, minutes, hours); + drawStringInSurface(Common::String::format("%02d", hours), 207, 8, front, back, surface); + drawStringInSurface(Common::String::format("%02d", minutes), 230, 8, front, back, surface); + drawStringInSurface(Common::String::format("%02d", seconds), 254, 8, front, back, surface); + + Common::String message; + int deadline; + getLatestMessages(message, deadline); + if (deadline <= _countdown) { + drawStringInSurface(message, 191, 176, back, front, surface); + _temporaryMessages.push_back(message); + _temporaryMessageDeadlines.push_back(deadline); + } else { + /*if (_currentArea->_gasPocketRadius == 0) + message = _messagesList[2]; + else if (_drillStatusByArea[_currentArea->getAreaID()]) + message = _messagesList[0]; + else*/ + message = _messagesList[1]; + drawStringInSurface(message, 191, 176, front, back, surface); + } + + uint32 green = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0x68, 0xa9, 0x41); + int energy = _gameStateVars[k8bitVariableEnergy]; + int shield = _gameStateVars[k8bitVariableShield]; + + if (energy >= 0) { + Common::Rect backBar(21, 183, 85 - energy, 190); + surface->fillRect(backBar, back); + Common::Rect energyBar(84 - energy, 184, 84, 190); + surface->fillRect(energyBar, green); + } + + if (shield >= 0) { + Common::Rect backBar(25 - 4, 180 - 4, 89 - shield - 4, 186 - 4); + surface->fillRect(backBar, back); + + Common::Rect shieldBar(88 - 4 - shield, 180 - 4, 88 - 4, 186 - 4); + surface->fillRect(shieldBar, green); + } +} + +} // End of namespace Freescape \ No newline at end of file diff --git a/engines/freescape/games/dark/dark.cpp b/engines/freescape/games/dark/dark.cpp index c2bf08dc266..29c8333dcc5 100644 --- a/engines/freescape/games/dark/dark.cpp +++ b/engines/freescape/games/dark/dark.cpp @@ -57,6 +57,8 @@ DarkEngine::DarkEngine(OSystem *syst, const ADGameDescription *gd) : FreescapeEn initDOS(); else if (isSpectrum()) initZX(); + else if (isC64()) + initC64(); else if (isCPC()) initCPC(); else if (isAmiga() || isAtariST()) diff --git a/engines/freescape/games/dark/dark.h b/engines/freescape/games/dark/dark.h index 5adaf7da938..e2eaef2e173 100644 --- a/engines/freescape/games/dark/dark.h +++ b/engines/freescape/games/dark/dark.h @@ -63,6 +63,7 @@ public: void executePrint(FCLInstruction &instruction) override; void initDOS(); + void initC64(); void initAmigaAtari(); void initZX(); void initCPC(); @@ -70,6 +71,7 @@ public: void loadAssets() override; void loadAssetsDOSFullGame() override; void loadAssetsDOSDemo() override; + void loadAssetsC64FullGame() override; void loadAssetsAmigaFullGame() override; void loadAssetsAtariFullGame() override; @@ -88,6 +90,7 @@ public: void drawSensorShoot(Sensor *sensor) override; void drawDOSUI(Graphics::Surface *surface) override; + void drawC64UI(Graphics::Surface *surface) override; void drawZXUI(Graphics::Surface *surface) override; void drawCPCUI(Graphics::Surface *surface) override; void drawAmigaAtariSTUI(Graphics::Surface *surface) override; diff --git a/engines/freescape/games/palettes.cpp b/engines/freescape/games/palettes.cpp index 94d3f046e70..0f881f2b9fa 100644 --- a/engines/freescape/games/palettes.cpp +++ b/engines/freescape/games/palettes.cpp @@ -218,7 +218,7 @@ void FreescapeEngine::swapPalette(uint16 levelID) { _gfx->_paperColor = _areaMap[levelID]->_paperColor; _gfx->_underFireBackgroundColor = _areaMap[levelID]->_underFireBackgroundColor; - if (!_border) + if (!_border || isC64()) // C64 does not have to process the border return; byte *palette = (byte *)malloc(sizeof(byte) * 4 * 3); diff --git a/engines/freescape/gfx.cpp b/engines/freescape/gfx.cpp index 5200ca6c9d3..94674411478 100644 --- a/engines/freescape/gfx.cpp +++ b/engines/freescape/gfx.cpp @@ -185,7 +185,7 @@ void Renderer::fillColorPairArray() { else if (_renderMode == Common::kRenderCPC) c1 = getCPCPixel(entry[0], 0, true); else if (_renderMode == Common::kRenderC64) - c1 = getC64Pixel(entry[0], 0); + c1 = getCPCPixel(entry[0], 0, true); else error("Not implemented"); @@ -199,7 +199,7 @@ void Renderer::fillColorPairArray() { else if (_renderMode == Common::kRenderCPC) c = getCPCPixel(entry[j], k, true); else if (_renderMode == Common::kRenderC64) - c = getC64Pixel(entry[j], k); + c = getCPCPixel(entry[j], k, true); else error("Not implemented"); if (c1 != c) { @@ -276,7 +276,7 @@ void Renderer::setColorMap(ColorMap *colorMap_) { for (int j = 0; j < 128; j++) _stipples[i][j] = getCGAStipple(entry[(j / 8) % 4], c1, c2); } - } /*else if (_renderMode == Common::kRenderC64) { + } else if (_renderMode == Common::kRenderC64) { fillColorPairArray(); for (int i = 4; i < 15; i++) { byte pair = _colorPair[i]; @@ -284,9 +284,9 @@ void Renderer::setColorMap(ColorMap *colorMap_) { byte c2 = (pair >> 4) & 0xf; byte *entry = (*_colorMap)[i]; for (int j = 0; j < 128; j++) - _stipples[i][j] = getC64Stipple(entry[(j / 8) % 4], c1, c2); + _stipples[i][j] = getCPCStipple(entry[(j / 8) % 4], c1, c2); } - }*/ + } if (_isAccelerated && _authenticGraphics) { for (int i = 1; i <= 14; i++) { @@ -363,6 +363,27 @@ void Renderer::extractC64Indexes(uint8 cm1, uint8 cm2, uint8 &i1, uint8 &i2) { } else if (cm1 == 0x41 && cm2 == 0x52) { i1 = 0; i2 = 3; + } else if (cm1 == 0xdd && cm2 == 0xdd) { + i1 = 3; + i2 = 3; + } else if (cm1 == 0xaa && cm2 == 0x55) { + i1 = 3; + i2 = 1; + } else if (cm1 == 0x05 && cm2 == 0x0a) { + i1 = 1; + i2 = 0; + } else if (cm1 == 0xf5 && cm2 == 0xfa) { + i1 = 2; + i2 = 2; + } else if (cm1 == 0x50 && cm2 == 0xa0) { + i1 = 2; + i2 = 2; + } else if (cm1 == 0x5f && cm2 == 0xaf) { + i1 = 2; + i2 = 2; + } else if (cm1 == 0x5a && cm2 == 0xa5) { + i1 = 2; + i2 = 2; } else { i1 = 0; i2 = 0; @@ -370,27 +391,37 @@ void Renderer::extractC64Indexes(uint8 cm1, uint8 cm2, uint8 &i1, uint8 &i2) { } -bool Renderer::getRGBAtC64(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2) { +bool Renderer::getRGBAtC64(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2, byte *&stipple) { if (index == _keyColor) return false; - if (index <= 4) { // Solid colors - selectColorFromFourColorPalette(index - 1, r1, g1, b1); + if (_colorRemaps && _colorRemaps->contains(index)) { + index = (*_colorRemaps)[index]; + if (index == 0) { + r1 = g1 = b1 = 0; + r2 = r1; + g2 = g1; + b2 = b1; + stipple = nullptr; + return true; + } + readFromPalette(index, r1, g1, b1); r2 = r1; g2 = g1; b2 = b1; + stipple = nullptr; return true; } - - uint8 i1, i2; + assert (_renderMode == Common::kRenderC64); + stipple = (byte *)_stipples[index - 1]; byte *entry = (*_colorMap)[index - 1]; - uint8 cm1 = *(entry); - entry++; - uint8 cm2 = *(entry); - - extractC64Indexes(cm1, cm2, i1, i2); + uint8 i1 = getCPCPixel(entry[0], 0, true); + uint8 i2 = getCPCPixel(entry[0], 1, true); selectColorFromFourColorPalette(i1, r1, g1, b1); selectColorFromFourColorPalette(i2, r2, g2, b2); + if (r1 == r2 && g1 == g2 && b1 == b2) { + stipple = nullptr; + } return true; } @@ -573,7 +604,7 @@ bool Renderer::getRGBAt(uint8 index, uint8 ecolor, uint8 &r1, uint8 &g1, uint8 & } else if (_renderMode == Common::kRenderEGA) return getRGBAtEGA(index, r1, g1, b1, r2, g2, b2); else if (_renderMode == Common::kRenderC64) - return getRGBAtC64(index, r1, g1, b1, r2, g2, b2); + return getRGBAtC64(index, r1, g1, b1, r2, g2, b2, stipple); else if (_renderMode == Common::kRenderCGA) return getRGBAtCGA(index, r1, g1, b1, r2, g2, b2, stipple); else if (_renderMode == Common::kRenderCPC) diff --git a/engines/freescape/gfx.h b/engines/freescape/gfx.h index 24506afd9d9..1fcaa207d3a 100644 --- a/engines/freescape/gfx.h +++ b/engines/freescape/gfx.h @@ -116,7 +116,7 @@ public: uint8 mapEGAColor(uint8 index); bool getRGBAt(uint8 index, uint8 ecolor, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2, byte *&stipple); - bool getRGBAtC64(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2); + bool getRGBAtC64(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2, byte *&stipple); bool getRGBAtCGA(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2, byte *&stipple); bool getRGBAtCPC(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2, byte *&stipple); bool getRGBAtEGA(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2); diff --git a/engines/freescape/loaders/8bitBinaryLoader.cpp b/engines/freescape/loaders/8bitBinaryLoader.cpp index 40e64ea4e53..76404059b38 100644 --- a/engines/freescape/loaders/8bitBinaryLoader.cpp +++ b/engines/freescape/loaders/8bitBinaryLoader.cpp @@ -344,6 +344,9 @@ Object *FreescapeEngine::load8bitObject(Common::SeekableReadStream *file) { readArray(file, byteSizeOfObject - 9); return nullptr; } + if (isC64() && isDark()) + objectType = (ObjectType)(objectType % ObjectType::kGroupType); + assert(objectType <= ObjectType::kGroupType); assert(byteSizeOfObject >= 9); byteSizeOfObject = byteSizeOfObject - 9; diff --git a/engines/freescape/module.mk b/engines/freescape/module.mk index 556ec728153..9c860d08f8b 100644 --- a/engines/freescape/module.mk +++ b/engines/freescape/module.mk @@ -14,6 +14,7 @@ MODULE_OBJS := \ games/castle/zx.o \ games/dark/amiga.o \ games/dark/atari.o \ + games/dark/c64.o \ games/dark/cpc.o \ games/dark/dark.o \ games/dark/dos.o \