[Scummvm-git-logs] scummvm master -> 1fdee2957a6dcb59a8fbd7e851a08c2c08b6bac3
neuromancer
noreply at scummvm.org
Tue Nov 18 22:16:13 UTC 2025
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
1fdee2957a FREESCAPE: initial implementation for loading Virtual Worlds compressed data for Atari ST (driller)
Commit: 1fdee2957a6dcb59a8fbd7e851a08c2c08b6bac3
https://github.com/scummvm/scummvm/commit/1fdee2957a6dcb59a8fbd7e851a08c2c08b6bac3
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-18T23:13:41+01:00
Commit Message:
FREESCAPE: initial implementation for loading Virtual Worlds compressed data for Atari ST (driller)
Changed paths:
engines/freescape/detection.cpp
engines/freescape/games/driller/atari.cpp
engines/freescape/games/driller/driller.h
diff --git a/engines/freescape/detection.cpp b/engines/freescape/detection.cpp
index df1fb850cb8..0f73184a86b 100644
--- a/engines/freescape/detection.cpp
+++ b/engines/freescape/detection.cpp
@@ -161,7 +161,7 @@ static const ADGameDescription gameDescriptions[] = {
{
// Virtual Worlds release
"driller",
- "This release requires unpacking, check the wiki for instructions: https://wiki.scummvm.org/index.php?title=Driller#AtariST_releases",
+ "",
{
{"d.pak", 0, "607b44b9d31e0da5668b653e03d25efe", 706},
{"dril.all", 0, "65277222effa1eb4d73b234245001d75", 158158},
@@ -169,7 +169,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformAtariST,
- ADGF_UNSUPPORTED,
+ ADGF_UNSTABLE | GF_ATARI_BUDGET,
GUIO3(GUIO_NOMIDI, GUIO_RENDERATARIST, GAMEOPTION_AUTOMATIC_DRILLING)
},
{
diff --git a/engines/freescape/games/driller/atari.cpp b/engines/freescape/games/driller/atari.cpp
index 188898b9c0d..90af8fbeff0 100644
--- a/engines/freescape/games/driller/atari.cpp
+++ b/engines/freescape/games/driller/atari.cpp
@@ -20,6 +20,7 @@
*/
#include "common/file.h"
#include "common/memstream.h"
+#include "common/endian.h"
#include "freescape/freescape.h"
#include "freescape/games/driller/driller.h"
@@ -27,6 +28,149 @@
namespace Freescape {
+Common::SeekableReadStream *DrillerEngine::decryptFileAtariVirtualWorlds(const Common::Path &filename) {
+ Common::File file;
+ if (!file.open(filename)) {
+ error("Failed to open %s", filename.toString().c_str());
+ }
+ const int size = file.size();
+ byte *data = (byte *)malloc(size);
+ file.read(data, size);
+
+ int start = 0;
+ int valid_offset = -1;
+ int chunk_size = 0;
+
+ while (true) {
+ byte *found = (byte *)memmem(data + start, size - start, "CBCP", 4);
+ if (!found) break;
+
+ int idx = found - data;
+ if (idx + 8 <= size) {
+ int sz = READ_BE_UINT32(data + idx + 4);
+ if (sz > 0 && sz < size + 0x20000) {
+ valid_offset = idx;
+ chunk_size = sz;
+ }
+ }
+ start = idx + 1;
+ }
+
+ if (valid_offset == -1) {
+ error("No valid CBCP chunk found in %s", filename.toString().c_str());
+ }
+
+ const byte *payload = data + valid_offset + 8;
+ const int payload_size = chunk_size;
+
+ if (payload_size < 12) {
+ error("Payload too short in %s", filename.toString().c_str());
+ }
+
+ uint32 bit_buf_init = READ_BE_UINT32(payload + payload_size - 12);
+ uint32 checksum_init = READ_BE_UINT32(payload + payload_size - 8);
+ uint32 decoded_size = READ_BE_UINT32(payload + payload_size - 4);
+
+ byte *out_buffer = (byte *)malloc(decoded_size);
+ int dst_idx = decoded_size;
+
+ struct BitStream {
+ const byte *_src_data;
+ int _src_idx;
+ uint32 _bit_buffer;
+ uint32 _checksum;
+ int _refill_carry;
+
+ BitStream(const byte *src_data, int start_idx, uint32 bit_buffer, uint32 checksum) :
+ _src_data(src_data), _src_idx(start_idx), _bit_buffer(bit_buffer), _checksum(checksum), _refill_carry(0) {}
+
+ void refill() {
+ if (_src_idx < 0) {
+ _refill_carry = 0;
+ _bit_buffer = 0x80000000;
+ return;
+ }
+ uint32 val = READ_BE_UINT32(_src_data + _src_idx);
+ _src_idx -= 4;
+ _checksum ^= val;
+ _refill_carry = val & 1;
+ _bit_buffer = (val >> 1) | 0x80000000;
+ }
+
+ int getBits(int count) {
+ uint32 result = 0;
+ for (int i = 0; i < count; ++i) {
+ int carry = _bit_buffer & 1;
+ _bit_buffer >>= 1;
+ if (_bit_buffer == 0) {
+ refill();
+ carry = _refill_carry;
+ }
+ result = (result << 1) | carry;
+ }
+ return result;
+ }
+ };
+
+ int src_idx = payload_size - 16;
+ uint32 checksum = checksum_init ^ bit_buf_init;
+ BitStream bs(payload, src_idx, bit_buf_init, checksum);
+
+ while (dst_idx > 0) {
+ if (bs.getBits(1) == 0) {
+ if (bs.getBits(1) == 1) {
+ int offset = bs.getBits(8);
+ for (int i = 0; i < 2; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = out_buffer[dst_idx + offset];
+ }
+ }
+ } else {
+ int count = bs.getBits(3) + 1;
+ for (int i = 0; i < count; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = bs.getBits(8);
+ }
+ }
+ }
+ } else {
+ int tag = bs.getBits(2);
+ if (tag == 3) {
+ int count = bs.getBits(8) + 9;
+ for (int i = 0; i < count; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = bs.getBits(8);
+ }
+ }
+ } else if (tag == 2) {
+ int length = bs.getBits(8) + 1;
+ int offset = bs.getBits(12);
+ for (int i = 0; i < length; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = out_buffer[dst_idx + offset];
+ }
+ }
+ } else {
+ int bits_offset = 9 + tag;
+ int length = 3 + tag;
+ int offset = bs.getBits(bits_offset);
+ for (int i = 0; i < length; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = out_buffer[dst_idx + offset];
+ }
+ }
+ }
+ }
+ }
+ free(data);
+ return new Common::MemoryReadStream(out_buffer, decoded_size);
+}
+
Common::SeekableReadStream *DrillerEngine::decryptFileAtari(const Common::Path &filename) {
Common::File file;
file.open(filename);
@@ -61,9 +205,9 @@ Common::SeekableReadStream *DrillerEngine::decryptFileAtari(const Common::Path &
}
void DrillerEngine::loadAssetsAtariFullGame() {
-
+ Common::SeekableReadStream *stream = nullptr;
if (_variant & GF_ATARI_RETAIL) {
- Common::SeekableReadStream *stream = decryptFileAtari("x.prg");
+ stream = decryptFileAtari("x.prg");
_border = loadAndConvertNeoImage(stream, 0x14b96);
_borderExtra = loadAndConvertNeoImage(stream, 0x1c916);
@@ -84,8 +228,10 @@ void DrillerEngine::loadAssetsAtariFullGame() {
Common::File file;
file.open("x.prg");
- if (!file.isOpen())
- error("Failed to open 'x.prg' executable for AtariST");
+ if (!file.isOpen()) {
+ stream = decryptFileAtariVirtualWorlds("dril.all");
+ } else
+ stream = &file;
if (isSpaceStationOblivion()) {
_border = loadAndConvertNeoImage(&file, 0x13544);
@@ -104,23 +250,24 @@ void DrillerEngine::loadAssetsAtariFullGame() {
loadPalettes(&file, 0x296fa - 0x1d6);
loadSoundsFx(&file, 0x30da6 - 0x1d6, 25);
} else {
- _border = loadAndConvertNeoImage(&file, 0x1371a);
- _title = loadAndConvertNeoImage(&file, 0x396);
+ _border = loadAndConvertNeoImage(stream, 0x1371a);
+ _title = loadAndConvertNeoImage(stream, 0x396);
- loadFonts(&file, 0x8a32);
+ loadFonts(stream, 0x8a32);
Common::Array<Graphics::ManagedSurface *> chars;
- chars = getCharsAmigaAtariInternal(8, 8, -3, 33, 32, &file, 0x8a32 + 112 * 33 + 1, 100);
+ chars = getCharsAmigaAtariInternal(8, 8, -3, 33, 32, stream, 0x8a32 + 112 * 33 + 1, 100);
_fontSmall = Font(chars);
_fontSmall.setCharWidth(5);
- loadMessagesFixedSize(&file, 0xc5d8, 14, 20);
- loadGlobalObjects(&file, 0xbccc, 8);
- load8bitBinary(&file, 0x29b3c, 16);
- loadPalettes(&file, 0x296fa);
- loadSoundsFx(&file, 0x30da6, 25);
+ loadMessagesFixedSize(stream, 0xc5d8, 14, 20);
+ loadGlobalObjects(stream, 0xbccc, 8);
+ load8bitBinary(stream, 0x29b3c, 16);
+ loadPalettes(stream, 0x296fa);
+ loadSoundsFx(stream, 0x30da6, 25);
}
- }
+ } else
+ error("Unknown Atari ST Driller variant");
for (auto &area : _areaMap) {
// Center and pad each area name so we do not have to do it at each frame
diff --git a/engines/freescape/games/driller/driller.h b/engines/freescape/games/driller/driller.h
index e39c7b53492..5d0ab47deef 100644
--- a/engines/freescape/games/driller/driller.h
+++ b/engines/freescape/games/driller/driller.h
@@ -124,6 +124,7 @@ private:
Texture *_borderExtraTexture;
Common::SeekableReadStream *decryptFileAtari(const Common::Path &filename);
+ Common::SeekableReadStream *decryptFileAtariVirtualWorlds(const Common::Path &filename);
};
enum DrillerReleaseFlags {
More information about the Scummvm-git-logs
mailing list