scummvm/engines/drascula/drascula.cpp
Thierry Crozat 9230026876 DRASCULA: Fix loading game from launcher
This was particularly an issue when the game had been saved in
chapter 1 as in this case the load would happen too early and
the game would crash. In other cases it was working but was
not optimal (the gane loop was run once before it succeeded
to load the game).

This fixes bug #10959.
2019-05-13 22:56:57 +01:00

1176 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/config-manager.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "backends/audiocd/audiocd.h"
#include "engines/util.h"
#include "drascula/drascula.h"
#include "drascula/console.h"
namespace Drascula {
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;
term_int = 0;
currentChapter = 0;
_loadedDifferentChapter = false;
_canSaveLoad = false;
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;
lowerLimit = 0;
upperLimit = 0;
trackFinal = 0;
_walkToObject = false;
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 = false;
curDirection = 0;
trackProtagonist = 0;
_characterFrame = 0;
_characterVisible = false;
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");
_system->getAudioCDManager()->open();
_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 || f == kSupportsLoadingDuringRuntime || f == kSupportsSavingDuringRuntime);
}
Common::Error DrasculaEngine::run() {
// Initialize backend
initGraphics(320, 200);
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;
case Common::RU_RUS:
_lang = kRussian;
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) {
// Set the current chapter to -1. This forces the load to happen
// later during the game loop, and not now.
currentChapter = -1;
loadGame(directSaveSlotLoading);
currentChapter++;
}
checkCD();
allocMemory();
while (!shouldQuit()) {
int i;
takeObject = 0;
_menuBar = false;
_menuScreen = false;
_hasName = false;
frame_y = 0;
curX = -1;
_characterMoved = false;
trackProtagonist = 3;
_characterFrame = 0;
_characterVisible = true;
checkFlags = 1;
doBreak = 0;
_walkToObject = false;
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;
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;
_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 && currentChapter != 6)
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++;
}
freeMemory();
return Common::kNoError;
}
void DrasculaEngine::endChapter() {
stopSound();
clearRoom();
black();
MusicFadeout();
stopMusic();
}
bool DrasculaEngine::runCurrentChapter() {
int n;
int framesWithoutAction = 0;
_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;
walkToPoint(Common::Point(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) {
stepX = STEP_X;
stepY = STEP_Y;
}
if (!_characterMoved && _walkToObject) {
trackProtagonist = trackFinal;
_walkToObject = false;
}
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)) {
walkToPoint(Common::Point(178, 121));
walkToPoint(Common::Point(169, 135));
} else if (_roomNumber == 14 && (curX == 214) && (curY + curHeight == 121)) {
_walkToObject = true;
walkToPoint(Common::Point(190, 130));
} else if (_roomNumber == 14 && (curX == 246) && (curY + curHeight == 112)) {
_walkToObject = true;
walkToPoint(Common::Point(190, 130));
}
}
moveCursor();
updateScreen();
if (currentChapter == 2) {
if (musicStatus() == 0 && roomMusic != 0)
playMusic(roomMusic);
} else {
if (musicStatus() == 0)
playMusic(roomMusic);
}
_canSaveLoad = true;
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
_canSaveLoad = false;
if (_loadedDifferentChapter)
return true;
if (!_menuScreen && takeObject == 1)
checkObjects();
#ifdef _WIN32_WCE
if (_rightMouseButton) {
if (_menuScreen) {
#else
if (_rightMouseButton == 1 && _menuScreen) {
#endif
_rightMouseButton = 0;
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;
_characterMoved = false;
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) {
selectVerbFromBar();
} else if (_leftMouseButton == 1 && takeObject == 0) {
if (verify1())
return true;
delay(100);
} else if (_leftMouseButton == 1 && takeObject == 1) {
if (verify2())
return true;
}
_menuBar = (_mouseY < 24 && !_menuScreen) ? true : false;
_canSaveLoad = true;
Common::KeyCode key = getScan();
_canSaveLoad = false;
if (_loadedDifferentChapter)
return true;
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 (_objectRect[l].contains(Common::Point(_mouseX, _mouseY)) && 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 (_objectRect[l].contains(Common::Point(_mouseX, _mouseY)) && doBreak == 0) {
roomX = _roomObject[l].x;
roomY = _roomObject[l].y;
trackFinal = trackObj[l];
doBreak = 1;
_walkToObject = true;
startWalking();
}
}
if (doBreak == 0) {
roomX = CLIP<int16>(_mouseX, _walkRect.left, _walkRect.right);
roomY = CLIP<int16>(_mouseY, _walkRect.top + feetHeight, _walkRect.bottom);
startWalking();
}
doBreak = 0;
}
return false;
}
bool DrasculaEngine::verify2() {
int l;
if (_menuScreen) {
if (pickupObject())
return true;
} else {
if (!strcmp(textName, _textmisc[3]) && _hasName) {
if (checkAction(50))
return true;
} else {
for (l = 0; l < numRoomObjs; l++) {
if (_objectRect[l].contains(Common::Point(_mouseX, _mouseY)) && visible[l] == 1) {
trackFinal = trackObj[l];
_walkToObject = true;
walkToPoint(_roomObject[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() && !_loadedDifferentChapter);
}
void DrasculaEngine::pause(int duration) {
delay(duration * 15);
}
int DrasculaEngine::getTime() {
return _system->getMillis() / 10;
}
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;
Common::String filename = "drascula.dat";
int i;
in.open(filename.c_str());
if (!in.isOpen()) {
Common::String errorMessage = Common::String::format(_("Unable to locate the '%s' engine data file."), filename.c_str());
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 = Common::String::format(_("The '%s' engine data file is corrupt."), filename.c_str());
GUIErrorMessage(errorMessage);
warning("%s", errorMessage.c_str());
return false;
}
ver = in.readByte();
if (ver != DRASCULA_DAT_VER) {
Common::String errorMessage = Common::String::format(
_("Incorrect version of the '%s' engine data file found. Expected %d.%d but got %d.%d."),
filename.c_str(), DRASCULA_DAT_VER, 0, ver, 0);
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