2008-06-07 19:40:43 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
2014-02-18 02:34:19 +01:00
*
2008-06-07 19:40:43 +00:00
* 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 .
2014-02-18 02:34:19 +01:00
*
2008-06-07 19:40:43 +00:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
*/
# include "drascula/drascula.h"
2009-08-04 17:22:18 +00:00
# include "graphics/surface.h"
2010-02-08 16:13:31 +00:00
2011-04-24 11:34:27 +03:00
# include "common/stream.h"
# include "common/textconsole.h"
2008-06-07 19:40:43 +00:00
namespace Drascula {
void DrasculaEngine : : allocMemory ( ) {
2008-06-08 15:56:48 +00:00
// FIXME: decodeOffset writes beyond 64000, so this
// buffer has been initialized to 64256 bytes (like
// the original did with the MiVideoSSN buffer)
screenSurface = ( byte * ) malloc ( 64256 ) ;
2008-06-07 19:40:43 +00:00
assert ( screenSurface ) ;
frontSurface = ( byte * ) malloc ( 64000 ) ;
assert ( frontSurface ) ;
backSurface = ( byte * ) malloc ( 64000 ) ;
assert ( backSurface ) ;
2008-06-10 18:54:32 +00:00
bgSurface = ( byte * ) malloc ( 64000 ) ;
assert ( bgSurface ) ;
2008-06-07 19:40:43 +00:00
drawSurface2 = ( byte * ) malloc ( 64000 ) ;
assert ( drawSurface2 ) ;
drawSurface3 = ( byte * ) malloc ( 64000 ) ;
assert ( drawSurface3 ) ;
tableSurface = ( byte * ) malloc ( 64000 ) ;
assert ( tableSurface ) ;
extraSurface = ( byte * ) malloc ( 64000 ) ;
assert ( extraSurface ) ;
2009-08-04 21:56:59 +00:00
crosshairCursor = ( byte * ) malloc ( OBJWIDTH * OBJHEIGHT ) ;
2008-09-11 09:31:45 +00:00
assert ( crosshairCursor ) ;
mouseCursor = ( byte * ) malloc ( OBJWIDTH * OBJHEIGHT ) ;
assert ( mouseCursor ) ;
2010-06-15 10:21:42 +00:00
cursorSurface = ( byte * ) malloc ( 64000 ) ;
2008-06-07 19:40:43 +00:00
}
void DrasculaEngine : : freeMemory ( ) {
free ( screenSurface ) ;
2008-06-10 18:54:32 +00:00
free ( bgSurface ) ;
2008-06-07 19:40:43 +00:00
free ( backSurface ) ;
free ( drawSurface2 ) ;
free ( tableSurface ) ;
free ( drawSurface3 ) ;
free ( extraSurface ) ;
free ( frontSurface ) ;
2008-09-11 09:31:45 +00:00
free ( crosshairCursor ) ;
free ( mouseCursor ) ;
2010-06-15 10:21:42 +00:00
free ( cursorSurface ) ;
2008-06-07 19:40:43 +00:00
}
void DrasculaEngine : : moveCursor ( ) {
2008-08-26 08:21:21 +00:00
copyBackground ( ) ;
2008-06-07 19:40:43 +00:00
updateRefresh_pre ( ) ;
moveCharacters ( ) ;
updateRefresh ( ) ;
2009-05-13 11:59:49 +00:00
if ( ! strcmp ( textName , " hacker " ) & & _hasName ) {
if ( _color ! = kColorRed & & ! _menuScreen )
2008-06-07 19:40:43 +00:00
color_abc ( kColorRed ) ;
2009-05-13 11:59:49 +00:00
} else if ( ! _menuScreen & & _color ! = kColorLightGreen )
2008-06-07 19:40:43 +00:00
color_abc ( kColorLightGreen ) ;
2009-05-13 11:59:49 +00:00
if ( _hasName & & ! _menuScreen )
2013-08-19 03:08:11 +03:00
centerText ( textName , _mouseX , _mouseY ) ;
2009-05-13 11:59:49 +00:00
if ( _menuScreen )
2008-06-07 19:40:43 +00:00
showMenu ( ) ;
2009-05-13 11:59:49 +00:00
else if ( _menuBar )
2008-06-07 19:40:43 +00:00
clearMenu ( ) ;
2008-09-11 09:31:45 +00:00
}
2008-06-07 19:40:43 +00:00
void DrasculaEngine : : loadPic ( const char * NamePcc , byte * targetSurface , int colorCount ) {
2010-06-15 10:20:10 +00:00
debug ( 5 , " loadPic(%s) " , NamePcc ) ;
2008-06-17 18:27:03 +00:00
uint dataSize = 0 ;
byte * pcxData ;
2008-06-07 19:40:43 +00:00
2010-02-08 18:17:32 +00:00
Common : : SeekableReadStream * stream = _archives . open ( NamePcc ) ;
2010-02-08 16:14:04 +00:00
if ( ! stream )
2008-06-07 19:40:43 +00:00
error ( " missing game data %s %c " , NamePcc , 7 ) ;
2010-02-08 16:14:04 +00:00
dataSize = stream - > size ( ) - 128 - ( 256 * 3 ) ;
2008-06-17 18:27:03 +00:00
pcxData = ( byte * ) malloc ( dataSize ) ;
2010-02-08 16:14:04 +00:00
stream - > seek ( 128 , SEEK_SET ) ;
stream - > read ( pcxData , dataSize ) ;
2008-06-17 18:27:03 +00:00
decodeRLE ( pcxData , targetSurface ) ;
free ( pcxData ) ;
2008-06-07 19:40:43 +00:00
2008-06-09 18:03:11 +00:00
for ( int i = 0 ; i < 256 ; i + + ) {
2010-02-08 16:14:04 +00:00
cPal [ i * 3 + 0 ] = stream - > readByte ( ) ;
cPal [ i * 3 + 1 ] = stream - > readByte ( ) ;
cPal [ i * 3 + 2 ] = stream - > readByte ( ) ;
2008-06-09 18:03:11 +00:00
}
2010-02-08 16:14:04 +00:00
delete stream ;
2008-06-07 19:40:43 +00:00
setRGB ( ( byte * ) cPal , colorCount ) ;
}
2010-02-08 16:14:04 +00:00
void DrasculaEngine : : showFrame ( Common : : SeekableReadStream * stream , bool firstFrame ) {
int dataSize = stream - > readSint32LE ( ) ;
2008-06-08 14:11:22 +00:00
byte * pcxData = ( byte * ) malloc ( dataSize ) ;
2010-02-08 16:14:04 +00:00
stream - > read ( pcxData , dataSize ) ;
2008-06-09 18:03:11 +00:00
for ( int i = 0 ; i < 256 ; i + + ) {
2010-02-08 16:14:04 +00:00
cPal [ i * 3 + 0 ] = stream - > readByte ( ) ;
cPal [ i * 3 + 1 ] = stream - > readByte ( ) ;
cPal [ i * 3 + 2 ] = stream - > readByte ( ) ;
2008-06-09 18:03:11 +00:00
}
2008-06-08 14:11:22 +00:00
byte * prevFrame = ( byte * ) malloc ( 64000 ) ;
2011-05-04 23:54:57 +02:00
Graphics : : Surface * screenSurf = _system - > lockScreen ( ) ;
2013-08-03 02:38:46 +02:00
byte * screenBuffer = ( byte * ) screenSurf - > getPixels ( ) ;
2011-05-04 23:54:57 +02:00
uint16 screenPitch = screenSurf - > pitch ;
for ( int y = 0 ; y < 200 ; y + + ) {
memcpy ( prevFrame + y * 320 , screenBuffer + y * screenPitch , 320 ) ;
}
2008-06-08 14:11:22 +00:00
2011-05-04 23:54:57 +02:00
decodeRLE ( pcxData , screenBuffer , screenPitch ) ;
2008-06-08 14:11:22 +00:00
free ( pcxData ) ;
2008-06-08 14:17:35 +00:00
if ( ! firstFrame )
2011-05-04 23:54:57 +02:00
mixVideo ( screenBuffer , prevFrame , screenPitch ) ;
2008-06-08 14:11:22 +00:00
2009-08-04 17:22:18 +00:00
_system - > unlockScreen ( ) ;
2008-06-08 14:11:22 +00:00
_system - > updateScreen ( ) ;
2009-08-04 17:22:18 +00:00
2008-06-08 14:11:22 +00:00
if ( firstFrame )
setPalette ( cPal ) ;
free ( prevFrame ) ;
2008-06-07 19:40:43 +00:00
}
2010-06-15 10:22:19 +00:00
void DrasculaEngine : : copyBackground ( int xorg , int yorg , int xdes , int ydes , int width , int height , byte * src , byte * dest ) {
2011-11-25 06:30:10 +00:00
debug ( 1 , " DrasculaEngine::copyBackground(xorg:%d, yorg:%d, xdes:%d, ydes:%d width:%d height:%d, src, dest) " , xorg , yorg , xdes , ydes , width , height ) ;
2008-06-07 19:40:43 +00:00
dest + = xdes + ydes * 320 ;
src + = xorg + yorg * 320 ;
2008-09-11 12:04:45 +00:00
/* Unoptimized code
2008-06-07 19:40:43 +00:00
for ( int x = 0 ; x < height ; x + + ) {
2008-09-11 09:37:42 +00:00
memcpy ( dest + 320 * x , src + 320 * x , width ) ;
2008-09-11 12:04:45 +00:00
} */
// A bit more optimized code, thanks to Fingolfin
// Uses 2 less registers and performs 2 less multiplications
int x = height ;
while ( x - - ) {
memcpy ( dest , src , width ) ;
dest + = 320 ;
src + = 320 ;
2008-06-07 19:40:43 +00:00
}
}
void DrasculaEngine : : copyRect ( int xorg , int yorg , int xdes , int ydes , int width ,
int height , byte * src , byte * dest ) {
int y , x ;
2008-09-12 12:54:16 +00:00
//
2008-06-07 19:40:43 +00:00
if ( ydes < 0 ) {
yorg + = - ydes ;
height + = ydes ;
ydes = 0 ;
}
if ( xdes < 0 ) {
xorg + = - xdes ;
width + = xdes ;
xdes = 0 ;
}
if ( ( xdes + width ) > 319 )
width - = ( xdes + width ) - 320 ;
if ( ( ydes + height ) > 199 )
height - = ( ydes + height ) - 200 ;
2008-09-12 12:54:16 +00:00
//
2008-06-07 19:40:43 +00:00
dest + = xdes + ydes * 320 ;
src + = xorg + yorg * 320 ;
2010-06-15 10:17:34 +00:00
int ptr = 0 ;
for ( y = 0 ; y < height ; y + + ) {
for ( x = 0 ; x < width ; x + + ) {
if ( src [ ptr ] ! = 255 )
dest [ ptr ] = src [ ptr ] ;
ptr + + ;
}
ptr + = 320 - width ;
}
2011-06-20 00:59:48 +02:00
2008-06-07 19:40:43 +00:00
}
void DrasculaEngine : : updateScreen ( int xorg , int yorg , int xdes , int ydes , int width , int height , byte * buffer ) {
2010-06-15 10:20:26 +00:00
_system - > copyRectToScreen ( buffer + xorg + yorg * 320 , 320 , xdes , ydes , width , height ) ;
2008-06-07 19:40:43 +00:00
_system - > updateScreen ( ) ;
}
void DrasculaEngine : : print_abc ( const char * said , int screenX , int screenY ) {
2008-06-07 20:47:52 +00:00
int letterY = 0 , letterX = 0 , i ;
2008-06-07 19:40:43 +00:00
uint len = strlen ( said ) ;
2008-06-07 20:47:52 +00:00
byte c ;
2016-10-09 14:59:58 +02:00
2016-04-16 16:46:38 +01:00
byte * srcSurface = tableSurface ;
if ( _lang = = kSpanish & & currentChapter = = 6 )
srcSurface = extraSurface ;
2008-06-07 19:40:43 +00:00
for ( uint h = 0 ; h < len ; h + + ) {
c = toupper ( said [ h ] ) ;
2008-06-07 20:47:52 +00:00
for ( i = 0 ; i < _charMapSize ; i + + ) {
if ( c = = _charMap [ i ] . inChar ) {
letterX = _charMap [ i ] . mappedChar ;
2008-06-07 19:40:43 +00:00
2008-06-07 20:47:52 +00:00
switch ( _charMap [ i ] . charType ) {
2008-09-13 15:23:23 +00:00
case 0 : // letters
letterY = ( _lang = = kSpanish ) ? 149 : 158 ;
break ;
case 1 : // signs
letterY = ( _lang = = kSpanish ) ? 160 : 169 ;
break ;
case 2 : // accented
letterY = 180 ;
break ;
2008-06-07 19:40:43 +00:00
} // switch
break ;
} // if
} // for
2009-01-01 15:06:43 +00:00
copyRect ( letterX , letterY , screenX , screenY ,
2016-04-16 16:46:38 +01:00
CHAR_WIDTH , CHAR_HEIGHT , srcSurface , screenSurface ) ;
2008-06-07 19:40:43 +00:00
screenX = screenX + CHAR_WIDTH ;
if ( screenX > 317 ) {
screenX = 0 ;
screenY = screenY + CHAR_HEIGHT + 2 ;
}
} // for
}
2009-07-25 13:07:50 +00:00
int DrasculaEngine : : print_abc_opc ( const char * said , int screenY , int game ) {
2008-06-07 19:40:43 +00:00
int signY , letterY , letterX = 0 ;
uint len = strlen ( said ) ;
2008-09-09 11:20:34 +00:00
int screenX = 1 ;
2009-07-25 13:07:50 +00:00
int lines = 1 ;
2008-09-09 11:20:34 +00:00
2008-06-07 19:40:43 +00:00
for ( uint h = 0 ; h < len ; h + + ) {
2009-07-25 13:07:50 +00:00
int wordLength ;
// Look ahead to the end of the word.
wordLength = 0 ;
int pos = h ;
while ( said [ pos ] & & said [ pos ] ! = ' ' ) {
wordLength + + ;
pos + + ;
}
if ( screenX + wordLength * CHAR_WIDTH_OPC > 317 ) {
screenX = 0 ;
screenY + = ( CHAR_HEIGHT + 2 ) ;
lines + + ;
}
2008-06-07 19:40:43 +00:00
if ( game = = 1 ) {
letterY = 6 ;
signY = 15 ;
} else if ( game = = 3 ) {
letterY = 56 ;
signY = 65 ;
} else {
letterY = 31 ;
signY = 40 ;
}
2008-06-08 22:11:18 +00:00
byte c = toupper ( said [ h ] ) ;
2008-06-07 19:40:43 +00:00
// WORKAROUND: Even original did not process it correctly
// Fixes apostrophe rendering
if ( _lang ! = kSpanish )
if ( c = = ' \' ' )
2008-06-08 22:11:18 +00:00
c = ( byte ) ' \244 ' ;
2008-06-07 19:40:43 +00:00
2008-06-07 20:47:52 +00:00
for ( int i = 0 ; i < _charMapSize ; i + + ) {
if ( c = = _charMap [ i ] . inChar ) {
2008-06-07 19:40:43 +00:00
// Convert the mapped char of the normal font to the
// mapped char of the dialogue font
2008-06-07 20:47:52 +00:00
int multiplier = ( _charMap [ i ] . mappedChar - 6 ) / 9 ;
2008-06-07 19:40:43 +00:00
letterX = multiplier * 7 + 10 ;
2008-06-07 20:47:52 +00:00
if ( _charMap [ i ] . charType > 0 )
2008-06-07 19:40:43 +00:00
letterY = signY ;
break ;
} // if
} // for
2009-01-01 15:06:43 +00:00
copyRect ( letterX , letterY , screenX , screenY ,
2008-09-12 12:54:16 +00:00
CHAR_WIDTH_OPC , CHAR_HEIGHT_OPC , backSurface , screenSurface ) ;
2008-06-07 19:40:43 +00:00
screenX = screenX + CHAR_WIDTH_OPC ;
}
2009-07-25 13:07:50 +00:00
return lines ;
2008-06-07 19:40:43 +00:00
}
2008-09-15 13:37:28 +00:00
bool DrasculaEngine : : textFitsCentered ( char * text , int x ) {
2016-04-13 21:08:17 +01:00
int textLen = strlen ( text ) ;
int halfLen = ( textLen / 2 ) * CHAR_WIDTH ;
2016-04-08 02:04:13 +01:00
2016-04-13 21:08:17 +01:00
//if (x > 160)
// x = 315 - x;
//return (halfLen <= x);
2016-10-09 14:59:58 +02:00
2016-04-13 21:08:17 +01:00
// The commented out code above is what the original engine is doing. Instead of testing the
// upper bound if x is greater than 160 it takes the complement to 315 and test only the lower
// bounds.
// Also note that since it does an integer division to compute the half length of the string,
// in the case where the string has an odd number of characters there is one more character to
// the right than to the left. If the string center is beyond 160, this is taken care of by
// taking the complement to 315 instead of 320. But if the string center is close to the screen
// center, but not greater than 160, this can lead to the string being accepted despite having
// one character beyond the right edge of the screen.
// In ScummVM we therefore also test the right edge, which leads to differences
// with the original engine, but for the better.
2016-04-08 02:04:13 +01:00
if ( x > 160 )
2016-04-13 21:08:17 +01:00
return ( 315 - x - halfLen > = 0 ) ;
return ( x - halfLen > = 0 & & x + halfLen + ( textLen % 2 ) * CHAR_WIDTH < = 320 ) ;
2008-09-15 13:37:28 +00:00
}
2008-06-07 19:40:43 +00:00
2008-09-15 13:37:28 +00:00
void DrasculaEngine : : centerText ( const char * message , int textX , int textY ) {
char msg [ 200 ] ;
2013-10-17 13:40:26 +02:00
Common : : strlcpy ( msg , message , 200 ) ;
2016-10-09 14:59:58 +02:00
2016-04-08 02:04:13 +01:00
// We make sure to have a width of at least 120 pixels by clipping the center.
// In theory since the screen width is 320 I would expect something like this:
// x = CLIP<int>(x, 60, 260);
// return (x - halfLen >= 0 && x + halfLen <= 319);
2016-10-09 14:59:58 +02:00
2016-04-08 02:04:13 +01:00
// The engines does things differently though. It tries to clips text at 315 instead of 319.
2016-04-13 21:08:17 +01:00
// See also the comment in textFitsCentered().
2016-10-09 14:59:58 +02:00
2016-04-08 02:04:13 +01:00
textX = CLIP < int > ( textX , 60 , 255 ) ;
2008-09-15 13:37:28 +00:00
// If the message fits on screen as-is, just print it here
if ( textFitsCentered ( msg , textX ) ) {
2016-04-08 02:04:13 +01:00
int x = textX - ( strlen ( msg ) / 2 ) * CHAR_WIDTH - 1 ;
// The original starts to draw (nbLines + 2) lines above textY, except if there is a single line
// in which case it starts drawing at (nbLines + 3) above textY.
// Also clip to the screen height although the original does not do it.
int y = textY - 4 * CHAR_HEIGHT ;
y = CLIP < int > ( y , 0 , 200 - CHAR_HEIGHT ) ;
2008-09-15 13:37:28 +00:00
print_abc ( msg , x , y ) ;
return ;
2008-06-07 19:40:43 +00:00
}
2010-04-29 03:54:20 +00:00
// If it's a one-word message it can't be broken up. It's probably a
// mouse-over text, so try just sliding it to the side a bit to make it
// fit. This happens with the word "TOTENKOPF" in the very first room
// with the German translation.
if ( ! strchr ( msg , ' ' ) ) {
int len = strlen ( msg ) ;
2016-04-08 02:04:13 +01:00
int x = CLIP < int > ( textX - ( len / 2 ) * CHAR_WIDTH - 1 , 0 , 319 - len * CHAR_WIDTH ) ;
int y = textY - 4 * CHAR_HEIGHT ;
y = CLIP < int > ( y , 0 , 200 - CHAR_HEIGHT ) ;
2010-04-29 03:54:20 +00:00
print_abc ( msg , x , y ) ;
return ;
}
2011-06-20 00:59:48 +02:00
2008-09-15 13:37:28 +00:00
// Message doesn't fit on screen, split it
2016-04-08 02:04:13 +01:00
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).
int curLine = 0 ;
char messageCurLine [ 50 ] ;
char tmpMessageCurLine [ 50 ] ;
* messageCurLine = 0 ;
* tmpMessageCurLine = 0 ;
2008-09-15 13:37:28 +00:00
// Get a word from the message
2016-04-08 02:04:13 +01:00
char * curWord = strtok ( msg , " " ) ;
2008-09-15 13:37:28 +00:00
while ( curWord ! = NULL ) {
// Check if the word and the current line fit on screen
2016-04-08 02:04:13 +01:00
if ( tmpMessageCurLine [ 0 ] ! = ' \0 ' )
Common : : strlcat ( tmpMessageCurLine , " " , 50 ) ;
Common : : strlcat ( tmpMessageCurLine , curWord , 50 ) ;
if ( textFitsCentered ( tmpMessageCurLine , textX ) ) {
2008-09-15 13:37:28 +00:00
// Line fits, so add the word to the current message line
2016-04-08 02:04:13 +01:00
strcpy ( messageCurLine , tmpMessageCurLine ) ;
2008-09-15 13:37:28 +00:00
} else {
2016-04-08 02:04:13 +01:00
// Line does't fit. Store the current line and start a new line.
Common : : strlcpy ( messageLines [ curLine + + ] , messageCurLine , 41 ) ;
Common : : strlcpy ( messageCurLine , curWord , 50 ) ;
Common : : strlcpy ( tmpMessageCurLine , curWord , 50 ) ;
2008-09-15 13:37:28 +00:00
}
2008-06-07 19:40:43 +00:00
2008-09-15 13:37:28 +00:00
// Get next word
2008-09-16 07:16:26 +00:00
curWord = strtok ( NULL , " " ) ;
2008-09-15 13:37:28 +00:00
if ( curWord = = NULL ) {
2016-04-08 02:04:13 +01:00
// The original has an interesting bug that if we split the text on several lines
// a space is added at the end (which impacts the alignment, and may even cause the line
// to become too long).
Common : : strlcat ( messageCurLine , " " , 50 ) ;
if ( ! textFitsCentered ( messageCurLine , textX ) ) {
messageCurLine [ strlen ( messageCurLine ) - 1 ] = ' \0 ' ;
Common : : strlcpy ( messageLines [ curLine + + ] , messageCurLine , 41 ) ;
strcpy ( messageLines [ curLine + + ] , " " ) ;
} else
Common : : strlcpy ( messageLines [ curLine + + ] , messageCurLine , 41 ) ;
2008-09-15 13:37:28 +00:00
}
2008-06-07 19:40:43 +00:00
}
2016-10-09 14:59:58 +02:00
2016-04-08 02:04:13 +01:00
// The original starts to draw (nbLines + 2) lines above textY.
// Also clip to the screen height although the original does not do it.
int y = textY - ( curLine + 2 ) * CHAR_HEIGHT ;
y = CLIP < int > ( y , 0 , 200 - curLine * ( CHAR_HEIGHT + 2 ) + 2 ) ;
for ( int line = 0 ; line < curLine ; + + line , y + = CHAR_HEIGHT + 2 ) {
int textHalfLen = ( strlen ( messageLines [ line ] ) / 2 ) * CHAR_WIDTH ;
print_abc ( messageLines [ line ] , textX - textHalfLen - 1 , y ) ;
}
2008-06-07 19:40:43 +00:00
}
void DrasculaEngine : : screenSaver ( ) {
int xr , yr ;
byte * copia , * ghost ;
float coeff = 0 , coeff2 = 0 ;
int count = 0 ;
int count2 = 0 ;
int tempLine [ 320 ] ;
int tempRow [ 200 ] ;
2008-09-14 16:21:31 +00:00
hideCursor ( ) ;
2008-06-07 19:40:43 +00:00
clearRoom ( ) ;
2008-06-10 18:54:32 +00:00
loadPic ( " sv.alg " , bgSurface , HALF_PAL ) ;
2008-06-07 19:40:43 +00:00
// inicio_ghost();
copia = ( byte * ) malloc ( 64000 ) ;
ghost = ( byte * ) malloc ( 65536 ) ;
// carga_ghost();
2010-02-08 18:17:32 +00:00
Common : : SeekableReadStream * stream = _archives . open ( " ghost.drv " ) ;
2010-02-08 16:14:04 +00:00
if ( ! stream )
2008-06-07 19:40:43 +00:00
error ( " Cannot open file ghost.drv " ) ;
2010-02-08 16:14:04 +00:00
stream - > read ( ghost , 65536 ) ;
delete stream ;
2008-06-07 19:40:43 +00:00
updateEvents ( ) ;
2013-08-19 03:08:11 +03:00
xr = _mouseX ;
yr = _mouseY ;
2008-06-07 19:40:43 +00:00
2011-01-28 08:07:50 +00:00
while ( ! shouldQuit ( ) ) {
2008-06-10 18:54:32 +00:00
// efecto(bgSurface);
2008-06-07 19:40:43 +00:00
2008-06-10 18:54:32 +00:00
memcpy ( copia , bgSurface , 64000 ) ;
2008-06-07 19:40:43 +00:00
coeff + = 0.1f ;
coeff2 = coeff ;
if ( + + count > 319 )
count = 0 ;
for ( int i = 0 ; i < 320 ; i + + ) {
tempLine [ i ] = ( int ) ( sin ( coeff2 ) * 16 ) ;
coeff2 + = 0.02f ;
tempLine [ i ] = checkWrapY ( tempLine [ i ] ) ;
}
coeff2 = coeff ;
for ( int i = 0 ; i < 200 ; i + + ) {
tempRow [ i ] = ( int ) ( sin ( coeff2 ) * 16 ) ;
coeff2 + = 0.02f ;
tempRow [ i ] = checkWrapX ( tempRow [ i ] ) ;
}
if ( + + count2 > 199 )
count2 = 0 ;
int x1_ , y1_ , off1 , off2 ;
2011-05-04 23:54:57 +02:00
Graphics : : Surface * screenSurf = _system - > lockScreen ( ) ;
2013-08-03 02:38:46 +02:00
byte * screenBuffer = ( byte * ) screenSurf - > getPixels ( ) ;
2011-05-04 23:54:57 +02:00
uint16 screenPitch = screenSurf - > pitch ;
2008-06-07 19:40:43 +00:00
for ( int i = 0 ; i < 200 ; i + + ) {
for ( int j = 0 ; j < 320 ; j + + ) {
x1_ = j + tempRow [ i ] ;
x1_ = checkWrapX ( x1_ ) ;
y1_ = i + count2 ;
y1_ = checkWrapY ( y1_ ) ;
off1 = 320 * y1_ + x1_ ;
x1_ = j + count ;
x1_ = checkWrapX ( x1_ ) ;
y1_ = i + tempLine [ j ] ;
y1_ = checkWrapY ( y1_ ) ;
off2 = 320 * y1_ + x1_ ;
2011-05-04 23:54:57 +02:00
screenBuffer [ screenPitch * i + j ] = ghost [ bgSurface [ off2 ] + ( copia [ off1 ] < < 8 ) ] ;
2008-06-07 19:40:43 +00:00
}
}
2009-08-04 17:22:18 +00:00
_system - > unlockScreen ( ) ;
2008-06-07 19:40:43 +00:00
_system - > updateScreen ( ) ;
_system - > delayMillis ( 20 ) ;
// end of efecto()
updateEvents ( ) ;
2013-08-19 03:08:11 +03:00
if ( _rightMouseButton = = 1 | | _leftMouseButton = = 1 )
2008-06-07 19:40:43 +00:00
break ;
2013-08-19 03:08:11 +03:00
if ( _mouseX ! = xr )
2008-06-07 19:40:43 +00:00
break ;
2013-08-19 03:08:11 +03:00
if ( _mouseY ! = yr )
2008-06-07 19:40:43 +00:00
break ;
}
// fin_ghost();
free ( copia ) ;
free ( ghost ) ;
2013-08-19 03:08:11 +03:00
loadPic ( _roomNumber , bgSurface , HALF_PAL ) ;
2008-09-14 16:21:31 +00:00
showCursor ( ) ;
2008-06-07 19:40:43 +00:00
}
void DrasculaEngine : : playFLI ( const char * filefli , int vel ) {
// Open file
globalSpeed = 1000 / vel ;
FrameSSN = 0 ;
2010-02-08 18:17:32 +00:00
Common : : SeekableReadStream * stream = _archives . open ( filefli ) ;
2008-06-07 19:40:43 +00:00
LastFrame = _system - > getMillis ( ) ;
2011-01-28 08:07:50 +00:00
while ( playFrameSSN ( stream ) & & ( ! term_int ) & & ! shouldQuit ( ) ) {
2008-06-07 19:40:43 +00:00
if ( getScan ( ) = = Common : : KEYCODE_ESCAPE )
term_int = 1 ;
}
2010-02-08 16:14:04 +00:00
delete stream ;
2008-06-07 19:40:43 +00:00
}
2010-02-08 16:14:04 +00:00
int DrasculaEngine : : playFrameSSN ( Common : : SeekableReadStream * stream ) {
2008-06-07 19:40:43 +00:00
int Exit = 0 ;
2008-06-09 18:03:11 +00:00
uint32 length ;
2008-06-07 19:40:43 +00:00
byte * BufferSSN ;
2010-03-09 23:36:18 +00:00
byte CHUNK = stream - > readByte ( ) ;
2008-06-07 19:40:43 +00:00
switch ( CHUNK ) {
2010-03-09 23:36:18 +00:00
case kFrameSetPal : {
byte dacSSN [ 768 ] ;
stream - > read ( dacSSN , 768 ) ;
2008-06-07 19:40:43 +00:00
setPalette ( dacSSN ) ;
break ;
2010-03-09 23:36:18 +00:00
}
2008-06-07 19:40:43 +00:00
case kFrameEmptyFrame :
2008-06-08 14:17:35 +00:00
waitFrameSSN ( ) ;
2008-06-07 19:40:43 +00:00
break ;
2010-03-09 23:36:18 +00:00
case kFrameInit : {
byte CMP = stream - > readByte ( ) ;
length = stream - > readUint32LE ( ) ;
2008-06-07 19:40:43 +00:00
if ( CMP = = kFrameCmpRle ) {
2008-06-09 18:03:11 +00:00
BufferSSN = ( byte * ) malloc ( length ) ;
2010-03-09 23:36:18 +00:00
stream - > read ( BufferSSN , length ) ;
2008-06-08 15:56:48 +00:00
decodeRLE ( BufferSSN , screenSurface ) ;
2008-06-07 19:40:43 +00:00
free ( BufferSSN ) ;
2008-06-08 14:17:35 +00:00
waitFrameSSN ( ) ;
2009-08-04 17:22:18 +00:00
2011-05-04 23:54:57 +02:00
Graphics : : Surface * screenSurf = _system - > lockScreen ( ) ;
2013-08-03 02:38:46 +02:00
byte * screenBuffer = ( byte * ) screenSurf - > getPixels ( ) ;
2011-05-04 23:54:57 +02:00
uint16 screenPitch = screenSurf - > pitch ;
2008-06-08 03:09:21 +00:00
if ( FrameSSN )
2011-05-04 23:54:57 +02:00
mixVideo ( screenBuffer , screenSurface , screenPitch ) ;
2008-06-08 03:09:21 +00:00
else
2011-05-04 23:54:57 +02:00
for ( int y = 0 ; y < 200 ; y + + )
memcpy ( screenBuffer + y * screenPitch , screenSurface + y * 320 , 320 ) ;
2010-01-25 01:39:44 +00:00
2009-08-04 17:22:18 +00:00
_system - > unlockScreen ( ) ;
2008-06-07 19:40:43 +00:00
_system - > updateScreen ( ) ;
FrameSSN + + ;
} else {
if ( CMP = = kFrameCmpOff ) {
2008-06-09 18:03:11 +00:00
BufferSSN = ( byte * ) malloc ( length ) ;
2010-03-09 23:36:18 +00:00
stream - > read ( BufferSSN , length ) ;
2008-06-09 18:03:11 +00:00
decodeOffset ( BufferSSN , screenSurface , length ) ;
2008-06-07 19:40:43 +00:00
free ( BufferSSN ) ;
2008-06-08 14:17:35 +00:00
waitFrameSSN ( ) ;
2011-05-04 23:54:57 +02:00
Graphics : : Surface * screenSurf = _system - > lockScreen ( ) ;
2013-08-03 02:38:46 +02:00
byte * screenBuffer = ( byte * ) screenSurf - > getPixels ( ) ;
2011-05-04 23:54:57 +02:00
uint16 screenPitch = screenSurf - > pitch ;
2008-06-08 03:09:21 +00:00
if ( FrameSSN )
2011-05-04 23:54:57 +02:00
mixVideo ( screenBuffer , screenSurface , screenPitch ) ;
2008-06-08 03:09:21 +00:00
else
2011-05-04 23:54:57 +02:00
for ( int y = 0 ; y < 200 ; y + + )
memcpy ( screenBuffer + y * screenPitch , screenSurface + y * 320 , 320 ) ;
2009-08-04 17:22:18 +00:00
_system - > unlockScreen ( ) ;
2008-06-07 19:40:43 +00:00
_system - > updateScreen ( ) ;
FrameSSN + + ;
}
}
break ;
2010-03-09 23:36:18 +00:00
}
2008-06-07 19:40:43 +00:00
case kFrameEndAnim :
Exit = 1 ;
break ;
default :
Exit = 1 ;
break ;
}
return ( ! Exit ) ;
}
2008-06-08 14:59:52 +00:00
void DrasculaEngine : : decodeOffset ( byte * BufferOFF , byte * MiVideoOFF , int length ) {
2008-06-07 19:40:43 +00:00
int x = 0 ;
2008-06-08 15:56:48 +00:00
int size ;
int offset ;
2008-06-07 19:40:43 +00:00
2008-06-08 15:56:48 +00:00
memset ( screenSurface , 0 , 64000 ) ;
2008-06-08 14:59:52 +00:00
while ( x < length ) {
2008-06-08 15:56:48 +00:00
offset = BufferOFF [ x ] + BufferOFF [ x + 1 ] * 256 ;
// FIXME: this writes beyond 64000, so the buffer has been initialized
// to 64256 bytes (like the original did)
size = BufferOFF [ x + 2 ] ;
memcpy ( MiVideoOFF + offset , & BufferOFF [ x + 3 ] , size ) ;
x + = 3 + size ;
2008-06-07 19:40:43 +00:00
}
}
2011-05-04 23:54:57 +02:00
void DrasculaEngine : : decodeRLE ( byte * srcPtr , byte * dstPtr , uint16 pitch ) {
2008-06-08 14:59:52 +00:00
bool stopProcessing = false ;
byte pixel ;
uint repeat ;
2011-05-04 23:54:57 +02:00
int curByte = 0 , curLine = 0 ;
pitch - = 320 ;
2008-06-08 14:59:52 +00:00
while ( ! stopProcessing ) {
pixel = * srcPtr + + ;
repeat = 1 ;
if ( ( pixel & 192 ) = = 192 ) {
repeat = ( pixel & 63 ) ;
pixel = * srcPtr + + ;
2008-06-07 19:40:43 +00:00
}
2008-06-08 14:59:52 +00:00
for ( uint j = 0 ; j < repeat ; j + + ) {
2008-08-17 18:58:23 +00:00
* dstPtr + + = pixel ;
2011-05-04 23:54:57 +02:00
if ( + + curByte > = 320 ) {
curByte = 0 ;
dstPtr + = pitch ;
if ( + + curLine > = 200 ) {
stopProcessing = true ;
break ;
}
2008-06-08 14:59:52 +00:00
}
2008-06-07 19:40:43 +00:00
}
}
}
2011-05-04 23:54:57 +02:00
void DrasculaEngine : : mixVideo ( byte * OldScreen , byte * NewScreen , uint16 oldPitch ) {
for ( int y = 0 ; y < 200 ; y + + ) {
for ( int x = 0 ; x < 320 ; x + + )
OldScreen [ x ] ^ = NewScreen [ x ] ;
OldScreen + = oldPitch ;
NewScreen + = 320 ;
}
2008-06-07 19:40:43 +00:00
}
2008-06-08 14:17:35 +00:00
void DrasculaEngine : : waitFrameSSN ( ) {
2008-06-07 19:40:43 +00:00
uint32 now ;
while ( ( now = _system - > getMillis ( ) ) - LastFrame < ( ( uint32 ) globalSpeed ) )
_system - > delayMillis ( globalSpeed - ( now - LastFrame ) ) ;
LastFrame = LastFrame + globalSpeed ;
}
bool DrasculaEngine : : animate ( const char * animationFile , int FPS ) {
2011-11-02 23:18:10 +00:00
int NFrames ;
2008-06-07 19:40:43 +00:00
int cnt = 2 ;
2010-02-08 18:17:32 +00:00
Common : : SeekableReadStream * stream = _archives . open ( animationFile ) ;
2008-06-07 19:40:43 +00:00
2010-02-08 16:14:04 +00:00
if ( ! stream ) {
2008-06-07 19:40:43 +00:00
error ( " Animation file %s not found " , animationFile ) ;
}
2010-02-08 16:14:04 +00:00
NFrames = stream - > readSint32LE ( ) ;
showFrame ( stream , true ) ;
2008-06-08 14:11:22 +00:00
_system - > delayMillis ( 1000 / FPS ) ;
2008-06-07 19:40:43 +00:00
while ( cnt < NFrames ) {
2010-02-08 16:14:04 +00:00
showFrame ( stream ) ;
2008-06-08 14:11:22 +00:00
_system - > delayMillis ( 1000 / FPS ) ;
2008-06-07 19:40:43 +00:00
cnt + + ;
byte key = getScan ( ) ;
if ( key = = Common : : KEYCODE_ESCAPE )
term_int = 1 ;
if ( key ! = 0 )
break ;
}
2010-02-08 16:14:04 +00:00
delete stream ;
2008-06-07 19:40:43 +00:00
2013-01-04 23:06:19 +02:00
return ( ( term_int = = 1 ) | | ( getScan ( ) = = Common : : KEYCODE_ESCAPE ) | | shouldQuit ( ) ) ;
2008-06-07 19:40:43 +00:00
}
} // End of namespace Drascula