Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

mult_v2.cpp

/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-11-1/engines/gob/mult_v2.cpp $
 * $Id: mult_v2.cpp 30944 2008-02-23 22:50:18Z sev $
 *
 */


#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/goblin.h"
#include "gob/inter.h"
#include "gob/parse.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;
      uint32 dataSize;
      byte *extData;
      bool hasImds;

      index = (resId & 0x8000) ? *_vm->_global->_inter_execPtr++ : 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;

      extData = (byte *) _vm->_game->loadExtData(resId, 0, 0, &dataSize);
      Common::MemoryReadStream data(extData, dataSize);

      _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 =
                        READ_LE_UINT16(_vm->_global->_inter_execPtr);
                  for (j = 0; j < i; j++) {
                        if (_multData->sndKeys[j].resId ==
                                    _multData->sndKeys[i].resId) {
                              _multData->sndKeys[i].soundIndex =
                                    _multData->sndKeys[j].soundIndex;
                              _vm->_global->_inter_execPtr += 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->_global->_inter_execPtr += 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[] extData;
}

void Mult_v2::loadImds(Common::SeekableReadStream &data) {
      int16 size;

      size = _vm->_inter->load16();
      _multData->execPtr = _vm->_global->_inter_execPtr;
      _vm->_global->_inter_execPtr += size * 2;

      if (_vm->_game->_totFileData[0x29] < 51)
            return;

      size = data.readSint16LE();
      if (size > 0) {
            _multData->somepointer10 = new char[size * 20];
            data.read(_multData->somepointer10, size * 20);
      }

      size = _vm->_inter->load16();
      if (size <= 0)
            return;

      _multData->imdFiles = new char[size * 14];
      memcpy(_multData->imdFiles, _vm->_global->_inter_execPtr, size * 14);
      _vm->_global->_inter_execPtr += 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");

      debugC(4, kDebugGameFlow, "Sub mult %d", multIndex);
      _multData = _multDatas[multIndex];

      if (!_multData) {
            _vm->_parse->parseValExpr();
            _vm->_parse->parseValExpr();
            _vm->_parse->parseValExpr();
            _vm->_parse->parseValExpr();
            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->_parse->parseValExpr();

      expr = _vm->_parse->parseValExpr();
      _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;
      }

      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;

            _vm->_util->setFrameRate(_multData->frameRate);
            _animTop = 0;
            _animLeft = 0;
            _animWidth = _vm->_video->_surfWidth;
            _animHeight = _vm->_video->_surfHeight;
            _objCount = 4;

            delete[] _objects;
            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 int32[_objCount];
            _animArrayY = new int32[_objCount];
            _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(_animArrayX, 0, _objCount * sizeof(int32));
            memset(_animArrayY, 0, _objCount * sizeof(int32));
            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 = (int32 *) &_animArrayX[_counter];
                  multObj.pPosY = (int32 *) &_animArrayY[_counter];
                  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) { // loc_50D5
      int16 count;
      int animIndex;

      for (int i = 0; i < 4; i++) {
            int16 animKeysCount = _multData->animKeysCount[i];
            if (_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);
      int nAnim = animData.animation;
      int nLayer = animData.layer;

      if (_vm->_scenery->getAnimLayersCount(nAnim) <= nLayer)
            return;

      Scenery::AnimLayer *animLayer = _vm->_scenery->getAnimLayer(nAnim, nLayer);

      if (animData.animType == 4) {
            animData.frame = 0;
            animData.isPaused = 1;
            return;
      }

      if (animData.animType != 8)
            animData.frame++;

      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;
            break;

      case 6:
      case 7:
            animData.frame--;
            animData.isPaused = 1;
            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->_totFileData[0x29] > 50) &&
                                    (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);

                  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 && !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) {
                  _vm->_scenery->updateAnim(animData1.layer, animData1.frame,
                              animData1.animation, 10, *animObj1.pPosX, *animObj1.pPosY, 1);

                  if (_vm->_scenery->_toRedrawLeft != -12345) {
                        if (_vm->_global->_pressedKeys[0x36]) {
                              _vm->_video->drawLine(_vm->_draw->_frontSurface,
                                          _vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawTop,
                                          _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawTop, 15);
                              _vm->_video->drawLine(_vm->_draw->_frontSurface,
                                          _vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawBottom,
                                          _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawBottom, 15);
                              _vm->_video->drawLine(_vm->_draw->_frontSurface,
                                          _vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawTop,
                                          _vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawBottom, 15);
                              _vm->_video->drawLine(_vm->_draw->_frontSurface,
                                          _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawTop,
                                          _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawBottom, 15);
                        }
                        animObj1.lastLeft = _vm->_scenery->_toRedrawLeft;
                        animObj1.lastRight = _vm->_scenery->_toRedrawRight;
                        animObj1.lastTop = _vm->_scenery->_toRedrawTop;
                        animObj1.lastBottom = _vm->_scenery->_toRedrawBottom;
                  } else
                        animObj1.lastLeft = -1;
            } else {
                  _vm->_scenery->_toRedrawLeft = animObj1.newLeft;
                  _vm->_scenery->_toRedrawRight = animObj1.newRight;
                  _vm->_scenery->_toRedrawTop = animObj1.newTop;
                  _vm->_scenery->_toRedrawBottom = animObj1.newBottom;
            }
            _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;

      _vm->_game->_preventScroll = true;

      if (_vm->_draw->_renderFlags & 0x100) {
            x = VAR(55);
            y = VAR(56);
      } else
            x = y = -1;

      if (key.imdFile == -1) {
            _vm->_vidPlayer->closeVideo();
            _vm->_game->_preventScroll = false;
            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->_game->_preventScroll = false;
                        _vm->_vidPlayer->closeVideo();
                        return;
                  }

      if (!_vm->_vidPlayer->openVideo(imdFile, x, y, flags)) {
            _vm->_game->_preventScroll = false;
            return;
      }

      if (palFrame == -1)
            palFrame = 0;

      if (lastFrame == -1)
            lastFrame = _vm->_vidPlayer->getFramesCount() - 1;

      baseFrame = startFrame % (lastFrame - palFrame + 1);
      _vm->_vidPlayer->play(baseFrame + palFrame, baseFrame + palFrame, 0,
                  flags & 0x7F, palStart, palEnd, palFrame, lastFrame);
}

void Mult_v2::advanceObjects(int16 index) {
      int16 frame;
      bool stop = false;
      bool hasImds = 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;

                  hasImds = true;
                  playImd(imdFile, key, dir, startFrame);
            }
      }

      if (!hasImds && (_vm->_draw->_showCursor == 3))
            _vm->_game->_preventScroll = false;

      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

Generated by  Doxygen 1.6.0   Back to index