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