scummvm/engines/gob/game.cpp

1699 lines
46 KiB
C++
Raw Normal View History

/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 Ivan Dubrov
2006-01-18 17:39:49 +00:00
* Copyright (C) 2004-2006 The ScummVM project
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#include "common/stdafx.h"
#include "common/endian.h"
#include "gob/gob.h"
#include "gob/global.h"
#include "gob/game.h"
#include "gob/video.h"
#include "gob/dataio.h"
#include "gob/pack.h"
#include "gob/scenery.h"
#include "gob/inter.h"
#include "gob/parse.h"
#include "gob/draw.h"
#include "gob/mult.h"
#include "gob/util.h"
#include "gob/goblin.h"
#include "gob/cdrom.h"
#include "gob/music.h"
#include "gob/palanim.h"
namespace Gob {
int16 Game::_captureCount = 0;
Common::Rect Game::_captureStack[20];
Game::Game(GobEngine *vm) : _vm(vm) {
_extTable = 0;
_totFileData = 0;
_totResourceTable = 0;
_imFileData = 0;
_extHandle = 0;
_collisionAreas = 0;
_shouldPushColls = 0;
_totTextData = 0;
// Collisions stack
_collStackSize = 0;
int i;
for (i = 0; i < 5; i++) {
_collStack[i] = 0;
_collStackElemSizes[i] = 0;
}
for (i = 0; i < 60; i++) {
_soundSamples[i] = 0;
_soundIds[i] = 0;
_soundTypes[i] = 0;
_soundFromExt[i] = 0;
_soundADL[i] = false;
}
_infIns = 0;
_infogrames = 0;
_curTotFile[0] = 0;
_curExtFile[0] = 0;
_totToLoad[0] = 0;
_startTimeKey = 0;
_mouseButtons = 0;
_lastCollKey = 0;
_lastCollAreaIndex = 0;
_lastCollId = 0;
_activeCollResId = 0;
_activeCollIndex = 0;
_handleMouse = 0;
_forceHandleMouse = 0;
_tempStr[0] = 0;
_curImaFile[0] = 0;
_collStr[0] = 0;
_backupedCount = 0;
_curBackupPos = 0;
for (i = 0; i < 5; i++) {
_cursorXDeltaArray[i] = 0;
_cursorYDeltaArray[i] = 0;
_totTextDataArray[i] = 0;
_totFileDataArray[i] = 0;
_totResourceTableArray[i] = 0;
_extTableArray[i] = 0;
_extHandleArray[i] = 0;
_imFileDataArray[i] = 0;
_variablesArray[i] = 0;
_curTotFileArray[i][0] = 0;
}
_imdFile = 0;
_curImdFile[0] = 0;
_imdX = 0;
_imdY = 0;
_imdFrameDataSize = 0;
_imdVidBufferSize = 0;
_imdFrameData = 0;
_imdVidBuffer = 0;
warning("GOB2 Stub! _byte_2FC82, _byte_2FC83, _word_2FC80");
_byte_2FC82 = 0;
_byte_2FC83 = 0;
_word_2FC80 = 0;
warning("GOB2 Stub! _byte_2FC9B, _dword_2F2B6");
_byte_2FC9B = 0;
_dword_2F2B6 = 0;
}
Game::~Game() {
if (_imdFile) {
if (_imdFile->palette)
delete[] _imdFile->palette;
if (_imdFile->surfDesc &&
(_imdFile->surfDesc != _vm->_draw->_spritesArray[20]) &&
(_imdFile->surfDesc != _vm->_draw->_spritesArray[21]))
_vm->_video->freeSurfDesc(_imdFile->surfDesc);
if (_imdFile->framesPos)
delete[] _imdFile->framesPos;
if (_imdFile->frameCoords)
delete[] _imdFile->frameCoords;
delete _imdFile;
}
if (_imdFrameData)
delete[] _imdFrameData;
if (_imdVidBuffer)
delete[] _imdVidBuffer;
if (_word_2FC80)
delete[] _word_2FC80;
if (_infIns)
delete _infIns;
for (int i = 0; i < 60; i++)
freeSoundSlot(i);
}
char *Game::loadExtData(int16 itemId, int16 *pResWidth, int16 *pResHeight, uint32 *dataSize) {
int16 commonHandle;
int16 itemsCount;
int32 offset;
uint32 size;
uint32 realSize;
ExtItem *item;
char isPacked;
int16 handle;
int32 tableSize;
char path[20];
char *dataBuf;
char *packedBuf;
char *dataPtr;
itemId -= 30000;
if (_extTable == 0)
return 0;
commonHandle = -1;
itemsCount = _extTable->itemsCount;
item = &_extTable->items[itemId];
tableSize = szGame_ExtTable + szGame_ExtItem * itemsCount;
offset = item->offset;
size = item->size;
if (item->width & 0x8000)
isPacked = 1;
else
isPacked = 0;
if (pResWidth != 0) {
*pResWidth = item->width & 0x7fff;
*pResHeight = item->height;
debugC(7, kDebugFileIO, "loadExtData(%d, %d, %d)", itemId, *pResWidth, *pResHeight);
}
debugC(7, kDebugFileIO, "loadExtData(%d, 0, 0)", itemId);
if (item->height == 0)
size += (item->width & 0x7fff) << 16;
debugC(7, kDebugFileIO, "size: %d off: %d", size, offset);
if (offset >= 0) {
handle = _extHandle;
} else {
offset = -(offset + 1);
tableSize = 0;
_vm->_dataio->closeData(_extHandle);
strcpy(path, "commun.ex1");
path[strlen(path) - 1] = *(_totFileData + 0x3c) + '0';
commonHandle = _vm->_dataio->openData(path);
handle = commonHandle;
}
debugC(7, kDebugFileIO, "off: %d size: %d", offset, tableSize);
_vm->_dataio->seekData(handle, offset + tableSize, SEEK_SET);
realSize = size;
// CHECKME: is the below correct?
if (isPacked)
dataBuf = new char[size];
else
dataBuf = new char[size];
dataPtr = dataBuf;
while (size > 32000) {
// BUG: huge->far conversion. Need normalization?
_vm->_dataio->readData(handle, (char *)dataPtr, 32000);
size -= 32000;
dataPtr += 32000;
}
_vm->_dataio->readData(handle, (char *)dataPtr, size);
if (commonHandle != -1) {
_vm->_dataio->closeData(commonHandle);
_extHandle = _vm->_dataio->openData(_curExtFile);
}
if (isPacked != 0) {
packedBuf = dataBuf;
realSize = READ_LE_UINT32(packedBuf);
dataBuf = new char[realSize];
_vm->_pack->unpackData(packedBuf, dataBuf);
delete[] packedBuf;
}
if (dataSize)
*dataSize = realSize;
return dataBuf;
}
void Game::freeCollision(int16 id) {
int16 i;
for (i = 0; i < 250; i++) {
if (_collisionAreas[i].id == id)
_collisionAreas[i].left = -1;
}
}
void Game::capturePush(int16 left, int16 top, int16 width, int16 height) {
int16 right;
if (_captureCount == 20)
error("capturePush: Capture stack overflow!");
_captureStack[_captureCount].left = left;
_captureStack[_captureCount].top = top;
_captureStack[_captureCount].right = left + width;
_captureStack[_captureCount].bottom = top + height;
_vm->_draw->_spriteTop = top;
_vm->_draw->_spriteBottom = height;
right = left + width - 1;
left &= 0xfff0;
right |= 0xf;
_vm->_draw->_spritesArray[30 + _captureCount] =
_vm->_video->initSurfDesc(_vm->_global->_videoMode, right - left + 1, height, 0);
_vm->_draw->_sourceSurface = 21;
_vm->_draw->_destSurface = 30 + _captureCount;
_vm->_draw->_spriteLeft = left;
_vm->_draw->_spriteRight = right - left + 1;
_vm->_draw->_destSpriteX = 0;
_vm->_draw->_destSpriteY = 0;
_vm->_draw->_transparency = 0;
_vm->_draw->spriteOperation(0);
_captureCount++;
}
void Game::capturePop(char doDraw) {
if (_captureCount <= 0)
return;
_captureCount--;
if (doDraw) {
_vm->_draw->_destSpriteX = _captureStack[_captureCount].left;
_vm->_draw->_destSpriteY = _captureStack[_captureCount].top;
_vm->_draw->_spriteRight =
_captureStack[_captureCount].width();
_vm->_draw->_spriteBottom =
_captureStack[_captureCount].height();
_vm->_draw->_transparency = 0;
_vm->_draw->_sourceSurface = 30 + _captureCount;
_vm->_draw->_destSurface = 21;
_vm->_draw->_spriteLeft = _vm->_draw->_destSpriteX & 0xf;
_vm->_draw->_spriteTop = 0;
_vm->_draw->spriteOperation(0);
}
_vm->_video->freeSurfDesc(_vm->_draw->_spritesArray[30 + _captureCount]);
_vm->_draw->_spritesArray[30 + _captureCount] = 0;
}
char *Game::loadTotResource(int16 id, int16 *dataSize) {
TotResItem *itemPtr;
int32 offset;
itemPtr = &_totResourceTable->items[id];
offset = itemPtr->offset;
if (dataSize)
*dataSize = itemPtr->size;
if (offset >= 0) {
return _totResourceTable->dataPtr + szGame_TotResTable +
szGame_TotResItem * _totResourceTable->itemsCount + offset;
} else {
return (char *)(_imFileData + (int32)READ_LE_UINT32(&((int32 *)_imFileData)[-offset - 1]));
}
}
void Game::loadSound(int16 slot, char *dataPtr, uint32 dataSize) {
Snd::SoundDesc *soundDesc;
byte *data = (byte *) dataPtr;
soundDesc = new Snd::SoundDesc;
_soundSamples[slot] = soundDesc;
soundDesc->frequency = (data[4] << 8) + data[5];
// Somehow, one sound in one CD version has a wrong size, leading to statics and crashes
soundDesc->size = MIN((uint32) ((data[1] << 16) + (data[2] << 8) + data[3]), dataSize - 6);
soundDesc->data = dataPtr + 6;
soundDesc->timerTicks = (int32)1193180 / (int32)soundDesc->frequency;
soundDesc->inClocks = (soundDesc->frequency * 10) / 182;
soundDesc->flag = 0;
}
void Game::freeSoundSlot(int16 slot) {
if (slot == -1)
slot = _vm->_parse->parseValExpr();
if ((slot < 0) || (slot >= 60) || (_soundSamples[slot] == 0))
return;
if (_soundADL[slot]) {
if (_vm->_adlib && (_vm->_adlib->getIndex() == slot))
_vm->_adlib->stopPlay();
if (_soundFromExt[slot] == 1) {
delete[] _soundSamples[slot]->data;
_soundFromExt[slot] = 0;
}
2007-01-28 15:24:22 +00:00
delete _soundSamples[slot];
} else {
char* data = _soundSamples[slot]->data;
_vm->_snd->freeSoundDesc(_soundSamples[slot], false);
if (_soundFromExt[slot] == 1) {
delete[] (data - 6);
_soundFromExt[slot] = 0;
}
}
_soundSamples[slot] = 0;
}
int16 Game::adjustKey(int16 key) {
if (key <= 0x60 || key >= 0x7b)
return key;
return key - 0x20;
}
int32 Game::loadTotFile(char *path) {
int16 handle;
int32 size;
size = -1;
handle = _vm->_dataio->openData(path);
if (handle >= 0) {
_vm->_dataio->closeData(handle);
size = _vm->_dataio->getDataSize(path);
_totFileData = _vm->_dataio->getData(path);
} else {
_totFileData = 0;
}
return size;
}
void Game::loadExtTable(void) {
int16 count, i;
// Function is correct. [sev]
_extHandle = _vm->_dataio->openData(_curExtFile);
if (_extHandle < 0)
return;
_vm->_dataio->readData(_extHandle, (char *)&count, 2);
count = FROM_LE_16(count);
_vm->_dataio->seekData(_extHandle, 0, 0);
_extTable = new ExtTable;
_extTable->items = 0;
if (count)
_extTable->items = new ExtItem[count];
_vm->_dataio->readData(_extHandle, (char *)&_extTable->itemsCount, 2);
_extTable->itemsCount = FROM_LE_16(_extTable->itemsCount);
_vm->_dataio->readData(_extHandle, (char *)&_extTable->unknown, 1);
for (i = 0; i < count; i++) {
_vm->_dataio->readData(_extHandle, (char *)&_extTable->items[i].offset, 4);
_extTable->items[i].offset = FROM_LE_32(_extTable->items[i].offset);
_vm->_dataio->readData(_extHandle, (char *)&_extTable->items[i].size, 2);
_extTable->items[i].size = FROM_LE_16(_extTable->items[i].size);
_vm->_dataio->readData(_extHandle, (char *)&_extTable->items[i].width, 2);
_extTable->items[i].width = FROM_LE_16(_extTable->items[i].width);
_vm->_dataio->readData(_extHandle, (char *)&_extTable->items[i].height, 2);
_extTable->items[i].height = FROM_LE_16(_extTable->items[i].height);
}
}
void Game::loadImFile(void) {
char path[20];
int16 handle;
if (_totFileData[0x3d] != 0 && _totFileData[0x3b] == 0)
return;
strcpy(path, "commun.im1");
if (_totFileData[0x3b] != 0)
path[strlen(path) - 1] = '0' + _totFileData[0x3b];
handle = _vm->_dataio->openData(path);
if (handle < 0)
return;
_vm->_dataio->closeData(handle);
_imFileData = _vm->_dataio->getData(path);
}
void Game::start(void) {
int i;
_collisionAreas = new Collision[250];
memset(_collisionAreas, 0, 250 * sizeof(Collision));
prepareStart();
playTot(-2);
delete[] _collisionAreas;
_vm->_draw->closeScreen();
_vm->_draw->_spritesArray[20] = 0;
for (i = 0; i < 50; i++) {
_vm->_video->freeSurfDesc(_vm->_draw->_spritesArray[i]);
_vm->_draw->_spritesArray[i] = 0;
}
_vm->_video->freeSurfDesc(_vm->_draw->_scummvmCursor);
}
// flagbits: 0 = freeInterVariables, 1 = skipPlay
void Game::totSub(int8 flags, char *newTotFile) {
int8 curBackupPos;
if (_backupedCount >= 5)
return;
_cursorXDeltaArray[_backupedCount] = _vm->_draw->_cursorXDeltaVar;
_cursorYDeltaArray[_backupedCount] = _vm->_draw->_cursorYDeltaVar;
_totTextDataArray[_backupedCount] = _totTextData;
_totFileDataArray[_backupedCount] = _totFileData;
_totResourceTableArray[_backupedCount] = _totResourceTable;
_extTableArray[_backupedCount] = _extTable;
_extHandleArray[_backupedCount] = _extHandle;
_imFileDataArray[_backupedCount] = _imFileData;
_variablesArray[_backupedCount] = _vm->_global->_inter_variables;
_variablesSizesArray[_backupedCount] = _vm->_global->_inter_variablesSizes;
strcpy(_curTotFileArray[_backupedCount], _curTotFile);
curBackupPos = _curBackupPos;
_backupedCount++;
_curBackupPos = _backupedCount;
_totTextData = 0;
_totFileData = 0;
_totResourceTable = 0;
if (flags & 1) {
_vm->_global->_inter_variables = 0;
_vm->_global->_inter_variablesSizes = 0;
}
strcpy(_curTotFile, newTotFile);
strcat(_curTotFile, ".TOT");
if (_vm->_inter->_terminate != 0)
return;
pushCollisions(0);
if (flags & 2)
playTot(-1);
else
playTot(0);
if (_vm->_inter->_terminate != 2)
_vm->_inter->_terminate = 0;
popCollisions();
if ((flags & 1) && (_vm->_global->_inter_variables != 0)) {
delete[] _vm->_global->_inter_variables;
delete[] _vm->_global->_inter_variablesSizes;
}
_backupedCount--;
_curBackupPos = curBackupPos;
_vm->_draw->_cursorXDeltaVar = _cursorXDeltaArray[_backupedCount];
_vm->_draw->_cursorYDeltaVar = _cursorYDeltaArray[_backupedCount];
_totTextData = _totTextDataArray[_backupedCount];
_totFileData = _totFileDataArray[_backupedCount];
_totResourceTable = _totResourceTableArray[_backupedCount];
_extTable = _extTableArray[_backupedCount];
_extHandle = _extHandleArray[_backupedCount];
_imFileData = _imFileDataArray[_backupedCount];
_vm->_global->_inter_variables = _variablesArray[_backupedCount];
_vm->_global->_inter_variablesSizes = _variablesSizesArray[_backupedCount];
strcpy(_curTotFile, _curTotFileArray[_backupedCount]);
strcpy(_curExtFile, _curTotFile);
_curExtFile[strlen(_curExtFile)-4] = '\0';
strcat(_curExtFile, ".EXT");
}
void Game::switchTotSub(int16 index, int16 skipPlay) {
int16 backupedCount;
int16 curBackupPos;
if ((_backupedCount - index) < 1)
return;
curBackupPos = _curBackupPos;
backupedCount = _backupedCount;
if (_curBackupPos == _backupedCount) {
_cursorXDeltaArray[_backupedCount] = _vm->_draw->_cursorXDeltaVar;
_cursorYDeltaArray[_backupedCount] = _vm->_draw->_cursorYDeltaVar;
_totTextDataArray[_backupedCount] = _totTextData;
_totFileDataArray[_backupedCount] = _totFileData;
_totResourceTableArray[_backupedCount] = _totResourceTable;
_extTableArray[_backupedCount] = _extTable;
_extHandleArray[_backupedCount] = _extHandle;
_imFileDataArray[_backupedCount] = _imFileData;
_variablesArray[_backupedCount] = _vm->_global->_inter_variables;
_variablesSizesArray[_backupedCount] = _vm->_global->_inter_variablesSizes;
strcpy(_curTotFileArray[_backupedCount], _curTotFile);
_backupedCount++;
}
_curBackupPos -= index;
if (index >= 0)
_curBackupPos--;
_vm->_draw->_cursorXDeltaVar = _cursorXDeltaArray[_curBackupPos];
_vm->_draw->_cursorYDeltaVar = _cursorYDeltaArray[_curBackupPos];
_totTextData = _totTextDataArray[_curBackupPos];
_totFileData = _totFileDataArray[_curBackupPos];
_totResourceTable = _totResourceTableArray[_curBackupPos];
_imFileData = _imFileDataArray[_curBackupPos];
_extTable = _extTableArray[_curBackupPos];
_extHandle = _extHandleArray[_curBackupPos];
_vm->_global->_inter_variables = _variablesArray[_curBackupPos];
_vm->_global->_inter_variablesSizes = _variablesSizesArray[_curBackupPos];
strcpy(_curTotFile, _curTotFileArray[_curBackupPos]);
strcpy(_curExtFile, _curTotFile);
_curExtFile[strlen(_curExtFile)-4] = '\0';
strcat(_curExtFile, ".EXT");
if (_vm->_inter->_terminate != 0)
return;
_vm->_game->pushCollisions(0);
_vm->_game->playTot(skipPlay);
if (_vm->_inter->_terminate != 2)
_vm->_inter->_terminate = 0;
_vm->_game->popCollisions();
_curBackupPos = curBackupPos;
_backupedCount = backupedCount;
_vm->_draw->_cursorXDeltaVar = _cursorXDeltaArray[_curBackupPos];
_vm->_draw->_cursorYDeltaVar = _cursorYDeltaArray[_curBackupPos];
_totTextData = _totTextDataArray[_curBackupPos];
_totFileData = _totFileDataArray[_curBackupPos];
_totResourceTable = _totResourceTableArray[_curBackupPos];
_extTable = _extTableArray[_curBackupPos];
_extHandle = _extHandleArray[_curBackupPos];
_imFileData = _imFileDataArray[_curBackupPos];
_vm->_global->_inter_variables = _variablesArray[_curBackupPos];
_vm->_global->_inter_variablesSizes = _variablesSizesArray[_curBackupPos];
strcpy(_curTotFile, _curTotFileArray[_curBackupPos]);
strcpy(_curExtFile, _curTotFile);
_curExtFile[strlen(_curExtFile)-4] = '\0';
strcat(_curExtFile, ".EXT");
}
int16 Game::openLocTextFile(char *locTextFile, int language) {
int n;
n = strlen(locTextFile);
if (n < 4)
return -1;
locTextFile[n - 4] = 0;
switch (language) {
case 0:
strcat(locTextFile, ".dat");
break;
case 1:
strcat(locTextFile, ".all");
break;
case 3:
strcat(locTextFile, ".esp");
break;
case 4:
strcat(locTextFile, ".ita");
break;
case 5:
strcat(locTextFile, ".usa");
break;
case 6:
strcat(locTextFile, ".ndl");
break;
case 7:
strcat(locTextFile, ".kor");
break;
case 8:
strcat(locTextFile, ".isr");
break;
default:
strcat(locTextFile, ".ang");
break;
}
return _vm->_dataio->openData(locTextFile);
}
char *Game::loadLocTexts(void) {
char locTextFile[20];
int16 handle;
int i;
strcpy(locTextFile, _curTotFile);
handle = openLocTextFile(locTextFile, _vm->_global->_language);
if ((handle < 0) && !scumm_stricmp(_vm->_game->_curTotFile, _vm->_startTot0)) {
warning("Your game version doesn't support the requested language, using the first one available");
for (i = 0; i < 10; i++) {
handle = openLocTextFile(locTextFile, i);
if (handle >= 0) {
_vm->_global->_language = i;
break;
}
}
}
if (handle >= 0) {
_vm->_dataio->closeData(handle);
return _vm->_dataio->getData(locTextFile);
}
return 0;
}
void Game::setCollisions(void) {
char *savedIP;
int16 left;
int16 top;
int16 width;
int16 height;
Collision *collArea;
for (collArea = _collisionAreas; collArea->left != -1; collArea++) {
if (((collArea->id & 0xC000) != 0x8000) || (collArea->field_12 == 0))
continue;
savedIP = _vm->_global->_inter_execPtr;
_vm->_global->_inter_execPtr = _totFileData + collArea->field_12;
left = _vm->_parse->parseValExpr();
top = _vm->_parse->parseValExpr();
width = _vm->_parse->parseValExpr();
height = _vm->_parse->parseValExpr();
if ((_vm->_draw->_renderFlags & 8) && (left != -1)) {
left += _vm->_draw->_backDeltaX;
top += _vm->_draw->_backDeltaY;
}
if (_vm->_draw->_word_2E8E2 != 2) {
_vm->_draw->adjustCoords(0, &left, &top);
if ((collArea->flags & 0x0F) < 3)
_vm->_draw->adjustCoords(2, &width, &height);
else {
height &= 0xFFFE;
_vm->_draw->adjustCoords(2, 0, &height);
}
}
collArea->left = left;
collArea->top = top;
collArea->right = left + width - 1;
collArea->bottom = top + height - 1;
_vm->_global->_inter_execPtr = savedIP;
}
}
void Game::collSub(int16 offset) {
char *savedIP;
int16 collStackSize;
savedIP = _vm->_global->_inter_execPtr;
_vm->_global->_inter_execPtr = _totFileData + offset;
_shouldPushColls = 1;
collStackSize = _collStackSize;
_vm->_inter->funcBlock(0);
if (collStackSize != _collStackSize)
popCollisions();
_shouldPushColls = 0;
_vm->_global->_inter_execPtr = savedIP;
setCollisions();
}
void Game::collAreaSub(int16 index, int8 enter) {
uint16 collId;
collId = _collisionAreas[index].id & 0xF000;
2006-11-14 15:39:11 +00:00
if ((collId == 0xA000) || (collId == 0x9000)) {
if (enter == 0)
WRITE_VAR(17, _collisionAreas[index].id & 0x0FFF);
else
WRITE_VAR(17, -(_collisionAreas[index].id & 0x0FFF));
}
if (enter != 0) {
if (_collisionAreas[index].funcEnter != 0)
collSub(_collisionAreas[index].funcEnter);
} else {
if (_collisionAreas[index].funcLeave != 0)
collSub(_collisionAreas[index].funcLeave);
}
}
Snd::SoundDesc *Game::loadSND(const char *path, int8 arg_4) {
Snd::SoundDesc *soundDesc;
uint32 dSize;
char *data;
char *dataPtr;
soundDesc = new Snd::SoundDesc;
dSize = _vm->_dataio->getDataSize(path) - 6;
data = _vm->_dataio->getData(path);
soundDesc->data = new char[dSize];
soundDesc->flag = *data ? (*data & 0x7F) : 8;
dataPtr = data + 4;
WRITE_LE_UINT16(dataPtr, READ_BE_UINT16(dataPtr));
WRITE_LE_UINT32(data,
(READ_LE_UINT32(data) >> 24) +
((READ_LE_UINT16(data) & 0xFF00) << 8) +
((READ_LE_UINT16(data + 2) & 0xFF) >> 8));
soundDesc->size = MAX(dSize, READ_LE_UINT32(data));
soundDesc->frequency = READ_LE_UINT16(dataPtr);
soundDesc->timerTicks = 1193180 / READ_LE_UINT16(dataPtr);
memcpy(soundDesc->data, data + 6, dSize - 6);
if (arg_4 & 2)
arg_4 |= 1;
if ((soundDesc->frequency < 4700) && (arg_4 & 1))
arg_4 &= 0xFE;
if (arg_4 & 1) {
if ((_vm->_global->_soundFlags & BLASTER_FLAG) || (_vm->_global->_soundFlags & PROAUDIO_FLAG)) {
}
}
return soundDesc;
}
int8 Game::openImd(const char *path, int16 x, int16 y, int16 repeat, int16 flags) {
int i;
int j;
const char *src;
byte *vidMem;
Video::SurfaceDesc *surfDesc;
if (path[0] != 0) {
if (_imdFile == 0)
_curImdFile[0] = 0;
src = strrchr(path, '\\');
src = src == 0 ? path : src+1;
if (strcmp(_curImdFile, src) != 0) {
closeImd();
_imdFile = loadImdFile(path, 0, 2);
if (_imdFile == 0)
return 0;
_imdX = _imdFile->x;
_imdY = _imdFile->y;
strcpy(_curImdFile, src);
_imdFrameData = new byte[_imdFrameDataSize + 1000];
_imdVidBuffer = new byte[_imdVidBufferSize + 1000];
memset(_imdFrameData, 0, _imdFrameDataSize + 1000);
memset(_imdVidBuffer, 0, _imdVidBufferSize + 1000);
if (_vm->_global->_videoMode == 0x14) {
_byte_2FC83 = (flags & 0x80) ? 1 : 0;
if (!(_imdFile->field_E & 0x100) || (_imdFile->field_E & 0x2000)) {
setImdXY(_imdFile, 0, 0);
_imdFile->surfDesc =
_vm->_video->initSurfDesc(0x13, _imdFile->width, _imdFile->height, 0);
} else {
if (_byte_2FC82 == 0)
_imdFile->surfDesc = _vm->_draw->_spritesArray[21];
else
_imdFile->surfDesc = _vm->_draw->_spritesArray[20];
if ((x != -1) || (y != -1)) {
_imdX = x != -1 ? x : _imdX;
_imdY = y != -1 ? y : _imdY;
setImdXY(_imdFile, _imdX, _imdY);
}
}
if (flags & 0x40) {
_imdX = x != -1 ? x : _imdX;
_imdY = y != -1 ? y : _imdY;
if ((_imdFile->surfDesc->vidMode & 0x7F) == 0x14) {
surfDesc = _vm->_video->initSurfDesc(0x13, _imdFile->width, _imdFile->height, 0);
_vm->_video->drawSprite(_vm->_draw->_spritesArray[21], surfDesc, _imdX, _imdY,
_imdX + _imdFile->width - 1, _imdY + _imdFile->height - 1, 0, 0, 0);
vidMem = _imdFile->surfDesc->vidPtr;
for (i = 0; i < _imdFile->height; i++)
for (j = 0; j < _imdFile->width; j++, vidMem++) {
*(vidMem) = *(surfDesc->vidPtr
+ (j / 4)
+ (surfDesc->width / 4 * i)
+ (surfDesc->reserved2 * (j & 3)));
}
_vm->_video->freeSurfDesc(surfDesc);
}
}
} else {
if ((x != -1) || (y != -1)) {
_imdX = x != -1 ? x : _imdX;
_imdY = y != -1 ? y : _imdY;
setImdXY(_imdFile, _imdX, _imdY);
}
_byte_2FC83 = (flags & 0x80) ? 1 : 0;
if (_byte_2FC83 == 0)
_imdFile->surfDesc = _vm->_draw->_spritesArray[21];
else
_imdFile->surfDesc = _vm->_draw->_spritesArray[20];
}
}
}
if (_imdFile == 0)
return 0;
if (repeat == -1) {
closeImd();
return 0;
}
_imdX = x != -1 ? x : _imdX;
_imdY = y != -1 ? y : _imdY;
WRITE_VAR(7, _imdFile->framesCount);
return 1;
}
void Game::closeImd(void) {
if (_imdFile == 0)
return;
if ((_imdFile->surfDesc != _vm->_draw->_spritesArray[20]) &&
(_imdFile->surfDesc != _vm->_draw->_spritesArray[21]))
_vm->_video->freeSurfDesc(_imdFile->surfDesc);
finishImd(_imdFile);
delete[] _imdFrameData;
delete[] _imdVidBuffer;
_imdFrameData = 0;
_imdVidBuffer = 0;
_imdFile = 0;
}
void Game::finishImd(Game::Imd *imdPtr) {
if (imdPtr == 0)
return;
/*
if (dword_31345 != 0) {
_vm->_sound->stopSound(0);
dword_31345 = 0;
delete off_31461;
byte_31344 = 0;
}
*/
_vm->_dataio->closeData(imdPtr->fileHandle);
if (imdPtr->frameCoords != 0)
delete[] imdPtr->frameCoords;
if (imdPtr->palette != 0)
delete[] imdPtr->palette;
if (imdPtr->framesPos != 0)
delete[] imdPtr->framesPos;
delete imdPtr;
imdPtr = 0;
}
// flagsBit: 0 = read and set palette
// 1 = read palette
Game::Imd *Game::loadImdFile(const char *path, Video::SurfaceDesc *surfDesc, int8 flags) {
int i;
Imd *imdPtr;
int16 handle;
int16 setAllPalBak;
char buf[18];
Video::Color *palBak;
int32 byte_31449 = 0;
int32 byte_3144D = 0;
buf[0] = 0;
strcpy(buf, path);
strcat(buf, ".IMD");
handle = _vm->_dataio->openData(buf);
if (handle < 0) {
warning("Can't open IMD \"%s\"", buf);
return 0;
}
imdPtr = new Imd;
memset(imdPtr, 0, sizeof(Imd));
imdPtr->palette = 0;
_vm->_dataio->readData(handle, buf, 18);
// "fileHandle" holds the major version while loading
imdPtr->fileHandle = READ_LE_UINT16(buf);
imdPtr->verMin = READ_LE_UINT16(buf + 2);
imdPtr->framesCount = READ_LE_UINT16(buf + 4);
imdPtr->x = READ_LE_UINT16(buf + 6);
imdPtr->y = READ_LE_UINT16(buf + 8);
imdPtr->width = READ_LE_UINT16(buf + 10);
imdPtr->height = READ_LE_UINT16(buf + 12);
imdPtr->field_E = READ_LE_UINT16(buf + 14);
imdPtr->curFrame = READ_LE_UINT16(buf + 16);
if (imdPtr->fileHandle != 0)
imdPtr->verMin = 0;
if ((imdPtr->verMin & 0xFF) < 2) {
warning("IMD version incorrect (%d,%d)", imdPtr->fileHandle, imdPtr->verMin);
_vm->_dataio->closeData(handle);
delete imdPtr;
return 0;
}
imdPtr->surfDesc = surfDesc;
imdPtr->framesPos = 0;
imdPtr->firstFramePos = imdPtr->curFrame;
if (flags & 3) {
imdPtr->palette = new Video::Color[256];
_vm->_dataio->readData(handle, (char *) imdPtr->palette, 768);
} else {
_vm->_dataio->seekData(handle, 768, 1);
imdPtr->palette = 0;
}
if ((flags & 3) == 1) {
palBak = _vm->_global->_pPaletteDesc->vgaPal;
setAllPalBak = _vm->_global->_setAllPalette;
_vm->_global->_pPaletteDesc->vgaPal = imdPtr->palette;
_vm->_global->_setAllPalette = 1;
_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
_vm->_global->_setAllPalette = setAllPalBak;
_vm->_global->_pPaletteDesc->vgaPal = palBak;
}
if ((imdPtr->verMin & 0xFF) >= 3) {
_vm->_dataio->readData(handle, buf, 2);
imdPtr->stdX = READ_LE_UINT16(buf);
if (imdPtr->stdX > 1) {
warning("IMD ListI incorrect (%d)", imdPtr->stdX);
_vm->_dataio->closeData(handle);
delete imdPtr;
return 0;
}
if (imdPtr->stdX != 0) {
_vm->_dataio->readData(handle, buf, 8);
imdPtr->stdX = READ_LE_UINT16(buf);
imdPtr->stdY = READ_LE_UINT16(buf + 2);
imdPtr->stdWidth = READ_LE_UINT16(buf + 4);
imdPtr->stdHeight = READ_LE_UINT16(buf + 6);
} else
imdPtr->stdX = -1;
} else
imdPtr->stdX = -1;
if ((imdPtr->verMin & 0xFF) >= 4) {
_vm->_dataio->readData(handle, buf, 4);
byte_31449 = READ_LE_UINT32(buf);
imdPtr->framesPos = byte_31449 == 0 ? 0 : new int32[imdPtr->framesCount];
} else
imdPtr->framesPos = 0;
if (imdPtr->verMin & 0x8000) {
_vm->_dataio->readData(handle, buf, 4);
byte_3144D = READ_LE_UINT32(buf);
}
if (imdPtr->verMin & 0x4000) {
// loc_29C4F
warning("GOB2 Stub! loadImdFile, imdPtr->verMin & 0x4000");
warning("Can't open IMD \"%s.IMD\"", path);
return 0;
// Sound stuff, I presume...
}
if (imdPtr->verMin & 0x2000) {
_vm->_dataio->readData(handle, buf, 4);
imdPtr->frameDataSize = READ_LE_UINT16(buf);
imdPtr->vidBufferSize = READ_LE_UINT16(buf + 2);
} else {
imdPtr->frameDataSize = imdPtr->width * imdPtr->height + 1000;
imdPtr->vidBufferSize = imdPtr->width * imdPtr->height + 1000;
}
if (imdPtr->framesPos != 0) {
_vm->_dataio->seekData(handle, byte_31449, 0);
for (i = 0; i < imdPtr->framesCount; i++) {
_vm->_dataio->readData(handle, buf, 4);
imdPtr->framesPos[i] = READ_LE_UINT32(buf);
}
}
if (imdPtr->verMin & 0x8000) {
_vm->_dataio->seekData(handle, byte_3144D, 0);
imdPtr->frameCoords = new ImdCoord[imdPtr->framesCount];
for (i = 0; i < imdPtr->framesCount; i++) {
_vm->_dataio->readData(handle, buf, 8);
imdPtr->frameCoords[i].left = READ_LE_UINT16(buf);
imdPtr->frameCoords[i].top = READ_LE_UINT16(buf + 2);
imdPtr->frameCoords[i].right = READ_LE_UINT16(buf + 4);
imdPtr->frameCoords[i].bottom = READ_LE_UINT16(buf + 6);
}
} else
imdPtr->frameCoords = 0;
_vm->_dataio->seekData(handle, imdPtr->firstFramePos, 0);
imdPtr->curFrame = 0;
imdPtr->fileHandle = handle;
imdPtr->filePos = imdPtr->firstFramePos;
_imdFrameDataSize = imdPtr->frameDataSize;
_imdVidBufferSize = imdPtr->vidBufferSize;
if (flags & 0x80) {
imdPtr->verMin |= 0x1000;
warning("GOB2 Stub! loadImdFile(), flags & 0x80");
}
return imdPtr;
}
void Game::setImdXY(Game::Imd *imdPtr, int16 x, int16 y) {
int i;
if (imdPtr->stdX != -1) {
imdPtr->stdX = imdPtr->stdX - imdPtr->x + x;
imdPtr->stdY = imdPtr->stdY - imdPtr->y + y;
}
if (imdPtr->frameCoords != 0) {
for (i = 0; i < imdPtr->framesCount; i++) {
imdPtr->frameCoords[i].left -= imdPtr->frameCoords[i].left - imdPtr->x + x;
imdPtr->frameCoords[i].top -= imdPtr->frameCoords[i].top - imdPtr->y + y;
imdPtr->frameCoords[i].right -= imdPtr->frameCoords[i].right - imdPtr->x + x;
imdPtr->frameCoords[i].bottom -= imdPtr->frameCoords[i].bottom - imdPtr->y + y;
}
}
imdPtr->x = x;
imdPtr->y = y;
}
void Game::playImd(int16 frame, int16 arg_2, int16 arg_4, int16 arg_6, int16 arg_8, int16 lastFrame) {
int16 var_1;
int16 var_4 = 0;
byte *vidMemBak;
Video::SurfaceDesc *surfDescBak;
Video::SurfaceDesc frontSurfBak;
int8 byte_31344 = 0;
if ((frame < 0) || (frame > lastFrame))
return;
if ((frame == arg_8) || ((frame == lastFrame) && (arg_2 == 8))) { // loc_1C3F0
var_1 = 1;
_vm->_draw->_applyPal = 0;
if (arg_2 >= 4) {
if (arg_4 != -1)
memcpy( ((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + arg_4 * 3,
((char *) (_imdFile->palette)) + arg_4 * 3, (arg_6 - arg_4 + 1) * 3);
else
memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, (char *) _imdFile->palette, 768);
}
} else
var_1 = 0;
if ((var_1 == 1) && (arg_2 == 8) && (_byte_2FC83 != 0))
_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
if (_imdFile->surfDesc->vidMode == 0x14) {
if ((_byte_2FC82 != 0) && (_word_2FC80 == _vm->_draw->_spritesArray[20]->vidPtr)) {
vidMemBak = _vm->_draw->_spritesArray[20]->vidPtr;
_vm->_draw->_spritesArray[20]->vidPtr = _vm->_draw->_spritesArray[21]->vidPtr;
var_4 = viewImd(_imdFile, frame);
_vm->_draw->_spritesArray[20]->vidPtr = vidMemBak;
} else
var_4 = viewImd(_imdFile, frame);
if (_byte_2FC82 == 0) {
if ((_imdFile->frameCoords == 0) || (_imdFile->frameCoords[frame].left == -1))
_vm->_draw->invalidateRect(_imdX, _imdY,
_imdX + _imdFile->width - 1, _imdY + _imdFile->height - 1);
else
_vm->_draw->invalidateRect(_imdFile->frameCoords[frame].left,
_imdFile->frameCoords[frame].top, _imdFile->frameCoords[frame].right,
_imdFile->frameCoords[frame].bottom);
}
} else {
if ((_imdFile->field_E & 0x100) && (_vm->_global->_videoMode == 0x14) &&
(_byte_2FC82 != 0) && (sub_2C825(_imdFile) & 0x8000) && (_byte_2FC83 == 0)) {
surfDescBak = _imdFile->surfDesc;
if (_word_2FC80 == _vm->_draw->_spritesArray[20]->vidPtr)
_imdFile->surfDesc = _vm->_draw->_spritesArray[21];
else
_imdFile->surfDesc = _vm->_draw->_spritesArray[20];
setImdXY(_imdFile, _imdX, _imdY);
var_4 = viewImd(_imdFile, frame);
_imdFile->surfDesc = surfDescBak;
setImdXY(_imdFile, 0, 0);
} else {
var_4 = viewImd(_imdFile, frame);
if (!(var_4 & 0x800)) {
if (_byte_2FC83 == 0) {
if (_vm->_global->_videoMode == 0x14) {
if (_byte_2FC82 == 0) {
memcpy((char *) &frontSurfBak, (char *) &_vm->_draw->_frontSurface,
sizeof(Video::SurfaceDesc));
memcpy((char *) &_vm->_draw->_frontSurface, (char *) &_vm->_draw->_spritesArray[21],
sizeof(Video::SurfaceDesc));
imdDrawFrame(_imdFile, frame, _imdX, _imdY);
memcpy((char *) &_vm->_draw->_frontSurface, (char *) &frontSurfBak,
sizeof(Video::SurfaceDesc));
if ((_imdFile->frameCoords == 0) || (_imdFile->frameCoords[frame].left == -1))
_vm->_draw->invalidateRect(_imdX, _imdY, _imdX + _imdFile->width - 1,
_imdY + _imdFile->height - 1);
else
_vm->_draw->invalidateRect(_imdFile->frameCoords[frame].left,
_imdFile->frameCoords[frame].top, _imdFile->frameCoords[frame].right,
_imdFile->frameCoords[frame].bottom);
} else {
if (_word_2FC80 == _vm->_draw->_spritesArray[20]->vidPtr) { // loc_1C68D
memcpy((char *) &frontSurfBak, (char *) &_vm->_draw->_frontSurface,
sizeof(Video::SurfaceDesc));
memcpy((char *) &_vm->_draw->_frontSurface, (char *) &_vm->_draw->_spritesArray[21],
sizeof(Video::SurfaceDesc));
imdDrawFrame(_imdFile, frame, _imdX, _imdY);
memcpy((char *) &_vm->_draw->_frontSurface, (char *) &frontSurfBak,
sizeof(Video::SurfaceDesc));
} else
imdDrawFrame(_imdFile, frame, _imdX, _imdY);
}
} else {
if ((_imdFile->frameCoords == 0) || (_imdFile->frameCoords[frame].left == -1))
_vm->_draw->invalidateRect(_imdX, _imdY, _imdX + _imdFile->width - 1,
_imdY + _imdFile->height - 1);
else
_vm->_draw->invalidateRect(_imdFile->frameCoords[frame].left,
_imdFile->frameCoords[frame].top, _imdFile->frameCoords[frame].right,
_imdFile->frameCoords[frame].bottom);
}
} else
if (_vm->_global->_videoMode == 0x14)
imdDrawFrame(_imdFile, frame, _imdX, _imdY);
}
}
}
if ((var_1 != 0) && (arg_2 == 16)) {
if ((_vm->_draw->_spritesArray[20] != _vm->_draw->_spritesArray[21]) && (_byte_2FC83 == 0))
_vm->_video->drawSprite(_vm->_draw->_spritesArray[21],
_vm->_draw->_spritesArray[20], 0, 0,
_vm->_draw->_spritesArray[21]->width - 1,
_vm->_draw->_spritesArray[21]->height - 1, 0, 0, 0);
_vm->_palanim->fade(_vm->_global->_pPaletteDesc, -2, 0);
_vm->_draw->_noInvalidated = 1;
}
if ((var_1 != 0) && (arg_2 == 8) && (_byte_2FC83 == 0))
_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
if (!(var_4 & 0x800)) {
if (_vm->_draw->_cursorIndex == -1) {
if (_byte_2FC82 != 0) {
if (_word_2FC80 == _vm->_draw->_spritesArray[20]->vidPtr)
_word_2FC80 = _vm->_draw->_spritesArray[21]->vidPtr;
else
_word_2FC80 = _vm->_draw->_spritesArray[20]->vidPtr;
warning("GOB2 Stub! sub_1BC3A(_word_2FC80);");
} else
_vm->_draw->blitInvalidated();
} else
_vm->_draw->animateCursor(-1);
}
if ((var_1 != 0) && ((arg_2 == 2) || (arg_2 == 4)))
_vm->_palanim->fade(_vm->_global->_pPaletteDesc, -2, 0);
// To allow quitting, etc. during IMDs
_vm->_util->processInput();
if (_vm->_quitRequested)
return;
if (byte_31344 != 2) {
if (var_4 & 0x800) {
if (_dword_2F2B6 == 0)
_vm->_util->delay(30);
else {
_dword_2F2B6 -= 30;
if (_dword_2F2B6 < 0)
_dword_2F2B6 = 0;
}
} else
_vm->_util->waitEndFrame();
}
_vm->_inter->animPalette();
}
int16 Game::viewImd(Game::Imd *imdPtr, int16 frame) {
int16 x;
int16 y;
int16 width;
int16 height;
int16 retVal;
uint32 tmp;
char buf[4];
int8 var_4;
int32 var_12 = 0;
// .---
int16 word_31451 = 0;
int8 byte_31344 = 0;
int8 byte_2DA60 = 0;
int16 word_2DA61 = -1;
// '---
word_31451 = 0;
if (imdPtr == 0)
return (int16)0x8000;
retVal = 0;
var_4 = 0;
if (frame != imdPtr->curFrame) {
retVal |= 0x2000;
if (frame == 0)
imdPtr->filePos = imdPtr->firstFramePos;
else if (frame == 1) {
imdPtr->filePos = imdPtr->firstFramePos;
_vm->_dataio->seekData(imdPtr->fileHandle, imdPtr->filePos, 0);
_vm->_dataio->readData(imdPtr->fileHandle, buf, 2);
tmp = READ_LE_UINT16(buf);
imdPtr->filePos += tmp + 4;
} else if (imdPtr->framesPos != 0)
imdPtr->filePos = imdPtr->framesPos[frame];
else
error("Image %d inaccessible in IMD", frame);
imdPtr->curFrame = frame;
_vm->_dataio->seekData(imdPtr->fileHandle, imdPtr->filePos, 0);
}
x = imdPtr->x;
y = imdPtr->y;
width = imdPtr->width;
height = imdPtr->height;
do {
if (frame != 0) {
if (imdPtr->stdX != -1) {
imdPtr->x = imdPtr->stdX;
imdPtr->y = imdPtr->stdY;
imdPtr->width = imdPtr->stdWidth;
imdPtr->height = imdPtr->stdHeight;
retVal |= 0x1000;
}
if ((imdPtr->frameCoords != 0) && (imdPtr->frameCoords[frame].left != -1)) {
var_4 |= 0x400;
imdPtr->x = imdPtr->frameCoords[frame].left;
imdPtr->y = imdPtr->frameCoords[frame].top;
imdPtr->width = imdPtr->frameCoords[frame].right - imdPtr->x + 1;
imdPtr->height = imdPtr->frameCoords[frame].bottom - imdPtr->y + 1;
}
}
_vm->_dataio->readData(imdPtr->fileHandle, buf, 2);
tmp = READ_LE_UINT16(buf);
imdPtr->filePos += 2;
if ((tmp & 0xFFF8) == 0xFFF0) {
if (tmp == 0xFFF0) {
_vm->_dataio->readData(imdPtr->fileHandle, buf, 2);
tmp = READ_LE_UINT16(buf);
if (var_4 == 0)
word_31451 = tmp;
_vm->_dataio->readData(imdPtr->fileHandle, buf, 2);
tmp = READ_LE_UINT16(buf);
imdPtr->filePos += 4;
} else if (tmp == 0xFFF1) {
retVal = (int16)0x8000;
continue;
} else if (tmp == 0xFFF2) {
_vm->_dataio->readData(imdPtr->fileHandle, buf, 2);
tmp = READ_LE_UINT16(buf);
imdPtr->filePos += 2;
_vm->_dataio->seekData(imdPtr->fileHandle, tmp, 1);
imdPtr->filePos += tmp;
retVal = (int16)0x8000;
continue;
} else if (tmp == 0xFFF3) {
_vm->_dataio->readData(imdPtr->fileHandle, buf, 4);
tmp = READ_LE_UINT32(buf);
imdPtr->filePos += 4;
_vm->_dataio->seekData(imdPtr->fileHandle, tmp, 1);
imdPtr->filePos += tmp;
retVal = (int16)0x8000;
continue;
}
}
if (byte_31344 != 0) {
if ((var_4 == 0) && (_vm->_global->_soundFlags & 0x14) && (byte_31344 == 2)) { // loc_2A503
var_12 = _vm->_util->getTimeKey();
warning("GOB2 Stub! viewImd, IMD sound stuff");
}
}
var_4 = 0;
if (tmp == 0xFFFD) {
_vm->_dataio->readData(imdPtr->fileHandle, buf, 2);
frame = READ_LE_UINT16(buf);
if ((imdPtr->framesPos != 0) && (byte_2DA60 == 0)) {
word_2DA61 = frame;
imdPtr->filePos = imdPtr->framesPos[frame];
_vm->_dataio->seekData(imdPtr->fileHandle, imdPtr->filePos, 0);
var_4 = 1;
retVal |= 0x200;
imdPtr->curFrame = frame;
} else
imdPtr->filePos += 2;
continue;
}
if (tmp != 0) {
imdPtr->filePos += tmp + 2;
if (byte_2DA60 != 0) {
_vm->_dataio->seekData(imdPtr->fileHandle, tmp + 2, 1);
} else {
_vm->_dataio->readData(imdPtr->fileHandle, (char *) _imdFrameData, tmp + 2);
retVal |= *_imdFrameData;
if (imdPtr->surfDesc == 0)
continue;
if (imdPtr->surfDesc->vidMode != 0x14)
imdRenderFrame(imdPtr);
else
warning("GOB2 Stub! viedImd, sub_2C69A(imdPtr);");
}
} else
retVal |= 0x800;
} while (var_4 != 0);
if (byte_2DA60 != 0) {
byte_2DA60 = 0;
retVal |= 0x100;
}
imdPtr->x = x;
imdPtr->y = y;
imdPtr->width = width;
imdPtr->height = height;
imdPtr->curFrame++;
return retVal;
}
void Game::imdDrawFrame(Imd *imdPtr, int16 frame, int16 x, int16 y,
Video::SurfaceDesc *dest) {
if (!dest)
dest = _vm->_draw->_frontSurface;
if (frame == 0)
_vm->_video->drawSprite(imdPtr->surfDesc, dest, 0, 0,
imdPtr->width - 1, imdPtr->height - 1, x, y, 1);
else if ((imdPtr->frameCoords != 0) && (imdPtr->frameCoords[frame].left != -1))
_vm->_video->drawSprite(imdPtr->surfDesc, dest,
imdPtr->frameCoords[frame].left, imdPtr->frameCoords[frame].top,
imdPtr->frameCoords[frame].right, imdPtr->frameCoords[frame].bottom,
imdPtr->frameCoords[frame].left, imdPtr->frameCoords[frame].top, 1);
else if (imdPtr->stdX != -1)
_vm->_video->drawSprite(imdPtr->surfDesc, dest,
imdPtr->stdX, imdPtr->stdY, imdPtr->stdX + imdPtr->stdWidth - 1,
imdPtr->stdY + imdPtr->stdHeight - 1, x + imdPtr->stdX,
y + imdPtr->stdY, 1);
else
_vm->_video->drawSprite(imdPtr->surfDesc, dest, 0, 0,
imdPtr->width - 1, imdPtr->height - 1, x, y, 0);
}
void Game::imdRenderFrame(Imd *imdPtr) {
int i;
int16 imdX;
int16 imdY;
int16 imdW;
int16 imdH;
int16 sW;
uint16 pixCount, pixWritten;
uint8 type;
byte *imdVidMem;
byte *imdVidMemBak;
byte *dataPtr = 0;
byte *srcPtr = 0;
byte *srcPtrBak = 0;
dataPtr = (byte *) _imdFrameData;
imdX = imdPtr->x;
imdY = imdPtr->y;
imdW = imdPtr->width;
imdH = imdPtr->height;
sW = imdPtr->surfDesc->width;
imdVidMem = imdPtr->surfDesc->vidPtr + sW * imdY + imdX;
type = *dataPtr++;
srcPtr = dataPtr;
if (type & 0x10) {
type ^= 0x10;
dataPtr++; // => 0x3C8 |_ palette
dataPtr += 48; // => 0x3C9 | stuff
}
srcPtr = dataPtr;
if (type & 0x80) {
srcPtr = (byte *) _imdVidBuffer;
type &= 0x7F;
if ((type == 2) && (imdW == sW)) {
imdFrameUncompressor(imdVidMem, dataPtr);
return;
} else
imdFrameUncompressor(srcPtr, dataPtr);
}
if (type == 2) {
for (i = 0; i < imdH; i++) {
memcpy(imdVidMem, srcPtr, imdW);
srcPtr += imdW;
imdVidMem += sW;
}
} else if (type == 1) {
imdVidMemBak = imdVidMem;
for (i = 0; i < imdH; i++) {
pixWritten = 0;
while (pixWritten < imdW) {
pixCount = *srcPtr++;
if (pixCount & 0x80) {
pixCount = (pixCount & 0x7F) + 1;
// Just to be safe
pixCount = (pixWritten + pixCount) > imdW ? imdW - pixWritten : pixCount;
pixWritten += pixCount;
memcpy(imdVidMem, srcPtr, pixCount);
imdVidMem += pixCount;
srcPtr += pixCount;
} else {
pixCount = (pixCount + 1) % 256;
pixWritten += pixCount;
imdVidMem += pixCount;
}
}
imdVidMemBak += sW;
imdVidMem = imdVidMemBak;
}
} else if (type == 0x42) { // loc_2AFC4
warning("=> type == 0x42");
} else if ((type & 0xF) == 2) { // loc_2AFEC
warning("=> (type & 0xF) == 2");
} else { // loc_2B021
srcPtrBak = srcPtr;
for (i = 0; i < imdH; i += 2) {
pixWritten = 0;
while (pixWritten < imdW) {
pixCount = *srcPtr++;
if (pixCount & 0x80) {
pixCount = (pixCount & 0x7F) + 1;
// Just to be safe
pixCount = (pixWritten + pixCount) > imdW ? imdW - pixWritten : pixCount;
pixWritten += pixCount;
memcpy(imdVidMem, srcPtr, pixCount);
memcpy(imdVidMem + sW, srcPtr, pixCount);
imdVidMem += pixCount;
srcPtr += pixCount;
} else {
pixCount = (pixCount + 1) % 256;
pixWritten += pixCount;
imdVidMem += pixCount;
}
}
srcPtrBak += sW + sW;
srcPtr = srcPtrBak;
}
}
}
void Game::imdFrameUncompressor(byte *dest, byte *src) {
int i;
byte buf[4370];
int16 chunkLength;
int16 frameLength;
uint16 bufPos1;
uint16 bufPos2;
uint16 tmp;
uint8 chunkBitField;
uint8 chunkCount;
bool mode;
frameLength = READ_LE_UINT16(src);
src += 4;
bufPos1 = 4078;
mode = 0; // 275h (jnz +2)
if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) {
src += 4;
bufPos1 = 273;
mode = 1; // 123Ch (cmp al, 12h)
}
memset(buf, 32, bufPos1);
chunkCount = 1;
chunkBitField = 0;
while (frameLength > 0) {
chunkCount--;
if (chunkCount == 0) {
tmp = *src++;
chunkCount = 8;
chunkBitField = tmp;
}
if (chunkBitField % 2) {
chunkBitField >>= 1;
buf[bufPos1] = *src;
*dest++ = *src++;
bufPos1 = (bufPos1 + 1) % 4096;
frameLength--;
continue;
}
chunkBitField >>= 1;
tmp = READ_LE_UINT16(src);
src += 2;
chunkLength = ((tmp & 0xF00) >> 8) + 3;
if ((mode && ((chunkLength & 0xFF) == 0x12)) || (!mode && (chunkLength == 0)))
chunkLength = *src++ + 0x12;
bufPos2 = (tmp & 0xFF) + ((tmp >> 4) & 0x0F00);
if (((tmp + chunkLength) >= 4096) || ((chunkLength + bufPos1) >= 4096)) {
for (i = 0; i < chunkLength; i++, dest++) {
*dest = buf[bufPos2];
buf[bufPos1] = buf[bufPos2];
bufPos1 = (bufPos1 + 1) % 4096;
bufPos2 = (bufPos2 + 1) % 4096;
}
frameLength -= chunkLength;
} else if (((tmp + chunkLength) < bufPos1) || ((chunkLength + bufPos1) < bufPos2)) {
memcpy(dest, buf + bufPos2, chunkLength);
dest += chunkLength;
memmove(buf + bufPos1, buf + bufPos2, chunkLength);
bufPos1 += chunkLength;
bufPos2 += chunkLength;
frameLength -= chunkLength;
} else {
for (i = 0; i < chunkLength; i++, dest++, bufPos1++, bufPos2++) {
*dest = buf[bufPos2];
buf[bufPos1] = buf[bufPos2];
}
frameLength -= chunkLength;
}
}
}
void Game::playImd(const char *path, int16 x, int16 y, int16 startFrame, int16 frames,
bool fade, bool interruptible) {
int16 mouseX;
int16 mouseY;
int16 buttons;
int curFrame;
int endFrame;
int backFrame;
_vm->_util->setFrameRate(12);
openImd(path, 0, 0, 0, 0);
_vm->_video->fillRect(_vm->_draw->_frontSurface, x, y, x + _imdFile->width - 1,
y + _imdFile->height - 1, 0);
if (fade)
_vm->_palanim->fade(0, -2, 0);
endFrame = frames > 0 ? frames : _imdFile->framesCount;
for (curFrame = 0; curFrame < endFrame; curFrame++) {
viewImd(_imdFile, curFrame);
imdDrawFrame(_imdFile, curFrame, x, y);
if (fade) {
_vm->_palanim->fade(_vm->_global->_pPaletteDesc, -2, 0);
fade = false;
}
_vm->_video->waitRetrace(_vm->_global->_videoMode);
if ((interruptible && (checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B)) ||
_vm->_quitRequested) {
_vm->_palanim->fade(0, -2, 0);
_vm->_video->clearSurf(_vm->_draw->_frontSurface);
memset((char *) _vm->_draw->_vgaPalette, 0, 768);
WRITE_VAR(4, buttons);
WRITE_VAR(0, 0x11B);
WRITE_VAR(57, (uint32) -1);
break;
}
_vm->_util->waitEndFrame();
}
if (frames < 0) {
endFrame = _imdFile->framesCount + frames;
for (curFrame = _imdFile->framesCount - 1; curFrame >= endFrame; curFrame--) {
for (backFrame = 0; backFrame <= curFrame; backFrame++)
viewImd(_imdFile, backFrame);
imdDrawFrame(_imdFile, curFrame, x, y);
_vm->_video->waitRetrace(_vm->_global->_videoMode);
if ((interruptible && (checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B)) ||
_vm->_quitRequested) {
_vm->_palanim->fade(0, -2, 0);
_vm->_video->clearSurf(_vm->_draw->_frontSurface);
memset((char *) _vm->_draw->_vgaPalette, 0, 768);
WRITE_VAR(4, buttons);
WRITE_VAR(0, 0x11B);
WRITE_VAR(57, (uint32) -1);
break;
}
_vm->_util->waitEndFrame();
}
}
closeImd();
}
int16 Game::sub_2C825(Imd *imdPtr) {
warning("GOB2 Stub! sub_2C825()");
return 0;
}
} // End of namespace Gob