scummvm/engines/drascula/drascula.cpp
Filippos Karapetis 9c4d086165 DRASCULA: Handle audio files in the "audio" folder (bug #6631)
The music add-on packs we provide have the audio files in an "audio"
folder, but without clear indication that its contents should be
copied inside the game data folder. Since this can lead to confusion
from users, we just add support for this case
2014-06-15 03:54:43 +03:00

1191 lines
27 KiB
C++

/* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/events.h"
#include "common/keyboard.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/config-manager.h"
#include "common/textconsole.h"
#include "backends/audiocd/audiocd.h"
#include "base/plugins.h"
#include "base/version.h"
#include "engines/util.h"
#include "audio/mixer.h"
#include "drascula/drascula.h"
#include "drascula/console.h"
namespace Drascula {
struct GameSettings {
const char *gameid;
const char *description;
byte id;
uint32 features;
const char *detectname;
};
static const GameSettings drasculaSettings[] = {
{"drascula", "Drascula game", 0, 0, 0},
{NULL, NULL, 0, 0, NULL}
};
DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
_charMap = 0;
_itemLocations = 0;
_polX = 0;
_polY = 0;
_verbBarX = 0;
_x1d_menu = 0;
_y1d_menu = 0;
_frameX = 0;
_candleX = 0;
_candleY = 0;
_pianistX = 0;
_drunkX = 0;
_roomPreUpdates = 0;
_roomUpdates = 0;
_roomActions = 0;
_text = 0;
_textd = 0;
_textb = 0;
_textbj = 0;
_texte = 0;
_texti = 0;
_textl = 0;
_textp = 0;
_textt = 0;
_textvb = 0;
_textsys = 0;
_texthis = 0;
_textverbs = 0;
_textmisc = 0;
_textd1 = 0;
_talkSequences = 0;
_currentSaveSlot = 0;
bjX = 0;
bjY = 0;
trackBJ = 0;
framesWithoutAction = 0;
term_int = 0;
currentChapter = 0;
_loadedDifferentChapter = 0;
musicStopped = 0;
FrameSSN = 0;
globalSpeed = 0;
LastFrame = 0;
flag_tv = 0;
_charMapSize = 0;
_itemLocationsSize = 0;
_polXSize = 0;
_verbBarXSize = 0;
_x1dMenuSize = 0;
_frameXSize = 0;
_candleXSize = 0;
_pianistXSize = 0;
_drunkXSize = 0;
_roomPreUpdatesSize = 0;
_roomUpdatesSize = 0;
_roomActionsSize = 0;
_talkSequencesSize = 0;
_numLangs = 0;
feetHeight = 0;
floorX1 = 0;
floorY1 = 0;
floorX2 = 0;
floorY2 = 0;
lowerLimit = 0;
upperLimit = 0;
trackFinal = 0;
walkToObject = 0;
objExit = 0;
_startTime = 0;
hasAnswer = 0;
savedTime = 0;
breakOut = 0;
vonBraunX = 0;
trackVonBraun = 0;
vonBraunHasMoved = 0;
newHeight = 0;
newWidth = 0;
color_solo = 0;
igorX = 0;
igorY = 0;
trackIgor = 0;
drasculaX = 0;
drasculaY = 0;
trackDrascula = 0;
_roomNumber = 0;
numRoomObjs = 0;
takeObject = 0;
pickedObject = 0;
_subtitlesDisabled = 0;
_menuBar = 0;
_menuScreen = 0;
_hasName = 0;
curExcuseLook = 0;
curExcuseAction = 0;
frame_y = 0;
curX = 0;
curY = 0;
characterMoved = 0;
curDirection = 0;
trackProtagonist = 0;
_characterFrame = 0;
hare_se_ve = 0;
roomX = 0;
roomY = 0;
checkFlags = 0;
doBreak = 0;
stepX = 0;
stepY = 0;
curHeight = 0;
curWidth = 0;
_color = 0;
blinking = 0;
_mouseX = 0;
_mouseY = 0;
_leftMouseButton = 0;
_rightMouseButton = 0;
*textName = 0;
crosshairCursor = 0;
mouseCursor = 0;
bgSurface = 0;
backSurface = 0;
cursorSurface = 0;
drawSurface3 = 0;
drawSurface2 = 0;
tableSurface = 0;
extraSurface = 0;
screenSurface = 0;
frontSurface = 0;
previousMusic = 0;
roomMusic = 0;
_rnd = new Common::RandomSource("drascula");
_console = 0;
const Common::FSNode gameDataDir(ConfMan.get("path"));
SearchMan.addSubDirectoryMatching(gameDataDir, "audio");
int cd_num = ConfMan.getInt("cdrom");
if (cd_num >= 0)
_system->getAudioCDManager()->openCD(cd_num);
_lang = kEnglish;
_keyBufferHead = _keyBufferTail = 0;
_roomHandlers = 0;
}
DrasculaEngine::~DrasculaEngine() {
delete _rnd;
stopSound();
freeRoomsTable();
delete _console;
free(_charMap);
free(_itemLocations);
free(_polX);
free(_polY);
free(_verbBarX);
free(_x1d_menu);
free(_y1d_menu);
free(_frameX);
free(_candleX);
free(_candleY);
free(_pianistX);
free(_drunkX);
free(_roomPreUpdates);
free(_roomUpdates);
free(_roomActions);
free(_talkSequences);
freeTexts(_text);
freeTexts(_textd);
freeTexts(_textb);
freeTexts(_textbj);
freeTexts(_texte);
freeTexts(_texti);
freeTexts(_textl);
freeTexts(_textp);
freeTexts(_textt);
freeTexts(_textvb);
freeTexts(_textsys);
freeTexts(_texthis);
freeTexts(_textverbs);
freeTexts(_textmisc);
freeTexts(_textd1);
}
bool DrasculaEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsRTL);
}
Common::Error DrasculaEngine::run() {
// Initialize backend
initGraphics(320, 200, false);
switch (getLanguage()) {
case Common::EN_ANY:
_lang = kEnglish;
break;
case Common::ES_ESP:
_lang = kSpanish;
break;
case Common::DE_DEU:
_lang = kGerman;
break;
case Common::FR_FRA:
_lang = kFrench;
break;
case Common::IT_ITA:
_lang = kItalian;
break;
default:
warning("Unknown game language. Falling back to English");
_lang = kEnglish;
}
_console = new Console(this);
if (!loadDrasculaDat())
return Common::kUnknownError;
checkForOldSaveGames();
setupRoomsTable();
loadArchives();
// Setup mixer
syncSoundSettings();
currentChapter = 1; // values from 1 to 6 will start each part of game
_loadedDifferentChapter = false;
setTotalPlayTime(0);
// Check if a save is loaded from the launcher
int directSaveSlotLoading = ConfMan.getInt("save_slot");
if (directSaveSlotLoading >= 0) {
loadGame(directSaveSlotLoading);
}
checkCD();
while (!shouldQuit()) {
int i;
takeObject = 0;
_menuBar = false;
_menuScreen = false;
_hasName = false;
frame_y = 0;
curX = -1;
characterMoved = 0;
trackProtagonist = 3;
_characterFrame = 0;
hare_se_ve = 1;
checkFlags = 1;
doBreak = 0;
walkToObject = 0;
stepX = STEP_X;
stepY = STEP_Y;
curHeight = CHARACTER_HEIGHT;
curWidth = CHARACTER_WIDTH;
feetHeight = FEET_HEIGHT;
hasAnswer = 0;
savedTime = 0;
breakOut = 0;
vonBraunX = 120;
trackVonBraun = 1;
vonBraunHasMoved = 0;
framesWithoutAction = 0;
term_int = 0;
musicStopped = 0;
globalSpeed = 0;
curExcuseLook = 0;
curExcuseAction = 0;
_roomNumber = 0;
for (i = 0; i < 8; i++)
actorFrames[i] = 0;
actorFrames[kFrameVonBraun] = 1;
allocMemory();
_subtitlesDisabled = !ConfMan.getBool("subtitles");
if (currentChapter != 3)
loadPic(96, frontSurface, COMPLETE_PAL);
loadPic(99, cursorSurface);
if (currentChapter == 1) {
} else if (currentChapter == 2) {
loadPic("pts.alg", drawSurface2);
} else if (currentChapter == 3) {
loadPic("aux13.alg", bgSurface, COMPLETE_PAL);
loadPic(96, frontSurface);
} else if (currentChapter == 4) {
if (!_loadedDifferentChapter)
animation_castle();
loadPic(96, frontSurface);
clearRoom();
} else if (currentChapter == 5) {
} else if (currentChapter == 6) {
igorX = 105;
igorY = 85;
trackIgor = 1;
drasculaX = 62;
drasculaY = 99;
trackDrascula = 1;
actorFrames[kFramePendulum] = 0;
flag_tv = 0;
}
loadPic(95, tableSurface);
for (i = 0; i < 25; i++)
memcpy(crosshairCursor + i * 40, tableSurface + 225 + (56 + i) * 320, 40);
if (_lang == kSpanish)
loadPic(974, tableSurface);
if (currentChapter != 2) {
loadPic(99, cursorSurface);
loadPic(99, backSurface);
loadPic(97, extraSurface);
}
memset(iconName, 0, sizeof(iconName));
for (i = 0; i < 6; i++)
Common::strlcpy(iconName[i + 1], _textverbs[i], 13);
assignPalette(defaultPalette);
if (!runCurrentChapter()) {
endChapter();
break;
}
endChapter();
if (currentChapter == 6)
break;
currentChapter++;
}
return Common::kNoError;
}
void DrasculaEngine::endChapter() {
stopSound();
clearRoom();
black();
MusicFadeout();
stopMusic();
freeMemory();
}
bool DrasculaEngine::runCurrentChapter() {
int n;
_rightMouseButton = 0;
previousMusic = -1;
if (currentChapter != 2) {
int soc = 0;
for (n = 0; n < 6; n++) {
soc = soc + CHARACTER_WIDTH;
_frameX[n] = soc;
}
}
for (n = 1; n < ARRAYSIZE(inventoryObjects); n++)
inventoryObjects[n] = 0;
for (n = 0; n < NUM_FLAGS; n++)
flags[n] = 0;
if (currentChapter == 2) {
flags[16] = 1;
flags[17] = 1;
flags[27] = 1;
}
for (n = 1; n < 7; n++)
inventoryObjects[n] = n;
if (currentChapter == 1) {
pickObject(28);
if (!_loadedDifferentChapter)
animation_1_1();
selectVerb(kVerbNone);
loadPic("2aux62.alg", drawSurface2);
trackProtagonist = 1;
objExit = 104;
if (_loadedDifferentChapter) {
if (!loadGame(_currentSaveSlot)) {
return true;
}
} else {
enterRoom(62);
curX = -20;
curY = 56;
gotoObject(65, 145);
}
// REMINDER: This is a good place to debug animations
} else if (currentChapter == 2) {
addObject(kItemPhone);
trackProtagonist = 3;
objExit = 162;
if (!_loadedDifferentChapter)
enterRoom(14);
else {
if (!loadGame(_currentSaveSlot)) {
return true;
}
}
} else if (currentChapter == 3) {
addObject(kItemPhone);
addObject(kItemEarplugs);
addObject(kItemSickle);
addObject(kItemHandbag);
addObject(kItemCross);
addObject(kItemReefer);
addObject(kItemOneCoin);
flags[1] = 1;
trackProtagonist = 1;
objExit = 99;
if (!_loadedDifferentChapter)
enterRoom(20);
else {
if (!loadGame(_currentSaveSlot)) {
return true;
}
}
// From here onwards the items have different IDs
} else if (currentChapter == 4) {
addObject(kItemPhone2);
addObject(kItemCross2);
addObject(kItemReefer2);
addObject(kItemOneCoin2);
objExit = 100;
if (!_loadedDifferentChapter) {
enterRoom(21);
trackProtagonist = 0;
curX = 235;
curY = 164;
} else {
if (!loadGame(_currentSaveSlot)) {
return true;
}
}
} else if (currentChapter == 5) {
addObject(28);
addObject(7);
addObject(9);
addObject(11);
addObject(13);
addObject(14);
addObject(15);
addObject(17);
addObject(20);
trackProtagonist = 1;
objExit = 100;
if (!_loadedDifferentChapter) {
enterRoom(45);
} else {
if (!loadGame(_currentSaveSlot)) {
return true;
}
}
} else if (currentChapter == 6) {
addObject(28);
addObject(9);
trackProtagonist = 1;
objExit = 104;
if (!_loadedDifferentChapter) {
enterRoom(58);
animation_1_6();
} else {
if (!loadGame(_currentSaveSlot)) {
return true;
}
loadPic("auxdr.alg", drawSurface2);
}
}
showCursor();
while (!shouldQuit()) {
if (characterMoved == 0) {
stepX = STEP_X;
stepY = STEP_Y;
}
if (characterMoved == 0 && walkToObject == 1) {
trackProtagonist = trackFinal;
walkToObject = 0;
}
if (currentChapter == 2) {
// NOTE: the checks for room number 14 below are a hack used in the original
// game, and move the character to a place where his feet are not drawn above
// the pianist's head. Originally, walkToObject was not updated properly, which
// lead to an incorrect setting of the protagonist's tracking flag (above). This
// made the character start walking off screen, as his actual position was
// different than the displayed one
if (_roomNumber == 3 && (curX == 279) && (curY + curHeight == 101)) {
gotoObject(178, 121);
gotoObject(169, 135);
} else if (_roomNumber == 14 && (curX == 214) && (curY + curHeight == 121)) {
walkToObject = 1;
gotoObject(190, 130);
} else if (_roomNumber == 14 && (curX == 246) && (curY + curHeight == 112)) {
walkToObject = 1;
gotoObject(190, 130);
}
}
moveCursor();
updateScreen();
if (currentChapter == 2) {
if (musicStatus() == 0 && roomMusic != 0)
playMusic(roomMusic);
} else {
if (musicStatus() == 0)
playMusic(roomMusic);
}
delay(25);
#ifndef _WIN32_WCE
// FIXME
// This and the following #ifndefs disable the excess updateEvents() calls *within* the game loop.
// Events such as keypresses or mouse clicks are dropped on the ground with no processing
// by these calls. They are properly handled by the implicit call through getScan() below.
// It is not a good practice to not process events and indeed this created problems with synthesized
// events in the wince port.
updateEvents();
#endif
if (!_menuScreen && takeObject == 1)
checkObjects();
#ifdef _WIN32_WCE
if (_rightMouseButton) {
if (_menuScreen) {
#else
if (_rightMouseButton == 1 && _menuScreen) {
#endif
_rightMouseButton = 0;
delay(100);
if (currentChapter == 2) {
loadPic(menuBackground, cursorSurface);
loadPic(menuBackground, backSurface);
} else {
loadPic(99, cursorSurface);
loadPic(99, backSurface);
}
setPalette((byte *)&gamePalette);
_menuScreen = false;
#ifndef _WIN32_WCE
// FIXME: This call here is in hope that it will catch the rightmouseup event so the
// next if block won't be executed. This too is not a good coding practice. I've recoded it
// with a mutual exclusive if block for the menu. I would commit this properly but I cannot test
// for other (see Desktop) ports right now.
updateEvents();
#endif
#ifdef _WIN32_WCE
} else {
#else
}
// Do not show the inventory screen in chapter 5, if the right mouse button is clicked
// while the plug (object 16) is held
// Fixes bug #2059621 - "DRASCULA: Plug bug"
if (_rightMouseButton == 1 && !_menuScreen &&
!(currentChapter == 5 && pickedObject == 16)) {
#endif
_rightMouseButton = 0;
delay(100);
characterMoved = 0;
if (trackProtagonist == 2)
trackProtagonist = 1;
if (currentChapter == 4) {
loadPic("icons2.alg", backSurface);
loadPic("icons2.alg", cursorSurface);
} else if (currentChapter == 5) {
loadPic("icons3.alg", backSurface);
loadPic("icons3.alg", cursorSurface);
} else if (currentChapter == 6) {
loadPic("iconsp.alg", backSurface);
loadPic("iconsp.alg", cursorSurface);
} else {
loadPic("icons.alg", backSurface);
loadPic("icons.alg", cursorSurface);
}
_menuScreen = true;
#ifndef _WIN32_WCE
updateEvents();
#endif
selectVerb(kVerbNone);
}
#ifdef _WIN32_WCE
}
#endif
if (_leftMouseButton == 1 && _menuBar) {
delay(100);
selectVerbFromBar();
} else if (_leftMouseButton == 1 && takeObject == 0) {
delay(100);
if (verify1())
return true;
} else if (_leftMouseButton == 1 && takeObject == 1) {
if (verify2())
return true;
}
_menuBar = (_mouseY < 24 && !_menuScreen) ? true : false;
Common::KeyCode key = getScan();
if (key == Common::KEYCODE_F1 && !_menuScreen) {
selectVerb(kVerbLook);
} else if (key == Common::KEYCODE_F2 && !_menuScreen) {
selectVerb(kVerbPick);
} else if (key == Common::KEYCODE_F3 && !_menuScreen) {
selectVerb(kVerbOpen);
} else if (key == Common::KEYCODE_F4 && !_menuScreen) {
selectVerb(kVerbClose);
} else if (key == Common::KEYCODE_F5 && !_menuScreen) {
selectVerb(kVerbTalk);
} else if (key == Common::KEYCODE_F6 && !_menuScreen) {
selectVerb(kVerbMove);
} else if (key == Common::KEYCODE_F7) {
// ScummVM load screen
if (!scummVMSaveLoadDialog(false))
return true;
} else if (key == Common::KEYCODE_F8) {
selectVerb(kVerbNone);
} else if (key == Common::KEYCODE_F9) {
volumeControls();
} else if (key == Common::KEYCODE_F10) {
if (!ConfMan.getBool("originalsaveload")) {
// ScummVM save screen
scummVMSaveLoadDialog(true);
} else {
// Original save/load screen
if (!saveLoadScreen())
return true;
}
} else if (key == Common::KEYCODE_v) {
_subtitlesDisabled = true;
ConfMan.setBool("subtitles", !_subtitlesDisabled);
print_abc(_textsys[2], 96, 86);
updateScreen();
delay(1410);
} else if (key == Common::KEYCODE_t) {
_subtitlesDisabled = false;
ConfMan.setBool("subtitles", !_subtitlesDisabled);
print_abc(_textsys[3], 94, 86);
updateScreen();
delay(1460);
} else if (key == Common::KEYCODE_ESCAPE) {
if (!confirmExit())
return false;
} else if (key == Common::KEYCODE_TILDE || key == Common::KEYCODE_BACKQUOTE) {
_console->attach();
_console->onFrame();
} else if (currentChapter == 6 && key == Common::KEYCODE_0 && _roomNumber == 61) {
loadPic("alcbar.alg", bgSurface, 255);
}
if (_leftMouseButton != 0 || _rightMouseButton != 0 || key != 0)
framesWithoutAction = 0;
if (framesWithoutAction == 15000) {
screenSaver();
framesWithoutAction = 0;
}
framesWithoutAction++;
}
return false;
}
bool DrasculaEngine::verify1() {
int l;
if (_menuScreen)
removeObject();
else {
for (l = 0; l < numRoomObjs; l++) {
if (_mouseX >= _objectX1[l] && _mouseY >= _objectY1[l]
&& _mouseX <= _objectX2[l] && _mouseY <= _objectY2[l] && doBreak == 0) {
if (exitRoom(l))
return true;
if (doBreak == 1)
break;
}
}
if (_mouseX > curX && _mouseY > curY
&& _mouseX < curX + curWidth && _mouseY < curY + curHeight)
doBreak = 1;
for (l = 0; l < numRoomObjs; l++) {
if (_mouseX > _objectX1[l] && _mouseY > _objectY1[l]
&& _mouseX < _objectX2[l] && _mouseY < _objectY2[l] && doBreak == 0) {
roomX = roomObjX[l];
roomY = roomObjY[l];
trackFinal = trackObj[l];
doBreak = 1;
walkToObject = 1;
startWalking();
}
}
if (doBreak == 0) {
roomX = CLIP(_mouseX, floorX1, floorX2);
roomY = CLIP(_mouseY, floorY1 + feetHeight, floorY2);
startWalking();
}
doBreak = 0;
}
return false;
}
bool DrasculaEngine::verify2() {
int l;
if (_menuScreen) {
if (pickupObject())
return true;
} else {
if (!strcmp(textName, "hacker") && _hasName) {
if (checkAction(50))
return true;
} else {
for (l = 0; l < numRoomObjs; l++) {
if (_mouseX > _objectX1[l] && _mouseY > _objectY1[l]
&& _mouseX < _objectX2[l] && _mouseY < _objectY2[l] && visible[l] == 1) {
trackFinal = trackObj[l];
walkToObject = 1;
gotoObject(roomObjX[l], roomObjY[l]);
if (checkAction(objectNum[l]))
return true;
if (currentChapter == 4)
break;
}
}
}
}
return false;
}
Common::KeyCode DrasculaEngine::getScan() {
updateEvents();
if (_keyBufferHead == _keyBufferTail)
return Common::KEYCODE_INVALID;
Common::KeyCode key = _keyBuffer[_keyBufferTail].keycode;
_keyBufferTail = (_keyBufferTail + 1) % KEYBUFSIZE;
return key;
}
void DrasculaEngine::addKeyToBuffer(Common::KeyState& key) {
if ((_keyBufferHead + 1) % KEYBUFSIZE == _keyBufferTail) {
warning("key buffer overflow");
return;
}
_keyBuffer[_keyBufferHead] = key;
_keyBufferHead = (_keyBufferHead + 1) % KEYBUFSIZE;
}
void DrasculaEngine::flushKeyBuffer() {
updateEvents();
_keyBufferHead = _keyBufferTail = 0;
}
void DrasculaEngine::updateEvents() {
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
updateMusic();
#ifdef _WIN32_WCE
if (eventMan->pollEvent(event)) {
#else
while (eventMan->pollEvent(event)) {
#endif
switch (event.type) {
case Common::EVENT_KEYDOWN:
if (event.kbd.keycode == Common::KEYCODE_d && event.kbd.hasFlags(Common::KBD_CTRL)) {
// Start the debugger
getDebugger()->attach();
getDebugger()->onFrame();
}
addKeyToBuffer(event.kbd);
break;
case Common::EVENT_KEYUP:
break;
case Common::EVENT_MOUSEMOVE:
_mouseX = event.mouse.x;
_mouseY = event.mouse.y;
break;
case Common::EVENT_LBUTTONDOWN:
_leftMouseButton = 1;
break;
case Common::EVENT_LBUTTONUP:
_leftMouseButton = 0;
break;
case Common::EVENT_RBUTTONDOWN:
// We changed semantic and react only on button up event
break;
case Common::EVENT_RBUTTONUP:
_rightMouseButton = 1;
break;
default:
break;
}
}
}
void DrasculaEngine::delay(int ms) {
uint32 end = _system->getMillis() + ms * 2; // originally was 1
do {
_system->delayMillis(10);
updateEvents();
_system->updateScreen();
} while (_system->getMillis() < end && !shouldQuit());
}
void DrasculaEngine::pause(int duration) {
delay(duration * 15);
}
int DrasculaEngine::getTime() {
return _system->getMillis() / 20; // originally was 1
}
void DrasculaEngine::reduce_hare_chico(int xx1, int yy1, int xx2, int yy2, int width, int height, int factor, byte *dir_inicio, byte *dir_fin) {
float totalX, totalY;
int n, m;
float pixelX, pixelY;
newWidth = (width * factor) / 100;
newHeight = (height * factor) / 100;
totalX = width / newWidth;
totalY = height / newHeight;
pixelX = xx1;
pixelY = yy1;
for (n = 0; n < newHeight; n++) {
for (m = 0; m < newWidth; m++) {
copyRect((int)pixelX, (int)pixelY, xx2 + m, yy2 + n,
1, 1, dir_inicio, dir_fin);
pixelX += totalX;
}
pixelX = xx1;
pixelY += totalY;
}
}
void DrasculaEngine::hipo_sin_nadie(int counter){
int y = 0, trackCharacter = 0;
if (currentChapter == 3)
y = -1;
do {
counter--;
copyBackground();
if (currentChapter == 3)
updateScreen(0, 0, 0, y, 320, 200, screenSurface);
else
updateScreen(0, 1, 0, y, 320, 198, screenSurface);
if (trackCharacter == 0)
y++;
else
y--;
if (currentChapter == 3) {
if (y == 1)
trackCharacter = 1;
if (y == -1)
trackCharacter = 0;
} else {
if (y == 2)
trackCharacter = 1;
if (y == 0)
trackCharacter = 0;
}
} while (counter > 0);
copyBackground();
updateScreen();
}
bool DrasculaEngine::loadDrasculaDat() {
Common::File in;
int i;
in.open("drascula.dat");
if (!in.isOpen()) {
Common::String errorMessage = "You're missing the 'drascula.dat' file. Get it from the ScummVM website";
GUIErrorMessage(errorMessage);
warning("%s", errorMessage.c_str());
return false;
}
char buf[256];
int ver;
in.read(buf, 8);
buf[8] = '\0';
if (strcmp(buf, "DRASCULA") != 0) {
Common::String errorMessage = "File 'drascula.dat' is corrupt. Get it from the ScummVM website";
GUIErrorMessage(errorMessage);
warning("%s", errorMessage.c_str());
return false;
}
ver = in.readByte();
if (ver != DRASCULA_DAT_VER) {
Common::String errorMessage = Common::String::format("File 'drascula.dat' is wrong version. Expected %d but got %d. Get it from the ScummVM website", DRASCULA_DAT_VER, ver);
GUIErrorMessage(errorMessage);
warning("%s", errorMessage.c_str());
return false;
}
_charMapSize = in.readUint16BE();
_charMap = (CharInfo *)malloc(sizeof(CharInfo) * _charMapSize);
for (i = 0; i < _charMapSize; i++) {
_charMap[i].inChar = in.readByte();
_charMap[i].mappedChar = in.readSint16BE();
_charMap[i].charType = in.readByte();
}
_itemLocationsSize = in.readUint16BE();
_itemLocations = (ItemLocation *)malloc(sizeof(ItemLocation) * _itemLocationsSize);
for (i = 0; i < _itemLocationsSize; i++) {
_itemLocations[i].x = in.readSint16BE();
_itemLocations[i].y = in.readSint16BE();
}
_polXSize = in.readUint16BE();
_polX = (int *)malloc(sizeof(int) * _polXSize);
_polY = (int *)malloc(sizeof(int) * _polXSize);
for (i = 0; i < _polXSize; i++) {
_polX[i] = in.readSint16BE();
_polY[i] = in.readSint16BE();
}
_verbBarXSize = in.readUint16BE();
_verbBarX = (int *)malloc(sizeof(int) * _verbBarXSize);
for (i = 0; i < _verbBarXSize; i++) {
_verbBarX[i] = in.readSint16BE();
}
_x1dMenuSize = in.readUint16BE();
_x1d_menu = (int *)malloc(sizeof(int) * _x1dMenuSize);
_y1d_menu = (int *)malloc(sizeof(int) * _x1dMenuSize);
for (i = 0; i < _x1dMenuSize; i++) {
_x1d_menu[i] = in.readSint16BE();
_y1d_menu[i] = in.readSint16BE();
}
_frameXSize = in.readUint16BE();
_frameX = (int *)malloc(sizeof(int) * _frameXSize);
for (i = 0; i < _frameXSize; i++) {
_frameX[i] = in.readSint16BE();
}
_candleXSize = in.readUint16BE();
_candleX = (int *)malloc(sizeof(int) * _candleXSize);
_candleY = (int *)malloc(sizeof(int) * _candleXSize);
for (i = 0; i < _candleXSize; i++) {
_candleX[i] = in.readSint16BE();
_candleY[i] = in.readSint16BE();
}
_pianistXSize = in.readUint16BE();
_pianistX = (int *)malloc(sizeof(int) * _pianistXSize);
for (i = 0; i < _pianistXSize; i++) {
_pianistX[i] = in.readSint16BE();
}
_drunkXSize = in.readUint16BE();
_drunkX = (int *)malloc(sizeof(int) * _drunkXSize);
for (i = 0; i < _drunkXSize; i++) {
_drunkX[i] = in.readSint16BE();
}
_roomPreUpdatesSize = in.readUint16BE();
_roomPreUpdates = (RoomUpdate *)malloc(sizeof(RoomUpdate) * _roomPreUpdatesSize);
for (i = 0; i < _roomPreUpdatesSize; i++) {
_roomPreUpdates[i].roomNum = in.readSint16BE();
_roomPreUpdates[i].flag = in.readSint16BE();
_roomPreUpdates[i].flagValue = in.readSint16BE();
_roomPreUpdates[i].sourceX = in.readSint16BE();
_roomPreUpdates[i].sourceY = in.readSint16BE();
_roomPreUpdates[i].destX = in.readSint16BE();
_roomPreUpdates[i].destY = in.readSint16BE();
_roomPreUpdates[i].width = in.readSint16BE();
_roomPreUpdates[i].height = in.readSint16BE();
_roomPreUpdates[i].type = in.readSint16BE();
}
_roomUpdatesSize = in.readUint16BE();
_roomUpdates = (RoomUpdate *)malloc(sizeof(RoomUpdate) * _roomUpdatesSize);
for (i = 0; i < _roomUpdatesSize; i++) {
_roomUpdates[i].roomNum = in.readSint16BE();
_roomUpdates[i].flag = in.readSint16BE();
_roomUpdates[i].flagValue = in.readSint16BE();
_roomUpdates[i].sourceX = in.readSint16BE();
_roomUpdates[i].sourceY = in.readSint16BE();
_roomUpdates[i].destX = in.readSint16BE();
_roomUpdates[i].destY = in.readSint16BE();
_roomUpdates[i].width = in.readSint16BE();
_roomUpdates[i].height = in.readSint16BE();
_roomUpdates[i].type = in.readSint16BE();
}
_roomActionsSize = in.readUint16BE();
_roomActions = (RoomTalkAction *)malloc(sizeof(RoomTalkAction) * _roomActionsSize);
for (i = 0; i < _roomActionsSize; i++) {
_roomActions[i].room = in.readSint16BE();
_roomActions[i].chapter = in.readSint16BE();
_roomActions[i].action = in.readSint16BE();
_roomActions[i].objectID = in.readSint16BE();
_roomActions[i].speechID = in.readSint16BE();
}
_talkSequencesSize = in.readUint16BE();
_talkSequences = (TalkSequenceCommand *)malloc(sizeof(TalkSequenceCommand) * _talkSequencesSize);
for (i = 0; i < _talkSequencesSize; i++) {
_talkSequences[i].chapter = in.readSint16BE();
_talkSequences[i].sequence = in.readSint16BE();
_talkSequences[i].commandType = in.readSint16BE();
_talkSequences[i].action = in.readSint16BE();
}
_numLangs = in.readUint16BE();
_text = loadTexts(in);
_textd = loadTexts(in);
_textb = loadTexts(in);
_textbj = loadTexts(in);
_texte = loadTexts(in);
_texti = loadTexts(in);
_textl = loadTexts(in);
_textp = loadTexts(in);
_textt = loadTexts(in);
_textvb = loadTexts(in);
_textsys = loadTexts(in);
_texthis = loadTexts(in);
_textverbs = loadTexts(in);
_textmisc = loadTexts(in);
_textd1 = loadTexts(in);
return true;
}
char **DrasculaEngine::loadTexts(Common::File &in) {
int numTexts = in.readUint16BE();
char **res = (char **)malloc(sizeof(char *) * numTexts);
int entryLen;
char *pos = 0;
int len;
for (int lang = 0; lang < _numLangs; lang++) {
entryLen = in.readUint16BE();
if (lang == _lang) {
pos = (char *)malloc(entryLen);
in.read(pos, entryLen);
res[0] = pos;
pos += DATAALIGNMENT;
for (int i = 1; i < numTexts; i++) {
pos -= 2;
len = READ_BE_UINT16(pos);
pos += 2 + len;
res[i] = pos;
}
} else
in.seek(entryLen, SEEK_CUR);
}
return res;
}
void DrasculaEngine::freeTexts(char **ptr) {
if (!ptr)
return;
free(*ptr);
free(ptr);
}
} // End of namespace Drascula