1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 // winnt.h defines ARRAYSIZE, but we want our own one...
32 #include "engines/engine.h"
33 #include "common/config-manager.h"
34 #include "common/events.h"
35 #include "common/file.h"
36 #include "common/timer.h"
37 #include "common/savefile.h"
38 #include "common/system.h"
39 #include "gui/message.h"
40 #include "gui/GuiManager.h"
41 #include "sound/mixer.h"
42 #include "engines/dialogs.h"
43 #include "engines/metaengine.h"
46 extern bool isSmartphone(void);
49 // FIXME: HACK for MidiEmu & error()
53 Engine::Engine(OSystem
*syst
)
55 _mixer(_system
->getMixer()),
56 _timer(_system
->getTimerManager()),
57 _eventMan(_system
->getEventManager()),
58 _saveFileMan(_system
->getSavefileManager()),
59 _targetName(ConfMan
.getActiveDomainName()),
60 _gameDataDir(ConfMan
.get("path")),
62 _mainMenuDialog(NULL
) {
66 // FIXME: Get rid of the following again. It is only here temporarily.
67 // We really should never run with a non-working Mixer, so ought to handle
68 // this at a much earlier stage. If we *really* want to support systems
69 // without a working mixer, then we need more work. E.g. we could modify the
70 // Mixer to immediately drop any streams passed to it. This way, at least
71 // we don't crash because heaps of (sound) memory get allocated but never
72 // freed. Of course, there still would be problems with many games...
73 if (!_mixer
->isReady())
74 warning("Sound initialization failed. This may cause severe problems in some games.");
80 delete _mainMenuDialog
;
84 void initCommonGFX(bool defaultTo1XScaler
) {
85 const Common::ConfigManager::Domain
*transientDomain
= ConfMan
.getDomain(Common::ConfigManager::kTransientDomain
);
86 const Common::ConfigManager::Domain
*gameDomain
= ConfMan
.getActiveDomain();
88 assert(transientDomain
);
90 const bool useDefaultGraphicsMode
=
91 !transientDomain
->contains("gfx_mode") &&
94 !gameDomain
->contains("gfx_mode") ||
95 !scumm_stricmp(gameDomain
->get("gfx_mode").c_str(), "normal") ||
96 !scumm_stricmp(gameDomain
->get("gfx_mode").c_str(), "default")
99 // See if the game should default to 1x scaler
100 if (useDefaultGraphicsMode
&& defaultTo1XScaler
) {
101 // FIXME: As a hack, we use "1x" here. Would be nicer to use
102 // getDefaultGraphicsMode() instead, but right now, we do not specify
103 // whether that is a 1x scaler or not...
104 g_system
->setGraphicsMode("1x");
106 // Override global scaler with any game-specific define
107 if (ConfMan
.hasKey("gfx_mode")) {
108 g_system
->setGraphicsMode(ConfMan
.get("gfx_mode").c_str());
112 // Note: The following code deals with the fullscreen / ASR settings. This
113 // is a bit tricky, because there are three ways the user can affect these
114 // settings: Via the config file, via the command line, and via in-game
116 // Any global or command line settings already have been applied at the time
117 // we get here. Hence we only do something
119 // (De)activate aspect-ratio correction as determined by the config settings
120 if (gameDomain
&& gameDomain
->contains("aspect_ratio"))
121 g_system
->setFeatureState(OSystem::kFeatureAspectRatioCorrection
, ConfMan
.getBool("aspect_ratio"));
123 // (De)activate fullscreen mode as determined by the config settings
124 if (gameDomain
&& gameDomain
->contains("fullscreen"))
125 g_system
->setFeatureState(OSystem::kFeatureFullscreenMode
, ConfMan
.getBool("fullscreen"));
128 void initGraphics(int width
, int height
, bool defaultTo1xScaler
) {
129 g_system
->beginGFXTransaction();
131 initCommonGFX(defaultTo1xScaler
);
132 g_system
->initSize(width
, height
);
134 OSystem::TransactionError gfxError
= g_system
->endGFXTransaction();
136 if (gfxError
== OSystem::kTransactionSuccess
)
139 // Error out on size switch failure
140 if (gfxError
& OSystem::kTransactionSizeChangeFailed
) {
142 snprintf(buffer
, 16, "%dx%d", width
, height
);
144 Common::String message
= "Could not switch to resolution: '";
148 GUIErrorMessage(message
);
149 error("%s", message
.c_str());
152 // Just show warnings then these occur:
153 if (gfxError
& OSystem::kTransactionModeSwitchFailed
) {
154 Common::String message
= "Could not switch to video mode: '";
155 message
+= ConfMan
.get("gfx_mode");
158 GUI::MessageDialog
dialog(message
);
162 if (gfxError
& OSystem::kTransactionAspectRatioFailed
) {
163 GUI::MessageDialog
dialog("Could not apply aspect ratio setting.");
167 if (gfxError
& OSystem::kTransactionFullscreenFailed
) {
168 GUI::MessageDialog
dialog("Could not apply fullscreen setting.");
173 void GUIErrorMessage(const Common::String msg
) {
174 g_system
->setWindowCaption("Error");
175 g_system
->beginGFXTransaction();
176 initCommonGFX(false);
177 g_system
->initSize(320, 200);
178 if (g_system
->endGFXTransaction() == OSystem::kTransactionSuccess
) {
179 GUI::MessageDialog
dialog(msg
);
182 error("%s", msg
.c_str());
186 void Engine::checkCD() {
187 #if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
188 // It is a known bug under Windows that games that play CD audio cause
189 // ScummVM to crash if the data files are read from the same CD. Check
190 // if this appears to be the case and issue a warning.
192 // If we can find a compressed audio track, then it should be ok even
193 // if it's running from CD.
196 if (Common::File::exists("track1.ogg") ||
197 Common::File::exists("track01.ogg"))
201 if (Common::File::exists("track1.fla") ||
202 Common::File::exists("track1.flac") ||
203 Common::File::exists("track01.fla") ||
204 Common::File::exists("track01.flac"))
208 if (Common::File::exists("track1.mp3") ||
209 Common::File::exists("track01.mp3"))
213 char buffer
[MAXPATHLEN
];
216 if (_gameDataDir
.getPath().empty()) {
217 // That's it! I give up!
218 if (getcwd(buffer
, MAXPATHLEN
) == NULL
)
221 strncpy(buffer
, _gameDataDir
.getPath().c_str(), MAXPATHLEN
);
223 for (i
= 0; i
< MAXPATHLEN
- 1; i
++) {
224 if (buffer
[i
] == '\\')
230 if (GetDriveType(buffer
) == DRIVE_CDROM
) {
231 GUI::MessageDialog
dialog(
232 "You appear to be playing this game directly\n"
233 "from the CD. This is known to cause problems,\n"
234 "and it is therefore recommended that you copy\n"
235 "the data files to your hard disk instead.\n"
236 "See the README file for details.", "OK");
239 // If we reached here, the game has audio tracks,
240 // it's not ran from the CD and the tracks have not
242 GUI::MessageDialog
dialog(
243 "This game has audio tracks in its disk. These\n"
244 "tracks need to be ripped from the disk using\n"
245 "an appropriate CD audio extracting tool in\n"
246 "order to listen to the game's music.\n"
247 "See the README file for details.", "OK");
253 bool Engine::shouldPerformAutoSave(int lastSaveTime
) {
254 const int diff
= _system
->getMillis() - lastSaveTime
;
255 const int autosavePeriod
= ConfMan
.getInt("autosave_period");
256 return autosavePeriod
!= 0 && diff
> autosavePeriod
* 1000;
259 void Engine::errorString(const char *buf1
, char *buf2
, int size
) {
260 strncpy(buf2
, buf1
, size
);
265 void Engine::pauseEngine(bool pause
) {
266 assert((pause
&& _pauseLevel
>= 0) || (!pause
&& _pauseLevel
));
273 if (_pauseLevel
== 1) {
274 pauseEngineIntern(true);
275 } else if (_pauseLevel
== 0) {
276 pauseEngineIntern(false);
280 void Engine::pauseEngineIntern(bool pause
) {
281 // By default, just (un)pause all digital sounds
282 _mixer
->pauseAll(pause
);
285 void Engine::openMainMenuDialog() {
286 if (!_mainMenuDialog
)
287 _mainMenuDialog
= new MainMenuDialog(this);
288 runDialog(*_mainMenuDialog
);
292 int Engine::runDialog(GUI::Dialog
&dialog
) {
294 int result
= dialog
.runModal();
300 void Engine::syncSoundSettings() {
302 // Sync the engine with the config manager
303 int soundVolumeMusic
= ConfMan
.getInt("music_volume");
304 int soundVolumeSFX
= ConfMan
.getInt("sfx_volume");
305 int soundVolumeSpeech
= ConfMan
.getInt("speech_volume");
308 if (ConfMan
.hasKey("mute"))
309 mute
= ConfMan
.getBool("mute");
311 _mixer
->setVolumeForSoundType(Audio::Mixer::kMusicSoundType
, (mute
? 0 : soundVolumeMusic
));
312 _mixer
->setVolumeForSoundType(Audio::Mixer::kSFXSoundType
, (mute
? 0 : soundVolumeSFX
));
313 _mixer
->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType
, (mute
? 0 : soundVolumeSpeech
));
316 void Engine::flipMute() {
319 if (ConfMan
.hasKey("mute")) {
320 mute
= !ConfMan
.getBool("mute");
323 ConfMan
.setBool("mute", mute
);
328 Common::Error
Engine::loadGameState(int slot
) {
329 // Do nothing by default
330 return Common::kNoError
;
333 bool Engine::canLoadGameStateCurrently() {
334 // Do not allow loading by default
338 Common::Error
Engine::saveGameState(int slot
, const char *desc
) {
339 // Do nothing by default
340 return Common::kNoError
;
343 bool Engine::canSaveGameStateCurrently() {
344 // Do not allow saving by default
348 void Engine::quitGame() {
351 event
.type
= Common::EVENT_QUIT
;
352 g_system
->getEventManager()->pushEvent(event
);
355 bool Engine::shouldQuit() {
356 Common::EventManager
*eventMan
= g_system
->getEventManager();
357 return (eventMan
->shouldQuit() || eventMan
->shouldRTL());
361 EnginePlugin *Engine::getMetaEnginePlugin() const {
363 const EnginePlugin *plugin = 0;
364 Common::String gameid = ConfMan.get("gameid");
365 gameid.toLowercase();
366 EngineMan.findGame(gameid, &plugin);