aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/resource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/resource.cpp')
-rw-r--r--engines/sci/resource.cpp247
1 files changed, 173 insertions, 74 deletions
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 9809f10576..a19e7bc893 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -114,16 +114,21 @@ static const char *s_resourceTypeNames[] = {
"patch", "bitmap", "palette", "cdaudio",
"audio", "sync", "message", "map", "heap",
"audio36", "sync36", "xlate", "robot", "vmd",
- "chunk", "macibin", "macibis", "macpict"
+ "chunk", "animation", "etc", "duck", "clut",
+ "tga", "zzz", "macibin", "macibis", "macpict"
};
+// Resource type suffixes. Note that the
+// suffic of SCI3 scripts has been changed from
+// scr to csc
static const char *s_resourceTypeSuffixes[] = {
"v56", "p56", "scr", "tex", "snd",
"", "voc", "fon", "cur", "pat",
"bit", "pal", "cda", "aud", "syn",
"msg", "map", "hep", "", "",
"trn", "rbt", "vmd", "chk", "",
- "", ""
+ "etc", "duk", "clu", "tga", "zzz",
+ "", "", ""
};
const char *getResourceTypeName(ResourceType restype) {
@@ -144,18 +149,19 @@ static const ResourceType s_resTypeMapSci0[] = {
// TODO: 12 should be "Wave", but SCI seems to just store it in Audio resources
static const ResourceType s_resTypeMapSci21[] = {
- kResourceTypeView, kResourceTypePic, kResourceTypeScript, kResourceTypeText, // 0x00-0x03
- kResourceTypeSound, kResourceTypeMemory, kResourceTypeVocab, kResourceTypeFont, // 0x04-0x07
+ kResourceTypeView, kResourceTypePic, kResourceTypeScript, kResourceTypeAnimation, // 0x00-0x03
+ kResourceTypeSound, kResourceTypeEtc, kResourceTypeVocab, kResourceTypeFont, // 0x04-0x07
kResourceTypeCursor, kResourceTypePatch, kResourceTypeBitmap, kResourceTypePalette, // 0x08-0x0B
kResourceTypeInvalid, kResourceTypeAudio, kResourceTypeSync, kResourceTypeMessage, // 0x0C-0x0F
kResourceTypeMap, kResourceTypeHeap, kResourceTypeChunk, kResourceTypeAudio36, // 0x10-0x13
- kResourceTypeSync36, kResourceTypeTranslation, kResourceTypeRobot, kResourceTypeVMD // 0x14-0x17
+ kResourceTypeSync36, kResourceTypeTranslation, kResourceTypeRobot, kResourceTypeVMD, // 0x14-0x17
+ kResourceTypeDuck, kResourceTypeClut, kResourceTypeTGA, kResourceTypeZZZ // 0x18-0x1B
};
ResourceType ResourceManager::convertResType(byte type) {
type &= 0x7f;
- if (_mapVersion != kResVersionSci32) {
+ if (_mapVersion < kResVersionSci2) {
// SCI0 - SCI2
if (type < ARRAYSIZE(s_resTypeMapSci0))
return s_resTypeMapSci0[type];
@@ -587,6 +593,8 @@ int ResourceManager::addAppropriateSources() {
int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
ResourceSource *map = 0;
+ Common::Array<ResourceSource *> sci21Maps;
+
#ifdef ENABLE_SCI32
ResourceSource *sci21PatchMap = 0;
const Common::FSNode *sci21PatchRes = 0;
@@ -605,8 +613,13 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
if (filename.contains("resmap.0")) {
const char *dot = strrchr(file->getName().c_str(), '.');
- int number = atoi(dot + 1);
- map = addExternalMap(file, number);
+ uint number = atoi(dot + 1);
+
+ // We need to store each of these maps for use later on
+ if (number >= sci21Maps.size())
+ sci21Maps.resize(number + 1);
+
+ sci21Maps[number] = addExternalMap(file, number);
}
#ifdef ENABLE_SCI32
@@ -619,7 +632,7 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
#endif
}
- if (!map)
+ if (!map && sci21Maps.empty())
return 0;
#ifdef ENABLE_SCI32
@@ -635,11 +648,17 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
Common::String filename = file->getName();
filename.toLowercase();
- if (filename.contains("resource.0") || filename.contains("ressci.0")) {
+ if (filename.contains("resource.0")) {
const char *dot = strrchr(filename.c_str(), '.');
int number = atoi(dot + 1);
addSource(new VolumeResourceSource(file->getName(), map, number, file));
+ } else if (filename.contains("ressci.0")) {
+ const char *dot = strrchr(filename.c_str(), '.');
+ int number = atoi(dot + 1);
+
+ // Match this volume to its own map
+ addSource(new VolumeResourceSource(file->getName(), sci21Maps[number], number, file));
}
}
@@ -660,11 +679,29 @@ int ResourceManager::addInternalSources() {
addSource(new AudioVolumeResourceSource(this, "RESOURCE.SFX", src, 0));
else if (Common::File::exists("RESOURCE.AUD"))
addSource(new AudioVolumeResourceSource(this, "RESOURCE.AUD", src, 0));
+ else
+ return 0;
++itr;
}
delete resources;
+
+#ifdef ENABLE_SCI32
+ if (_mapVersion >= kResVersionSci2) {
+ // If we have no scripts, but chunk 0 is present, open up the chunk
+ // to try to get to any scripts in there. The Lighthouse SCI2.1 demo
+ // does exactly this.
+
+ resources = listResources(kResourceTypeScript);
+
+ if (resources->empty() && testResource(ResourceId(kResourceTypeChunk, 0)))
+ addResourcesFromChunk(0);
+
+ delete resources;
+ }
+#endif
+
return 1;
}
@@ -779,7 +816,7 @@ void ChunkResourceSource::loadResource(ResourceManager *resMan, Resource *res) {
}
void ResourceManager::addResourcesFromChunk(uint16 id) {
- addSource(new ChunkResourceSource(Common::String::printf("Chunk %d", id), id));
+ addSource(new ChunkResourceSource(Common::String::format("Chunk %d", id), id));
scanNewSources();
}
@@ -795,7 +832,7 @@ void ResourceManager::freeResourceSources() {
ResourceManager::ResourceManager() {
}
-void ResourceManager::init() {
+void ResourceManager::init(bool initFromFallbackDetector) {
_memoryLocked = 0;
_memoryLRU = 0;
_LRU.clear();
@@ -806,6 +843,13 @@ void ResourceManager::init() {
_mapVersion = detectMapVersion();
_volVersion = detectVolVersion();
+
+ // TODO/FIXME: Remove once SCI3 resource detection is finished
+ if ((_mapVersion == kResVersionSci3 || _volVersion == kResVersionSci3) && (_mapVersion != _volVersion)) {
+ warning("FIXME: Incomplete SCI3 detection: setting map and volume version to SCI3");
+ _mapVersion = _volVersion = kResVersionSci3;
+ }
+
if ((_volVersion == kResVersionUnknown) && (_mapVersion != kResVersionUnknown)) {
warning("Volume version not detected, but map version has been detected. Setting volume version to map version");
_volVersion = _mapVersion;
@@ -826,8 +870,13 @@ void ResourceManager::init() {
}
scanNewSources();
- addInternalSources();
- scanNewSources();
+
+ if (!initFromFallbackDetector) {
+ if (!addInternalSources())
+ error("Somehow I can't seem to find the sound files I need (RESOURCE.AUD/RESOURCE.SFX), aborting");
+
+ scanNewSources();
+ }
detectSciVersion();
@@ -858,21 +907,6 @@ void ResourceManager::init() {
}
#endif
}
-
-#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1) {
- // If we have no scripts, but chunk 0 is present, open up the chunk
- // to try to get to any scripts in there. The Lighthouse SCI2.1 demo
- // does exactly this.
-
- Common::List<ResourceId> *scriptList = listResources(kResourceTypeScript);
-
- if (scriptList->empty() && testResource(ResourceId(kResourceTypeChunk, 0)))
- addResourcesFromChunk(0);
-
- delete scriptList;
- }
-#endif
}
ResourceManager::~ResourceManager() {
@@ -940,7 +974,7 @@ void ResourceManager::freeOldResources() {
removeFromLRU(goner);
goner->unalloc();
#ifdef SCI_VERBOSE_RESMAN
- printf("resMan-debug: LRU: Freeing %s.%03d (%d bytes)\n", getResourceTypeName(goner->type), goner->number, goner->size);
+ debug("resMan-debug: LRU: Freeing %s.%03d (%d bytes)", getResourceTypeName(goner->type), goner->number, goner->size);
#endif
}
}
@@ -1024,8 +1058,10 @@ const char *ResourceManager::versionDescription(ResVersion version) const {
return "SCI1.1";
case kResVersionSci11Mac:
return "Mac SCI1.1+";
- case kResVersionSci32:
- return "SCI32";
+ case kResVersionSci2:
+ return "SCI2/2.1";
+ case kResVersionSci3:
+ return "SCI3";
}
return "Version not valid";
@@ -1036,6 +1072,8 @@ ResVersion ResourceManager::detectMapVersion() {
byte buff[6];
ResourceSource *rsrc= 0;
+ // TODO: Add SCI3 support
+
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
rsrc = *it;
@@ -1084,8 +1122,8 @@ ResVersion ResourceManager::detectMapVersion() {
directoryOffset = fileStream->readUint16LE();
// Only SCI32 has directory type < 0x80
- if (directoryType < 0x80 && (mapDetected == kResVersionUnknown || mapDetected == kResVersionSci32))
- mapDetected = kResVersionSci32;
+ if (directoryType < 0x80 && (mapDetected == kResVersionUnknown || mapDetected == kResVersionSci2))
+ mapDetected = kResVersionSci2;
else if (directoryType < 0x80 || ((directoryType & 0x7f) > 0x20 && directoryType != 0xFF))
break;
@@ -1127,7 +1165,7 @@ ResVersion ResourceManager::detectVolVersion() {
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
rsrc = *it;
-
+
if (rsrc->getSourceType() == kSourceVolume) {
if (rsrc->_resourceFile) {
fileStream = rsrc->_resourceFile->createReadStream();
@@ -1163,23 +1201,38 @@ ResVersion ResourceManager::detectVolVersion() {
bool failed = false;
bool sci11Align = false;
- // Check for SCI0, SCI1, SCI1.1 and SCI32 v2 (Gabriel Knight 1 CD) formats
+ // Check for SCI0, SCI1, SCI1.1, SCI32 v2 (Gabriel Knight 1 CD) and SCI32 v3 (LSL7) formats
while (!fileStream->eos() && fileStream->pos() < 0x100000) {
if (curVersion > kResVersionSci0Sci1Early)
fileStream->readByte();
resId = fileStream->readUint16LE();
- dwPacked = (curVersion < kResVersionSci32) ? fileStream->readUint16LE() : fileStream->readUint32LE();
- dwUnpacked = (curVersion < kResVersionSci32) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+ dwPacked = (curVersion < kResVersionSci2) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+ dwUnpacked = (curVersion < kResVersionSci2) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+
+ // The compression field is present, but bogus when
+ // loading SCI3 volumes, the format is otherwise
+ // identical to SCI2. We therefore get the compression
+ // indicator here, but disregard it in the following
+ // code.
wCompression = fileStream->readUint16LE();
+
if (fileStream->eos()) {
delete fileStream;
return curVersion;
}
- int chk = (curVersion == kResVersionSci0Sci1Early) ? 4 : 20;
+ int chk;
+
+ if (curVersion == kResVersionSci0Sci1Early)
+ chk = 4;
+ else if (curVersion < kResVersionSci2)
+ chk = 20;
+ else
+ chk = 32; // We don't need this, but include it for completeness
+
int offs = curVersion < kResVersionSci11 ? 4 : 0;
- if ((curVersion < kResVersionSci32 && wCompression > chk)
- || (curVersion == kResVersionSci32 && wCompression != 0 && wCompression != 32)
+ if ((curVersion < kResVersionSci2 && wCompression > chk)
+ || (curVersion == kResVersionSci2 && wCompression != 0 && wCompression != 32)
|| (wCompression == 0 && dwPacked != dwUnpacked + offs)
|| (dwUnpacked < dwPacked - offs)) {
@@ -1192,7 +1245,9 @@ ResVersion ResourceManager::detectVolVersion() {
// Later versions (e.g. QFG1VGA) have resources word-aligned
sci11Align = true;
} else if (curVersion == kResVersionSci11) {
- curVersion = kResVersionSci32;
+ curVersion = kResVersionSci2;
+ } else if (curVersion == kResVersionSci2) {
+ curVersion = kResVersionSci3;
} else {
// All version checks failed, exit loop
failed = true;
@@ -1207,7 +1262,7 @@ ResVersion ResourceManager::detectVolVersion() {
fileStream->seek(dwPacked - 4, SEEK_CUR);
else if (curVersion == kResVersionSci11)
fileStream->seek(sci11Align && ((9 + dwPacked) % 2) ? dwPacked + 1 : dwPacked, SEEK_CUR);
- else if (curVersion == kResVersionSci32)
+ else if (curVersion >= kResVersionSci2)
fileStream->seek(dwPacked, SEEK_CUR);
}
@@ -1390,7 +1445,7 @@ void ResourceManager::readResourcePatches() {
for (int i = kResourceTypeView; i < kResourceTypeInvalid; ++i) {
// Ignore the types that can't be patched (and Robot/VMD is handled externally for now)
- if (!s_resourceTypeSuffixes[i] || i == kResourceTypeRobot || i == kResourceTypeVMD)
+ if (!s_resourceTypeSuffixes[i] || (i >= kResourceTypeRobot && i != kResourceTypeChunk))
continue;
files.clear();
@@ -1404,6 +1459,12 @@ void ResourceManager::readResourcePatches() {
mask += s_resourceTypeSuffixes[i];
SearchMan.listMatchingMembers(files, mask);
+ if (i == kResourceTypeScript && files.size() == 0) {
+ // SCI3 (we can't use getSciVersion() at this point)
+ mask = "*.csc";
+ SearchMan.listMatchingMembers(files, mask);
+ }
+
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
bool bAdd = false;
name = (*x)->getName();
@@ -1557,10 +1618,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
// the actual resource file.
int mapVolumeNr = volume_nr + map->_volumeNumber;
ResourceSource *source = findVolume(map, mapVolumeNr);
- // FIXME: this code has serious issues with multiple RESMAP.* files (like in unmodified gk2)
- // adding a resource with source == NULL would crash later on
- if (!source)
- error("Unable to find volume for map %s volumeNr %d", map->getLocationName().c_str(), mapVolumeNr);
+
+ assert(source);
Resource *resource = _resMap.getVal(resId, NULL);
if (!resource) {
@@ -1583,10 +1642,12 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
return 0;
}
-struct {
+struct MacResTag {
uint32 tag;
ResourceType type;
-} static const macResTagMap[] = {
+};
+
+static const MacResTag macResTagMap[] = {
{ MKID_BE('V56 '), kResourceTypeView },
{ MKID_BE('P56 '), kResourceTypePic },
{ MKID_BE('SCR '), kResourceTypeScript },
@@ -1731,12 +1792,22 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream
wCompression = 0;
break;
#ifdef ENABLE_SCI32
- case kResVersionSci32:
+ case kResVersionSci2:
+ case kResVersionSci3:
type = _resMan->convertResType(file->readByte());
number = file->readUint16LE();
szPacked = file->readUint32LE();
szUnpacked = file->readUint32LE();
+
+ // The same comment applies here as in
+ // detectVolVersion regarding SCI3. We ignore the
+ // compression field for SCI3 games, but must presume
+ // it exists in the file.
wCompression = file->readUint16LE();
+
+ if (volVersion == kResVersionSci3)
+ wCompression = szPacked != szUnpacked ? 32 : 0;
+
break;
#endif
default:
@@ -1953,7 +2024,7 @@ void ResourceManager::detectSciVersion() {
#ifdef ENABLE_SCI32
viewCompression = getViewCompression();
#else
- if (_volVersion == kResVersionSci32) {
+ if (_volVersion >= kResVersionSci2) {
// SCI32 support isn't built in, thus view detection will fail
viewCompression = kCompUnknown;
} else {
@@ -1975,7 +2046,7 @@ void ResourceManager::detectSciVersion() {
|| _volVersion == kResVersionSci11Mac
#ifdef ENABLE_SCI32
|| viewCompression == kCompSTACpack
- || _volVersion == kResVersionSci32 // kq7
+ || _volVersion == kResVersionSci2 // kq7
#endif
) {
// SCI1.1 VGA views
@@ -1985,7 +2056,7 @@ void ResourceManager::detectSciVersion() {
// Otherwise we detect it from a view
_viewType = detectViewType();
#else
- if (_volVersion == kResVersionSci32 && viewCompression == kCompUnknown) {
+ if (_volVersion == kResVersionSci2 && viewCompression == kCompUnknown) {
// A SCI32 game, but SCI32 support is disabled. Force the view type
// to kViewVga11, as we can't read from the game's resource files
_viewType = kViewVga11;
@@ -2009,17 +2080,20 @@ void ResourceManager::detectSciVersion() {
}
// Handle SCI32 versions here
- if (_volVersion == kResVersionSci32) {
+ if (_volVersion >= kResVersionSci2) {
+ Common::List<ResourceId> *heaps = listResources(kResourceTypeHeap);
// SCI2.1/3 and SCI1 Late resource maps are the same, except that
// SCI1 Late resource maps have the resource types or'd with
// 0x80. We differentiate between SCI2 and SCI2.1/3 based on that.
- // TODO: Differentiate between SCI2.1 and SCI3
if (_mapVersion == kResVersionSci1Late) {
s_sciVersion = SCI_VERSION_2;
return;
- } else {
+ } else if (!heaps->empty()) {
s_sciVersion = SCI_VERSION_2_1;
return;
+ } else {
+ s_sciVersion = SCI_VERSION_3;
+ return;
}
}
@@ -2284,7 +2358,7 @@ bool ResourceManager::hasSci1Voc900() {
return offset == res->size;
}
-// Same function as Script::findBlock(). Slight code
+// Same function as Script::findBlockSCI0(). Slight code
// duplication here, but this has been done to keep the resource
// manager independent from the rest of the engine
static byte *findSci0ExportsBlock(byte *buffer) {
@@ -2310,6 +2384,24 @@ static byte *findSci0ExportsBlock(byte *buffer) {
return NULL;
}
+// This code duplicates Script::relocateOffsetSci3, but we can't use
+// that here since we can't instantiate scripts at this point.
+static int relocateOffsetSci3(const byte *buf, uint32 offset) {
+ int relocStart = READ_LE_UINT32(buf + 8);
+ int relocCount = READ_LE_UINT16(buf + 18);
+ const byte *seeker = buf + relocStart;
+
+ for (int i = 0; i < relocCount; ++i) {
+ if (READ_SCI11ENDIAN_UINT32(seeker) == offset) {
+ // TODO: Find out what UINT16 at (seeker + 8) means
+ return READ_SCI11ENDIAN_UINT16(buf + offset) + READ_SCI11ENDIAN_UINT32(seeker + 4);
+ }
+ seeker += 10;
+ }
+
+ return -1;
+}
+
reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
Resource *script = findResource(ResourceId(kResourceTypeScript, 0), false);
@@ -2318,7 +2410,7 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
byte *offsetPtr = 0;
- if (getSciVersion() < SCI_VERSION_1_1) {
+ if (getSciVersion() <= SCI_VERSION_1_LATE) {
byte *buf = (getSciVersion() == SCI_VERSION_0_EARLY) ? script->data + 2 : script->data;
// Check if the first block is the exports block (in most cases, it is)
@@ -2331,35 +2423,42 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
error("Unable to find exports block from script 0");
offsetPtr += 4 + 2;
}
- } else {
+
+ int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
+ return make_reg(1, offset);
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
offsetPtr = script->data + 4 + 2 + 2;
- }
-
- int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
- // In SCI1.1 and newer, the heap is appended at the end of the script,
- // so adjust the offset accordingly
- if (getSciVersion() >= SCI_VERSION_1_1 && addSci11ScriptOffset) {
- offset += script->size;
+ // In SCI1.1 - SCI2.1, the heap is appended at the end of the script,
+ // so adjust the offset accordingly if requested
+ int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
+ if (addSci11ScriptOffset) {
+ offset += script->size;
- // Ensure that the start of the heap is word-aligned - same as in Script::init()
- if (script->size & 2)
- offset++;
- }
+ // Ensure that the start of the heap is word-aligned - same as in Script::init()
+ if (script->size & 2)
+ offset++;
+ }
- return make_reg(1, offset);
+ return make_reg(1, offset);
+ } else {
+ return make_reg(1, relocateOffsetSci3(script->data, 22));
+ }
}
Common::String ResourceManager::findSierraGameId() {
- // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1+, it's separated
+ // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1 - SCI2.1,
+ // it's in a separate heap resource
Resource *heap = 0;
int nameSelector = 3;
if (getSciVersion() < SCI_VERSION_1_1) {
heap = findResource(ResourceId(kResourceTypeScript, 0), false);
- } else {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
heap = findResource(ResourceId(kResourceTypeHeap, 0), false);
nameSelector += 5;
+ } else if (getSciVersion() == SCI_VERSION_3) {
+ warning("TODO: findSierraGameId(): SCI3 equivalent");
}
if (!heap)