Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,624 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef ENABLE_EOB
#include "kyra/engine/eob.h"
#include "kyra/graphics/screen_eob.h"
#include "kyra/graphics/screen_eob_segacd.h"
#include "kyra/resource/resource.h"
#include "kyra/resource/resource_segacd.h"
#include "kyra/sequence/seqplayer_eob_segacd.h"
#include "common/system.h"
namespace Kyra {
SegaSequencePlayer::SegaSequencePlayer(EoBEngine *vm, Screen_EoB *screen, SegaCDResource *res) : _vm(vm), _screen(screen), _res(res), _tileSets(0), _debugResyncCnt(0), _speechAnimType(0),
_playingID(1), _waterdeepScene(0), _playSpeechAnimation(0), _frameTimer(0), _waterdeepSceneTimer(0), _speechAnimTimer(0), _speechAnimNo(0), _speechAnimFrame(0),
_newTrack(-1), _pauseStart(0), _fastForward(false), _renderer(_screen->sega_getRenderer()), _animator(_screen->sega_getAnimator()) {
#define SQOPC(x) _opcodes.push_back(new SQOpcode(this, &SegaSequencePlayer::x, #x))
SQOPC(s_initDrawObject);
SQOPC(s_drawTileSet);
SQOPC(s_loadTileDataSingle);
SQOPC(s_drawTileSetCustom);
SQOPC(s_drawTileSetCustomTopToBottom);
SQOPC(s_fillRect);
SQOPC(s_void);
SQOPC(s_initSprite);
SQOPC(s_removeSprite);
SQOPC(s_displayTextJp);
SQOPC(s_fadeToNeutral);
SQOPC(s_fadeToBlack);
SQOPC(s_fadeToNeutral2);
SQOPC(s_fadeToWhite);
SQOPC(s_setPalette);
SQOPC(s_vScroll);
SQOPC(s_hScroll);
SQOPC(s_paletteOps);
SQOPC(s_initSpriteCustomCoords);
SQOPC(s_fillRectWithPattern);
SQOPC(s_loadTileDataSeries);
SQOPC(s_drawTileSetSeries);
SQOPC(s_initSpriteSeries);
SQOPC(s_initSpriteCustom);
SQOPC(s_drawTileSetCustomCoords);
SQOPC(s_waitForPaletteFade);
SQOPC(s_clearSprites);
SQOPC(s_moveSprites2);
SQOPC(s_moveSprites);
SQOPC(s_moveMorphSprite);
SQOPC(s_unpauseCD);
SQOPC(s_toggleWaterDeepAnimations);
SQOPC(s_assignSpeechAnimGraphics);
SQOPC(s_toggleSpeechAnimation);
SQOPC(s_orbZoomEffect);
SQOPC(s_stopCD);
SQOPC(s_playCD);
SQOPC(s_displayTextEn);
SQOPC(s_loadCustomPalettes);
SQOPC(s_playSoundEffect);
#undef SQOPC
_scrollManager = new ScrollManager(_renderer);
assert(_scrollManager);
_tileSets = new TileSet[100]();
assert(_tileSets);
_drawObjects = new DrawObject[100]();
assert(_drawObjects);
memset(_speechAnimDrawOps, 0, sizeof(_speechAnimDrawOps));
_scaleSrcBuffer = new uint8[0x5800]();
assert(_scaleSrcBuffer);
_scaleOutBuffer = new uint8[0x5800]();
assert(_scaleOutBuffer);
_scaleStampMap = new uint16[0x100]();
assert(_scaleStampMap);
_scaleTraceVectors = new uint16[0x580]();
assert(_scaleTraceVectors);
int temp;
_wdDsX = _vm->staticres()->loadRawDataBe16(kEoB1IntroWdDsX, temp);
_wdDsY = _vm->staticres()->loadRawData(kEoB1IntroWdDsY, temp);
_wdAnimSprites = _vm->staticres()->loadRawData(kEoB1WdAnimSprites, temp);
_speechAnimData = _vm->staticres()->loadRawData(kEoB1SpeechAnimData, temp);
_cdaTracks = _vm->staticres()->loadRawData(kEoB1SequenceTrackMap, temp);
for (int i = 0; i < 6; ++i)
_patternTables[i] = _vm->staticres()->loadRawDataBe16(kEoB1PatternTable0 + i, temp);
}
SegaSequencePlayer::~SegaSequencePlayer() {
delete[] _drawObjects;
delete[] _tileSets;
delete[] _scaleSrcBuffer;
delete[] _scaleOutBuffer;
delete[] _scaleStampMap;
delete[] _scaleTraceVectors;
for (Common::Array<SQOpcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
delete (*i);
delete _scrollManager;
}
bool SegaSequencePlayer::play(int id) {
_renderer->render(0);
_screen->sega_fadeToBlack(2);
_screen->clearPage(0);
_animator->clearSprites();
_scrollManager->setVScrollTimers(0, 1, 0, 0, 1, 0);
_scrollManager->setHScrollTimers(0, 1, 0, 0, 1, 0);
_vm->_txt->clearDim(2);
_renderer->fillRectWithTiles(2, 0, 0, 40, 28, 0xE6C2);
_renderer->fillRectWithTiles(0, 0, 0, 64, 42, 0);
_renderer->fillRectWithTiles(1, 0, 0, 64, 28, 0);
_renderer->fillRectWithTiles(2, 1, (id == 53 || id == 54) ? 22 : 20, 38, 6, 0xE51C, true);
_debugResyncCnt = 0;
_playingID = id;
_newTrack = -1;
_vm->_allowSkip = true;
_vm->resetSkipFlag();
for (bool runLoop = true; runLoop && !(_vm->shouldQuit() || _vm->skipFlag()); ) {
uint32 offset = (id - 1) * 0x3C000;
if (id >= 54)
offset -= 0x8000;
if (id >= 55)
offset -= 0x18000;
uint32 size = (id == 53) ? 0x34000 : ((id == 54) ? 0x24000 : 0x3C000);
if (!_res->loadContainer("VISUAL", offset, size))
return false;
Common::SeekableReadStreamEndian *in = _res->resStreamEndian(0);
if (!in)
return false;
_screen->sega_loadCustomPaletteData(in);
delete in;
_screen->sega_selectPalette(31, 0, false);
_screen->sega_selectPalette(32, 1, false);
_screen->sega_selectPalette(30, 3, false);
in = _res->resStreamEndian(2);
if (!in)
return false;
uint32 len = in->size();
uint8 *tileData = new uint8[len];
in->read(tileData, len);
delete in;
in = _res->resStreamEndian(1);
if (!in)
return false;
memset(_tileSets, 0, 100 * sizeof(TileSet));
for (TileSet *t = _tileSets; !in->eos(); ++t) {
uint32 off = in->readUint32();
if ((off & 0xFFFF) == 0xFFFF)
break;
t->data = (const uint16*)(tileData + off);
t->width = in->readUint16();
t->height = in->readUint16();
}
delete in;
in = _res->resStreamEndian(3);
if (!in)
return false;
len = in->size();
uint8 *frames = new uint8[len];
in->read(frames, len);
delete in;
if (id == 53)
_vm->delay(2000);
else if (id == 55 || id == 56)
_vm->snd_playSong(2);
run(frames);
delete[] frames;
delete[] tileData;
if (++id != 54)
runLoop = false;
}
debugC(3, kDebugLevelSequence, "Total millis out of sync: %d", _debugResyncCnt);
if (_vm->shouldQuit() || _vm->skipFlag()) {
if (!(_playingID == 55 || _playingID == 56))
_vm->snd_stopSound();
}
_vm->_allowSkip = false;
_vm->resetSkipFlag();
_playingID = 1;
return true;
}
void SegaSequencePlayer::pause(bool togglePause) {
if (togglePause)
_pauseStart = _vm->_system->getMillis();
else
_frameTimer += (_vm->_system->getMillis() - _pauseStart);
}
void SegaSequencePlayer::run(const uint8 *data) {
_waterdeepScene = _playSpeechAnimation = false;
_frameTimer = _vm->_system->getMillis();
_fastForward = false;
for (bool runLoop = true; runLoop; ) {
// In case of a skip or shouldQuit event we fastforward through the sequence instead of just aborting. This way
// we ensure that we have the same palettes and scroll offsets as if the sequence had been played normally.
_fastForward = _vm->shouldQuit() || _vm->skipFlag();
uint16 frameSize = READ_BE_UINT16(data);
if (!frameSize)
return;
uint32 frameStart = _vm->_system->getMillis();
uint16 timeStamp = READ_BE_UINT16(data + 2);
uint32 nextFrame = _frameTimer + (timeStamp * 16667) / 1000;
bool insertDelay = false;
if (_vm->_system->getMillis() >= nextFrame || _fastForward) {
debugC(5, kDebugLevelSequence, "SeqPlayer: Timestamp %08d", timeStamp);
for (uint16 timeStamp2 = timeStamp; timeStamp2 == timeStamp; ) {
uint16 op = READ_BE_UINT16(data + 4);
_opcodes[op]->run(data + 6);
_screen->clearPage(0);
frameSize = READ_BE_UINT16(data);
data += (frameSize & ~1);
timeStamp2 = READ_BE_UINT16(data + 2);
}
} else {
insertDelay = true;
}
if (_waterdeepScene)
animateWaterdeepScene();
if (_playSpeechAnimation)
updateSpeechAnimations();
_animator->update();
if (_fastForward) {
_scrollManager->fastForward();
} else {
_scrollManager->updateScrollTimers();
_renderer->render(0);
_screen->sega_updatePaletteFaders(-1);
_screen->updateScreen();
}
if (insertDelay) {
int diff = _vm->_system->getMillis() - (frameStart + 16);
if (diff < 0)
_vm->delay((uint32)-diff);
}
}
}
void SegaSequencePlayer::animateWaterdeepScene() {
if (--_waterdeepSceneTimer > 0)
return;
_waterdeepSceneTimer = 5;
for (int i = 0; i < 5; ++i) {
int rnd = _vm->_rnd.getRandomNumber(30);
DrawObject *d = &_drawObjects[10 + rnd];
_animator->initSprite(_wdAnimSprites[rnd] + 3, _wdDsX[_wdAnimSprites[rnd]] - 80, _wdDsY[_wdAnimSprites[rnd]] + 32, d->nTblVal, d->addr);
}
}
void SegaSequencePlayer::updateSpeechAnimations() {
if (--_speechAnimTimer > 0)
return;
int animDrawOp = -1;
for (bool runLoop = true; runLoop; ) {
if (_speechAnimTimer == 0) {
const uint8 *pos = &_speechAnimData[_speechAnimNo * 12 + _speechAnimFrame];
_speechAnimTimer = pos[1];
if (pos[0] != 0xFF) {
animDrawOp = pos[0];
runLoop = false;
}
_speechAnimFrame += 2;
} else {
_speechAnimTimer = 0;
}
if (animDrawOp == -1) {
_speechAnimNo = (_speechAnimType == 2) ? _vm->_rnd.getRandomNumberRng(4, 6) : _vm->_rnd.getRandomNumberRng(0, 3);
_speechAnimFrame = 0;
}
}
updateSpeechAnimGraphics(animDrawOp);
}
void SegaSequencePlayer::updateSpeechAnimGraphics(int animDrawOp) {
assert(animDrawOp < 6);
DrawObject *d = &_drawObjects[_speechAnimDrawOps[animDrawOp * 2]];
if (_speechAnimDrawOps[animDrawOp * 2 + 1])
_renderer->loadToVRAM(d->tileData, (d->width * d->height) << 5, (d->nTblVal & 0x7FF) << 5);
else
_renderer->fillRectWithTiles(d->addr, d->x, d->y, d->width, d->height, d->nTblVal, true);
}
#define ARG(x) READ_BE_UINT16(pos + x)
#define S_ARG(x) (int16)ARG(x)
void SegaSequencePlayer::s_initDrawObject(const uint8 *pos) {
int idx = ARG(0);
DrawObject *w = &_drawObjects[idx];
TileSet *t = &_tileSets[idx];
w->agg = ARG(2);
w->tileData = t->data;
w->width = t->width;
w->height = t->height;
w->nTblVal = ARG(4) == 0xFFFF ? _drawObjects[idx - 1].width * _drawObjects[idx - 1].height + _drawObjects[idx - 1].nTblVal : (ARG(4) == 0xFFFE ? _drawObjects[idx - 1].nTblVal : ARG(4));
w->x = ARG(6);
w->y = ARG(8);
w->addr = ARG(10);
}
void SegaSequencePlayer::s_drawTileSet(const uint8 *pos) {
DrawObject *w = &_drawObjects[ARG(0)];
_renderer->fillRectWithTiles(w->addr, w->x, w->y, w->width, w->height, w->nTblVal, true);
}
void SegaSequencePlayer::s_loadTileDataSingle(const uint8 *pos) {
DrawObject *w = &_drawObjects[ARG(0)];
_renderer->loadToVRAM(w->tileData, (w->width * w-> height) << 5, (w->nTblVal & 0x7FF) << 5);
}
void SegaSequencePlayer::s_drawTileSetCustom(const uint8 *pos) {
_renderer->fillRectWithTiles(ARG(8), ARG(0), ARG(2), ARG(4), ARG(6), ARG(10), true);
}
void SegaSequencePlayer::s_drawTileSetCustomTopToBottom(const uint8 *pos) {
_renderer->fillRectWithTiles(ARG(8), ARG(0), ARG(2), ARG(4), ARG(6), ARG(10), true, true);
}
void SegaSequencePlayer::s_fillRect(const uint8 *pos) {
_renderer->fillRectWithTiles(ARG(8), ARG(0), ARG(2), ARG(4), ARG(6), ARG(10));
}
void SegaSequencePlayer::s_initSprite(const uint8 *pos) {
DrawObject *d = &_drawObjects[ARG(2)];
_animator->initSprite(ARG(0), d->x << 3, d->y << 3, d->nTblVal, d->addr);
}
void SegaSequencePlayer::s_removeSprite(const uint8 *pos) {
_animator->initSprite(ARG(0), 0x4000, 0, 0, 0);
}
void SegaSequencePlayer::s_displayTextJp(const uint8 *pos) {
if (_vm->gameFlags().lang != Common::JA_JPN)
return;
const char *str = (const char*)pos;
_vm->_txt->clearDim(2);
int w = _screen->getTextWidth(str);
int x = 0;
int y = 0;
if (w < 288) {
x = 152 - (w >> 1);
y = 16;
}
_vm->_txt->printShadedText(str, x, y, -1, 0xEE);
}
void SegaSequencePlayer::s_fadeToNeutral(const uint8 *pos) {
_screen->sega_fadeToNeutral(ARG(0));
}
void SegaSequencePlayer::s_fadeToBlack(const uint8 *pos) {
_screen->sega_fadeToBlack(ARG(0));
}
void SegaSequencePlayer::s_fadeToNeutral2(const uint8 *pos) {
_screen->sega_fadeToNeutral(ARG(0));
}
void SegaSequencePlayer::s_fadeToWhite(const uint8 *pos) {
_screen->sega_fadeToWhite(ARG(0));
}
void SegaSequencePlayer::s_setPalette(const uint8 *pos) {
_screen->sega_selectPalette(ARG(2) + 31, ARG(0), false);
}
void SegaSequencePlayer::s_vScroll(const uint8 *pos) {
_scrollManager->setVScrollTimers(ARG(0), S_ARG(2), ARG(4), ARG(6), S_ARG(8), ARG(10));
}
void SegaSequencePlayer::s_hScroll(const uint8 *pos) {
_scrollManager->setHScrollTimers(ARG(0), S_ARG(2), ARG(4), ARG(6), S_ARG(8), ARG(10));
}
void SegaSequencePlayer::s_paletteOps(const uint8 *pos) {
_screen->sega_paletteOps(S_ARG(0), S_ARG(2), S_ARG(4));
}
void SegaSequencePlayer::s_initSpriteCustomCoords(const uint8 *pos) {
DrawObject *d = &_drawObjects[ARG(2)];
_animator->initSprite(ARG(0), S_ARG(4), S_ARG(6), d->nTblVal, d->addr);
}
void SegaSequencePlayer::s_fillRectWithPattern(const uint8 *pos) {
assert(ARG(12) < 6);
_renderer->fillRectWithTiles(ARG(8), ARG(0), ARG(2), ARG(4), ARG(6), ARG(10), false, false, _patternTables[ARG(12)]);
}
void SegaSequencePlayer::s_loadTileDataSeries(const uint8 *pos) {
for (DrawObject *d = &_drawObjects[ARG(0)]; d != &_drawObjects[ARG(0) + ARG(2)]; ++d)
_renderer->loadToVRAM(d->tileData, (d->width * d->height) << 5, (d->nTblVal & 0x7FF) << 5);
}
void SegaSequencePlayer::s_drawTileSetSeries(const uint8 *pos) {
for (DrawObject *d = &_drawObjects[ARG(0)]; d != &_drawObjects[ARG(0) + ARG(2)]; ++d)
_renderer->fillRectWithTiles(d->addr, d->x, d->y, d->width, d->height, d->nTblVal, true);
}
void SegaSequencePlayer::s_initSpriteSeries(const uint8 *pos) {
int id = ARG(0);
for (DrawObject *d = &_drawObjects[ARG(2)]; d != &_drawObjects[ARG(2) + ARG(4)]; ++d)
_animator->initSprite(id++, d->x << 3, d->y << 3, d->nTblVal, d->addr);
}
void SegaSequencePlayer::s_initSpriteCustom(const uint8 *pos) {
_animator->initSprite(ARG(0), S_ARG(4), S_ARG(6), ARG(2), ARG(8));
}
void SegaSequencePlayer::s_drawTileSetCustomCoords(const uint8 *pos) {
DrawObject *w = &_drawObjects[ARG(0)];
_renderer->fillRectWithTiles(w->addr, ARG(2), ARG(4), w->width, w->height, w->nTblVal, true);
}
void SegaSequencePlayer::s_waitForPaletteFade(const uint8*) {
_screen->sega_fadePalette(0, 0, -1, true, true);
}
void SegaSequencePlayer::s_clearSprites(const uint8*) {
_animator->clearSprites();
}
void SegaSequencePlayer::s_moveSprites2(const uint8 *pos) {
_animator->moveSprites2(ARG(0), ARG(2), S_ARG(4), S_ARG(6));
}
void SegaSequencePlayer::s_moveSprites(const uint8 *pos) {
_animator->moveSprites(ARG(0), ARG(2), S_ARG(4), S_ARG(6));
}
void SegaSequencePlayer::s_moveMorphSprite(const uint8 *pos) {
_animator->moveMorphSprite(ARG(0), ARG(2), S_ARG(4), S_ARG(6));
}
void SegaSequencePlayer::s_unpauseCD(const uint8 *pos) {
// We don't support this in our AudioCD API. The original will use s_playCD() to seek to a track,
// wait for the seek to finish and then pause. It then uses this opcode to actually start the playback.
// Since s_playCD() and s_unpauseCD() are not always called on the same frame I emulate the original
// behavior like this.
if (_newTrack != -1)
_vm->snd_playSong(_newTrack, false);
_newTrack = -1;
}
void SegaSequencePlayer::s_toggleWaterDeepAnimations(const uint8 *pos) {
_waterdeepScene = ARG(0);
_waterdeepSceneTimer = 0;
}
void SegaSequencePlayer::s_assignSpeechAnimGraphics(const uint8 *pos) {
if (ARG(0) == 100) {
_speechAnimType = ARG(2);
} else {
assert(ARG(0) < 6);
_speechAnimDrawOps[ARG(0) * 2] = ARG(2);
_speechAnimDrawOps[ARG(0) * 2 + 1] = ARG(4);
}
}
void SegaSequencePlayer::s_toggleSpeechAnimation(const uint8 *pos) {
_playSpeechAnimation = ARG(0);
_speechAnimTimer = 0;
if (_playSpeechAnimation)
updateSpeechAnimGraphics(0);
}
void SegaSequencePlayer::s_orbZoomEffect(const uint8*) {
_renderer->memsetVRAM(0x2AA0, 0, 0x5800);
DrawObject *d = &_drawObjects[16];
memset(_scaleSrcBuffer, 0, 0x5800);
memcpy(_scaleSrcBuffer + 128, d->tileData, (d->width * d->height) << 5);
_renderer->fillRectWithTiles(0, 4, 0, 32, 22, 0x2155, true, true);
memset(_scaleStampMap, 0, 0x100 * sizeof(uint16));
uint16 *dst2 = &_scaleStampMap[(7 << 4) + 6];
uint16 t = 1;
for (int h = 0; h < 9; ++h) {
uint16 *dst = dst2;
for (int w = 0; w < 10; ++w)
*dst++ = t++;
dst2 += 16;
}
int step = 512;
for (int i = 0; i < 90; ++i) {
uint32 nextFrame = _vm->_system->getMillis() + 64;
uint16 *dst = _scaleTraceVectors;
uint32 xtr = 0x58000 - step * 128;
uint32 ytr = 0x59000 - step * 88;
for (int ii = 0; ii < 176; ++ii) {
*dst++ = xtr >> 8;
*dst++ = ytr >> 8;
*dst++ = step;
*dst++ = 0;
ytr += step;
}
memset(_scaleOutBuffer, 0, 0x5800);
_screen->sega_gfxScale(_scaleOutBuffer, 256, 176, 21, _scaleSrcBuffer, _scaleStampMap, _scaleTraceVectors);
_renderer->loadToVRAM(_scaleOutBuffer, 0x5800, 0x2AA0);
if (!_fastForward) {
_renderer->render(0);
_screen->updateScreen();
_vm->delayUntil(nextFrame);
}
step += 16;
}
}
void SegaSequencePlayer::s_stopCD(const uint8*) {
_vm->snd_stopSound();
}
void SegaSequencePlayer::s_playCD(const uint8 *pos) {
int track = _cdaTracks[ARG(0)];
// The original seeks to the requested CD track here and pauses it.
// The actual playback is then triggered via s_unpauseCD().
if (track)
_newTrack = track;
_vm->snd_stopSound();
}
void SegaSequencePlayer::s_displayTextEn(const uint8 *pos) {
if (_vm->gameFlags().lang == Common::JA_JPN)
return;
const char *str = (const char*)pos;
_vm->_txt->clearDim(2);
if (_playingID >= 55) {
int cs = _screen->setFontStyles(_screen->_currentFont, Font::kStyleFullWidth);
_vm->_txt->printShadedText(str, 0, 0, -1, 0xEE);
_screen->setFontStyles(_screen->_currentFont, cs);
} else {
int x = 0;
int y = 0;
if (_playingID >= 53) {
x = 152 - (_screen->getTextWidth(str) >> 1);
y = 16;
}
_vm->_txt->printShadedText(str, x, y, -1, 0xEE);
}
}
void SegaSequencePlayer::s_loadCustomPalettes(const uint8 *pos) {
Common::SeekableReadStreamEndian *in = _res->resStreamEndian(0);
in->seek(ARG(0) << 5);
_screen->sega_loadCustomPaletteData(in);
delete in;
}
void SegaSequencePlayer::s_playSoundEffect(const uint8 *pos) {
if (!_fastForward)
_vm->snd_playSoundEffect(ARG(0));
}
#undef S_ARG
#undef ARG
} // End of namespace Kyra
#endif // ENABLE_EOB

View File

@@ -0,0 +1,171 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef ENABLE_EOB
#ifndef KYRA_SEQPLAYER_SEGACD_H
#define KYRA_SEQPLAYER_SEGACD_H
namespace Common {
class SeekableReadStream;
class SeekableReadStreamEndian;
}
namespace Kyra {
class EoBEngine;
class Screen_EoB;
class SegaRenderer;
class SegaCDResource;
class SegaSequencePlayer {
public:
SegaSequencePlayer(EoBEngine *vm, Screen_EoB *screen, SegaCDResource *res);
~SegaSequencePlayer();
bool play(int id);
void pause(bool togglePause);
private:
void run(const uint8 *data);
void animateWaterdeepScene();
void updateSpeechAnimations();
void updateSpeechAnimGraphics(int animDrawOp);
struct TileSet {
const uint16 *data;
uint16 width;
uint16 height;
};
TileSet *_tileSets;
struct DrawObject {
uint16 agg;
const uint16 *tileData;
uint16 width;
uint16 height;
uint16 nTblVal;
uint16 x;
uint16 y;
uint16 addr;
};
uint16 _waterdeepScene;
uint16 _playSpeechAnimation;
uint16 _speechAnimType;
uint16 _speechAnimDrawOps[14];
uint32 _frameTimer;
uint32 _pauseStart;
bool _fastForward;
int _waterdeepSceneTimer, _speechAnimTimer;
uint16 _speechAnimNo, _speechAnimFrame;
int _playingID;
int _newTrack;
uint8 *_scaleSrcBuffer;
uint8 *_scaleOutBuffer;
uint16 *_scaleStampMap;
uint16 *_scaleTraceVectors;
uint32 _debugResyncCnt;
DrawObject *_drawObjects;
EoBEngine *_vm;
Screen_EoB *_screen;
SegaRenderer *_renderer;
SegaAnimator *_animator;
SegaCDResource *_res;
ScrollManager *_scrollManager;
private:
class SQOpcode : public Common::Functor1Mem<const uint8*, void, SegaSequencePlayer> {
public:
typedef Common::Functor1Mem<const uint8*, void, SegaSequencePlayer> SQFunc;
SQOpcode(SegaSequencePlayer *sq, const SQFunc::FuncType &func, const char *dbgName) : SQFunc(sq, func), _msg(Common::String::format(" %s()", dbgName)) {}
~SQOpcode() override {}
void run(const uint8 *arg) {
assert(arg);
debugC(7, kDebugLevelSequence, "%s", _msg.c_str());
if (SQFunc::isValid())
SQFunc::operator()(arg);
}
private:
Common::String _msg;
};
Common::Array<SQOpcode*> _opcodes;
void s_initDrawObject(const uint8 *pos);
void s_drawTileSet(const uint8 *pos);
void s_loadTileDataSingle(const uint8 *pos);
void s_drawTileSetCustom(const uint8 *pos);
void s_drawTileSetCustomTopToBottom(const uint8 *pos);
void s_fillRect(const uint8 *pos);
void s_void(const uint8*) {}
void s_initSprite(const uint8 *pos);
void s_removeSprite(const uint8 *pos);
void s_displayTextJp(const uint8 *pos);
void s_fadeToNeutral(const uint8 *pos);
void s_fadeToBlack(const uint8 *pos);
void s_fadeToNeutral2(const uint8 *pos);
void s_fadeToWhite(const uint8 *pos);
void s_setPalette(const uint8 *pos);
void s_vScroll(const uint8 *pos);
void s_hScroll(const uint8 *pos);
void s_paletteOps(const uint8 *pos);
void s_initSpriteCustomCoords(const uint8 *pos);
void s_fillRectWithPattern(const uint8 *pos);
void s_loadTileDataSeries(const uint8 *pos);
void s_drawTileSetSeries(const uint8 *pos);
void s_initSpriteSeries(const uint8 *pos);
void s_initSpriteCustom(const uint8 *pos);
void s_drawTileSetCustomCoords(const uint8 *pos);
void s_waitForPaletteFade(const uint8*);
void s_clearSprites(const uint8*);
void s_moveSprites2(const uint8 *pos);
void s_moveSprites(const uint8 *pos);
void s_moveMorphSprite(const uint8 *pos);
void s_unpauseCD(const uint8 *pos);
void s_toggleWaterDeepAnimations(const uint8 *pos);
void s_assignSpeechAnimGraphics(const uint8 *pos);
void s_toggleSpeechAnimation(const uint8 *pos);
void s_orbZoomEffect(const uint8*);
void s_stopCD(const uint8*);
void s_playCD(const uint8 *pos);
void s_displayTextEn(const uint8 *pos);
void s_loadCustomPalettes(const uint8 *pos);
void s_playSoundEffect(const uint8 *pos);
private:
const uint8 *_cdaTracks;
const uint8 *_wdAnimSprites;
const uint8 *_speechAnimData;
const uint16 *_wdDsX;
const uint8 *_wdDsY;
const uint16 *_patternTables[6];
};
} // End of namespace Kyra
#endif
#endif // ENABLE_EOB

View File

@@ -0,0 +1,751 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "kyra/sequence/seqplayer_lok.h"
#include "kyra/resource/resource.h"
#include "kyra/sound/sound.h"
#include "common/system.h"
namespace Kyra {
SeqPlayer::SeqPlayer(KyraEngine_LoK *vm, OSystem *system) {
_vm = vm;
_system = system;
_screen = vm->screen();
_sound = vm->sound();
_res = vm->resource();
_copyViewOffs = false;
_specialBuffer = nullptr;
_seqCode = 0;
_seqVocStartTimer = 0;
_seqSkipCommand = false;
_seqLoopPos = 0;
_seqData = nullptr;
_seqWsaCurDecodePage = 0;
_seqDisplayedTextTimer = 0;
_seqDisplayTextFlag = false;
_seqDisplayedText = 0;
_seqDisplayedChar = 0;
_seqDisplayedTextX = 0;
_seqTalkTextPrinted = false;
_seqTalkTextRestored = false;
_seqQuitFlag = false;
for (int i = 0; i < ARRAYSIZE(_handShapes); ++i)
_handShapes[i] = nullptr;
for (int i = 0; i < ARRAYSIZE(_seqMovies); ++i)
_seqMovies[i].movie = nullptr;
}
SeqPlayer::~SeqPlayer() {
freeHandShapes();
for (int i = 0; i < ARRAYSIZE(_seqMovies); ++i) {
if (!_seqMovies[i].movie)
continue;
_seqMovies[i].movie->close();
delete _seqMovies[i].movie;
_seqMovies[i].movie = nullptr;
}
}
uint8 *SeqPlayer::setPanPages(int pageNum, int shape) {
uint8 *panPage = nullptr;
const uint8 *data = _screen->getCPagePtr(pageNum);
uint16 numShapes = READ_LE_UINT16(data);
if (shape < numShapes) {
uint32 offs = 0;
if (_vm->gameFlags().useAltShapeHeader)
offs = READ_LE_UINT32(data + 2 + shape * 4);
else
offs = READ_LE_UINT16(data + 2 + shape * 2);
if (offs != 0) {
data += offs;
uint16 sz = READ_LE_UINT16(data + 6);
panPage = new uint8[sz];
assert(panPage);
memcpy(panPage, data, sz);
}
}
return panPage;
}
void SeqPlayer::makeHandShapes() {
_screen->loadBitmap("WRITING.CPS", 3, 3, &_screen->getPalette(0));
if (_vm->gameFlags().platform == Common::kPlatformMacintosh || _vm->gameFlags().platform == Common::kPlatformAmiga) {
freeHandShapes();
int pageBackUp = _screen->_curPage;
_screen->_curPage = 2;
_handShapes[0] = _screen->encodeShape(0, 0, 88, 122, 0);
assert(_handShapes[0]);
_handShapes[1] = _screen->encodeShape(88, 0, 80, 117, 0);
assert(_handShapes[1]);
_handShapes[2] = _screen->encodeShape(168, 0, 117, 124, 0);
assert(_handShapes[2]);
_screen->_curPage = pageBackUp;
} else {
for (int i = 0; i < ARRAYSIZE(_handShapes); ++i) {
if (_handShapes[i])
delete[] _handShapes[i];
_handShapes[i] = setPanPages(3, i);
assert(_handShapes[i]);
}
}
}
void SeqPlayer::freeHandShapes() {
for (int i = 0; i < ARRAYSIZE(_handShapes); ++i) {
delete[] _handShapes[i];
_handShapes[i] = nullptr;
}
}
void SeqPlayer::s1_wsaOpen() {
uint8 wsaObj = *_seqData++;
assert(wsaObj < ARRAYSIZE(_seqMovies));
uint8 offscreenDecode = *_seqData++;
_seqWsaCurDecodePage = _seqMovies[wsaObj].page = (offscreenDecode == 0) ? 0 : 3;
if (!_seqMovies[wsaObj].movie)
_seqMovies[wsaObj].movie = _vm->createWSAMovie();
_seqMovies[wsaObj].movie->open(_vm->seqWSATable()[wsaObj], offscreenDecode, nullptr);
_seqMovies[wsaObj].frame = 0;
_seqMovies[wsaObj].numFrames = _seqMovies[wsaObj].movie->frames() - 1;
}
void SeqPlayer::s1_wsaClose() {
uint8 wsaObj = *_seqData++;
assert(wsaObj < ARRAYSIZE(_seqMovies));
if (_seqMovies[wsaObj].movie)
_seqMovies[wsaObj].movie->close();
}
void SeqPlayer::s1_wsaPlayFrame() {
uint8 wsaObj = *_seqData++;
assert(wsaObj < ARRAYSIZE(_seqMovies));
int16 frame = (int8)*_seqData++;
_seqMovies[wsaObj].pos.x = READ_LE_UINT16(_seqData); _seqData += 2;
_seqMovies[wsaObj].pos.y = *_seqData++;
assert(_seqMovies[wsaObj].movie);
_seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, nullptr, nullptr);
_seqMovies[wsaObj].frame = frame;
}
void SeqPlayer::s1_wsaPlayNextFrame() {
uint8 wsaObj = *_seqData++;
assert(wsaObj < ARRAYSIZE(_seqMovies));
int16 frame = ++_seqMovies[wsaObj].frame;
if (frame > _seqMovies[wsaObj].numFrames) {
frame = 0;
_seqMovies[wsaObj].frame = 0;
}
_seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, nullptr, nullptr);
}
void SeqPlayer::s1_wsaPlayPrevFrame() {
uint8 wsaObj = *_seqData++;
assert(wsaObj < ARRAYSIZE(_seqMovies));
int16 frame = --_seqMovies[wsaObj].frame;
if (frame < 0) {
frame = _seqMovies[wsaObj].numFrames;
_seqMovies[wsaObj].frame = frame;
} else {
_seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, nullptr, nullptr);
}
}
void SeqPlayer::s1_drawShape() {
uint8 shapeNum = *_seqData++;
int x = READ_LE_UINT16(_seqData); _seqData += 2;
int y = *_seqData++;
_screen->drawShape(2, _handShapes[shapeNum], x, y, 0, 0, 0);
}
void SeqPlayer::s1_waitTicks() {
uint16 ticks = READ_LE_UINT16(_seqData); _seqData += 2;
if (_seqCode == 6 && _vm->speechEnabled() && !_vm->textEnabled())
return;
_vm->delay(ticks * _vm->tickLength());
}
void SeqPlayer::s1_copyWaitTicks() {
s1_copyView();
s1_waitTicks();
}
void SeqPlayer::s1_shuffleScreen() {
_screen->shuffleScreen(0, 16, 320, 128, 2, 0, 0, false);
if (_specialBuffer)
_screen->copyRegionToBuffer(2, 0, 16, 320, 128, _specialBuffer);
_screen->_curPage = 0;
}
void SeqPlayer::s1_copyView() {
int h = !_copyViewOffs ? 120 : 128;
if (_specialBuffer && !_copyViewOffs)
_screen->copyToPage0(16, h, 3, _specialBuffer);
else
_screen->copyRegion(0, 16, 0, 16, 320, h, 2, 0);
}
void SeqPlayer::s1_loopInit() {
_seqLoopPos = *_seqData++;
if (_seqLoopPos < ARRAYSIZE(_seqLoopTable))
_seqLoopTable[_seqLoopPos].ptr = _seqData;
else
_seqQuitFlag = true;
}
void SeqPlayer::s1_loopInc() {
_seqLoopPos = *_seqData++;
uint16 seqLoopCount = READ_LE_UINT16(_seqData); _seqData += 2;
if (_seqCode == 13 && _vm->speechEnabled() && !_vm->textEnabled()) {
if (_vm->snd_voiceIsPlaying()) {
_seqData = _seqLoopTable[_seqLoopPos].ptr;
} else {
_seqLoopTable[_seqLoopPos].count = 0xFFFF;
_seqLoopTable[_seqLoopPos].ptr = nullptr;
}
} else if (_seqLoopTable[_seqLoopPos].count == 0xFFFF) {
_seqLoopTable[_seqLoopPos].count = seqLoopCount - 1;
_seqData = _seqLoopTable[_seqLoopPos].ptr;
} else if (_seqLoopTable[_seqLoopPos].count == 0) {
_seqLoopTable[_seqLoopPos].count = 0xFFFF;
_seqLoopTable[_seqLoopPos].ptr = nullptr;
} else {
--_seqLoopTable[_seqLoopPos].count;
_seqData = _seqLoopTable[_seqLoopPos].ptr;
}
}
void SeqPlayer::s1_skip() {
uint8 val = *_seqData++;
if (!_vm->speechEnabled() || _vm->textEnabled() || !val)
return;
_seqSkipCommand = true;
uint32 vocPlayTime = _vm->snd_getVoicePlayTime();
if (vocPlayTime) {
if (((_system->getMillis() - _seqVocStartTimer) / _vm->tickLength()) < (val * (vocPlayTime / _vm->tickLength()) / 100))
_seqSkipCommand = false;
}
}
void SeqPlayer::s1_loadPalette() {
uint8 colNum = *_seqData++;
if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
if (!colNum)
_screen->copyPalette(0, 6);
else if (colNum == 3)
_screen->copyPalette(0, 7);
else if (colNum == 4)
_screen->copyPalette(0, 3);
_screen->setScreenPalette(_screen->getPalette(0));
} else {
_screen->loadPalette(_vm->seqCOLTable()[colNum], _screen->getPalette(0));
}
}
void SeqPlayer::s1_loadBitmap() {
uint8 cpsNum = *_seqData++;
_screen->loadBitmap(_vm->seqCPSTable()[cpsNum], 3, 3, &_screen->getPalette(0));
}
void SeqPlayer::s1_fadeToBlack() {
_screen->fadeToBlack();
}
void SeqPlayer::s1_printText() {
static const uint8 colorMap[] = { 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0 };
uint8 txt = *_seqData++;
if (!_vm->textEnabled())
return;
if (_vm->gameFlags().platform == Common::kPlatformAmiga)
_screen->fillRect(0, 180, 319, 195, 0);
else
_screen->fillRect(0, 180, 319, 195, 12);
_screen->setTextColorMap(colorMap);
if (!_seqDisplayTextFlag) {
const char *str = _vm->seqTextsTable()[txt];
int x = (Screen::SCREEN_W - _screen->getTextWidth(str)) / 2;
_screen->printText(str, x, 180, 0xF, 0xC);
} else {
_seqDisplayedTextTimer = _system->getMillis() + 1000 / ((_vm->gameFlags().lang == Common::FR_FRA) ? 120 : 60);
_seqDisplayedText = txt;
_seqDisplayedChar = 0;
const char *str = _vm->seqTextsTable()[_seqDisplayedText];
_seqDisplayedTextX = (Screen::SCREEN_W - _screen->getTextWidth(str)) / 2;
}
}
void SeqPlayer::s1_printTalkText() {
uint8 txt = *_seqData++;
int x = READ_LE_UINT16(_seqData); _seqData += 2;
int y = *_seqData++;
uint8 fillColor = *_seqData++;
int b;
if (_seqTalkTextPrinted && !_seqTalkTextRestored) {
if (_seqWsaCurDecodePage != 0 && !_specialBuffer)
b = 2;
else
b = 0;
_vm->text()->restoreTalkTextMessageBkgd(2, b);
}
if (!_vm->textEnabled())
return;
_seqTalkTextPrinted = true;
_seqTalkTextRestored = false;
if (_seqWsaCurDecodePage != 0 && !_specialBuffer)
b = 2;
else
b = 0;
_vm->text()->printTalkTextMessage(_vm->seqTextsTable()[txt], x, y, fillColor, b, 2);
}
void SeqPlayer::s1_restoreTalkText() {
if (_seqTalkTextPrinted && !_seqTalkTextRestored && _vm->textEnabled()) {
int b;
if (_seqWsaCurDecodePage != 0 && !_specialBuffer)
b = 2;
else
b = 0;
_vm->text()->restoreTalkTextMessageBkgd(2, b);
_seqTalkTextRestored = true;
}
}
void SeqPlayer::s1_clearCurrentScreen() {
if (_vm->gameFlags().platform == Common::kPlatformAmiga)
_screen->fillRect(10, 180, 319, 195, 0);
else
_screen->fillRect(10, 180, 319, 196, 0xC);
}
void SeqPlayer::s1_break() {
// Do nothing
}
void SeqPlayer::s1_fadeFromBlack() {
_screen->fadeFromBlack();
}
void SeqPlayer::s1_copyRegion() {
uint8 srcPage = *_seqData++;
uint8 dstPage = *_seqData++;
_screen->copyRegion(0, 0, 0, 0, 320, 200, srcPage, dstPage);
}
void SeqPlayer::s1_copyRegionSpecial() {
static const uint8 colorMap[] = { 0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0 };
const char *copyStr = nullptr;
if (!_vm->gameFlags().isTalkie)
copyStr = "Copyright (c) 1992 Westwood Studios";
else
copyStr = "Copyright (c) 1992,1993 Westwood Studios";
uint8 so = *_seqData++;
switch (so) {
case 0:
if (_vm->gameFlags().platform == Common::kPlatformAmiga)
_screen->copyRegion(0, 0, 0, 47, 312, 76, 2, 0);
else
_screen->copyRegion(0, 0, 0, 47, 320, 77, 2, 0);
break;
case 1:
if (_vm->gameFlags().platform == Common::kPlatformAmiga)
_screen->copyRegion(0, 0, 8, 47, 312, 55, 2, 0);
else
_screen->copyRegion(0, 0, 0, 47, 320, 56, 2, 0);
break;
case 2:
if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
_screen->copyRegion(104, 72, 104, 72, 40, 87, 2, 0);
_screen->copyRegion(128, 159, 128, 159, 32, 17, 2, 0);
_screen->copyRegion(160, 105, 160, 105, 32, 9, 2, 0);
_screen->copyRegion(200, 83, 200, 83, 88, 93, 2, 0);
} else {
_screen->copyRegion(107, 72, 107, 72, 43, 87, 2, 0);
_screen->copyRegion(130, 159, 130, 159, 35, 17, 2, 0);
_screen->copyRegion(165, 105, 165, 105, 32, 9, 2, 0);
_screen->copyRegion(206, 83, 206, 83, 94, 93, 2, 0);
}
break;
case 3:
_screen->copyRegion(152, 56, 152, 56, 48, 48, 2, 0);
break;
case 4: {
_screen->_charSpacing = -2;
const int x = (Screen::SCREEN_W - _screen->getTextWidth(copyStr)) / 2;
const int y = 179;
_screen->setTextColorMap(colorMap);
if (_vm->gameFlags().platform != Common::kPlatformAmiga)
_screen->printText(copyStr, x + 1, y + 1, 0xB, 0xC);
_screen->printText(copyStr, x, y, 0xF, 0xC);
} break;
case 5:
_screen->_curPage = 2;
break;
default:
error("Invalid subopcode %d for s1_copyRegionSpecial", so);
}
}
void SeqPlayer::s1_fillRect() {
int x1 = READ_LE_UINT16(_seqData); _seqData += 2;
int y1 = *_seqData++;
int x2 = READ_LE_UINT16(_seqData); _seqData += 2;
int y2 = *_seqData++;
uint8 color = *_seqData++;
uint8 page = *_seqData++;
_screen->fillRect(x1, y1, x2, y2, color, page);
}
void SeqPlayer::s1_playEffect() {
uint8 track = *_seqData++;
_vm->delay(3 * _vm->tickLength());
if (_vm->gameFlags().platform == Common::kPlatformPC98) {
if (track > 21 && track < 38)
track -= 22;
else
return;
}
_sound->playSoundEffect(track);
}
void SeqPlayer::s1_playTrack() {
uint8 msg = *_seqData++;
if (_vm->gameFlags().platform != Common::kPlatformMacintosh && _vm->gameFlags().platform != Common::kPlatformAmiga)
_vm->delay(3 * _vm->tickLength());
if (msg == 0 && (_vm->gameFlags().platform != Common::kPlatformDOS && _vm->gameFlags().platform != Common::kPlatformAmiga)) {
_sound->haltTrack();
} else if (msg == 1) {
_sound->beginFadeOut();
} else {
_sound->haltTrack();
if (_vm->gameFlags().platform != Common::kPlatformMacintosh && _vm->gameFlags().platform != Common::kPlatformAmiga)
_vm->delay(3 * _vm->tickLength());
_sound->playTrack(_vm->gameFlags().platform == Common::kPlatformFMTowns ? msg + 2 : msg);
}
if (msg < 2 && (_vm->gameFlags().platform != Common::kPlatformMacintosh && _vm->gameFlags().platform != Common::kPlatformAmiga))
_vm->delay(3 * _vm->tickLength());
}
void SeqPlayer::s1_allocTempBuffer() {
if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
_seqQuitFlag = true;
} else {
if (!_specialBuffer && !_copyViewOffs) {
_specialBuffer = new uint8[40960];
assert(_specialBuffer);
_screen->copyRegionToBuffer(2, 0, 16, 320, 128, _specialBuffer);
}
}
}
void SeqPlayer::s1_textDisplayEnable() {
_seqDisplayTextFlag = true;
}
void SeqPlayer::s1_textDisplayDisable() {
_seqDisplayTextFlag = false;
}
void SeqPlayer::s1_endOfScript() {
_seqQuitFlag = true;
}
void SeqPlayer::s1_loadIntroVRM() {
_res->loadPakFile("INTRO.VRM");
}
void SeqPlayer::s1_playVocFile() {
_vm->snd_voiceWaitForFinish(false);
uint8 a = *_seqData++;
if (_vm->speechEnabled()) {
_seqVocStartTimer = _system->getMillis();
_vm->snd_playVoiceFile(a);
}
}
void SeqPlayer::s1_miscUnk3() {
// This is just a file cash flushing function in the original. We don't need that.
}
void SeqPlayer::s1_prefetchVocFile() {
_seqData++;
// we do not have to prefetch the vocfiles on modern systems
}
void SeqPlayer::s1_textDisplayWait() {
// This is used in the Mac Talkie version for the Kallak writing sequence.
// But in my tests the condition was never reached...
if (_seqDisplayedTextTimer != 0xFFFFFFFF)
_seqData--;
}
#define SEQOP(n, x) { n, &SeqPlayer::x, #x }
bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) {
assert(seqData);
static const SeqEntry floppySeqProcs[] = {
// 0x00
SEQOP(3, s1_wsaOpen),
SEQOP(2, s1_wsaClose),
SEQOP(6, s1_wsaPlayFrame),
SEQOP(2, s1_wsaPlayNextFrame),
// 0x04
SEQOP(2, s1_wsaPlayPrevFrame),
SEQOP(5, s1_drawShape),
SEQOP(3, s1_waitTicks),
SEQOP(3, s1_copyWaitTicks),
// 0x08
SEQOP(1, s1_shuffleScreen),
SEQOP(1, s1_copyView),
SEQOP(2, s1_loopInit),
SEQOP(4, s1_loopInc),
// 0x0C
SEQOP(2, s1_loadPalette),
SEQOP(2, s1_loadBitmap),
SEQOP(1, s1_fadeToBlack),
SEQOP(2, s1_printText),
// 0x10
SEQOP(6, s1_printTalkText),
SEQOP(1, s1_restoreTalkText),
SEQOP(1, s1_clearCurrentScreen),
SEQOP(1, s1_break),
// 0x14
SEQOP(1, s1_fadeFromBlack),
SEQOP(3, s1_copyRegion),
SEQOP(2, s1_copyRegionSpecial),
SEQOP(9, s1_fillRect),
// 0x18
SEQOP(2, s1_playEffect),
SEQOP(2, s1_playTrack),
SEQOP(1, s1_allocTempBuffer),
SEQOP(1, s1_textDisplayEnable),
// 0x1C
SEQOP(1, s1_textDisplayDisable),
SEQOP(1, s1_endOfScript)
};
static const SeqEntry cdromSeqProcs[] = {
// 0x00
SEQOP(3, s1_wsaOpen),
SEQOP(2, s1_wsaClose),
SEQOP(6, s1_wsaPlayFrame),
SEQOP(2, s1_wsaPlayNextFrame),
// 0x04
SEQOP(2, s1_wsaPlayPrevFrame),
SEQOP(5, s1_drawShape),
SEQOP(3, s1_waitTicks),
SEQOP(3, s1_waitTicks),
// 0x08
SEQOP(3, s1_copyWaitTicks),
SEQOP(1, s1_shuffleScreen),
SEQOP(1, s1_copyView),
SEQOP(2, s1_loopInit),
// 0x0C
SEQOP(4, s1_loopInc),
SEQOP(4, s1_loopInc),
SEQOP(2, s1_skip),
SEQOP(2, s1_loadPalette),
// 0x10
SEQOP(2, s1_loadBitmap),
SEQOP(1, s1_fadeToBlack),
SEQOP(2, s1_printText),
SEQOP(6, s1_printTalkText),
// 0x14
SEQOP(1, s1_restoreTalkText),
SEQOP(1, s1_clearCurrentScreen),
SEQOP(1, s1_break),
SEQOP(1, s1_fadeFromBlack),
// 0x18
SEQOP(3, s1_copyRegion),
SEQOP(2, s1_copyRegionSpecial),
SEQOP(9, s1_fillRect),
SEQOP(2, s1_playEffect),
// 0x1C
SEQOP(2, s1_playTrack),
SEQOP(1, s1_allocTempBuffer),
SEQOP(1, s1_textDisplayEnable),
SEQOP(1, s1_textDisplayDisable),
// 0x20
SEQOP(1, s1_endOfScript),
SEQOP(1, s1_loadIntroVRM),
SEQOP(2, s1_playVocFile),
SEQOP(1, s1_miscUnk3),
// 0x24
SEQOP(2, s1_prefetchVocFile),
SEQOP(1, s1_textDisplayWait)
};
const SeqEntry *commands;
int numCommands;
if (_vm->gameFlags().isTalkie) {
commands = cdromSeqProcs;
numCommands = ARRAYSIZE(cdromSeqProcs);
} else {
commands = floppySeqProcs;
numCommands = ARRAYSIZE(floppySeqProcs);
}
bool seqSkippedFlag = false;
_seqData = seqData;
_seqDisplayedTextTimer = 0xFFFFFFFF;
_seqDisplayTextFlag = false;
_seqDisplayedTextX = 0;
_seqDisplayedText = 0;
_seqDisplayedChar = 0;
_seqTalkTextRestored = false;
_seqTalkTextPrinted = false;
_seqSkipCommand = false;
_seqQuitFlag = false;
_seqWsaCurDecodePage = 0;
_seqLoopPos = 0;
for (int i = 0; i < 20; ++i) {
_seqLoopTable[i].ptr = nullptr;
_seqLoopTable[i].count = 0xFFFF;
}
for (uint i = 0; i < ARRAYSIZE(_seqMovies); i++) {
_seqMovies[i].clear();
}
_screen->_curPage = 0;
char revBuffer[384];
memset(revBuffer, 0, sizeof(revBuffer));
int charIdx = 0;
while (!_seqQuitFlag && !_vm->shouldQuit()) {
uint32 startFrameCt = _vm->_system->getMillis();
if (_seqSkipCommand || (skipSeq && _vm->seq_skipSequence())) {
while (1) {
uint8 code = *_seqData;
if (commands[code].proc == &SeqPlayer::s1_endOfScript)
break;
if (_seqSkipCommand && commands[code].proc == &SeqPlayer::s1_skip && _seqData[1] == 0)
break;
if (commands[code].proc == &SeqPlayer::s1_break)
break;
_seqData += commands[code].len;
}
skipSeq = false;
seqSkippedFlag = true;
if (_seqSkipCommand) {
_seqSkipCommand = false;
_seqData += commands[14].len;
_seqLoopTable[_seqLoopPos].count = 0xFFFF;
_seqLoopTable[_seqLoopPos].ptr = nullptr;
}
}
// used in Kallak writing intro
if (_seqDisplayTextFlag && _seqDisplayedTextTimer != 0xFFFFFFFF && _vm->textEnabled()) {
if (_seqDisplayedTextTimer < _system->getMillis()) {
char charStr[3];
charStr[0] = _vm->seqTextsTable()[_seqDisplayedText][_seqDisplayedChar];
if (_vm->gameFlags().lang == Common::HE_ISR) {
for (int k = charIdx; k > 0; k--) {
revBuffer[k] = revBuffer[k - 1];
}
revBuffer[0] = charStr[0];
if (!charIdx) {
int w = _screen->getTextWidth(_vm->seqTextsTable()[_seqDisplayedText] + _seqDisplayedChar);
_seqDisplayedTextX += w;
}
charIdx++;
}
charStr[1] = charStr[2] = '\0';
if (_vm->gameFlags().lang == Common::JA_JPN || _vm->gameFlags().lang == Common::ZH_TWN || (_vm->gameFlags().lang == Common::KO_KOR && (charStr[0] & 0x80))) {
charStr[1] = _vm->seqTextsTable()[_seqDisplayedText][++_seqDisplayedChar];
_screen->printText(charStr, _seqDisplayedTextX, 180, 0xF, 0xC);
_seqDisplayedTextX += _screen->getTextWidth(charStr);
} else if (_vm->gameFlags().lang == Common::HE_ISR) {
_seqDisplayedTextX -= _screen->getCharWidth((uint8)charStr[0]);
_screen->printText(revBuffer, _seqDisplayedTextX, 180, 0xF, 0xC);
} else {
_screen->printText(charStr, _seqDisplayedTextX, 180, 0xF, 0xC);
_seqDisplayedTextX += _screen->getCharWidth((uint8)charStr[0]);
}
++_seqDisplayedChar;
if (_vm->seqTextsTable()[_seqDisplayedText][_seqDisplayedChar] == '\0') {
_seqDisplayedTextTimer = 0xFFFFFFFF;
memset(revBuffer, 0, sizeof(revBuffer));
charIdx = 0;
} else {
_seqDisplayedTextTimer = _system->getMillis() + 1000 / ((_vm->gameFlags().lang == Common::FR_FRA) ? 120 : 60);
}
}
}
_seqCode = *_seqData++;
if (_seqCode < numCommands) {
SeqProc currentProc = commands[_seqCode].proc;
debugC(5, kDebugLevelSequence, "0x%.4X seqCode = %d (%s)", (uint16)(_seqData - 1 - seqData), _seqCode, commands[_seqCode].desc);
(this->*currentProc)();
} else {
error("Invalid sequence opcode %d called from 0x%.04X", _seqCode, (uint16)(_seqData - 1 - seqData));
}
int extraDelay = _screen->updateScreen();
uint32 ct = _system->getMillis();
_vm->delayUntil(startFrameCt + extraDelay > ct ? startFrameCt + extraDelay : ct + 8);
}
delete[] _specialBuffer;
_specialBuffer = nullptr;
for (uint i = 0; i < ARRAYSIZE(_seqMovies); ++i) {
delete _seqMovies[i].movie;
_seqMovies[i].movie = nullptr;
}
return seqSkippedFlag;
}
#undef SEQOP
#undef KYRA_SEQ_SCREENFRAMEDELAY_MIN
} // End of namespace Kyra

