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