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 "ags/shared/core/platform.h"
24 #define AGS_PLATFORM_DEFINES_PSP_VARS (AGS_PLATFORM_OS_IOS || AGS_PLATFORM_OS_ANDROID)
25 #include "ags/lib/std/set.h"
26 #include "ags/lib/allegro.h" // allegro_exit
27 #include "ags/shared/ac/common.h"
28 #include "ags/engine/ac/game_setup.h"
29 #include "ags/engine/ac/game_state.h"
30 #include "ags/shared/core/def_version.h"
31 #include "ags/engine/debugging/debugger.h"
32 #include "ags/engine/debugging/debug_log.h"
33 #include "ags/shared/debugging/out.h"
34 #include "ags/engine/main/config.h"
35 #include "ags/engine/main/engine.h"
36 #include "ags/engine/main/main.h"
37 #include "ags/engine/platform/base/ags_platform_driver.h"
38 #include "ags/engine/platform/base/sys_main.h"
39 #include "ags/engine/ac/route_finder.h"
40 #include "ags/shared/core/asset_manager.h"
41 #include "ags/shared/util/directory.h"
42 #include "ags/shared/util/path.h"
43 #include "ags/shared/util/string_compat.h"
44 #include "ags/globals.h"
45 
46 namespace AGS3 {
47 
48 #if AGS_PLATFORM_OS_WINDOWS && !AGS_PLATFORM_DEBUG
49 #define USE_CUSTOM_EXCEPTION_HANDLER
50 #endif
51 
52 using namespace AGS::Shared;
53 using namespace AGS::Engine;
54 
main_pre_init()55 void main_pre_init() {
56 	_G(our_eip) = -999;
57 	_GP(AssetMgr)->SetSearchPriority(Shared::kAssetPriorityDir);
58 	_GP(play).takeover_data = 0;
59 }
60 
main_create_platform_driver()61 void main_create_platform_driver() {
62 	_G(platform) = AGSPlatformDriver::GetDriver();
63 }
64 
65 // this needs to be updated if the "play" struct changes
66 #define SVG_VERSION_BWCOMPAT_MAJOR      3
67 #define SVG_VERSION_BWCOMPAT_MINOR      2
68 #define SVG_VERSION_BWCOMPAT_RELEASE    0
69 #define SVG_VERSION_BWCOMPAT_REVISION   1103
70 // CHECKME: we may lower this down, if we find that earlier versions may still
71 // load new savedgames
72 #define SVG_VERSION_FWCOMPAT_MAJOR      3
73 #define SVG_VERSION_FWCOMPAT_MINOR      2
74 #define SVG_VERSION_FWCOMPAT_RELEASE    1
75 #define SVG_VERSION_FWCOMPAT_REVISION   1111
76 
main_init(int argc,const char * argv[])77 void main_init(int argc, const char *argv[]) {
78 	// Init libraries: set text encoding
79 	set_uformat(U_UTF8);
80 	set_filename_encoding(U_UNICODE);
81 
82 	_G(EngineVersion) = Version(ACI_VERSION_STR " " SPECIAL_VERSION);
83 #if defined (BUILD_STR)
84 	_G(EngineVersion).BuildInfo = BUILD_STR;
85 #endif
86 	_G(SavedgameLowestBackwardCompatVersion) = Version(SVG_VERSION_BWCOMPAT_MAJOR, SVG_VERSION_BWCOMPAT_MINOR, SVG_VERSION_BWCOMPAT_RELEASE, SVG_VERSION_BWCOMPAT_REVISION);
87 	_G(SavedgameLowestForwardCompatVersion) = Version(SVG_VERSION_FWCOMPAT_MAJOR, SVG_VERSION_FWCOMPAT_MINOR, SVG_VERSION_FWCOMPAT_RELEASE, SVG_VERSION_FWCOMPAT_REVISION);
88 
89 	_GP(AssetMgr).reset(new AssetManager());
90 	main_pre_init();
91 	main_create_platform_driver();
92 	_G(platform)->MainInitAdjustments();
93 
94 	_G(global_argv) = argv;
95 	_G(global_argc) = argc;
96 }
97 
get_engine_string()98 String get_engine_string() {
99 	return String::FromFormat("Adventure Game Studio v%s Interpreter\n"
100 	                          "Copyright (c) 1999-2011 Chris Jones and " ACI_COPYRIGHT_YEARS " others\n"
101 #ifdef BUILD_STR
102 	                          "ACI version %s (Build: %s)\n",
103 	                          _G(EngineVersion).ShortString.GetCStr(), _G(EngineVersion).LongString.GetCStr(), _G(EngineVersion).BuildInfo.GetCStr());
104 #else
105 	                          "ACI version %s\n", _G(EngineVersion).ShortString.GetCStr(), _G(EngineVersion).LongString.GetCStr());
106 #endif
107 }
108 
main_print_help()109 void main_print_help() {
110 	_G(platform)->WriteStdOut("%s",
111 	                          "Usage: ags [OPTIONS] [GAMEFILE or DIRECTORY]\n\n"
112 	                          //--------------------------------------------------------------------------------|
113 	                          "Options:\n"
114 	                          "  --conf FILEPATH              Specify explicit config file to read on startup\n"
115 #if AGS_PLATFORM_OS_WINDOWS
116 	                          "  --console-attach             Write output to the parent process's console\n"
117 #endif
118 	                          "  --fps                        Display fps counter\n"
119 	                          "  --fullscreen                 Force display mode to fullscreen\n"
120 	                          "  --gfxdriver <id>             Request graphics driver. Available options:\n"
121 #if AGS_PLATFORM_OS_WINDOWS
122 	                          "                                 d3d9, ogl, software\n"
123 #else
124 	                          "                                 ogl, software\n"
125 #endif
126 	                          "  --gfxfilter FILTER [SCALING]\n"
127 	                          "                               Request graphics filter. Available options:\n"
128 	                          "                                 hqx, linear, none, stdscale\n"
129 	                          "                                 (support differs between graphic drivers);\n"
130 	                          "                                 scaling is specified by integer number\n"
131 	                          "  --help                       Print this help message and stop\n"
132 	                          "  --loadsavedgame FILEPATH     Load savegame on startup\n"
133 	                          "  --localuserconf              Read and write user config in the game's \n"
134 	                          "                               directory rather than using standard system path.\n"
135 	                          "                               Game directory must be writeable.\n"
136 	                          "  --log-OUTPUT=GROUP[:LEVEL][,GROUP[:LEVEL]][,...]\n"
137 	                          "  --log-OUTPUT=+GROUPLIST[:LEVEL]\n"
138 	                          "                               Setup logging to the chosen OUTPUT with given\n"
139 	                          "                               log groups and verbosity levels. Groups may\n"
140 	                          "                               be also defined by a LIST of one-letter IDs,\n"
141 	                          "                               preceded by '+', e.g. +ABCD:LEVEL. Verbosity may\n"
142 	                          "                               be also defined by a numberic ID.\n"
143 	                          "                               OUTPUTs are\n"
144 	                          "                                 stdout, file, console\n"
145 	                          "                               (where \"console\" is internal engine's console)\n"
146 	                          "                               GROUPs are:\n"
147 	                          "                                 all, main (m), game (g), manobj (o),\n"
148 	                          "                                 sprcache (c)\n"
149 	                          "                               LEVELs are:\n"
150 	                          "                                 all, alert (1), fatal (2), error (3), warn (4),\n"
151 	                          "                                 info (5), debug (6)\n"
152 	                          "                               Examples:\n"
153 	                          "                                 --log-stdout=+mg:debug\n"
154 	                          "                                 --log-file=all:warn\n"
155 	                          "  --log-file-path=PATH         Define custom path for the log file\n"
156 	                          //--------------------------------------------------------------------------------|
157 #if AGS_PLATFORM_OS_WINDOWS
158 	                          "  --no-message-box             Disable alerts as modal message boxes\n"
159 #endif
160 	                          "  --noiface                    Don't draw game GUI\n"
161 	                          "  --noscript                   Don't run room scripts; *WARNING:* unreliable\n"
162 	                          "  --nospr                      Don't draw room objects and characters\n"
163 	                          "  --noupdate                   Don't run game update\n"
164 	                          "  --novideo                    Don't play game videos\n"
165 #if AGS_PLATFORM_OS_WINDOWS
166 	                          "  --setup                      Run setup application\n"
167 #endif
168 	                          "  --shared-data-dir DIR        Set the shared game data directory\n"
169 	                          "  --startr <room_number>       Start game by loading certain room.\n"
170 	                          "  --tell                       Print various information concerning engine\n"
171 	                          "                                 and the game; for selected output use:\n"
172 	                          "  --tell-config                Print contents of merged game config\n"
173 	                          "  --tell-configpath            Print paths to available config files\n"
174 	                          "  --tell-data                  Print information on game data and its location\n"
175 	                          "  --tell-gameproperties        Print information on game general settings\n"
176 	                          "  --tell-engine                Print engine name and version\n"
177 	                          "  --tell-filepath              Print all filepaths engine uses for the game\n"
178 	                          "  --tell-graphicdriver         Print list of supported graphic drivers\n"
179 	                          "\n"
180 	                          "  --test                       Run game in the test mode\n"
181 	                          "  --version                    Print engine's version and stop\n"
182 	                          "  --user-data-dir DIR          Set the save game directory\n"
183 	                          "  --windowed                   Force display mode to windowed\n"
184 	                          "\n"
185 	                          "Gamefile options:\n"
186 	                          "  /dir/path/game/              Launch the game in specified directory\n"
187 	                          "  /dir/path/game/penguin.exe   Launch penguin.exe\n"
188 	                          "  [nothing]                    Launch the game in the current directory\n"
189 	                          //--------------------------------------------------------------------------------|
190 	                         );
191 }
192 
main_process_cmdline(ConfigTree & cfg,int argc,const char * argv[])193 int main_process_cmdline(ConfigTree &cfg, int argc, const char *argv[]) {
194 	int datafile_argv = 0;
195 	for (int ee = 1; ee < argc; ++ee) {
196 		const char *arg = argv[ee];
197 		//
198 		// Startup options
199 		//
200 		if (ags_stricmp(arg, "--help") == 0 || ags_stricmp(arg, "/?") == 0 || ags_stricmp(arg, "-?") == 0) {
201 			_G(justDisplayHelp) = true;
202 		}
203 		if (ags_stricmp(arg, "-v") == 0 || ags_stricmp(arg, "--version") == 0) {
204 			_G(justDisplayVersion) = true;
205 		} else if (ags_stricmp(arg, "--updatereg") == 0)
206 			_G(debug_flags) |= DBG_REGONLY;
207 		else if ((ags_stricmp(arg, "--startr") == 0) && (ee < argc - 1)) {
208 			_G(override_start_room) = atoi(argv[ee + 1]);
209 			ee++;
210 		} else if (ags_stricmp(arg, "--noexceptionhandler") == 0) _GP(usetup).disable_exception_handling = true;
211 		else if (ags_stricmp(arg, "--setup") == 0) {
212 			_G(justRunSetup) = true;
213 		} else if (ags_stricmp(arg, "--registergame") == 0) {
214 			_G(justRegisterGame) = true;
215 		} else if (ags_stricmp(arg, "--unregistergame") == 0) {
216 			_G(justUnRegisterGame) = true;
217 		} else if ((ags_stricmp(arg, "--loadsavedgame") == 0) && (argc > ee + 1)) {
218 			_G(loadSaveGameOnStartup) = atoi(argv[ee + 1]);
219 			ee++;
220 		} else if ((ags_stricmp(arg, "--enabledebugger") == 0) && (argc > ee + 1)) {
221 			strcpy(_G(editor_debugger_instance_token), argv[ee + 1]);
222 			_G(editor_debugging_enabled) = 1;
223 			_G(force_window) = 1;
224 			ee++;
225 		} else if (ags_stricmp(arg, "--conf") == 0 && (argc > ee + 1)) {
226 			_GP(usetup).conf_path = argv[++ee];
227 		} else if (ags_stricmp(arg, "--localuserconf") == 0) {
228 			_GP(usetup).local_user_conf = true;
229 		} else if (ags_stricmp(arg, "--runfromide") == 0 && (argc > ee + 4)) {
230 			_GP(usetup).install_dir = argv[ee + 1];
231 			_GP(usetup).opt_data_dir = argv[ee + 2];
232 			_GP(usetup).opt_audio_dir = argv[ee + 3];
233 			_GP(usetup).opt_voice_dir = argv[ee + 4];
234 			ee += 4;
235 		} else if (ags_stricmp(arg, "--takeover") == 0) {
236 			if (argc < ee + 2)
237 				break;
238 			_GP(play).takeover_data = atoi(argv[ee + 1]);
239 			strncpy(_GP(play).takeover_from, argv[ee + 2], 49);
240 			_GP(play).takeover_from[49] = 0;
241 			ee += 2;
242 		} else if (ags_strnicmp(arg, "--tell", 6) == 0) {
243 			if (arg[6] == 0)
244 				_G(tellInfoKeys).insert(String("all"));
245 			else if (arg[6] == '-' && arg[7] != 0)
246 				_G(tellInfoKeys).insert(String(arg + 7));
247 		}
248 		//
249 		// Config overrides
250 		//
251 		else if ((ags_stricmp(arg, "--user-data-dir") == 0) && (argc > ee + 1))
252 			cfg["misc"]["user_data_dir"] = argv[++ee];
253 		else if ((ags_stricmp(arg, "--shared-data-dir") == 0) && (argc > ee + 1))
254 			cfg["misc"]["shared_data_dir"] = argv[++ee];
255 		else if (ags_stricmp(arg, "--windowed") == 0)
256 			_G(force_window) = 1;
257 		else if (ags_stricmp(arg, "--fullscreen") == 0)
258 			_G(force_window) = 2;
259 		else if ((ags_stricmp(arg, "--gfxdriver") == 0) && (argc > ee + 1)) {
260 			INIwritestring(cfg, "graphics", "driver", argv[++ee]);
261 		} else if ((ags_stricmp(arg, "--gfxfilter") == 0) && (argc > ee + 1)) {
262 			// NOTE: we make an assumption here that if user provides scaling factor,
263 			// this factor means to be applied to windowed mode only.
264 			INIwritestring(cfg, "graphics", "filter", argv[++ee]);
265 			if (argc > ee + 1 && argv[ee + 1][0] != '-')
266 				INIwritestring(cfg, "graphics", "game_scale_win", argv[++ee]);
267 			else
268 				INIwritestring(cfg, "graphics", "game_scale_win", "max_round");
269 		} else if (ags_stricmp(arg, "--fps") == 0) _G(display_fps) = kFPS_Forced;
270 		else if (ags_stricmp(arg, "--test") == 0) _G(debug_flags) |= DBG_DEBUGMODE;
271 		else if (ags_stricmp(arg, "--noiface") == 0) _G(debug_flags) |= DBG_NOIFACE;
272 		else if (ags_stricmp(arg, "--nosprdisp") == 0) _G(debug_flags) |= DBG_NODRAWSPRITES;
273 		else if (ags_stricmp(arg, "--nospr") == 0) _G(debug_flags) |= DBG_NOOBJECTS;
274 		else if (ags_stricmp(arg, "--noupdate") == 0) _G(debug_flags) |= DBG_NOUPDATE;
275 		else if (ags_stricmp(arg, "--nosound") == 0) _G(debug_flags) |= DBG_NOSFX;
276 		else if (ags_stricmp(arg, "--nomusic") == 0) _G(debug_flags) |= DBG_NOMUSIC;
277 		else if (ags_stricmp(arg, "--noscript") == 0) _G(debug_flags) |= DBG_NOSCRIPT;
278 		else if (ags_stricmp(arg, "--novideo") == 0) _G(debug_flags) |= DBG_NOVIDEO;
279 		else if (ags_strnicmp(arg, "--log-", 6) == 0 && arg[6] != 0) {
280 			String logarg = arg + 6;
281 			size_t split_at = logarg.FindChar('=');
282 			if (split_at != String::npos)
283 				cfg["log"][logarg.Left(split_at)] = logarg.Mid(split_at + 1);
284 			else
285 				cfg["log"][logarg] = "";
286 		}
287 		//
288 		// Special case: data file location
289 		//
290 		else if (arg[0] != '-') datafile_argv = ee;
291 	}
292 
293 	if (datafile_argv > 0) {
294 		_G(cmdGameDataPath) = GetPathFromCmdArg(datafile_argv);
295 	} else {
296 		// assign standard path for mobile/consoles (defined in their own platform implementation)
297 		_G(cmdGameDataPath) = _G(psp_game_file_name);
298 	}
299 
300 	if (_G(tellInfoKeys).size() > 0)
301 		_G(justTellInfo) = true;
302 
303 	return 0;
304 }
305 
main_set_gamedir(int argc,const char * argv[])306 void main_set_gamedir(int argc, const char *argv[]) {
307 	_G(appPath) = GetPathFromCmdArg(0);
308 	_G(appDirectory) = Path::GetDirectoryPath(_G(appPath));
309 
310 	// TODO: remove following when supporting unicode paths
311 	{
312 		// It looks like Allegro library does not like ANSI (ACP) paths.
313 		// When *not* working in U_UNICODE filepath mode, whenever it gets
314 		// current directory for its own operations, it "fixes" it by
315 		// substituting non-ASCII symbols with '^'.
316 		// Here we explicitly set current directory to ASCII path.
317 		String cur_dir = Directory::GetCurrentDirectory();
318 		String path = Path::GetPathInASCII(cur_dir);
319 		if (!path.IsEmpty())
320 			Directory::SetCurrentDirectory(Path::MakeAbsolutePath(path));
321 		else
322 			Debug::Printf(kDbgMsg_Error, "Unable to determine current directory: GetPathInASCII failed.\nArg: %s", cur_dir.GetCStr());
323 	}
324 }
325 
GetPathFromCmdArg(int arg_index)326 String GetPathFromCmdArg(int arg_index) {
327 	if (arg_index < 0 || arg_index >= _G(global_argc))
328 		return "";
329 	String path = Path::GetCmdLinePathInASCII(_G(global_argv)[arg_index], arg_index);
330 	if (!path.IsEmpty())
331 		return Path::MakeAbsolutePath(path);
332 	Debug::Printf(kDbgMsg_Error, "Unable to determine path: GetCmdLinePathInASCII failed.\nCommand line argument %i: %s", arg_index, _G(global_argv)[arg_index]);
333 	return _G(global_argv)[arg_index];
334 }
335 
336 } // namespace AGS3
337