diff options
author | Sven Hesse | 2008-04-27 03:19:19 +0000 |
---|---|---|
committer | Sven Hesse | 2008-04-27 03:19:19 +0000 |
commit | ab1a3b0cc89686fa2e9ef864a429ae27ed7b2d2f (patch) | |
tree | 201eb24a9d3c98d641bb44dd811d69ba2a882ec4 /engines/gob | |
parent | 1d167da633a7dd666bb946156dd9e0ec29be2b53 (diff) | |
download | scummvm-rg350-ab1a3b0cc89686fa2e9ef864a429ae27ed7b2d2f.tar.gz scummvm-rg350-ab1a3b0cc89686fa2e9ef864a429ae27ed7b2d2f.tar.bz2 scummvm-rg350-ab1a3b0cc89686fa2e9ef864a429ae27ed7b2d2f.zip |
Implemented support for VMDs substituting object animations.
Still far from being complete (and correct), but it's a start...
- Only VMD "command" -3 is followed
- Not all animation types are working
- Timing is still off in most cases
- Offsets are generally OK, but not always
- No sound yet
- Shouldn't segfault randomly, but I'm not entirely sure ;)
svn-id: r31750
Diffstat (limited to 'engines/gob')
-rw-r--r-- | engines/gob/coktelvideo.cpp | 85 | ||||
-rw-r--r-- | engines/gob/coktelvideo.h | 28 | ||||
-rw-r--r-- | engines/gob/game_v2.cpp | 2 | ||||
-rw-r--r-- | engines/gob/goblin.h | 14 | ||||
-rw-r--r-- | engines/gob/goblin_v2.cpp | 2 | ||||
-rw-r--r-- | engines/gob/goblin_v4.cpp | 635 | ||||
-rw-r--r-- | engines/gob/init.cpp | 6 | ||||
-rw-r--r-- | engines/gob/inter_bargon.cpp | 48 | ||||
-rw-r--r-- | engines/gob/inter_v2.cpp | 29 | ||||
-rw-r--r-- | engines/gob/inter_v4.cpp | 33 | ||||
-rw-r--r-- | engines/gob/module.mk | 1 | ||||
-rw-r--r-- | engines/gob/mult.h | 3 | ||||
-rw-r--r-- | engines/gob/mult_v2.cpp | 67 | ||||
-rw-r--r-- | engines/gob/scenery.cpp | 153 | ||||
-rw-r--r-- | engines/gob/scenery.h | 1 | ||||
-rw-r--r-- | engines/gob/util.cpp | 4 | ||||
-rw-r--r-- | engines/gob/videoplayer.cpp | 366 | ||||
-rw-r--r-- | engines/gob/videoplayer.h | 67 |
18 files changed, 1351 insertions, 193 deletions
diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp index c6286fba3b..d508dc75f9 100644 --- a/engines/gob/coktelvideo.cpp +++ b/engines/gob/coktelvideo.cpp @@ -333,41 +333,44 @@ void Imd::waitEndFrame() { g_system->delayMillis(_frameLength); } -void Imd::copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp) { +void Imd::copyCurrentFrame(byte *dest, + uint16 left, uint16 top, uint16 width, uint16 height, + uint16 x, uint16 y, uint16 pitch, int16 transp) { + if (!_vidMem) return; - dest += width * y; + if (((left + width) > _width) || ((top + height) > _height)) + return; - uint16 copyWidth = MIN<int16>(width - x, _width); - uint16 destPitch = width - x; - byte *vidMem = _vidMem; + dest += pitch * y; + byte *vidMem = _vidMem + _width * top; if (transp < 0) { // No transparency - if ((x > 0) || (_width != width)) { + if ((x > 0) || (left > 0) || (pitch != _width) || (width != _width)) { // Copy row-by-row - for (int i = 0; i < _height; i++) { - dest += x; - memcpy(dest, vidMem, copyWidth); - dest += destPitch; + for (int i = 0; i < height; i++) { + byte *d = dest + x; + byte *s = vidMem + left; + + memcpy(d, s, width); + + dest += pitch; vidMem += _width; } - } else // Dimensions fit, copy everything at once - memcpy(dest, _vidMem, _width * _height); + memcpy(dest, vidMem, width * height); return; } - // Transparency, copy per pixel - for (int i = 0; i < _height; i++) { - byte *s = vidMem; - byte *d = dest; + for (int i = 0; i < height; i++) { + byte *d = dest + x; + byte *s = vidMem + left; - d += x; - for (int j = 0; j < _width; j++) { + for (int j = 0; j < width; j++) { if (*s != transp) *d = *s; @@ -375,9 +378,10 @@ void Imd::copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 t d++; } - dest += width; + dest += pitch; vidMem += _width; } + } void Imd::deleteVidMem(bool del) { @@ -938,9 +942,9 @@ bool Vmd::load(Common::SeekableReadStream &stream) { } else _frameLength = 1000 / _frameRate; - uint32 frameInfoOffset = _stream->readUint32LE(); + _frameInfoOffset = _stream->readUint32LE(); - _stream->seek(frameInfoOffset); + _stream->seek(_frameInfoOffset); _frames = new Frame[_framesCount]; for (uint16 i = 0; i < _framesCount; i++) { _frames[i].parts = new Part[_partsPerFrame]; @@ -1350,4 +1354,43 @@ void Vmd::deDPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n) { } } +bool Vmd::getAnchor(int16 frame, uint16 partType, + int16 &x, int16 &y, int16 &width, int16 &height) { + + uint32 pos = _stream->pos(); + + _stream->seek(_frameInfoOffset); + // Offsets to frames + _stream->skip(_framesCount * 6); + // Jump to the specified frame + _stream->skip(_partsPerFrame * frame * 16); + + // Find the anchor part + uint16 i; + for (i = 0; i < _partsPerFrame; i++) { + byte type = _stream->readByte(); + + if ((type == 0) || (type == partType)) + break; + + _stream->skip(15); + } + + if (i == _partsPerFrame) { + // No anchor + + _stream->seek(pos); + return false; + } + + _stream->skip(5); + x = _stream->readSint16LE(); + y = _stream->readSint16LE(); + width = _stream->readSint16LE() - x + 1; + height = _stream->readSint16LE() - y + 1; + + _stream->seek(pos); + return true; +} + } // End of namespace Gob diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h index 84271073f6..4f9543e8d0 100644 --- a/engines/gob/coktelvideo.h +++ b/engines/gob/coktelvideo.h @@ -90,6 +90,8 @@ public: /** Returns the features the loaded video possesses. */ virtual uint16 getFeatures() const = 0; + /** Returns the flags the loaded video possesses. */ + virtual uint16 getFlags() const = 0; /** Returns the x coordinate of the video. */ virtual int16 getX() const = 0; /** Returns the y coordinate of the video. */ @@ -113,6 +115,10 @@ public: /** Returns the current frame's palette. */ virtual const byte *getPalette() const = 0; + /** Reads the video's anchor pointer */ + virtual bool getAnchor(int16 frame, uint16 partType, + int16 &x, int16 &y, int16 &width, int16 &height) = 0; + /** Load a video out of a stream. */ virtual bool load(Common::SeekableReadStream &stream) = 0; /** Unload the currently loaded video. */ @@ -148,13 +154,19 @@ public: /** Copy the current frame. * - * @param dest The memory to which to copy the current frame + * @param dest The memory to which to copy the current frame. + * @param left The x position within the frame. + * @param top The y position within the frame. + * @param width The width of the area to copy. + * @param height The height of the area to copy. * @param x The x position to where to copy. * @param y The y position to where to copy. * @param pitch The buffer's width. * @param transp Which color should be seen as transparent? */ - virtual void copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp = -1) = 0; + virtual void copyCurrentFrame(byte *dest, + uint16 left, uint16 top, uint16 width, uint16 height, + uint16 x, uint16 y, uint16 pitch, int16 transp = -1) = 0; }; /** Coktel Vision's IMD files. @@ -165,6 +177,7 @@ public: ~Imd(); uint16 getFeatures() const { return _features; } + uint16 getFlags() const { return _flags; } int16 getX() const { return _x; } int16 getY() const { return _y; } int16 getWidth() const { return _width; } @@ -175,6 +188,9 @@ public: uint32 getSyncLag() const { return _skipFrames; } const byte *getPalette() const { return _palette; } + bool getAnchor(int16 frame, uint16 partType, + int16 &x, int16 &y, int16 &width, int16 &height) { return false; } + void setFrameRate(int16 frameRate); bool load(Common::SeekableReadStream &stream); @@ -192,7 +208,9 @@ public: State nextFrame(); void waitEndFrame(); - void copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp = -1); + void copyCurrentFrame(byte *dest, + uint16 left, uint16 top, uint16 width, uint16 height, + uint16 x, uint16 y, uint16 pitch, int16 transp = -1); protected: struct Coord { @@ -260,6 +278,9 @@ public: Vmd(); ~Vmd(); + bool getAnchor(int16 frame, uint16 partType, + int16 &x, int16 &y, int16 &width, int16 &height); + bool load(Common::SeekableReadStream &stream); void unload(); @@ -295,6 +316,7 @@ protected: bool _hasVideo; + uint32 _frameInfoOffset; uint16 _partsPerFrame; Frame *_frames; diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp index c69db45f15..45542541e3 100644 --- a/engines/gob/game_v2.cpp +++ b/engines/gob/game_v2.cpp @@ -272,7 +272,7 @@ void Game_v2::playTot(int16 skipPlay) { _vm->_snd->freeSample(_soundSamples[i]); } - _vm->_vidPlayer->closeVideo(); + _vm->_vidPlayer->primaryClose(); if (_totToLoad[0] == 0) break; diff --git a/engines/gob/goblin.h b/engines/gob/goblin.h index 0da4b5ace5..f7ac4aa549 100644 --- a/engines/gob/goblin.h +++ b/engines/gob/goblin.h @@ -315,6 +315,20 @@ protected: virtual void advMovement(Mult::Mult_Object *obj, int8 state); }; +class Goblin_v4 : public Goblin_v3 { +public: + virtual void movePathFind(Mult::Mult_Object *obj, + Gob_Object *gobDesc, int16 nextAct); + virtual void moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc, + int16 nextAct, int16 framesCount); + + Goblin_v4(GobEngine *vm); + virtual ~Goblin_v4() {} + +private: + int16 sub_20430(int16 state, uint16 dir); +}; + } // End of namespace Gob #endif // GOB_GOBLIN_H diff --git a/engines/gob/goblin_v2.cpp b/engines/gob/goblin_v2.cpp index c9e155ad08..8af4015c1b 100644 --- a/engines/gob/goblin_v2.cpp +++ b/engines/gob/goblin_v2.cpp @@ -266,7 +266,7 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16 if (_vm->_map->_screenWidth == 640) { if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) animData->nextState = 41; - if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY + 2) != 10) + if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY) != 10) animData->nextState = 7; } break; diff --git a/engines/gob/goblin_v4.cpp b/engines/gob/goblin_v4.cpp new file mode 100644 index 0000000000..0defd32289 --- /dev/null +++ b/engines/gob/goblin_v4.cpp @@ -0,0 +1,635 @@ +/* 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 "gob/gob.h" +#include "gob/goblin.h" +#include "gob/global.h" +#include "gob/mult.h" +#include "gob/map.h" +#include "gob/scenery.h" + +namespace Gob { + +Goblin_v4::Goblin_v4(GobEngine *vm) : Goblin_v3(vm) { +} + +void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16 nextAct) { + Mult::Mult_AnimData *animData; + int16 framesCount; + int16 gobX; + int16 gobY; + int16 gobDestX; + int16 gobDestY; + int16 destX; + int16 destY; + int16 dir; + + dir = 0; + animData = obj->pAnimData; + framesCount = _vm->_scenery->getAnimLayer(animData->animation, animData->layer)->framesCount; + animData->newCycle = framesCount; + gobX = obj->goblinX; + gobY = obj->goblinY; + animData->order = gobY; + gobDestX = obj->gobDestX; + gobDestY = obj->gobDestY; + animData->destX = gobDestX; + animData->destY = gobDestY; + destX = obj->destX; + destY = obj->destY; + + if (animData->pathExistence == 1) { + dir = _vm->_map->getDirection(gobX, gobY, destX, destY); + if (dir == 0) + animData->pathExistence = 0; + if ((gobX == destX) && (gobY == destY)) + animData->pathExistence = 4; + } else if (animData->pathExistence == 3) { + if ((gobX == gobDestX) && (gobY == gobDestY)) { + animData->pathExistence = 4; + destX = gobDestX; + destY = gobDestY; + } else { + if (_vm->_map->checkDirectPath(obj, gobX, gobY, gobDestX, gobDestY) != 1) { + if ((gobX == destX) && (gobY == destY)) { + if (obj->nearestWayPoint > obj->nearestDest) { + _vm->_map->optimizePoints(obj, gobX, gobY); + destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x; + destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y; + if (_vm->_map->checkDirectPath(obj, gobX, gobY, destX, destY) == 3) { + WRITE_VAR(56, 1); + animData->pathExistence = 0; + } + if (obj->nearestWayPoint > obj->nearestDest) + obj->nearestWayPoint--; + } else if (obj->nearestWayPoint < obj->nearestDest) { + _vm->_map->optimizePoints(obj, gobX, gobY); + destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x; + destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y; + if (_vm->_map->checkDirectPath(obj, gobX, gobY, destX, destY) == 3) { + WRITE_VAR(56, 1); + animData->pathExistence = 0; + } + if (obj->nearestWayPoint < obj->nearestDest) + obj->nearestWayPoint++; + } else { + if ((_vm->_map->checkDirectPath(obj, gobX, gobY, gobDestX, gobDestY) == 3) && + (_vm->_map->getPass(gobDestX, gobDestY) != 0)) { + destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x; + destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y; + WRITE_VAR(56, 1); + } else { + animData->pathExistence = 1; + destX = gobDestX; + destY = gobDestY; + } + } + } + } else { + destX = gobDestX; + destY = gobDestY; + } + dir = _vm->_map->getDirection(gobX, gobY, destX, destY); + } + } + + obj->goblinX = gobX; + obj->goblinY = gobY; + obj->gobDestX = gobDestX; + obj->gobDestY = gobDestY; + obj->destX = destX; + obj->destY = destY; + + if (_vm->_map->_widthByte == 4) { + switch (dir) { + case Map::kDirNW: + animData->nextState = sub_20430(animData->state, Map::kDirNW); + if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) && + (animData->nextState == 1)) + animData->nextState = 40; + if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10) + animData->nextState = sub_20430(animData->state, Map::kDirNW); + break; + + case Map::kDirN: + animData->nextState = + (animData->curLookDir == 2) ? 2 : sub_20430(animData->state, Map::kDirN); + if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) { + if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10) { + if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) == 10) + animData->nextState = 42; + else + animData->nextState = 2; + } else + animData->nextState = 40; + } + if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 20) && + (animData->nextState == 2)) + animData->nextState = 38; + if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 19) && + (animData->nextState == 2)) + animData->nextState = 26; + break; + + case Map::kDirNE: + animData->nextState = sub_20430(animData->state, Map::kDirNE); + if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) && + (animData->nextState == 3)) + animData->nextState = 42; + if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) != 10) + animData->nextState = sub_20430(animData->state, Map::kDirNE); + break; + + case Map::kDirW: + animData->nextState = sub_20430(animData->state, Map::kDirW); + break; + + case Map::kDirE: + animData->nextState = sub_20430(animData->state, Map::kDirE); + break; + + case Map::kDirSW: + animData->nextState = sub_20430(animData->state, Map::kDirSW); + if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) && + (animData->nextState == 7)) + animData->nextState = 41; + if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY) != 10) + animData->nextState = sub_20430(animData->state, Map::kDirSW); + break; + + case Map::kDirS: + animData->nextState = + (animData->curLookDir == 6) ? 6 : sub_20430(animData->state, Map::kDirS); + if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) { + if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY + 2) != 10) { + if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY + 2) == 10) + animData->nextState = 43; + else + animData->nextState = 6; + } else + animData->nextState = 41; + } + // loc_20AAD + if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 20) && + (animData->nextState == 6)) + animData->nextState = 39; + if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 19) && + (animData->nextState == 6)) + animData->nextState = 27; + break; + + case Map::kDirSE: + animData->nextState = sub_20430(animData->state, Map::kDirSE); + if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) && + (animData->nextState == 5)) + animData->nextState = 43; + if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY) != 10) + animData->nextState = sub_20430(animData->state, Map::kDirSE); + break; + + default: + // loc_20D18 + switch (animData->state) { + case 0: + case 8: + // loc_21134 + animData->nextState = 8; + break; + + case 1: + case 10: + case 40: + // loc_21152 + animData->nextState = 10; + break; + + case 2: + case 29: + // loc_2113E + animData->nextState = 29; + break; + + case 3: + case 11: + case 42: + // loc_2115C + animData->nextState = 11; + break; + + case 4: + case 9: + // loc_2112A + animData->nextState = 9; + break; + + case 5: + case 30: + case 43: + // loc_21166 + animData->nextState = 30; + break; + + case 6: + case 28: + // loc_21148 + animData->nextState = 28; + break; + + case 7: + case 31: + case 41: + // loc_21170 + animData->nextState = 31; + break; + } + break; + } + } else { + switch (dir) { + case Map::kDirNW: + animData->nextState = 1; + if (_vm->_map->_screenWidth == 640) { + if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) + animData->nextState = 40; + if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10) + animData->nextState = 1; + } + break; + + case Map::kDirN: + animData->nextState = + (animData->curLookDir == 2) ? 2 : rotateState(animData->curLookDir, 2); + if (_vm->_map->_screenWidth == 640) { + if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) { + if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10) { + if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) == 10) + animData->nextState = 42; + else + animData->nextState = 2; + } else + animData->nextState = 40; + } else if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 20) + animData->nextState = 38; + else if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 19) + animData->nextState = 26; + } + break; + + case Map::kDirNE: + animData->nextState = 3; + if (_vm->_map->_screenWidth == 640) { + if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) + animData->nextState = 42; + if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) != 10) + animData->nextState = 3; + } + break; + + case Map::kDirW: + animData->nextState = rotateState(animData->curLookDir, 0); + break; + + case Map::kDirE: + animData->nextState = rotateState(animData->curLookDir, 4); + break; + + case Map::kDirSW: + animData->nextState = 7; + if (_vm->_map->_screenWidth == 640) { + if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) + animData->nextState = 41; + if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY + 2) != 10) + animData->nextState = 7; + } + break; + + case Map::kDirS: + animData->nextState = + (animData->curLookDir == 6) ? 6 : rotateState(animData->curLookDir, 6); + if (_vm->_map->_screenWidth == 640) { + if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 20) + animData->nextState = 39; + else if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 19) + animData->nextState = 27; + } + break; + + case Map::kDirSE: + animData->nextState = 5; + if (_vm->_map->_screenWidth == 640) { + if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) + animData->nextState = 43; + if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY + 2) != 10) + animData->nextState = 5; + } + break; + + default: + switch (animData->curLookDir) { + case 0: + animData->nextState = 8; + break; + case 1: + animData->nextState = 10; + break; + case 2: + animData->nextState = 29; + break; + case 3: + animData->nextState = 11; + break; + case 4: + animData->nextState = 9; + break; + case 5: + animData->nextState = 30; + break; + case 6: + animData->nextState = 28; + break; + case 7: + animData->nextState = 31; + break; + } + break; + } + } +} + +void Goblin_v4::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc, + int16 nextAct, int16 framesCount) { + Mult::Mult_AnimData *animData; + int16 gobX; + int16 gobY; + int16 animation; + int16 state; + int16 layer; + + if (!obj->goblinStates) + return; + + movePathFind(obj, 0, 0); + playSounds(obj); + + animData = obj->pAnimData; + + framesCount = _vm->_scenery->getAnimLayer(animData->animation, animData->layer)->framesCount; + + if (animData->isPaused == 0) + animData->frame++; + + switch (animData->stateType) { + case 0: + case 1: + animData->isPaused = 0; + break; + + case 4: + if (animData->frame == 0) + animData->isPaused = 1; + break; + + case 6: + if (animData->frame >= framesCount) + animData->isPaused = 1; + break; + } + + switch (animData->state) { + case 0: + case 1: + case 7: + case 13: + case 16: + case 23: + animData->curLookDir = 0; + break; + + case 2: + case 15: + case 18: + case 21: + animData->curLookDir = 2; + break; + + case 3: + case 4: + case 5: + case 12: + case 19: + case 22: + animData->curLookDir = 4; + break; + + case 6: + case 14: + case 17: + case 20: + animData->curLookDir = 6; + break; + + case 8: + case 9: + case 28: + case 29: + if (animData->pathExistence == 4) + animData->pathExistence = 5; + break; + } + + if ((animData->newState != -1) && (animData->frame == framesCount) && + (animData->newState != animData->state)) { + animData->nextState = animData->newState; + animData->newState = -1; + animData->state = animData->nextState; + + Scenery::AnimLayer *animLayer = + _vm->_scenery->getAnimLayer(animData->animation, animData->layer); + *obj->pPosX += animLayer->animDeltaX; + *obj->pPosY += animLayer->animDeltaY; + + animation = obj->goblinStates[animData->nextState][0].animation; + layer = obj->goblinStates[animData->nextState][0].layer; + animData->layer = layer; + animData->animation = animation; + animData->frame = 0; + } else { + if (isMovement(animData->state)) { + state = animData->nextState; + if (animData->frame == ((framesCount + 1) / 2)) { + gobX = obj->goblinX; + gobY = obj->goblinY; + + advMovement(obj, state); + + if (animData->state != state) { + animation = obj->goblinStates[state][0].animation; + layer = obj->goblinStates[state][0].layer; + animData->layer = layer; + animData->animation = animation; + animData->frame = 0; + animData->state = state; + _vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0); + if (_vm->_map->_bigTiles) + *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) - + (_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (gobY + 1) / 2; + else + *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) - + (_vm->_scenery->_animBottom - _vm->_scenery->_animTop); + *obj->pPosX = gobX * _vm->_map->_tilesWidth; + } + } + } + + if (animData->frame >= framesCount) { + state = animData->nextState; + animation = obj->goblinStates[state][0].animation; + layer = obj->goblinStates[state][0].layer; + animData->layer = layer; + animData->animation = animation; + animData->frame = 0; + animData->state = state; + gobX = obj->goblinX; + gobY = obj->goblinY; + + advMovement(obj, state); + + _vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0); + if (_vm->_map->_bigTiles) + *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) - + (_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (gobY + 1) / 2; + else + *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) - + (_vm->_scenery->_animBottom - _vm->_scenery->_animTop); + *obj->pPosX = gobX * _vm->_map->_tilesWidth; + } + } +} + +int16 Goblin_v4::sub_20430(int16 state, uint16 dir) { + static const int16 word_3F25E[8][8] = { + {0, 1, 10, 10, 10, 31, 31, 7}, + {0, 1, 2, 29, 29, 29, 8, 8}, + {10, 1, 2, 3, 11, 11, 11, 10}, + {29, 29, 2, 3, 4, 9, 9, 9}, + {30, 11, 11, 3, 4, 5, 30, 30}, + {28, 28, 9, 9, 4, 5, 6, 28}, + {31, 31, 31, 30, 30, 5, 6, 7}, + {0, 8, 8, 8, 28, 28, 6, 7} + }; + int16 dx = state, cx = 0; + + switch (state) { + case 0: + case 8: + // loc_20447 + dx = 0; + break; + + case 1: + case 10: + case 40: + // loc_2044B + dx = 1; + break; + + case 3: + case 11: + case 42: + // loc_20455 + dx = 3; + break; + + case 5: + case 30: + case 43: + // loc_2045F + dx = 5; + break; + + case 7: + case 31: + case 41: + // loc_20469 + dx = 7; + break; + + case 9: + // loc_2045A + dx = 4; + break; + + case 28: + // loc_20464 + dx = 6; + break; + + case 29: + // loc_20450 + dx = 2; + break; + } + + // loc_2046C + + + switch (dir) { + case Map::kDirNW: + cx = 1; + break; + + case Map::kDirN: + cx = 2; + break; + + case Map::kDirNE: + cx = 3; + break; + + case Map::kDirW: + cx = 0; + break; + + case Map::kDirE: + cx = 4; + break; + + case Map::kDirSW: + cx = 7; + break; + + case Map::kDirS: + cx = 6; + break; + + case Map::kDirSE: + cx = 5; + break; + } + + return word_3F25E[dx][cx]; +} + +} // End of namespace Gob diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index f38d5ac115..4d184c53d3 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -181,9 +181,9 @@ void Init::initGame(const char *totName) { _vm->_util->longDelay(200); // Letting everything settle - if (_vm->_vidPlayer->openVideo("coktel.imd")) { - _vm->_vidPlayer->play(); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("coktel.imd")) { + _vm->_vidPlayer->primaryPlay(); + _vm->_vidPlayer->primaryClose(); } _vm->_draw->closeScreen(); diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index 0de8245dea..702950d539 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -717,16 +717,16 @@ const char *Inter_Bargon::getOpcodeGoblinDesc(int i) { } void Inter_Bargon::oBargon_intro0(OpGobParams ¶ms) { - if (_vm->_vidPlayer->openVideo("scaa", 0, 160)) { - _vm->_vidPlayer->play(0, 92, 27, 0, 0, 0); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("scaa", 0, 160)) { + _vm->_vidPlayer->primaryPlay(0, 92, 27, 0, 0, 0); + _vm->_vidPlayer->primaryClose(); } } void Inter_Bargon::oBargon_intro1(OpGobParams ¶ms) { - if (_vm->_vidPlayer->openVideo("scaa", 0, 160)) { - _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0, 0, 0, true, 23); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("scaa", 0, 160)) { + _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0, 0, 0, true, 23); + _vm->_vidPlayer->primaryClose(); } } @@ -819,44 +819,44 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { } void Inter_Bargon::oBargon_intro4(OpGobParams ¶ms) { - if (_vm->_vidPlayer->openVideo("scba", 191, 54)) { - _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0, 0, 0, true); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("scba", 191, 54)) { + _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0, 0, 0, true); + _vm->_vidPlayer->primaryClose(); } } void Inter_Bargon::oBargon_intro5(OpGobParams ¶ms) { - if (_vm->_vidPlayer->openVideo("scbb", 191, 54)) { - _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("scbb", 191, 54)) { + _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->primaryClose(); } } void Inter_Bargon::oBargon_intro6(OpGobParams ¶ms) { - if (_vm->_vidPlayer->openVideo("scbc", 191, 54)) { - _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("scbc", 191, 54)) { + _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->primaryClose(); } } void Inter_Bargon::oBargon_intro7(OpGobParams ¶ms) { - if (_vm->_vidPlayer->openVideo("scbf", 191, 54)) { - _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("scbf", 191, 54)) { + _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->primaryClose(); } } void Inter_Bargon::oBargon_intro8(OpGobParams ¶ms) { - if (_vm->_vidPlayer->openVideo("scbc", 191, 54)) { - _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("scbc", 191, 54)) { + _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->primaryClose(); } } void Inter_Bargon::oBargon_intro9(OpGobParams ¶ms) { - if (_vm->_vidPlayer->openVideo("scbd", 191, 54)) { - _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->closeVideo(); + if (_vm->_vidPlayer->primaryOpen("scbd", 191, 54)) { + _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->primaryClose(); } } diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 46d40d1553..9b474a08d6 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -988,12 +988,10 @@ void Inter_v2::o2_loadMultObject() { _vm->_global->_inter_execPtr++; } - if (_vm->_goblin->_gobsCount <= objIndex) - return; - Mult::Mult_Object &obj = _vm->_mult->_objects[objIndex]; Mult::Mult_AnimData &objAnim = *(obj.pAnimData); - if (objAnim.animType == 100) { + + if ((objAnim.animType == 100) && (objIndex < _vm->_goblin->_gobsCount)) { val = *(obj.pPosX) % 256; obj.destX = val; @@ -1029,7 +1027,7 @@ void Inter_v2::o2_loadMultObject() { ((obj.goblinY + 1) / 2); *(obj.pPosX) = obj.goblinX * _vm->_map->_tilesWidth; - } else if (objAnim.animType == 101) { + } else if ((objAnim.animType == 101) && (objIndex < _vm->_goblin->_gobsCount)) { layer = objAnim.layer; animation = obj.goblinStates[layer][0].animation; @@ -1048,6 +1046,21 @@ void Inter_v2::o2_loadMultObject() { } _vm->_scenery->updateAnim(layer, 0, animation, 0, *(obj.pPosX), *(obj.pPosY), 0); + + } else if ((objAnim.animType != 100) && (objAnim.animType != 101)) { + + if ((*(obj.pPosX) == -1234) && (*(obj.pPosY) == -4321)) { + + if (obj.videoSlot > 0) + _vm->_vidPlayer->slotClose(obj.videoSlot - 1); + + obj.videoSlot = 0; + obj.lastLeft = -1; + obj.lastTop = -1; + obj.lastBottom = -1; + obj.lastRight = -1; + } + } } @@ -1519,7 +1532,7 @@ void Inter_v2::o2_playImd() { palEnd = _vm->_parse->parseValExpr(); palCmd = 1 << (flags & 0x3F); - if ((imd[0] != 0) && !_vm->_vidPlayer->openVideo(imd, x, y, flags)) { + if ((imd[0] != 0) && !_vm->_vidPlayer->primaryOpen(imd, x, y, flags)) { WRITE_VAR(11, -1); return; } @@ -1532,12 +1545,12 @@ void Inter_v2::o2_playImd() { if (startFrame >= 0) { _vm->_game->_preventScroll = true; - _vm->_vidPlayer->play(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); + _vm->_vidPlayer->primaryPlay(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); _vm->_game->_preventScroll = false; } if (close) - _vm->_vidPlayer->closeVideo(); + _vm->_vidPlayer->primaryClose(); } void Inter_v2::o2_getImdInfo() { diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp index d2269e5b2c..71c0f293ec 100644 --- a/engines/gob/inter_v4.cpp +++ b/engines/gob/inter_v4.cpp @@ -544,9 +544,9 @@ void Inter_v4::setupOpcodes() { static const OpcodeGoblinEntryV4 opcodesGoblin[71] = { /* 00 */ - OPCODE(o2_loadInfogramesIns), - OPCODE(o2_startInfogrames), - OPCODE(o2_stopInfogrames), + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, {NULL, ""}, /* 04 */ {NULL, ""}, @@ -555,7 +555,7 @@ void Inter_v4::setupOpcodes() { {NULL, ""}, /* 08 */ {NULL, ""}, - OPCODE(o2_playInfogrames), + {NULL, ""}, {NULL, ""}, {NULL, ""}, /* 0C */ @@ -592,7 +592,7 @@ void Inter_v4::setupOpcodes() { {NULL, ""}, {NULL, ""}, {NULL, ""}, - OPCODE(o2_handleGoblins), + {NULL, ""}, /* 28 */ {NULL, ""}, {NULL, ""}, @@ -723,7 +723,6 @@ void Inter_v4::o4_playVmdOrMusic() { bool close; evalExpr(0); - _vm->_global->_inter_resStr[8] = 0; strncpy0(fileName, _vm->_global->_inter_resStr, 127); x = _vm->_parse->parseValExpr(); @@ -740,8 +739,20 @@ void Inter_v4::o4_playVmdOrMusic() { if (lastFrame == -1) { close = true; } else if (lastFrame == -3) { - warning("Woodruff Stub: Video/Music command -3: Play background video %s", fileName); -// return; + warning("Woodruff Stub: Video/Music command -3: Play background video %s, %d, %d", fileName, x, y); + + _vm->_mult->_objects[startFrame].pAnimData->animation = -startFrame - 1; + + if (_vm->_mult->_objects[startFrame].videoSlot > 0) + _vm->_vidPlayer->slotClose(_vm->_mult->_objects[startFrame].videoSlot - 1); + _vm->_mult->_objects[startFrame].videoSlot = _vm->_vidPlayer->slotOpen(fileName) + 1; + + if (x != -1) { + *_vm->_mult->_objects[startFrame].pPosX = x; + *_vm->_mult->_objects[startFrame].pPosY = y; + } + + return; } else if (lastFrame == -4) { warning("Woodruff Stub: Video/Music command -4: Play background video %s", fileName); return; @@ -767,19 +778,19 @@ void Inter_v4::o4_playVmdOrMusic() { close = false; } - if ((fileName[0] != 0) && !_vm->_vidPlayer->openVideo(fileName, x, y, flags)) { + if ((fileName[0] != 0) && !_vm->_vidPlayer->primaryOpen(fileName, x, y, flags)) { WRITE_VAR(11, -1); return; } if (startFrame >= 0) { _vm->_game->_preventScroll = true; - _vm->_vidPlayer->play(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); + _vm->_vidPlayer->primaryPlay(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); _vm->_game->_preventScroll = false; } if (close) - _vm->_vidPlayer->closeVideo(); + _vm->_vidPlayer->primaryClose(); } } // End of namespace Gob diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 8a428b4d34..734996ddd5 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -18,6 +18,7 @@ MODULE_OBJS := \ goblin_v1.o \ goblin_v2.o \ goblin_v3.o \ + goblin_v4.o \ coktelvideo.o \ videoplayer.o \ init.o \ diff --git a/engines/gob/mult.h b/engines/gob/mult.h index 90f6e61f9a..9d43435184 100644 --- a/engines/gob/mult.h +++ b/engines/gob/mult.h @@ -36,7 +36,7 @@ public: #include "common/pack-start.h" // START STRUCT PACKING struct Mult_AnimData { - uint8 animation; + int8 animation; uint8 layer; uint8 frame; int8 animType; @@ -104,6 +104,7 @@ public: int16 newTop; int16 newRight; int16 newBottom; + uint32 videoSlot; } PACKED_STRUCT; struct Mult_StaticKey { diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index 37c360d53a..95617a704a 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -463,8 +463,7 @@ void Mult_v2::multSub(uint16 multIndex) { int obj = _multData->animObjs[index][i]; if ((obj != -1) && (obj != 1024)) - _objects[obj].pAnimData->animTypeBak = - _objects[obj].pAnimData->animType; + _objects[obj].pAnimData->animTypeBak = _objects[obj].pAnimData->animType; } } @@ -472,8 +471,10 @@ void Mult_v2::multSub(uint16 multIndex) { _multData->animKeysIndices[index][i] = 0; for (int j = 0; j < _multData->animKeysCount[i]; j++) - if (_multData->animKeys[i][j].frame == startFrame) + if (_multData->animKeys[i][j].frame >= startFrame) { _multData->animKeysIndices[index][i] = j; + break; + } } if (_multData->animDirection == -1) { @@ -487,6 +488,7 @@ void Mult_v2::multSub(uint16 multIndex) { 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; @@ -675,28 +677,54 @@ void Mult_v2::drawAnims(bool &stop) { // loc_50D5 void Mult_v2::newCycleAnim(Mult_Object &animObj) { Mult_AnimData &animData = *(animObj.pAnimData); - int nAnim = animData.animation; - int nLayer = animData.layer; + Scenery::AnimLayer *animLayer = 0; - if (_vm->_scenery->getAnimLayersCount(nAnim) <= nLayer) - return; + if (animData.animation >= 0) { + int nAnim = animData.animation, nLayer = animData.layer; + + if (_vm->_scenery->getAnimLayersCount(nAnim) <= nLayer) + return; - Scenery::AnimLayer *animLayer = _vm->_scenery->getAnimLayer(nAnim, nLayer); + animLayer = _vm->_scenery->getAnimLayer(nAnim, nLayer); + } if (animData.animType == 4) { + // loc_1E091 animData.frame = 0; animData.isPaused = 1; + if (animData.animation < 0) + warning("TODO: AnimType 4, animation: %d", animData.animation); + return; + } + + if (animData.animType == 12) + animData.animType = 11; + + if (animData.animType == 11) { + if (animData.isBusy != 0) { + warning("TODO: AnimType 11"); + } return; } if (animData.animType != 8) animData.frame++; - if (animData.frame < animLayer->framesCount) { - animData.newCycle = 0; - return; + if (animData.animation < 0) { + if ((animObj.videoSlot > 0) && + (_vm->_vidPlayer->getCurrentFrame(animObj.videoSlot - 1) < + _vm->_vidPlayer->getFramesCount(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; @@ -728,6 +756,12 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { 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; } animData.newCycle = 1; @@ -897,6 +931,9 @@ void Mult_v2::animate() { 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); @@ -1043,7 +1080,7 @@ void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir, x = y = -1; if (key.imdFile == -1) { - _vm->_vidPlayer->closeVideo(); + _vm->_vidPlayer->primaryClose(); _vm->_game->_preventScroll = false; return; } @@ -1061,11 +1098,11 @@ void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir, if ((lastFrame - palFrame) < startFrame) if (!(key.flags & 0x4000)) { _vm->_game->_preventScroll = false; - _vm->_vidPlayer->closeVideo(); + _vm->_vidPlayer->primaryClose(); return; } - if (!_vm->_vidPlayer->openVideo(imdFile, x, y, flags)) { + if (!_vm->_vidPlayer->primaryOpen(imdFile, x, y, flags)) { _vm->_game->_preventScroll = false; return; } @@ -1077,7 +1114,7 @@ void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir, lastFrame = _vm->_vidPlayer->getFramesCount() - 1; baseFrame = startFrame % (lastFrame - palFrame + 1); - _vm->_vidPlayer->play(baseFrame + palFrame, baseFrame + palFrame, 0, + _vm->_vidPlayer->primaryPlay(baseFrame + palFrame, baseFrame + palFrame, 0, flags & 0x7F, palStart, palEnd, palFrame, lastFrame); } diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index 5979927dfa..7338dab15b 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -33,6 +33,8 @@ #include "gob/draw.h" #include "gob/game.h" #include "gob/inter.h" +#include "gob/map.h" +#include "gob/videoplayer.h" namespace Gob { @@ -454,6 +456,7 @@ int16 Scenery::loadAnim(char search) { ptr->layers = new AnimLayer[ptr->layersCount]; ptr->pieces = new PieceDesc*[picsCount]; ptr->piecesFromExt = new bool[picsCount]; + ptr->sizes = new uint16[picsCount]; for (i = 0; i < ptr->layersCount; i++) { int16 offset = READ_LE_UINT16(dataPtr + i * 2); @@ -492,13 +495,19 @@ int16 Scenery::loadAnim(char search) { for (i = 0; i < picsCount; i++) { pictDescId = _vm->_inter->load16(); if (pictDescId >= 30000) { + uint32 size; + ptr->pieces[i] = - (PieceDesc *) _vm->_game->loadExtData(pictDescId, 0, 0); + (PieceDesc *) _vm->_game->loadExtData(pictDescId, 0, 0, &size); ptr->piecesFromExt[i] = true; + ptr->sizes[i] = size / 8; } else { + int16 size; + ptr->pieces[i] = - (PieceDesc *) _vm->_game->loadTotResource(pictDescId); + (PieceDesc *) _vm->_game->loadTotResource(pictDescId, &size); ptr->piecesFromExt[i] = false; + ptr->sizes[i] = size / 8; } width = _vm->_inter->load16(); @@ -561,6 +570,7 @@ void Scenery::freeAnim(int16 index) { delete[] _animations[index].layers; delete[] _animations[index].pieces; delete[] _animations[index].piecesFromExt; + delete[] _animations[index].sizes; _animPictCount[index] = 0; } @@ -592,6 +602,135 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, int16 destX; int16 destY; + if (animation < 0) { + // Object video + + if (flags & 1) { // Do capture + updateAnim(layer, frame, animation, 0, drawDeltaX, drawDeltaY, 0); + + if (_toRedrawLeft == -12345) + return; + + _vm->_game->capturePush(_toRedrawLeft, _toRedrawTop, + _toRedrawRight - _toRedrawLeft + 1, + _toRedrawBottom - _toRedrawTop + 1); + + *_pCaptureCounter = *_pCaptureCounter + 1; + } + + Mult::Mult_Object &obj = _vm->_mult->_objects[-animation - 1]; + + if (!_vm->_vidPlayer->slotIsOpen(obj.videoSlot - 1)) { + _toRedrawLeft = -1234; + return; + } + + // Seek to frame + while (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) <= frame) + _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); + + destX = 0; + destY = 0; + left = *(obj.pPosX); + top = *(obj.pPosY); + right = left + _vm->_vidPlayer->getWidth(obj.videoSlot - 1) - 1; + bottom = top + _vm->_vidPlayer->getHeight(obj.videoSlot - 1) - 1; + + if (flags & 2) { + if (left < _vm->_mult->_animLeft) { + destX += _vm->_mult->_animLeft - left; + left = _vm->_mult->_animLeft; + } + + if ((_vm->_mult->_animLeft + _vm->_mult->_animWidth) <= right) + right = _vm->_mult->_animLeft + _vm->_mult->_animWidth - 1; + + if (top < _vm->_mult->_animTop) { + destY += _vm->_mult->_animTop - top; + top = _vm->_mult->_animTop; + } + + if ((_vm->_mult->_animTop + _vm->_mult->_animHeight) <= bottom) + bottom = _vm->_mult->_animTop + _vm->_mult->_animHeight - 1; + + } else if (flags & 4) { + if (left < _toRedrawLeft) { + destX += _toRedrawLeft - left; + left = _toRedrawLeft; + } + + if (right > _toRedrawRight) + right = _toRedrawRight; + + if (top < _toRedrawTop) { + destY += _toRedrawTop - top; + top = _toRedrawTop; + } + + if (bottom > _toRedrawBottom) + bottom = _toRedrawBottom; + + } else { + _toRedrawTop = top; + _toRedrawLeft = left; + _toRedrawRight = right; + _toRedrawBottom = bottom; + } + + if (doDraw) { + if ((left > right) || (top > bottom)) + return; + + if (left < _vm->_mult->_animLeft) { + destX += _vm->_mult->_animLeft - left; + left = _vm->_mult->_animLeft; + } + + if ((_vm->_mult->_animLeft + _vm->_mult->_animWidth) <= right) + right = _vm->_mult->_animLeft + _vm->_mult->_animWidth - 1; + + if (top < _vm->_mult->_animTop) { + destY += _vm->_mult->_animTop - top; + top = _vm->_mult->_animTop; + } + + if ((_vm->_mult->_animTop + _vm->_mult->_animHeight) <= bottom) + bottom = _vm->_mult->_animTop + _vm->_mult->_animHeight - 1; + + _vm->_draw->_spriteLeft = destX; + _vm->_draw->_spriteTop = destY; + _vm->_draw->_spriteRight = right - left + 1; + _vm->_draw->_spriteBottom = bottom - top + 1; + _vm->_draw->_destSpriteX = left; + _vm->_draw->_destSpriteY = top; + _vm->_draw->_transparency = layer; + if (layer & 0x80) + _vm->_draw->_spriteLeft = _vm->_vidPlayer->getWidth(obj.videoSlot - 1) - + (destX + _vm->_draw->_spriteRight); + + _vm->_vidPlayer->slotCopyFrame(obj.videoSlot - 1, _vm->_draw->_backSurface->getVidMem(), + _vm->_draw->_spriteLeft, _vm->_draw->_spriteTop, + _vm->_draw->_spriteRight, _vm->_draw->_spriteBottom, + _vm->_draw->_destSpriteX, _vm->_draw->_destSpriteY, + _vm->_draw->_backSurface->getWidth(), + (_vm->_draw->_transparency != 0) ? 0 : -1); + + _vm->_draw->invalidateRect(_vm->_draw->_destSpriteX, _vm->_draw->_destSpriteY, + _vm->_draw->_destSpriteX + _vm->_draw->_spriteRight - 1, + _vm->_draw->_destSpriteY + _vm->_draw->_spriteBottom - 1); + + } + + if (flags & 4) { + _animLeft = _toRedrawLeft = left; + _animTop = _toRedrawTop = top; + _animRight = _toRedrawRight = right; + _animBottom = _toRedrawBottom = bottom; + } + + return; + } + if ((_animPictCount[animation] == 0) || (layer < 0)) return; if (layer >= _animations[animation].layersCount) @@ -670,6 +809,16 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, pictIndex = (pictIndex & 15) - 1; + if ((pictIndex == 0xFFFF) || (_animPictCount[animation] <= pictIndex)) { + warning("Scenery::updateAnim: pictIndex out of range"); + return; + } + + if (_animations[animation].sizes[pictIndex] <= pieceIndex) { + warning("Scenery::updateAnim: pieceIndex out of range"); + continue; + } + left = READ_LE_UINT16(&pictPtr[pictIndex][pieceIndex].left); right = READ_LE_UINT16(&pictPtr[pictIndex][pieceIndex].right); top = READ_LE_UINT16(&pictPtr[pictIndex][pieceIndex].top); diff --git a/engines/gob/scenery.h b/engines/gob/scenery.h index 290d67d2d5..a1a1304d4d 100644 --- a/engines/gob/scenery.h +++ b/engines/gob/scenery.h @@ -92,6 +92,7 @@ public: AnimLayer *layers; PieceDesc **pieces; bool *piecesFromExt; + uint16 *sizes; Animation() : layersCount(0), layers(0), pieces(0), piecesFromExt(0) {} }; diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index 6ca694c11a..7ed2fb044b 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -331,12 +331,12 @@ void Util::waitEndFrame() { void Util::setScrollOffset(int16 x, int16 y) { processInput(); - if(x >= 0) + if (x >= 0) _vm->_video->_scrollOffsetX = x; else _vm->_video->_scrollOffsetX = _vm->_draw->_scrollOffsetX; - if(y >= 0) + if (y >= 0) _vm->_video->_scrollOffsetY = y; else _vm->_video->_scrollOffsetY = _vm->_draw->_scrollOffsetY; diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index c3cecea318..25b80c89d9 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -32,29 +32,105 @@ #include "gob/game.h" #include "gob/palanim.h" #include "gob/inter.h" +#include "gob/map.h" namespace Gob { const char *VideoPlayer::_extensions[] = { "IMD", "VMD" }; -VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm) { - _curFile[0] = 0; - _stream = 0; +VideoPlayer::Video::Video(GobEngine *vm) : _vm(vm), _fileName(0), _stream(0), _video(0) { +} + +VideoPlayer::Video::~Video() { + close(); +} + +bool VideoPlayer::Video::open(const char *fileName, Type which) { + close(); + + int16 handle = _vm->_dataIO->openData(fileName); + + if (handle < 0) { + warning("Couldn't open video \"%s\": No such file", fileName); + return false; + } + + _stream = _vm->_dataIO->openAsStream(handle, true); + + if (which == kVideoTypeIMD) { + _video = new Imd(); + } else if (which == kVideoTypeVMD) { + _video = new Vmd(); + } else { + warning("Couldn't open video \"%s\": Invalid video Type", fileName); + close(); + return false; + } + + if (!_video->load(*_stream)) { + warning("While loading video \"%s\"", fileName); + close(); + return false; + } + + _fileName = new char[strlen(fileName) + 1]; + strcpy(_fileName, fileName); + + return true; +} + +void VideoPlayer::Video::close() { + delete _video; + delete _stream; + delete[] _fileName; + _video = 0; + _stream = 0; + _fileName = 0; + memset(&_state, 0, sizeof(CoktelVideo::State)); +} + +bool VideoPlayer::Video::isOpen() const { + return (_video != 0); +} + +const char *VideoPlayer::Video::getFileName() const { + return _fileName ? _fileName : ""; +} + +CoktelVideo *VideoPlayer::Video::getVideo() { + return _video; +} + +const CoktelVideo *VideoPlayer::Video::getVideo() const { + return _video; +} + +CoktelVideo::State VideoPlayer::Video::getState() const { + return _state; +} + +CoktelVideo::State VideoPlayer::Video::nextFrame() { + if (_video) + _state = _video->nextFrame(); + + return _state; +} + +VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm) { + _primaryVideo = new Video(vm); _backSurf = false; _needBlit = false; _noCursorSwitch = false; } VideoPlayer::~VideoPlayer() { - closeVideo(); + delete _primaryVideo; + for (uint i = 0; i < _videoSlots.size(); i++) + delete _videoSlots[i]; } -bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Type which) { - char fileName[256]; - - strncpy0(fileName, video, 250); - +bool VideoPlayer::findFile(char *fileName, Type &which) { char *extStart = strrchr(fileName, '.'); // There's no empty extension if (extStart == (fileName + strlen(fileName) - 1)) { @@ -112,33 +188,22 @@ bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Ty } - if (scumm_strnicmp(_curFile, fileName, strlen(fileName))) { - closeVideo(); + return true; +} - int16 handle = _vm->_dataIO->openData(fileName); +bool VideoPlayer::primaryOpen(const char *videoFile, int16 x, int16 y, + int16 flags, Type which) { - if (handle < 0) { - warning("Couldn't open video \"%s\": No such file", fileName); - return false; - } + char fileName[256]; - _stream = _vm->_dataIO->openAsStream(handle, true); + strncpy0(fileName, videoFile, 250); - if (which == kVideoTypeIMD) { - _video = new Imd(); - } else if (which == kVideoTypeVMD) { - _video = new Vmd(); - } else { - warning("Couldn't open video \"%s\": Invalid video Type", fileName); - closeVideo(); - return false; - } + if (!findFile(fileName, which)) + return false; - if (!_video->load(*_stream)) { - warning("While loading video \"%s\"", fileName); - closeVideo(); + if (scumm_strnicmp(_primaryVideo->getFileName(), fileName, strlen(fileName))) { + if (!_primaryVideo->open(fileName, which)) return false; - } // WORKAROUND: In some rare cases, the cursor should still be // displayed while a video is playing. @@ -153,53 +218,54 @@ bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Ty _noCursorSwitch = true; } - strcpy(_curFile, fileName); - if (!(flags & kFlagNoVideo)) { _backSurf = ((flags & kFlagFrontSurface) == 0); SurfaceDesc::Ptr surf = _vm->_draw->_spritesArray[_backSurf ? 21 : 20]; - _video->setVideoMemory(surf->getVidMem(), surf->getWidth(), surf->getHeight()); + _primaryVideo->getVideo()->setVideoMemory(surf->getVidMem(), + surf->getWidth(), surf->getHeight()); } else - _video->setVideoMemory(); + _primaryVideo->getVideo()->setVideoMemory(); _needBlit = ((flags & kFlagUseBackSurfaceContent) != 0) && ((flags & kFlagFrontSurface) != 0); - _video->enableSound(*_vm->_mixer); + _primaryVideo->getVideo()->enableSound(*_vm->_mixer); } - if (!_video) + if (!_primaryVideo->isOpen()) return false; - _video->setFrameRate(_vm->_util->getFrameRate()); - _video->setXY(x, y); - WRITE_VAR(7, _video->getFramesCount()); + _primaryVideo->getVideo()->setFrameRate(_vm->_util->getFrameRate()); + _primaryVideo->getVideo()->setXY(x, y); + WRITE_VAR(7, _primaryVideo->getVideo()->getFramesCount()); return true; } -void VideoPlayer::play(int16 startFrame, int16 lastFrame, int16 breakKey, +void VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, int16 palFrame, int16 endFrame, bool fade, int16 reverseTo) { - if (!_video) + if (!_primaryVideo->isOpen()) return; + CoktelVideo &video = *(_primaryVideo->getVideo()); + breakKey = 27; if (startFrame < 0) - startFrame = _video->getCurrentFrame(); + startFrame = video.getCurrentFrame(); if (lastFrame < 0) - lastFrame = _video->getFramesCount() - 1; + lastFrame = video.getFramesCount() - 1; if (palFrame < 0) palFrame = startFrame; if (endFrame < 0) endFrame = lastFrame; palCmd &= 0x3F; - if (_video->getCurrentFrame() != startFrame) { - if (_video->getFeatures() & CoktelVideo::kFeaturesSound) - startFrame = _video->getCurrentFrame(); + if (video.getCurrentFrame() != startFrame) { + if (video.getFeatures() & CoktelVideo::kFeaturesSound) + startFrame = video.getCurrentFrame(); else - _video->seekFrame(startFrame); + video.seekFrame(startFrame); } _vm->_draw->_showCursor = _noCursorSwitch ? 3 : 0; @@ -217,36 +283,156 @@ void VideoPlayer::play(int16 startFrame, int16 lastFrame, int16 breakKey, } if (!_noCursorSwitch) - _video->waitEndFrame(); + video.waitEndFrame(); startFrame++; } if (reverseTo >= 0) { - int16 toFrame = _video->getFramesCount() - reverseTo; - for (int i = _video->getCurrentFrame(); i >= toFrame; i--) { - _video->seekFrame(i, SEEK_SET, true); + int16 toFrame = video.getFramesCount() - reverseTo; + for (int i = video.getCurrentFrame(); i >= toFrame; i--) { + video.seekFrame(i, SEEK_SET, true); if (doPlay(i, breakKey, 0, 0, 0, 0, 0)) { _vm->_palAnim->fade(0, -2, 0); memset((char *) _vm->_draw->_vgaPalette, 0, 768); } if (!_noCursorSwitch) - _video->waitEndFrame(); + video.waitEndFrame(); } } } -int16 VideoPlayer::getFramesCount() const { - if (!_video) - return 0; +void VideoPlayer::primaryClose() { + _primaryVideo->close(); +} + +int VideoPlayer::slotOpen(const char *videoFile, Type which) { + Video *video = new Video(_vm); + char fileName[256]; + + strncpy0(fileName, videoFile, 250); + + if (!findFile(fileName, which)) { + delete video; + return -1; + } + + if (!video->open(fileName, which)) { + delete video; + return -1; + } + + video->getVideo()->setVideoMemory(); + video->getVideo()->disableSound(); + + _videoSlots.push_back(video); + + WRITE_VAR(7, video->getVideo()->getFramesCount()); + + return _videoSlots.size() - 1; +} + +void VideoPlayer::slotPlay(int slot, int16 frame) { + if ((slot < 0) || (((uint) slot) >= _videoSlots.size())) + return; + + CoktelVideo &video = *(_videoSlots[slot]->getVideo()); + + if (frame < 0) + frame = video.getCurrentFrame(); + + if (video.getCurrentFrame() != frame) + video.seekFrame(frame); + + _videoSlots[slot]->nextFrame(); + WRITE_VAR(11, frame); +} + +void VideoPlayer::slotClose(int slot) { + if ((slot < 0) || (((uint) slot) >= _videoSlots.size())) + return; + + delete _videoSlots[slot]; + _videoSlots.remove_at(slot); +} + +void VideoPlayer::slotCopyFrame(int slot, byte *dest, + uint16 left, uint16 top, uint16 width, uint16 height, + uint16 x, uint16 y, uint16 pitch, int16 transp) { + + if ((slot < 0) || (((uint) slot) >= _videoSlots.size())) + return; + + _videoSlots[slot]->getVideo()->copyCurrentFrame(dest, + left, top, width, height, x, y, pitch, transp); +} + +void VideoPlayer::slotCopyPalette(int slot, int16 palStart, int16 palEnd) { + if ((slot < 0) || (((uint) slot) >= _videoSlots.size())) + return; + + copyPalette(*(_videoSlots[slot]->getVideo()), palStart, palEnd); +} + +bool VideoPlayer::slotIsOpen(int slot) const { + if ((slot >= 0) && (((uint) slot) < _videoSlots.size())) + return true; + + return false; +} + +const VideoPlayer::Video *VideoPlayer::getVideoBySlot(int slot) const { + if (slot < 0) { + if (_primaryVideo->isOpen()) + return _primaryVideo; + } else if (((uint) slot) < _videoSlots.size()) + return _videoSlots[slot]; + + return 0; +} + +uint16 VideoPlayer::getFlags(int slot) const { + const Video *video = getVideoBySlot(slot); + + if (video) + return video->getVideo()->getFlags(); + + return 0; +} + +int16 VideoPlayer::getFramesCount(int slot) const { + const Video *video = getVideoBySlot(slot); + + if (video) + return video->getVideo()->getFramesCount(); + + return 0; +} + +int16 VideoPlayer::getCurrentFrame(int slot) const { + const Video *video = getVideoBySlot(slot); + + if (video) + return video->getVideo()->getCurrentFrame(); + + return 0; +} + +int16 VideoPlayer::getWidth(int slot) const { + const Video *video = getVideoBySlot(slot); - return _video->getFramesCount(); + if (video) + return video->getVideo()->getWidth(); + + return 0; } -int16 VideoPlayer::getCurrentFrame() const { - if (!_video) - return 0; +int16 VideoPlayer::getHeight(int slot) const { + const Video *video = getVideoBySlot(slot); + + if (video) + return video->getVideo()->getHeight(); - return _video->getCurrentFrame(); + return 0; } bool VideoPlayer::doPlay(int16 frame, int16 breakKey, @@ -260,7 +446,7 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, _vm->_draw->_applyPal = true; if (palCmd >= 4) - copyPalette(palStart, palEnd); + copyPalette(*(_primaryVideo->getVideo()), palStart, palEnd); } if (modifiedPal && (palCmd == 8) && !_backSurf) @@ -270,7 +456,7 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, if (_needBlit) _vm->_draw->forceBlit(); - CoktelVideo::State state = _video->nextFrame(); + CoktelVideo::State state = _primaryVideo->nextFrame(); WRITE_VAR(11, frame); if (_needBlit) @@ -285,7 +471,7 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, } if (state.flags & CoktelVideo::kStatePalette) { - copyPalette(palStart, palEnd); + copyPalette(*(_primaryVideo->getVideo()), palStart, palEnd); if (!_backSurf) _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); @@ -311,7 +497,7 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, _vm->_util->processInput(); if (_vm->_quitRequested) { - _video->disableSound(); + _primaryVideo->getVideo()->disableSound(); return true; } @@ -321,7 +507,7 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, _vm->_inter->storeKey(_vm->_util->checkKey()); if (VAR(0) == (unsigned) breakKey) { - _video->disableSound(); + _primaryVideo->getVideo()->disableSound(); return true; } } @@ -329,26 +515,37 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, return false; } -void VideoPlayer::copyPalette(int16 palStart, int16 palEnd) { - if ((palStart == -1) || (palEnd == -1)) - memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, - _video->getPalette(), 768); - else - memcpy(((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + - palStart * 3, _video->getPalette() + palStart * 3, +void VideoPlayer::copyPalette(CoktelVideo &video, int16 palStart, int16 palEnd) { + if ((palStart != -1) && (palEnd != -1)) + memcpy(((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + palStart * 3, + video.getPalette() + palStart * 3, (palEnd - palStart + 1) * 3); + else + memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, video.getPalette(), 768); } -void VideoPlayer::writeVideoInfo(const char *video, int16 varX, int16 varY, +void VideoPlayer::writeVideoInfo(const char *videoFile, int16 varX, int16 varY, int16 varFrames, int16 varWidth, int16 varHeight) { - if (openVideo(video)) { - WRITE_VAR_OFFSET(varX, _video->getX()); - WRITE_VAR_OFFSET(varY, _video->getY()); - WRITE_VAR_OFFSET(varFrames, _video->getFramesCount()); - WRITE_VAR_OFFSET(varWidth, _video->getWidth()); - WRITE_VAR_OFFSET(varHeight, _video->getHeight()); - closeVideo(); + if (primaryOpen(videoFile)) { + int16 x, y, width, height; + + if ((VAR_OFFSET(varX) != 0xFFFFFFFF) || + !_primaryVideo->getVideo()->getAnchor(1, 2, x, y, width, height)) { + + x = _primaryVideo->getVideo()->getX(); + y = _primaryVideo->getVideo()->getY(); + width = _primaryVideo->getVideo()->getWidth(); + height = _primaryVideo->getVideo()->getHeight(); + } + + WRITE_VAR_OFFSET(varX, x); + WRITE_VAR_OFFSET(varY, y); + WRITE_VAR_OFFSET(varFrames, _primaryVideo->getVideo()->getFramesCount()); + WRITE_VAR_OFFSET(varWidth, width); + WRITE_VAR_OFFSET(varHeight, height); + + primaryClose(); } else { WRITE_VAR_OFFSET(varX, -1); WRITE_VAR_OFFSET(varY, -1); @@ -358,13 +555,4 @@ void VideoPlayer::writeVideoInfo(const char *video, int16 varX, int16 varY, } } -void VideoPlayer::closeVideo() { - delete _video; - delete _stream; - - _video = 0; - _stream = 0; - *_curFile = 0; -} - } // End of namespace Gob diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h index 7b9a3ca687..3a6ec0d9da 100644 --- a/engines/gob/videoplayer.h +++ b/engines/gob/videoplayer.h @@ -26,6 +26,8 @@ #ifndef GOB_VIDEOPLAYER_H #define GOB_VIDEOPLAYER_H +#include "common/array.h" + #include "gob/coktelvideo.h" #include "gob/dataio.h" @@ -51,34 +53,75 @@ public: VideoPlayer(GobEngine *vm); ~VideoPlayer(); - bool openVideo(const char *video, int16 x = -1, int16 y = -1, + bool primaryOpen(const char *videoFile, int16 x = -1, int16 y = -1, int16 flags = kFlagFrontSurface, Type which = kVideoTypeTry); - - void play(int16 startFrame = -1, int16 lastFrame = -1, int16 breakKey = 27, + void primaryPlay(int16 startFrame = -1, int16 lastFrame = -1, int16 breakKey = 27, uint16 palCmd = 8, int16 palStart = 0, int16 palEnd = 255, int16 palFrame = -1, int16 endFrame = -1, bool fade = false, int16 reverseTo = -1); + void primaryClose(); - int16 getFramesCount() const; - int16 getCurrentFrame() const; - void writeVideoInfo(const char *video, int16 varX, int16 varY, - int16 varFrames, int16 varWidth, int16 varHeight); + int slotOpen(const char *videoFile, Type which = kVideoTypeTry); + void slotPlay(int slot, int16 frame = -1); + void slotClose(int slot); + void slotCopyFrame(int slot, byte *dest, + uint16 left, uint16 top, uint16 width, uint16 height, + uint16 x, uint16 y, uint16 pitch, int16 transp = -1); + void slotCopyPalette(int slot, int16 palStart = -1, int16 palEnd = -1); + + bool slotIsOpen(int slot) const; - void closeVideo(); + uint16 getFlags(int slot = -1) const; + int16 getFramesCount(int slot = -1) const; + int16 getCurrentFrame(int slot = -1) const; + int16 getWidth(int slot = -1) const; + int16 getHeight(int slot = -1) const; + + void writeVideoInfo(const char *videoFile, int16 varX, int16 varY, + int16 varFrames, int16 varWidth, int16 varHeight); private: + class Video { + public: + Video(GobEngine *vm); + ~Video(); + + bool open(const char *fileName, Type which); + void close(); + + bool isOpen() const; + + const char *getFileName() const; + CoktelVideo *getVideo(); + const CoktelVideo *getVideo() const; + CoktelVideo::State getState() const; + + CoktelVideo::State nextFrame(); + + private: + GobEngine *_vm; + + char *_fileName; + DataStream *_stream; + CoktelVideo *_video; + CoktelVideo::State _state; + }; + static const char *_extensions[]; GobEngine *_vm; - char _curFile[256]; - DataStream *_stream; - CoktelVideo *_video; + Common::Array<Video *> _videoSlots; + Video *_primaryVideo; bool _backSurf; bool _needBlit; bool _noCursorSwitch; - void copyPalette(int16 palStart = -1, int16 palEnd = -1); + bool findFile(char *fileName, Type &which); + + const Video *getVideoBySlot(int slot = -1) const; + + void copyPalette(CoktelVideo &video, int16 palStart = -1, int16 palEnd = -1); bool doPlay(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, int16 palFrame, int16 endFrame); |