First part of GSoC2008 RTL branch merge

svn-id: r34241
This commit is contained in:
Max Horn 2008-09-01 17:30:03 +00:00
commit 027ae0a6f6
18 changed files with 885 additions and 36 deletions

125
README
View File

@ -39,10 +39,12 @@ Table of Contents:
* 5.1 Command Line Options
* 5.2 Language Options
* 5.3 Graphics Filters
* 5.4 Hotkeys
* 5.4 Global Menu
* 5.5 Hotkeys
6.0) Savegames
* 6.1 Autosaves
* 6.2 Converting savegames
* 6.3 Viewing/Loading savegames from the command line
7.0) Music and Sound
* 7.1 Adlib emulation
* 7.2 FluidSynth MIDI emulation
@ -781,6 +783,7 @@ arguments -- see the next section.
-h, --help Display a brief help text and exit
-z, --list-games Display list of supported games and exit
-t, --list-targets Display list of configured targets and exit
--list-saves=TARGET Display a list of savegames for the game (TARGET) specified
-c, --config=CONFIG Use alternate configuration file
-p, --path=PATH Path to where the game is installed
@ -968,7 +971,38 @@ Likewise, games that originally were using 640x480 (such as COMI or Broken Sword
will be scaled to 1280x960 and 1920x1440.
5.4) Hot Keys:
5.4) Global Menu:
---- ------------
The Global Menu is a general menu which is available to all of the game engines
by pressing F6. From this menu there are the following buttons: Resume,
Options, About, Return to Launcher, and Quit. Selecting 'Options' will display
a dialog where basic audio settings, such as volume levels, can be adjusted.
Selecting 'Return to Launcher' will close the current game and return the user
back to the ScummVM Launcher, where another game may be selected to play.
Note: Returning to the Launcher is not supported by all of the engines,
and the button will be disabled in the Global Menu if it is not supported.
Engines which currently support Returning to the Launcher are:
AGI
AGOS
CINE
GOB
KYRA
LURE
PARALLACTION
QUEEN
SAGA
SCUMM
SKY
SWORD1
SWORD2
TOUCHE
5.5) Hot Keys:
---- ---------
TODO
TODO: Rework this section to clearly state which hotkeys are implemented in *all*
@ -982,7 +1016,8 @@ ScummVM supports various in-game hotkeys. They differ between SCUMM games and
other games.
Common:
Cmd-q - Quit (Mac OS X)
F6 - Displays the Global Menu
Cmd-q - Quit (Mac OS X)
Ctrl-q - Quit (other unices including Linux)
Ctrl-z OR Alt-x - Quit (other platforms)
Ctrl-m - Toggle mouse capture
@ -1138,45 +1173,93 @@ The platforms that currently have a different default directory are:
6.1) Autosaves:
---- ----------
For some games (namely "Beneath a Steel Sky", "Flight of the Amazon
Queen" and all SCUMM games), ScummVM will by default automatically
save the current state every five minutes (adjustable via the
"autosave_period" config setting). For the SCUMM engine, it will save
in Slot 0. This savestate can then be loaded again via Ctrl-0, or the
F5 menu.
For some games, (namely "Beneath a Steel Sky", "Flight of the Amazon Queen",
all AGI games, and all SCUMM games), ScummVM will by default automatically
save the current state every five minutes (adjustable via the "autosave_period"
config setting). For the AGI and SCUMM engines, it will save in Slot 0. For the
SCUMM engine, this savestate can then be loaded again via Ctrl-0, or the F5
menu.
6.2) Converting Savegames:
---- ----------
Using savegames from original versions, isn't supported by all game engines. Only
the following games, can use savedgames from their original versions.
---- ---------------------
Using savegames from original versions, isn't supported by all game engines.
Only the following games, can use savegames from their original versions.
Elvira 1
- Add 8 bytes (savedgame name) to the start of the savegame file
- Rename the savedgame to 'elvira1.xxx'
- Add 8 bytes (savegame name) to the start of the savegame file
- Rename the savegame to 'elvira1.xxx'
Elvira 2
- Add 8 bytes (savedgame name) to the start of the savegame file
- Rename the savedgame to 'elvira2-pc.xxx' (DOS version) or
- Add 8 bytes (savegame name) to the start of the savegame file
- Rename the savegame to 'elvira2-pc.xxx' (DOS version) or
'elvira2.xxx' (Other versions)
Waxworks
- Add 8 bytes (savedgame name) to the start of the savegame file
- Rename the savedgame to 'waxworks-pc.xxx' (DOS version) or
- Add 8 bytes (savegame name) to the start of the savegame file
- Rename the savegame to 'waxworks-pc.xxx' (DOS version) or
'waxworks.xxx' (Other versions)
Simon the Sorcerer 1
- Rename the savedgame to 'simon1.xxx'
- Rename the savegame to 'simon1.xxx'
Simon the Sorcerer 1
- Rename the savedgame to 'simon2.xxx'
- Rename the savegame to 'simon2.xxx'
The Feeble Files
- Rename the savedgame to 'feeble.xxx'
- Rename the savegame to 'feeble.xxx'
Where 'xxx' is exact the saved game slot (ie 001) under ScummVM
6.3) Viewing/Loading savegames from the command line:
---- ------------------------------------------------
--list-saves:
This switch may be used to display a list of the current savegames
of the specified target game and their corresponding save slots.
Usage: --list-saves=[TARGET], where [TARGET] is the target game.
Engines which currently support --list-saves are:
AGI
AGOS
CINE
KYRA
LURE
PARALLACTION
QUEEN
SAGA
SCUMM
SKY
SWORD1
SWORD2
TOUCHE
--save-slot/-x:
This switch may be used to load a savegame directly from the command line.
Usage: --save-slot[SLOT] or -x[SLOT], where [SLOT] is the save slot number.
Engines which currently support --save-slot/-x are:
AGI
CINE
KYRA
LURE
PARALLACTION
QUEEN
SAGA
SCUMM
SKY
SWORD1
SWORD2
TOUCHE
7.0) Music and Sound:
---- ----------------