View File

@@ -0,0 +1,137 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef KYRA_SEQPLAYER_H
#define KYRA_SEQPLAYER_H
#include "kyra/engine/kyra_lok.h"
namespace Kyra {
class SeqPlayer {
public:
SeqPlayer(KyraEngine_LoK *vm, OSystem *system);
~SeqPlayer();
void setCopyViewOffs(bool offs) {
_copyViewOffs = offs;
}
void makeHandShapes();
void freeHandShapes();
bool playSequence(const uint8 *seqData, bool skipSeq);
uint8 *setPanPages(int pageNum, int shape);
protected:
KyraEngine_LoK *_vm;
OSystem *_system;
Screen *_screen;
Sound *_sound;
Resource *_res;
uint8 *_handShapes[3];
bool _copyViewOffs;
typedef void (SeqPlayer::*SeqProc)();
struct SeqEntry {
uint8 len;
SeqProc proc;
const char *desc;
};
// the sequence procs
void s1_wsaOpen();
void s1_wsaClose();
void s1_wsaPlayFrame();
void s1_wsaPlayNextFrame();
void s1_wsaPlayPrevFrame();
void s1_drawShape();
void s1_waitTicks();
void s1_copyWaitTicks();
void s1_shuffleScreen();
void s1_copyView();
void s1_loopInit();
void s1_loopInc();
void s1_skip();
void s1_loadPalette();
void s1_loadBitmap();
void s1_fadeToBlack();
void s1_printText();
void s1_printTalkText();
void s1_restoreTalkText();
void s1_clearCurrentScreen();
void s1_break();
void s1_fadeFromBlack();
void s1_copyRegion();
void s1_copyRegionSpecial();
void s1_fillRect();
void s1_playEffect();
void s1_playTrack();
void s1_allocTempBuffer();
void s1_textDisplayEnable();
void s1_textDisplayDisable();
void s1_endOfScript();
void s1_loadIntroVRM();
void s1_playVocFile();
void s1_miscUnk3();
void s1_prefetchVocFile();
void s1_textDisplayWait();
struct SeqMovie {
Movie *movie;
int32 page;
int16 frame;
int16 numFrames;
Common::Point pos;
void clear() {
movie = nullptr;
page = 0;
frame = 0;
numFrames = 0;
pos.x = 0;
pos.y = 0;
}
};
const uint8 *_seqData;
uint8 _seqCode;
uint8 *_specialBuffer;
SeqMovie _seqMovies[12];
SeqLoop _seqLoopTable[20];
uint8 _seqLoopPos;
uint16 _seqWsaCurDecodePage;
uint32 _seqDisplayedTextTimer;
uint32 _seqVocStartTimer;
bool _seqDisplayTextFlag;
uint8 _seqDisplayedText;
uint8 _seqDisplayedChar;
uint16 _seqDisplayedTextX;
bool _seqTalkTextPrinted;
bool _seqTalkTextRestored;
bool _seqQuitFlag;
bool _seqSkipCommand;
};
} // End of namespace Kyra
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef KYRA_SEQUENCES_HOF_H
#define KYRA_SEQUENCES_HOF_H
#include "kyra/engine/kyra_v2.h"
namespace Kyra {
struct HoFSequence {
const char *wsaFile;
const char *cpsFile;
uint16 flags;
uint8 fadeInTransitionType;
uint8 fadeOutTransitionType;
int16 stringIndex1;
int16 stringIndex2;
uint16 startFrame;
uint16 numFrames;
uint16 duration;
uint16 xPos;
uint16 yPos;
uint16 timeout;
};
struct HoFNestedSequence {
const char *wsaFile;
const FrameControl *wsaControl;
uint16 flags;
uint16 startframe;
uint16 endFrame;
uint16 frameDelay;
uint16 x;
uint16 y;
uint16 fadeInTransitionType;
uint16 fadeOutTransitionType;
};
struct HoFSeqData {
const HoFSequence *seq;
int numSeq;
const HoFNestedSequence *nestedSeq;
int numNestedSeq;
};
struct HoFSeqItemAnimData {
int16 itemIndex;
uint16 y;
const uint16 *frames;
};
} // End of namespace Kyra
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,237 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "kyra/engine/kyra_mr.h"
#include "kyra/resource/resource.h"
namespace Kyra {
void KyraEngine_MR::showBadConscience() {
if (_badConscienceShown)
return;
_badConscienceShown = true;
_badConscienceAnim = _rnd.getRandomNumberRng(0, 2);
if (_currentChapter == 2)
_badConscienceAnim = 5;
else if (_currentChapter == 3)
_badConscienceAnim = 3;
else if (_currentChapter == 4 && _rnd.getRandomNumberRng(1, 100) <= 25)
_badConscienceAnim = 6;
else if (_currentChapter == 5 && _rnd.getRandomNumberRng(1, 100) <= 25)
_badConscienceAnim = 7;
if (_characterShapeFile == 9)
_badConscienceAnim = 4;
_badConsciencePosition = (_mainCharacter.x1 <= 160);
if (_goodConscienceShown)
_badConsciencePosition = !_goodConsciencePosition;
int anim = _badConscienceAnim + (_badConsciencePosition ? 0 : 8);
TalkObject &talkObject = _talkObjectList[1];
if (_badConsciencePosition)
talkObject.x = 290;
else
talkObject.x = 30;
talkObject.y = 30;
static const char *const animFilenames[] = {
"GUNFL00.WSA", "GUNFL01.WSA", "GUNFL02.WSA", "GUNFL03.WSA", "GUNFL04.WSA", "GUNFL05.WSA", "GUNFL06.WSA", "GUNFL07.WSA",
"GUNFR00.WSA", "GUNFR01.WSA", "GUNFR02.WSA", "GUNFR03.WSA", "GUNFR04.WSA", "GUNFR05.WSA", "GUNFR06.WSA", "GUNFR07.WSA"
};
setupSceneAnimObject(0x0E, 9, 0, _interfaceCommandLineY1 - 1, -1, -1, -1, -1, 0, 0, 0, -1, animFilenames[anim]);
for (uint i = 0; i <= _badConscienceFrameTable[_badConscienceAnim]; ++i) {
if (i == 8)
snd_playSoundEffect(0x1B, 0xC8);
updateSceneAnim(0x0E, i);
delay(3*_tickLength, true);
}
if (_mainCharacter.animFrame < 50 || _mainCharacter.animFrame > 87)
return;
if (_mainCharacter.y1 == -1 || (_mainCharacter.x1 != -1 && _mainCharacter.animFrame == 87) || _mainCharacter.animFrame == 87) {
_mainCharacter.animFrame = 87;
} else {
if (_badConsciencePosition)
_mainCharacter.facing = 3;
else
_mainCharacter.facing = 5;
// _mainCharacter.facing can not be 0xFF here, so this is safe.
_mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
}
updateCharacterAnim(0);
refreshAnimObjectsIfNeed();
}
void KyraEngine_MR::hideBadConscience() {
if (!_badConscienceShown)
return;
_badConscienceShown = false;
for (int frame = _badConscienceFrameTable[_badConscienceAnim+8]; frame >= 0; --frame) {
if (frame == 15)
snd_playSoundEffect(0x31, 0xC8);
updateSceneAnim(0x0E, frame);
delay(1*_tickLength, true);
}
updateSceneAnim(0x0E, -1);
update();
removeSceneAnimObject(0x0E, 1);
setNextIdleAnimTimer();
}
void KyraEngine_MR::showGoodConscience() {
if (_goodConscienceShown)
return;
_goodConscienceShown = true;
++_goodConscienceAnim;
_goodConscienceAnim %= 5;
setNextIdleAnimTimer();
_goodConsciencePosition = (_mainCharacter.x1 <= 160);
if (_badConscienceShown)
_goodConsciencePosition = !_badConsciencePosition;
int anim = _goodConscienceAnim + (_goodConsciencePosition ? 0 : 5);
TalkObject &talkObject = _talkObjectList[87];
if (_goodConsciencePosition)
talkObject.x = 290;
else
talkObject.x = 30;
talkObject.y = 30;
static const char *const animFilenames[] = {
"STUFL00.WSA", "STUFL02.WSA", "STUFL04.WSA", "STUFL03.WSA", "STUFL01.WSA",
"STUFR00.WSA", "STUFR02.WSA", "STUFR04.WSA", "STUFR03.WSA", "STUFR01.WSA"
};
setupSceneAnimObject(0x0F, 9, 0, 187, -1, -1, -1, -1, 0, 0, 0, -1, animFilenames[anim]);
for (uint i = 0; i <= _goodConscienceFrameTable[_goodConscienceAnim]; ++i) {
if (i == 10)
snd_playSoundEffect(0x7F, 0xC8);
updateSceneAnim(0x0F, i);
delay(2*_tickLength, true);
}
if (_mainCharacter.animFrame < 50 || _mainCharacter.animFrame > 87)
return;
if (_mainCharacter.y1 == -1 || (_mainCharacter.x1 != -1 && _mainCharacter.animFrame == 87) || _mainCharacter.animFrame == 87) {
_mainCharacter.animFrame = 87;
} else {
if (_goodConsciencePosition)
_mainCharacter.facing = 3;
else
_mainCharacter.facing = 5;
_mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
}
updateCharacterAnim(0);
refreshAnimObjectsIfNeed();
}
void KyraEngine_MR::hideGoodConscience() {
if (!_goodConscienceShown)
return;
_goodConscienceShown = false;
for (int frame = _goodConscienceFrameTable[_goodConscienceAnim+5]; frame >= 0; --frame) {
if (frame == 17)
snd_playSoundEffect(0x31, 0xC8);
updateSceneAnim(0x0F, frame);
delay(1*_tickLength, true);
}
updateSceneAnim(0x0F, -1);
update();
removeSceneAnimObject(0x0F, 1);
setNextIdleAnimTimer();
}
void KyraEngine_MR::eelScript() {
if (!_chatText.empty())
return;
_screen->hideMouse();
if (_inventoryState)
hideInventory();
removeHandItem();
objectChat((const char *)getTableEntry(_cCodeFile, 35), 0, 204, 35);
objectChat((const char *)getTableEntry(_cCodeFile, 40), 0, 204, 40);
setGameFlag(0xD1);
snd_playSoundEffect(0x2A, 0xC8);
setGameFlag(0x171);
switch (_characterShapeFile-1) {
case 0:
runAnimationScript("EELS01.EMC", 0, 0, 1, 1);
break;
case 1:
runAnimationScript("EELS02.EMC", 0, 0, 1, 1);
break;
case 2:
runAnimationScript("EELS03.EMC", 0, 0, 1, 1);
break;
case 3:
runAnimationScript("EELS04.EMC", 0, 0, 1, 1);
break;
default:
resetGameFlag(0x171);
runAnimationScript("EELS00.EMC", 0, 0, 1, 1);
}
changeChapter(2, 29, 0, 4);
_screen->showMouse();
}
int KyraEngine_MR::initAnimationShapes(uint8 *filedata) {
const int lastEntry = MIN(_animShapeLastEntry, 41);
for (int i = 0; i < lastEntry; ++i)
_gameShapes[9+i] = _screen->getPtrToShape(filedata, i);
return lastEntry;
}
void KyraEngine_MR::uninitAnimationShapes(int count, uint8 *filedata) {
for (int i = 0; i < count; ++i)
_gameShapes[9+i] = 0;
delete[] filedata;
setNextIdleAnimTimer();
}
} // End of namespace Kyra

