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
This commit is contained in:
Sven Hesse 2008-04-27 03:19:19 +00:00
parent 1d167da633
commit ab1a3b0cc8
18 changed files with 1355 additions and 197 deletions

View file

@ -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

View file

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

View file

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

View file

@ -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

View file

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

635
engines/gob/goblin_v4.cpp Normal file
View file

@ -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

View file

@ -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();

View file

@ -717,16 +717,16 @@ const char *Inter_Bargon::getOpcodeGoblinDesc(int i) {
}
void Inter_Bargon::oBargon_intro0(OpGobParams &params) {
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 &params) {
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 &params) {
}
void Inter_Bargon::oBargon_intro4(OpGobParams &params) {
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 &params) {
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 &params) {
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 &params) {
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 &params) {
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 &params) {
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();
}
}

View file

@ -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() {

View file

@ -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

View file

@ -18,6 +18,7 @@ MODULE_OBJS := \
goblin_v1.o \
goblin_v2.o \
goblin_v3.o \
goblin_v4.o \
coktelvideo.o \
videoplayer.o \
init.o \

View file

@ -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 {

View file

@ -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,27 +677,53 @@ 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 (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.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:
@ -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);
}

View file

@ -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);

View file

@ -92,6 +92,7 @@ public:
AnimLayer *layers;
PieceDesc **pieces;
bool *piecesFromExt;
uint16 *sizes;
Animation() : layersCount(0), layers(0), pieces(0),
piecesFromExt(0) {}
};

View file

@ -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();
int16 handle = _vm->_dataIO->openData(fileName);
if (handle < 0) {
warning("Couldn't open video \"%s\": No such file", fileName);
return false;
return true;
}
_stream = _vm->_dataIO->openAsStream(handle, true);
bool VideoPlayer::primaryOpen(const char *videoFile, int16 x, int16 y,
int16 flags, Type which) {
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;
}
char fileName[256];
if (!_video->load(*_stream)) {
warning("While loading video \"%s\"", fileName);
closeVideo();
strncpy0(fileName, videoFile, 250);
if (!findFile(fileName, which))
return false;
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)
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;
return _video->getFramesCount();
}
int16 VideoPlayer::getCurrentFrame() const {
if (!_video)
return 0;
uint16 VideoPlayer::getFlags(int slot) const {
const Video *video = getVideoBySlot(slot);
return _video->getCurrentFrame();
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);
if (video)
return video->getVideo()->getWidth();
return 0;
}
int16 VideoPlayer::getHeight(int slot) const {
const Video *video = getVideoBySlot(slot);
if (video)
return video->getVideo()->getHeight();
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

View file

@ -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,
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;
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);
void closeVideo();
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);