aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/igor/detection.cpp29
-rw-r--r--engines/igor/igor.cpp200
-rw-r--r--engines/igor/igor.h16
-rw-r--r--engines/igor/parts/part_90.cpp5
-rw-r--r--engines/igor/parts/part_main.cpp18
-rw-r--r--engines/igor/staticres.cpp11
6 files changed, 146 insertions, 133 deletions
diff --git a/engines/igor/detection.cpp b/engines/igor/detection.cpp
index 5e68f2df3b..130cf22780 100644
--- a/engines/igor/detection.cpp
+++ b/engines/igor/detection.cpp
@@ -40,7 +40,11 @@ static const IgorGameDescription igorGameDescriptions[] = {
{
"igor",
"Demo 1.00s",
- AD_ENTRY1s("IGOR.DAT", 0, 4086790),
+ {
+ { "IGOR.DAT", 0, 0, 4086790 },
+ { "IGOR.FSD", 0, 0, 462564 },
+ { 0, 0, 0, 0 }
+ },
Common::EN_ANY,
Common::kPlatformPC,
Common::ADGF_DEMO
@@ -51,13 +55,32 @@ static const IgorGameDescription igorGameDescriptions[] = {
{
"igor",
"Demo 1.10s",
- AD_ENTRY1s("IGOR.DAT", 0, 4094103),
+ {
+ { "IGOR.DAT", 0, 0, 4094103 },
+ { "IGOR.FSD", 0, 0, 462564 },
+ { 0, 0, 0, 0 }
+ },
Common::EN_ANY,
Common::kPlatformPC,
Common::ADGF_DEMO
},
Igor::kIdEngDemo110
},
+ {
+ {
+ "igor",
+ "Talkie",
+ {
+ { "IGOR.EXE", 0, 0, 9115648 },
+ { "IGOR.DAT", 0, 0, 61682719 },
+ { 0, 0, 0, 0 }
+ },
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ Igor::kIdSpaCD
+ },
{ AD_TABLE_END_MARKER, 0 }
};
@@ -69,7 +92,7 @@ static const PlainGameDescriptor igorGameDescriptors[] = {
static const Common::ADParams igorDetectionParams = {
(const byte *)igorGameDescriptions,
sizeof(IgorGameDescription),
- 0, // no md5
+ 1024, // number of md5 bytes
igorGameDescriptors,
0,
"igor",
diff --git a/engines/igor/igor.cpp b/engines/igor/igor.cpp
index e0d98b1dbc..5e761a9e11 100644
--- a/engines/igor/igor.cpp
+++ b/engines/igor/igor.cpp
@@ -64,6 +64,8 @@ IgorEngine::IgorEngine(OSystem *system, int gameVersion)
IgorEngine::~IgorEngine() {
delete _midiPlayer;
+ free(_resourceEntries);
+ free(_soundOffsets);
Common::clearAllSpecialDebugLevels();
free(_screenVGA);
for (int i = 0; i < 4; ++i) {
@@ -110,7 +112,7 @@ void IgorEngine::restart() {
_actionCode = 0;
_actionWalkPoint = 0;
memset(_inputVars, 0, sizeof(_inputVars));
- memset(_musicSequenceTable, 0, sizeof(_musicSequenceTable));
+ _musicData = 0;
_talkDelay = _talkSpeechCounter = _talkDelayCounter = 0;
memset(_dialogueTextsTable, 0, sizeof(_dialogueTextsTable));
@@ -140,7 +142,7 @@ void IgorEngine::restart() {
_executeMainAction = 0;
_executeRoomAction = 0;
_previousMusic = 0;
- memset(_musicSequenceTable, 0, sizeof(_musicSequenceTable));
+ _musicData = 0;
_actionCode = 0;
_actionWalkPoint = 0;
memset(_inputVars, 0, sizeof(_inputVars));
@@ -151,6 +153,11 @@ void IgorEngine::restart() {
_updateDialogue = 0;
_updateRoomBackground = 0;
+ _resourceEntriesCount = 0;
+ _resourceEntries = 0;
+ _soundOffsetsCount = 0;
+ _soundOffsets = 0;
+
_gameTicks = 0;
}
@@ -161,14 +168,17 @@ int IgorEngine::go() {
if (_currentPart == 0) {
_currentPart = kStartupPart;
}
- if (!_ovlFile.open("IGOR.DAT")) {
- error("Unable to open 'IGOR.DAT'");
+ const char *ovlFileName = "IGOR.DAT";
+ const char *fsdFileName = "IGOR.FSD";
+ if (_gameVersion == kIdSpaCD) {
+ ovlFileName = "IGOR.EXE";
+ fsdFileName = "IGOR.DAT";
}
- if (!_sndFile.open("IGOR.FSD")) {
- error("Unable to open 'IGOR.FSD'");
+ if (!_ovlFile.open(ovlFileName)) {
+ error("Unable to open '%s'", ovlFileName);
}
- if (!_tblFile.open("IGOR.TBL")) {
- error("Unable to open 'IGOR.TBL'");
+ if (!_sndFile.open(fsdFileName)) {
+ error("Unable to open '%s'", fsdFileName);
}
readResourceTableFile();
loadMainTexts();
@@ -180,25 +190,43 @@ int IgorEngine::go() {
PART_MAIN();
_ovlFile.close();
_sndFile.close();
- _tblFile.close();
return 0;
}
void IgorEngine::readResourceTableFile() {
- if (_tblFile.readUint32BE() == MKID_BE('ITBL') && _tblFile.readUint32BE() == 1) {
+ Common::File tblFile;
+ uint32 resourcesEntriesOffset = 0, soundEntriesOffset = 0;
+ if (tblFile.open("IGOR.TBL") && tblFile.readUint32BE() == MKID_BE('ITBL') && tblFile.readUint32BE() == 2) {
+ tblFile.skip(4);
uint32 borlandOverlaySize = _ovlFile.size();
- int gameVersionsCount = _tblFile.readByte();
+ int gameVersionsCount = tblFile.readByte();
for (int i = 0; i < gameVersionsCount; ++i) {
- uint32 size = _tblFile.readUint32BE();
- uint32 offs = _tblFile.readUint32BE();
+ uint32 size = tblFile.readUint32BE();
if (size == borlandOverlaySize) {
- _tblFile.seek(offs);
- _resourceEntriesCount = _tblFile.readUint16BE();
- _resourceEntriesOffset = offs + 2;
- return;
+ resourcesEntriesOffset = tblFile.readUint32BE();
+ soundEntriesOffset = tblFile.readUint32BE();
+ break;
}
+ tblFile.skip(8);
}
}
+ if (resourcesEntriesOffset != 0 && soundEntriesOffset != 0) {
+ tblFile.seek(resourcesEntriesOffset);
+ _resourceEntriesCount = tblFile.readUint16BE();
+ _resourceEntries = (ResourceEntry *)malloc(sizeof(ResourceEntry) * _resourceEntriesCount);
+ for (int i = 0; i < _resourceEntriesCount; ++i) {
+ _resourceEntries[i].id = tblFile.readUint16BE();
+ _resourceEntries[i].offs = tblFile.readUint32BE();
+ _resourceEntries[i].size = tblFile.readUint32BE();
+ }
+ tblFile.seek(soundEntriesOffset);
+ _soundOffsetsCount = tblFile.readUint16BE();
+ _soundOffsets = (uint32 *)malloc(sizeof(uint32) * _soundOffsetsCount);
+ for (int i = 0; i < _soundOffsetsCount; ++i) {
+ _soundOffsets[i] = tblFile.readUint32BE();
+ }
+ return;
+ }
error("Unable to read 'IGOR.TBL'");
}
@@ -255,11 +283,12 @@ void IgorEngine::waitForTimer(int ticks) {
return;
}
_gameTicks += kTimerTicksCount;
- if (_gameTicks == 64) {
+ if (_gameTicks == 64) { // TODO: original switches cursors more often
_gameTicks = 0;
setCursor(_currentCursor);
_currentCursor = (_currentCursor + 1) & 3;
}
+ // TODO: updateMusic();
}
void IgorEngine::copyArea(uint8 *dst, int dstOffset, int dstPitch, const uint8 *src, int srcPitch, int w, int h, bool transparent) {
@@ -280,89 +309,60 @@ void IgorEngine::copyArea(uint8 *dst, int dstOffset, int dstPitch, const uint8 *
}
int IgorEngine::getRandomNumber(int m) {
- assert(m != 0);
- return rand() % m;
+ assert(m > 0);
+ return _rnd.getRandomNumber(m - 1);
+}
+
+void IgorEngine::startMusic(int cmf) {
+ _midiPlayer->stopMusic();
+ free(_musicData);
+ int musicDataSize;
+ _musicData = loadData(cmf, 0, &musicDataSize);
+ _midiPlayer->playMusic(_musicData, musicDataSize);
}
void IgorEngine::playMusic(int num) {
debugC(9, kDebugEngine, "playMusic() %d", num);
- const int *seq = 0;
- switch (num) {
- case 2: {
- static const int cmf[] = { CMF_2_1, CMF_2_2, CMF_2_3, CMF_2_4, 0 };
- seq = cmf;
- }
- break;
- case 3: {
- static const int cmf[] = { CMF_3, 0 };
- seq = cmf;
- }
- break;
- case 4: {
- static const int cmf[] = { CMF_4, 0 };
- seq = cmf;
- }
- break;
- case 7: {
- static const int cmf[] = { CMF_7_1, CMF_7_2, CMF_7_3, CMF_7_4, 0 };
- seq = cmf;
- }
- break;
- case 8: {
- static const int cmf[] = { CMF_8, 0 };
- seq = cmf;
- }
- break;
- case 9: {
- static const int cmf[] = { CMF_9, 0 };
- seq = cmf;
- }
- break;
- case 10: {
- static const int cmf[] = { CMF_10, 0 };
- seq = cmf;
- }
- break;
- case 11: {
- static const int cmf[] = { CMF_11, 0 };
- seq = cmf;
- }
- break;
- case 12: {
- static const int cmf[] = { CMF_12, 0 };
- seq = cmf;
- }
- break;
- }
- if (seq) {
- for (int i = 0; i < 5; ++i) {
- free(_musicSequenceTable[i].data);
- }
- for (int i = 0; seq[i]; ++i) {
- _musicSequenceTable[i].data = loadData(seq[i], 0, &_musicSequenceTable[i].dataSize);
- }
- }
+ static const int cmf[] = { 0, 0, CMF_2_1, CMF_3, CMF_4, 0, 0, CMF_7_1, CMF_8, CMF_9, CMF_10, CMF_11, CMF_12 };
+ assert(num < ARRAYSIZE(cmf) && cmf[num] != 0);
_gameState.musicNum = num;
_gameState.musicSequenceIndex = 1;
- _midiPlayer->playMusic(_musicSequenceTable[0].data, _musicSequenceTable[0].dataSize);
+ if (_gameVersion == kIdSpaCD) {
+ // different file format
+ return;
+ }
+ startMusic(cmf[num]);
}
void IgorEngine::updateMusic() {
+ static const int cmf2Seq[] = { CMF_2_1, CMF_2_2, CMF_2_3, CMF_2_4 };
+ static const int cmf7Seq[] = { CMF_7_1, CMF_7_2, CMF_7_3, CMF_7_4 };
if (_gameState.jumpToNextMusic) {
- if (_gameState.musicNum == 2) {
+ switch (_gameState.musicNum) {
+ case 2:
_gameState.musicSequenceIndex = getRandomNumber(4) + 1;
+ startMusic(cmf2Seq[_gameState.musicSequenceIndex - 1]);
// _timerHandler0x1CCounter = 5;
- } else if (_gameState.musicNum == 3 || _gameState.musicNum == 4 || _gameState.musicNum == 8 || _gameState.musicNum == 9 || _gameState.musicNum == 10) {
-// _timerHandler0x1CCounter = 50;
- } else if (_gameState.musicNum == 7) {
+ break;
+ case 7:
if (_gameState.musicSequenceIndex == 4) {
_gameState.musicSequenceIndex = 1;
} else {
++_gameState.musicSequenceIndex;
}
+ startMusic(cmf7Seq[_gameState.musicSequenceIndex - 1]);
// _timerHandler0x1CCounter = 5;
- } else if (_gameState.musicNum == 11) {
+ break;
+ case 3:
+ case 4:
+ case 8:
+ case 9:
+ case 10:
+// _timerHandler0x1CCounter = 50;
+ break;
+ case 11:
// _timerHandler0x1CCounter = 5;
+ break;
}
}
}
@@ -377,7 +377,8 @@ void IgorEngine::playSound(int num, int fl) {
return;
}
--num;
- _sndFile.seek(_fdsOffsetsTable[num]);
+ assert(num >= 0 && num < _soundOffsetsCount);
+ _sndFile.seek(_soundOffsets[num]);
Audio::AudioStream *stream = Audio::makeVOCStream(_sndFile);
if (stream) {
_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, stream);
@@ -633,30 +634,31 @@ int IgorEngine::getObjectFromInventory(int x) const {
return 0;
}
-ResourceEntry IgorEngine::findData(int id) {
- assert(id >= 1 && id <= _resourceEntriesCount);
- _tblFile.seek(_resourceEntriesOffset + (id - 1) * 10);
- ResourceEntry re;
- re.id = _tblFile.readUint16BE();
- re.offs = _tblFile.readUint32BE();
- re.size = _tblFile.readUint32BE();
- assert(re.id == id);
+static int compareResourceEntry(const void *a, const void *b) {
+ int id = *(const int *)a;
+ const ResourceEntry *entry = (const ResourceEntry *)b;
+ return id - entry->id;
+}
+
+ResourceEntry *IgorEngine::findData(int id) {
+ ResourceEntry *re = (ResourceEntry *)bsearch(&id, _resourceEntries, _resourceEntriesCount, sizeof(ResourceEntry), compareResourceEntry);
+ assert(re);
return re;
}
uint8 *IgorEngine::loadData(int id, uint8 *dst, int *size) {
- ResourceEntry re = findData(id);
- debugC(9, kDebugResource, "loadData() id %d offset %d size %d", id, re.offs, re.size);
+ debugC(9, kDebugResource, "loadData() id %d", id);
+ ResourceEntry *re = findData(id);
if (!dst) {
- dst = (uint8 *)malloc(re.size);
+ dst = (uint8 *)malloc(re->size);
if (!dst) {
- error("Unable to allocate %d bytes", re.size);
+ error("Unable to allocate %d bytes", re->size);
}
}
- _ovlFile.seek(re.offs);
- _ovlFile.read(dst, re.size);
+ _ovlFile.seek(re->offs);
+ _ovlFile.read(dst, re->size);
if (size) {
- *size = re.size;
+ *size = re->size;
}
return dst;
}
@@ -811,7 +813,7 @@ void IgorEngine::loadAnimData(const int *anm, int loadOffset) {
void IgorEngine::loadActionData(int act) {
if (act != 0) {
- assert(findData(act).size <= 0x2000);
+ assert(findData(act)->size <= 0x2000);
loadData(act, _roomActionsTable);
}
}
diff --git a/engines/igor/igor.h b/engines/igor/igor.h
index a71c741c89..6659d21132 100644
--- a/engines/igor/igor.h
+++ b/engines/igor/igor.h
@@ -311,6 +311,7 @@ protected:
int getRandomNumber(int m);
void handleOptionsMenu();
void handlePause();
+ void startMusic(int cmf);
void playMusic(int num);
void updateMusic();
void playSound(int num, int fl);
@@ -323,7 +324,7 @@ protected:
void startIgorDialogue();
void waitForEndOfIgorDialogue();
int getObjectFromInventory(int x) const;
- ResourceEntry findData(int num);
+ ResourceEntry *findData(int num);
uint8 *loadData(int num, uint8 *dst = 0, int *size = 0);
void decodeMainText(const uint8 *p);
void decodeRoomStrings(const uint8 *p, bool skipObjectNames = false);
@@ -400,9 +401,10 @@ protected:
MidiPlayer *_midiPlayer;
+ Common::RandomSource _rnd;
+
Common::File _ovlFile;
Common::File _sndFile;
- Common::File _tblFile;
Audio::SoundHandle _sfxHandle;
@@ -468,10 +470,7 @@ protected:
ExecuteActionProc _executeMainAction;
ExecuteActionProc _executeRoomAction;
uint8 _previousMusic;
- struct {
- uint8 *data;
- int dataSize;
- } _musicSequenceTable[5];
+ uint8 *_musicData;
Action _currentAction;
uint8 _actionCode;
uint8 _actionWalkPoint;
@@ -487,7 +486,9 @@ protected:
UpdateRoomBackgroundProc _updateRoomBackground;
int _gameTicks;
int _resourceEntriesCount;
- int _resourceEntriesOffset;
+ ResourceEntry *_resourceEntries;
+ int _soundOffsetsCount;
+ uint32 *_soundOffsets;
char _saveStateDescriptions[kMaxSaveStates][100];
static const uint8 _dialogueColor[];
@@ -504,7 +505,6 @@ protected:
static const uint8 _walkScaleTable[];
static const uint8 _mouseCursorMask[];
static const uint8 _mouseCursorData[];
- static const uint32 _fdsOffsetsTable[];
//
diff --git a/engines/igor/parts/part_90.cpp b/engines/igor/parts/part_90.cpp
index c069d5d34e..c503d155f2 100644
--- a/engines/igor/parts/part_90.cpp
+++ b/engines/igor/parts/part_90.cpp
@@ -69,10 +69,9 @@ void IgorEngine::PART_90() {
_inputVars[kInputEscape] = 0;
fadeOutPalette(768);
if (_currentPart != kInvalidPart) {
- if (_currentPart == 904) {
+ ++_currentPart;
+ if ((_gameVersion == kIdSpaCD && _currentPart == 904) || _currentPart == 905) {
_currentPart = 850;
- } else {
- ++_currentPart;
}
}
}
diff --git a/engines/igor/parts/part_main.cpp b/engines/igor/parts/part_main.cpp
index 44731b72b8..f3c99b8de1 100644
--- a/engines/igor/parts/part_main.cpp
+++ b/engines/igor/parts/part_main.cpp
@@ -585,13 +585,13 @@ void IgorEngine::UPDATE_OBJECT_STATE(int num) {
if (num == 1 || num == 255) {
switch (_objectsState[0]) {
case 0:
- memcpy(_globalObjectNames + 0x592 / 62, " bottle of whisky", 30);
+ strcpy(_globalObjectNames[23], " bottle of whisky");
break;
case 1:
- memcpy(_globalObjectNames + 0x592 / 62, " empty bottle", 30);
+ strcpy(_globalObjectNames[23], " empty bottle");
break;
case 2:
- memcpy(_globalObjectNames + 0x592 / 62, " bottle of water", 30);
+ strcpy(_globalObjectNames[23], " bottle of water");
break;
}
}
@@ -599,21 +599,21 @@ void IgorEngine::UPDATE_OBJECT_STATE(int num) {
switch (_objectsState[1]) {
case 0:
_inventoryImages[23] = 27;
- memcpy(_globalObjectNames + 0x5D0 / 62, " lizard", 30);
+ strcpy(_globalObjectNames[24], " lizard");
break;
default:
_inventoryImages[23] = 35;
- memcpy(_globalObjectNames + 0x5D0 / 62, " fat lizard", 30);
+ strcpy(_globalObjectNames[24], " fat lizard");
break;
}
}
if (num == 4 || num == 255) {
switch (_objectsState[3]) {
case 0:
- memcpy(_globalObjectNames + 0x554 / 62, " Caroline%s folder", 30);
+ strcpy(_globalObjectNames[22], " Caroline%s folder");
break;
case 1:
- memcpy(_globalObjectNames + 0x554 / 62, " Philip%s folder", 30);
+ strcpy(_globalObjectNames[22], " Philip%s folder");
break;
}
}
@@ -632,10 +632,10 @@ void IgorEngine::UPDATE_OBJECT_STATE(int num) {
}
if (num == 8 || num == 255) {
if (_objectsState[7] == 0) {
- memcpy(_globalObjectNames + 0x60E / 62, " statuette", 30);
+ strcpy(_globalObjectNames[25], " statuette");
_inventoryImages[24] = 29;
} else {
- memcpy(_globalObjectNames + 0x60E / 62, " reward", 30);
+ strcpy(_globalObjectNames[25], " reward");
_inventoryImages[24] = 39;
}
}
diff --git a/engines/igor/staticres.cpp b/engines/igor/staticres.cpp
index 31761ebccf..b44090ce34 100644
--- a/engines/igor/staticres.cpp
+++ b/engines/igor/staticres.cpp
@@ -904,17 +904,6 @@ const uint8 IgorEngine::_mouseCursorData[] = {
0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05
};
-const uint32 IgorEngine::_fdsOffsetsTable[] = {
- 0x000000, 0x000001, 0x000002, 0x0018E4, 0x003301, 0x003302, 0x003303, 0x003304,
- 0x003305, 0x003306, 0x003307, 0x003308, 0x003309, 0x003EEB, 0x005908, 0x005909,
- 0x00590A, 0x01542C, 0x016418, 0x016419, 0x01D37F, 0x01E4A1, 0x01F42C, 0x01F95F,
- 0x026B80, 0x026B81, 0x026B82, 0x026B83, 0x026B84, 0x026B85, 0x026B86, 0x026B87,
- 0x026B88, 0x02CA59, 0x02DD76, 0x02ED6A, 0x02ED6B, 0x02ED6C, 0x02ED6D, 0x02ED6E,
- 0x02ED6F, 0x02ED70, 0x02ED71, 0x02ED72, 0x02ED73, 0x047F4F, 0x047F50, 0x04AC64,
- 0x04EFC5, 0x052755, 0x052756, 0x052988, 0x058119, 0x05811A, 0x06202A, 0x06202B,
- 0x06202C, 0x06202D, 0x06202E, 0x06202F, 0x062030, 0x062031, 0x070CB2
-};
-
const uint8 IgorEngine::PAL_48_1[] = {
0x2D, 0x16, 0x00, 0x3D, 0x26, 0x01, 0x32, 0x32, 0x24, 0x16, 0x1D, 0x16, 0x12, 0x19, 0x12, 0x0B,
0x12, 0x0B, 0x32, 0x32, 0x24, 0x16, 0x1D, 0x16, 0x12, 0x19, 0x12, 0x0B, 0x12, 0x0B, 0x3D, 0x3D,