#include "options.h" #include "external/tinyxml2/tinyxml2.h" #include "util/utils.h" #include "util/fileutils.h" #include static const std::vector CATEGORY_ORDER_API = { "SpiceCompanion and API", "API (Serial)", "API (Dev)", "BT5 API", }; static const std::vector CATEGORY_ORDER_BASIC = { "Game Options", "Common", "Network", "Overlay", "Graphics (Common)", "Graphics (Windowed)", "Audio", }; static const std::vector CATEGORY_ORDER_ADVANCED = { "Game Options (Advanced)", "Network (Advanced)", "Performance", "Miscellaneous", "Paths", "Touch Parameters", "Lights Options", "Card Readers", }; static const std::vector CATEGORY_ORDER_DEV = { "Network Adapters", "I/O Modules", "Development", }; static const std::vector CATEGORY_ORDER_NONE = { "" }; /* * Option Definitions * Be aware that the order must be the same as in the enum launcher::Options! */ static const std::vector OPTION_DEFINITIONS = { { .title = "Game Executable", .name = "exec", .desc = "Path to the game DLL file", .type = OptionType::Text, .setting_name = "*.dll", .category = "Paths", }, { .title = "Open Configurator", .name = "cfg", .desc = "Opens configuration window. This can only be launched via the command line " "(spice -cfg or spice64 -cfg) or just launch spicecfg.exe", .type = OptionType::Bool, .hidden = true, .disabled = true, }, { .title = "Open KFControl", .name = "kfcontrol", .desc = "This can only be launched via the command line. Opens KFControl, tool for controlling arcade cabinet", .type = OptionType::Bool, .hidden = true, .disabled = true, }, { .title = "Basic Local EA Emulation", .name = "ea", .desc = "Enables the integrated local EA server, just enough to boot the game; no card in, no data saving", .type = OptionType::Bool, .category = "Network", }, { .title = "EA Service URL", .name = "url", .desc = "Sets a custom service URL override", .type = OptionType::Text, .category = "Network", }, { .title = "PCBID", .name = "p", .desc = "Sets a custom PCBID override", .type = OptionType::Text, .setting_name = "04040000000000000000", .category = "Network", .sensitive = true, }, { .title = "Player 1 Card", .name = "card0", .desc = "Set a card number for reader 1. Overrides the selected card file.", .type = OptionType::Text, .setting_name = "E004010000000000", .category = "Network", .sensitive = true, }, { .title = "Player 2 Card", .name = "card1", .desc = "Set a card number for reader 2. Overrides the selected card file.", .type = OptionType::Text, .setting_name = "E004010000000000", .category = "Network", .sensitive = true, }, { .title = "Windowed Mode", .name = "w", .desc = "Enables windowed mode", .type = OptionType::Bool, .category = "Graphics (Windowed)", }, { .title = "Inject DLL Hooks", .name = "k", .desc = "Multiple files are allowed; use multiple -k flags, or in SpiceCfg, separate by " "space (foo.dll bar.dll baz.dll). Injects a hook by using LoadLibrary on the " "specified file before running the main game code", .type = OptionType::Text, .setting_name = "a.dll b.dll c.dll", .category = "Common", }, { .title = "Execute Script", .name = "script", .desc = "Executes a script (.lua) at the given path on game boot", .type = OptionType::Text, .category = "Miscellaneous", }, { .title = "Lock Cursor to Window", .name = "c", .desc = "Confines the cursor to be within the game window", .type = OptionType::Bool, .category = "Common", }, { .title = "Show Cursor & Touch Emulation Enable", .name = "s", .desc = "Shows the cursor in the game window; also turns on touch emulation. Do not use if you use a real touch screen", .type = OptionType::Bool, .category = "Common", }, { .title = "Monitor", .name = "monitor", .desc = "Sets the display that the game will be opened in, for multiple monitors", .type = OptionType::Integer, .category = "Graphics (Common)", }, { .title = "Force Refresh Rate", .name = "graphics-force-refresh", .desc = "Force the refresh rate for the primary display adapter; works in both full screen and windowed modes", .type = OptionType::Integer, .category = "Graphics (Common)", }, { .title = "Only Use One Monitor", .name = "graphics-force-single-adapter", .desc = "Force the graphics device to be opened utilizing only one adapter in multi-monitor systems.\n\n" "May cause unstable framerate and desyncs, especially if monitors have different refresh rates!", .type = OptionType::Bool, .category = "Graphics (Common)", }, { // Graphics9On12 .title = "DirectX 9 on 12 (DEPRECATED - use -dx9on12 instead)", .name = "9on12", .desc = "Use D3D9On12 wrapper library, requires Windows 10 Insider Preview 18956 or later. Deprecated - use -dx9on12 instead", .type = OptionType::Bool, .hidden = true, .category = "Graphics (Common)", }, { // spice2x_Dx9On12 .title = "DirectX 9 on 12", .name = "sp2x-dx9on12", .display_name = "dx9on12", .aliases= "dx9on12", .desc = "Use D3D9On12 wrapper library, requires Windows 10 Insider Preview 18956 or later. Has no effect games on that don't use DX9.\n\n" "Default: auto (use DX9 for most games, but turn on 9on12 for games that require it on non-NVIDIA GPUs)", .type = OptionType::Enum, .category = "Graphics (Common)", .elements = { {"auto", "Automatic"}, {"0", "Use DX9"}, {"1", "Use DX9on12"}, }, }, { .title = "Disable Win/Media/Special Keys", .name = "nolegacy", .desc = "Disables legacy key activation in-game.", .type = OptionType::Bool, .category = "Miscellaneous", }, { .title = "Discord Rich Presence", .name = "richpresence", .desc = "Enables Discord Rich Presence support", .type = OptionType::Bool, .category = "Miscellaneous", }, { .title = "Smart EA", .name = "smartea", .desc = "Automatically enables -ea when server is offline", .type = OptionType::Bool, .category = "Network (Advanced)", }, { // EAmusementMaintenance .title = "EA Maintenance (DEPRECATED - use -forceeamaint instead)", .name = "eamaint", .desc = "Enables EA Maintenance, 1 for on, 0 for off.", .type = OptionType::Enum, .hidden = true, .category = "Network (Advanced)", .elements = {{"0", "Off"}, {"1", "On"}}, }, { // spice2x_EAmusementMaintenance .title = "Force EA Maintenance", .name = "sp2x-eamaint", .display_name = "forceeamaint", .aliases= "forceeamaint", .desc = "Force enables EA maintenance mode", .type = OptionType::Bool, .category = "Network (Advanced)", }, { .title = "Preferred NetAdapter IP", .name = "network", .desc = "This is NOT the EA service URL; use -url for that. " "Force the use of an adapter with the specified network. Must also provide -subnet", .type = OptionType::Text, .category = "Network Adapters", }, { .title = "Preferred NetAdapter Subnet", .name = "subnet", .desc = "Force the use of an adapter with the specified subnet. Must also provide -network", .type = OptionType::Text, .category = "Network Adapters", }, { .title = "Disable Network Fixes", .name = "netfixdisable", .desc = "Force disables network fixes", .type = OptionType::Bool, .category = "Network Adapters", }, { .title = "HTTP/1.1", .name = "http11", .desc = "Sets EA3 http11 value", .type = OptionType::Enum, .category = "Network (Advanced)", .elements = {{"0", "Off"}, {"1", "On"}}, }, { .title = "Disable SSL Protocol", .name = "ssldisable", .desc = "Prevents the SSL protocol from being registered", .type = OptionType::Bool, .category = "Network (Advanced)", }, { .title = "URL Slash", .name = "urlslash", .desc = "Sets EA3 urlslash value", .type = OptionType::Enum, .category = "Network (Advanced)", .elements = {{"0", "Off"}, {"1", "On"}}, }, { .title = "SOFTID", .name = "r", .desc = "Set custom SOFTID override", .type = OptionType::Text, .category = "Network (Advanced)", .sensitive = true, }, { .title = "VR controls (experimental)", .name = "vr", .desc = "Enable experimental VR support for feet input. " "Hint: bind a key to Toggle VR Control overlay window", .type = OptionType::Bool, .game_name = "DANCERUSH", .category = "Game Options", }, { .title = "Disable Spice Overlay", .name = "overlaydisable", .desc = "Disables the in-game overlay", .type = OptionType::Bool, .category = "Overlay", }, { // spice2x_FpsAutoShow .title = "Auto Show FPS/Clock", .name = "sp2x-autofps", .display_name = "autofps", .aliases= "autofps", .desc = "Automatically show FPS / clock / timer overlay window when the game starts", .type = OptionType::Bool, .category = "Overlay", }, { // spice2x_SubScreenAutoShow .title = "Auto Show Subscreen", .name = "sp2x-autosubscreen", .display_name = "autosubscreen", .aliases= "autosubscreen", .desc = "Automatically show the subscreen overlay when the game starts, if the game has one", .type = OptionType::Bool, .category = "Overlay", }, { // spice2x_IOPanelAutoShow .title = "Auto Show IO Panel", .name = "sp2x-autoiopanel", .display_name = "autoiopanel", .aliases= "autoiopanel", .desc = "Automatically show I/O panel window when the game starts", .type = OptionType::Bool, .category = "Overlay", }, { // spice2x_KeypadAutoShow .title = "Auto Show Keypad", .name = "sp2x-autokeypad", .display_name = "autokeypad", .aliases= "autokeypad", .desc = "Automatically show virtual keypad window when the game starts", .type = OptionType::Enum, .category = "Overlay", .elements = { {"0", "Off"}, {"1", "P1"}, {"2", "P2"}, {"3", "P1 and P2"}, }, }, { .title = "Force Load IIDX Module", .name = "iidx", .desc = "Manually enable Beatmania IIDX module", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { .title = "IIDX Camera Order Flip", .name = "iidxflipcams", .desc = "Flip the camera order", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { .title = "IIDX Disable Cameras", .name = "iidxdisablecams", .desc = "Disables cameras", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options", }, { // IIDXTDJCamera .title = "IIDX TDJ Cam Hook (Experimental)", .name = "iidxtdjcamhook", .desc = "Experimental camera support for IIDX 27+. " "Requires TDJ (010) DLL and camera(s) that support 16:9 YUY2 or NV12 encoding", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options", }, { // IIDXTDJCameraRatio .title = "IIDX TDJ Cam Aspect Ratio", .name = "iidxtdjcamhookratio", .desc = "Determine what aspect ratio should be preferred for webcam input. Default: 16:9", .type = OptionType::Enum, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", .elements = { {"43", "4:3"}, {"169", "16:9"}, }, }, { // IIDXTDJCameraOverride .title = "IIDX TDJ Cam Hook Offset Override", .name = "iidxtdjcamhookoffset", .desc = "Override DLL offsets for TDJ camera hook (-iidxtdjcamhook); " "format: 4 hex values separated by commas " "(offset_hook_a, offset_hook_b, offset_textures, offset_d3d_device)", .type = OptionType::Text, .setting_name = "0x5817a0,0x5ea3b0,0x6fffbd8,0xe0", .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { .title = "IIDX Sound Output Device", .name = "iidxsounddevice", .desc = "SOUND_OUTPUT_DEVICE environment variable override. Default: auto. " "Auto will use WASAPI, unless -iidxasio is set or if XONAR SOUND CARD is present, then ASIO is used.\n\n" "Only IIDX27-30 will accept this option; ignored in other games", .type = OptionType::Enum, .game_name = "Beatmania IIDX", .category = "Game Options", .elements = { {"auto", "Automatic"}, {"wasapi", "Windows Audio"}, {"asio", "ASIO"}, }, }, { .title = "IIDX ASIO Driver", .name = "iidxasio", .desc = "ASIO driver name to use, replacing XONAR SOUND CARD(64). " "String should match registry key under HKLM\\SOFTWARE\\ASIO\\. " "IIDX is very picky about ASIO devices it can support, YMMV", .type = OptionType::Text, .game_name = "Beatmania IIDX", .category = "Game Options", }, { .title = "IIDX BIO2 Firmware", .name = "iidxbio2fw", .desc = "Enables BIO2 firmware updates", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { .title = "IIDX TDJ Mode", .name = "iidxtdj", .desc = "Enables TDJ cabinet mode. Ensure you also set -iidxsounddevice to desired option", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options", }, { // spice2x_IIDXDigitalTTSensitivity .title = "IIDX Digital TT Sensitivity", .name = "sp2x-iidxdigitalttsens", .display_name = "iidxdigitalttsens", .aliases= "iidxdigitalttsens", .desc = "Adjust sensitivity of turntable when digital input (buttons) is used. Does not affect analog input! Default: 4", .type = OptionType::Integer, .setting_name = "(0-255)", .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // spice2x_IIDXLDJForce720p .title = "IIDX LDJ Force 720p (HD)", .name = "sp2x-iidxldjforce720p", .display_name = "iidxldjforce720p", .aliases= "iidxldjforce720p", .desc = "Force Definition Type HD (720p) mode instead of FHD (1080p) for IIDX30+. Only for LDJ! TDJ is always FHD in IIDX30+", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // spice2x_IIDXTDJSubSize .title = "IIDX TDJ Subscreen Size", .name = "sp2x-iidxtdjsubsize", .display_name = "iidxtdjsubsize", .aliases= "iidxtdjsubsize", .desc = "Default size of the subscreen overlay.\n\nNote: in windowed mode, subscreen will always be full size.\n\nDefault: medium", .type = OptionType::Enum, .game_name = "Beatmania IIDX", .category = "Overlay", .elements = { {"small", ""}, {"medium", ""}, {"large", ""}, {"fullscreen", ""}, }, }, { // spice2x_IIDXLEDFontSize .title = "IIDX LED Ticker Font Size", .name = "sp2x-iidxledfontsize", .display_name = "iidxledfontsize", .aliases= "iidxledfontsize", .desc = "Configure the font size of the segment display, in pixels. Default: 64 (px)", .type = OptionType::Integer, .game_name = "Beatmania IIDX", .category = "Overlay", }, { // spice2x_IIDXLEDColor .title = "IIDX LED Ticker Color", .name = "sp2x-iidxledcolor", .display_name = "iidxledcolor", .aliases= "iidxledcolor", .desc = "Configure the font color of the segment display; specify RGB value in hex. " "Default: 0xff0000 (red)", .type = OptionType::Hex, .game_name = "Beatmania IIDX", .category = "Overlay", }, { // spice2x_IIDXLEDPos .title = "IIDX LED Ticker Position", .name = "sp2x-iidxledpos", .display_name = "iidxledpos", .aliases= "iidxledpos", .desc = "Initial position of the segment display. Default: bottom", .type = OptionType::Enum, .game_name = "Beatmania IIDX", .category = "Overlay", .elements = { {"topleft", ""}, {"top", ""}, {"topright", ""}, {"bottomleft", ""}, {"bottom", ""}, {"bottomright", ""}, }, }, { .title = "Force Load Sound Voltex Module", .name = "sdvx", .desc = "Manually enable Sound Voltex Module", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { .title = "SDVX Force 720p", .name = "sdvx720", .desc = "Force Sound Voltex 720p display mode, used by older games. " "For newer games, use window resize function instead", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { .title = "SDVX Printer Emulation", .name = "printer", .desc = "Enable Sound Voltex printer emulation", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { .title = "SDVX Printer Output Path", .name = "printerpath", .desc = "Path to folder where images will be stored", .type = OptionType::Text, .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { .title = "SDVX Printer Output Clear", .name = "printerclear", .desc = "Clean up saved images in the output directory on startup", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { .title = "SDVX Printer Output Overwrite", .name = "printeroverwrite", .desc = "Always overwrite the same file in output directory", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { .title = "SDVX Printer Output Format", .name = "printerformat", .desc = "Path to folder where images will be stored", .type = OptionType::Text, .setting_name = "(png/bmp/tga/jpg)", .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { .title = "SDVX Printer JPG Quality", .name = "printerjpgquality", .desc = "Quality setting in percent if JPG format is used", .type = OptionType::Integer, .setting_name = "(0-100)", .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { .title = "SDVX Disable Cameras", .name = "sdvxdisablecams", .desc = "Disables cameras", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options", }, { .title = "SDVX Native Touch Handling", .name = "sdvxnativetouch", .desc = "Disables touch hooks and lets the game access a touch screen directly. " "Requires a touch screen to be connected as a secondary monitor. " "Touch input must be routed to the primary screen via Windows Tablet PC settings. " "Enable this when you get duplicate touch inputs from an actual touch screen", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options", }, { // spice2x_SDVXDigitalKnobSensitivity .title = "SDVX Digital Knob Sensitivity", .name = "sp2x-sdvxdigitalknobsens", .display_name = "sdvxdigitalknobsens", .aliases= "sdvxdigitalknobsens", .desc = "Adjust sensitivity of knobs when digital input (buttons) is used. Does not affect analog input! Default: 16", .type = OptionType::Integer, .setting_name = "(0-255)", .game_name = "Sound Voltex", .category = "Game Options (Advanced)", }, { // spice2x_SDVXAsioDriver .title = "SDVX ASIO driver", .name = "sp2x-sdvxasio", .display_name = "sdvxasio", .aliases= "sdvxasio", .desc = "ASIO driver name to use, replacing XONAR SOUND CARD(64). " "String should match registry key under HLKM\\SOFTWARE\\ASIO\\ " "SDVX is EXTREMELY picky about ASIO devices it can support!", .type = OptionType::Text, .game_name = "Sound Voltex", .category = "Game Options", }, { // spice2x_SDVXSubPos .title = "SDVX Subscreen Overlay Position", .name = "sp2x-sdvxsubpos", .display_name = "sdvxsubpos", .aliases= "sdvxsubpos", .desc = "Location for the subscreen overlay. Default: bottom", .type = OptionType::Enum, .game_name = "Sound Voltex", .category = "Overlay", .elements = {{"top", ""}, {"center", ""}, {"bottom", ""}}, }, { // spice2x_SDVXSubRedraw .title = "SDVX Subscreen Force Redraw", .name = "sp2x-sdvxsubredraw", .display_name = "sdvxsubredraw", .aliases= "sdvxsubredraw", .desc = "Check if second monitor for subscreen doesn't update every frame; " "forces subscreen to redraw every frame, only needed for newer EG.", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options", }, { .title = "Force Load DDR Module", .name = "ddr", .desc = "Manually enable Dance Dance Revolution module", .type = OptionType::Bool, .game_name = "Dance Dance Revolution", .category = "Game Options (Advanced)", }, { .title = "DDR 4:3 Mode", .name = "ddrsd/o", .desc = "Enable DDR 4:3 (SD) mode", .type = OptionType::Bool, .game_name = "Dance Dance Revolution", .category = "Game Options", }, { .title = "Force Load Pop'n Music Module", .name = "pnm", .desc = "Manually enable Pop'n Music module", .type = OptionType::Bool, .game_name = "Pop'n Music", .category = "Game Options (Advanced)", }, { .title = "Pop'n Music Force HD Mode", .name = "pnmhd", .desc = "Force enable Pop'n Music HD mode", .type = OptionType::Bool, .game_name = "Pop'n Music", .category = "Game Options", }, { .title = "Pop'n Music Force SD Mode", .name = "pnmsd", .desc = "Force enable Pop'n Music SD mode", .type = OptionType::Bool, .game_name = "Pop'n Music", .category = "Game Options", }, { .title = "Force Load HELLO! Pop'n Music Module", .name = "hpm", .desc = "Manually enable HELLO! Pop'n Music module", .type = OptionType::Bool, .game_name = "HELLO! Pop'n Music", .category = "Game Options (Advanced)", }, { .title = "Force Load GitaDora Module", .name = "gd", .desc = "Manually enable GitaDora module", .type = OptionType::Bool, .game_name = "GitaDora", .category = "Game Options (Advanced)", }, { .title = "GitaDora Two Channel Audio", .name = "2ch", .desc = "Attempt to reduce audio channels down to just two channels.", .type = OptionType::Bool, .game_name = "GitaDora", .category = "Game Options", }, { .title = "GitaDora Cabinet Type", .name = "gdcabtype", .desc = "Select cabinet type. DX has more input and lights. Pick SD2 for single player guitar mode on white cab", .type = OptionType::Enum, .game_name = "GitaDora", .category = "Game Options", .elements = {{"1", "DX"}, {"2", "SD"}, {"3", "SD2 - white cab"}}, }, { .title = "Force Load Jubeat Module", .name = "jb", .desc = "Manually enable Jubeat module", .type = OptionType::Bool, .game_name = "Jubeat", .category = "Game Options (Advanced)", }, { .title = "Force Load Reflec Beat Module", .name = "rb", .desc = "Manually enable Reflec Beat module", .type = OptionType::Bool, .game_name = "Reflec Beat", .category = "Game Options (Advanced)", }, { .title = "Force Load Tenkaichi Shogikai Module", .name = "shogikai", .desc = "Manually enable Tenkaichi Shogikai module", .type = OptionType::Bool, .game_name = "Tenkaichi Shogikai", .category = "Game Options (Advanced)", }, { .title = "Force Load Beatstream Module", .name = "bs", .desc = "Manually enable Beatstream module", .type = OptionType::Bool, .game_name = "Beatstream", .category = "Game Options (Advanced)", }, { .title = "Force Load Nostalgia Module", .name = "nostalgia", .desc = "Manually enable Nostalgia module", .type = OptionType::Bool, .game_name = "Nostalgia", .category = "Game Options (Advanced)", }, { .title = "Force Load Dance Evolution Module", .name = "dea", .desc = "Manually enable Dance Evolution module", .type = OptionType::Bool, .game_name = "Dance Evolution", .category = "Game Options (Advanced)", }, { .title = "Force Load FutureTomTom Module", .name = "ftt", .desc = "Manually enable FutureTomTom module", .type = OptionType::Bool, .game_name = "FutureTomTom", .category = "Game Options (Advanced)", }, { .title = "Force Load BBC Module", .name = "bbc", .desc = "Manually enable Bishi Bashi Channel module", .type = OptionType::Bool, .game_name = "Bishi Bashi Channel", .category = "Game Options (Advanced)", }, { .title = "Force Load Metal Gear Arcade Module", .name = "mga", .desc = "Manually enable Metal Gear Arcade module", .type = OptionType::Bool, .game_name = "Metal Gear", .category = "Game Options (Advanced)", }, { .title = "Force Load Quiz Magic Academy Module", .name = "qma", .desc = "Manually enable Quiz Magic Academy module", .type = OptionType::Bool, .game_name = "Quiz Magic Academy", .category = "Game Options (Advanced)", }, { .title = "Force Load Road Fighters 3D Module", .name = "rf3d", .desc = "Manually enable Road Fighters 3D module", .type = OptionType::Bool, .game_name = "Road Fighters 3D", .category = "Game Options (Advanced)", }, { .title = "Force Load Steel Chronicle Module", .name = "sc", .desc = "Manually enable Steel Chronicle module", .type = OptionType::Bool, .game_name = "Steel Chronicle", .category = "Game Options (Advanced)", }, { .title = "Force Load Mahjong Fight Club Module", .name = "mfc", .desc = "Manually enable Mahjong Fight Club module", .type = OptionType::Bool, .game_name = "Mahjong Fight Club", .category = "Game Options (Advanced)", }, { .title = "Force Load Scotto Module", .name = "scotto", .desc = "Manually enable Scotto module", .type = OptionType::Bool, .game_name = "Scotto", .category = "Game Options (Advanced)", }, { .title = "Force Load Dance Rush Module", .name = "dr", .desc = "Manually enable Dance Rush module", .type = OptionType::Bool, .game_name = "DANCERUSH", .category = "Game Options (Advanced)", }, { .title = "Force Load Winning Eleven Module", .name = "we", .desc = "Manually enable Winning Eleven module", .type = OptionType::Bool, .game_name = "Winning Eleven", .category = "Game Options (Advanced)", }, { .title = "Force Load Otoca D'or Module", .name = "otoca", .desc = "Manually enable Otoca D'or module", .type = OptionType::Bool, .game_name = "Otoca D'or", .category = "Game Options (Advanced)", }, { .title = "Force Load LovePlus Module", .name = "loveplus", .desc = "manually enable LovePlus module", .type = OptionType::Bool, .game_name = "LovePlus", .category = "Game Options (Advanced)", }, { .title = "Force Load Charge Machine Module", .name = "pcm", .desc = "manually enable Charge Machine module", .type = OptionType::Bool, .game_name = "Charge Machine", .category = "Game Options (Advanced)", }, { .title = "Force Load Ongaku Paradise Module", .name = "onpara", .desc = "manually enable Ongaku Paradise module", .type = OptionType::Bool, .game_name = "Ongaku Paradise", .category = "Game Options (Advanced)", }, { .title = "Force Load Busou Shinki Module", .name = "busou", .desc = "manually enable Busou Shinki module", .type = OptionType::Bool, .game_name = "Busou Shinki: Armored Princess Battle Conductor", .category = "Game Options (Advanced)", }, { // LoadCCJModule .title = "Force Load Chase Chase Jokers", .name = "ccj", .desc = "manually enable Chase Chase Jokers module", .type = OptionType::Bool, .game_name = "Chase Chase Jokers", .category = "Game Options (Advanced)", }, { // LoadQKSModule .title = "Force Load QuizKnock STADIUM", .name = "qks", .desc = "manually enable QuizKnock STADIUM module", .type = OptionType::Bool, .game_name = "QuizKnock STADIUM", .category = "Game Options (Advanced)", }, { // LoadMusecaModule .title = "Force Load Museca", .name = "museca", .desc = "manually enable Museca module", .type = OptionType::Bool, .game_name = "Museca", .category = "Game Options (Advanced)", }, { .title = "Modules Folder Path", .name = "modules", .desc = "Sets a custom path to the modules folder", .type = OptionType::Text, .category = "Paths", }, { .title = "Screenshot Folder Path", .name = "screenshotpath", .desc = "Sets a custom path to the screenshots folder", .type = OptionType::Text, .category = "Paths", }, { .title = "Configuration Path", .name = "cfgpath", .desc = "Sets a custom file path for config file. Must be passed via the command line. " "If left empty, %appdata%\\spicetools.xml will be used", .type = OptionType::Text, .setting_name = "(default)", .category = "Paths", .disabled = true, }, { // ScreenResizeConfigPath .title = "Screen Resize Config Path", .name = "resizecfgpath", .desc = "Sets a custom file path for screen resize config file. " "If left empty, %appdata%\\spicetools_screen_resize.json will be used", .type = OptionType::Text, .category = "Paths", }, { .title = "Intel SDE Folder Path", .name = "sde", .desc = "Path to Intel SDE kit path for automatic attaching", .type = OptionType::Text, .category = "Paths", }, { .title = "Path to ea3-config.xml", .name = "e", .desc = "Sets a custom path to ea3-config.xml", .type = OptionType::Text, .category = "Paths", }, { .title = "Path to app-config.xml", .name = "a", .desc = "Sets a custom path to app-config.xml", .type = OptionType::Text, .category = "Paths", }, { .title = "Path to avs-config.xml", .name = "v", .desc = "Sets a custom path to avs-config.xml", .type = OptionType::Text, .category = "Paths", }, { .title = "Path to bootstrap.xml", .name = "b", .desc = "Sets a custom path to bootstrap.xml", .type = OptionType::Text, .category = "Paths", }, { .title = "Path to log.txt", .name = "y", .desc = "Sets a custom path to log.txt", .type = OptionType::Text, .category = "Paths", }, { .title = "API TCP Port", .name = "api", .desc = "Port the API should be listening on", .type = OptionType::Integer, .category = "SpiceCompanion and API", }, { .title = "API Password", .name = "apipass", .desc = "Set the custom user password needed to use the API", .type = OptionType::Text, .category = "SpiceCompanion and API", .sensitive = true, }, { .title = "API Verbose Logging", .name = "apilogging", .desc = "verbose logging of API activity", .type = OptionType::Bool, .category = "API (Dev)", }, { .title = "API Serial Port", .name = "apiserial", .desc = "Serial port the API should be listening on", .type = OptionType::Text, .category = "API (Serial)", }, { .title = "API Serial Baud", .name = "apiserialbaud", .desc = "Baud rate for the serial port", .type = OptionType::Integer, .category = "API (Serial)", }, { .title = "API Pretty", .name = "apipretty", .desc = "Slower, but pretty API output", .type = OptionType::Bool, .category = "API (Dev)", }, { .title = "API Debug Mode", .name = "apidebug", .desc = "Enables API debugging mode", .type = OptionType::Bool, .category = "API (Dev)", }, { .title = "Enable All IO Modules", .name = "io", .desc = "Manually enable ALL IO emulation", .type = OptionType::Bool, .category = "I/O Modules", }, { .title = "Enable ACIO Module", .name = "acio", .desc = "Manually enable ACIO emulation", .type = OptionType::Bool, .category = "I/O Modules", }, { .title = "Enable ICCA Module", .name = "icca", .desc = "Manually enable ICCA emulation", .type = OptionType::Bool, .category = "I/O Modules", }, { .title = "Enable DEVICE Module", .name = "device", .desc = "Manually enable DEVICE emulation", .type = OptionType::Bool, .category = "I/O Modules", }, { .title = "Enable EXTDEV Module", .name = "extdev", .desc = "Manually enable EXTDEV emulation", .type = OptionType::Bool, .category = "I/O Modules", }, { .title = "Enable SCIUNIT Module", .name = "sciunit", .desc = "Manually enable SCIUNIT emulation", .type = OptionType::Bool, .category = "I/O Modules", }, { .title = "Enable device passthrough", .name = "devicehookdisable", .desc = "Disable I/O and serial device hooks", .type = OptionType::Bool, .category = "I/O Modules", }, { .title = "Disable Raw Input Touch", .name = "wintouch", .desc = "For touch screen input, disable usage of Raw Input API and instead use " "Win8 Pointer API or Win7 Touch API. Only enable this if you have trouble " "using the default (raw input) touch input, as Raw Input performs better", .type = OptionType::Bool, .category = "Touch Parameters", }, { .title = "Force Touch Emulation", .name = "touchemuforce", .desc = "Force enable hook for GetTouchInputInfo API and inject WM_TOUCH events. " "This is automatically turned on when needed, so it is not typically required to " "turn it on manually. Do not enable this unless you have trouble", .type = OptionType::Bool, .category = "Touch Parameters", }, { .title = "Invert Raw Input Touch", .name = "touchinvert", .desc = "Inverts raw touch coordinates; only works for default raw input handler, " "and not Windows Touch API", .type = OptionType::Bool, .category = "Touch Parameters", }, { // DisableTouchCardInsert .title = "Disable Touch Card Insert (DEPRECATED - use -touchcard instead)", .name = "touchnocard", .desc = "Disables touch overlay card insert button.", .type = OptionType::Bool, .hidden = true, .category = "Touch Parameters", }, { // spice2x_TouchCardInsert .title = "Show Insert Card button", .name = "sp2x-touchcard", .display_name = "touchcard", .aliases= "touchcard", .desc = "Show Insert Card touch button on main display", .type = OptionType::Bool, .category = "Touch Parameters", }, { .title = "ICCA Reader Port", .name = "reader", .desc = "Connects to and uses a ICCA on a given COM port", .type = OptionType::Text, .category = "Card Readers", }, { .title = "ICCA Reader Port (with toggle)", .name = "togglereader", .desc = "Connects to and uses a ICCA on a given COM port, and enabled NumLock toggling between P1/P2", .type = OptionType::Text, .category = "Card Readers", }, { .title = "CardIO HID Reader Support", .name = "cardio", .desc = "Enables detection and support of cardio HID readers", .type = OptionType::Bool, .category = "Card Readers", }, { .title = "CardIO HID Reader Order Flip", .name = "cardioflip", .desc = "Flips the order of detection for P1/P2", .type = OptionType::Bool, .category = "Card Readers", }, { // CardIOHIDReaderOrderToggle .title = "CardIO HID Reader Order Toggle", .name = "cardiotoggle", .desc = "Toggles reader between P1/P2 using the NumLock key state", .type = OptionType::Bool, .category = "Card Readers", }, { .title = "HID SmartCard", .name = "scard", .desc = "Detects and uses HID smart card readers for card input", .type = OptionType::Bool, .category = "Card Readers", }, { .title = "HID SmartCard Order Flip", .name = "scardflip", .desc = "Flips the order of detection for P1/P2", .type = OptionType::Bool, .category = "Card Readers", }, { .title = "HID SmartCard Order Toggle", .name = "scardtoggle", .desc = "Toggles reader between P1/P2 using the NumLock key state", .type = OptionType::Bool, .category = "Card Readers", }, { .title = "SextetStream Port", .name = "sextet", .desc = "Use a SextetStream device on a given COM port", .type = OptionType::Text, .category = "Miscellaneous", }, { .title = "Enable BemaniTools 5 API", .name = "bt5api", .desc = "Enables partial BemaniTools 5 API compatibility layer", .type = OptionType::Bool, .category = "BT5 API", }, { .title = "Realtime Process Priority (DEPRECATED - use -processpriority instead)", .name = "realtime", .desc = "Sets the process priority to realtime, can help with odd lag spikes.", .type = OptionType::Bool, .hidden = true, .category = "Performance", }, { // spice2x_ProcessPriority .title = "Process Priority", .name = "sp2x-processpriority", .display_name = "processpriority", .aliases= "processpriority", .desc = "Sets the process priority, can help with odd lag spikes. Default: high", .type = OptionType::Enum, .category = "Performance", .elements = { {"belownormal", ""}, {"normal", ""}, {"abovenormal", ""}, {"high", ""}, {"realtime", ""} }, }, { // spice2x_ProcessAffinity .title = "Process Affinity", .name = "sp2x-processaffinity", .display_name = "processaffinity", .aliases= "processaffinity", .desc = "Set process affinity by calling SetProcessAffinityMask. " "Must provide a hexadecimal mask (e.g., 0x1ff00)", .type = OptionType::Hex, .category = "Performance", }, { // spice2x_ProcessorEfficiencyClass .title = "Process Efficiency Class", .name = "sp2x-processefficiency", .display_name = "processefficiency", .aliases= "processefficiency", .desc = "Has no effect if -processaffinity is set. Default: Use all cores", .type = OptionType::Enum, .category = "Performance", .elements = { {"all", "Use all cores"}, {"pcores", "Performant cores only"}, {"ecores", "Efficient cores only"}, }, }, { .title = "Heap Size", .name = "h", .desc = "Custom heap size in bytes", .type = OptionType::Integer, .category = "Development", }, // TODO: remove this and create an ignore list { // DisableGSyncDetection .title = "(REMOVED) Disable G-Sync Detection", .name = "keepgsync", .desc = "Broken feature that was not implemented correctly", .type = OptionType::Bool, .hidden = true, .category = "Graphics (Common)", }, { // spice2x_NvapiProfile .title = "NVIDIA profile optimization", .name = "sp2x-nvprofile", .display_name = "nvprofile", .aliases= "nvprofile", .desc = "Creates an NVIDIA application profile for spice(64).exe and applies GPU tweaks.\n\n" "Disables G-SYNC by setting the Monitor Technology to 'Fixed Refresh', and the Power Management Mode to 'Prefer maximum performance'.\n\n" "G-SYNC may fail to disable properly; try enabling full-screen optimizations (FSO) for spice(64).exe.\n\n" "May not work as expected for some games; namely G-SYNC and SDVX ", .type = OptionType::Bool, .category = "Graphics (Common)", }, { // DisableAudioHooks .title = "Disable All Spice Audio Hooks", .name = "audiohookdisable", .desc = "Disables all audio hooks, including device initialization and volume hooks.\n\n" "Default: off (allow Spice to hook IMMDeviceEnumerator for and optionally let " "you use a different backend instead of exclusive WASAPI).\n\n" "Check this if you want games to natively access your audio device", .type = OptionType::Bool, .category = "Audio", }, { // spice2x_DisableVolumeHook .title = "Disable Audio Volume Hook", .name = "sp2x-volumehookdisable", .display_name = "volumehookdisable", .aliases= "volumehookdisable", .desc = "Disables audio volume hook.\n\n" "Default: off (prevent games from changing audio volume by hooking IAudioEndpointVolume).\n\n" "Check this if you want games to freely change your volume", .type = OptionType::Bool, .category = "Audio", }, { .title = "Spice Audio Hook Backend", .name = "audiobackend", .desc = "Selects the audio backend to use when spice audio hook is enabled, overriding exclusive WASAPI. " " Does nothing for games that do not output to exclusive WASAPI", .type = OptionType::Enum, .category = "Audio", .elements = {{"asio", "ASIO"}, {"waveout", "waveOut"},{"pipewire", "Pipewire (Linux)"},{"none", "None"}}, }, { .title = "Spice Audio Hook ASIO Driver ID", .name = "asiodriverid", .desc = "Selects the ASIO driver id to use when Spice Audio Backend is set to ASIO", .type = OptionType::Integer, .category = "Audio", }, { .title = "WASAPI Dummy Context", .name = "audiodummy", .desc = "Uses a dummy `IAudioClient` context to maintain full audio control. " "This is automatically enabled when required and not normally needed", .type = OptionType::Bool, .hidden = true, .category = "Audio", }, { // DelayBy5Seconds .title = "Delay by 5 Seconds (DEPRECATED - use -sleepduration instead)", .name = "sleep", .desc = "Waits five seconds before starting the game", .type = OptionType::Bool, .hidden = true, // superseded by sp2x-sleep_duration .category = "Miscellaneous", }, { // spice2x_DelayByNSeconds .title = "Delay Game Launch", .name = "sp2x-sleepduration", .display_name = "sleepduration", .aliases= "sleepduration", .desc = "Wait for N seconds before starting the game", .type = OptionType::Integer, .category = "Miscellaneous", }, { .title = "Load KBT/KLD Stubs", .name = "stubs", .desc = "Enables loading kbt/kld stub files", .type = OptionType::Bool, .category = "Development", }, { .title = "Adjust Display Orientation (DEPRECATED - use -autoorientation instead)", .name = "adjustorientation", .desc = "Automatically adjust the orientation of your display in portrait games. " "WARNING: game may launch at incorrect refresh rate! Use in combination with " "-graphics-force-refresh flag to fix.", .type = OptionType::Bool, .hidden = true, // superseded by sp2x-autoorientation .category = "Graphics (Common)", }, { // spice2x_AutoOrientation .title = "Auto-rotate Display", .name = "sp2x-autoorientation", .display_name = "autoorientation", .aliases= "autoorientation", .desc = "Automatically adjust the orientation of your display when launched. " "WARNING: game may launch at incorrect refresh rate! Use in combination with " "-graphics-force-refresh and potentially either -9on12 or full-screen optimizations (FSO) to fix.", .type = OptionType::Enum, .category = "Graphics (Common)", // match graphics_orientation .elements = {{"0", "90 (CW)"}, {"1", "270 (CCW)"}}, }, { .title = "Log Level", .name = "loglevel", .desc = "Set the level of detail that gets written to the log", .type = OptionType::Enum, .category = "Performance", .elements = {{"fatal", ""}, {"warning", ""}, {"info", ""}, {"misc", ""}, {"all", ""}, {"disable", ""}}, }, { .title = "EA Automap", .name = "automap", .desc = "Enable automap in patch configuration", .type = OptionType::Bool, .category = "Development", }, { .title = "EA Netdump", .name = "netdump", .desc = "Enable automap in network dumping configuration", .type = OptionType::Bool, .category = "Development", }, { .title = "Discord RPC AppID Override", .name = "discordappid", .desc = "Set the discord RPC AppID override", .type = OptionType::Text, .category = "Development", }, { .title = "Blocking Logger", .name = "logblock", .desc = "Slower but safer logging used for debugging", .type = OptionType::Bool, .category = "Development", }, { .title = "Debug CreateFile", .name = "createfiledebug", .desc = "Outputs CreateFile debug prints", .type = OptionType::Bool, .category = "Development", }, { .title = "Verbose Graphics Logging", .name = "graphicsverbose", .desc = "Enable the verbose logging of graphics hook code", .type = OptionType::Bool, .category = "Development", }, { .title = "Verbose AVS Logging", .name = "avsverbose", .desc = "Enable the verbose logging of AVS filesystem functions", .type = OptionType::Bool, .category = "Development", }, { .title = "Disable Colored Output", .name = "nocolor", .desc = "Disable terminal colors for log outputs to console", .type = OptionType::Bool, .category = "Development", }, { .title = "Disable ACP Hook", .name = "acphookdisable", .desc = "Force disable advanced code pages hooks for encoding", .type = OptionType::Bool, .category = "Development", }, { .title = "Disable Signal Handling", .name = "signaldisable", .desc = "Force disable signal handling", .type = OptionType::Bool, .category = "Development", }, { .title = "Disable Debug Hooks", .name = "dbghookdisable", .desc = "Disable hooks for debug functions (e.g. OutputDebugString)", .type = OptionType::Bool, .category = "Development", }, { .title = "Disable AVS VFS Drive Mount Redirection", .name = "avs-redirect-disable", .desc = "Disable D:/E:/F: AVS VFS mount redirection", .type = OptionType::Bool, .category = "Development", }, { .title = "Output PEB", .name = "pebprint", .desc = "Prints PEB on startup to console", .type = OptionType::Bool, .category = "Development", }, { .title = "QKS Arguments Override", .name = "qksargs", .desc = "Command line arguments passed to the game.", .type = OptionType::Text, .setting_name = "", .game_name = "QuizKnock STADIUM", .category = "Game Options (Advanced)", }, { .title = "CCJ Arguments Override", .name = "ccjargs", .desc = "Command line arguments passed to the game. " "If left blank, '-nomatchselect' is applied, which disables matchmaking debug menu", .type = OptionType::Text, .setting_name = "", .game_name = "Chase Chase Jokers", .category = "Game Options (Advanced)", }, { .title = "CCJ Mouse Trackball", .name = "ccjmousetb", .desc = "Use mouse for trackball input; disables any keyboard / joystick control for the trackball. "\ "Hold RMB and move the cursor to control the trackball", .type = OptionType::Bool, .game_name = "Chase Chase Jokers", .category = "Game Options", }, { .title = "CCJ Mouse Trackball Toggle", .name = "ccjmousetbt", .desc = "Instead of holding RMB, click RMB to toggle trackball input", .type = OptionType::Bool, .game_name = "Chase Chase Jokers", .category = "Game Options", }, { .title = "CCJ Trackball Sensitivity", .name = "ccjtrackballsens", .desc = "Adjust sensitivity of trackball. Affects both digital and analog input. Default: 10", .type = OptionType::Integer, .setting_name = "(0-255)", .game_name = "Chase Chase Jokers", .category = "Game Options", }, { // spice2x_LightsOverallBrightness .title = "Lights Brightness Adjustment", .name = "sp2x-lights-brightness", .display_name = "lightsbrightness", .aliases= "lightsbrightness", .desc = "Modify HID output values, measured in %. Default is 100. " "Requires compatible hardware, not just any LED", .type = OptionType::Integer, .setting_name = "(0-100)", .category = "Lights Options", }, { // spice2x_WindowBorder .title = "Window Border Style", .name = "sp2x-windowborder", .display_name = "windowborder", .aliases= "windowborder", .desc = "For windowed mode: overrides window border style. " "Does not work for all games; can possibly make the game crash! " "Can also be changed in Screen Resize window (default F11)", .type = OptionType::Enum, .category = "Graphics (Windowed)", // match cfg::WindowDecorationMode .elements = { {"0", "default"}, {"1", "borderless"}, {"2", "resizable window"}, }, }, { // spice2x_WindowSize .title = "Window Size", .name = "sp2x-windowsize", .display_name = "windowsize", .aliases= "windowsize", .desc = "For windowed mode: override for window size, width and height separated by comma. " "Can also be changed in Screen Resize window (default F11)", .type = OptionType::Text, .setting_name = "1280,720", .category = "Graphics (Windowed)", }, { // spice2x_WindowPosition .title = "Window Position", .name = "sp2x-windowpos", .display_name = "windowpos", .aliases= "windowpos", .desc = "For windowed mode: override for window position, x and y separated by comma. " "Can also be changed in Screen Resize window (default F11)", .type = OptionType::Text, .setting_name = "120,240", .category = "Graphics (Windowed)", }, { // spice2x_WindowAlwaysOnTop .title = "Window Always on Top", .name = "sp2x-windowalwaysontop", .display_name = "windowalwaysontop", .aliases= "windowalwaysontop", .desc = "For windowed mode: make window to be always on top of other windows. " "Can also be changed in Screen Resize window (default F11)", .type = OptionType::Bool, .category = "Graphics (Windowed)", }, { // spice2x_IIDXWindowedSubscreenSize .title = "IIDX Windowed Subscreen Size", .name = "iidxwsubsize", .desc = "Size of the subscreen window. Defaults to (1280,720).", .type = OptionType::Text, .setting_name = "1280,720", .game_name = "Beatmania IIDX", .category = "Graphics (Windowed)", }, { // spice2x_IIDXWindowedSubscreenPosition .title = "IIDX Windowed Subscreen Position", .name = "iidxwsubpos", .desc = "Initial position of the subscreen window. Defaults to (0,0).", .type = OptionType::Text, .setting_name = "0,0", .game_name = "Beatmania IIDX", .category = "Graphics (Windowed)", }, { // spice2x_JubeatLegacyTouch .title = "JB Legacy Touch Targets", .name = "sp2x-jubeatlegacytouch", .display_name = "jubeatlegacytouch", .aliases= "jubeatlegacytouch", .desc = "For touch screen players - use the legacy & less accurate grid-based layout for touch recognition, " "instead of the new & more accurate touch targets. Default: off", .type = OptionType::Bool, .game_name = "Jubeat", .category = "Game Options", }, { // spice2x_RBTouchScale .title = "RB Scale Touch Input", .name = "sp2x-rbscaletouch", .display_name = "rbscaletouch", .aliases= "rbscaletouch", .desc = "Apply scaling to make touch area smaller than the screen. " "Specify a number out of 1000 (e.g., 800 means 80%). Default: 1000", .type = OptionType::Integer, .game_name = "Reflec Beat", .category = "Game Options", }, { // spice2x_AsioForceUnload .title = "ASIO Force Unload On Stop", .name = "sp2x-asioforceunload", .display_name = "asioforceunload", .aliases= "asioforceunload", .desc = "For certain buggy ASIO drivers, force unload of ASIO driver when audio stream stops. " "Used for working around ASIO drivers that lock up after force quitting games", .type = OptionType::Bool, .category = "Audio", }, { // spice2x_IIDXNoESpec .title = "IIDX Disable E-spec I/O", .name = "sp2x-iidxnoespec", .display_name = "iidxnoespec", .aliases= "iidxnoespec", .desc = "Disable I/O emulation for E-spec I/O upgrade (GELDJ-JX kit)", .type = OptionType::Bool, .hidden = true, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // spice2x_IIDXWindowedTDJ .title = "IIDX TDJ Windowed Mode (DEPRECATED - just use -iidxtdj and -w together)", .name = "sp2x-iidxtdjw", .display_name = "iidxtdjw", .aliases= "iidxtdjw", .desc = "Enable TDJ, optimized for windowed mode. " "Press Toggle Subscreen button and use your mouse on the main window.", .type = OptionType::Bool, .hidden = true, .game_name = "Beatmania IIDX", .category = "Game Options", }, { // spice2x_DRSDisableTouch .title = "DRS Disable Touch Input", .name = "sp2x-drsdisabletouch", .display_name = "drsdisabletouch", .aliases= "drsdisabletouch", .desc = "Disables multitouch input", .type = OptionType::Bool, .game_name = "DANCERUSH", .category = "Game Options", }, { // spice2x_DRSTransposeTouch .title = "DRS Transpose Touch Input", .name = "sp2x-drstransposetouch", .display_name = "drstransposetouch", .aliases= "drstransposetouch", .desc = "Swap x and y values of touch input", .type = OptionType::Bool, .game_name = "DANCERUSH", .category = "Game Options", }, { // spice2x_IIDXNativeTouch .title = "IIDX Native Touch Handling", .name = "sp2x-iidxnativetouch", .display_name = "iidxnativetouch", .aliases= "iidxnativetouch", .desc = "Disables touch hooks and lets the game access a touch screen directly. " "Requires a touch screen to be connected as a secondary monitor. " "Touch input must be routed to the primary screen via Windows Tablet PC settings. " "Enable this when you get duplicate touch inputs from an actual touch screen", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options", }, { // spice2x_IIDXNoSub .title = "IIDX TDJ Subscreen Disable", .name = "sp2x-iidxnosub", .display_name = "iidxnosub", .aliases= "iidxnosub", .desc = "Prevents TDJ subscreen from launching a separate window.", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options", }, { // spice2x_IIDXEmulateSubscreenKeypadTouch .title = "IIDX TDJ Subscreen Keypad Touch Emulation", .name = "sp2x-iidxsubpoke", .display_name = "iidxsubpoke", .aliases = "iidxsubpoke", .desc = "Emulates touches on TDJ subscreen when keypad input is received. " "Should be used along with 'Unscramble Touch Screen Keypad in TDJ' patch. " "00 is mapped to erase button, and Decimal is shows/hides the keypad", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options", }, { // spice2x_AutoCard .title = "Auto Card Insert", .name = "sp2x-autocard", .display_name = "autocard", .aliases= "autocard", .desc = "Periodically present virtual card(s) to the reader, removing the need to press Insert Card button. " "Only applies to local virtual cards (-card0, -card1, or card0/1.txt), " "do not use with physical card reader or API.", .type = OptionType::Enum, .category = "Network", .elements = { {"off", ""}, {"p1", ""}, {"p2", ""}, {"both", ""}, }, }, { // spice2x_LowLatencySharedAudio .title = "Low Latency Shared Audio", .name = "sp2x-lowlatencysharedaudio", .display_name = "lowlatencysharedaudio", .aliases= "lowlatencysharedaudio", .desc = "Force the usage of smallest buffer size supported by the device when shared mode audio is used. " "Works for games using DirectSound or shared WASAPI; no effect for exclusive WASAPI and ASIO. " "For best results (under 10ms), use the default Windows inbox audio driver instead of manufacturer supplied driver. " "Requires Windows 10 and above", .type = OptionType::Bool, .category = "Audio", }, { // spice2x_TapeLedAlgorithm .title = "Tape LED Avg Algorithm", .name = "sp2x-tapeledalgo", .display_name = "tapeledalgo", .aliases= "tapeledalgo", .desc = "For games with light arrays, determine the algorithm that is used to translate them into a single light binding in Lights tab. " "Only applies to IIDX, SDVX, and DDR for now. Default: mid", .type = OptionType::Enum, .category = "Lights Options", .elements = { {"off", "Off"}, {"first", "First LED"}, {"mid", "Middle LED"}, {"last", "Last LED"}, {"avg", "Average color"}, }, }, { // spice2x_NoNVAPI .title = "NVAPI Block", .name = "sp2x-nonvapi", .display_name = "nonvapi", .aliases= "nonvapi", .desc = "Completely block the game from accessing NVAPI. Can be used if NVAPI is returning undesirable " "results to the game (e.g., wrong values from NvDisplayConfig for SDVX). You may need to apply additional " "hex edits in order to boot the game correctly", .type = OptionType::Bool, .category = "Graphics (Common)", }, { // spice2x_NoD3D9DeviceHook .title = "Disable D3D9 Device Hook (DEPRECATED - no longer needed for TDJ recording)", .name = "sp2x-nod3d9devhook", .display_name = "nod3d9devhook", .aliases= "nod3d9devhook", .desc = "This was previously required for TDJ play recording, but as of 2024-08-04, it is no longer needed. " "Completely disable all DXD9 device hook, preventing features like Spice overlay, subscreen window, " "screenshots, screen resize, touch emulation, streaming to Companion, etc.", .type = OptionType::Bool, .hidden = true, .category = "Graphics (Common)", }, { // spice2x_SDVXNoSub .title = "SDVX Subscreen Disable", .name = "sp2x-sdvxnosub", .display_name = "sdvxnosub", .aliases= "sdvxnosub", .desc = "Prevents VM subscreen from launching a separate window.", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Game Options", }, { // spice2x_EnableSMXStage .title = "StepmaniaX Stage Lighting Support", .name = "sp2x-smx-stage", .display_name = "smxstage", .aliases= "smxstage", .desc = "StepmaniaX stage will show up as a device that can recieve lighting output. " "For configurator, restart spicecfg.exe after enabling this to have the device show up for binding", .type = OptionType::Bool, .category = "Lights Options", }, }; const std::vector &launcher::get_categories(Options::OptionsCategory category) { switch (category) { case Options::OptionsCategory::API: return CATEGORY_ORDER_API; case Options::OptionsCategory::Basic: return CATEGORY_ORDER_BASIC; case Options::OptionsCategory::Advanced: return CATEGORY_ORDER_ADVANCED; case Options::OptionsCategory::Dev: return CATEGORY_ORDER_DEV; case Options::OptionsCategory::Everything: default: return CATEGORY_ORDER_NONE; } } const std::vector &launcher::get_option_definitions() { return OPTION_DEFINITIONS; } std::unique_ptr> launcher::parse_options(int argc, char *argv[]) { // generate options auto &definitions = get_option_definitions(); auto options = std::make_unique>(); options->reserve(definitions.size()); for (auto &definition : definitions) { // create aliases std::vector aliases; aliases.push_back(definition.name); if (!definition.aliases.empty()) { strsplit(definition.aliases, aliases, '/'); } // create option auto &option = options->emplace_back(definition, ""); // check if enabled for (int i = 1; i < argc; i++) { // ignore leading '-' characters auto argument = argv[i]; while (argument[0] == '-') { argument++; } // check aliases for (const auto &alias : aliases) { if (_stricmp(alias.c_str(), argument) == 0) { switch (definition.type) { case OptionType::Bool: { option.value_add("/ENABLED"); break; } case OptionType::Integer: { if (++i >= argc) { log_fatal("options", "missing parameter for -{}", alias); } else { // validate it is an integer char *p; strtol(argv[i], &p, 10); if (*p) { log_fatal("options", "parameter for -{} is not a number: {}", alias, argv[i]); } else { option.value_add(argv[i]); } } break; } case OptionType::Hex: { if (++i >= argc) { log_fatal("options", "missing parameter for -{}", alias); } else { // validate it is an integer try { std::stoull(argv[i], nullptr, 16); } catch (const std::exception &ex) { log_fatal("options", "parameter for -{} is not a hex number: {}", alias, argv[i]); } } break; } case OptionType::Enum: case OptionType::Text: { if (++i >= argc) { log_fatal("options", "missing parameter for -{}", alias); } else { option.value_add(argv[i]); } break; } default: { log_warning("options", "unknown option type: {} (-{})", definition.type, alias); break; } } break; } } } } // positional arguments std::vector positional; for (int i = 1; i < argc; i++) { // check if enabled bool found = false; for (auto &definition : definitions) { // create aliases std::vector aliases; aliases.push_back(definition.name); if (!definition.aliases.empty()) { strsplit(definition.aliases, aliases, '/'); } // ignore leading '-' characters auto argument = argv[i]; while (argument[0] == '-') { argument++; } // check aliases for (const auto &alias : aliases) { if (_stricmp(alias.c_str(), argument) == 0) { found = true; switch (definition.type) { case OptionType::Bool: break; case OptionType::Integer: case OptionType::Hex: case OptionType::Text: case OptionType::Enum: i++; break; } break; } } // early quit if (found) { break; } } // positional argument if (!found && *argv[i] != '-') { positional.emplace_back(argv[i]); } } // game executable if (!positional.empty()) { options->at(launcher::Options::GameExecutable).value = positional[0]; } // return vector return options; } std::vector