View File

@ -93,7 +93,8 @@ DefaultEventManager::DefaultEventManager(OSystem *boss) :
_boss(boss),
_buttonState(0),
_modifierState(0),
_shouldQuit(false) {
_shouldQuit(false),
_shouldRTL(false) {
assert(_boss);
@ -200,6 +201,9 @@ DefaultEventManager::~DefaultEventManager() {
_boss->unlockMutex(_timeMutex);
_boss->unlockMutex(_recorderMutex);
if (!artificialEventQueue.empty())
artificialEventQueue.clear();
if (_playbackFile != NULL) {
delete _playbackFile;
}
@ -349,7 +353,11 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
uint32 time = _boss->getMillis();
bool result;
result = _boss->pollEvent(event);
if (!artificialEventQueue.empty()) {
event = artificialEventQueue.pop();
result = true;
} else
result = _boss->pollEvent(event);
if (_recordMode != kPassthrough) {
@ -375,7 +383,6 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
switch (event.type) {
case Common::EVENT_KEYDOWN:
_modifierState = event.kbd.flags;
// init continuous event stream
// not done on PalmOS because keyboard is emulated and keyup is not generated
#if !defined(PALMOS_MODE)
@ -384,7 +391,27 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_currentKeyDown.flags = event.kbd.flags;
_keyRepeatTime = time + kKeyRepeatInitialDelay;
#endif
// Global Main Menu
// FIXME: F6 is not the best trigger, it conflicts with some games!!!
if (event.kbd.keycode == Common::KEYCODE_F6)
if (g_engine && !g_engine->isPaused()) {
Common::Event menuEvent;
menuEvent.type = Common::EVENT_MAINMENU;
// FIXME: GSoC RTL branch passes the F6 key event to the
// engine, and also enqueues a EVENT_MAINMENU. For now,
// we just drop the key event and return an EVENT_MAINMENU
// instead. This way, we don't have to add special cases
// to engines (like it was the case for LURE in the RTL branch).
//
// However, this has other consequences, possibly negative ones.
// Like, what happens with key repeat for the trigger key?
//pushEvent(menuEvent);
event = menuEvent;
}
break;
case Common::EVENT_KEYUP:
_modifierState = event.kbd.flags;
if (event.kbd.keycode == _currentKeyDown.keycode) {
@ -401,6 +428,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_mousePos = event.mouse;
_buttonState |= LBUTTON;
break;
case Common::EVENT_LBUTTONUP:
_mousePos = event.mouse;
_buttonState &= ~LBUTTON;
@ -410,11 +438,26 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_mousePos = event.mouse;
_buttonState |= RBUTTON;
break;
case Common::EVENT_RBUTTONUP:
_mousePos = event.mouse;
_buttonState &= ~RBUTTON;
break;
case Common::EVENT_MAINMENU:
if (g_engine && !g_engine->isPaused())
g_engine->mainMenuDialog();
if (_shouldQuit)
event.type = Common::EVENT_QUIT;
else if (_shouldRTL)
event.type = Common::EVENT_RTL;
break;
case Common::EVENT_RTL:
_shouldRTL = true;
break;
case Common::EVENT_QUIT:
if (ConfMan.getBool("confirm_exit")) {
if (g_engine)
@ -425,6 +468,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
g_engine->pauseEngine(false);
} else
_shouldQuit = true;
break;
default:
@ -447,4 +491,14 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
return result;
}
void DefaultEventManager::pushEvent(Common::Event event) {
// If already received an EVENT_QUIT, don't add another one
if (event.type == Common::EVENT_QUIT) {
if (!_shouldQuit)
artificialEventQueue.push(event);
} else
artificialEventQueue.push(event);
}
#endif // !defined(DISABLE_DEFAULT_EVENTMANAGER)

View File

@ -48,6 +48,7 @@ class DefaultEventManager : public Common::EventManager {
int _buttonState;
int _modifierState;
bool _shouldQuit;
bool _shouldRTL;
class RandomSourceRecord {
public:
@ -107,6 +108,7 @@ public:
~DefaultEventManager();
virtual bool pollEvent(Common::Event &event);
virtual void pushEvent(Common::Event event);
virtual void registerRandomSource(Common::RandomSource &rnd, const char *name);
virtual void processMillis(uint32 &millis);
@ -114,6 +116,8 @@ public:
virtual int getButtonState() const { return _buttonState; }
virtual int getModifierState() const { return _modifierState; }
virtual int shouldQuit() const { return _shouldQuit; }
virtual int shouldRTL() const { return _shouldRTL; }
virtual void resetRTL() { _shouldRTL = false; }
};
#endif

View File

@ -56,6 +56,7 @@ static const char HELP_STRING[] =
" -h, --help Display a brief help text and exit\n"
" -z, --list-games Display list of supported games and exit\n"
" -t, --list-targets Display list of configured targets and exit\n"
" --list-saves=TARGET Display a list of savegames for the game (TARGET) specified\n"
"\n"
" -c, --config=CONFIG Use alternate configuration file\n"
" -p, --path=PATH Path to where the game is installed\n"

View File

@ -38,6 +38,7 @@
#include "base/version.h"
#include "common/config-manager.h"
#include "common/events.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/system.h"
@ -200,7 +201,8 @@ static int runGame(const EnginePlugin *plugin, OSystem &system, const Common::St
// Reset the file/directory mappings
Common::File::resetDefaultDirectories();
return 0;
// If result=1 return to the launcher, else quit ScummVM
return result;
}
@ -286,6 +288,10 @@ extern "C" int scummvm_main(int argc, char *argv[]) {
// TODO: We should keep running if starting the selected game failed
// (so instead of just quitting, show a nice error dialog to the
// user and let him pick another game).
// Reset RTL flag in case we want to load another engine
g_system->getEventManager()->resetRTL();
if (result == 0)
break;

View File

@ -27,6 +27,7 @@
#define COMMON_EVENTS_H
#include "common/keyboard.h"
#include "common/queue.h"
#include "common/rect.h"
#include "common/system.h"
#include "common/noncopyable.h"
@ -58,6 +59,9 @@ enum EventType {
EVENT_MBUTTONDOWN = 13,
EVENT_MBUTTONUP = 14,
EVENT_MAINMENU = 15,
EVENT_RTL = 16,
EVENT_QUIT = 10,
EVENT_SCREEN_CHANGED = 11,
/**
@ -142,6 +146,11 @@ public:
*/
virtual bool pollEvent(Common::Event &event) = 0;
/**
* Pushes a "fake" event of the specified type into the event queue
*/
virtual void pushEvent(Common::Event event) = 0;
/** Register random source so it can be serialized in game test purposes **/
virtual void registerRandomSource(Common::RandomSource &rnd, const char *name) = 0;
@ -166,6 +175,16 @@ public:
*/
virtual int shouldQuit() const = 0;
/**
* Should we return to the launcher?
*/
virtual int shouldRTL() const = 0;
/**
* We have returned to the launcher, and the _shouldRTL should be reset to false
*/
virtual void resetRTL() = 0;
// Optional: check whether a given key is currently pressed ????
//virtual bool isKeyPressed(int keycode) = 0;
@ -173,6 +192,9 @@ public:
// TODO: Consider removing OSystem::getScreenChangeID and
// replacing it by a generic getScreenChangeID method here
protected:
Common::Queue<Common::Event> artificialEventQueue;
};
} // End of namespace Common

224
engines/dialogs.cpp Normal file
View File

@ -0,0 +1,224 @@
/* 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.
*
* $URL$
* $Id$
*/
#include "base/version.h"
#include "common/config-manager.h"
#include "common/savefile.h"
#include "common/system.h"
#include "common/events.h"
#include "graphics/scaler.h"
#include "gui/about.h"
#include "gui/eval.h"
#include "gui/newgui.h"
#include "gui/ListWidget.h"
#include "engines/dialogs.h"
#include "engines/engine.h"
#include "engines/metaengine.h"
#ifdef SMALL_SCREEN_DEVICE
#include "gui/KeysDialog.h"
#endif
using GUI::CommandSender;
using GUI::StaticTextWidget;
using GUI::kButtonWidth;
using GUI::kButtonHeight;
using GUI::kBigButtonWidth;
using GUI::kBigButtonHeight;
using GUI::kCloseCmd;
using GUI::kTextAlignCenter;
using GUI::kTextAlignLeft;
using GUI::WIDGET_ENABLED;
typedef GUI::OptionsDialog GUI_OptionsDialog;
typedef GUI::Dialog GUI_Dialog;
GlobalDialog::GlobalDialog(String name)
: GUI::Dialog(name) {
_drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;}
enum {
kSaveCmd = 'SAVE',
kLoadCmd = 'LOAD',
kPlayCmd = 'PLAY',
kOptionsCmd = 'OPTN',
kHelpCmd = 'HELP',
kAboutCmd = 'ABOU',
kQuitCmd = 'QUIT',
kRTLCmd = 'RTL',
kChooseCmd = 'CHOS'
};
MainMenuDialog::MainMenuDialog(Engine *engine)
: GlobalDialog("globalmain"), _engine(engine) {
new StaticTextWidget(this, "global_title", "ScummVM");
new StaticTextWidget(this, "global_version", gScummVMVersionDate);
new GUI::ButtonWidget(this, "globalmain_resume", "Resume", kPlayCmd, 'P');
// new GUI::ButtonWidget(this, "globalmain_load", "Load", kLoadCmd, 'L');
// new GUI::ButtonWidget(this, "globalmain_save", "Save", kSaveCmd, 'S');
new GUI::ButtonWidget(this, "globalmain_options", "Options", kOptionsCmd, 'O');
new GUI::ButtonWidget(this, "globalmain_about", "About", kAboutCmd, 'A');
_rtlButton = new GUI::ButtonWidget(this, "globalmain_rtl", "Return to Launcher", kRTLCmd, 'R');
// '0' corresponds to the kSupportsRTL MetaEngineFeature
_rtlButton->setEnabled(_engine->hasFeature(0));
new GUI::ButtonWidget(this, "globalmain_quit", "Quit", kQuitCmd, 'Q');
_aboutDialog = new GUI::AboutDialog();
_optionsDialog = new ConfigDialog();
}
MainMenuDialog::~MainMenuDialog() {
delete _aboutDialog;
delete _optionsDialog;
}
void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kPlayCmd:
close();
break;
case kOptionsCmd:
_optionsDialog->runModal();
break;
case kAboutCmd:
_aboutDialog->runModal();
break;
case kRTLCmd: {
Common::Event eventRTL;
eventRTL.type = Common::EVENT_RTL;
g_system->getEventManager()->pushEvent(eventRTL);
close();
}
break;
case kQuitCmd: {
Common::Event eventQ;
eventQ.type = Common::EVENT_QUIT;
g_system->getEventManager()->pushEvent(eventQ);
close();
}
break;
default:
GlobalDialog::handleCommand(sender, cmd, data);
}
}
enum {
kOKCmd = 'ok '
};
enum {
kKeysCmd = 'KEYS'
};
// FIXME: We use the empty string as domain name here. This tells the
// ConfigManager to use the 'default' domain for all its actions. We do that
// to get as close as possible to editing the 'active' settings.
//
// However, that requires bad & evil hacks in the ConfigManager code,
// and even then still doesn't work quite correctly.
// For example, if the transient domain contains 'false' for the 'fullscreen'
// flag, but the user used a hotkey to switch to windowed mode, then the dialog
// will display the wrong value anyway.
//
// Proposed solution consisting of multiple steps:
// 1) Add special code to the open() code that reads out everything stored
// in the transient domain that is controlled by this dialog, and updates
// the dialog accordingly.
// 2) Even more code is added to query the backend for current settings, like
// the fullscreen mode flag etc., and also updates the dialog accordingly.
// 3) The domain being edited is set to the active game domain.
// 4) If the dialog is closed with the "OK" button, then we remove everything
// stored in the transient domain (or at least everything corresponding to
// switches in this dialog.
// If OTOH the dialog is closed with "Cancel" we do no such thing.
//
// These changes will achieve two things at once: Allow us to get rid of using
// "" as value for the domain, and in fact provide a somewhat better user
// experience at the same time.
ConfigDialog::ConfigDialog()
: GUI::OptionsDialog("", "scummconfig") {
//
// Sound controllers
//
addVolumeControls(this, "scummconfig_");
//
// Some misc options
//
// SCUMM has a talkspeed range of 0-9
addSubtitleControls(this, "scummconfig_", 9);
//
// Add the buttons
//
new GUI::ButtonWidget(this, "scummconfig_ok", "OK", GUI::OptionsDialog::kOKCmd, 'O');
new GUI::ButtonWidget(this, "scummconfig_cancel", "Cancel", kCloseCmd, 'C');
#ifdef SMALL_SCREEN_DEVICE
new GUI::ButtonWidget(this, "scummconfig_keys", "Keys", kKeysCmd, 'K');
//
// Create the sub dialog(s)
//
_keysDialog = new GUI::KeysDialog();
#endif
}
ConfigDialog::~ConfigDialog() {
#ifdef SMALL_SCREEN_DEVICE
delete _keysDialog;
#endif
}
void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kKeysCmd:
#ifdef SMALL_SCREEN_DEVICE
_keysDialog->runModal();
#endif
break;
default:
GUI_OptionsDialog::handleCommand (sender, cmd, data);
}
}

74
engines/dialogs.h Normal file
View File

@ -0,0 +1,74 @@
/* 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.
*
* $URL$
* $Id$
*/
#ifndef GLOBAL_DIALOGS_H
#define GLOBAL_DIALOGS_H
#include "common/str.h"
#include "gui/dialog.h"
#include "gui/options.h"
#include "gui/widget.h"
#include "engines/engine.h"
class GlobalDialog : public GUI::Dialog {
public:
GlobalDialog(Common::String name);
protected:
typedef Common::String String;
};
class MainMenuDialog : public GlobalDialog {
public:
MainMenuDialog(Engine *engine);
~MainMenuDialog();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
protected:
Engine *_engine;
GUI::ButtonWidget *_rtlButton;
GUI::Dialog *_aboutDialog;
GUI::Dialog *_optionsDialog;
};
class ConfigDialog : public GUI::OptionsDialog {
protected:
#ifdef SMALL_SCREEN_DEVICE
GUI::Dialog *_keysDialog;
#endif
public:
ConfigDialog();
~ConfigDialog();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
};
#endif

View File

@ -36,7 +36,10 @@
#include "common/savefile.h"
#include "common/system.h"
#include "gui/message.h"
#include "gui/newgui.h"
#include "sound/mixer.h"
#include "engines/dialogs.h"
#include "engines/metaengine.h"
#ifdef _WIN32_WCE
extern bool isSmartphone(void);
@ -54,7 +57,8 @@ Engine::Engine(OSystem *syst)
_saveFileMan(_system->getSavefileManager()),
_targetName(ConfMan.getActiveDomainName()),
_gameDataPath(ConfMan.get("path")),
_pauseLevel(0) {
_pauseLevel(0),
_mainMenuDialog(NULL) {
g_engine = this;
_autosavePeriod = ConfMan.getInt("autosave_period");
@ -72,7 +76,8 @@ Engine::Engine(OSystem *syst)
Engine::~Engine() {
_mixer->stopAll();
delete _mainMenuDialog;
g_engine = NULL;
}
@ -210,3 +215,50 @@ void Engine::pauseEngineIntern(bool pause) {
// By default, just (un)pause all digital sounds
_mixer->pauseAll(pause);
}
void Engine::mainMenuDialog() {
if (!_mainMenuDialog)
_mainMenuDialog = new MainMenuDialog(this);
runDialog(*_mainMenuDialog);
syncSoundSettings();
}
int Engine::runDialog(Dialog &dialog) {
pauseEngine(true);
int result = dialog.runModal();
pauseEngine(false);
return result;
}
void Engine::syncSoundSettings() {
// Sync the engine with the config manager
int soundVolumeMusic = ConfMan.getInt("music_volume");
int soundVolumeSFX = ConfMan.getInt("sfx_volume");
int soundVolumeSpeech = ConfMan.getInt("speech_volume");
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX);
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech);
}
void Engine::quitGame() {
Common::Event event;
event.type = Common::EVENT_QUIT;
_eventMan->pushEvent(event);
}
bool Engine::hasFeature(int f) {
const EnginePlugin *plugin = 0;
Common::String gameid = ConfMan.get("gameid");
gameid.toLowercase();
EngineMan.findGame(gameid, &plugin);
return ( (*plugin)->hasFeature((MetaEngine::MetaEngineFeature)f) );
}

View File

@ -25,10 +25,12 @@
#ifndef ENGINES_ENGINE_H
#define ENGINES_ENGINE_H
#include "common/events.h"
#include "common/scummsys.h"
#include "common/str.h"
class OSystem;
namespace Audio {
class Mixer;
}
@ -39,8 +41,11 @@ namespace Common {
}
namespace GUI {
class Debugger;
class Dialog;
}
using GUI::Dialog;
class Engine {
public:
OSystem *_system;
@ -50,6 +55,9 @@ public:
protected:
Common::EventManager *_eventMan;
Common::SaveFileManager *_saveFileMan;
Dialog *_mainMenuDialog;
virtual int runDialog(Dialog &dialog);
const Common::String _targetName; // target name for saves
const Common::String _gameDataPath;
@ -108,11 +116,33 @@ public:
*/
void pauseEngine(bool pause);
/**
* Quit the engine, sends a Quit event to the Event Manager
*/
void quitGame();
/**
* Return whether the engine is currently paused or not.
*/
bool isPaused() const { return _pauseLevel != 0; }
/**
* Return whether or not the ENGINE should quit
*/
bool quit() const { return (_eventMan->shouldQuit() || _eventMan->shouldRTL()); }
/** Run the Global Main Menu Dialog
*/
virtual void mainMenuDialog();
/** Sync the engine's sound settings with the config manager
*/
virtual void syncSoundSettings();
/** Determine whether the engine supports the specified MetaEngine feature
*/
virtual bool hasFeature(int f);
public:
/** Setup the backend's graphics mode. */

View File

@ -91,6 +91,45 @@ public:
virtual SaveStateList listSaves(const char *target) const {
return SaveStateList();
}
/**
* Remove the specified save state.
*
* For most engines this just involves a call removeSaveFile().
* Engines which keep an index file will also update it accordingly.
*
* @param slot slot number of the save state to be removed
* @param saveNames a list of all the save state description names
*/
virtual void removeSaveState(int slot, Common::StringList saveNames) const {};
/** @name MetaEngineFeature flags */
//@{
/**
* A feature in this context means an ability of the engine which can be
* either on or off. Examples include:
* - Listing Save States (--list-saves)
* - Loading from the Launcher (-x)
* - Deleting Saves from the Launcher
*
* These determine whether the features will be available to the engine
* in the launcher.
*/
enum MetaEngineFeature {
kSupportsRTL = 0,
kSupportsListSaves = 1,
kSupportsDirectLoad = 2,
kSupportsDeleteSave = 3
};
/**
* Determine whether the engine supports the specified MetaEngine feature
*/
virtual bool hasFeature(MetaEngineFeature f) const { return false; };
//@}
};

View File

@ -1,7 +1,7 @@
MODULE := engines
MODULE_OBJS := \
engine.o
engine.o \
dialogs.o
# Include common rules
include $(srcdir)/rules.mk

View File

@ -29,6 +29,7 @@
#include "common/events.h"
#include "common/fs.h"
#include "common/util.h"
#include "common/savefile.h"
#include "common/system.h"
#include "gui/about.h"
@ -61,7 +62,10 @@ enum {
kAddGameCmd = 'ADDG',
kEditGameCmd = 'EDTG',
kRemoveGameCmd = 'REMG',
kLoadGameCmd = 'LOAD',
kQuitCmd = 'QUIT',
kChooseCmd = 'CHOS',
kDelCmd = 'DEL',
kCmdGlobalGraphicsOverride = 'OGFX',
@ -468,6 +472,140 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
}
}
class SaveLoadChooser : public GUI::Dialog {
typedef Common::String String;
typedef Common::StringList StringList;
protected:
bool _delSave;
bool _delSupport;
GUI::ListWidget *_list;
GUI::ButtonWidget *_chooseButton;
GUI::ButtonWidget *_deleteButton;
GUI::GraphicsWidget *_gfxWidget;
GUI::ContainerWidget *_container;
uint8 _fillR, _fillG, _fillB;
void updateInfos(bool redraw);
public:
SaveLoadChooser(const String &title, const String &buttonLabel);
~SaveLoadChooser();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
const String &getResultString() const;
void setList(const StringList& list);
int runModal(bool delSupport);
virtual void reflowLayout();
bool delSave() { return _delSave; };
};
SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel)
: Dialog("scummsaveload"), _delSave(0), _delSupport(0), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) {
_drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
new StaticTextWidget(this, "scummsaveload_title", title);
// Add choice list
_list = new GUI::ListWidget(this, "scummsaveload_list");
_list->setNumberingMode(GUI::kListNumberingZero);
_container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
_container->setHints(GUI::THEME_HINT_USE_SHADOW);
_gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10);
// Buttons
new GUI::ButtonWidget(this, "scummsaveload_cancel", "Cancel", kCloseCmd, 0);
_chooseButton = new GUI::ButtonWidget(this, "scummsaveload_choose", buttonLabel, kChooseCmd, 0);
_chooseButton->setEnabled(false);
_deleteButton = new GUI::ButtonWidget(this, "scummsaveload_delete", "Delete", kDelCmd, 0);
_deleteButton->setEnabled(false);
}
SaveLoadChooser::~SaveLoadChooser() {
}
const Common::String &SaveLoadChooser::getResultString() const {
return _list->getSelectedString();
}
void SaveLoadChooser::setList(const StringList& list) {
_list->setList(list);
}
int SaveLoadChooser::runModal(bool delSupport) {
if (_gfxWidget)
_gfxWidget->setGfx(0);
_delSave = false;
_delSupport = delSupport;
int ret = Dialog::runModal();
return ret;
}
void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
int selItem = _list->getSelected();
switch (cmd) {
case GUI::kListItemActivatedCmd:
case GUI::kListItemDoubleClickedCmd:
if (selItem >= 0) {
if (!getResultString().empty()) {
_list->endEditMode();
setResult(selItem);
close();
}
}
break;
case kChooseCmd:
_list->endEditMode();
setResult(selItem);
close();
break;
case GUI::kListSelectionChangedCmd: {
if (_gfxWidget) {
updateInfos(true);
}
// Disable these buttons if nothing is selected, or if an empty
// list item is selected.
_chooseButton->setEnabled(selItem >= 0 && (!getResultString().empty()));
_chooseButton->draw();
// Delete will always be disabled if the engine doesn't support it.
_deleteButton->setEnabled(_delSupport && (selItem >= 0) && (!getResultString().empty()));
_deleteButton->draw();
} break;
case kDelCmd:
setResult(selItem);
_delSave = true;
// Disable these buttons again after deleteing a selection
_chooseButton->setEnabled(false);
_deleteButton->setEnabled(false);
close();
break;
case kCloseCmd:
setResult(-1);
default:
Dialog::handleCommand(sender, cmd, data);
}
}
void SaveLoadChooser::reflowLayout() {
_container->setFlags(GUI::WIDGET_INVISIBLE);
_gfxWidget->setFlags(GUI::WIDGET_INVISIBLE);
Dialog::reflowLayout();
}
void SaveLoadChooser::updateInfos(bool redraw) {
_gfxWidget->setGfx(-1, -1, _fillR, _fillG, _fillB);
if (redraw)
_gfxWidget->draw();
}
#pragma mark -
@ -501,6 +639,8 @@ LauncherDialog::LauncherDialog()
new ButtonWidget(this, "launcher_options_button", "Options", kOptionsCmd, 'O');
_startButton =
new ButtonWidget(this, "launcher_start_button", "Start", kStartCmd, 'S');
new ButtonWidget(this, "launcher_loadGame_button", "Load", kLoadGameCmd, 'L');
// Above the lowest button rows: two more buttons (directly below the list box)
_addButton =
@ -529,6 +669,9 @@ LauncherDialog::LauncherDialog()
// Create file browser dialog
_browser = new BrowserDialog("Select directory with game data", true);
// Create Load dialog
_loadDialog = new SaveLoadChooser("Load game:", "Load");
}
void LauncherDialog::selectGame(const String &name) {
@ -546,6 +689,7 @@ void LauncherDialog::selectGame(const String &name) {
LauncherDialog::~LauncherDialog() {
delete _browser;
delete _loadDialog;
}
void LauncherDialog::open() {
@ -795,6 +939,80 @@ void LauncherDialog::editGame(int item) {
}
}
void LauncherDialog::loadGame(int item) {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
String gameId = ConfMan.get("gameid", _domains[item]);
if (gameId.empty())
gameId = _domains[item];
const EnginePlugin *plugin = 0;
GameDescriptor game = EngineMan.findGame(gameId, &plugin);
String description = _domains[item];
description.toLowercase();
int idx;
if (plugin) {
bool delSupport = (*plugin)->hasFeature(MetaEngine::kSupportsDeleteSave);
if ((*plugin)->hasFeature(MetaEngine::kSupportsListSaves) &&
(*plugin)->hasFeature(MetaEngine::kSupportsDirectLoad))
{
do {
Common::StringList saveNames = generateSavegameList(item, plugin);
_loadDialog->setList(saveNames);
SaveStateList saveList = (*plugin)->listSaves(description.c_str());
idx = _loadDialog->runModal(delSupport);
if (idx >= 0) {
// Delete the savegame
if (_loadDialog->delSave()) {
String filename = saveList[idx].filename();
//printf("Deleting file: %s\n", filename.c_str());
MessageDialog alert("Do you really want to delete this savegame?",
"Yes", "No");
if (alert.runModal() == GUI::kMessageOK) {
saveFileMan->removeSavefile(filename.c_str());
if ((saveList.size() - 1) == 0)
ConfMan.setInt("save_slot", -1);
}
}
// Load the savegame
else {
int slot = atoi(saveList[idx].save_slot().c_str());
//const char *file = saveList[idx].filename().c_str();
//printf("Loading slot: %d\n", slot);
//printf("Loading file: %s\n", file);
ConfMan.setActiveDomain(_domains[item]);
ConfMan.setInt("save_slot", slot);
close();
}
}
}
while (_loadDialog->delSave());
} else {
MessageDialog dialog
("Sorry, this game does not yet support loading games from the launcher.", "OK");
dialog.runModal();
}
} else {
MessageDialog dialog("ScummVM could not find any engine capable of running the selected game!", "OK");
dialog.runModal();
}
}
Common::StringList LauncherDialog::generateSavegameList(int item, const EnginePlugin *plugin) {
String description = _domains[item];
description.toLowercase();
StringList saveNames;
SaveStateList saveList = (*plugin)->listSaves(description.c_str());
for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x)
saveNames.push_back(x->description().c_str());
return saveNames;
}
void LauncherDialog::handleKeyDown(Common::KeyState state) {
Dialog::handleKeyDown(state);
updateButtons();
@ -818,6 +1036,9 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
case kEditGameCmd:
editGame(item);
break;
case kLoadGameCmd:
loadGame(item);
break;
case kOptionsCmd: {
GlobalOptionsDialog options;
options.runModal();

View File

@ -34,11 +34,10 @@ namespace GUI {
class BrowserDialog;
class ListWidget;
class GraphicsWidget;
class SaveLoadChooser;
Common::String addGameToConf(const GameDescriptor &result);
class LauncherDialog : public Dialog {
typedef Common::String String;
typedef Common::StringList StringList;
@ -62,6 +61,7 @@ protected:
#endif
StringList _domains;
BrowserDialog *_browser;
SaveLoadChooser *_loadDialog;
virtual void reflowLayout();
@ -73,6 +73,9 @@ protected:
virtual void addGame();
void removeGame(int item);
void editGame(int item);
void loadGame(int item);
StringList generateSavegameList(int item, const EnginePlugin *plugin);
void selectGame(const String &name);
};

View File

@ -25,6 +25,7 @@
#include "common/events.h"
#include "common/system.h"
#include "common/util.h"
#include "engines/engine.h"
#include "graphics/cursorman.h"
#include "gui/newgui.h"
#include "gui/dialog.h"
@ -255,7 +256,7 @@ void NewGui::runLoop() {
Common::Event event;
while (eventMan->pollEvent(event)) {
if (activeDialog != getTopDialog() && event.type != Common::EVENT_QUIT && event.type != Common::EVENT_SCREEN_CHANGED)
if (activeDialog != getTopDialog() && event.type != Common::EVENT_SCREEN_CHANGED)
continue;
Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y);
@ -313,7 +314,8 @@ void NewGui::runLoop() {
activeDialog->handleMouseWheel(mouse.x, mouse.y, 1);
break;
case Common::EVENT_QUIT:
_system->quit();
if (!g_engine)
_system->quit();
return;
case Common::EVENT_SCREEN_CHANGED:
screenChange();

View File

@ -95,6 +95,7 @@ const char *Theme::_defaultConfigINI =
"scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 22)) 18\n"
"scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n"
"scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h\n"
"scummsaveload_delete=prev.x2 prev.y prev.w prev.h\n"
"scummsaveload_extinfo.visible=false\n"
"\n"
"# MM NES resolution\n"
@ -118,6 +119,7 @@ const char *Theme::_defaultConfigINI =
"def_aboutXOff=8\n"
"def_aboutYOff=5\n"
"def_aboutOuterBorder=80\n"
"def_globalmainHOffset=52\n"
"def_scummmainHOffset=12\n"
"def_scummmainVSpace=7\n"
"def_scummmainVAddOff=3\n"
@ -171,10 +173,11 @@ const char *Theme::_defaultConfigINI =
"launcher_options_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_start_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"top=(top - buttonHeight * 2)\n"
"numButtons=3\n"
"numButtons=4\n"
"space=10\n"
"butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)\n"
"launcher_addGame_button=hBorder top butWidth buttonHeight\n"
"launcher_loadGame_button=hBorder top butWidth buttonHeight\n"
"launcher_addGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_editGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_removeGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_list=hBorder (kLineHeight + 16) (w - 2 * hBorder) (top - kLineHeight - 20)\n"
@ -371,6 +374,7 @@ const char *Theme::_defaultConfigINI =
"scummsaveload_thumbnail.fillB=0\n"
"scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n"
"scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h\n"
"scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h\n"
"scummsaveload_extinfo.visible=true\n"
"\n"
"############################################\n"
@ -482,6 +486,31 @@ const char *Theme::_defaultConfigINI =
"smH=(smY + scummmainVSpace)\n"
"scummmain=((w - smW) / 2) ((h - smH) / 2) smW smH\n"
"\n"
"#### Global Main Menu Dialog"
"[globalmain]\n"
"# note that globalmain size depends on overall height\n"
"hBorder=10\n"
"gmW=(scummmainButtonWidth + (2 * scummmainHOffset) + 80)\n"
"global_title=hBorder 8 (gmW - 2 * hBorder) kLineHeight\n"
"global_title.align=kTextAlignCenter\n"
"global_version=hBorder 25 (gmW - 2 * hBorder) kLineHeight\n"
"global_version.align=kTextAlignCenter\n"
"gmY=((scummmainVSpace * 7)+ scummmainVAddOff)\n"
"globalmain_resume=globalmainHOffset gmY scummmainButtonWidth scummmainButtonHeight\n"
"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
"gmY=(gmY + scummmainVSpace)\n"
"globalmain_options=prev.x gmY prev.w prev.h\n"
"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
"globalmain_about=prev.x gmY prev.w prev.h\n"
"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
"gmY=(gmY + scummmainVSpace)\n"
"globalmain_rtl=prev.x gmY prev.w prev.h\n"
"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
"globalmain_quit=prev.x gmY prev.w prev.h\n"
"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
"gmH=(gmY + scummmainVSpace)\n"
"globalmain=((w - gmW) / 2) ((h - gmH) / 2) gmW gmH\n"
"\n"
"# PSP GUI\n"
"[480x272]\n"
"def_buttonWidth=100\n"

View File

@ -82,13 +82,14 @@ hBorder=10
launcher_version=hBorder 8 (w - 2 * hBorder) kLineHeight
launcher_version.align=kTextAlignCenter
top=(h - 8 - buttonHeight)
numButtons=4
numButtons=3
space=8
butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)
launcher_quit_button=hBorder top butWidth buttonHeight
launcher_about_button=(prev.x2 + space) prev.y prev.w prev.h
launcher_options_button=(prev.x2 + space) prev.y prev.w prev.h
launcher_start_button=(prev.x2 + space) prev.y prev.w prev.h
launcher_loadGame_button=(prev.x2 + space) prev.y prev.w prev.h
top=(top - buttonHeight * 2)
numButtons=3
space=10
@ -289,6 +290,7 @@ scummsaveload_thumbnail.fillG=0
scummsaveload_thumbnail.fillB=0
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=true
############################################
@ -441,6 +443,7 @@ scummsaveload_list=10 18 prev.w (parent.h - 17 - buttonHeight - 8 - self.y)
scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 22)) 18
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=false
# MM NES resolution

View File

@ -250,6 +250,7 @@ space1=20
space2=5
launcher_list=insetX insetY insetW insetH
launcher_start_button=(prev.x2 + 17) prev.y buttonWidth buttonHeight
launcher_loadGame_button=prev.x (prev.y2 + space2) prev.w prev.h
launcher_addGame_button=prev.x (prev.y2 + space1) prev.w prev.h
launcher_editGame_button=prev.x (prev.y2 + space2) prev.w prev.h
launcher_removeGame_button=prev.x (prev.y2 + space2) prev.w prev.h
@ -456,6 +457,7 @@ scummsaveload_thumbnail.fillG=0
scummsaveload_thumbnail.fillB=0
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=true
############################################