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 #include "drascula/drascula.h"
24 #include "graphics/surface.h"
25
26 #include "common/stream.h"
27 #include "common/textconsole.h"
28
29 namespace Drascula {
30
allocMemory()31 void DrasculaEngine::allocMemory() {
32 // FIXME: decodeOffset writes beyond 64000, so this
33 // buffer has been initialized to 64256 bytes (like
34 // the original did with the MiVideoSSN buffer)
35 screenSurface = (byte *)malloc(64256);
36 assert(screenSurface);
37 frontSurface = (byte *)malloc(64000);
38 assert(frontSurface);
39 backSurface = (byte *)malloc(64000);
40 assert(backSurface);
41 bgSurface = (byte *)malloc(64000);
42 assert(bgSurface);
43 drawSurface2 = (byte *)malloc(64000);
44 assert(drawSurface2);
45 drawSurface3 = (byte *)malloc(64000);
46 assert(drawSurface3);
47 tableSurface = (byte *)malloc(64000);
48 assert(tableSurface);
49 extraSurface = (byte *)malloc(64000);
50 assert(extraSurface);
51 crosshairCursor = (byte *)malloc(OBJWIDTH * OBJHEIGHT);
52 assert(crosshairCursor);
53 mouseCursor = (byte *)malloc(OBJWIDTH * OBJHEIGHT);
54 assert(mouseCursor);
55 cursorSurface = (byte *)malloc(64000);
56 }
57
freeMemory()58 void DrasculaEngine::freeMemory() {
59 free(screenSurface);
60 free(bgSurface);
61 free(backSurface);
62 free(drawSurface2);
63 free(tableSurface);
64 free(drawSurface3);
65 free(extraSurface);
66 free(frontSurface);
67 free(crosshairCursor);
68 free(mouseCursor);
69 free(cursorSurface);
70 }
71
moveCursor()72 void DrasculaEngine::moveCursor() {
73 copyBackground();
74
75 updateRefresh_pre();
76 moveCharacters();
77 updateRefresh();
78
79 if (!strcmp(textName, _textmisc[3]) && _hasName) {
80 if (_color != kColorRed && !_menuScreen)
81 color_abc(kColorRed);
82 } else if (!_menuScreen && _color != kColorLightGreen)
83 color_abc(kColorLightGreen);
84 if (_hasName && !_menuScreen)
85 centerText(textName, _mouseX, _mouseY);
86 if (_menuScreen)
87 showMenu();
88 else if (_menuBar)
89 clearMenu();
90 }
91
loadPic(const char * NamePcc,byte * targetSurface,int colorCount)92 void DrasculaEngine::loadPic(const char *NamePcc, byte *targetSurface, int colorCount) {
93 debug(5, "loadPic(%s)", NamePcc);
94
95 uint dataSize = 0;
96 byte *pcxData;
97
98 Common::SeekableReadStream *stream = _archives.open(NamePcc);
99 if (!stream)
100 error("missing game data %s %c", NamePcc, 7);
101
102 dataSize = stream->size() - 128 - (256 * 3);
103 pcxData = (byte *)malloc(dataSize);
104
105 stream->seek(128, SEEK_SET);
106 stream->read(pcxData, dataSize);
107
108 decodeRLE(pcxData, targetSurface);
109 free(pcxData);
110
111 for (int i = 0; i < 256; i++) {
112 cPal[i * 3 + 0] = stream->readByte();
113 cPal[i * 3 + 1] = stream->readByte();
114 cPal[i * 3 + 2] = stream->readByte();
115 }
116
117 delete stream;
118
119 setRGB((byte *)cPal, colorCount);
120 }
121
showFrame(Common::SeekableReadStream * stream,bool firstFrame)122 void DrasculaEngine::showFrame(Common::SeekableReadStream *stream, bool firstFrame) {
123 int dataSize = stream->readSint32LE();
124 byte *pcxData = (byte *)malloc(dataSize);
125 stream->read(pcxData, dataSize);
126
127 for (int i = 0; i < 256; i++) {
128 cPal[i * 3 + 0] = stream->readByte();
129 cPal[i * 3 + 1] = stream->readByte();
130 cPal[i * 3 + 2] = stream->readByte();
131 }
132
133 byte *prevFrame = (byte *)malloc(64000);
134 Graphics::Surface *screenSurf = _system->lockScreen();
135 byte *screenBuffer = (byte *)screenSurf->getPixels();
136 uint16 screenPitch = screenSurf->pitch;
137 for (int y = 0; y < 200; y++) {
138 memcpy(prevFrame+y*320, screenBuffer+y*screenPitch, 320);
139 }
140
141 decodeRLE(pcxData, screenBuffer, screenPitch);
142 free(pcxData);
143
144 if (!firstFrame)
145 mixVideo(screenBuffer, prevFrame, screenPitch);
146
147 _system->unlockScreen();
148 _system->updateScreen();
149
150 if (firstFrame)
151 setPalette(cPal);
152
153 free(prevFrame);
154 }
155
copyBackground(int xorg,int yorg,int xdes,int ydes,int width,int height,byte * src,byte * dest)156 void DrasculaEngine::copyBackground(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *src, byte *dest) {
157 debug(5, "DrasculaEngine::copyBackground(xorg:%d, yorg:%d, xdes:%d, ydes:%d width:%d height:%d, src, dest)", xorg, yorg, xdes, ydes, width,height);
158 dest += xdes + ydes * 320;
159 src += xorg + yorg * 320;
160 /* Unoptimized code
161 for (int x = 0; x < height; x++) {
162 memcpy(dest + 320 * x, src + 320 * x, width);
163 } */
164
165 // A bit more optimized code, thanks to Fingolfin
166 // Uses 2 less registers and performs 2 less multiplications
167 int x = height;
168 while (x--) {
169 memcpy(dest, src, width);
170 dest += 320;
171 src += 320;
172 }
173 }
174
copyRect(int xorg,int yorg,int xdes,int ydes,int width,int height,byte * src,byte * dest)175 void DrasculaEngine::copyRect(int xorg, int yorg, int xdes, int ydes, int width,
176 int height, byte *src, byte *dest) {
177 int y, x;
178
179 //
180 if (ydes < 0) {
181 yorg += -ydes;
182 height += ydes;
183 ydes = 0;
184 }
185 if (xdes < 0) {
186 xorg += -xdes;
187 width += xdes;
188 xdes = 0;
189 }
190 if ((xdes + width) > 319)
191 width -= (xdes + width) - 320;
192 if ((ydes + height) > 199)
193 height -= (ydes + height) - 200;
194 //
195
196 dest += xdes + ydes * 320;
197 src += xorg + yorg * 320;
198
199 assert(xorg >= 0);
200 assert(yorg >= 0);
201 assert(xorg + width <= 320);
202 assert(yorg + height <= 200);
203
204 int ptr = 0;
205 for (y = 0; y < height; y++) {
206 for (x = 0; x < width; x++) {
207 if (src[ptr] != 255)
208 dest[ptr] = src[ptr];
209 ptr++;
210 }
211 ptr += 320 - width;
212 }
213
214 }
215
updateScreen(int xorg,int yorg,int xdes,int ydes,int width,int height,byte * buffer)216 void DrasculaEngine::updateScreen(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *buffer) {
217 _system->copyRectToScreen(buffer + xorg + yorg * 320, 320, xdes, ydes, width, height);
218 _system->updateScreen();
219 }
220
print_abc(const char * said,int screenX,int screenY)221 void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) {
222 int letterY = 0, letterX = 0, i;
223 uint len = strlen(said);
224 byte c;
225
226 byte *srcSurface = tableSurface;
227 if (_lang == kSpanish && currentChapter == 6)
228 srcSurface = extraSurface;
229
230 for (uint h = 0; h < len; h++) {
231 c = toupper(said[h]);
232
233 for (i = 0; i < _charMapSize; i++) {
234 if (c == _charMap[i].inChar) {
235 letterX = _charMap[i].mappedChar;
236
237 switch (_charMap[i].charType) {
238 case 0: // letters
239 default:
240 letterY = (_lang == kSpanish) ? 149 : 158;
241 break;
242 case 1: // signs
243 letterY = (_lang == kSpanish) ? 160 : 169;
244 break;
245 case 2: // accented
246 letterY = 180;
247 break;
248 } // switch
249 break;
250 } // if
251 } // for
252
253 copyRect(letterX, letterY, screenX, screenY,
254 CHAR_WIDTH, CHAR_HEIGHT, srcSurface, screenSurface);
255
256 screenX = screenX + CHAR_WIDTH;
257 if (screenX > 317) {
258 screenX = 0;
259 screenY = screenY + CHAR_HEIGHT + 2;
260 }
261 } // for
262 }
263
print_abc_opc(const char * said,int screenY,int game)264 int DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) {
265 int signY, letterY, letterX = 0;
266 uint len = strlen(said);
267
268 int screenX = 1;
269 int lines = 1;
270
271 for (uint h = 0; h < len; h++) {
272 int wordLength;
273
274 // Look ahead to the end of the word.
275 wordLength = 0;
276 int pos = h;
277 while (said[pos] && said[pos] != ' ') {
278 wordLength++;
279 pos++;
280 }
281
282 if (screenX + wordLength * CHAR_WIDTH_OPC > 317) {
283 screenX = 0;
284 screenY += (CHAR_HEIGHT + 2);
285 lines++;
286 }
287
288 if (game == 1) {
289 letterY = 6;
290 signY = 15;
291 } else if (game == 3) {
292 letterY = 56;
293 signY = 65;
294 } else {
295 letterY = 31;
296 signY = 40;
297 }
298
299 byte c = toupper(said[h]);
300
301 // WORKAROUND: Even original did not process it correctly
302 // Fixes apostrophe rendering
303 if (_lang != kSpanish)
304 if (c == '\'')
305 c = (byte)'\244';
306
307 for (int i = 0; i < _charMapSize; i++) {
308 if (c == _charMap[i].inChar) {
309 // Convert the mapped char of the normal font to the
310 // mapped char of the dialogue font
311
312 int multiplier = (_charMap[i].mappedChar - 6) / 9;
313
314 letterX = multiplier * 7 + 10;
315
316 if (_charMap[i].charType > 0)
317 letterY = signY;
318 break;
319 } // if
320 } // for
321
322 copyRect(letterX, letterY, screenX, screenY,
323 CHAR_WIDTH_OPC, CHAR_HEIGHT_OPC, backSurface, screenSurface);
324
325 screenX = screenX + CHAR_WIDTH_OPC;
326 }
327
328 return lines;
329 }
330
textFitsCentered(char * text,int x)331 bool DrasculaEngine::textFitsCentered(char *text, int x) {
332 int textLen = strlen(text);
333 int halfLen = (textLen / 2) * CHAR_WIDTH;
334
335 //if (x > 160)
336 // x = 315 - x;
337 //return (halfLen <= x);
338
339 // The commented out code above is what the original engine is doing. Instead of testing the
340 // upper bound if x is greater than 160 it takes the complement to 315 and test only the lower
341 // bounds.
342 // Also note that since it does an integer division to compute the half length of the string,
343 // in the case where the string has an odd number of characters there is one more character to
344 // the right than to the left. If the string center is beyond 160, this is taken care of by
345 // taking the complement to 315 instead of 320. But if the string center is close to the screen
346 // center, but not greater than 160, this can lead to the string being accepted despite having
347 // one character beyond the right edge of the screen.
348 // In ScummVM we therefore also test the right edge, which leads to differences
349 // with the original engine, but for the better.
350 if (x > 160)
351 return (315 - x - halfLen >= 0);
352 return (x - halfLen >= 0 && x + halfLen + (textLen % 2) * CHAR_WIDTH <= 320);
353 }
354
centerText(const char * message,int textX,int textY)355 void DrasculaEngine::centerText(const char *message, int textX, int textY) {
356 char msg[200];
357 Common::strlcpy(msg, message, 200);
358
359 // We make sure to have a width of at least 120 pixels by clipping the center.
360 // In theory since the screen width is 320 I would expect something like this:
361 // x = CLIP<int>(x, 60, 260);
362 // return (x - halfLen >= 0 && x + halfLen <= 319);
363
364 // The engines does things differently though. It tries to clips text at 315 instead of 319.
365 // See also the comment in textFitsCentered().
366
367 textX = CLIP<int>(textX, 60, 255);
368
369 // If the message fits on screen as-is, just print it here
370 if (textFitsCentered(msg, textX)) {
371 int x = textX - (strlen(msg) / 2) * CHAR_WIDTH - 1;
372 // The original starts to draw (nbLines + 2) lines above textY, except if there is a single line
373 // in which case it starts drawing at (nbLines + 3) above textY.
374 // Also clip to the screen height although the original does not do it.
375 int y = textY - 4 * CHAR_HEIGHT;
376 y = CLIP<int>(y, 0, 200 - CHAR_HEIGHT);
377 print_abc(msg, x, y);
378 return;
379 }
380
381 // If it's a one-word message it can't be broken up. It's probably a
382 // mouse-over text, so try just sliding it to the side a bit to make it
383 // fit. This happens with the word "TOTENKOPF" in the very first room
384 // with the German translation.
385 if (!strchr(msg, ' ')) {
386 int len = strlen(msg);
387 int x = CLIP<int>(textX - (len / 2) * CHAR_WIDTH - 1, 0, 319 - len * CHAR_WIDTH);
388 int y = textY - 4 * CHAR_HEIGHT;
389 y = CLIP<int>(y, 0, 200 - CHAR_HEIGHT);
390 print_abc(msg, x, y);
391 return;
392 }
393
394 // Message doesn't fit on screen, split it
395 char messageLines[15][41]; // screenWidth/charWidth = 320/8 = 40. Thus lines can have up to 41 characters with the null terminator (despite the original allocating only 40 characters here).
396 int curLine = 0;
397 char messageCurLine[50];
398 char tmpMessageCurLine[50];
399 *messageCurLine = 0;
400 *tmpMessageCurLine = 0;
401 // Get a word from the message
402 char* curWord = strtok(msg, " ");
403 while (curWord != NULL) {
404 // Check if the word and the current line fit on screen
405 if (tmpMessageCurLine[0] != '\0')
406 Common::strlcat(tmpMessageCurLine, " ", 50);
407 Common::strlcat(tmpMessageCurLine, curWord, 50);
408 if (textFitsCentered(tmpMessageCurLine, textX)) {
409 // Line fits, so add the word to the current message line
410 strcpy(messageCurLine, tmpMessageCurLine);
411 } else {
412 // Line does't fit. Store the current line and start a new line.
413 Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
414 Common::strlcpy(messageCurLine, curWord, 50);
415 Common::strlcpy(tmpMessageCurLine, curWord, 50);
416 }
417
418 // Get next word
419 curWord = strtok(NULL, " ");
420 if (curWord == NULL) {
421 // The original has an interesting bug that if we split the text on several lines
422 // a space is added at the end (which impacts the alignment, and may even cause the line
423 // to become too long).
424 Common::strlcat(messageCurLine, " ", 50);
425 if (!textFitsCentered(messageCurLine, textX)) {
426 messageCurLine[strlen(messageCurLine) - 1] = '\0';
427 Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
428 strcpy(messageLines[curLine++], " ");
429 } else
430 Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
431 }
432 }
433
434 // The original starts to draw (nbLines + 2) lines above textY.
435 // Also clip to the screen height although the original does not do it.
436 int y = textY - (curLine + 2) * CHAR_HEIGHT;
437 y = CLIP<int>(y, 0, 200 - curLine * (CHAR_HEIGHT + 2) + 2);
438 for (int line = 0 ; line < curLine ; ++line, y += CHAR_HEIGHT + 2) {
439 int textHalfLen = (strlen(messageLines[line]) / 2) * CHAR_WIDTH;
440 print_abc(messageLines[line], textX - textHalfLen - 1, y);
441 }
442 }
443
screenSaver()444 void DrasculaEngine::screenSaver() {
445 int xr, yr;
446 byte *copia, *ghost;
447 float coeff = 0, coeff2 = 0;
448 int count = 0;
449 int count2 = 0;
450 int tempLine[320];
451 int tempRow[200];
452
453 hideCursor();
454
455 clearRoom();
456
457 loadPic("sv.alg", bgSurface, HALF_PAL);
458
459 // inicio_ghost();
460 copia = (byte *)malloc(64000);
461 ghost = (byte *)malloc(65536);
462
463 // carga_ghost();
464 Common::SeekableReadStream *stream = _archives.open("ghost.drv");
465 if (!stream)
466 error("Cannot open file ghost.drv");
467
468 stream->read(ghost, 65536);
469 delete stream;
470
471 updateEvents();
472 xr = _mouseX;
473 yr = _mouseY;
474
475 while (!shouldQuit()) {
476 // efecto(bgSurface);
477
478 memcpy(copia, bgSurface, 64000);
479 coeff += 0.1f;
480 coeff2 = coeff;
481
482 if (++count > 319)
483 count = 0;
484
485 for (int i = 0; i < 320; i++) {
486 tempLine[i] = (int)(sin(coeff2) * 16);
487 coeff2 += 0.02f;
488 tempLine[i] = checkWrapY(tempLine[i]);
489 }
490
491 coeff2 = coeff;
492 for (int i = 0; i < 200; i++) {
493 tempRow[i] = (int)(sin(coeff2) * 16);
494 coeff2 += 0.02f;
495 tempRow[i] = checkWrapX(tempRow[i]);
496 }
497
498 if (++count2 > 199)
499 count2 = 0;
500
501 int x1_, y1_, off1, off2;
502
503 Graphics::Surface *screenSurf = _system->lockScreen();
504 byte *screenBuffer = (byte *)screenSurf->getPixels();
505 uint16 screenPitch = screenSurf->pitch;
506 for (int i = 0; i < 200; i++) {
507 for (int j = 0; j < 320; j++) {
508 x1_ = j + tempRow[i];
509 x1_ = checkWrapX(x1_);
510
511 y1_ = i + count2;
512 y1_ = checkWrapY(y1_);
513
514 off1 = 320 * y1_ + x1_;
515
516 x1_ = j + count;
517 x1_ = checkWrapX(x1_);
518
519 y1_ = i + tempLine[j];
520 y1_ = checkWrapY(y1_);
521 off2 = 320 * y1_ + x1_;
522
523 screenBuffer[screenPitch * i + j] = ghost[bgSurface[off2] + (copia[off1] << 8)];
524 }
525 }
526
527 _system->unlockScreen();
528 _system->updateScreen();
529
530 _system->delayMillis(20);
531
532 // end of efecto()
533
534 updateEvents();
535 if (_rightMouseButton == 1 || _leftMouseButton == 1)
536 break;
537 if (_mouseX != xr)
538 break;
539 if (_mouseY != yr)
540 break;
541 }
542 // fin_ghost();
543 free(copia);
544 free(ghost);
545
546 loadPic(_roomNumber, bgSurface, HALF_PAL);
547 showCursor();
548 }
549
playFLI(const char * filefli,int vel)550 void DrasculaEngine::playFLI(const char *filefli, int vel) {
551 // Open file
552 globalSpeed = 1000 / vel;
553 FrameSSN = 0;
554 Common::SeekableReadStream *stream = _archives.open(filefli);
555 LastFrame = _system->getMillis();
556
557 while (playFrameSSN(stream) && (!term_int) && !shouldQuit()) {
558 if (getScan() == Common::KEYCODE_ESCAPE)
559 term_int = 1;
560 }
561
562 delete stream;
563 }
564
playFrameSSN(Common::SeekableReadStream * stream)565 int DrasculaEngine::playFrameSSN(Common::SeekableReadStream *stream) {
566 int Exit = 0;
567 uint32 length;
568 byte *BufferSSN;
569
570 byte CHUNK = stream->readByte();
571
572 switch (CHUNK) {
573 case kFrameSetPal: {
574 byte dacSSN[768];
575 stream->read(dacSSN, 768);
576 setPalette(dacSSN);
577 break;
578 }
579 case kFrameEmptyFrame:
580 waitFrameSSN();
581 break;
582 case kFrameInit: {
583 byte CMP = stream->readByte();
584 length = stream->readUint32LE();
585 if (CMP == kFrameCmpRle) {
586 BufferSSN = (byte *)malloc(length);
587 stream->read(BufferSSN, length);
588 decodeRLE(BufferSSN, screenSurface);
589 free(BufferSSN);
590 waitFrameSSN();
591
592 Graphics::Surface *screenSurf = _system->lockScreen();
593 byte *screenBuffer = (byte *)screenSurf->getPixels();
594 uint16 screenPitch = screenSurf->pitch;
595 if (FrameSSN)
596 mixVideo(screenBuffer, screenSurface, screenPitch);
597 else
598 for (int y = 0; y < 200; y++)
599 memcpy(screenBuffer+y*screenPitch, screenSurface+y*320, 320);
600
601 _system->unlockScreen();
602 _system->updateScreen();
603 FrameSSN++;
604 } else {
605 if (CMP == kFrameCmpOff) {
606 BufferSSN = (byte *)malloc(length);
607 stream->read(BufferSSN, length);
608 decodeOffset(BufferSSN, screenSurface, length);
609 free(BufferSSN);
610 waitFrameSSN();
611 Graphics::Surface *screenSurf = _system->lockScreen();
612 byte *screenBuffer = (byte *)screenSurf->getPixels();
613 uint16 screenPitch = screenSurf->pitch;
614 if (FrameSSN)
615 mixVideo(screenBuffer, screenSurface, screenPitch);
616 else
617 for (int y = 0; y < 200; y++)
618 memcpy(screenBuffer+y*screenPitch, screenSurface+y*320, 320);
619
620 _system->unlockScreen();
621 _system->updateScreen();
622 FrameSSN++;
623 }
624 }
625 break;
626 }
627 case kFrameEndAnim:
628 Exit = 1;
629 break;
630 default:
631 Exit = 1;
632 break;
633 }
634
635 return (!Exit);
636 }
637
decodeOffset(byte * BufferOFF,byte * MiVideoOFF,int length)638 void DrasculaEngine::decodeOffset(byte *BufferOFF, byte *MiVideoOFF, int length) {
639 int x = 0;
640 int size;
641 int offset;
642
643 memset(screenSurface, 0, 64000);
644 while (x < length) {
645 offset = BufferOFF[x] + BufferOFF[x + 1] * 256;
646 // FIXME: this writes beyond 64000, so the buffer has been initialized
647 // to 64256 bytes (like the original did)
648 size = BufferOFF[x + 2];
649 memcpy(MiVideoOFF + offset, &BufferOFF[x + 3], size);
650 x += 3 + size;
651 }
652 }
653
decodeRLE(byte * srcPtr,byte * dstPtr,uint16 pitch)654 void DrasculaEngine::decodeRLE(byte* srcPtr, byte* dstPtr, uint16 pitch) {
655 bool stopProcessing = false;
656 byte pixel;
657 uint repeat;
658 int curByte = 0, curLine = 0;
659 pitch -= 320;
660
661 while (!stopProcessing) {
662 pixel = *srcPtr++;
663 repeat = 1;
664 if ((pixel & 192) == 192) {
665 repeat = (pixel & 63);
666 pixel = *srcPtr++;
667 }
668 for (uint j = 0; j < repeat; j++) {
669 *dstPtr++ = pixel;
670 if (++curByte >= 320) {
671 curByte = 0;
672 dstPtr += pitch;
673 if (++curLine >= 200) {
674 stopProcessing = true;
675 break;
676 }
677 }
678 }
679 }
680 }
681
mixVideo(byte * OldScreen,byte * NewScreen,uint16 oldPitch)682 void DrasculaEngine::mixVideo(byte *OldScreen, byte *NewScreen, uint16 oldPitch) {
683 for (int y = 0; y < 200; y++) {
684 for (int x = 0; x < 320; x++)
685 OldScreen[x] ^= NewScreen[x];
686 OldScreen += oldPitch;
687 NewScreen += 320;
688 }
689 }
690
waitFrameSSN()691 void DrasculaEngine::waitFrameSSN() {
692 uint32 now;
693 while ((now = _system->getMillis()) - LastFrame < ((uint32) globalSpeed))
694 _system->delayMillis(globalSpeed - (now - LastFrame));
695 LastFrame = LastFrame + globalSpeed;
696 }
697
animate(const char * animationFile,int FPS)698 bool DrasculaEngine::animate(const char *animationFile, int FPS) {
699 int NFrames;
700 int cnt = 2;
701
702 Common::SeekableReadStream *stream = _archives.open(animationFile);
703
704 if (!stream) {
705 error("Animation file %s not found", animationFile);
706 }
707
708 NFrames = stream->readSint32LE();
709 showFrame(stream, true);
710 _system->delayMillis(1000 / FPS);
711 while (cnt < NFrames) {
712 showFrame(stream);
713 _system->delayMillis(1000 / FPS);
714 cnt++;
715 byte key = getScan();
716 if (key == Common::KEYCODE_ESCAPE)
717 term_int = 1;
718 if (key != 0)
719 break;
720 }
721 delete stream;
722
723 return ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit());
724 }
725
726 } // End of namespace Drascula
727