View File

@@ -0,0 +1,130 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "kyra/engine/kyra_v2.h"
#include "kyra/resource/resource.h"
#include "common/system.h"
namespace Kyra {
void KyraEngine_v2::runAnimationScript(const char *filename, int allowSkip, int resetChar, int newShapes, int shapeUnload) {
memset(&_animationScriptData, 0, sizeof(_animationScriptData));
memset(&_animationScriptState, 0, sizeof(_animationScriptState));
if (!_emc->load(filename, &_animationScriptData, &_opcodesAnimation))
error("Couldn't load temporary script '%s'", filename);
_emc->init(&_animationScriptState, &_animationScriptData);
_emc->start(&_animationScriptState, 0);
_animResetFrame = -1;
if (_animShapeFiledata && newShapes) {
uninitAnimationShapes(_animShapeCount, _animShapeFiledata);
_animShapeFiledata = nullptr;
_animShapeCount = 0;
}
while (_emc->isValid(&_animationScriptState))
_emc->run(&_animationScriptState);
uint8 *fileData = nullptr;
if (newShapes)
_animShapeFiledata = _res->fileData(_animShapeFilename, nullptr);
fileData = _animShapeFiledata;
if (!fileData) {
_emc->unload(&_animationScriptData);
return;
}
if (newShapes)
_animShapeCount = initAnimationShapes(fileData);
processAnimationScript(allowSkip, resetChar);
if (shapeUnload) {
uninitAnimationShapes(_animShapeCount, fileData);
_animShapeCount = 0;
_animShapeFiledata = nullptr;
}
_emc->unload(&_animationScriptData);
}
void KyraEngine_v2::processAnimationScript(int allowSkip, int resetChar) {
setCharacterAnimDim(_animShapeWidth, _animShapeHeight);
_emc->init(&_animationScriptState, &_animationScriptData);
_emc->start(&_animationScriptState, 1);
resetSkipFlag();
while (_emc->isValid(&_animationScriptState)) {
_animNeedUpdate = false;
while (_emc->isValid(&_animationScriptState) && !_animNeedUpdate)
_emc->run(&_animationScriptState);
if (_animNewFrame < 0)
continue;
_mainCharacter.animFrame = _animNewFrame + _desc.animScriptFrameAdd;
updateCharacterAnim(0);
if (!_chatText.empty())
updateWithText();
else
update();
uint32 delayEnd = _system->getMillis() + _animDelayTime * _tickLength;
while ((!skipFlag() || !allowSkip) && _system->getMillis() < delayEnd)
delay(10, true);
if (skipFlag()) {
if (!_kbEventSkip || _eventList.front().event.type != Common::EVENT_KEYDOWN)
resetSkipFlag();
if (allowSkip)
break;
}
}
if (resetChar) {
if (_animResetFrame >= 0) {
_mainCharacter.animFrame = _animResetFrame + _desc.animScriptFrameAdd;
updateCharacterAnim(0);
if (!_chatText.empty())
updateWithText();
else
update();
}
_mainCharacter.animFrame = _desc.characterFrameTable[_mainCharacter.facing];
updateCharacterAnim(0);
}
_animResetFrame = -1;
resetCharacterAnimDim();
}
} // End of namespace Kyra