mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-18 23:57:32 +00:00
1188 lines
27 KiB
C++
1188 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;
|
|
|
|
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
|