/* 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 "common/memstream.h" #include "freescape/freescape.h" #include "freescape/games/driller/driller.h" #include "freescape/language/8bitDetokeniser.h" namespace Freescape { void DrillerEngine::initCPC() { _viewArea = Common::Rect(36, 16, 284, 117); } byte kCPCPaletteTitleData[4][3] = { {0x00, 0x00, 0x00}, {0x00, 0x80, 0xff}, {0xff, 0x00, 0x00}, {0xff, 0xff, 0x00}, }; byte kCPCPaletteBorderData[4][3] = { {0x00, 0x00, 0x00}, {0xff, 0x80, 0x00}, {0x80, 0xff, 0xff}, {0x00, 0x80, 0x00}, }; byte getCPCPixelMode1(byte cpc_byte, int index) { if (index == 0) return ((cpc_byte & 0x08) >> 2) | ((cpc_byte & 0x80) >> 7); else if (index == 1) return ((cpc_byte & 0x04) >> 1) | ((cpc_byte & 0x40) >> 6); else if (index == 2) return (cpc_byte & 0x02) | ((cpc_byte & 0x20) >> 5); else if (index == 3) return ((cpc_byte & 0x01) << 1) | ((cpc_byte & 0x10) >> 4); else error("Invalid index %d requested", index); } byte getCPCPixelMode0(byte cpc_byte, int index) { if (index == 0) { // Extract Pixel 0 from the byte return ((cpc_byte & 0x02) >> 1) | // Bit 1 -> Bit 3 (MSB) ((cpc_byte & 0x20) >> 4) | // Bit 5 -> Bit 2 ((cpc_byte & 0x08) >> 1) | // Bit 3 -> Bit 1 ((cpc_byte & 0x80) >> 7); // Bit 7 -> Bit 0 (LSB) } else if (index == 2) { // Extract Pixel 1 from the byte return ((cpc_byte & 0x01) << 3) | // Bit 0 -> Bit 3 (MSB) ((cpc_byte & 0x10) >> 2) | // Bit 4 -> Bit 2 ((cpc_byte & 0x04) >> 1) | // Bit 2 -> Bit 1 ((cpc_byte & 0x40) >> 6); // Bit 6 -> Bit 0 (LSB) } else { error("Invalid index %d requested", index); } } byte getCPCPixel(byte cpc_byte, int index, bool mode1) { if (mode1) return getCPCPixelMode1(cpc_byte, index); else return getCPCPixelMode0(cpc_byte, index); } Graphics::ManagedSurface *readCPCImage(Common::SeekableReadStream *file, bool mode1) { Graphics::ManagedSurface *surface = new Graphics::ManagedSurface(); surface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); surface->fillRect(Common::Rect(0, 0, 320, 200), 0); int x, y; file->seek(0x80); for (int block = 0; block < 8; block++) { for (int line = 0; line < 25; line++) { for (int offset = 0; offset < 320 / 4; offset++) { byte cpc_byte = file->readByte(); // Get CPC byte // Process first pixel int pixel_0 = getCPCPixel(cpc_byte, 0, mode1); // %Aa y = line * 8 + block ; // Coord Y for the pixel x = 4 * offset + 0; // Coord X for the pixel surface->setPixel(x, y, pixel_0); // Process second pixel y = line * 8 + block ; // Coord Y for the pixel x = 4 * offset + 1; // Coord X for the pixel if (mode1) { int pixel_1 = getCPCPixel(cpc_byte, 1, mode1); // %Bb surface->setPixel(x, y, pixel_1); } else surface->setPixel(x, y, pixel_0); // Process third pixel int pixel_2 = getCPCPixel(cpc_byte, 2, mode1); // %Cc y = line * 8 + block ; // Coord Y for the pixel x = 4 * offset + 2; // Coord X for the pixel surface->setPixel(x, y, pixel_2); // Process fourth pixel y = line * 8 + block ; // Coord Y for the pixel x = 4 * offset + 3; // Coord X for the pixel if (mode1) { int pixel_3 = getCPCPixel(cpc_byte, 3, mode1); // %Dd surface->setPixel(x, y, pixel_3); } else surface->setPixel(x, y, pixel_2); } } // We should skip the next 48 bytes, because they are padding the block to be 2048 bytes file->seek(48, SEEK_CUR); } return surface; } void DrillerEngine::loadAssetsCPCFullGame() { Common::File file; file.open("DSCN1.BIN"); if (!file.isOpen()) error("Failed to open DSCN1.BIN"); _title = readCPCImage(&file, true); _title->setPalette((byte*)&kCPCPaletteTitleData, 0, 4); file.close(); file.open("DSCN2.BIN"); if (!file.isOpen()) error("Failed to open DSCN2.BIN"); _border = readCPCImage(&file, true); _border->setPalette((byte*)&kCPCPaletteBorderData, 0, 4); file.close(); file.open("DRILL.BIN"); if (!file.isOpen()) error("Failed to open DRILL.BIN"); loadMessagesFixedSize(&file, 0x214c, 14, 20); loadFonts(&file, 0x5b69); loadGlobalObjects(&file, 0x1d07, 8); load8bitBinary(&file, 0x5ccb, 16); } void DrillerEngine::drawCPCUI(Graphics::Surface *surface) { uint32 color = _currentArea->_underFireBackgroundColor; uint8 r, g, b; _gfx->readFromPalette(color, r, g, b); uint32 front = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b); color = _currentArea->_usualBackgroundColor; 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, 185, front, back, surface); drawStringInSurface(Common::String::format("%04d", int(2 * _position.x())), 151, 145, front, back, surface); drawStringInSurface(Common::String::format("%04d", int(2 * _position.z())), 151, 153, front, back, surface); drawStringInSurface(Common::String::format("%04d", int(2 * _position.y())), 151, 161, front, back, surface); if (_playerHeightNumber >= 0) drawStringInSurface(Common::String::format("%d", _playerHeightNumber), 54, 161, front, back, surface); else drawStringInSurface(Common::String::format("%s", "J"), 54, 161, front, back, surface); drawStringInSurface(Common::String::format("%02d", int(_angleRotations[_angleRotationIndex])), 47, 145, front, back, surface); drawStringInSurface(Common::String::format("%3d", _playerSteps[_playerStepIndex]), 44, 153, front, back, surface); drawStringInSurface(Common::String::format("%07d", score), 239, 129, front, back, surface); int seconds, minutes, hours; getTimeFromCountdown(seconds, minutes, hours); drawStringInSurface(Common::String::format("%02d", hours), 209, 8, front, back, surface); drawStringInSurface(Common::String::format("%02d", minutes), 232, 8, front, back, surface); drawStringInSurface(Common::String::format("%02d", seconds), 255, 8, front, back, surface); Common::String message; int deadline; getLatestMessages(message, deadline); if (deadline <= _countdown) { drawStringInSurface(message, 191, 177, back, front, surface); _temporaryMessages.push_back(message); _temporaryMessageDeadlines.push_back(deadline); } else if (_messagesList.size() > 0) { if (_currentArea->_gasPocketRadius == 0) message = _messagesList[2]; else if (_drillStatusByArea[_currentArea->getAreaID()]) message = _messagesList[0]; else message = _messagesList[1]; drawStringInSurface(message, 191, 177, front, back, surface); } int energy = _gameStateVars[k8bitVariableEnergy]; int shield = _gameStateVars[k8bitVariableShield]; if (energy >= 0) { Common::Rect backBar(25, 184, 89 - energy, 191); surface->fillRect(backBar, back); Common::Rect energyBar(88 - energy, 184, 88, 191); surface->fillRect(energyBar, front); } if (shield >= 0) { Common::Rect backBar(25, 177, 89 - shield, 183); surface->fillRect(backBar, back); Common::Rect shieldBar(88 - shield, 177, 88, 183); surface->fillRect(shieldBar, front); } drawCompass(surface, 87, 156, _yaw - 30, 10, 75, front); drawCompass(surface, 230, 156, _pitch - 30, 10, 60, front); } } // End of namespace Freescape