1 /* ScummVM - Graphic Adventure Engine
2 *
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.
6 *
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.
11 *
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.
16 *
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.
20 *
21 */
22
23 #include "common/scummsys.h"
24 #include "common/config-manager.h"
25 #include "common/debug-channels.h"
26 #include "common/events.h"
27 #include "engines/util.h"
28 #include "xeen/xeen.h"
29 #include "xeen/files.h"
30 #include "xeen/resources.h"
31
32 namespace Xeen {
33
34 XeenEngine *g_vm = nullptr;
35
XeenEngine(OSystem * syst,const XeenGameDescription * gameDesc)36 XeenEngine::XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc)
37 : Engine(syst), _gameDescription(gameDesc), _randomSource("Xeen") {
38
39 _combat = nullptr;
40 _debugger = nullptr;
41 _events = nullptr;
42 _files = nullptr;
43 _interface = nullptr;
44 _locations = nullptr;
45 _map = nullptr;
46 _party = nullptr;
47 _patcher = nullptr;
48 _resources = nullptr;
49 _saves = nullptr;
50 _screen = nullptr;
51 _scripts = nullptr;
52 _sound = nullptr;
53 _spells = nullptr;
54 _windows = nullptr;
55 _noDirectionSense = false;
56 _startupWindowActive = false;
57 _gameMode = GMODE_STARTUP;
58 _mode = MODE_STARTUP;
59 _endingScore = 0;
60 _loadSaveSlot = -1;
61 _gameWon[0] = _gameWon[1] = _gameWon[2] = false;
62 _finalScore = 0;
63 g_vm = this;
64 }
65
~XeenEngine()66 XeenEngine::~XeenEngine() {
67 delete _combat;
68 //_debugger is deleted by Engine
69 delete _events;
70 delete _interface;
71 delete _locations;
72 delete _map;
73 delete _party;
74 delete _patcher;
75 delete _saves;
76 delete _screen;
77 delete _scripts;
78 delete _sound;
79 delete _spells;
80 delete _windows;
81 delete _resources;
82 delete _files;
83 g_vm = nullptr;
84 }
85
initialize()86 bool XeenEngine::initialize() {
87 // Create sub-objects of the engine
88 _files = new FileManager(this);
89 if (!_files->setup())
90 return false;
91
92 _resources = new Resources();
93 _combat = new Combat(this);
94 _debugger = new Debugger(this);
95 setDebugger(_debugger);
96 _events = new EventsManager(this);
97 _interface = new Interface(this);
98 _locations = new LocationManager();
99 _map = new Map(this);
100 _party = new Party(this);
101 _patcher = new Patcher();
102 _saves = new SavesManager(_targetName);
103 _screen = new Screen(this);
104 _scripts = new Scripts(this);
105 _sound = new Sound(_mixer);
106 _spells = new Spells(this);
107 _windows = new Windows();
108
109 // Set graphics mode
110 initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
111
112 // Setup mixer
113 syncSoundSettings();
114
115 // Load settings
116 loadSettings();
117
118 return true;
119 }
120
loadSettings()121 void XeenEngine::loadSettings() {
122 _gameWon[0] = ConfMan.hasKey("game_won") && ConfMan.getBool("game_won");
123 _gameWon[1] = ConfMan.hasKey("game_won2") && ConfMan.getBool("game_won2");
124 _gameWon[2] = ConfMan.hasKey("game_won3") && ConfMan.getBool("game_won3");
125 _finalScore = ConfMan.hasKey("final_score") ? ConfMan.getInt("final_score") : 0;
126
127 _extOptions._showItemCosts = ConfMan.hasKey("ShowItemCosts") && ConfMan.getBool("ShowItemCosts");
128 _extOptions._durableArmor = ConfMan.hasKey("DurableArmor") && ConfMan.getBool("DurableArmor");
129
130 // If requested, load a savegame instead of showing the intro
131 if (ConfMan.hasKey("save_slot")) {
132 int saveSlot = ConfMan.getInt("save_slot");
133 if (saveSlot >= 0 && saveSlot <= 999)
134 _loadSaveSlot = saveSlot;
135 }
136 }
137
run()138 Common::Error XeenEngine::run() {
139 if (initialize())
140 outerGameLoop();
141
142 return Common::kNoError;
143 }
144
outerGameLoop()145 void XeenEngine::outerGameLoop() {
146 if (_loadSaveSlot != -1)
147 // Loading savegame from launcher, so Skip menu and go straight to game
148 _gameMode = GMODE_PLAY_GAME;
149
150 while (!shouldQuit() && _gameMode != GMODE_QUIT) {
151 GameMode mode = _gameMode;
152 _gameMode = GMODE_NONE;
153 assert(mode != GMODE_NONE);
154
155 switch (mode) {
156 case GMODE_STARTUP:
157 showStartup();
158 break;
159
160 case GMODE_MENU:
161 showMainMenu();
162 break;
163
164 case GMODE_PLAY_GAME:
165 playGame();
166 break;
167
168 default:
169 break;
170 }
171 }
172 }
173
getRandomNumber(int maxNumber)174 int XeenEngine::getRandomNumber(int maxNumber) {
175 return _randomSource.getRandomNumber(maxNumber);
176 }
177
getRandomNumber(int minNumber,int maxNumber)178 int XeenEngine::getRandomNumber(int minNumber, int maxNumber) {
179 return getRandomNumber(maxNumber - minNumber) + minNumber;
180 }
181
saveGameState(int slot,const Common::String & desc,bool isAutosave)182 Common::Error XeenEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
183 return _saves->saveGameState(slot, desc);
184 }
185
loadGameState(int slot)186 Common::Error XeenEngine::loadGameState(int slot) {
187 _loadSaveSlot = slot;
188 return Common::kNoError;
189 }
190
canLoadGameStateCurrently()191 bool XeenEngine::canLoadGameStateCurrently() {
192 return _mode != MODE_STARTUP;
193 }
194
canSaveGameStateCurrently()195 bool XeenEngine::canSaveGameStateCurrently() {
196 return _mode != MODE_COMBAT && _mode != MODE_STARTUP && _mode != MODE_SCRIPT_IN_PROGRESS
197 && (_map->mazeData()._mazeFlags & RESTRICTION_SAVE) == 0;
198 }
199
canSaveAutosaveCurrently()200 bool XeenEngine::canSaveAutosaveCurrently() {
201 return canSaveGameStateCurrently() &&
202 (_map && !(_map->mazeData()._mazeFlags & RESTRICTION_SAVE));
203 }
204
playGame()205 void XeenEngine::playGame() {
206 _files->setGameCc(0);
207 _sound->stopAllAudio();
208 SpriteResource::setClippedBottom(140);
209
210 play();
211 _sound->stopAllAudio();
212 }
213
play()214 void XeenEngine::play() {
215 _interface->setup();
216 _screen->loadBackground("back.raw");
217 _screen->loadPalette("mm4.pal");
218
219 if (getGameID() == GType_DarkSide && !_map->_loadCcNum) {
220 _map->_loadCcNum = 1;
221 _party->_mazeId = 29;
222 _party->_mazeDirection = DIR_NORTH;
223 _party->_mazePosition.x = 25;
224 _party->_mazePosition.y = 21;
225 }
226
227 _map->clearMaze();
228 if (_loadSaveSlot >= 0) {
229 _saves->newGame();
230 _saves->loadGameState(_loadSaveSlot);
231 _loadSaveSlot = -1;
232 } else {
233 _map->load(_party->_mazeId);
234 }
235
236 _interface->startup();
237 if (_mode == MODE_STARTUP) {
238 // _screen->fadeOut();
239 }
240
241 (*_windows)[0].update();
242 _interface->mainIconsPrint();
243 (*_windows)[0].update();
244 _events->setCursor(0);
245
246 _combat->_moveMonsters = true;
247 if (_mode == MODE_STARTUP) {
248 _mode = MODE_INTERACTIVE;
249 _screen->fadeIn();
250 }
251
252 _combat->_moveMonsters = true;
253
254 gameLoop();
255
256 if (_party->_dead)
257 death();
258
259 _mode = MODE_STARTUP;
260 _gameMode = GMODE_MENU;
261 }
262
gameLoop()263 void XeenEngine::gameLoop() {
264 // Main game loop
265 while (isLoadPending() || !shouldExit()) {
266 if (isLoadPending()) {
267 // Load any pending savegame
268 int saveSlot = _loadSaveSlot;
269 _loadSaveSlot = -1;
270 (void)_saves->loadGameState(saveSlot);
271 _interface->drawParty(true);
272 }
273
274 _map->cellFlagLookup(_party->_mazePosition);
275 if (_map->_currentIsEvent) {
276 _gameMode = (GameMode)_scripts->checkEvents();
277 if (isLoadPending())
278 continue;
279 if (shouldExit())
280 return;
281 }
282 _party->giveTreasure();
283
284 // Main user interface handler for waiting for and processing user input
285 _interface->perform();
286
287 if (_party->_dead)
288 break;
289 }
290 }
291
printMil(uint value)292 Common::String XeenEngine::printMil(uint value) {
293 return (value >= 1000000) ? Common::String::format("%u mil", value / 1000000) :
294 Common::String::format("%u", value);
295 }
296
printK(uint value)297 Common::String XeenEngine::printK(uint value) {
298 return (value > 9999) ? Common::String::format("%uk", value / 1000) :
299 Common::String::format("%u", value);
300 }
301
printK2(uint value)302 Common::String XeenEngine::printK2(uint value) {
303 return (value > 999) ? Common::String::format("%uk", value / 1000) :
304 Common::String::format("%u", value);
305 }
306
syncSoundSettings()307 void XeenEngine::syncSoundSettings() {
308 Engine::syncSoundSettings();
309
310 if (_sound)
311 _sound->updateSoundSettings();
312 }
313
saveSettings()314 void XeenEngine::saveSettings() {
315 if (_gameWon[0])
316 ConfMan.setBool("game_won", true);
317 if (_gameWon[1])
318 ConfMan.setBool("game_won2", true);
319 if (_gameWon[2])
320 ConfMan.setBool("game_won3", true);
321
322 ConfMan.setInt("final_score", _finalScore);
323 ConfMan.flushToDisk();
324 }
325
GUIError(const Common::U32String & msg)326 void XeenEngine::GUIError(const Common::U32String &msg) {
327 GUIErrorMessage(msg);
328 }
329
330 } // End of namespace Xeen
331