1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #ifdef ENABLE_EOB
24
25 #include "kyra/engine/eob.h"
26 #include "kyra/graphics/screen_eob.h"
27 #include "kyra/graphics/screen_eob_segacd.h"
28 #include "kyra/resource/resource.h"
29 #include "kyra/resource/resource_segacd.h"
30 #include "kyra/sequence/seqplayer_eob_segacd.h"
31 #include "common/system.h"
32
33 namespace Kyra {
34
SegaSequencePlayer(EoBEngine * vm,Screen_EoB * screen,SegaCDResource * res)35 SegaSequencePlayer::SegaSequencePlayer(EoBEngine *vm, Screen_EoB *screen, SegaCDResource *res) : _vm(vm), _screen(screen), _res(res), _tileSets(0), _debugResyncCnt(0), _speechAnimType(0),
36 _playingID(1), _waterdeepScene(0), _playSpeechAnimation(0), _frameTimer(0), _waterdeepSceneTimer(0), _speechAnimTimer(0), _speechAnimNo(0), _speechAnimFrame(0),
37 _newTrack(-1), _pauseStart(0), _fastForward(false), _renderer(_screen->sega_getRenderer()), _animator(_screen->sega_getAnimator()) {
38 #define SQOPC(x) _opcodes.push_back(new SQOpcode(this, &SegaSequencePlayer::x, #x))
39 SQOPC(s_initDrawObject);
40 SQOPC(s_drawTileSet);
41 SQOPC(s_loadTileDataSingle);
42 SQOPC(s_drawTileSetCustom);
43 SQOPC(s_drawTileSetCustomTopToBottom);
44 SQOPC(s_fillRect);
45 SQOPC(s_void);
46 SQOPC(s_initSprite);
47 SQOPC(s_removeSprite);
48 SQOPC(s_displayTextJp);
49 SQOPC(s_fadeToNeutral);
50 SQOPC(s_fadeToBlack);
51 SQOPC(s_fadeToNeutral2);
52 SQOPC(s_fadeToWhite);
53 SQOPC(s_setPalette);
54 SQOPC(s_vScroll);
55 SQOPC(s_hScroll);
56 SQOPC(s_paletteOps);
57 SQOPC(s_initSpriteCustomCoords);
58 SQOPC(s_fillRectWithPattern);
59 SQOPC(s_loadTileDataSeries);
60 SQOPC(s_drawTileSetSeries);
61 SQOPC(s_initSpriteSeries);
62 SQOPC(s_initSpriteCustom);
63 SQOPC(s_drawTileSetCustomCoords);
64 SQOPC(s_waitForPaletteFade);
65 SQOPC(s_clearSprites);
66 SQOPC(s_moveSprites2);
67 SQOPC(s_moveSprites);
68 SQOPC(s_moveMorphSprite);
69 SQOPC(s_unpauseCD);
70 SQOPC(s_toggleWaterDeepAnimations);
71 SQOPC(s_assignSpeechAnimGraphics);
72 SQOPC(s_toggleSpeechAnimation);
73 SQOPC(s_orbZoomEffect);
74 SQOPC(s_stopCD);
75 SQOPC(s_playCD);
76 SQOPC(s_displayTextEn);
77 SQOPC(s_loadCustomPalettes);
78 SQOPC(s_playSoundEffect);
79 #undef SQOPC
80
81 _scrollManager = new ScrollManager(_renderer);
82 assert(_scrollManager);
83 _tileSets = new TileSet[100];
84 assert(_tileSets);
85 memset(_tileSets, 0, 100 * sizeof(TileSet));
86 _drawObjects = new DrawObject[100];
87 assert(_drawObjects);
88 memset(_drawObjects, 0, 100 * sizeof(DrawObject));
89
90 memset(_speechAnimDrawOps, 0, sizeof(_speechAnimDrawOps));
91
92 _scaleSrcBuffer = new uint8[0x5800];
93 assert(_scaleSrcBuffer);
94 memset(_scaleSrcBuffer, 0, 0x5800 * sizeof(uint8));
95 _scaleOutBuffer = new uint8[0x5800];
96 assert(_scaleOutBuffer);
97 memset(_scaleOutBuffer, 0, 0x5800 * sizeof(uint8));
98 _scaleStampMap = new uint16[0x100];
99 assert(_scaleStampMap);
100 memset(_scaleStampMap, 0, 0x100 * sizeof(uint16));
101 _scaleTraceVectors = new uint16[0x580];
102 assert(_scaleTraceVectors);
103 memset(_scaleTraceVectors, 0, 0x580 * sizeof(uint16));
104
105 int temp;
106 _wdDsX = _vm->staticres()->loadRawDataBe16(kEoB1IntroWdDsX, temp);
107 _wdDsY = _vm->staticres()->loadRawData(kEoB1IntroWdDsY, temp);
108 _wdAnimSprites = _vm->staticres()->loadRawData(kEoB1WdAnimSprites, temp);
109 _speechAnimData = _vm->staticres()->loadRawData(kEoB1SpeechAnimData, temp);
110 _cdaTracks = _vm->staticres()->loadRawData(kEoB1SequenceTrackMap, temp);
111 for (int i = 0; i < 6; ++i)
112 _patternTables[i] = _vm->staticres()->loadRawDataBe16(kEoB1PatternTable0 + i, temp);
113 }
114
~SegaSequencePlayer()115 SegaSequencePlayer::~SegaSequencePlayer() {
116 delete[] _drawObjects;
117 delete[] _tileSets;
118 delete[] _scaleSrcBuffer;
119 delete[] _scaleOutBuffer;
120 delete[] _scaleStampMap;
121 delete[] _scaleTraceVectors;
122
123 for (Common::Array<SQOpcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
124 delete (*i);
125
126 delete _scrollManager;
127 }
128
play(int id)129 bool SegaSequencePlayer::play(int id) {
130 _renderer->render(0);
131 _screen->sega_fadeToBlack(2);
132 _screen->clearPage(0);
133
134 _animator->clearSprites();
135 _scrollManager->setVScrollTimers(0, 1, 0, 0, 1, 0);
136 _scrollManager->setHScrollTimers(0, 1, 0, 0, 1, 0);
137 _vm->_txt->clearDim(2);
138
139 _renderer->fillRectWithTiles(2, 0, 0, 40, 28, 0xE6C2);
140 _renderer->fillRectWithTiles(0, 0, 0, 64, 42, 0);
141 _renderer->fillRectWithTiles(1, 0, 0, 64, 28, 0);
142 _renderer->fillRectWithTiles(2, 1, (id == 53 || id == 54) ? 22 : 20, 38, 6, 0xE51C, true);
143
144 _debugResyncCnt = 0;
145 _playingID = id;
146 _newTrack = -1;
147
148 _vm->_allowSkip = true;
149 _vm->resetSkipFlag();
150
151 for (bool runLoop = true; runLoop && !(_vm->shouldQuit() || _vm->skipFlag()); ) {
152 uint32 offset = (id - 1) * 0x3C000;
153 if (id >= 54)
154 offset -= 0x8000;
155 if (id >= 55)
156 offset -= 0x18000;
157
158 uint32 size = (id == 53) ? 0x34000 : ((id == 54) ? 0x24000 : 0x3C000);
159
160 if (!_res->loadContainer("VISUAL", offset, size))
161 return false;
162
163 Common::SeekableReadStreamEndian *in = _res->resStreamEndian(0);
164 if (!in)
165 return false;
166 _screen->sega_loadCustomPaletteData(in);
167 delete in;
168
169 _screen->sega_selectPalette(31, 0, false);
170 _screen->sega_selectPalette(32, 1, false);
171 _screen->sega_selectPalette(30, 3, false);
172
173 in = _res->resStreamEndian(2);
174 if (!in)
175 return false;
176 uint32 len = in->size();
177 uint8 *tileData = new uint8[len];
178 in->read(tileData, len);
179 delete in;
180
181 in = _res->resStreamEndian(1);
182 if (!in)
183 return false;
184 memset(_tileSets, 0, 100 * sizeof(TileSet));
185 for (TileSet *t = _tileSets; !in->eos(); ++t) {
186 uint32 off = in->readUint32();
187 if ((off & 0xFFFF) == 0xFFFF)
188 break;
189 t->data = (const uint16*)(tileData + off);
190 t->width = in->readUint16();
191 t->height = in->readUint16();
192 }
193 delete in;
194
195 in = _res->resStreamEndian(3);
196 if (!in)
197 return false;
198 len = in->size();
199 uint8 *frames = new uint8[len];
200 in->read(frames, len);
201 delete in;
202
203 if (id == 53)
204 _vm->delay(2000);
205 else if (id == 55 || id == 56)
206 _vm->snd_playSong(2);
207
208 run(frames);
209
210 delete[] frames;
211 delete[] tileData;
212 if (++id != 54)
213 runLoop = false;
214 }
215
216 debugC(3, kDebugLevelSequence, "Total millis out of sync: %d", _debugResyncCnt);
217
218 if (_vm->shouldQuit() || _vm->skipFlag()) {
219 if (!(_playingID == 55 || _playingID == 56))
220 _vm->snd_stopSound();
221 }
222
223 _vm->_allowSkip = false;
224 _vm->resetSkipFlag();
225
226 _playingID = 1;
227 return true;
228 }
229
pause(bool pause)230 void SegaSequencePlayer::pause(bool pause) {
231 if (pause)
232 _pauseStart = _vm->_system->getMillis();
233 else
234 _frameTimer += (_vm->_system->getMillis() - _pauseStart);
235 }
236
run(const uint8 * data)237 void SegaSequencePlayer::run(const uint8 *data) {
238 _waterdeepScene = _playSpeechAnimation = false;
239 _frameTimer = _vm->_system->getMillis();
240 _fastForward = false;
241
242 for (bool runLoop = true; runLoop; ) {
243 // In case of a skip or shouldQuit event we fastforward through the sequence instead of just aborting. This way
244 // we ensure that we have the same palettes and scroll offsets as if the sequence had been played normally.
245 _fastForward = _vm->shouldQuit() || _vm->skipFlag();
246 uint16 frameSize = READ_BE_UINT16(data);
247 if (!frameSize)
248 return;
249
250 uint32 frameStart = _vm->_system->getMillis();
251 uint16 timeStamp = READ_BE_UINT16(data + 2);
252 uint32 nextFrame = _frameTimer + (timeStamp * 16667) / 1000;
253 bool insertDelay = false;
254
255 if (_vm->_system->getMillis() >= nextFrame || _fastForward) {
256 debugC(5, kDebugLevelSequence, "SeqPlayer: Timestamp %08d", timeStamp);
257 for (uint16 timeStamp2 = timeStamp; timeStamp2 == timeStamp; ) {
258 uint16 op = READ_BE_UINT16(data + 4);
259 _opcodes[op]->run(data + 6);
260 _screen->clearPage(0);
261
262 frameSize = READ_BE_UINT16(data);
263 data += (frameSize & ~1);
264
265 timeStamp2 = READ_BE_UINT16(data + 2);
266 }
267 } else {
268 insertDelay = true;
269 }
270
271 if (_waterdeepScene)
272 animateWaterdeepScene();
273
274 if (_playSpeechAnimation)
275 updateSpeechAnimations();
276
277 _animator->update();
278
279 if (_fastForward) {
280 _scrollManager->fastForward();
281 } else {
282 _scrollManager->updateScrollTimers();
283 _renderer->render(0);
284 _screen->sega_updatePaletteFaders(-1);
285 _screen->updateScreen();
286 }
287
288 if (insertDelay) {
289 int diff = _vm->_system->getMillis() - (frameStart + 16);
290 if (diff < 0)
291 _vm->delay((uint32)-diff);
292 }
293 }
294 }
295
animateWaterdeepScene()296 void SegaSequencePlayer::animateWaterdeepScene() {
297 if (--_waterdeepSceneTimer > 0)
298 return;
299 _waterdeepSceneTimer = 5;
300
301 for (int i = 0; i < 5; ++i) {
302 int rnd = _vm->_rnd.getRandomNumber(30);
303 DrawObject *d = &_drawObjects[10 + rnd];
304 _animator->initSprite(_wdAnimSprites[rnd] + 3, _wdDsX[_wdAnimSprites[rnd]] - 80, _wdDsY[_wdAnimSprites[rnd]] + 32, d->nTblVal, d->addr);
305 }
306 }
307
updateSpeechAnimations()308 void SegaSequencePlayer::updateSpeechAnimations() {
309 if (--_speechAnimTimer > 0)
310 return;
311
312 int animDrawOp = -1;
313
314 for (bool runLoop = true; runLoop; ) {
315 if (_speechAnimTimer == 0) {
316 const uint8 *pos = &_speechAnimData[_speechAnimNo * 12 + _speechAnimFrame];
317 _speechAnimTimer = pos[1];
318 if (pos[0] != 0xFF) {
319 animDrawOp = pos[0];
320 runLoop = false;
321 }
322 _speechAnimFrame += 2;
323 } else {
324 _speechAnimTimer = 0;
325 }
326
327 if (animDrawOp == -1) {
328 _speechAnimNo = (_speechAnimType == 2) ? _vm->_rnd.getRandomNumberRng(4, 6) : _vm->_rnd.getRandomNumberRng(0, 3);
329 _speechAnimFrame = 0;
330 }
331 }
332
333 updateSpeechAnimGraphics(animDrawOp);
334 }
335
updateSpeechAnimGraphics(int animDrawOp)336 void SegaSequencePlayer::updateSpeechAnimGraphics(int animDrawOp) {
337 assert(animDrawOp < 6);
338 DrawObject *d = &_drawObjects[_speechAnimDrawOps[animDrawOp * 2]];
339 if (_speechAnimDrawOps[animDrawOp * 2 + 1])
340 _renderer->loadToVRAM(d->tileData, (d->width * d->height) << 5, (d->nTblVal & 0x7FF) << 5);
341 else
342 _renderer->fillRectWithTiles(d->addr, d->x, d->y, d->width, d->height, d->nTblVal, true);
343
344 }
345
346 #define ARG(x) READ_BE_UINT16(pos + x)
347 #define S_ARG(x) (int16)ARG(x)
348
s_initDrawObject(const uint8 * pos)349 void SegaSequencePlayer::s_initDrawObject(const uint8 *pos) {
350 int idx = ARG(0);
351 DrawObject *w = &_drawObjects[idx];
352 TileSet *t = &_tileSets[idx];
353 w->agg = ARG(2);
354 w->tileData = t->data;
355 w->width = t->width;
356 w->height = t->height;
357 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));
358 w->x = ARG(6);
359 w->y = ARG(8);
360 w->addr = ARG(10);
361 }
362
s_drawTileSet(const uint8 * pos)363 void SegaSequencePlayer::s_drawTileSet(const uint8 *pos) {
364 DrawObject *w = &_drawObjects[ARG(0)];
365 _renderer->fillRectWithTiles(w->addr, w->x, w->y, w->width, w->height, w->nTblVal, true);
366 }
367
s_loadTileDataSingle(const uint8 * pos)368 void SegaSequencePlayer::s_loadTileDataSingle(const uint8 *pos) {
369 DrawObject *w = &_drawObjects[ARG(0)];
370 _renderer->loadToVRAM(w->tileData, (w->width * w-> height) << 5, (w->nTblVal & 0x7FF) << 5);
371 }
372
s_drawTileSetCustom(const uint8 * pos)373 void SegaSequencePlayer::s_drawTileSetCustom(const uint8 *pos) {
374 _renderer->fillRectWithTiles(ARG(8), ARG(0), ARG(2), ARG(4), ARG(6), ARG(10), true);
375 }
376
s_drawTileSetCustomTopToBottom(const uint8 * pos)377 void SegaSequencePlayer::s_drawTileSetCustomTopToBottom(const uint8 *pos) {
378 _renderer->fillRectWithTiles(ARG(8), ARG(0), ARG(2), ARG(4), ARG(6), ARG(10), true, true);
379 }
380
s_fillRect(const uint8 * pos)381 void SegaSequencePlayer::s_fillRect(const uint8 *pos) {
382 _renderer->fillRectWithTiles(ARG(8), ARG(0), ARG(2), ARG(4), ARG(6), ARG(10));
383 }
384
s_initSprite(const uint8 * pos)385 void SegaSequencePlayer::s_initSprite(const uint8 *pos) {
386 DrawObject *d = &_drawObjects[ARG(2)];
387 _animator->initSprite(ARG(0), d->x << 3, d->y << 3, d->nTblVal, d->addr);
388 }
389
s_removeSprite(const uint8 * pos)390 void SegaSequencePlayer::s_removeSprite(const uint8 *pos) {
391 _animator->initSprite(ARG(0), 0x4000, 0, 0, 0);
392 }
393
s_displayTextJp(const uint8 * pos)394 void SegaSequencePlayer::s_displayTextJp(const uint8 *pos) {
395 if (_vm->gameFlags().lang != Common::JA_JPN)
396 return;
397
398 const char *str = (const char*)pos;
399 _vm->_txt->clearDim(2);
400
401 int w = _screen->getTextWidth(str);
402 int x = 0;
403 int y = 0;
404
405 if (w < 288) {
406 x = 152 - (w >> 1);
407 y = 16;
408 }
409
410 _vm->_txt->printShadedText(str, x, y, -1, 0xEE);
411 }
412
s_fadeToNeutral(const uint8 * pos)413 void SegaSequencePlayer::s_fadeToNeutral(const uint8 *pos) {
414 _screen->sega_fadeToNeutral(ARG(0));
415 }
416
s_fadeToBlack(const uint8 * pos)417 void SegaSequencePlayer::s_fadeToBlack(const uint8 *pos) {
418 _screen->sega_fadeToBlack(ARG(0));
419 }
420
s_fadeToNeutral2(const uint8 * pos)421 void SegaSequencePlayer::s_fadeToNeutral2(const uint8 *pos) {
422 _screen->sega_fadeToNeutral(ARG(0));
423 }
424
s_fadeToWhite(const uint8 * pos)425 void SegaSequencePlayer::s_fadeToWhite(const uint8 *pos) {
426 _screen->sega_fadeToWhite(ARG(0));
427 }
428
s_setPalette(const uint8 * pos)429 void SegaSequencePlayer::s_setPalette(const uint8 *pos) {
430 _screen->sega_selectPalette(ARG(2) + 31, ARG(0), false);
431 }
432
s_vScroll(const uint8 * pos)433 void SegaSequencePlayer::s_vScroll(const uint8 *pos) {
434 _scrollManager->setVScrollTimers(ARG(0), S_ARG(2), ARG(4), ARG(6), S_ARG(8), ARG(10));
435 }
436
s_hScroll(const uint8 * pos)437 void SegaSequencePlayer::s_hScroll(const uint8 *pos) {
438 _scrollManager->setHScrollTimers(ARG(0), S_ARG(2), ARG(4), ARG(6), S_ARG(8), ARG(10));
439 }
440
s_paletteOps(const uint8 * pos)441 void SegaSequencePlayer::s_paletteOps(const uint8 *pos) {
442 _screen->sega_paletteOps(S_ARG(0), S_ARG(2), S_ARG(4));
443 }
444
s_initSpriteCustomCoords(const uint8 * pos)445 void SegaSequencePlayer::s_initSpriteCustomCoords(const uint8 *pos) {
446 DrawObject *d = &_drawObjects[ARG(2)];
447 _animator->initSprite(ARG(0), S_ARG(4), S_ARG(6), d->nTblVal, d->addr);
448 }
449
s_fillRectWithPattern(const uint8 * pos)450 void SegaSequencePlayer::s_fillRectWithPattern(const uint8 *pos) {
451 assert(ARG(12) < 6);
452 _renderer->fillRectWithTiles(ARG(8), ARG(0), ARG(2), ARG(4), ARG(6), ARG(10), false, false, _patternTables[ARG(12)]);
453 }
454
s_loadTileDataSeries(const uint8 * pos)455 void SegaSequencePlayer::s_loadTileDataSeries(const uint8 *pos) {
456 for (DrawObject *d = &_drawObjects[ARG(0)]; d != &_drawObjects[ARG(0) + ARG(2)]; ++d)
457 _renderer->loadToVRAM(d->tileData, (d->width * d->height) << 5, (d->nTblVal & 0x7FF) << 5);
458 }
459
s_drawTileSetSeries(const uint8 * pos)460 void SegaSequencePlayer::s_drawTileSetSeries(const uint8 *pos) {
461 for (DrawObject *d = &_drawObjects[ARG(0)]; d != &_drawObjects[ARG(0) + ARG(2)]; ++d)
462 _renderer->fillRectWithTiles(d->addr, d->x, d->y, d->width, d->height, d->nTblVal, true);
463 }
464
s_initSpriteSeries(const uint8 * pos)465 void SegaSequencePlayer::s_initSpriteSeries(const uint8 *pos) {
466 int id = ARG(0);
467 for (DrawObject *d = &_drawObjects[ARG(2)]; d != &_drawObjects[ARG(2) + ARG(4)]; ++d)
468 _animator->initSprite(id++, d->x << 3, d->y << 3, d->nTblVal, d->addr);
469 }
470
s_initSpriteCustom(const uint8 * pos)471 void SegaSequencePlayer::s_initSpriteCustom(const uint8 *pos) {
472 _animator->initSprite(ARG(0), S_ARG(4), S_ARG(6), ARG(2), ARG(8));
473 }
474
s_drawTileSetCustomCoords(const uint8 * pos)475 void SegaSequencePlayer::s_drawTileSetCustomCoords(const uint8 *pos) {
476 DrawObject *w = &_drawObjects[ARG(0)];
477 _renderer->fillRectWithTiles(w->addr, ARG(2), ARG(4), w->width, w->height, w->nTblVal, true);
478 }
479
s_waitForPaletteFade(const uint8 *)480 void SegaSequencePlayer::s_waitForPaletteFade(const uint8*) {
481 _screen->sega_fadePalette(0, 0, -1, true, true);
482 }
483
s_clearSprites(const uint8 *)484 void SegaSequencePlayer::s_clearSprites(const uint8*) {
485 _animator->clearSprites();
486 }
487
s_moveSprites2(const uint8 * pos)488 void SegaSequencePlayer::s_moveSprites2(const uint8 *pos) {
489 _animator->moveSprites2(ARG(0), ARG(2), S_ARG(4), S_ARG(6));
490 }
491
s_moveSprites(const uint8 * pos)492 void SegaSequencePlayer::s_moveSprites(const uint8 *pos) {
493 _animator->moveSprites(ARG(0), ARG(2), S_ARG(4), S_ARG(6));
494 }
495
s_moveMorphSprite(const uint8 * pos)496 void SegaSequencePlayer::s_moveMorphSprite(const uint8 *pos) {
497 _animator->moveMorphSprite(ARG(0), ARG(2), S_ARG(4), S_ARG(6));
498 }
499
s_unpauseCD(const uint8 * pos)500 void SegaSequencePlayer::s_unpauseCD(const uint8 *pos) {
501 // We don't support this in our AudioCD API. The original will use s_playCD() to seek to a track,
502 // wait for the seek to finish and then pause. It then uses this opcode to actually start the playback.
503 // Since s_playCD() and s_unpauseCD() are not always called on the same frame I emulate the original
504 // behavior like this.
505 if (_newTrack != -1)
506 _vm->snd_playSong(_newTrack, false);
507 _newTrack = -1;
508 }
509
s_toggleWaterDeepAnimations(const uint8 * pos)510 void SegaSequencePlayer::s_toggleWaterDeepAnimations(const uint8 *pos) {
511 _waterdeepScene = ARG(0);
512 _waterdeepSceneTimer = 0;
513 }
514
s_assignSpeechAnimGraphics(const uint8 * pos)515 void SegaSequencePlayer::s_assignSpeechAnimGraphics(const uint8 *pos) {
516 if (ARG(0) == 100) {
517 _speechAnimType = ARG(2);
518 } else {
519 assert(ARG(0) < 6);
520 _speechAnimDrawOps[ARG(0) * 2] = ARG(2);
521 _speechAnimDrawOps[ARG(0) * 2 + 1] = ARG(4);
522 }
523 }
524
s_toggleSpeechAnimation(const uint8 * pos)525 void SegaSequencePlayer::s_toggleSpeechAnimation(const uint8 *pos) {
526 _playSpeechAnimation = ARG(0);
527 _speechAnimTimer = 0;
528 if (_playSpeechAnimation)
529 updateSpeechAnimGraphics(0);
530 }
531
s_orbZoomEffect(const uint8 *)532 void SegaSequencePlayer::s_orbZoomEffect(const uint8*) {
533 _renderer->memsetVRAM(0x2AA0, 0, 0x5800);
534 DrawObject *d = &_drawObjects[16];
535 memset(_scaleSrcBuffer, 0, 0x5800);
536 memcpy(_scaleSrcBuffer + 128, d->tileData, (d->width * d->height) << 5);
537 _renderer->fillRectWithTiles(0, 4, 0, 32, 22, 0x2155, true, true);
538
539 memset(_scaleStampMap, 0, 0x100 * sizeof(uint16));
540 uint16 *dst2 = &_scaleStampMap[(7 << 4) + 6];
541 uint16 t = 1;
542 for (int h = 0; h < 9; ++h) {
543 uint16 *dst = dst2;
544 for (int w = 0; w < 10; ++w)
545 *dst++ = t++;
546 dst2 += 16;
547 }
548
549 int step = 512;
550 for (int i = 0; i < 90; ++i) {
551 uint32 nextFrame = _vm->_system->getMillis() + 64;
552 uint16 *dst = _scaleTraceVectors;
553 uint32 xtr = 0x58000 - step * 128;
554 uint32 ytr = 0x59000 - step * 88;
555 for (int ii = 0; ii < 176; ++ii) {
556 *dst++ = xtr >> 8;
557 *dst++ = ytr >> 8;
558 *dst++ = step;
559 *dst++ = 0;
560 ytr += step;
561 }
562 memset(_scaleOutBuffer, 0, 0x5800);
563 _screen->sega_gfxScale(_scaleOutBuffer, 256, 176, 21, _scaleSrcBuffer, _scaleStampMap, _scaleTraceVectors);
564 _renderer->loadToVRAM(_scaleOutBuffer, 0x5800, 0x2AA0);
565
566 if (!_fastForward) {
567 _renderer->render(0);
568 _screen->updateScreen();
569 _vm->delayUntil(nextFrame);
570 }
571
572 step += 16;
573 }
574 }
575
s_stopCD(const uint8 *)576 void SegaSequencePlayer::s_stopCD(const uint8*) {
577 _vm->snd_stopSound();
578 }
579
s_playCD(const uint8 * pos)580 void SegaSequencePlayer::s_playCD(const uint8 *pos) {
581 int track = _cdaTracks[ARG(0)];
582
583 // The original seeks to the requested CD track here and pauses it.
584 // The actual playback is then triggered via s_unpauseCD().
585 if (track)
586 _newTrack = track;
587 _vm->snd_stopSound();
588 }
589
s_displayTextEn(const uint8 * pos)590 void SegaSequencePlayer::s_displayTextEn(const uint8 *pos) {
591 if (_vm->gameFlags().lang == Common::JA_JPN)
592 return;
593
594 const char *str = (const char*)pos;
595 _vm->_txt->clearDim(2);
596
597 if (_playingID >= 55) {
598 int cs = _screen->setFontStyles(_screen->_currentFont, Font::kStyleFullWidth);
599 _vm->_txt->printShadedText(str, 0, 0, -1, 0xEE);
600 _screen->setFontStyles(_screen->_currentFont, cs);
601 } else {
602 int x = 0;
603 int y = 0;
604
605 if (_playingID >= 53) {
606 x = 152 - (_screen->getTextWidth(str) >> 1);
607 y = 16;
608 }
609
610 _vm->_txt->printShadedText(str, x, y, -1, 0xEE);
611 }
612 }
613
s_loadCustomPalettes(const uint8 * pos)614 void SegaSequencePlayer::s_loadCustomPalettes(const uint8 *pos) {
615 Common::SeekableReadStreamEndian *in = _res->resStreamEndian(0);
616 in->seek(ARG(0) << 5);
617 _screen->sega_loadCustomPaletteData(in);
618 delete in;
619 }
620
s_playSoundEffect(const uint8 * pos)621 void SegaSequencePlayer::s_playSoundEffect(const uint8 *pos) {
622 if (!_fastForward)
623 _vm->snd_playSoundEffect(ARG(0));
624 }
625
626 #undef S_ARG
627 #undef ARG
628
629 } // End of namespace Kyra
630
631 #endif // ENABLE_EOB
632