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