It's alive!! (The second one.)
[scummvm-innocent.git] / engines / engine.cpp
blob0847e27246d85abd9798bc80f0ab25025c7264ce
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.
21 * $URL$
22 * $Id$
25 #if defined(WIN32)
26 #include <windows.h>
27 #include <direct.h>
28 // winnt.h defines ARRAYSIZE, but we want our own one...
29 #undef ARRAYSIZE
30 #endif
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"
45 #ifdef _WIN32_WCE
46 extern bool isSmartphone(void);
47 #endif
49 // FIXME: HACK for MidiEmu & error()
50 Engine *g_engine = 0;
53 Engine::Engine(OSystem *syst)
54 : _system(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")),
61 _pauseLevel(0),
62 _mainMenuDialog(NULL) {
64 g_engine = this;
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.");
77 Engine::~Engine() {
78 _mixer->stopAll();
80 delete _mainMenuDialog;
81 g_engine = NULL;
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") &&
93 !gameDomain ||
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");
105 } else {
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
115 // hotkeys.
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)
137 return;
139 // Error out on size switch failure
140 if (gfxError & OSystem::kTransactionSizeChangeFailed) {
141 char buffer[16];
142 snprintf(buffer, 16, "%dx%d", width, height);
144 Common::String message = "Could not switch to resolution: '";
145 message += buffer;
146 message += "'.";
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");
156 message += "'.";
158 GUI::MessageDialog dialog(message);
159 dialog.runModal();
162 if (gfxError & OSystem::kTransactionAspectRatioFailed) {
163 GUI::MessageDialog dialog("Could not apply aspect ratio setting.");
164 dialog.runModal();
167 if (gfxError & OSystem::kTransactionFullscreenFailed) {
168 GUI::MessageDialog dialog("Could not apply fullscreen setting.");
169 dialog.runModal();
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);
180 dialog.runModal();
181 } else {
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.
195 #ifdef USE_VORBIS
196 if (Common::File::exists("track1.ogg") ||
197 Common::File::exists("track01.ogg"))
198 return;
199 #endif
200 #ifdef USE_FLAC
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"))
205 return;
206 #endif
207 #ifdef USE_MAD
208 if (Common::File::exists("track1.mp3") ||
209 Common::File::exists("track01.mp3"))
210 return;
211 #endif
213 char buffer[MAXPATHLEN];
214 int i;
216 if (_gameDataDir.getPath().empty()) {
217 // That's it! I give up!
218 if (getcwd(buffer, MAXPATHLEN) == NULL)
219 return;
220 } else
221 strncpy(buffer, _gameDataDir.getPath().c_str(), MAXPATHLEN);
223 for (i = 0; i < MAXPATHLEN - 1; i++) {
224 if (buffer[i] == '\\')
225 break;
228 buffer[i + 1] = 0;
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");
237 dialog.runModal();
238 } else {
239 // If we reached here, the game has audio tracks,
240 // it's not ran from the CD and the tracks have not
241 // been ripped.
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");
248 dialog.runModal();
250 #endif
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);
261 if (size > 0)
262 buf2[size-1] = '\0';
265 void Engine::pauseEngine(bool pause) {
266 assert((pause && _pauseLevel >= 0) || (!pause && _pauseLevel));
268 if (pause)
269 _pauseLevel++;
270 else
271 _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);
289 syncSoundSettings();
292 int Engine::runDialog(GUI::Dialog &dialog) {
293 pauseEngine(true);
294 int result = dialog.runModal();
295 pauseEngine(false);
297 return result;
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");
307 bool mute = false;
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() {
317 bool mute = false;
319 if (ConfMan.hasKey("mute")) {
320 mute = !ConfMan.getBool("mute");
323 ConfMan.setBool("mute", mute);
325 syncSoundSettings();
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
335 return false;
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
345 return false;
348 void Engine::quitGame() {
349 Common::Event event;
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);
367 return plugin;