Import 0.4.8
This commit is contained in:
parent
bc1337da63
commit
315bb9bcff
|
@ -1,3 +1,8 @@
|
|||
* release 0.4.8
|
||||
- added detection for DOS version with .ABA files
|
||||
- added Macintosh credits
|
||||
- fixed ESPIONS cutscene timing with Amiga music
|
||||
|
||||
* release 0.4.7
|
||||
- added detection for Macintosh CD version
|
||||
- restored some content from MEMO cutscene
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
REminiscence README
|
||||
Release version: 0.4.7
|
||||
Release version: 0.4.8
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
102
cutscene.cpp
102
cutscene.cpp
|
@ -147,8 +147,14 @@ uint16_t Cutscene::findTextSeparators(const uint8_t *p, int len) {
|
|||
void Cutscene::drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color, uint8_t *page, int textJustify) {
|
||||
debug(DBG_CUT, "Cutscene::drawText(x=%d, y=%d, c=%d, justify=%d)", x, y, color, textJustify);
|
||||
int len = 0;
|
||||
if (_res->_type == kResourceTypeMac) {
|
||||
if (_res->isMac()) {
|
||||
if (p == _textBuf) {
|
||||
while (p[len] != 0xA) {
|
||||
++len;
|
||||
}
|
||||
} else {
|
||||
len = *p++;
|
||||
}
|
||||
} else {
|
||||
len = strlen((const char *)p);
|
||||
}
|
||||
|
@ -197,16 +203,39 @@ void Cutscene::clearBackPage() {
|
|||
|
||||
void Cutscene::drawCreditsText() {
|
||||
if (_creditsSequence) {
|
||||
if (_creditsKeepText != 0) {
|
||||
if (_creditsSlowText == 0) {
|
||||
_creditsKeepText = 0;
|
||||
} else {
|
||||
if (_creditsKeepText) {
|
||||
if (_creditsSlowText) {
|
||||
return;
|
||||
}
|
||||
_creditsKeepText = false;
|
||||
}
|
||||
if (_creditsTextCounter <= 0) {
|
||||
const uint8_t code = *_textCurPtr;
|
||||
if (code == 0xFF) {
|
||||
uint8_t code;
|
||||
const bool isMac = _res->isMac();
|
||||
if (isMac && _creditsTextLen <= 0) {
|
||||
const uint8_t *p = _res->getCreditsString(_creditsTextIndex++);
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
_creditsTextCounter = 60;
|
||||
_creditsTextPosX = p[0];
|
||||
_creditsTextPosY = p[1];
|
||||
_creditsTextLen = p[2];
|
||||
_textCurPtr = p + 2;
|
||||
code = 0;
|
||||
} else {
|
||||
code = *_textCurPtr;
|
||||
}
|
||||
if (code == 0x7D && isMac) {
|
||||
++_textCurPtr;
|
||||
code = *_textCurPtr++;
|
||||
_creditsTextLen -= 2;
|
||||
assert(code > 0x30);
|
||||
for (int i = 0; i < (code - 0x30); ++i) {
|
||||
*_textCurBuf++ = ' ';
|
||||
}
|
||||
*_textCurBuf = 0xA;
|
||||
} else if (code == 0xFF) {
|
||||
_textBuf[0] = 0xA;
|
||||
} else if (code == 0xFE) {
|
||||
++_textCurPtr;
|
||||
|
@ -219,13 +248,19 @@ void Cutscene::drawCreditsText() {
|
|||
_textCurBuf = _textBuf;
|
||||
_textBuf[0] = 0xA;
|
||||
++_textCurPtr;
|
||||
if (_creditsSlowText != 0) {
|
||||
_creditsKeepText = 0xFF;
|
||||
if (_creditsSlowText) {
|
||||
_creditsKeepText = true;
|
||||
}
|
||||
} else {
|
||||
*_textCurBuf++ = code;
|
||||
*_textCurBuf = 0xA;
|
||||
++_textCurPtr;
|
||||
if (isMac) {
|
||||
--_creditsTextLen;
|
||||
if (_creditsTextLen == 0) {
|
||||
_creditsTextCounter = 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_creditsTextCounter -= 10;
|
||||
|
@ -276,7 +311,7 @@ void Cutscene::op_markCurPos() {
|
|||
_frameDelay = 5;
|
||||
updateScreen();
|
||||
clearBackPage();
|
||||
_creditsSlowText = 0;
|
||||
_creditsSlowText = false;
|
||||
}
|
||||
|
||||
void Cutscene::op_refreshScreen() {
|
||||
|
@ -284,7 +319,7 @@ void Cutscene::op_refreshScreen() {
|
|||
_clearScreen = fetchNextCmdByte();
|
||||
if (_clearScreen != 0) {
|
||||
clearBackPage();
|
||||
_creditsSlowText = 0;
|
||||
_creditsSlowText = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,17 +328,17 @@ void Cutscene::op_waitForSync() {
|
|||
if (_creditsSequence) {
|
||||
uint16_t n = fetchNextCmdByte() * 2;
|
||||
do {
|
||||
_creditsSlowText = 0xFF;
|
||||
_creditsSlowText = true;
|
||||
_frameDelay = 3;
|
||||
if (_textBuf == _textCurBuf) {
|
||||
_creditsTextCounter = _res->isAmiga() ? 60 : 20;
|
||||
_creditsTextCounter = _res->isDOS() ? 20 : 60;
|
||||
}
|
||||
memcpy(_backPage, _frontPage, _vid->_layerSize);
|
||||
drawCreditsText();
|
||||
updateScreen();
|
||||
} while (--n);
|
||||
clearBackPage();
|
||||
_creditsSlowText = 0;
|
||||
_creditsSlowText = false;
|
||||
} else {
|
||||
_frameDelay = fetchNextCmdByte() * 4;
|
||||
sync(); // XXX handle input
|
||||
|
@ -418,15 +453,6 @@ void Cutscene::op_drawCaptionText() {
|
|||
uint16_t strId = fetchNextCmdWord();
|
||||
if (!_creditsSequence) {
|
||||
|
||||
// 'espions' - ignore last call, allows caption to be displayed longer on the screen
|
||||
if (_id == 0x39 && strId == 0xFFFF) {
|
||||
if ((_res->isDOS() && (_cmdPtr - _cmdPtrBak) == 0x10) || (_res->isAmiga() && (_cmdPtr - getCommandData()) == 0x9F3)) {
|
||||
_frameDelay = 100;
|
||||
updateScreen();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const int h = 45 * _vid->_layerScale;
|
||||
const int y = Video::GAMESCREEN_H * _vid->_layerScale - h;
|
||||
|
||||
|
@ -439,6 +465,10 @@ void Cutscene::op_drawCaptionText() {
|
|||
drawText(0, 129, str, 0xEF, _backPage, kTextJustifyAlign);
|
||||
drawText(0, 129, str, 0xEF, _auxPage, kTextJustifyAlign);
|
||||
}
|
||||
} else if (_id == kCineEspions) {
|
||||
// cutscene relies on drawCaptionText opcodes for timing
|
||||
_frameDelay = 100;
|
||||
sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -457,7 +487,7 @@ void Cutscene::op_refreshAll() {
|
|||
_frameDelay = 5;
|
||||
updateScreen();
|
||||
clearBackPage();
|
||||
_creditsSlowText = 0xFF;
|
||||
_creditsSlowText = true;
|
||||
op_handleKeys();
|
||||
}
|
||||
|
||||
|
@ -634,7 +664,7 @@ void Cutscene::op_drawShapeScale() {
|
|||
_hasAlphaColor = (verticesOffset & 0x4000) != 0;
|
||||
uint8_t color = *shapeData++;
|
||||
if (_clearScreen == 0) {
|
||||
color += 0x10; // 2nd paletter buffer
|
||||
color += 0x10; // 2nd palette buffer
|
||||
}
|
||||
_primitiveColor = 0xC0 + color;
|
||||
drawShapeScale(p, zoom, dx, dy, x, y, 0, 0);
|
||||
|
@ -908,7 +938,7 @@ static int findSetPaletteColor(const uint16_t color, const uint16_t *paletteBuff
|
|||
|
||||
void Cutscene::op_copyScreen() {
|
||||
debug(DBG_CUT, "Cutscene::op_copyScreen()");
|
||||
_creditsSlowText = 0xFF;
|
||||
_creditsSlowText = true;
|
||||
if (_textCurBuf == _textBuf) {
|
||||
++_creditsTextCounter;
|
||||
}
|
||||
|
@ -954,11 +984,11 @@ void Cutscene::op_drawTextAtPos() {
|
|||
if (!_creditsSequence) {
|
||||
const uint8_t *str = _res->getCineString(strId & 0xFFF);
|
||||
if (str) {
|
||||
uint8_t color = 0xD0 + (strId >> 0xC);
|
||||
const uint8_t color = 0xD0 + (strId >> 0xC);
|
||||
drawText(x, y, str, color, _backPage, kTextJustifyCenter);
|
||||
}
|
||||
// 'voyage' - cutscene script redraws the string to refresh the screen
|
||||
if (_id == 0x34 && (strId & 0xFFF) == 0x45) {
|
||||
if (_id == kCineVoyage && (strId & 0xFFF) == 0x45) {
|
||||
if ((_cmdPtr - _cmdPtrBak) == 0xA) {
|
||||
_stub->copyRect(0, 0, _vid->_w, _vid->_h, _backPage, _vid->_w);
|
||||
_stub->updateScreen(0);
|
||||
|
@ -1099,9 +1129,9 @@ bool Cutscene::load(uint16_t cutName) {
|
|||
name = "SERRURE";
|
||||
}
|
||||
_res->load(name, Resource::OT_CMP);
|
||||
if (_id == 0x39 && _res->_lang != LANG_FR) {
|
||||
if (_id == kCineEspions) {
|
||||
//
|
||||
// 'espions' - '... the power which we need' caption is missing in Amiga English.
|
||||
// '... the power which we need' caption is missing.
|
||||
// fixed in DOS version, opcodes order is wrong
|
||||
//
|
||||
// opcode 0 pos 0x323
|
||||
|
@ -1167,15 +1197,17 @@ void Cutscene::prepare() {
|
|||
|
||||
void Cutscene::playCredits() {
|
||||
if (_res->isMac()) {
|
||||
warning("Cutscene::playCredits() unimplemented");
|
||||
return;
|
||||
}
|
||||
_res->MAC_loadCreditsText();
|
||||
_creditsTextIndex = 0;
|
||||
_creditsTextLen = 0;
|
||||
} else {
|
||||
_textCurPtr = _res->isAmiga() ? _creditsDataAmiga : _creditsDataDOS;
|
||||
}
|
||||
_textBuf[0] = 0xA;
|
||||
_textCurBuf = _textBuf;
|
||||
_creditsSequence = true;
|
||||
_creditsSlowText = 0;
|
||||
_creditsKeepText = 0;
|
||||
_creditsSlowText = false;
|
||||
_creditsKeepText = false;
|
||||
_creditsTextCounter = 0;
|
||||
_interrupted = false;
|
||||
const uint16_t *cut_seq = _creditsCutSeq;
|
||||
|
|
10
cutscene.h
10
cutscene.h
|
@ -30,7 +30,9 @@ struct Cutscene {
|
|||
};
|
||||
|
||||
enum {
|
||||
kCineMemo = 48
|
||||
kCineMemo = 48,
|
||||
kCineVoyage = 52,
|
||||
kCineEspions = 57
|
||||
};
|
||||
|
||||
struct SetShape {
|
||||
|
@ -104,11 +106,13 @@ struct Cutscene {
|
|||
uint8_t _textBuf[500];
|
||||
const uint8_t *_textCurPtr;
|
||||
uint8_t *_textCurBuf;
|
||||
uint8_t _creditsSlowText;
|
||||
uint8_t _creditsKeepText;
|
||||
bool _creditsSlowText;
|
||||
bool _creditsKeepText;
|
||||
uint8_t _creditsTextPosX;
|
||||
uint8_t _creditsTextPosY;
|
||||
int16_t _creditsTextCounter;
|
||||
int _creditsTextIndex; /* MAC has the credits data in a resource */
|
||||
int _creditsTextLen;
|
||||
uint8_t *_frontPage, *_backPage, *_auxPage;
|
||||
|
||||
Cutscene(Resource *res, SystemStub *stub, Video *vid);
|
||||
|
|
|
@ -3,11 +3,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "decode_mac.h"
|
||||
#include "file.h"
|
||||
#include "util.h"
|
||||
|
||||
uint8_t *decodeLzss(File &f, uint32_t &decodedSize) {
|
||||
decodedSize = f.readUint32BE();
|
||||
uint8_t *dst = (uint8_t *)malloc(decodedSize);
|
||||
if (!dst) {
|
||||
warning("Failed to allocate %d bytes for LZSS", decodedSize);
|
||||
return 0;
|
||||
}
|
||||
uint32_t count = 0;
|
||||
while (count < decodedSize) {
|
||||
const int code = f.readByte();
|
||||
|
|
6
game.cpp
6
game.cpp
|
@ -11,7 +11,6 @@
|
|||
#include "game.h"
|
||||
#include "seq_player.h"
|
||||
#include "systemstub.h"
|
||||
#include "unpack.h"
|
||||
#include "util.h"
|
||||
|
||||
Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, ResourceType ver, Language lang, WidescreenMode widescreenMode, bool autoSave)
|
||||
|
@ -557,7 +556,8 @@ void Game::playCutscene(int id) {
|
|||
_stub->setPaletteEntry(0xC0 + i, &palette[i]);
|
||||
}
|
||||
}
|
||||
if (id == 0x3D) {
|
||||
if (_cut._id == 0x3D) {
|
||||
_mix.playMusic(Mixer::MUSIC_TRACK + 9);
|
||||
_cut.playCredits();
|
||||
}
|
||||
_mix.stopMusic();
|
||||
|
@ -1678,7 +1678,7 @@ void Game::loadLevelData() {
|
|||
_res.load(lvl->name, Resource::OT_CT);
|
||||
_res.load(lvl->name, Resource::OT_PAL);
|
||||
_res.load(lvl->name, Resource::OT_RP);
|
||||
if (_res._isDemo || g_options.use_tile_data) { // use .BNQ/.LEV/(.SGD) instead of .MAP (PC demo)
|
||||
if (_res._isDemo || g_options.use_tile_data || _res._aba) { // use .BNQ/.LEV/(.SGD) instead of .MAP (PC demo)
|
||||
if (_currentLevel == 0) {
|
||||
_res.load(lvl->name, Resource::OT_SGD);
|
||||
}
|
||||
|
|
4
main.cpp
4
main.cpp
|
@ -35,6 +35,7 @@ static int detectVersion(FileSystem *fs) {
|
|||
const char *name;
|
||||
} table[] = {
|
||||
{ "DEMO_UK.ABA", kResourceTypeDOS, "DOS (Demo)" },
|
||||
{ "GLOB_FR.ABA", kResourceTypeDOS, "DOS" },
|
||||
{ "INTRO.SEQ", kResourceTypeDOS, "DOS CD" },
|
||||
{ "MENU1SSI.MAP", kResourceTypeDOS, "DOS SSI" },
|
||||
{ "LEVEL1.MAP", kResourceTypeDOS, "DOS" },
|
||||
|
@ -60,7 +61,8 @@ static Language detectLanguage(FileSystem *fs) {
|
|||
const char *filename;
|
||||
Language language;
|
||||
} table[] = {
|
||||
// PC
|
||||
// DOS
|
||||
{ "GLOB_FR.ABA", LANG_FR },
|
||||
{ "ENGCINE.TXT", LANG_EN },
|
||||
{ "FR_CINE.TXT", LANG_FR },
|
||||
{ "GERCINE.TXT", LANG_DE },
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* Copyright (C) 2005-2019 Gregory Montoir (cyx@users.sourceforge.net)
|
||||
*/
|
||||
|
||||
#include "cutscene.h"
|
||||
#include "game.h"
|
||||
#include "resource.h"
|
||||
#include "systemstub.h"
|
||||
|
|
94
resource.cpp
94
resource.cpp
|
@ -56,16 +56,27 @@ Resource::~Resource() {
|
|||
delete _mac;
|
||||
}
|
||||
|
||||
static const char *_demoAba = "DEMO_UK.ABA";
|
||||
|
||||
static const char *_joystickAba[] = {
|
||||
"GLOB1_FB.ABA", "GLOB2_FB.ABA", "GLOB_FR.ABA", 0
|
||||
};
|
||||
|
||||
void Resource::init() {
|
||||
switch (_type) {
|
||||
case kResourceTypeAmiga:
|
||||
_isDemo = _fs->exists("demo.lev");
|
||||
break;
|
||||
case kResourceTypeDOS:
|
||||
if (_fs->exists(ResourceAba::FILENAME)) { // fbdemous
|
||||
if (_fs->exists(_demoAba)) { // fbdemous
|
||||
_aba = new ResourceAba(_fs);
|
||||
_aba->readEntries();
|
||||
_aba->readEntries(_demoAba);
|
||||
_isDemo = true;
|
||||
} else if (_fs->exists(_joystickAba[0])) { // Joystick "Hors Serie" April 1996
|
||||
_aba = new ResourceAba(_fs);
|
||||
for (int i = 0; _joystickAba[i]; ++i) {
|
||||
_aba->readEntries(_joystickAba[i]);
|
||||
}
|
||||
} else if (!fileExists("LEVEL2.MAP")) { // fbdemofr (no cutscenes)
|
||||
_isDemo = true;
|
||||
}
|
||||
|
@ -403,7 +414,7 @@ void Resource::load_CINE() {
|
|||
case kResourceTypeDOS:
|
||||
if (_cine_off == 0) {
|
||||
snprintf(_entryName, sizeof(_entryName), "%sCINE.BIN", prefix);
|
||||
if (!_fs->exists(_entryName)) {
|
||||
if (!fileExists(_entryName)) {
|
||||
strcpy(_entryName, "ENGCINE.BIN");
|
||||
}
|
||||
File f;
|
||||
|
@ -428,7 +439,7 @@ void Resource::load_CINE() {
|
|||
}
|
||||
if (_cine_txt == 0) {
|
||||
snprintf(_entryName, sizeof(_entryName), "%sCINE.TXT", prefix);
|
||||
if (!_fs->exists(_entryName)) {
|
||||
if (!fileExists(_entryName)) {
|
||||
strcpy(_entryName, "ENGCINE.TXT");
|
||||
}
|
||||
File f;
|
||||
|
@ -699,7 +710,7 @@ void Resource::load(const char *objName, int objType, const char *ext) {
|
|||
_numSpc = READ_BE_UINT16(_spc) / 2;
|
||||
break;
|
||||
case OT_RP:
|
||||
if (size != 0x4A) {
|
||||
if (size != sizeof(_rp)) {
|
||||
error("Unexpected size %d for '%s'", size, _entryName);
|
||||
}
|
||||
memcpy(_rp, dat, size);
|
||||
|
@ -728,6 +739,10 @@ void Resource::load(const char *objName, int objType, const char *ext) {
|
|||
case OT_POL:
|
||||
_pol = dat;
|
||||
break;
|
||||
case OT_SGD:
|
||||
_sgd = dat;
|
||||
_sgd[0] = 0; // clear number of entries, fix first offset
|
||||
break;
|
||||
case OT_BNQ:
|
||||
_bnq = dat;
|
||||
break;
|
||||
|
@ -825,7 +840,7 @@ void Resource::load_SPRM(File *f) {
|
|||
|
||||
void Resource::load_RP(File *f) {
|
||||
debug(DBG_RES, "Resource::load_RP()");
|
||||
f->read(_rp, 0x4A);
|
||||
f->read(_rp, sizeof(_rp));
|
||||
}
|
||||
|
||||
void Resource::load_SPC(File *f) {
|
||||
|
@ -1430,7 +1445,7 @@ uint8_t *Resource::decodeResourceMacText(const char *name, const char *suffix) {
|
|||
snprintf(buf, sizeof(buf), "%s %s", name, suffix);
|
||||
const ResourceMacEntry *entry = _mac->findEntry(buf);
|
||||
if (entry) {
|
||||
return decodeResourceMacData(buf, false);
|
||||
return decodeResourceMacData(entry, false);
|
||||
} else { // CD version
|
||||
if (strcmp(name, "Flashback") == 0) {
|
||||
name = "Game";
|
||||
|
@ -1442,23 +1457,35 @@ uint8_t *Resource::decodeResourceMacText(const char *name, const char *suffix) {
|
|||
}
|
||||
|
||||
uint8_t *Resource::decodeResourceMacData(const char *name, bool decompressLzss) {
|
||||
_resourceMacDataSize = 0;
|
||||
uint8_t *data = 0;
|
||||
const ResourceMacEntry *entry = _mac->findEntry(name);
|
||||
if (entry) {
|
||||
data = decodeResourceMacData(entry, decompressLzss);
|
||||
} else {
|
||||
_resourceMacDataSize = 0;
|
||||
error("Resource '%s' not found", name);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t *Resource::decodeResourceMacData(const ResourceMacEntry *entry, bool decompressLzss) {
|
||||
assert(entry);
|
||||
_mac->_f.seek(_mac->_dataOffset + entry->dataOffset);
|
||||
_resourceMacDataSize = _mac->_f.readUint32BE();
|
||||
uint8_t *data = 0;
|
||||
if (decompressLzss) {
|
||||
data = decodeLzss(_mac->_f, _resourceMacDataSize);
|
||||
if (!data) {
|
||||
error("Failed to decompress '%s'", entry->name);
|
||||
}
|
||||
} else {
|
||||
data = (uint8_t *)malloc(_resourceMacDataSize);
|
||||
if (data) {
|
||||
if (!data) {
|
||||
error("Failed to allocate %d bytes for '%s'", _resourceMacDataSize, entry->name);
|
||||
} else {
|
||||
_mac->_f.read(data, _resourceMacDataSize);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error("Resource '%s' not found", name);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -1501,11 +1528,9 @@ void Resource::MAC_decodeDataCLUT(const uint8_t *ptr) {
|
|||
|
||||
void Resource::MAC_loadClutData() {
|
||||
uint8_t *ptr = decodeResourceMacData("Flashback colors", false);
|
||||
if (ptr) {
|
||||
MAC_decodeDataCLUT(ptr);
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::MAC_loadFontData() {
|
||||
_fnt = decodeResourceMacData("Font", true);
|
||||
|
@ -1575,46 +1600,36 @@ static const char *_macLevelNumbers[] = { "1", "2", "3", "4-1", "4-2", "5-1", "5
|
|||
|
||||
void Resource::MAC_loadLevelData(int level) {
|
||||
char name[64];
|
||||
|
||||
// .PGE
|
||||
snprintf(name, sizeof(name), "Level %s objects", _macLevelNumbers[level]);
|
||||
uint8_t *ptr = decodeResourceMacData(name, true);
|
||||
if (ptr) {
|
||||
decodePGE(ptr, _resourceMacDataSize);
|
||||
free(ptr);
|
||||
} else {
|
||||
error("Failed to load '%s'", name);
|
||||
}
|
||||
|
||||
// .ANI
|
||||
snprintf(name, sizeof(name), "Level %s sequences", _macLevelNumbers[level]);
|
||||
_ani = decodeResourceMacData(name, true);
|
||||
if (_ani) {
|
||||
assert(READ_BE_UINT16(_ani) == 0x48D);
|
||||
} else {
|
||||
error("Failed to load '%s'", name);
|
||||
}
|
||||
|
||||
// .OBJ
|
||||
snprintf(name, sizeof(name), "Level %s conditions", _macLevelNumbers[level]);
|
||||
ptr = decodeResourceMacData(name, true);
|
||||
if (ptr) {
|
||||
assert(READ_BE_UINT16(ptr) == 0xE6);
|
||||
decodeOBJ(ptr, _resourceMacDataSize);
|
||||
free(ptr);
|
||||
} else {
|
||||
error("Failed to load '%s'", name);
|
||||
}
|
||||
|
||||
// .CT
|
||||
snprintf(name, sizeof(name), "Level %c map", _macLevelNumbers[level][0]);
|
||||
ptr = decodeResourceMacData(name, true);
|
||||
if (ptr) {
|
||||
assert(_resourceMacDataSize == 0x1D00);
|
||||
memcpy(_ctData, ptr, _resourceMacDataSize);
|
||||
free(ptr);
|
||||
} else {
|
||||
error("Failed to load '%s'", name);
|
||||
}
|
||||
|
||||
// .SPC
|
||||
snprintf(name, sizeof(name), "Objects %c", _macLevelNumbers[level][0]);
|
||||
_spc = decodeResourceMacData(name, true);
|
||||
|
||||
// .TBN
|
||||
snprintf(name, sizeof(name), "Level %s", _macLevelNumbers[level]);
|
||||
_tbn = decodeResourceMacText(name, "names");
|
||||
|
@ -1626,11 +1641,9 @@ void Resource::MAC_loadLevelRoom(int level, int i, DecodeBuffer *dst) {
|
|||
char name[64];
|
||||
snprintf(name, sizeof(name), "Level %c Room %d", _macLevelNumbers[level][0], i);
|
||||
uint8_t *ptr = decodeResourceMacData(name, true);
|
||||
if (ptr) {
|
||||
MAC_decodeImageData(ptr, 0, dst);
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::MAC_clearClut16(Color *clut, uint8_t dest) {
|
||||
memset(&clut[dest * 16], 0, 16 * sizeof(Color));
|
||||
|
@ -1704,15 +1717,24 @@ void Resource::MAC_unloadCutscene() {
|
|||
}
|
||||
|
||||
void Resource::MAC_loadCutscene(const char *cutscene) {
|
||||
MAC_unloadCutscene();
|
||||
char name[32];
|
||||
free(_cmd);
|
||||
|
||||
snprintf(name, sizeof(name), "%s movie", cutscene);
|
||||
stringLowerCase(name);
|
||||
_cmd = decodeResourceMacData(name, true);
|
||||
free(_pol);
|
||||
const ResourceMacEntry *cmdEntry = _mac->findEntry(name);
|
||||
if (!cmdEntry) {
|
||||
return;
|
||||
}
|
||||
_cmd = decodeResourceMacData(cmdEntry, true);
|
||||
|
||||
snprintf(name, sizeof(name), "%s polygons", cutscene);
|
||||
stringLowerCase(name);
|
||||
_pol = decodeResourceMacData(name, true);
|
||||
const ResourceMacEntry *polEntry = _mac->findEntry(name);
|
||||
if (!polEntry) {
|
||||
return;
|
||||
}
|
||||
_pol = decodeResourceMacData(polEntry, true);
|
||||
}
|
||||
|
||||
void Resource::MAC_loadCutsceneText() {
|
||||
|
|
18
resource.h
18
resource.h
|
@ -137,13 +137,13 @@ struct Resource {
|
|||
uint8_t *_icn;
|
||||
int _icnLen;
|
||||
uint8_t *_tab;
|
||||
uint8_t *_spc; // BE
|
||||
uint8_t *_spc;
|
||||
uint16_t _numSpc;
|
||||
uint8_t _rp[0x4A];
|
||||
uint8_t *_pal; // BE
|
||||
uint8_t _rp[74];
|
||||
uint8_t *_pal;
|
||||
uint8_t *_ani;
|
||||
uint8_t *_tbn;
|
||||
int8_t _ctData[0x1D00];
|
||||
int8_t _ctData[256 + 112 * 64];
|
||||
uint8_t *_spr1;
|
||||
uint8_t *_sprData[NUM_SPRITES]; // 0-0x22F + 0x28E-0x2E9 ... conrad, 0x22F-0x28D : junkie
|
||||
uint8_t _sprm[0x10000];
|
||||
|
@ -313,6 +313,15 @@ struct Resource {
|
|||
const char *getMenuString(int num) const {
|
||||
return (num >= 0 && num < LocaleData::LI_NUM) ? _textsTable[num] : "";
|
||||
}
|
||||
const uint8_t *getCreditsString(int num) {
|
||||
assert(_type == kResourceTypeMac);
|
||||
const int count = READ_BE_UINT16(_credits);
|
||||
if (num < count) {
|
||||
const int offset = READ_BE_UINT16(_credits + 2 + num * 2);
|
||||
return _credits + offset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void clearBankData();
|
||||
int getBankDataSize(uint16_t num);
|
||||
uint8_t *findBankData(uint16_t num);
|
||||
|
@ -320,6 +329,7 @@ struct Resource {
|
|||
|
||||
uint8_t *decodeResourceMacText(const char *name, const char *suffix);
|
||||
uint8_t *decodeResourceMacData(const char *name, bool decompressLzss);
|
||||
uint8_t *decodeResourceMacData(const ResourceMacEntry *entry, bool decompressLzss);
|
||||
void MAC_decodeImageData(const uint8_t *ptr, int i, DecodeBuffer *dst);
|
||||
void MAC_decodeDataCLUT(const uint8_t *ptr);
|
||||
void MAC_loadClutData();
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
#include "unpack.h"
|
||||
#include "util.h"
|
||||
|
||||
const char *ResourceAba::FILENAME = "DEMO_UK.ABA";
|
||||
|
||||
ResourceAba::ResourceAba(FileSystem *fs)
|
||||
: _fs(fs) {
|
||||
_filesCount = 0;
|
||||
_entries = 0;
|
||||
_entriesCount = 0;
|
||||
}
|
||||
|
@ -19,31 +18,38 @@ static int compareAbaEntry(const void *a, const void *b) {
|
|||
return strcasecmp(((ResourceAbaEntry *)a)->name, ((ResourceAbaEntry *)b)->name);
|
||||
}
|
||||
|
||||
void ResourceAba::readEntries() {
|
||||
if (_f.open(FILENAME, "rb", _fs)) {
|
||||
_entriesCount = _f.readUint16BE();
|
||||
_entries = (ResourceAbaEntry *)calloc(_entriesCount, sizeof(ResourceAbaEntry));
|
||||
void ResourceAba::readEntries(const char *aba) {
|
||||
assert(_filesCount < 3);
|
||||
if (_f[_filesCount].open(aba, "rb", _fs)) {
|
||||
File &f = _f[_filesCount];
|
||||
const int currentCount = _entriesCount;
|
||||
const int entriesCount = f.readUint16BE();
|
||||
_entries = (ResourceAbaEntry *)realloc(_entries, (currentCount + entriesCount) * sizeof(ResourceAbaEntry));
|
||||
if (!_entries) {
|
||||
error("Failed to allocate %d _entries", _entriesCount);
|
||||
error("Failed to allocate %d _entries", currentCount + entriesCount);
|
||||
return;
|
||||
}
|
||||
const int entrySize = _f.readUint16BE();
|
||||
_entriesCount = currentCount + entriesCount;
|
||||
const int entrySize = f.readUint16BE();
|
||||
assert(entrySize == 30);
|
||||
uint32_t nextOffset = 0;
|
||||
for (int i = 0; i < _entriesCount; ++i) {
|
||||
_f.read(_entries[i].name, sizeof(_entries[i].name));
|
||||
_entries[i].offset = _f.readUint32BE();
|
||||
_entries[i].compressedSize = _f.readUint32BE();
|
||||
_entries[i].size = _f.readUint32BE();
|
||||
const uint32_t tag = _f.readUint32BE();
|
||||
for (int i = 0; i < entriesCount; ++i) {
|
||||
const int j = currentCount + i;
|
||||
f.read(_entries[j].name, sizeof(_entries[j].name));
|
||||
_entries[j].offset = f.readUint32BE();
|
||||
_entries[j].compressedSize = f.readUint32BE();
|
||||
_entries[j].size = f.readUint32BE();
|
||||
_entries[j].fileIndex = _filesCount;
|
||||
const uint32_t tag = f.readUint32BE();
|
||||
assert(tag == TAG);
|
||||
debug(DBG_RES, "'%s' offset 0x%X size %d/%d", _entries[i].name, _entries[i].offset, _entries[i].compressedSize, _entries[i].size);
|
||||
debug(DBG_RES, "'%s' offset 0x%X size %d/%d", _entries[j].name, _entries[j].offset, _entries[j].compressedSize, _entries[j].size);
|
||||
if (i != 0) {
|
||||
assert(nextOffset == _entries[i].offset);
|
||||
assert(nextOffset == _entries[j].offset);
|
||||
}
|
||||
nextOffset = _entries[i].offset + _entries[i].compressedSize;
|
||||
nextOffset = _entries[j].offset + _entries[j].compressedSize;
|
||||
}
|
||||
qsort(_entries, _entriesCount, sizeof(ResourceAbaEntry), compareAbaEntry);
|
||||
++_filesCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,8 +71,8 @@ uint8_t *ResourceAba::loadEntry(const char *name, uint32_t *size) {
|
|||
error("Failed to allocate %d bytes", e->compressedSize);
|
||||
return 0;
|
||||
}
|
||||
_f.seek(e->offset);
|
||||
_f.read(tmp, e->compressedSize);
|
||||
_f[e->fileIndex].seek(e->offset);
|
||||
_f[e->fileIndex].read(tmp, e->compressedSize);
|
||||
if (e->compressedSize == e->size) {
|
||||
dst = tmp;
|
||||
} else {
|
||||
|
|
|
@ -11,22 +11,23 @@ struct ResourceAbaEntry {
|
|||
uint32_t offset;
|
||||
uint32_t compressedSize;
|
||||
uint32_t size;
|
||||
int fileIndex;
|
||||
};
|
||||
|
||||
struct ResourceAba {
|
||||
|
||||
static const char *FILENAME;
|
||||
static const int TAG = 0x442E4D2E;
|
||||
|
||||
FileSystem *_fs;
|
||||
File _f;
|
||||
File _f[3];
|
||||
int _filesCount;
|
||||
ResourceAbaEntry *_entries;
|
||||
int _entriesCount;
|
||||
|
||||
ResourceAba(FileSystem *fs);
|
||||
~ResourceAba();
|
||||
|
||||
void readEntries();
|
||||
void readEntries(const char *aba);
|
||||
const ResourceAbaEntry *findEntry(const char *name) const;
|
||||
uint8_t *loadEntry(const char *name, uint32_t *size = 0);
|
||||
};
|
||||
|
|
|
@ -30,8 +30,10 @@ static bool nextBit(UnpackCtx *uc) {
|
|||
template<int count>
|
||||
static uint32_t getBits(UnpackCtx *uc) { // rdd1bits
|
||||
uint32_t bits = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
bits |= (nextBit(uc) ? 1 : 0) << (count - 1 - i);
|
||||
for (uint32_t mask = 1 << (count - 1); mask != 0; mask >>= 1) {
|
||||
if (nextBit(uc)) {
|
||||
bits |= mask;
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue