scummvm/engines/gob/mult_v2.cpp
Sven Hesse a802e1e64f VIDEO: Stub a VideoDecoder-like CoktelDecoder
This creates a new CoktelDecoder class using the VideoDecoder
interface, which will eventually become the new way to decode
PreIMD, IMD and VMD videos.
Since the VideoPlayer in gob is not yet ready for this, we're
disabling all video playback in the gob engine for now.

svn-id: r51850
2010-08-08 00:33:59 +00:00

1302 lines
34 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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/endian.h"
#include "common/stream.h"
#include "gob/gob.h"
#include "gob/mult.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/draw.h"
#include "gob/game.h"
#include "gob/script.h"
#include "gob/resources.h"
#include "gob/goblin.h"
#include "gob/inter.h"
#include "gob/scenery.h"
#include "gob/video.h"
#include "gob/videoplayer.h"
namespace Gob {
Mult_v2::Mult_v2(GobEngine *vm) : Mult_v1(vm) {
_renderObjs = 0;
_multData = 0;
for (int i = 0; i < 8; i++)
_multDatas[i] = 0;
}
Mult_v2::~Mult_v2() {
freeMultKeys();
for (int i = 0; i < 8; i++) {
_multData = _multDatas[i];
freeMultKeys();
}
}
void Mult_v2::loadMult(int16 resId) {
int8 index;
uint8 staticCount;
uint8 animCount;
bool hasImds;
index = (resId & 0x8000) ? _vm->_game->_script->readByte() : 0;
resId &= 0x7FFF;
debugC(4, kDebugGameFlow, "Loading mult %d", index);
_multData = new Mult_Data;
memset(_multData, 0, sizeof(Mult_Data));
_multDatas[index] = _multData;
for (int i = 0; i < 4; i++)
_multData->animObjs[0][i] = i;
_multData->sndSlotsCount = 0;
_multData->frameStart = 0;
Resource *resource = _vm->_game->_resources->getResource(resId);
if (!resource)
return;
Common::SeekableReadStream &data = *resource->stream();
_multData->staticCount = staticCount = data.readSByte();
_multData->animCount = animCount = data.readSByte();
staticCount++;
animCount++;
hasImds = (staticCount & 0x80) != 0;
staticCount &= 0x7F;
debugC(7, kDebugGraphics, "statics: %u, anims: %u, imds: %u",
staticCount, animCount, hasImds);
for (int i = 0; i < 10; i++) {
_multData->staticLoaded[i] = false;
_multData->animLoaded[i] = false;
}
for (int i = 0; i < staticCount; i++, data.seek(14, SEEK_CUR)) {
_multData->staticIndices[i] = _vm->_scenery->loadStatic(1);
if (_multData->staticIndices[i] >= 100) {
_multData->staticIndices[i] -= 100;
_multData->staticLoaded[i] = true;
}
}
for (int i = 0; i < animCount; i++, data.seek(14, SEEK_CUR)) {
_multData->animIndices[i] = _vm->_scenery->loadAnim(1);
if (_multData->animIndices[i] >= 100) {
_multData->animIndices[i] -= 100;
_multData->animLoaded[i] = true;
}
}
_multData->frameRate = data.readSint16LE();
_multData->staticKeysCount = data.readSint16LE();
_multData->staticKeys = new Mult_StaticKey[_multData->staticKeysCount];
for (int i = 0; i < _multData->staticKeysCount; i++) {
_multData->staticKeys[i].frame = data.readSint16LE();
_multData->staticKeys[i].layer = data.readSint16LE();
}
for (int i = 0; i < 4; i++) {
_multData->imdKeysCount[i] = 0;
_multData->imdKeys[i] = 0;
_multData->imdIndices[i] = -1;
for (int j = 0; j < 4; j++) {
_multData->animKeysIndices[i][j] = 0;
_multData->imdKeysIndices[i][j] = 0;
}
_multData->animKeysFrames[i] = -1;
_multData->animKeysCount[i] = data.readSint16LE();
_multData->animKeys[i] = new Mult_AnimKey[_multData->animKeysCount[i]];
for (int j = 0; j < _multData->animKeysCount[i]; j++) {
_multData->animKeys[i][j].frame = data.readSint16LE();
_multData->animKeys[i][j].layer = data.readSint16LE();
_multData->animKeys[i][j].posX = data.readSint16LE();
_multData->animKeys[i][j].posY = data.readSint16LE();
_multData->animKeys[i][j].order = data.readSint16LE();
}
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 16; j++) {
_multData->fadePal[i][j].red = data.readByte();
_multData->fadePal[i][j].green = data.readByte();
_multData->fadePal[i][j].blue = data.readByte();
}
}
_multData->palFadeKeysCount = data.readSint16LE();
_multData->palFadeKeys = new Mult_PalFadeKey[_multData->palFadeKeysCount];
for (int i = 0; i < _multData->palFadeKeysCount; i++) {
_multData->palFadeKeys[i].frame = data.readSint16LE();
_multData->palFadeKeys[i].fade = data.readSint16LE();
_multData->palFadeKeys[i].palIndex = data.readSint16LE();
_multData->palFadeKeys[i].flag = data.readSByte();
}
_multData->palKeysCount = data.readSint16LE();
_multData->palKeys = new Mult_PalKey[_multData->palKeysCount];
for (int i = 0; i < _multData->palKeysCount; i++) {
_multData->palKeys[i].frame = data.readSint16LE();
_multData->palKeys[i].cmd = data.readSint16LE();
_multData->palKeys[i].rates[0] = data.readSint16LE();
_multData->palKeys[i].rates[1] = data.readSint16LE();
_multData->palKeys[i].rates[2] = data.readSint16LE();
_multData->palKeys[i].rates[3] = data.readSint16LE();
_multData->palKeys[i].unknown0 = data.readSint16LE();
_multData->palKeys[i].unknown1 = data.readSint16LE();
data.read(_multData->palKeys[i].subst, 64);
}
_multData->textKeysCount = data.readSint16LE();
_multData->textKeys = new Mult_TextKey[_multData->textKeysCount];
for (int i = 0; i < _multData->textKeysCount; i++) {
_multData->textKeys[i].frame = data.readSint16LE();
_multData->textKeys[i].cmd = data.readSint16LE();
if (!hasImds)
data.seek(24, SEEK_CUR);
}
_multData->sndKeysCount = data.readSint16LE();
_multData->sndKeys = new Mult_SndKey[_multData->sndKeysCount];
for (int i = 0; i < _multData->sndKeysCount; i++) {
int j;
_multData->sndKeys[i].frame = data.readSint16LE();
_multData->sndKeys[i].cmd = data.readSint16LE();
_multData->sndKeys[i].freq = data.readSint16LE();
_multData->sndKeys[i].fadeLength = data.readSint16LE();
_multData->sndKeys[i].repCount = data.readSint16LE();
_multData->sndKeys[i].soundIndex = -1;
_multData->sndKeys[i].resId = -1;
data.seek(2, SEEK_CUR);
if (!hasImds)
data.seek(24, SEEK_CUR);
switch (_multData->sndKeys[i].cmd) {
case 1:
case 4:
_multData->sndKeys[i].resId = _vm->_game->_script->peekUint16();
for (j = 0; j < i; j++) {
if (_multData->sndKeys[j].resId ==
_multData->sndKeys[i].resId) {
_multData->sndKeys[i].soundIndex =
_multData->sndKeys[j].soundIndex;
_vm->_game->_script->skip(2);
break;
}
}
if (i == j) {
_multData->sndSlot[_multData->sndSlotsCount] =
_vm->_inter->loadSound(1);
_multData->sndKeys[i].soundIndex =
_multData->sndSlot[_multData->sndSlotsCount] & 0x7FFF;
_multData->sndSlotsCount++;
}
break;
case 3:
_vm->_game->_script->skip(4);
break;
case -1:
break;
default:
warning("Mult_v2::loadMult(): Unknown sound key command (%d)",
_multData->sndKeys[i].cmd);
}
}
_multData->imdFiles = 0;
_multData->somepointer10 = 0;
if (hasImds)
loadImds(data);
delete resource;
}
void Mult_v2::loadImds(Common::SeekableReadStream &data) {
int16 size;
size = _vm->_game->_script->readInt16();
_multData->execPtr = _vm->_game->_script->getData() + _vm->_game->_script->pos();
_vm->_game->_script->skip(size * 2);
if (_vm->_game->_script->getVersionMinor() < 3)
return;
size = data.readSint16LE();
if (size > 0) {
_multData->somepointer10 = new char[size * 20];
data.read(_multData->somepointer10, size * 20);
}
size = _vm->_game->_script->readInt16();
if (size <= 0)
return;
_multData->imdFiles = new char[size * 14];
memcpy(_multData->imdFiles,
_vm->_game->_script->getData() + _vm->_game->_script->pos(), size * 14);
// WORKAROUND: The Windows version of Lost in Time has VMD not IMD files,
// but they are still referenced as IMD.
if ((_vm->getGameType() == kGameTypeLostInTime) &&
(_vm->getPlatform() == Common::kPlatformWindows)) {
for (int i = 0; i < size; i++) {
char *dot = strrchr(_multData->imdFiles + (i * 14), '.');
if (dot)
*dot = '\0';
}
}
_vm->_game->_script->skip(size * 14);
data.seek(2, SEEK_CUR);
for (int i = 0; i < 4; i++) {
_multData->imdKeysCount[i] = data.readSint16LE();
_multData->imdKeys[i] = new Mult_ImdKey[_multData->imdKeysCount[i]];
for (int j = 0; j < _multData->imdKeysCount[i]; j++) {
_multData->imdKeys[i][j].frame = data.readSint16LE();
_multData->imdKeys[i][j].imdFile = data.readSint16LE();
_multData->imdKeys[i][j].field_4 = data.readSint16LE();
_multData->imdKeys[i][j].field_6 = data.readSint16LE();
_multData->imdKeys[i][j].flags = data.readUint16LE();
_multData->imdKeys[i][j].palFrame = data.readSint16LE();
_multData->imdKeys[i][j].lastFrame = data.readSint16LE();
_multData->imdKeys[i][j].palStart = data.readSByte();
_multData->imdKeys[i][j].palEnd = data.readSByte();
}
}
}
void Mult_v2::freeMultKeys() {
uint8 animCount;
uint8 staticCount;
if (!_multData)
return;
staticCount = (_multData->staticCount + 1) & 0x7F;
animCount = _multData->animCount + 1;
for (int i = 0; i < staticCount; i++)
if (_multData->staticLoaded[i])
_vm->_scenery->freeStatic(_multData->staticIndices[i]);
for (int i = 0; i < animCount; i++)
if (_multData->animLoaded[i])
_vm->_scenery->freeAnim(_multData->animIndices[i]);
delete[] _multData->staticKeys;
for (int i = 0; i < 4; i++) {
delete[] _multData->animKeys[i];
delete[] _multData->imdKeys[i];
}
delete[] _multData->palFadeKeys;
delete[] _multData->palKeys;
delete[] _multData->textKeys;
for (int i = 0; i < _multData->sndSlotsCount; i++)
if (!(_multData->sndSlot[i] & 0x8000))
_vm->_game->freeSoundSlot(_multData->sndSlot[i]);
delete[] _multData->sndKeys;
delete[] _multData->imdFiles;
delete[] _multData->somepointer10;
if (_animDataAllocated) {
freeMult();
delete _animArrayX;
delete _animArrayY;
delete[] _animArrayData;
_animArrayX = 0;
_animArrayY = 0;
_animArrayData = 0;
_animDataAllocated = false;
}
for (int i = 0; i < 8; i++)
if (_multDatas[i] == _multData)
_multDatas[i] = 0;
delete _multData;
_multData = 0;
}
bool Mult_v2::hasMultData(uint16 multIndex) {
if (multIndex > 7)
error("Multindex out of range");
return _multDatas[multIndex] != 0;
}
void Mult_v2::setMultData(uint16 multIndex) {
if (multIndex > 7)
error("Multindex out of range");
debugC(4, kDebugGameFlow, "Switching to mult %d", multIndex);
_multData = _multDatas[multIndex];
}
void Mult_v2::zeroMultData(uint16 multIndex) {
if (multIndex > 7)
error("Multindex out of range");
_multDatas[multIndex] = 0;
}
void Mult_v2::multSub(uint16 multIndex) {
uint16 flags;
int16 expr;
int16 index;
int16 startFrame, stopFrame, firstFrame;
flags = multIndex;
multIndex = (multIndex >> 12) & 0xF;
if (multIndex > 7)
error("Multindex out of range");
_vm->_util->notifyNewAnim();
debugC(4, kDebugGameFlow, "Sub mult %d", multIndex);
_multData = _multDatas[multIndex];
if (!_multData) {
_vm->_game->_script->readValExpr();
_vm->_game->_script->readValExpr();
_vm->_game->_script->readValExpr();
_vm->_game->_script->readValExpr();
return;
}
if (flags & 0x200)
index = 3;
else if (flags & 0x100)
index = 2;
else if (flags & 0x80)
index = 1;
else
index = 0;
if (flags & 0x400) {
flags = 0x400;
_multData->animDirection = -1;
} else {
_multData->animDirection = 1;
flags &= 0x7F;
}
_multData->animObjs[index][0] = flags;
for (int i = 1; i < 4; i++)
_multData->animObjs[index][i] = _vm->_game->_script->readValExpr();
expr = _vm->_game->_script->readValExpr();
_multData->animKeysFrames[index] = expr;
_multData->animKeysStartFrames[index] = expr;
WRITE_VAR(18 + index, expr);
if (expr == -1) {
if (!_objects)
return;
for (int i = 0; i < 4; i++) {
int obj = _multData->animObjs[index][i];
if ((obj == -1) || (obj == 1024))
continue;
Mult_AnimData &animData = *(_objects[obj].pAnimData);
animData.animType = animData.animTypeBak;
}
return;
}
startFrame = _multData->animKeysStartFrames[index];
stopFrame = _multData->animKeysStopFrames[index];
if (_multData->animDirection == 1) {
stopFrame = 32000;
for (int i = 0; i < _multData->textKeysCount; i++) {
int16 textFrame = _multData->textKeys[i].frame;
if ((textFrame > startFrame) && (textFrame < stopFrame))
stopFrame = textFrame;
}
} else {
stopFrame = 0;
for (int i = 0; i < _multData->textKeysCount; i++) {
int16 textFrame = _multData->textKeys[i].frame;
if ((textFrame < startFrame) && (textFrame > stopFrame))
stopFrame = textFrame;
}
}
if (_objects) {
for (int i = 0; i < 4; i++) {
int obj = _multData->animObjs[index][i];
if ((obj != -1) && (obj != 1024))
_objects[obj].pAnimData->animTypeBak = _objects[obj].pAnimData->animType;
}
}
for (int i = 0; i < 4; i++) {
_multData->animKeysIndices[index][i] = 0;
for (int j = 0; j < _multData->animKeysCount[i]; j++)
if (_multData->animKeys[i][j].frame >= startFrame) {
_multData->animKeysIndices[index][i] = j;
break;
}
}
if (_multData->animDirection == -1) {
int i = 0;
while (_multData->imdKeys[index][i].frame <= startFrame)
i++;
_multData->imdIndices[index] = i - 1;
}
firstFrame = (_multData->animDirection == 1) ? startFrame : stopFrame;
for (int i = 0; i < 4; i++) {
_multData->imdKeysIndices[index][i] = 0;
for (int j = 0; j < _multData->imdKeysCount[i]; j++)
if (_multData->imdKeys[i][j].frame >= firstFrame) {
_multData->imdKeysIndices[index][i] = j;
break;
}
}
_multData->animKeysStartFrames[index] = startFrame;
_multData->animKeysStopFrames[index] = stopFrame;
}
void Mult_v2::playMultInit() {
_doPalSubst = false;
_palFadingRed = 0;
_palFadingGreen = 0;
_palFadingBlue = 0;
_oldPalette = _vm->_global->_pPaletteDesc->vgaPal;
if (!_animSurf) {
int16 width, height;
if (_objects)
for (int i = 0; i < _objCount; i++) {
delete _objects[i].pPosX;
delete _objects[i].pPosY;
}
delete[] _objects;
_vm->_util->setFrameRate(_multData->frameRate);
_animTop = 0;
_animLeft = 0;
_animWidth = _vm->_video->_surfWidth;
_animHeight = _vm->_video->_surfHeight;
_objCount = 4;
delete[] _orderArray;
delete[] _renderObjs;
delete _animArrayX;
delete _animArrayY;
delete[] _animArrayData;
_objects = new Mult_Object[_objCount];
_orderArray = new int8[_objCount];
_renderObjs = new Mult_Object*[_objCount];
_animArrayX = new VariablesLE(_objCount * 4);
_animArrayY = new VariablesLE(_objCount * 4);
_animArrayData = new Mult_AnimData[_objCount];
memset(_objects, 0, _objCount * sizeof(Mult_Object));
memset(_orderArray, 0, _objCount * sizeof(int8));
memset(_renderObjs, 0, _objCount * sizeof(Mult_Object *));
memset(_animArrayData, 0, _objCount * sizeof(Mult_AnimData));
for (_counter = 0; _counter < _objCount; _counter++) {
Mult_Object &multObj = _objects[_counter];
Mult_AnimData &animData = _animArrayData[_counter];
multObj.pPosX = new VariableReference(*_animArrayX, _counter * 4);
multObj.pPosY = new VariableReference(*_animArrayY, _counter * 4);
multObj.pAnimData = &animData;
animData.isStatic = 1;
multObj.lastLeft = -1;
multObj.lastTop = -1;
multObj.lastRight = -1;
multObj.lastBottom = -1;
}
width = _animWidth;
height = _animHeight;
_vm->_draw->adjustCoords(0, &width, &height);
_vm->_draw->initSpriteSurf(22, width, height, 0);
_animSurf = _vm->_draw->_spritesArray[22];
_vm->_video->drawSprite(*_vm->_draw->_spritesArray[21],
*_vm->_draw->_spritesArray[22], 0, 0,
_vm->_video->_surfWidth, _vm->_video->_surfHeight, 0, 0, 0);
for (_counter = 0; _counter < _objCount; _counter++)
_multData->palAnimIndices[_counter] = _counter;
_animDataAllocated = true;
} else
_animDataAllocated = false;
_frame = 0;
}
void Mult_v2::drawStatics(bool &stop) {
int staticIndex;
if (_multData->staticKeys[_multData->staticKeysCount - 1].frame > _frame)
stop = false;
for (_counter = 0; _counter < _multData->staticKeysCount; _counter++) {
if ((_multData->staticKeys[_counter].frame != _frame)
|| (_multData->staticKeys[_counter].layer == -1))
continue;
if (_multData->staticKeys[_counter].layer >= 0) {
int i = 0;
_vm->_scenery->_curStatic = 0;
_vm->_scenery->_curStaticLayer =
_multData->staticKeys[_counter].layer;
staticIndex = _multData->staticIndices[i];
while (_vm->_scenery->getStaticLayersCount(staticIndex) <=
_vm->_scenery->_curStaticLayer) {
_vm->_scenery->_curStaticLayer -=
_vm->_scenery->getStaticLayersCount(staticIndex);
staticIndex = _multData->staticIndices[++i];
_vm->_scenery->_curStatic++;
}
_vm->_scenery->_curStatic =
_multData->staticIndices[_vm->_scenery->_curStatic];
_vm->_scenery->renderStatic(_vm->_scenery->_curStatic,
_vm->_scenery->_curStaticLayer);
} else {
int layer = -_multData->staticKeys[_counter].layer - 2;
_vm->_draw->_spriteLeft =
READ_LE_UINT16(_multData->execPtr + layer * 2);
_vm->_draw->_destSpriteX = 0;
_vm->_draw->_destSpriteY = 0;
_vm->_draw->_destSurface = 21;
_vm->_draw->_transparency = 0;
_vm->_draw->spriteOperation(DRAW_LOADSPRITE);
_vm->_scenery->_curStatic = -1;
}
_vm->_video->drawSprite(*_vm->_draw->_spritesArray[21],
*_vm->_draw->_spritesArray[22], 0, 0,
_vm->_video->_surfWidth, _vm->_video->_surfHeight, 0, 0, 0);
}
}
void Mult_v2::drawAnims(bool &stop) {
int16 count;
int animIndex;
for (int i = 0; i < 4; i++) {
int16 animKeysCount = _multData->animKeysCount[i];
if ((animKeysCount > 0) && ((uint16) _multData->animKeys[i][animKeysCount - 1].frame > _frame))
stop = false;
}
for (_index = 0; _index < 4; _index++) {
int16 animKeysCount = _multData->animKeysCount[_index];
for (_counter = 0; _counter < animKeysCount; _counter++) {
Mult_AnimKey &key = _multData->animKeys[_index][_counter];
Mult_Object &animObj = _objects[_multData->animObjs[0][_index]];
Mult_AnimData &animData = *(animObj.pAnimData);
if (key.frame != _frame)
continue;
if (key.layer != -1) {
*(animObj.pPosX) = key.posX;
*(animObj.pPosY) = key.posY;
animData.frame = 0;
animData.order = key.order;
animData.animType = 1;
animData.isPaused = 0;
animData.isStatic = 0;
animData.maxTick = 0;
animObj.tick = 0;
animData.layer = key.layer;
int i = 0;
animIndex = _multData->animIndices[i];
count = _vm->_scenery->getAnimLayersCount(animIndex);
while (animData.layer >= count) {
animData.layer -= count;
animIndex = _multData->animIndices[++i];
count = _vm->_scenery->getAnimLayersCount(animIndex);
}
animData.animation = animIndex;
} else
animData.isStatic = 1;
}
}
}
void Mult_v2::newCycleAnim(Mult_Object &animObj) {
Mult_AnimData &animData = *(animObj.pAnimData);
Scenery::AnimLayer *animLayer = 0;
if (animData.animation >= 0) {
int nAnim = animData.animation, nLayer = animData.layer;
if (_vm->_scenery->getAnimLayersCount(nAnim) <= nLayer)
return;
animLayer = _vm->_scenery->getAnimLayer(nAnim, nLayer);
} else {
if (animObj.videoSlot > 0) {
_vm->_video->retrace();
_vm->_vidPlayer->slotWaitEndFrame(animObj.videoSlot - 1, true);
}
}
if (animData.animType == 4) {
animData.frame = 0;
animData.isPaused = 1;
if (animData.animation < 0)
warning("Woodruff Stub: AnimType 4, animation: %d", animData.animation);
return;
}
if (animData.animType == 12)
animData.animType = 11;
if (animData.animType == 11) {
if (animData.isBusy != 0)
warning("Woodruff Stub: AnimType 11");
return;
}
if (animData.animType != 8)
animData.frame++;
if (animData.animation < 0) {
if ((animObj.videoSlot > 0) &&
(_vm->_vidPlayer->getCurrentFrame(animObj.videoSlot - 1) <
_vm->_vidPlayer->getFrameCount(animObj.videoSlot - 1))) {
animData.newCycle = 0;
return;
}
} else {
if (animData.frame < animLayer->framesCount) {
animData.newCycle = 0;
return;
}
}
switch (animData.animType) {
case 0:
animData.frame = 0;
break;
case 1:
animData.frame = 0;
*(animObj.pPosX) += animLayer->animDeltaX;
*(animObj.pPosY) += animLayer->animDeltaY;
break;
case 2:
animData.frame = 0;
animData.animation = animData.newAnimation;
animData.layer = animData.newLayer;
break;
case 3:
animData.animType = 4;
animData.frame = 0;
break;
case 5:
animData.isStatic = 1;
animData.frame = 0;
if ((animData.animation < 0) && (animObj.videoSlot > 0)) {
_vm->_vidPlayer->slotClose(animObj.videoSlot - 1);
animObj.videoSlot = 0;
}
break;
case 6:
case 7:
animData.frame--;
animData.isPaused = 1;
/*
if ((animData.animation < 0) && (animObj.videoSlot > 0)) {
if (_vm->_vidPlayer->getFlags(animObj.videoSlot - 1) & 0x1000) {
_vm->_vidPlayer->slotClose(animObj.videoSlot - 1);
animObj.videoSlot = 0;
}
}
*/
break;
case 10:
warning("Woodruff Stub: AnimType 10");
break;
}
animData.newCycle = 1;
}
void Mult_v2::animate() {
int8 minOrder = 100;
int8 maxOrder = 0;
int8 *orderArray;
int orderArrayPos = 0;
int8 animIndices[150];
int numAnims = 0;
if (!_objects)
return;
if (_objCount > 0) {
if (!_orderArray)
return;
orderArray = _orderArray;
} else
orderArray = 0;
advanceAllObjects();
// Find relevant objects
for (int i = 0; i < _objCount; i++) {
Mult_Object &animObj = _objects[i];
Mult_AnimData &animData = *(animObj.pAnimData);
animData.intersected = 200;
if (animData.isStatic != 2) {
if ((animData.isStatic == 0) || (animObj.lastLeft != -1)) {
animIndices[numAnims] = i;
_renderObjs[numAnims] = &animObj;
numAnims++;
}
}
}
// Find dirty areas
for (int i = 0; i < numAnims; i++) {
Mult_Object &animObj = *_renderObjs[i];
Mult_AnimData &animData = *(animObj.pAnimData);
animObj.needRedraw = 0;
animObj.newTop = 1000;
animObj.newLeft = 1000;
animObj.newBottom = 0;
animObj.newRight = 0;
if (animData.isStatic == 2)
continue;
if (!animData.isStatic && !animData.isPaused &&
(animData.maxTick == animObj.tick)) {
animObj.needRedraw = 1;
_vm->_scenery->updateAnim(animData.layer, animData.frame,
animData.animation, 8, *animObj.pPosX, *animObj.pPosY, 0);
if (animObj.lastLeft == -1) {
animObj.newLeft = _vm->_scenery->_toRedrawLeft;
animObj.newTop = _vm->_scenery->_toRedrawTop;
animObj.newRight = _vm->_scenery->_toRedrawRight;
animObj.newBottom = _vm->_scenery->_toRedrawBottom;
} else {
animObj.newLeft =
MIN(animObj.lastLeft, _vm->_scenery->_toRedrawLeft);
animObj.newTop =
MIN(animObj.lastTop, _vm->_scenery->_toRedrawTop);
animObj.newRight =
MAX(animObj.lastRight, _vm->_scenery->_toRedrawRight);
animObj.newBottom =
MAX(animObj.lastBottom, _vm->_scenery->_toRedrawBottom);
if ((_vm->_game->_script->getVersionMinor() > 2) &&
(animObj.newLeft == animObj.lastLeft) &&
(animObj.newTop == animObj.lastTop) &&
(animObj.newRight == animObj.lastRight) &&
(animObj.newBottom == animObj.lastBottom) &&
(animData.redrawLayer == animData.layer) &&
(animData.redrawFrame == animData.frame) &&
(animData.redrawAnimation == animData.animation)) {
animObj.needRedraw = 0;
}
}
} else if (!animData.isStatic) {
if (animObj.lastLeft == -1) {
animObj.needRedraw = 1;
_vm->_scenery->updateAnim(animData.layer, animData.frame,
animData.animation, 8, *animObj.pPosX, *animObj.pPosY, 0);
animObj.newLeft = _vm->_scenery->_toRedrawLeft;
animObj.newTop = _vm->_scenery->_toRedrawTop;
animObj.newRight = _vm->_scenery->_toRedrawRight;
animObj.newBottom = _vm->_scenery->_toRedrawBottom;
} else {
animObj.newLeft = animObj.lastLeft;
animObj.newTop = animObj.lastTop;
animObj.newRight = animObj.lastRight;
animObj.newBottom = animObj.lastBottom;
}
} else if (animObj.lastLeft != -1) {
animObj.needRedraw = 1;
animObj.newLeft = animObj.lastLeft;
animObj.newTop = animObj.lastTop;
animObj.newRight = animObj.lastRight;
animObj.newBottom = animObj.lastBottom;
}
animData.redrawLayer = animData.layer;
animData.redrawFrame = animData.frame;
animData.redrawAnimation = animData.animation;
if (animObj.needRedraw || !animData.isStatic) {
minOrder = MIN(minOrder, animData.order);
maxOrder = MAX(maxOrder, animData.order);
}
}
// Restore dirty areas
for (int i = 0; i < numAnims; i++) {
Mult_Object &animObj = *_renderObjs[i];
if (!animObj.needRedraw || (animObj.lastLeft == -1))
continue;
animObj.lastLeft = -1;
int maxleft = MAX(animObj.newLeft, _animLeft);
int maxtop = MAX(animObj.newTop, _animTop);
int right = animObj.newRight - maxleft + 1;
int bottom = animObj.newBottom - maxtop + 1;
if ((right <= 0) || (bottom <= 0))
continue;
_vm->_draw->_sourceSurface = 22;
_vm->_draw->_destSurface = 21;
_vm->_draw->_spriteLeft = maxleft - _animLeft;
_vm->_draw->_spriteTop = maxtop - _animTop;
_vm->_draw->_spriteRight = right;
_vm->_draw->_spriteBottom = bottom;
_vm->_draw->_destSpriteX = maxleft;
_vm->_draw->_destSpriteY = maxtop;
_vm->_draw->_transparency = 0;
_vm->_draw->spriteOperation(DRAW_DRAWLETTER);
}
// Figure out the correct drawing order
for (int i = minOrder; i <= maxOrder; i++) {
for (int j = 0; j < numAnims; j++) {
Mult_Object &animObj = *_renderObjs[j];
Mult_AnimData &animData = *(animObj.pAnimData);
if (animData.order == i)
if (animObj.needRedraw || !animData.isStatic)
orderArray[orderArrayPos++] = j;
}
}
// Put the goblins in correct drawing order as well
if (_vm->_goblin->_gobsCount >= 0) {
for (int i = 0; i < orderArrayPos; i++) {
Mult_Object &animObj1 = *_renderObjs[orderArray[i]];
Mult_AnimData &animData1 = *(animObj1.pAnimData);
if (!animObj1.goblinStates)
continue;
for (int j = i+1; j < orderArrayPos; j++) {
Mult_Object &animObj2 = *_renderObjs[orderArray[j]];
Mult_AnimData &animData2 = *(animObj2.pAnimData);
if ((animData1.order == animData2.order) &&
((animObj1.newBottom > animObj2.newBottom) ||
((animObj1.newBottom == animObj2.newBottom) &&
(animData1.isBusy == 1))))
SWAP(orderArray[i], orderArray[j]);
}
}
}
// Update view
for (int i = 0; i < orderArrayPos; i++) {
Mult_Object &animObj1 = *_renderObjs[orderArray[i]];
Mult_AnimData &animData1 = *(animObj1.pAnimData);
if (!animObj1.needRedraw) {
if (!animData1.isStatic) {
for (int j = 0; j < orderArrayPos; j++) {
Mult_Object &animObj2 = *_renderObjs[orderArray[j]];
if (!animObj2.needRedraw)
continue;
if ((animObj1.newRight >= animObj2.newLeft) &&
(animObj2.newRight >= animObj1.newLeft) &&
(animObj1.newBottom >= animObj2.newTop) &&
(animObj2.newBottom >= animObj1.newTop)) {
_vm->_scenery->_toRedrawLeft = animObj2.newLeft;
_vm->_scenery->_toRedrawRight = animObj2.newRight;
_vm->_scenery->_toRedrawTop = animObj2.newTop;
_vm->_scenery->_toRedrawBottom = animObj2.newBottom;
_vm->_scenery->updateAnim(animData1.layer, animData1.frame,
animData1.animation, 12, *animObj1.pPosX, *animObj1.pPosY, 1);
_vm->_scenery->updateStatic(animData1.order + 1);
}
}
}
} else {
if (animData1.isStatic != 0) {
_vm->_scenery->_toRedrawLeft = animObj1.newLeft;
_vm->_scenery->_toRedrawRight = animObj1.newRight;
_vm->_scenery->_toRedrawTop = animObj1.newTop;
_vm->_scenery->_toRedrawBottom = animObj1.newBottom;
} else {
_vm->_scenery->updateAnim(animData1.layer, animData1.frame,
animData1.animation, 10, *animObj1.pPosX, *animObj1.pPosY, 1);
if (_vm->_scenery->_toRedrawLeft != -12345) {
animObj1.lastLeft = _vm->_scenery->_toRedrawLeft;
animObj1.lastRight = _vm->_scenery->_toRedrawRight;
animObj1.lastTop = _vm->_scenery->_toRedrawTop;
animObj1.lastBottom = _vm->_scenery->_toRedrawBottom;
} else {
animObj1.lastLeft = -1;
}
}
_vm->_scenery->updateStatic(animData1.order + 1);
}
}
// Advance animations
for (int i = 0; i < numAnims; i++) {
Mult_Object &animObj = *_renderObjs[i];
Mult_AnimData &animData = *(animObj.pAnimData);
if (animData.isStatic)
continue;
if ((animData.animType == 7) && (animData.newState != -1)) {
animData.layer = animData.newState;
animData.frame = 0;
animData.newState = -1;
animData.isPaused = 0;
}
if (animData.isPaused)
continue;
if (animData.maxTick == animObj.tick) {
animObj.tick = 0;
if ((animData.animType < 100) || (_vm->_goblin->_gobsCount < 0))
newCycleAnim(animObj);
else if (animData.animType == 100)
_vm->_goblin->moveAdvance(&animObj, 0, 0, 0);
else if (animData.animType == 101)
_vm->_goblin->animate(&animObj);
} else
animObj.tick++;
}
// Find intersections
for (int i = 0; i < numAnims; i++) {
Mult_Object &animObj1 = *_renderObjs[i];
Mult_AnimData &animData1 = *(animObj1.pAnimData);
if (animData1.isStatic || (animObj1.lastLeft == -1))
continue;
for (int j = 0; j < numAnims; j++) {
Mult_Object &animObj2 = *_renderObjs[i];
Mult_AnimData &animData2 = *(animObj2.pAnimData);
if (i == j)
continue;
if ((animData2.isStatic) || (animObj2.lastLeft == -1))
continue;
if ((animObj2.lastRight >= animObj1.lastLeft) &&
(animObj2.lastLeft <= animObj1.lastRight) &&
(animObj2.lastBottom >= animObj1.lastTop) &&
(animObj2.lastTop <= animObj1.lastBottom))
animData2.intersected = animIndices[i];
}
}
}
void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir,
int16 startFrame) {
int16 x, y;
int16 palStart, palEnd;
int16 baseFrame, palFrame, lastFrame;
uint16 flags;
if (_vm->_draw->_renderFlags & 0x100) {
x = VAR(55);
y = VAR(56);
} else
x = y = -1;
if (key.imdFile == -1) {
_vm->_vidPlayer->primaryClose();
return;
}
flags = (key.flags >> 8) & 0xFF;
if (flags & 0x20)
flags = (flags & 0x9F) | 0x80;
palStart = key.palStart;
palEnd = key.palEnd;
palFrame = key.palFrame;
lastFrame = key.lastFrame;
if ((palFrame != -1) && (lastFrame != -1))
if ((lastFrame - palFrame) < startFrame)
if (!(key.flags & 0x4000)) {
_vm->_vidPlayer->primaryClose();
return;
}
if (!_vm->_vidPlayer->primaryOpen(imdFile, x, y, flags))
return;
if (palFrame == -1)
palFrame = 0;
if (lastFrame == -1)
lastFrame = _vm->_vidPlayer->getFrameCount() - 1;
baseFrame = startFrame % (lastFrame - palFrame + 1);
_vm->_vidPlayer->primaryPlay(baseFrame + palFrame, baseFrame + palFrame, 0,
flags & 0x7F, palStart, palEnd, palFrame, lastFrame);
}
void Mult_v2::advanceObjects(int16 index) {
int16 frame;
bool stop = false;
frame = _multData->animKeysFrames[index];
if (frame == -1)
return;
for (int i = 0; i < 4; i++) {
int obj = _multData->animObjs[index][i];
if ((obj != -1) && (obj != 1024)) {
int keyIndex = _multData->animKeysIndices[index][i];
int count = _multData->animKeysCount[i];
for (int j = keyIndex; j < count; j++) {
Mult_AnimKey &key = _multData->animKeys[i][j];
Mult_Object &animObj = _objects[obj];
Mult_AnimData &animData = *(animObj.pAnimData);
if (key.frame > frame)
break;
else if (key.frame < frame)
continue;
if (key.layer > -1) {
int16 layer;
int16 layers;
int16 curAnim;
_multData->animKeysIndices[index][i] = j;
*(animObj.pPosX) = key.posX;
*(animObj.pPosY) = key.posY;
animData.frame = 0;
animData.animType = 1;
animData.isStatic = 0;
animData.isPaused = 0;
animData.maxTick = 0;
animData.animation = 0;
animObj.tick = 0;
curAnim = _multData->animIndices[0];
layer = key.layer;
layers = _vm->_scenery->getAnimLayersCount(curAnim);
while (layer >= layers) {
layer -= layers;
animData.animation++;
curAnim = _multData->animIndices[animData.animation];
layers = _vm->_scenery->getAnimLayersCount(curAnim);
}
animData.layer = layer;
animData.animation =
_multData->animIndices[animData.animation];
break;
} else
animData.isStatic = 1;
}
}
if (obj != -1) {
int keyIndex = _multData->imdKeysIndices[index][i];
int count = _multData->imdKeysCount[i];
for (int j = keyIndex; j < count; j++) {
Mult_ImdKey &key1 = _multData->imdKeys[i][j];
Mult_ImdKey &key2 = _multData->imdKeys[i][j - 1];
if (key1.frame > frame)
break;
else if (key1.frame < frame)
continue;
if (key1.imdFile != -1) {
_multData->imdIndices[0] = -1;
_multData->imdIndices[1] = -1;
_multData->imdIndices[2] = -1;
_multData->imdIndices[3] = -1;
if ((_multData->animDirection == 1) || (key2.imdFile == -1))
_multData->imdIndices[i] = j;
else if (_multData->animKeysStopFrames[index] == frame)
_multData->imdIndices[i] = -1;
else
_multData->imdIndices[i] = j - 1;
} else
_multData->imdIndices[i] = -1;
}
}
if (_multData->imdIndices[i] != -1) {
int fileN;
char *imdFile;
int dir;
int startFrame;
Mult_ImdKey &key = _multData->imdKeys[i][_multData->imdIndices[i]];
fileN = -key.imdFile - 2;
if (fileN < 0)
return;
imdFile = _multData->imdFiles + fileN * 14;
dir = _multData->animDirection;
startFrame = frame - key.frame;
if ((dir != 1) && (--startFrame < 0))
startFrame = 0;
playImd(imdFile, key, dir, startFrame);
}
}
doSoundAnim(stop, frame);
WRITE_VAR(22, frame);
if (_multData->animKeysStopFrames[index] == frame) {
_multData->imdIndices[0] = -1;
_multData->imdIndices[1] = -1;
_multData->imdIndices[2] = -1;
_multData->imdIndices[3] = -1;
frame = -1;
for (int i = 0; i < 4; i++) {
int obj = _multData->animObjs[index][i];
if ((obj == -1) || (obj == 1024))
continue;
Mult_Object &animObj = _objects[_multData->animObjs[index][i]];
animObj.pAnimData->animType = animObj.pAnimData->animTypeBak;
}
} else if (_multData->animDirection == 1)
frame++;
else
frame--;
_multData->animKeysFrames[index] = frame;
WRITE_VAR(18 + index, frame);
}
void Mult_v2::advanceAllObjects() {
Mult_Data *multData = _multData;
for (int i = 0; i < 8; i++) {
if (_multDatas[i]) {
_multData = _multDatas[i];
for (int j = 0; j < 4; j++)
advanceObjects(j);
}
}
_multData = multData;
}
} // End of namespace Gob