1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the AUTHORS
5 * file distributed with this source distribution.
6 *
7 * Additional copyright for this file:
8 * Copyright (C) 1999-2000 Revolution Software Ltd.
9 * This code is based on source code created by Revolution Software,
10 * used with permission.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 *
26 */
27
28 #include "engines/icb/keyboard.h"
29 #include "engines/icb/mouse.h"
30 #include "engines/icb/debug.h"
31 #include "engines/icb/res_man.h"
32 #include "engines/icb/options_manager_pc.h"
33 #include "engines/icb/p4.h"
34 #include "engines/icb/global_vars.h"
35 #include "engines/icb/common/px_common.h"
36 #include "engines/icb/common/px_bitmap.h"
37 #include "engines/icb/stage_draw.h"
38 #include "engines/icb/mission.h"
39 #include "engines/icb/cluster_manager_pc.h"
40 #include "engines/icb/configfile.h"
41
42 #include "common/str.h"
43 #include "common/config-manager.h"
44 #include "common/system.h"
45 #include "common/events.h"
46
47 namespace ICB {
48
49 bool gRegainedFocus = false;
50 bool gotTheFocus = false;
51
52 char g_characters[] = "characters\\";
53 char gamelanguage[ENGINE_STRING_LEN] = "english";
54 bool8 camera_hack;
55 uint32 BACKGROUND_BUFFER_SIZE;
56 uint32 ANIMATION_BUFFER_SIZE;
57 uint32 BITMAP_BUFFER_SIZE;
58 uint32 SONICS_BUFFER_SIZE;
59
60 // private session data (scripts+objects+walkgrids) : 200KB
61 #define PRIVATE_RESMAN_SIZE (400 * 1024)
62
63 // local prototypes
64 void Mission_and_console();
65
getConfigValueWithDefault(const ConfigFile & config,const Common::String & section,const Common::String & key,uint32 defaultValue)66 uint32 getConfigValueWithDefault(const ConfigFile &config, const Common::String §ion, const Common::String &key, uint32 defaultValue) {
67 if (scumm_stricmp("MusicVolume", key.c_str()) == 0) {
68 return ConfMan.getInt("music_volume") / 2;
69 } else if (scumm_stricmp("SpeechVolume", key.c_str()) == 0) {
70 return ConfMan.getInt("speech_volume") / 2;
71 } else if (scumm_stricmp("SfxVolume", key.c_str()) == 0) {
72 return ConfMan.getInt("sfx_volume") / 2;
73 } else if (scumm_stricmp("Game Completed", key.c_str()) == 0) {
74 if (ConfMan.hasKey("game_completed"))
75 return ConfMan.getBool("game_completed") ? 1 : 0;
76 else
77 return 0;
78 } else if (scumm_stricmp("Subtitles", key.c_str()) == 0) {
79 if (ConfMan.hasKey("subtitles"))
80 return (uint32)ConfMan.getBool("subtitles");
81 } else if (scumm_stricmp("Movie Library", section.c_str()) == 0) {
82 Common::String movie = Common::String("movie_") + key;
83 if (ConfMan.hasKey(movie))
84 return (uint32)ConfMan.getBool(movie);
85 else {
86 uint32 result = config.readIntSetting(section, key, defaultValue);
87 ConfMan.setBool(movie, result != 0);
88 }
89 } else if (scumm_stricmp("Controller Settings", section.c_str()) == 0 &&
90 scumm_stricmp("Method", key.c_str()) == 0) {
91 if (ConfMan.hasKey("actor_relative"))
92 return ConfMan.getBool("actor_relative") ? 0 : 1;
93 else {
94 uint32 result = config.readIntSetting(section, key, defaultValue);
95 ConfMan.setBool("actor_relative", result == 0);
96 }
97 }
98
99 return config.readIntSetting(section, key, defaultValue);
100 }
101
ReadConfigFromIniFile()102 void ReadConfigFromIniFile() {
103 char configFile[1024];
104 uint32 temp;
105
106 sprintf(configFile, CONFIG_INI_FILENAME);
107
108 ConfigFile config;
109 pxString filename = configFile;
110 filename.ConvertPath();
111 config.readFile(filename.c_str());
112
113 // Music volume
114 SetMusicVolume(getConfigValueWithDefault(config, "Option Settings", "MusicVolume", 127));
115
116 // Speech volume
117 SetSpeechVolume(getConfigValueWithDefault(config, "Option Settings", "SpeechVolume", 127));
118
119 // Sfx volume
120 SetSfxVolume(getConfigValueWithDefault(config, "Option Settings", "SfxVolume", 127));
121
122 // Has the game been completed previously
123 temp = getConfigValueWithDefault(config, "Extras", "Game Completed", 0);
124 // HACK: Enable all extras for now
125 warning("Enabling all extras for development purposes");
126 temp = 1;
127 if (temp == 0)
128 g_px->game_completed = FALSE8;
129 else
130 g_px->game_completed = TRUE8;
131
132 // Subtitle switch
133 temp = getConfigValueWithDefault(config, "Video Settings", "Subtitles", 1);
134 if (temp == 0)
135 g_px->on_screen_text = FALSE8;
136 else
137 g_px->on_screen_text = TRUE8;
138
139 // Control method
140 temp = getConfigValueWithDefault(config, "Controller Settings", "Method", ACTOR_RELATIVE);
141 if ((__Actor_control_mode)temp == SCREEN_RELATIVE)
142 g_icb_session->player.Set_control_mode(SCREEN_RELATIVE);
143 else
144 g_icb_session->player.Set_control_mode(ACTOR_RELATIVE);
145
146 // Set the default keys first in case the ini file mappings are invalid somehow
147 SetDefaultKeys();
148
149 // Read the movie library settings
150 for (uint32 i = 0; i < TOTAL_NUMBER_OF_MOVIES; i++) {
151 temp = config.readIntSetting("Movie Library", pxVString("%X", HashString(g_movieLibrary[i].filename)), 0);
152 if (temp == 0)
153 g_movieLibrary[i].visible = FALSE8;
154 else
155 g_movieLibrary[i].visible = TRUE8;
156 }
157 }
158
Save_config_file()159 void Save_config_file() {
160 ConfMan.setInt("music_volume", GetMusicVolume() * 2);
161 ConfMan.setInt("speech_volume", GetMusicVolume() * 2);
162 ConfMan.setInt("sfx_volume", GetMusicVolume() * 2);
163 ConfMan.setBool("subtitles", g_px->on_screen_text != 0);
164 ConfMan.setBool("game_completed", g_px->game_completed);
165 ConfMan.setBool("actor_relative", g_icb_session->player.Get_control_mode() == ACTOR_RELATIVE);
166
167 // Write the movie library settings
168 for (uint32 i = 0; i < TOTAL_NUMBER_OF_MOVIES; i++) {
169 // Only write a setting when it's been achieved
170 if (g_movieLibrary[i].visible) {
171 char temp[1024];
172 sprintf(temp, "%X", HashString(g_movieLibrary[i].filename));
173 Common::String movie = Common::String("movie_") + temp;
174 ConfMan.setBool(movie, true);
175 }
176 }
177
178 ConfMan.flushToDisk();
179 }
180
InitEngine(const char * lpCmdLine)181 void InitEngine(const char *lpCmdLine) {
182 CreateGlobalObjects();
183
184 // Set the character root directory to be the same as the normal root directory
185 camera_hack = false; // defaults to off
186
187 // create the surface manaager
188 surface_manager = new _surface_manager;
189
190 // Init the low level direct draw object
191 surface_manager->Init_direct_draw();
192
193 // Init the sound engine
194 if (!Init_Sound_Engine()) {
195 Message_box("Sound device unavailable.");
196 Zdebug("Failed to start the sound engine");
197 noSoundEngine = TRUE8;
198 }
199
200 // See how much memory we have in this machine
201 Memory_stats();
202
203 // Animations
204 rs1 = new res_man(ANIMATION_BUFFER_SIZE);
205 rs1->Set_auto_timeframe_advance();
206 rs_anims = rs1;
207
208 // Icons, Fonts and Remora
209 rs3 = new res_man(BITMAP_BUFFER_SIZE);
210 rs3->Set_auto_timeframe_advance();
211 rs_icons = rs3;
212 rs_remora = rs3;
213 rs_font = rs3;
214
215 // Stage
216 rs2 = new res_man(BACKGROUND_BUFFER_SIZE);
217 rs2->Set_auto_timeframe_advance();
218 rs_bg = rs2;
219
220 // Privates
221 private_session_resman = new res_man(PRIVATE_RESMAN_SIZE);
222
223 // Initalize the Revolution Render Device
224 InitRevRenderDevice();
225
226 // we run a special check for a font file - otherwise, res-open will fail triggering a con-fatal-error - not good
227 sys_font_hash = HashString(SYS_FONT);
228 font_cluster_hash = HashString(FONT_CLUSTER_PATH);
229
230 // inti direct input
231 Init_direct_input();
232
233 // init global variables
234 Zdebug("Init_globals");
235 Init_globals();
236 g_globalScriptVariables->SetVariable("missionelapsedtime", 0);
237 g_globalScriptVariables->SetVariable("demo", 0);
238 Zdebug("~Init_globals");
239
240 // ok, see if the special gameScript is present
241 // if so set the stub mode to GameScript mode
242 if (gs.Init_game_script() && strstr(lpCmdLine, "mission") == NULL) {
243 // GameScript mode
244 // unless there is a console.icb file we dont allow debugging
245
246 // set base mode of stub to gameScript processor
247 g_stub->Set_current_stub_mode(__game_script);
248 } else
249 g_stub->Set_current_stub_mode(__mission_and_console);
250
251 // Initialise the runtime cluster manager
252 g_theClusterManager->Initialise();
253
254 zdebug = FALSE8; // no console so switch off debugging (zoff)
255
256 ConfMan.setBool("actor_relative", true);
257 ConfMan.setBool("subtitles", true);
258
259 // Load settings from our ini file (must be called AFTER everything has been setup)
260 ReadConfigFromIniFile();
261 }
262
quitEngine()263 void quitEngine() {
264 Zdebug("\nap closed");
265 Zdebug("Be Vigilant!\n");
266
267 if (g_mission)
268 g_icb_mission->___delete_mission();
269
270 Close_Sound_Engine();
271
272 if (surface_manager)
273 delete surface_manager;
274
275 Save_config_file(); // write user options ini file
276 DestoryRevRenderDevice();
277
278 // Shutdown the runtime cluster manager
279 g_theClusterManager->Shutdown();
280
281 DestroyGlobalObjects();
282 }
283
mainLoopIteration()284 bool mainLoopIteration() {
285 Common::Event event;
286
287 while (g_system->getEventManager()->pollEvent(event)) {
288 switch (event.type) {
289 case Common::EVENT_KEYDOWN: {
290 // Pass ENTER and BACKSPACE KEYDOWN events to WriteKey() so the save menu in options_manager_pc.cpp can see them.
291 if (event.kbd.keycode == Common::KEYCODE_RETURN) {
292 WriteKey((char)event.kbd.keycode);
293 } else if (event.kbd.keycode == Common::KEYCODE_BACKSPACE) {
294 WriteKey((char)event.kbd.keycode);
295 } else {
296 WriteKey(event.kbd.keycode);
297 }
298 setKeyState(event.kbd.keycode, true);
299 break;
300 }
301 case Common::EVENT_KEYUP: {
302 setKeyState(event.kbd.keycode, false);
303 break;
304 }
305 case Common::EVENT_MOUSEMOVE:
306 mousex = event.mouse.x;
307 mousey = event.mouse.y;
308 break;
309 case Common::EVENT_LBUTTONDOWN:
310 LogMouseEvent(RD_LEFTBUTTONDOWN);
311 mousex = event.mouse.x;
312 mousey = event.mouse.y;
313 break;
314 case Common::EVENT_RBUTTONDOWN:
315 LogMouseEvent(RD_RIGHTBUTTONDOWN);
316 mousex = event.mouse.x;
317 mousey = event.mouse.y;
318 break;
319 case Common::EVENT_LBUTTONUP:
320 LogMouseEvent(RD_LEFTBUTTONUP);
321 mousex = event.mouse.x;
322 mousey = event.mouse.y;
323 break;
324 case Common::EVENT_RBUTTONUP:
325 LogMouseEvent(RD_RIGHTBUTTONUP);
326 mousex = event.mouse.x;
327 mousey = event.mouse.y;
328 break;
329
330 case Common::EVENT_QUIT:
331 quitEngine();
332 return false;
333 default:
334 break;
335 }
336 }
337 // Used to be triggered by else if(gotTheFocus).
338 g_stub->Process_stub();
339
340 g_system->delayMillis(1);
341 return true;
342 }
343
Mission_and_console()344 void Mission_and_console() {
345 // run the mission with console facility
346 // this mode will run forever
347
348 uint32 mission_ret;
349
350 gameCycle += 1; // tick up the game cycle flag
351
352 // logic
353 mission_ret = g_mission->Game_cycle();
354
355 if (mission_ret) {
356 // the mission has terminated of its own accord - as apposed to a user quit
357
358 // if the player died then we bring up a restart/continue menu here
359 c_game_object *ob = (c_game_object *)MS->objects->Fetch_item_by_number(MS->player.Fetch_player_id());
360 int32 ret = ob->GetVariable("state");
361 if (ob->GetIntegerVariable(ret)) {
362 // Return to avoid deleting the mission
363 g_stub->Push_stub_mode(__gameover_menu);
364 return;
365 }
366
367 g_icb_mission->___delete_mission();
368
369 if (!gs.Running_from_gamescript())
370 Fatal_error("Thank you for playing In Cold Blood");
371
372 else
373 g_stub->Pop_stub_mode(); // back to game script server
374 } else
375 g_mission->Create_display();
376 }
377
Terminate_ap()378 void Terminate_ap() {
379 // can be called from any service loop to exit the program and return to windows
380
381 Fatal_error("Terminate Ap");
382 }
383
Fix_time()384 void _stub::Fix_time() {
385 // wait until target time has elapsed
386 // presumably 1/12 second - pc==80ms
387 uint32 targetTime = (TARGET_TIME * 100) / cycle_speed;
388 do {
389 g_system->delayMillis(1);
390 } while ((g_system->getMillis() - stub_timer_time) < targetTime);
391 }
392
WhichCD(const char *)393 int32 WhichCD(const char * /* mission */) { return 1; }
394
HasMMXTechnology()395 bool HasMMXTechnology() { return true; }
396
LoadPlatformSpecific(Common::SeekableReadStream *)397 void _mission::LoadPlatformSpecific(Common::SeekableReadStream * /* fh */) {
398 // No PC specific stuff in here (at the moment)
399 }
400
SavePlatformSpecific(Common::WriteStream *)401 void _mission::SavePlatformSpecific(Common::WriteStream * /* fh */) {
402 // No PC specific stuff in here (at the moment)
403 }
404
405 } // End of namespace ICB
406