#include "port.h"
#include "snes9x.h"
#include "display.h"
+#include "hgw.h"
#define DIE(format, ...) do { \
fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
struct config Config;
-static const struct poptOption optionsTable[] = {
+/** Path to current rom file, with extension. */
+static char * romFile;
+/** Path to rom file, without extension.
+ * Used as a simple optimization to S9xGetFilename
+ */
+static char * basePath;
+
+static struct poptOption commonOptionsTable[] = {
{ "disable-audio", 'a', POPT_ARG_NONE, 0, 1,
"disable emulation and output of audio", 0 },
{ "display-framerate", 'r', POPT_ARG_NONE, 0, 2,
- "Show frames per second counter in lower left corner", 0 },
+ "show frames per second counter in lower left corner", 0 },
{ "skip-frames", 's', POPT_ARG_INT, 0, 3,
- "Render only 1 in every N frames", "NUM" },
+ "render only 1 in every N frames", "NUM" },
{ "fullscreen", 'f', POPT_ARG_NONE, 0, 4,
- "Start in fullscreen mode", 0 },
+ "start in fullscreen mode", 0 },
{ "transparency", 'y', POPT_ARG_NONE, 0, 5,
- "Enable transparency effects (slower)", 0 },
- { "hacks", 'h', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, 0, 6,
- "Enable hacks (yes, speed-only, no)", "option" },
+ "enable transparency effects (slower)", 0 },
+ { "scaler", 'S', POPT_ARG_STRING, 0, 6,
+ "select scaler to use", 0 },
{ "pal", 'p', POPT_ARG_NONE, 0, 7,
- "Run in PAL mode", 0 },
+ "run in PAL mode", 0 },
{ "ntsc", 'n', POPT_ARG_NONE, 0, 8,
- "Run in NTSC mode", 0 },
+ "run in NTSC mode", 0 },
{ "turbo", 't', POPT_ARG_NONE, 0, 9,
- "Turbo mode (do not try to sleep between frames)", 0 },
+ "turbo mode (do not try to sleep between frames)", 0 },
{ "conf", 'c', POPT_ARG_STRING, 0, 10,
- "Load extra configuration file", "FILE" },
+ "extra configuration file to load", "FILE" },
+ { "mouse", 'm', POPT_ARG_INT | POPT_ARGFLAG_OPTIONAL, 0, 11,
+ "enable mouse on controller NUM", "NUM"},
+ { "superscope", 'e', POPT_ARG_NONE, 0, 12,
+ "enable SuperScope", 0},
+ { "snapshot", 'o', POPT_ARG_NONE, 0, 13,
+ "unfreeze previous game on start and freeze game on exit", 0 },
+ { "audio-rate", 'u', POPT_ARG_INT, 0, 14,
+ "audio output rate", "HZ" },
+ { "audio-buffer-size", 'b', POPT_ARG_INT, 0, 15,
+ "audio output buffer size", "SAMPLES" },
+ { "touchscreen", 'd', POPT_ARG_NONE, 0, 16,
+ "enable touchscreen controls", 0 },
+ { "touchscreen-grid", 'D', POPT_ARG_NONE, 0, 17,
+ "enable touchscreen controls and show grid", 0 },
+ { "hacks", 'h', POPT_ARG_NONE, 0, 18,
+ "enable safe subset of speedhacks", 0 },
+ { "all-hacks", 'H', POPT_ARG_NONE, 0, 19,
+ "enable all speedhacks (may break sound)", 0 },
+ POPT_TABLEEND
+};
+
+static struct poptOption configOptionsTable[] = {
{ "scancode", '\0', POPT_ARG_INT, 0, 100,
- "Scancode to map", "CODE" },
+ "scancode to map", "CODE" },
{ "button", '\0', POPT_ARG_STRING, 0, 101,
"SNES Button to press (A, B, X, Y, L, R, Up, Down, Left, Right)", "name" },
{ "action", '\0', POPT_ARG_STRING, 0, 102,
- "Emulator action to do (fullscreen, quit, ...)", "action" },
+ "emulator action to do (fullscreen, quit, ...)", "action" },
{ "hacks-file", '\0', POPT_ARG_STRING, 0, 200,
- "Path to snesadvance.dat file", "FILE" },
+ "path to snesadvance.dat file", "FILE" },
+ POPT_TABLEEND
+};
+
+static struct poptOption optionsTable[] = {
+ { 0, '\0', POPT_ARG_INCLUDE_TABLE, commonOptionsTable, 0,
+ "Common options", 0 },
+ { 0, '\0', POPT_ARG_INCLUDE_TABLE, configOptionsTable, 0,
+ "Configuration file options", 0 },
POPT_AUTOHELP
POPT_TABLEEND
};
return kActionQuit;
} else if (strcasecmp(s, "fullscreen") == 0) {
return kActionToggleFullscreen;
+ } else if (strcasecmp(s, "quickload1") == 0) {
+ return kActionQuickLoad1;
+ } else if (strcasecmp(s, "quicksave1") == 0) {
+ return kActionQuickSave1;
+ } else if (strcasecmp(s, "quickload2") == 0) {
+ return kActionQuickLoad2;
+ } else if (strcasecmp(s, "quicksave2") == 0) {
+ return kActionQuickSave2;
} else {
DIE("Bad action name: %s\n", s);
}
}
-const char * S9xFiletitle(const char * f)
-{
- if (!f) return 0;
-
- const char * p = strrchr (f, '.');
-
- if (p)
- return p + 1;
-
- return f;
-}
-
-const char * S9xBasename(const char * f)
+const char * S9xGetFilename(FileTypes file)
{
- const char * p = strrchr (f, '/');
-
- if (p)
- return p + 1;
+ static char filename[PATH_MAX + 1];
+ const char * ext;
+ switch (file) {
+ case FILE_ROM:
+ return romFile;
+ case FILE_SRAM:
+ ext = "srm";
+ break;
+ case FILE_FREEZE:
+ ext = "frz.gz";
+ break;
+ case FILE_CHT:
+ ext = "cht";
+ break;
+ case FILE_IPS:
+ ext = "ips";
+ break;
+ case FILE_SCREENSHOT:
+ ext = "png";
+ break;
+ case FILE_SDD1_DAT:
+ ext = "dat";
+ break;
+ default:
+ ext = "???";
+ break;
+ }
- return f;
+ snprintf(filename, PATH_MAX, "%s.%s", basePath, ext);
+ return filename;
}
-const char * S9xGetFilename(const char * ext)
+const char * S9xGetQuickSaveFilename(unsigned int slot)
{
- static char filename [PATH_MAX + 1];
- sprintf(filename, "%s%s", Config.romFile, ext);
-
+ static char filename[PATH_MAX + 1];
+ snprintf(filename, PATH_MAX, "%s.frz.%u.gz", basePath, slot);
return filename;
}
ZeroMemory(&Settings, sizeof(Settings));
ZeroMemory(&Config, sizeof(Config));
+ romFile = 0;
+ basePath = 0;
+
Config.quitting = false;
Config.enableAudio = true;
Config.fullscreen = false;
- Config.xsp = false;
+ Config.scaler = 0;
+ Config.hacksFile = 0;
+ Config.touchscreenInput = false;
+ Config.touchscreenShow = false;
Settings.JoystickEnabled = FALSE;
Settings.SoundPlaybackRate = 22050;
Settings.Stereo = TRUE;
- Settings.SoundBufferSize = 0;
+ Settings.SoundBufferSize = 512; // in samples
Settings.CyclesPercentage = 100;
Settings.DisableSoundEcho = FALSE;
Settings.APUEnabled = FALSE;
Settings.H_Max = SNES_CYCLES_PER_SCANLINE;
Settings.SkipFrames = AUTO_FRAMERATE;
Settings.Shutdown = Settings.ShutdownMaster = TRUE;
- Settings.FrameTimePAL = 20000; // in usecs
- Settings.FrameTimeNTSC = 16667;
+ Settings.FrameTimePAL = 20; // in msecs
+ Settings.FrameTimeNTSC = 16;
Settings.FrameTime = Settings.FrameTimeNTSC;
Settings.DisableSampleCaching = FALSE;
Settings.DisableMasterVolume = FALSE;
Settings.Mouse = FALSE;
Settings.SuperScope = FALSE;
Settings.MultiPlayer5 = FALSE;
- // Settings.ControllerOption = SNES_MULTIPLAYER5;
- Settings.ControllerOption = 0;
+ Settings.ControllerOption = SNES_JOYPAD;
Settings.ForceTransparency = FALSE;
Settings.Transparency = FALSE;
Settings.ApplyCheats = FALSE;
Settings.TurboMode = FALSE;
Settings.TurboSkipFrames = 15;
- Settings.ThreadSound = FALSE;
- Settings.SoundSync = FALSE;
- //Settings.NoPatch = true;
-
- Settings.ApplyCheats = FALSE;
- Settings.TurboMode = FALSE;
Settings.ForcePAL = FALSE;
Settings.ForceNTSC = FALSE;
Settings.AutoSaveDelay = 15*60; // Autosave each 15 minutes.
}
-static void setRomFile(const char * path)
+void S9xSetRomFile(const char * path)
{
- char drive[1], dir[PATH_MAX], fname[PATH_MAX], ext[PATH_MAX];
-
- _splitpath (path, drive, dir, fname, ext);
- sprintf(Config.romFile, "%s%s%s", dir, strlen(dir) > 0 ? "/" : "", fname);
-}
+ if (romFile) {
+ free(romFile);
+ free(basePath);
+ }
-static bool gotRomFile()
-{
- return Config.romFile[0] != '\0';
+ romFile = strndup(path, PATH_MAX);
+ basePath = strdup(romFile);
+
+ // Truncate base path at the last '.' char
+ char * c = strrchr(basePath, '.');
+ if (c) {
+ if (strcasecmp(c, ".gz") == 0) {
+ // Ignore the .gz part when truncating
+ *c = '\0';
+ c = strrchr(basePath, '.');
+ if (c) {
+ *c = '\0';
+ }
+ } else {
+ *c = '\0';
+ }
+ }
}
-static void setHacks(const char * value)
+static bool gotRomFile()
{
- // Unconditionally enable hacks even if no argument passed
- Settings.HacksEnabled = TRUE;
-
- if (!value) return;
-
- if (strcasecmp(value, "speed-only") == 0 ||
- strcasecmp(value, "speed") == 0 ||
- strcasecmp(value, "s") == 0) {
- Settings.HacksFilter = TRUE;
- } else if (strcasecmp(value, "yes") == 0 ||
- strcasecmp(value, "y") == 0) {
- // Do nothing
- } else if (strcasecmp(value, "no") == 0 ||
- strcasecmp(value, "n") == 0) {
- Settings.HacksEnabled = FALSE;
- } else {
- // Hack: the user probably wants to enable hacks
- // and use this argument as the ROM file.
- // Wonder why popt does not support this or if there's a better way.
- setRomFile(value);
- }
+ return romFile ? true : false;
}
static void loadConfig(poptContext optCon, const char * file)
poptStuffArgs(optCon, newargv);
free(out);
+ fclose(fp);
/* XXX: currently leaking newargv */
}
unsigned char scancode = 0;
while ((rc = poptGetNextOpt(optCon)) > 0) {
+ const char * val;
switch (rc) {
case 1:
Config.enableAudio = false;
Settings.Transparency = TRUE;
break;
case 6:
- Settings.HacksEnabled = TRUE;
- setHacks(poptGetOptArg(optCon));
+ free(Config.scaler);
+ Config.scaler = strdup(poptGetOptArg(optCon));
break;
case 7:
Settings.ForcePAL = TRUE;
case 10:
loadConfig(optCon, poptGetOptArg(optCon));
break;
+ case 11:
+ val = poptGetOptArg(optCon);
+ Settings.Mouse = TRUE;
+ if (!val || atoi(val) <= 1) {
+ // Enable mouse on first controller
+ Settings.ControllerOption = SNES_MOUSE_SWAPPED;
+ } else {
+ // Enable mouse on second controller
+ Settings.ControllerOption = SNES_MOUSE;
+ }
+ break;
+ case 12:
+ Settings.SuperScope = TRUE;
+ Settings.ControllerOption = SNES_SUPERSCOPE;
+ break;
+ case 13:
+ Config.snapshotLoad = true;
+ Config.snapshotSave = true;
+ break;
+ case 14:
+ Settings.SoundPlaybackRate = atoi(poptGetOptArg(optCon));
+ break;
+ case 15:
+ Settings.SoundBufferSize = atoi(poptGetOptArg(optCon));
+ break;
+ case 16:
+ Config.touchscreenInput = true;
+ break;
+ case 17:
+ Config.touchscreenInput = true;
+ Config.touchscreenShow = true;
+ break;
+ case 18:
+ Settings.HacksEnabled = TRUE;
+ Settings.HacksFilter = TRUE;
+ break;
+ case 19:
+ Settings.HacksEnabled = TRUE;
+ Settings.HacksFilter = FALSE;
+ break;
case 100:
scancode = atoi(poptGetOptArg(optCon));
break;
actionNameToBit(poptGetOptArg(optCon));
break;
case 200:
- strcpy(Config.hacksFile, poptGetOptArg(optCon));
+ free(Config.hacksFile);
+ Config.hacksFile = strdup(poptGetOptArg(optCon));
break;
default:
DIE("Invalid popt argument (this is a bug): %d", rc);
/* if there's an extra unparsed arg it's our rom file */
const char * extra_arg = poptGetArg(optCon);
if (extra_arg)
- setRomFile(extra_arg);
+ S9xSetRomFile(extra_arg);
}
void S9xLoadConfig(int argc, const char ** argv)
// Command line parameters (including --conf args)
parseArgs(optCon);
+#if CONF_HGW
+ if (!gotRomFile() && !hgwLaunched) {
+ // User did not specify a ROM file,
+ // and we're not being launched from D-Bus.
+ fprintf(stderr, "You need to specify a ROM, like this:\n");
+ poptPrintUsage(optCon, stdout, 0);
+ poptFreeContext(optCon);
+ exit(2);
+ }
+#else
if (!gotRomFile()) {
+ // User did not specify a ROM file
fprintf(stderr, "You need to specify a ROM, like this:\n");
poptPrintUsage(optCon, stdout, 0);
- poptFreeContext(optCon);
+ poptFreeContext(optCon);
exit(2);
}
+#endif
poptFreeContext(optCon);
}
+void S9xUnloadConfig()
+{
+ if (romFile) {
+ free(romFile);
+ romFile = 0;
+ }
+ if (basePath) {
+ free(basePath);
+ basePath = 0;
+ }
+ if (Config.hacksFile) {
+ free(Config.hacksFile);
+ Config.hacksFile = 0;
+ }
+}
+