1 | /*****************************************************************************\ |
2 | Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. |
3 | This file is licensed under the Snes9x License. |
4 | For further information, consult the LICENSE file in the root directory. |
5 | \*****************************************************************************/ |
6 | |
7 | #include <ctype.h> |
8 | #include <string.h> |
9 | #ifdef HAVE_STRINGS_H |
10 | #include <strings.h> |
11 | #endif |
12 | |
13 | #include "snes9x.h" |
14 | #include "memmap.h" |
15 | #include "controls.h" |
16 | #include "crosshairs.h" |
17 | #include "cheats.h" |
18 | #include "display.h" |
19 | #include "conffile.h" |
20 | #ifdef NETPLAY_SUPPORT |
21 | #include "netplay.h" |
22 | #endif |
23 | |
24 | #ifdef DEBUGGER |
25 | #include "debug.h" |
26 | extern FILE *trace; |
27 | #endif |
28 | |
29 | #define S9X_CONF_FILE_NAME "snes9x.conf" |
30 | |
31 | static char *rom_filename = NULL; |
32 | |
33 | static bool parse_controller_spec (int, const char *); |
34 | static void parse_crosshair_spec (enum crosscontrols, const char *); |
35 | static bool try_load_config_file (const char *, ConfigFile &); |
36 | |
37 | |
38 | static bool parse_controller_spec (int port, const char *arg) |
39 | { |
40 | if (!strcasecmp(arg, "none" )) |
41 | S9xSetController(port, CTL_NONE, 0, 0, 0, 0); |
42 | else |
43 | if (!strncasecmp(arg, "pad" , 3) && arg[3] >= '1' && arg[3] <= '8' && arg[4] == '\0') |
44 | S9xSetController(port, CTL_JOYPAD, arg[3] - '1', 0, 0, 0); |
45 | else |
46 | if (!strncasecmp(arg, "mouse" , 5) && arg[5] >= '1' && arg[5] <= '2' && arg[6] == '\0') |
47 | S9xSetController(port, CTL_MOUSE, arg[5] - '1', 0, 0, 0); |
48 | else |
49 | if (!strcasecmp(arg, "superscope" )) |
50 | S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0); |
51 | else |
52 | if (!strcasecmp(arg, "justifier" )) |
53 | S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0); |
54 | else |
55 | if (!strcasecmp(arg, "two-justifiers" )) |
56 | S9xSetController(port, CTL_JUSTIFIER, 1, 0, 0, 0); |
57 | else |
58 | if (!strcasecmp(arg, "macsrifle" )) |
59 | S9xSetController(port, CTL_MACSRIFLE, 0, 0, 0, 0); |
60 | else |
61 | if (!strncasecmp(arg, "mp5:" , 4) && ((arg[4] >= '1' && arg[4] <= '8') || arg[4] == 'n') && |
62 | ((arg[5] >= '1' && arg[5] <= '8') || arg[5] == 'n') && |
63 | ((arg[6] >= '1' && arg[6] <= '8') || arg[6] == 'n') && |
64 | ((arg[7] >= '1' && arg[7] <= '8') || arg[7] == 'n') && arg[8] == '\0') |
65 | S9xSetController(port, CTL_MP5, (arg[4] == 'n') ? -1 : arg[4] - '1', |
66 | (arg[5] == 'n') ? -1 : arg[5] - '1', |
67 | (arg[6] == 'n') ? -1 : arg[6] - '1', |
68 | (arg[7] == 'n') ? -1 : arg[7] - '1'); |
69 | else |
70 | return (false); |
71 | |
72 | return (true); |
73 | } |
74 | |
75 | static void parse_crosshair_spec (enum crosscontrols ctl, const char *spec) |
76 | { |
77 | int idx = -1, i; |
78 | const char *fg = NULL, *bg = NULL, *s = spec; |
79 | |
80 | if (s[0] == '"') |
81 | { |
82 | s++; |
83 | for (i = 0; s[i] != '\0'; i++) |
84 | if (s[i] == '"' && s[i - 1] != '\\') |
85 | break; |
86 | |
87 | idx = 31 - ctl; |
88 | |
89 | std::string fname(s, i); |
90 | if (!S9xLoadCrosshairFile(idx, fname.c_str())) |
91 | return; |
92 | |
93 | s += i + 1; |
94 | } |
95 | else |
96 | { |
97 | if (isdigit(*s)) |
98 | { |
99 | idx = *s - '0'; |
100 | s++; |
101 | } |
102 | |
103 | if (isdigit(*s)) |
104 | { |
105 | idx = idx * 10 + *s - '0'; |
106 | s++; |
107 | } |
108 | |
109 | if (idx > 31) |
110 | { |
111 | fprintf(stderr, "Invalid crosshair spec '%s'.\n" , spec); |
112 | return; |
113 | } |
114 | } |
115 | |
116 | while (*s != '\0' && isspace(*s)) |
117 | s++; |
118 | |
119 | if (*s != '\0') |
120 | { |
121 | fg = s; |
122 | |
123 | while (isalnum(*s)) |
124 | s++; |
125 | |
126 | if (*s != '/' || !isalnum(s[1])) |
127 | { |
128 | fprintf(stderr, "Invalid crosshair spec '%s.'\n" , spec); |
129 | return; |
130 | } |
131 | |
132 | bg = ++s; |
133 | |
134 | while (isalnum(*s)) |
135 | s++; |
136 | |
137 | if (*s != '\0') |
138 | { |
139 | fprintf(stderr, "Invalid crosshair spec '%s'.\n" , spec); |
140 | return; |
141 | } |
142 | } |
143 | |
144 | S9xSetControllerCrosshair(ctl, idx, fg, bg); |
145 | } |
146 | |
147 | static bool try_load_config_file (const char *fname, ConfigFile &conf) |
148 | { |
149 | FSTREAM fp; |
150 | |
151 | fp = OPEN_FSTREAM(fname, "r" ); |
152 | if (fp) |
153 | { |
154 | fprintf(stdout, "Reading config file %s.\n" , fname); |
155 | fStream fS(fp); |
156 | conf.LoadFile(&fS); |
157 | CLOSE_FSTREAM(fp); |
158 | return (true); |
159 | } |
160 | |
161 | return (false); |
162 | } |
163 | |
164 | void S9xLoadConfigFiles (char **argv, int argc) |
165 | { |
166 | static ConfigFile conf; // static because some of its functions return pointers |
167 | conf.Clear(); |
168 | |
169 | bool skip = false; |
170 | for (int i = 0; i < argc; i++) |
171 | { |
172 | if (!strcasecmp(argv[i], "-nostdconf" )) |
173 | { |
174 | skip = true; |
175 | break; |
176 | } |
177 | } |
178 | |
179 | if (!skip) |
180 | { |
181 | #ifdef SYS_CONFIG_FILE |
182 | try_load_config_file(SYS_CONFIG_FILE, conf); |
183 | S9xParsePortConfig(conf, 0); |
184 | #endif |
185 | |
186 | std::string fname; |
187 | |
188 | fname = S9xGetDirectory(DEFAULT_DIR); |
189 | fname += SLASH_STR S9X_CONF_FILE_NAME; |
190 | try_load_config_file(fname.c_str(), conf); |
191 | } |
192 | else |
193 | fprintf(stderr, "Skipping standard config files.\n" ); |
194 | |
195 | for (int i = 0; i < argc - 1; i++) |
196 | if (!strcasecmp(argv[i], "-conf" )) |
197 | try_load_config_file(argv[++i], conf); |
198 | |
199 | // Parse config file here |
200 | |
201 | // ROM |
202 | |
203 | Settings.ForceInterleaved2 = conf.GetBool("ROM::Interleaved2" , false); |
204 | Settings.ForceInterleaveGD24 = conf.GetBool("ROM::InterleaveGD24" , false); |
205 | Settings.ApplyCheats = conf.GetBool("ROM::Cheat" , false); |
206 | Cheat.enabled = false; |
207 | Settings.NoPatch = !conf.GetBool("ROM::Patch" , true); |
208 | Settings.IgnorePatchChecksum = conf.GetBool("ROM::IgnorePatchChecksum" , false); |
209 | |
210 | Settings.ForceLoROM = conf.GetBool("ROM::LoROM" , false); |
211 | Settings.ForceHiROM = conf.GetBool("ROM::HiROM" , false); |
212 | if (Settings.ForceLoROM) |
213 | Settings.ForceHiROM = false; |
214 | |
215 | Settings.ForcePAL = conf.GetBool("ROM::PAL" , false); |
216 | Settings.ForceNTSC = conf.GetBool("ROM::NTSC" , false); |
217 | if (Settings.ForcePAL) |
218 | Settings.ForceNTSC = false; |
219 | |
220 | if (conf.Exists("ROM::Header" )) |
221 | { |
222 | Settings.ForceHeader = conf.GetBool("ROM::Header" , false); |
223 | Settings.ForceNoHeader = !Settings.ForceHeader; |
224 | } |
225 | |
226 | if (conf.Exists("ROM::Interleaved" )) |
227 | { |
228 | Settings.ForceInterleaved = conf.GetBool("ROM::Interleaved" , false); |
229 | Settings.ForceNotInterleaved = !Settings.ForceInterleaved; |
230 | } |
231 | |
232 | rom_filename = conf.GetStringDup("ROM::Filename" , NULL); |
233 | Settings.InitialSnapshotFilename[0] = '\0'; |
234 | |
235 | // Sound |
236 | |
237 | Settings.SoundSync = conf.GetBool("Sound::Sync" , false); |
238 | Settings.SixteenBitSound = conf.GetBool("Sound::16BitSound" , true); |
239 | Settings.Stereo = conf.GetBool("Sound::Stereo" , true); |
240 | Settings.ReverseStereo = conf.GetBool("Sound::ReverseStereo" , false); |
241 | Settings.SoundPlaybackRate = conf.GetUInt("Sound::Rate" , 48000); |
242 | Settings.SoundInputRate = conf.GetUInt("Sound::InputRate" , 31950); |
243 | Settings.Mute = conf.GetBool("Sound::Mute" , false); |
244 | Settings.DynamicRateControl = conf.GetBool("Sound::DynamicRateControl" , false); |
245 | Settings.DynamicRateLimit = conf.GetInt ("Sound::DynamicRateLimit" , 5); |
246 | Settings.InterpolationMethod = conf.GetInt ("Sound::InterpolationMethod" , 2); |
247 | |
248 | // Display |
249 | |
250 | Settings.SupportHiRes = conf.GetBool("Display::HiRes" , true); |
251 | Settings.Transparency = conf.GetBool("Display::Transparency" , true); |
252 | Settings.DisableGraphicWindows = !conf.GetBool("Display::GraphicWindows" , true); |
253 | Settings.DisplayTime = conf.GetBool("Display::DisplayTime" , false); |
254 | Settings.DisplayFrameRate = conf.GetBool("Display::DisplayFrameRate" , false); |
255 | Settings.DisplayWatchedAddresses = conf.GetBool("Display::DisplayWatchedAddresses" , false); |
256 | Settings.DisplayPressedKeys = conf.GetBool("Display::DisplayInput" , false); |
257 | Settings.DisplayMovieFrame = conf.GetBool("Display::DisplayFrameCount" , false); |
258 | Settings.AutoDisplayMessages = conf.GetBool("Display::MessagesInImage" , true); |
259 | Settings.InitialInfoStringTimeout = conf.GetInt ("Display::MessageDisplayTime" , 120); |
260 | Settings.BilinearFilter = conf.GetBool("Display::BilinearFilter" , false); |
261 | |
262 | // Settings |
263 | |
264 | Settings.BSXBootup = conf.GetBool("Settings::BSXBootup" , false); |
265 | Settings.TurboMode = conf.GetBool("Settings::TurboMode" , false); |
266 | Settings.TurboSkipFrames = conf.GetUInt("Settings::TurboFrameSkip" , 15); |
267 | Settings.MovieTruncate = conf.GetBool("Settings::MovieTruncateAtEnd" , false); |
268 | Settings.MovieNotifyIgnored = conf.GetBool("Settings::MovieNotifyIgnored" , false); |
269 | Settings.WrongMovieStateProtection = conf.GetBool("Settings::WrongMovieStateProtection" , true); |
270 | Settings.StretchScreenshots = conf.GetInt ("Settings::StretchScreenshots" , 1); |
271 | Settings.SnapshotScreenshots = conf.GetBool("Settings::SnapshotScreenshots" , true); |
272 | Settings.DontSaveOopsSnapshot = conf.GetBool("Settings::DontSaveOopsSnapshot" , false); |
273 | Settings.AutoSaveDelay = conf.GetUInt("Settings::AutoSaveDelay" , 0); |
274 | |
275 | if (conf.Exists("Settings::FrameTime" )) |
276 | Settings.FrameTimePAL = Settings.FrameTimeNTSC = conf.GetUInt("Settings::FrameTime" , 16667); |
277 | |
278 | if (!strcasecmp(conf.GetString("Settings::FrameSkip" , "Auto" ), "Auto" )) |
279 | Settings.SkipFrames = AUTO_FRAMERATE; |
280 | else |
281 | Settings.SkipFrames = conf.GetUInt("Settings::FrameSkip" , 0) + 1; |
282 | |
283 | // Controls |
284 | |
285 | Settings.MouseMaster = conf.GetBool("Controls::MouseMaster" , true); |
286 | Settings.SuperScopeMaster = conf.GetBool("Controls::SuperscopeMaster" , true); |
287 | Settings.JustifierMaster = conf.GetBool("Controls::JustifierMaster" , true); |
288 | Settings.MacsRifleMaster = conf.GetBool("Controls::MacsRifleMaster" , true); |
289 | Settings.MultiPlayer5Master = conf.GetBool("Controls::MP5Master" , true); |
290 | Settings.UpAndDown = conf.GetBool("Controls::AllowLeftRight" , false); |
291 | |
292 | if (conf.Exists("Controls::Port1" )) |
293 | parse_controller_spec(0, conf.GetString("Controls::Port1" )); |
294 | if (conf.Exists("Controls::Port2" )) |
295 | parse_controller_spec(1, conf.GetString("Controls::Port2" )); |
296 | |
297 | if (conf.Exists("Controls::Mouse1Crosshair" )) |
298 | parse_crosshair_spec(X_MOUSE1, conf.GetString("Controls::Mouse1Crosshair" )); |
299 | if (conf.Exists("Controls::Mouse2Crosshair" )) |
300 | parse_crosshair_spec(X_MOUSE2, conf.GetString("Controls::Mouse2Crosshair" )); |
301 | if (conf.Exists("Controls::SuperscopeCrosshair" )) |
302 | parse_crosshair_spec(X_SUPERSCOPE, conf.GetString("Controls::SuperscopeCrosshair" )); |
303 | if (conf.Exists("Controls::Justifier1Crosshair" )) |
304 | parse_crosshair_spec(X_JUSTIFIER1, conf.GetString("Controls::Justifier1Crosshair" )); |
305 | if (conf.Exists("Controls::Justifier2Crosshair" )) |
306 | parse_crosshair_spec(X_JUSTIFIER2, conf.GetString("Controls::Justifier2Crosshair" )); |
307 | if (conf.Exists("Controls::MacsRifleCrosshair" )) |
308 | parse_crosshair_spec(X_MACSRIFLE, conf.GetString("Controls::MacsRifleCrosshair" )); |
309 | |
310 | // Hack |
311 | Settings.SuperFXClockMultiplier = conf.GetUInt("Hack::SuperFXClockMultiplier" , 100); |
312 | Settings.OverclockMode = conf.GetUInt("Hack::OverclockMode" , 0); |
313 | Settings.SeparateEchoBuffer = conf.GetBool("Hack::SeparateEchoBuffer" , false); |
314 | Settings.DisableGameSpecificHacks = !conf.GetBool("Hack::EnableGameSpecificHacks" , true); |
315 | Settings.BlockInvalidVRAMAccessMaster = !conf.GetBool("Hack::AllowInvalidVRAMAccess" , false); |
316 | Settings.HDMATimingHack = conf.GetInt ("Hack::HDMATiming" , 100); |
317 | Settings.MaxSpriteTilesPerLine = conf.GetInt ("Hack::MaxSpriteTilesPerLine" , 34); |
318 | |
319 | // Netplay |
320 | |
321 | #ifdef NETPLAY_SUPPORT |
322 | Settings.NetPlay = conf.GetBool("Netplay::Enable" ); |
323 | |
324 | Settings.Port = NP_DEFAULT_PORT; |
325 | if (conf.Exists("Netplay::Port" )) |
326 | Settings.Port = -(int) conf.GetUInt("Netplay::Port" ); |
327 | |
328 | Settings.ServerName[0] = '\0'; |
329 | if (conf.Exists("Netplay::Server" )) |
330 | conf.GetString("Netplay::Server" , Settings.ServerName, 128); |
331 | #endif |
332 | |
333 | // Debug |
334 | |
335 | #ifdef DEBUGGER |
336 | if (conf.GetBool("DEBUG::Debugger" , false)) |
337 | CPU.Flags |= DEBUG_MODE_FLAG; |
338 | |
339 | if (conf.GetBool("DEBUG::Trace" , false)) |
340 | { |
341 | ENSURE_TRACE_OPEN(trace,"trace.log" ,"wb" ) |
342 | CPU.Flags |= TRACE_FLAG; |
343 | } |
344 | Settings.TraceSMP = FALSE; |
345 | #endif |
346 | |
347 | S9xParsePortConfig(conf, 1); |
348 | S9xVerifyControllers(); |
349 | } |
350 | |
351 | void S9xUsage (void) |
352 | { |
353 | /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */ |
354 | |
355 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
356 | S9xMessage(S9X_INFO, S9X_USAGE, "Snes9x " VERSION); |
357 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
358 | S9xMessage(S9X_INFO, S9X_USAGE, "usage: snes9x [options] <ROM image filename>" ); |
359 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
360 | |
361 | // SOUND OPTIONS |
362 | S9xMessage(S9X_INFO, S9X_USAGE, "-soundsync Synchronize sound as far as possible" ); |
363 | S9xMessage(S9X_INFO, S9X_USAGE, "-playbackrate <Hz> Set sound playback rate" ); |
364 | S9xMessage(S9X_INFO, S9X_USAGE, "-inputrate <Hz> Set sound input rate" ); |
365 | S9xMessage(S9X_INFO, S9X_USAGE, "-reversestereo Reverse stereo sound output" ); |
366 | S9xMessage(S9X_INFO, S9X_USAGE, "-nostereo Disable stereo sound output" ); |
367 | S9xMessage(S9X_INFO, S9X_USAGE, "-eightbit Use 8bit sound instead of 16bit" ); |
368 | S9xMessage(S9X_INFO, S9X_USAGE, "-mute Mute sound" ); |
369 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
370 | |
371 | // DISPLAY OPTIONS |
372 | S9xMessage(S9X_INFO, S9X_USAGE, "-displaytime Display the time" ); |
373 | S9xMessage(S9X_INFO, S9X_USAGE, "-displayframerate Display the frame rate counter" ); |
374 | S9xMessage(S9X_INFO, S9X_USAGE, "-displaykeypress Display input of all controllers and peripherals" ); |
375 | S9xMessage(S9X_INFO, S9X_USAGE, "-nohires (Not recommended) Disable support for hi-res and" ); |
376 | S9xMessage(S9X_INFO, S9X_USAGE, " interlace modes" ); |
377 | S9xMessage(S9X_INFO, S9X_USAGE, "-notransparency (Not recommended) Disable transparency effects" ); |
378 | S9xMessage(S9X_INFO, S9X_USAGE, "-nowindows (Not recommended) Disable graphic window effects" ); |
379 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
380 | |
381 | // CONTROLLER OPTIONS |
382 | S9xMessage(S9X_INFO, S9X_USAGE, "-nomp5 Disable emulation of the Multiplayer 5 adapter" ); |
383 | S9xMessage(S9X_INFO, S9X_USAGE, "-nomouse Disable emulation of the SNES mouse" ); |
384 | S9xMessage(S9X_INFO, S9X_USAGE, "-nosuperscope Disable emulation of the Superscope" ); |
385 | S9xMessage(S9X_INFO, S9X_USAGE, "-nojustifier Disable emulation of the Konami Justifier" ); |
386 | S9xMessage(S9X_INFO, S9X_USAGE, "-nomacsrifle Disable emulation of the M.A.C.S. Rifle" ); |
387 | S9xMessage(S9X_INFO, S9X_USAGE, "-port# <control> Specify which controller to emulate in port 1/2" ); |
388 | S9xMessage(S9X_INFO, S9X_USAGE, " Controllers: none No controller" ); |
389 | S9xMessage(S9X_INFO, S9X_USAGE, " pad# Joypad number 1-8" ); |
390 | S9xMessage(S9X_INFO, S9X_USAGE, " mouse# Mouse number 1-2" ); |
391 | S9xMessage(S9X_INFO, S9X_USAGE, " superscope Superscope (not useful with -port1)" ); |
392 | S9xMessage(S9X_INFO, S9X_USAGE, " justifier Blue Justifier (not useful with -port1)" ); |
393 | S9xMessage(S9X_INFO, S9X_USAGE, " two-justifiers Blue & Pink Justifiers" ); |
394 | S9xMessage(S9X_INFO, S9X_USAGE, " mp5:#### MP5 with the 4 named pads (1-8 or n)" ); |
395 | S9xMessage(S9X_INFO, S9X_USAGE, " macsrifle M.A.C.S. Rifle" ); |
396 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
397 | |
398 | // ROM OPTIONS |
399 | S9xMessage(S9X_INFO, S9X_USAGE, "-hirom Force Hi-ROM memory map" ); |
400 | S9xMessage(S9X_INFO, S9X_USAGE, "-lorom Force Lo-ROM memory map" ); |
401 | S9xMessage(S9X_INFO, S9X_USAGE, "-ntsc Force NTSC timing (60 frames/sec)" ); |
402 | S9xMessage(S9X_INFO, S9X_USAGE, "-pal Force PAL timing (50 frames/sec)" ); |
403 | S9xMessage(S9X_INFO, S9X_USAGE, "-nointerleave Assume the ROM image is not in interleaved" ); |
404 | S9xMessage(S9X_INFO, S9X_USAGE, " format" ); |
405 | S9xMessage(S9X_INFO, S9X_USAGE, "-interleaved Assume the ROM image is in interleaved format" ); |
406 | S9xMessage(S9X_INFO, S9X_USAGE, "-interleaved2 Assume the ROM image is in interleaved 2 format" ); |
407 | S9xMessage(S9X_INFO, S9X_USAGE, "-interleavedgd24 Assume the ROM image is in interleaved gd24" ); |
408 | S9xMessage(S9X_INFO, S9X_USAGE, " format" ); |
409 | S9xMessage(S9X_INFO, S9X_USAGE, "-noheader Assume the ROM image doesn't have a header of a" ); |
410 | S9xMessage(S9X_INFO, S9X_USAGE, " copier" ); |
411 | S9xMessage(S9X_INFO, S9X_USAGE, "-header Assume the ROM image has a header of a copier" ); |
412 | S9xMessage(S9X_INFO, S9X_USAGE, "-bsxbootup Boot up BS games from BS-X" ); |
413 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
414 | |
415 | // PATCH/CHEAT OPTIONS |
416 | S9xMessage(S9X_INFO, S9X_USAGE, "-nopatch Do not apply any available IPS/UPS patches" ); |
417 | S9xMessage(S9X_INFO, S9X_USAGE, "-cheat Apply saved cheats" ); |
418 | S9xMessage(S9X_INFO, S9X_USAGE, "-cheatcode <code> Supply a cheat code in Game Genie," ); |
419 | S9xMessage(S9X_INFO, S9X_USAGE, " Pro-Action Replay, or Raw format (address=byte)" ); |
420 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
421 | |
422 | #ifdef NETPLAY_SUPPORT |
423 | // NETPLAY OPTIONS |
424 | S9xMessage(S9X_INFO, S9X_USAGE, "-net Enable netplay" ); |
425 | S9xMessage(S9X_INFO, S9X_USAGE, "-port <num> Use port <num> for netplay (use with -net)" ); |
426 | S9xMessage(S9X_INFO, S9X_USAGE, "-server <string> Use the specified server for netplay" ); |
427 | S9xMessage(S9X_INFO, S9X_USAGE, " (use with -net)" ); |
428 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
429 | #endif |
430 | |
431 | // HACKING OR DEBUGGING OPTIONS |
432 | #ifdef DEBUGGER |
433 | S9xMessage(S9X_INFO, S9X_USAGE, "-debug Set the Debugger flag" ); |
434 | S9xMessage(S9X_INFO, S9X_USAGE, "-trace Begin CPU instruction tracing" ); |
435 | #endif |
436 | S9xMessage(S9X_INFO, S9X_USAGE, "-hdmatiming <1-199> (Not recommended) Changes HDMA transfer timings" ); |
437 | S9xMessage(S9X_INFO, S9X_USAGE, " event comes" ); |
438 | S9xMessage(S9X_INFO, S9X_USAGE, "-invalidvramaccess (Not recommended) Allow invalid VRAM access" ); |
439 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
440 | |
441 | // OTHER OPTIONS |
442 | S9xMessage(S9X_INFO, S9X_USAGE, "-frameskip <num> Screen update frame skip rate" ); |
443 | S9xMessage(S9X_INFO, S9X_USAGE, "-frametime <num> Milliseconds per frame for frameskip auto-adjust" ); |
444 | S9xMessage(S9X_INFO, S9X_USAGE, "-upanddown Override protection from pressing left+right or" ); |
445 | S9xMessage(S9X_INFO, S9X_USAGE, " up+down together" ); |
446 | S9xMessage(S9X_INFO, S9X_USAGE, "-conf <filename> Use specified conf file (after standard files)" ); |
447 | S9xMessage(S9X_INFO, S9X_USAGE, "-nostdconf Do not load the standard config files" ); |
448 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
449 | |
450 | S9xExtraUsage(); |
451 | |
452 | S9xMessage(S9X_INFO, S9X_USAGE, "" ); |
453 | S9xMessage(S9X_INFO, S9X_USAGE, "ROM image can be compressed with zip, gzip, JMA, or compress." ); |
454 | |
455 | exit(1); |
456 | } |
457 | |
458 | void S9xParseArgsForCheats (char **argv, int argc) |
459 | { |
460 | for (int i = 1; i < argc; i++) |
461 | { |
462 | if (!strcasecmp(argv[i], "-gamegenie" ) || |
463 | !strcasecmp(argv[i], "-actionreplay" ) || |
464 | !strcasecmp(argv[i], "-cheatcode" )) |
465 | { |
466 | if (i + 1 < argc) |
467 | { |
468 | if (S9xAddCheatGroup ("Unknown" , argv[++i]) < 0) |
469 | { |
470 | S9xMessage(S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, "Code format invalid" ); |
471 | } |
472 | else |
473 | { |
474 | S9xEnableCheatGroup (Cheat.g.size() - 1); |
475 | } |
476 | } |
477 | else |
478 | S9xUsage(); |
479 | } |
480 | } |
481 | } |
482 | |
483 | char * S9xParseArgs (char **argv, int argc) |
484 | { |
485 | for (int i = 1; i < argc; i++) |
486 | { |
487 | if (*argv[i] == '-') |
488 | { |
489 | if (!strcasecmp(argv[i], "-help" )) |
490 | S9xUsage(); |
491 | else |
492 | |
493 | // SOUND OPTIONS |
494 | |
495 | if (!strcasecmp(argv[i], "-soundsync" )) |
496 | Settings.SoundSync = TRUE; |
497 | else if (!strcasecmp(argv[i], "-dynamicratecontrol" )) |
498 | { |
499 | Settings.DynamicRateControl = TRUE; |
500 | Settings.DynamicRateLimit = 5; |
501 | } |
502 | else |
503 | if (!strcasecmp(argv[i], "-playbackrate" )) |
504 | { |
505 | if (i + 1 < argc) |
506 | { |
507 | Settings.SoundPlaybackRate = atoi(argv[++i]); |
508 | if (Settings.SoundPlaybackRate < 8192) |
509 | Settings.SoundPlaybackRate = 8192; |
510 | } |
511 | else |
512 | S9xUsage(); |
513 | } |
514 | else |
515 | if (!strcasecmp(argv[i], "-inputrate" )) |
516 | { |
517 | if (i + 1 < argc) |
518 | { |
519 | Settings.SoundInputRate = atoi(argv[++i]); |
520 | if (Settings.SoundInputRate < 31700) |
521 | Settings.SoundInputRate = 31700; |
522 | if (Settings.SoundInputRate > 32300) |
523 | Settings.SoundInputRate = 32300; |
524 | } |
525 | else |
526 | S9xUsage(); |
527 | } |
528 | else |
529 | if (!strcasecmp(argv[i], "-reversestereo" )) |
530 | Settings.ReverseStereo = TRUE; |
531 | else |
532 | if (!strcasecmp(argv[i], "-nostereo" )) |
533 | Settings.Stereo = FALSE; |
534 | else |
535 | if (!strcasecmp(argv[i], "-eightbit" )) |
536 | Settings.SixteenBitSound = FALSE; |
537 | else |
538 | if (!strcasecmp(argv[i], "-mute" )) |
539 | Settings.Mute = TRUE; |
540 | else |
541 | |
542 | // DISPLAY OPTIONS |
543 | |
544 | if (!strcasecmp(argv[i], "-displaytime" )) |
545 | Settings.DisplayTime = TRUE; |
546 | else |
547 | if (!strcasecmp(argv[i], "-displayframerate" )) |
548 | Settings.DisplayFrameRate = TRUE; |
549 | else |
550 | if (!strcasecmp(argv[i], "-displaykeypress" )) |
551 | Settings.DisplayPressedKeys = TRUE; |
552 | else |
553 | if (!strcasecmp(argv[i], "-nohires" )) |
554 | Settings.SupportHiRes = FALSE; |
555 | else |
556 | if (!strcasecmp(argv[i], "-notransparency" )) |
557 | Settings.Transparency = FALSE; |
558 | else |
559 | if (!strcasecmp(argv[i], "-nowindows" )) |
560 | Settings.DisableGraphicWindows = TRUE; |
561 | else |
562 | |
563 | // CONTROLLER OPTIONS |
564 | |
565 | if (!strcasecmp(argv[i], "-nomp5" )) |
566 | Settings.MultiPlayer5Master = FALSE; |
567 | else |
568 | if (!strcasecmp(argv[i], "-nomouse" )) |
569 | Settings.MouseMaster = FALSE; |
570 | else |
571 | if (!strcasecmp(argv[i], "-nosuperscope" )) |
572 | Settings.SuperScopeMaster = FALSE; |
573 | else |
574 | if (!strcasecmp(argv[i], "-nojustifier" )) |
575 | Settings.JustifierMaster = FALSE; |
576 | else |
577 | if (!strcasecmp(argv[i], "-nomacsrifle" )) |
578 | Settings.MacsRifleMaster = FALSE; |
579 | else |
580 | if (!strcasecmp(argv[i], "-port1" ) || |
581 | !strcasecmp(argv[i], "-port2" )) |
582 | { |
583 | if (i + 1 < argc) |
584 | { |
585 | i++; |
586 | if (!parse_controller_spec(argv[i - 1][5] - '1', argv[i])) |
587 | S9xUsage(); |
588 | } |
589 | else |
590 | S9xUsage(); |
591 | } |
592 | else |
593 | |
594 | // ROM OPTIONS |
595 | |
596 | if (!strcasecmp(argv[i], "-hirom" )) |
597 | Settings.ForceHiROM = TRUE; |
598 | else |
599 | if (!strcasecmp(argv[i], "-lorom" )) |
600 | Settings.ForceLoROM = TRUE; |
601 | else |
602 | if (!strcasecmp(argv[i], "-ntsc" )) |
603 | Settings.ForceNTSC = TRUE; |
604 | else |
605 | if (!strcasecmp(argv[i], "-pal" )) |
606 | Settings.ForcePAL = TRUE; |
607 | else |
608 | if (!strcasecmp(argv[i], "-nointerleave" )) |
609 | Settings.ForceNotInterleaved = TRUE; |
610 | else |
611 | if (!strcasecmp(argv[i], "-interleaved" )) |
612 | Settings.ForceInterleaved = TRUE; |
613 | else |
614 | if (!strcasecmp(argv[i], "-interleaved2" )) |
615 | Settings.ForceInterleaved2 = TRUE; |
616 | else |
617 | if (!strcasecmp(argv[i], "-interleavedgd24" )) |
618 | Settings.ForceInterleaveGD24 = TRUE; |
619 | else |
620 | if (!strcasecmp(argv[i], "-noheader" )) |
621 | Settings.ForceNoHeader = TRUE; |
622 | else |
623 | if (!strcasecmp(argv[i], "-header" )) |
624 | Settings.ForceHeader = TRUE; |
625 | else |
626 | if (!strcasecmp(argv[i], "-bsxbootup" )) |
627 | Settings.BSXBootup = TRUE; |
628 | else |
629 | if (!strcasecmp(argv[i], "-snapshot" )) |
630 | { |
631 | if (i + 1 < argc) |
632 | { |
633 | strncpy(Settings.InitialSnapshotFilename, argv[++i], PATH_MAX); |
634 | Settings.InitialSnapshotFilename[PATH_MAX] = 0; |
635 | } |
636 | else |
637 | S9xUsage(); |
638 | } |
639 | else |
640 | |
641 | // PATCH/CHEAT OPTIONS |
642 | |
643 | if (!strcasecmp(argv[i], "-nopatch" )) |
644 | Settings.NoPatch = TRUE; |
645 | else |
646 | if (!strcasecmp(argv[i], "-cheat" )) |
647 | Settings.ApplyCheats = TRUE; |
648 | else |
649 | if (!strcasecmp(argv[i], "-gamegenie" ) || |
650 | !strcasecmp(argv[i], "-actionreplay" ) || |
651 | !strcasecmp(argv[i], "-cheatcode" )) |
652 | { |
653 | if (i + 1 < argc) |
654 | { |
655 | if (S9xAddCheatGroup ("Unknown" , argv[++i]) < 0) |
656 | { |
657 | S9xMessage(S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, "Code format invalid" ); |
658 | } |
659 | else |
660 | { |
661 | S9xEnableCheatGroup (Cheat.g.size() - 1); |
662 | } |
663 | } |
664 | else |
665 | S9xUsage(); |
666 | } |
667 | else |
668 | // NETPLAY OPTIONS |
669 | |
670 | #ifdef NETPLAY_SUPPORT |
671 | if (!strcasecmp(argv[i], "-net" )) |
672 | Settings.NetPlay = TRUE; |
673 | else |
674 | if (!strcasecmp(argv[i], "-port" )) |
675 | { |
676 | if (i + 1 < argc) |
677 | Settings.Port = -atoi(argv[++i]); |
678 | else |
679 | S9xUsage(); |
680 | } |
681 | else |
682 | if (!strcasecmp(argv[i], "-server" )) |
683 | { |
684 | if (i + 1 < argc) |
685 | { |
686 | strncpy(Settings.ServerName, argv[++i], 127); |
687 | Settings.ServerName[127] = 0; |
688 | } |
689 | else |
690 | S9xUsage(); |
691 | } |
692 | else |
693 | #endif |
694 | |
695 | // HACKING OR DEBUGGING OPTIONS |
696 | |
697 | #ifdef DEBUGGER |
698 | if (!strcasecmp(argv[i], "-debug" )) |
699 | CPU.Flags |= DEBUG_MODE_FLAG; |
700 | else |
701 | if (!strcasecmp(argv[i], "-trace" )) |
702 | { |
703 | ENSURE_TRACE_OPEN(trace,"trace.log" ,"wb" ) |
704 | CPU.Flags |= TRACE_FLAG; |
705 | } |
706 | else |
707 | #endif |
708 | |
709 | if (!strcasecmp(argv[i], "-hdmatiming" )) |
710 | { |
711 | if (i + 1 < argc) |
712 | { |
713 | int p = atoi(argv[++i]); |
714 | if (p > 0 && p < 200) |
715 | Settings.HDMATimingHack = p; |
716 | } |
717 | else |
718 | S9xUsage(); |
719 | } |
720 | else |
721 | if (!strcasecmp(argv[i], "-invalidvramaccess" )) |
722 | Settings.BlockInvalidVRAMAccessMaster = FALSE; |
723 | else |
724 | |
725 | // OTHER OPTIONS |
726 | |
727 | if (!strcasecmp(argv[i], "-frameskip" )) |
728 | { |
729 | if (i + 1 < argc) |
730 | Settings.SkipFrames = atoi(argv[++i]) + 1; |
731 | else |
732 | S9xUsage(); |
733 | } |
734 | else |
735 | if (!strcasecmp(argv[i], "-frametime" )) |
736 | { |
737 | if (i + 1 < argc) |
738 | Settings.FrameTimePAL = Settings.FrameTimeNTSC = atoi(argv[++i]); |
739 | else |
740 | S9xUsage(); |
741 | } |
742 | else |
743 | if (!strcasecmp(argv[i], "-upanddown" )) |
744 | Settings.UpAndDown = TRUE; |
745 | else |
746 | if (!strcasecmp(argv[i], "-conf" )) |
747 | { |
748 | if (++i >= argc) |
749 | S9xUsage(); |
750 | // Else do nothing, S9xLoadConfigFiles() handled it. |
751 | } |
752 | else |
753 | if (!strcasecmp(argv[i], "-nostdconf" )) |
754 | { |
755 | // Do nothing, S9xLoadConfigFiles() handled it. |
756 | } |
757 | else |
758 | S9xParseArg(argv, i, argc); |
759 | } |
760 | else |
761 | rom_filename = argv[i]; |
762 | } |
763 | |
764 | S9xVerifyControllers(); |
765 | |
766 | return (rom_filename); |
767 | } |
768 | |