scummvm/engines/lure/lure.cpp
Eugene Sandulenko cd8a5f3a98 First phase of detection-related plugins interface improvements. Now plugins
return StringMap instead of fixed list of parameters. This adds great
flexibility.

Current patch should not alter any functionality, i.e. if there are regressions,
submit a report. Phase 2 will benefit from these changes and will come later.

svn-id: r25134
2007-01-20 21:27:57 +00:00

429 lines
10 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2005-2006 The ScummVM project
*
* 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.
*
* $URL$
* $Id$
*
*/
#include "common/stdafx.h"
#include "base/plugins.h"
#include "common/config-manager.h"
#include "common/endian.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/system.h"
#include "common/md5.h"
#include "common/savefile.h"
#include "common/stream.h"
#include "sound/mixer.h"
#include "sound/mididrv.h"
#include "sound/audiostream.h"
#include "lure/luredefs.h"
#include "lure/surface.h"
#include "lure/lure.h"
#include "lure/intro.h"
#include "lure/game.h"
#include "lure/system.h"
namespace Lure {
enum {
// We only compute MD5 of the first kilobyte of our data files.
kMD5FileSizeLimit = 1024
};
struct GameSettings {
const char *gameid;
const char *description;
byte id;
uint32 features;
Common::Language language;
const char *md5sum;
const char *checkFile;
};
//
static const GameSettings lure_games[] = {
{ "lure", "Lure of the Temptress", GI_LURE, GF_FLOPPY, Common::EN_ANY,
"b2a8aa6d7865813a17a3c636e063572e", "disk1.vga" },
/*
{ "lure", "Lure of the Temptress", GI_LURE, GF_FLOPPY, Common::DE_DEU,
"7aa19e444dab1ac7194d9f7a40ffe54a", "disk1.vga" },
{ "lure", "Lure of the Temptress", GI_LURE, GF_FLOPPY, Common::FR_FRA,
"1c94475c1bb7e0e88c1757d3b5377e94", "disk1.vga" },
*/
{ 0, 0, 0, 0, Common::UNK_LANG, 0, 0 }
};
// Keep list of different supported games
static const PlainGameDescriptor lure_list[] = {
{ "lure", "Lure of the Temptress" },
{ 0, 0 }
};
} // End of namespace Lure
using namespace Lure;
GameList Engine_LURE_gameIDList() {
GameList games;
const PlainGameDescriptor *g = lure_list;
while (g->gameid) {
games.push_back(*g);
g++;
}
return games;
}
GameDescriptor Engine_LURE_findGameID(const char *gameid) {
const PlainGameDescriptor *g = lure_list;
while (g->gameid) {
if (0 == scumm_stricmp(gameid, g->gameid))
break;
g++;
}
return GameDescriptor(g->gameid, g->description);
}
GameList Engine_LURE_detectGames(const FSList &fslist) {
GameList detectedGames;
const GameSettings *g;
FSList::const_iterator file;
// Iterate over all files in the given directory
bool isFound = false;
for (file = fslist.begin(); file != fslist.end(); file++) {
if (file->isDirectory())
continue;
for (g = lure_games; g->gameid; g++) {
if (scumm_stricmp(file->name().c_str(), g->checkFile) == 0)
isFound = true;
}
if (isFound)
break;
}
if (file == fslist.end())
return detectedGames;
uint8 md5sum[16];
char md5str[32 + 1];
if (Common::md5_file(*file, md5sum, kMD5FileSizeLimit)) {
for (int i = 0; i < 16; i++) {
sprintf(md5str + i * 2, "%02x", (int)md5sum[i]);
}
for (g = lure_games; g->gameid; g++) {
if (strcmp(g->md5sum, (char *)md5str) == 0) {
GameDescriptor dg(g->gameid, g->description, g->language);
dg.updateDesc((g->features & GF_FLOPPY) ? "Floppy" : 0);
detectedGames.push_back(dg);
}
}
if (detectedGames.empty()) {
debug("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team\n", md5str);
const PlainGameDescriptor *g1 = lure_list;
while (g1->gameid) {
detectedGames.push_back(*g1);
g1++;
}
}
}
return detectedGames;
}
PluginError Engine_LURE_create(OSystem *syst, Engine **engine) {
assert(engine);
*engine = new LureEngine(syst);
return kNoError;
}
REGISTER_PLUGIN(LURE, "Lure of the Temptress Engine", "Lure of the Temptress (C) Revolution");
namespace Lure {
static LureEngine *int_engine = NULL;
LureEngine::LureEngine(OSystem *system): Engine(system) {
Common::addSpecialDebugLevel(kLureDebugScripts, "scripts", "Scripts debugging");
Common::addSpecialDebugLevel(kLureDebugAnimations, "animations", "Animations debugging");
Common::addSpecialDebugLevel(kLureDebugHotspots, "hotspots", "Hotspots debugging");
// Setup mixer
/*
if (!_mixer->isReady()) {
warning("Sound initialization failed.");
}
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
*/
_features = 0;
_game = 0;
}
void LureEngine::detectGame() {
// Make sure all the needed files are present
if (!Common::File::exists(SUPPORT_FILENAME))
error("Missing %s - this is a custom file containing resources from the\n"
"Lure of the Temptress executable. See the documentation for creating it.",
SUPPORT_FILENAME);
for (uint8 fileNum = 1; fileNum <= 4; ++fileNum)
{
char sFilename[10];
sprintf(sFilename, "disk%d.vga", fileNum);
if (!Common::File::exists(sFilename))
error("Missing disk%d.vga", fileNum);
}
// Check the version of the lure.dat file
Common::File f;
if (!f.open(SUPPORT_FILENAME)) {
error("Error opening %s for validation", SUPPORT_FILENAME);
} else {
f.seek(0xbf * 8);
VersionStructure version;
f.read(&version, sizeof(VersionStructure));
f.close();
if (READ_LE_UINT16(&version.id) != 0xffff)
error("Error validating %s - file is invalid or out of date", SUPPORT_FILENAME);
else if ((version.vMajor != LURE_DAT_MAJOR) || (version.vMinor != LURE_DAT_MINOR))
error("Incorrect version of %s file - expected %d.%d but got %d.%d",
SUPPORT_FILENAME, LURE_DAT_MAJOR, LURE_DAT_MINOR,
version.vMajor, version.vMinor);
}
// Do an md5 check
uint8 md5sum[16];
char md5str[32 + 1];
const GameSettings *g;
bool found = false;
*md5str = 0;
for (g = lure_games; g->gameid; g++) {
if (!Common::File::exists(g->checkFile))
continue;
if (Common::md5_file(g->checkFile, md5sum, kMD5FileSizeLimit)) {
for (int j = 0; j < 16; j++) {
sprintf(md5str + j * 2, "%02x", (int)md5sum[j]);
}
} else
continue;
if (strcmp(g->md5sum, (char *)md5str) == 0) {
_features = g->features;
_game = g->id;
_language = g->language;
if (g->description)
g_system->setWindowCaption(g->description);
found = true;
break;
}
}
if (!found) {
debug("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team", md5str);
_features = GF_LNGUNK || GF_FLOPPY;
_game = GI_LURE;
}
}
int LureEngine::init() {
_system->beginGFXTransaction();
initCommonGFX(false);
_system->initSize(FULL_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
_system->endGFXTransaction();
detectGame();
_sys = new System(_system);
_disk = new Disk();
_resources = new Resources();
_strings = new StringData();
_screen = new Screen(*_system);
_mouse = new Mouse();
_events = new Events();
_menu = new Menu();
Surface::initialise();
_room = new Room();
int_engine = this;
return 0;
}
LureEngine::~LureEngine() {
// Remove all of our debug levels here
Common::clearAllSpecialDebugLevels();
// Delete and deinitialise subsystems
Surface::deinitialise();
delete _room;
delete _menu;
delete _events;
delete _mouse;
delete _screen;
delete _strings;
delete _resources;
delete _disk;
delete _sys;
}
LureEngine &LureEngine::getReference() {
return *int_engine;
}
int LureEngine::go() {
if (ConfMan.getInt("boot_param") == 0) {
// Show the introduction
Introduction *intro = new Introduction(*_screen, *_system);
intro->show();
delete intro;
}
// Play the game
if (!_events->quitFlag) {
// Play the game
Game *gameInstance = new Game();
gameInstance->execute();
delete gameInstance;
}
//quitGame();
return 0;
}
void LureEngine::quitGame() {
_system->quit();
}
const char *LureEngine::generateSaveName(int slotNumber) {
static char buffer[15];
sprintf(buffer, "lure.%.3d", slotNumber);
return buffer;
}
bool LureEngine::saveGame(uint8 slotNumber, Common::String &caption) {
Common::WriteStream *f = this->_saveFileMan->openForSaving(
generateSaveName(slotNumber));
if (f == NULL) {
warning("saveGame: Failed to save slot %d", slotNumber);
return false;
}
f->write("lure", 5);
f->writeByte(_language);
f->writeByte(LURE_DAT_MINOR);
f->writeString(caption);
f->writeByte(0); // End of string terminator
Room::getReference().saveToStream(f);
Resources::getReference().saveToStream(f);
delete f;
return true;
}
#define FAILED_MSG "loadGame: Failed to load slot %d"
bool LureEngine::loadGame(uint8 slotNumber) {
Common::ReadStream *f = this->_saveFileMan->openForLoading(
generateSaveName(slotNumber));
if (f == NULL) {
warning(FAILED_MSG, slotNumber);
return false;
}
// Check for header
char buffer[5];
f->read(buffer, 5);
if (memcmp(buffer, "lure", 5) != 0)
{
warning(FAILED_MSG, slotNumber);
delete f;
return false;
}
// Check language version
uint8 language = f->readByte();
uint8 version = f->readByte();
if ((language != _language) || (version != LURE_DAT_MINOR))
{
warning("loadGame: Failed to load slot %d - incorrect version", slotNumber);
delete f;
return false;
}
// Read in and discard the savegame caption
while (f->readByte() != 0) ;
// Load in the data
Room::getReference().loadFromStream(f);
Resources::getReference().loadFromStream(f);
delete f;
return true;
}
Common::String *LureEngine::detectSave(int slotNumber) {
Common::ReadStream *f = this->_saveFileMan->openForLoading(
generateSaveName(slotNumber));
if (f == NULL) return NULL;
Common::String *result = NULL;
// Check for header
char buffer[5];
f->read(&buffer[0], 5);
if (memcmp(&buffer[0], "lure", 5) == 0) {
// Check language version
uint8 language = f->readByte();
uint8 version = f->readByte();
if ((language == _language) && (version == LURE_DAT_MINOR)) {
// Read in the savegame title
char saveName[MAX_DESC_SIZE];
char *p = saveName;
int decCtr = MAX_DESC_SIZE - 1;
while ((decCtr > 0) && ((*p++ = f->readByte()) != 0)) --decCtr;
*p = '\0';
result = new Common::String(saveName);
}
}
delete f;
return result;
}
} // End of namespace Lure