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"
26extern FILE *trace;
27#endif
28
29#define S9X_CONF_FILE_NAME "snes9x.conf"
30
31static char *rom_filename = NULL;
32
33static bool parse_controller_spec (int, const char *);
34static void parse_crosshair_spec (enum crosscontrols, const char *);
35static bool try_load_config_file (const char *, ConfigFile &);
36
37
38static 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
75static 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
147static 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
164void 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
351void 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
458void 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
483char * 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