#include "options.h" #include "external/tinyxml2/tinyxml2.h" #include "util/utils.h" #include "util/fileutils.h" #include #ifdef NO_SCARD #define WITH_SCARD 0 #else #define WITH_SCARD 1 #endif 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", "Graphics (Common)", "Graphics (Full Screen)", "Graphics (Windowed)", "Audio", }; static const std::vector CATEGORY_ORDER_ADVANCED = { "Game Options (Advanced)", "Overlay", "Network (Advanced)", "Performance", "Miscellaneous", "Touch Parameters", "I/O Options", "NFC Card Readers", }; static const std::vector CATEGORY_ORDER_DEV = { "Path Overrides", "Network (Development)", "Audio (Hacks)", "I/O Modules", "Development", "Debug Log", }; static const std::vector CATEGORY_ORDER_NONE = { "" }; static auto format_as(OptionType f) { return fmt::underlying(f); } bool launcher::USE_CMD_OVERRIDE = false; /* * Option Definitions * Be aware that the order must be the same as in the enum launcher::Options! */ static const std::vector OPTION_DEFINITIONS = { { .title = "Override Game Executable & Disable Hooks", .name = "exec", .desc = "Path to the game DLL file.\n\n" "This option is typically not needed; leave it empty to allow spice to auto-detect your game.\n\n" "WARNING: this option also disables all game-specific hooks and turns off most I/O modules!", .type = OptionType::Text, .setting_name = "*.dll", .category = "Path Overrides", }, { .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 = "(REMOVED) Open KFControl", .name = "kfcontrol", .desc = "This feature has been removed; please use an older version.", .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", }, { // ServiceURL .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, }, { // Player1PinMacro .title = "Player 1 PIN Macro", .name = "pinmacro0", .desc = "Set a PIN for Player 1 that will cause the PIN to be automatically typed when Player 1 PIN Macro overlay key is pressed.", .type = OptionType::Text, .setting_name = "1234", .category = "Network (Advanced)", .sensitive = true, }, { // Player2PinMacro .title = "Player 2 PIN Macro", .name = "pinmacro1", .desc = "Set a PIN for Player 2 that will cause the PIN to be automatically typed when Player 2 PIN Macro overlay key is pressed.", .type = OptionType::Text, .setting_name = "5678", .category = "Network (Advanced)", .sensitive = true, }, { .title = "Windowed Mode", .name = "w", .desc = "Enables windowed mode.", .type = OptionType::Bool, .category = "Graphics (Windowed)", }, { // InjectHook .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", }, { // EarlyInjectHook .title = "Inject Early DLL Hooks", .name = "z", .desc = "Equivalent to 'Inject DLL Hooks' option, but ensures hooks are injected before " "the game module has been loaded into the process.", .type = OptionType::Text, .setting_name = "a.dll b.dll c.dll", .category = "Common", }, { .title = "(REMOVED) Execute Lua Script", .name = "script", .desc = "This feature has been removed.", .type = OptionType::Text, .hidden = true, .category = "Miscellaneous", .disabled = true, }, { .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.\n\n" "0 is the primary monitor, 1 is the second monitor, and so on.\n\n" "Not all games will respect this. Not recommended for multi-monitor games like Lightning Model / Valkyrie Model modes. " "Disable Full Screen Optimizations for best results.", .type = OptionType::Integer, .category = "Graphics (Full Screen)", }, { .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 (Full Screen)", }, { .title = "Force Monitor Refresh Rate", .name = "graphics-force-refresh", .desc = "Attempt to change the refresh rate for the primary monitor before the game boots; " "works in both full screen and windowed modes, but known to fail for some games.", .type = OptionType::Integer, .category = "Graphics (Common)", }, { // FullscreenResolution .title = "Force Full Screen Resolution", .name = "forceres", .desc = "For full screen mode, forcibly set a custom resolution.\n\n" "Works great for some games, but can COMPLETELY BREAK other games - YMMV!\n\n" "If you are using -forceresswap/-sdvxlandscape, put the TARGET monitor resolution in this field.\n\n" "This should only be used as last resort if your GPU/monitor can't display the resolution required by the game.", .type = OptionType::Text, .setting_name = "1280,720", .category = "Graphics (Full Screen)" }, { // FullscreenOrientationFlip .title = "Full Screen Orientation Swap (EXPERIMENTAL)", .name = "forceresswap", .desc = "Allows you to play portrait games in in landscape (and vice versa) by transposing resolution and applying image scaling.\n\n" "Works great for some games, but can COMPLETELY BREAK other games - YMMV!\n\n" "Strongly consider combining this with -forceres option to render at monitor native resolution\n\n" "WARNING: for SDVX, this messes with camera angle for note lanes, causing it to be zoomed out, and causes performance issues " "with Live2D!", .type = OptionType::Bool, .hidden = true, .category = "Graphics (Full Screen)" }, { // FullscreenSubRefreshRate .title = "Force Submonitor Refresh Rate (EXPERIMENTAL)", .name = "graphics-force-refresh-sub", .desc = "Override fullscreen refresh rate requested by the game for second monitor, " "useful if you have a sub monitor that is not quite exactly 60Hz.\n\n" "WARNING: experimental as we have not done extensive testing to see if this causes desyncs.", .type = OptionType::Integer, .category = "Graphics (Full Screen)" }, { // Graphics9On12 .title = "DirectX 9 on 12 (DEPRECATED - use -dx9on12 instead)", .name = "9on12", .desc = "Use D3D9On12 wrapper library, requires Windows 10. 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. Has no effect games on that don't use DX9. Can cause some games to crash.\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 = "I/O Options", }, { .title = "Discord Rich Presence", .name = "richpresence", .desc = "Enables Discord Rich Presence support.", .type = OptionType::Bool, .category = "Miscellaneous", }, { .title = "Smart Local 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 = "Local EA Maintenance", .name = "sp2x-eamaint", .display_name = "forceeamaint", .aliases= "forceeamaint", .desc = "Causes local EA to start in maintenance mode. Must be used with -ea or -smartea.", .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 (Development)", .sensitive = true, }, { .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 (Development)", }, { .title = "Disable Network Fixes", .name = "netfixdisable", .desc = "Force disables network fixes.", .type = OptionType::Bool, .category = "Network (Development)", }, { .title = "HTTP/1.1", .name = "http11", .desc = "Sets EA3 http11 value.", .type = OptionType::Enum, .category = "Network (Development)", .elements = {{"0", "Off"}, {"1", "On"}}, }, { .title = "Disable SSL Protocol", .name = "ssldisable", .desc = "Prevents the SSL protocol from being registered.", .type = OptionType::Bool, .category = "Network (Development)", }, { .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 = "Development", .sensitive = true, }, { .title = "(REMOVED) VR controls (experimental)", .name = "vr", .desc = "This feature has been removed.", .type = OptionType::Bool, .hidden = true, .game_name = "DANCERUSH", .category = "Game Options", .disabled = true, }, { // DisableOverlay .title = "Disable Spice Overlay", .name = "overlaydisable", .desc = "Disables the in-game overlay.", .type = OptionType::Bool, .category = "Overlay", }, { // OverlayScaling .title = "Spice Overlay UI Scale %", .name = "overlayscale", .desc = "Forces UI scaling for the overlay, " "things can look off since the UI was written for 100% scaling. " "Enter value in percentage, between 10-400, inclusive.", .type = OptionType::Integer, .setting_name = "200", .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_FpsOpposite .title = "Show FPS/Clock top-left", .name = "fpsflip", .desc = "Show FPS / clock / timer overlay on the top left of the screen instead of the top right.", .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)", }, { // IIDXDisableCameras .title = "IIDX Disable Cameras (DEPRECATED - no longer needed)", .name = "iidxdisablecams", .desc = "Disables cameras.", .type = OptionType::Bool, .hidden = true, .game_name = "Beatmania IIDX", .category = "Game Options", }, { // IIDXCabCamAccess .title = "IIDX Use Official AC Cams", .name = "iidxcabcams", .desc = "For IIDX25+, allow direct access to cameras from real arcade cabinets. " "Only turn this on if you have OFFICIAL arcade cameras connected to the correct USB ports. Default: auto.", .type = OptionType::Enum, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", .elements = { {"auto", ""}, {"off", ""}, {"on", ""} }, }, { // IIDXCamHook .title = "IIDX Cam Hook", .name = "iidxtdjcamhook", .display_name = "iidxcamhook", .aliases = "iidxcamhook", .desc = "Experimental camera support for IIDX 27+ via texture hooking. Requires camera(s) that support YUY2 or NV12 encoding.", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // IIDXCamHookRatio .title = "IIDX Cam Hook Aspect Ratio", .name = "iidxtdjcamhookratio", .display_name = "iidxcamhookratio", .aliases = "iidxcamhookratio", .desc = "Determine what aspect ratio should be preferred for webcam input. Default: 16:9.", .type = OptionType::Enum, .hidden = true, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", .elements = { {"43", "4:3"}, {"169", "16:9"}, }, }, { // IIDXCamHookOverride .title = "IIDX Cam Hook Offset Override", .name = "iidxtdjcamhookoffset", .display_name = "iidxcamhookoffset", .aliases = "iidxcamhookoffset", .desc = "Override DLL offsets for camera hook; " "format: 5 hex values separated by commas " "(offset_hook_a, offset_textures, offset_camera_manager, offset_d3d_device, offset_afp_texture).", .type = OptionType::Text, .setting_name = "0x5817a0,0x6fffbd8,0xbbae40,0xe0,0x30", .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // IIDXCamHookTopId .title = "IIDX Cam Hook Top ID", .name = "iidxtdjcamhooktop", .display_name = "iidxcamhooktop", .aliases = "iidxcamhooktop", .desc = "Specify a partial ID of the camera to use as the TOP camera. Useful if you have more than 3 cameras and need to tell spice which ones to use.\n\n" "To get IDs, launch the game and look for camera IDs from MFEnumDeviceSources.\n\n" "For example, `vid_1234&pid_5678` matches on `\\\\?\\usb#vid_1234&pid_5678&mi_00#7&234123456&1&0000#{e5323777-f976-4f5b-9b55-b94699c46e44}\\global`.", .type = OptionType::Text, .setting_name = "vid_1234&pid_5678", .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // IIDXCamHookFrontId .title = "IIDX Cam Hook Front ID", .name = "iidxtdjcamhookfront", .display_name = "iidxcamhookfront", .aliases = "iidxcamhookfront", .desc = "Specify a partial ID of the camera to use as the FRONT camera. Useful if you have more than 3 cameras and need to tell spice which ones to use.\n\n" "To get IDs, launch the game and look for camera IDs from MFEnumDeviceSources.\n\n" "For example, `vid_1234&pid_5678` matches on `\\\\?\\usb#vid_1234&pid_5678&mi_00#7&234123456&1&0000#{e5323777-f976-4f5b-9b55-b94699c46e44}\\global`.", .type = OptionType::Text, .setting_name = "vid_90ab&pid_cdef", .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.", .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\\ \n\n" "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 Update", .name = "iidxbio2fw", .desc = "Enables BIO2 firmware updates. WARNING - can cause semi-permanent change to your I/O board.", .type = OptionType::Bool, .hidden = true, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { .title = "IIDX TDJ Mode (Lightning Model)", .name = "iidxtdj", .desc = "Enables TDJ mode (Lightning Model cabinet).", .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)", }, { // IIDXDigitalTTSocd .title = "IIDX Digital TT SOCD Cleaner", .name = "iidxsocd", .desc = "SOCD for turntables when using button input; what happens when both directions are pressed.\n\n" "last: most recently pressed direction takes priority\n\n" "first: first pressed direction takes priority\n\n" "neutral (default): TT does not move when both directions are pressed, recommended to avoid excessive POORs.", .type = OptionType::Enum, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", .elements = { {"last", ""}, {"first", ""}, {"neutral", ""}, }, }, { // 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", ""}, }, }, { // IIDXLEDBorderless .title = "IIDX LED Ticker Borderless", .name = "iidxledborderless", .aliases= "iidxledborderless", .desc = "Make LED ticker overlay window borderless (remove window decoration).", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Overlay", }, { .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)", }, { // SDVXPrinterOutputPath .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)", }, { // SDVXPrinterOutputFormat .title = "SDVX Printer Output Format", .name = "printerformat", .desc = "File format for printer output.", .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 (DEPRECATED - no longer needed)", .name = "sdvxdisablecams", .desc = "This option does nothing.\n\n" "This option was used in the past to fix cameras in SDVX5 but this is no longer " "needed as camera check will always be skipped with a built-in patch.", .type = OptionType::Bool, .hidden = true, .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 (Advanced)", }, { // 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)", }, { // SDVXDigitalKnobSocd .title = "SDVX Digital Knob SOCD Cleaner", .name = "sdvxsocd", .desc = "SOCD for knobs when using button input; what happens when both directions are pressed.\n\n" "last (default): most recently pressed direction takes priority, recommended to deal with slams\n\n" "first: first pressed direction takes priority\n\n" "neutral: knob does not move when both directions are pressed.", .type = OptionType::Enum, .game_name = "Sound Voltex", .category = "Game Options (Advanced)", .elements = { {"last", ""}, {"first", ""}, {"neutral", ""}, }, }, { // 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\\ \n\n" "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", ""}, {"bottomleft", "for landscape"}, {"bottomright", "for landscape"}, }, }, { // 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 (Advanced)", }, { .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", }, { // DDRSkipCodecRegisteration .title = "DDR Skip Codec Registration", .name = "ddrnocodec", .desc = "Prevent automatic registration of codecs in the com folder.", .type = OptionType::Bool, .game_name = "Dance Dance Revolution", .category = "Game Options (Advanced)", }, { .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"}}, }, { // GitaDoraArenaSingleWindow .title = "GitaDora Arena Single Window (EXPERIMENTAL)", .name = "gdaonewindow", .desc = "For Arena Model, when combined with windowed mode, only show the main game window; enables subscreen overlay.", .type = OptionType::Bool, .game_name = "GitaDora", .category = "Game Options", }, { // GitaDoraLefty .title = "GitaDora Lefty Guitar (for Digital Wailing)", .name = "gdlefty", .desc = "Enables lefty mode, flipping motion sensor directions. Default: off.\n\n" "Without this option, enabling LEFT in the game option will continuously trigger UP wail.\n\n" "Has no effect if you are using analog bindings for X/Y axis; expectation is that your controller " "handles this correctly (most do not, however).\n\n" "As always, remember to restart the game after changing options. If you need to change in the game, " "use the I/O panel overlay window.", .type = OptionType::Enum, .game_name = "GitaDora", .category = "Game Options", .elements = { {"off", "both righty"}, {"p1", "p1 is lefty"}, {"p2", "p2 is lefty"}, {"both", "both lefty"}, }, }, { // GitaDoraWailHold .title = "GitaDora Digital Wail Hold", .name = "gdwailhold", .desc = "For digital wail input, how long (in milliseconds) to hold the wail state. Practically, this controls " "how sensitive wailing is.\n\n" "Default: 100 (ms)\n\n" "If set to 0, no hold will occur, which means you need to press the wail button longer to register; " "default value of 100ms will cause the game to trigger wail even on a light tap of the button.", .type = OptionType::Integer, .game_name = "GitaDora", .category = "Game Options", }, { // GitaDoraSubOverlaySize .title = "GitaDora Subscreen Overlay Size", .name = "gdsubsize", .desc = "Default size of the subscreen overlay. Default: medium.", .type = OptionType::Enum, .game_name = "GitaDora", .category = "Overlay", .elements = { {"small", ""}, {"medium", ""}, {"large", ""} }, }, { .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 Module", .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 Module", .name = "qks", .desc = "manually enable QuizKnock STADIUM module", .type = OptionType::Bool, .game_name = "QuizKnock STADIUM", .category = "Game Options (Advanced)", }, { // LoadMFGModule .title = "Force Load Mahjong Fight Girl Module", .name = "mfg", .desc = "manually enable Mahjong Fight Girl module.", .type = OptionType::Bool, .game_name = "Mahjong Fight Girl", .category = "Game Options (Advanced)", }, { // LoadPCModule .title = "Force Load Polaris Chord Module", .name = "pc", .desc = "manually enable Polaris Chord module.", .type = OptionType::Bool, .game_name = "Polaris Chord", .category = "Game Options (Advanced)", }, { // LoadMusecaModule .title = "Force Load Museca Module", .name = "museca", .desc = "manually enable Museca module.", .type = OptionType::Bool, .game_name = "Museca", .category = "Game Options (Advanced)", }, { .title = "Modules Folder Override", .name = "modules", .desc = "Sets a custom path to the modules folder.", .type = OptionType::Text, .category = "Path Overrides", }, { .title = "Screenshot Folder Override", .name = "screenshotpath", .desc = "Sets a custom path to the screenshots folder.", .type = OptionType::Text, .category = "Path Overrides", }, { .title = "Configuration Path Override", .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 = "Path Overrides", .disabled = true, }, { // ScreenResizeConfigPath .title = "Screen Resize Config Path Override", .name = "resizecfgpath", .desc = "Sets a custom file path for screen resize config file. " "If left empty, %appdata%\\spice2x\\spicetools_screen_resize.json will be used.", .type = OptionType::Text, .category = "Path Overrides", }, { // PatchManagerConfigPath .title = "Patch Manager Config Path Override", .name = "patchcfgpath", .desc = "Sets a custom file path for patch manager config file. Can be used to manage 'profiles' for auto-patches. " "If left empty, %appdata%\\spice2x\\spicetools_patch_manager.json will be used.", .type = OptionType::Text, .category = "Path Overrides", }, { .title = "Intel SDE", .name = "sde", .desc = "Path to Intel SDE kit path for automatic attaching.", .type = OptionType::Text, .category = "Development", }, { .title = "ea3-config.xml Override", .name = "e", .desc = "Sets a custom path to ea3-config.xml.", .type = OptionType::Text, .category = "Path Overrides", }, { .title = "app-config.xml Override", .name = "a", .desc = "Sets a custom path to app-config.xml.", .type = OptionType::Text, .category = "Path Overrides", }, { .title = "avs-config.xml Override", .name = "v", .desc = "Sets a custom path to avs-config.xml.", .type = OptionType::Text, .category = "Path Overrides", }, { .title = "bootstrap.xml Override", .name = "b", .desc = "Sets a custom path to bootstrap.xml.", .type = OptionType::Text, .category = "Path Overrides", }, { .title = "log.txt Override", .name = "y", .desc = "Sets a custom path to log.txt.", .type = OptionType::Text, .category = "Path Overrides", }, { .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)", }, { // APIScreenMirrorQuality .title = "API Screen Mirror Quality Override", .name = "apiscreenq", .desc = "JPEG compression level of mirrored images, overriding any client request. " "Value must be between 0 (poor quality) and 100 (best quality), inclusive. Default: 70.", .type = OptionType::Integer, .setting_name = "(0-100)", .category = "SpiceCompanion and API", }, { // APIScreenMirrorDivide .title = "API Screen Mirror Divide Override", .name = "apiscreendiv", .desc = "Divide value of mirrored images, overriding any client request. " "Divide of 1 means send every pixel, 2 means every other pixel, 3 means every third pixel, and so on; " "increasing the value drastically reduces transfer size at the cost of image quality. " "Value must be 1 or greater. Default: 1.", .type = OptionType::Integer, .setting_name = "1", .category = "SpiceCompanion and API", }, { .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 AMI2000 Module", .name = "ami2000", .desc = "Manually enable AMI2000 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", }, { // ICCAReaderPort .title = "ICCA Reader Port", .name = "reader", .desc = "Connects to and uses a ICCA on a given COM port.", .type = OptionType::Text, .category = "NFC 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 = "NFC Card Readers", }, { .title = "CardIO HID Reader Support", .name = "cardio", .desc = "Enables detection and support of cardio HID readers.", .type = OptionType::Bool, .category = "NFC Card Readers", }, { .title = "CardIO HID Reader Order Flip", .name = "cardioflip", .desc = "Flips the order of detection for P1/P2.", .type = OptionType::Bool, .category = "NFC 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 = "NFC Card Readers", }, { .title = "HID SmartCard (ACR122U)", .name = "scard", .desc = "Detects and uses HID smart card readers for card input. Developed for ACR122U reader.", .type = OptionType::Bool, .hidden = !WITH_SCARD, .category = "NFC Card Readers", .disabled = !WITH_SCARD, }, { .title = "HID SmartCard Order Flip", .name = "scardflip", .desc = "Flips the order of detection for P1/P2.", .type = OptionType::Bool, .hidden = !WITH_SCARD, .category = "NFC Card Readers", .disabled = !WITH_SCARD, }, { .title = "HID SmartCard Order Toggle", .name = "scardtoggle", .desc = "Toggles reader between P1/P2 using the NumLock key state.", .type = OptionType::Bool, .hidden = !WITH_SCARD, .category = "NFC Card Readers", .disabled = !WITH_SCARD, }, { // HIDSmartCardIdConvert .title = "HID SmartCard Fix UID", .name = "scardfix", .desc = "Modify behavior of SmartCard UID logic.\n\n" "legacy: Preserve buggy old behavior (Default)\n\n" "fix: Add E00401 to non-FeliCa cards, scan FeliCa cards as-is (Recommended for most users)\n\n" "all: Add E00401 to all cards, including FeliCa cards (For really old games only)\n\n" "The algorithm is simple; the prefix is applied, the scanned card number is appended upto 8 bytes, and remaining digits are discarded. " "For example, abcd56780123 is converted to e00401abcd567801 on card in. This results in different card numbers so " "be careful when connecting to servers!", .type = OptionType::Enum, .hidden = !WITH_SCARD, .category = "NFC Card Readers", .elements = { {"legacy", "Use cards as-is"}, {"fix", "Fix bad cards only"}, {"all", "Force all cards"}, }, .disabled = !WITH_SCARD, }, { // SextetStreamPort .title = "SextetStream Port", .name = "sextet", .desc = "Use a SextetStream device on a given COM port.", .type = OptionType::Text, .category = "I/O Options", }, { .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', " "sets v-sync to 'Application Controlled', " "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 (Hacks)", }, { // 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 (Hacks)", }, { .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", "broken, do not use"} }, }, { .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 (Hacks)", }, { // 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 = "AVS Log Level", .name = "loglevel", .desc = "Set the level of detail for AVS log messages written to the log. Does not affect logging from spice.", .type = OptionType::Enum, .category = "Debug Log", .elements = {{"fatal", ""}, {"warning", ""}, {"info", ""}, {"misc", ""}, {"all", ""}, {"disable", ""}}, }, { .title = "EA Automap", .name = "automap", .desc = "Enable automap in patch configuration.", .type = OptionType::Bool, .category = "Network (Development)", }, { .title = "EA Netdump", .name = "netdump", .desc = "Enable automap in network dumping configuration.", .type = OptionType::Bool, .category = "Network (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 = "Debug Log", }, { .title = "Debug CreateFile", .name = "createfiledebug", .desc = "Outputs CreateFile debug prints.", .type = OptionType::Bool, .category = "Debug Log", }, { .title = "Verbose Graphics Logging", .name = "graphicsverbose", .desc = "Enable the verbose logging of graphics hook code.", .type = OptionType::Bool, .category = "Debug Log", }, { .title = "Verbose AVS Logging", .name = "avsverbose", .desc = "Enable the verbose logging of AVS filesystem functions.", .type = OptionType::Bool, .category = "Debug Log", }, { // AllowEA3Verbose .title = "Allow EA3 Verbose Debug Logging", .name = "ea3verbose", .desc = "This option is only useful for network developers; leave this OFF.\n\n" "By default, ea3/debug/verbose node is removed by spice to prevent exposing PCBID in the logs. " "When this is enabled, ea3/debug/verbose node in the XML will be kept and exposed to the game.", .type = OptionType::Bool, .category = "Debug Log", }, { .title = "Disable Colored Output", .name = "nocolor", .desc = "Disable terminal colors for log outputs to console.", .type = OptionType::Bool, .category = "Debug Log", }, { .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", }, { // DisableAvsCache .title = "Disable AVS Cache", .name = "avscachedisable", .desc = "Disable optimization used for some games to cache data file info (only for IIDX32+ for now).", .type = OptionType::Bool, .category = "Development", }, { .title = "Output PEB", .name = "pebprint", .desc = "Prints PEB on startup to console.", .type = OptionType::Bool, .category = "Debug Log", }, { // DumpSystemInfo .title = "Dump System Information", .name = "sysdump", .desc = "Print system information to the log on startup. Default: basic.", .type = OptionType::Enum, .category = "Debug Log", .elements = { {"none", "Nothing"}, {"basic", "OS, CPU, SMBIOS, GPU"}, {"all", "basic + HID devices"}, }, }, { .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", }, { .title = "MFG Arguments Override", .name = "mfgargs", .desc = "Command line arguments passed to the game.", .type = OptionType::Text, .setting_name = "", .game_name = "Mahjong Fight Girl", .category = "Game Options (Advanced)", }, { .title = "MFG Cabinet Type", .name = "mfgcabtype", .desc = "MFG Cabinet Type. Default is HG.", .type = OptionType::Enum, .setting_name = "", .game_name = "Mahjong Fight Girl", .category = "Game Options", .elements = { {"HG", "HG"}, {"B", "B"}, {"C", "C"}, {"UKS", "UKS"}, }, }, { .title = "MFG Disable IO Emulation", .name = "mfgnoio", .desc = "Disables BI2X hooks for MFG.", .type = OptionType::Bool, .setting_name = "", .game_name = "Mahjong Fight Girl", .category = "Game Options (Advanced)" }, { // PCArgs .title = "PC Arguments Override", .name = "pcargs", .desc = "Command line arguments passed to the game.", .type = OptionType::Text, .setting_name = "", .game_name = "Polaris Chord", .category = "Game Options (Advanced)", }, { // PCNoIO .title = "PC Disable IO Emulation", .name = "pcnoio", .desc = "Disables BI2X hooks for PC.", .type = OptionType::Bool, .setting_name = "", .game_name = "Polaris Chord", .category = "Game Options (Advanced)" }, { // PCKnobMode .title = "PC Fader Knobs Mode", .name = "pcknobs", .desc = "Allows SDVX knobs and IIDX turntables to be bound as Polaris Chord faders.", .type = OptionType::Bool, .game_name = "Polaris Chord", .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 = "I/O 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)", }, { // WindowForceScaling .title = "Window Forced Render Scaling", .name = "windowscale", .desc = "For windowed mode: forcibly set DX9 back buffer dimensions to match window size. " "Reduces pixelated scaling artifacts. Works great for some games, but can COMPLETELY BREAK other games - YMMV!", .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)", }, { // IIDXWindowedSubscreenBorderless .title = "IIDX Windowed Subscreen Borderless", .name = "iidxwsubborderless", .desc = "Remove window decoration from windowed subscreen.", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Graphics (Windowed)", }, { // IIDXWindowedSubscreenAlwaysOnTop .title = "IIDX Windowed Subscreen Always On Top", .name = "iidxwsubtop", .desc = "Keep windowed subscreen on top.", .type = OptionType::Bool, .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 (Hacks)", }, { // 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", }, { // DRSRGBCameraHook .title = "DRS RGB Camera Hook", .name = "drsrgbcamhook", .desc = "Hook into the RGB camera detection and attempt to use your own non-official webcam. " "Not every webcam will be compatible with this; YMMV.\n\n" "Note: this is NOT for the motion camera - you still need a real RealSense camera for that!", .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 (Advanced)", }, { // 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 shows/hides the keypad.", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // 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. " "Default: mid.", .type = OptionType::Enum, .category = "I/O 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", }, { // SDVXFullscreenLandscape .title = "(DISABLED) SDVX Landscape Mode (SDVX5+)", .name = "sdvxlandscape", .desc = "Option HIDDEN and DISABLED due to it affecting in-game camera angle for displaying lanes.\n\n" "Allows you to play in landscape by transposing resolution and applying image scaling.\n\n" "Works only for SDVX5 and above! This is identical to -forceresswap.\n\n" "Will launch at 1080p by default; strongly consider combining this with -forceres option to render at monitor native resolution.", .type = OptionType::Bool, .hidden = true, .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 = "I/O Options", }, { // spice2x_EnableSMXDedicab .title = "StepManiaX Dedicated Cabinet Lighting Support", .name = "sp2x-smx-dedicab", .display_name = "smxdedicab", .aliases = "smxdedicab", .desc = "StepManiaX Dedicated Cabinet 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 = "I/O Options" }, { // IIDXRecQuality .title = "IIDX Recording Quality", .name = "iidxreccqp", .desc = "WARNING: double check if your network allows this & your hardware supports it.\n\n" "For TDJ Play Record feature, specify ConstQP quality settings for NVENC. Lower is higher quality but bigger file.\n\n" "Two options: specify a single number (20) to set CQ Level, or specify comma-separated numbers (23,25,20) to set P, B, I levels.", .type = OptionType::Text, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // IIDXRecDisable .title = "IIDX Recording Force Disable", .name = "iidxnorec", .desc = "When enabled, this prevents the play record feature from being used.", .type = OptionType::Bool, .game_name = "Beatmania IIDX", .category = "Game Options (Advanced)", }, { // MidiAlgoVer .title = "MIDI Note Input Algorithm", .name = "midialgo", .desc = "Remember to restart after changing this value.\n\n" "Switch algorithm used for MIDI note handling.\n\n" "auto (default): use v2 for most games, v2_drum for DrumMania and FutureTomTom\n\n" "v2: new delta-time logic in spice2x, timestamp every on/off events and apply min. sustain period to rapid on/off triggers, supports velocity threshold\n\n" "v2_drum: same as v2, but disable holds; better for some drum kits\n\n" "legacy: legacy poll-based spicetools logic, may behave incorrectly when the same input is mapped to multiple buttons, no support for velocity threshold.", .type = OptionType::Enum, .category = "I/O Options", .elements = { {"auto", ""}, {"v2", ""}, {"v2_drum", ""}, {"legacy", ""}, }, }, { // MidiNoteSustain .title = "MIDI Note Min. Sustain", .name = "midisustain", .desc = "Remember to restart after changing this value. Only affects v2 MIDI algorithm. Does not affect spicecfg.\n\n" "Set the minimum duration (in milliseconds) each note is sustained, so that the game's I/O can pick up the input when polled.\n\n" "If this is too short, when game polls for input, it may fail to observe quick input (such as drums). " "If this is too long, rapid hits may be dropped due to coalescing.\n\n" "Recommended to keep at default of 20ms unless you have issues.", .type = OptionType::Integer, .setting_name = "20", .category = "I/O Options", }, { // DDRP4IOBufferMode .title = "DDR P4IO Buffer Algorithm", .name = "ddrp4iobuffer", .desc = "Remember to restart after changing this value.\n\n" "Sets the algorithm used to populate entries to the buffer of controller polls read by the game.\n\n" "auto (default): thread mode if <120Hz, backfill if >=120Hz\n\n" "thread: starts a thread to periodically insert polls into the buffer\n\n" "backfill: fills the buffer on each frame with last known state info at short regular intervals up to the current time, then writes the current state.\n\n" "Only has an effect when emulating P4IO (arkmdxp4.dll).", .type = OptionType::Enum, .game_name = "Dance Dance Revolution", .category = "Game Options (Advanced)", .elements = { {"auto", ""}, {"thread", ""}, {"backfill", ""}, }, }, { // InputRequiresFocus .title = "Input Requires Focus", .name = "inputfocus", .desc = "Determine input behavior when game window is not in focus.\n\n" "never: allow input regardless of focus\n" "naive (default): only naive bindings check for window focus, rawinput binds are always allowed\n" "always: only process input when window is in focus.", .type = OptionType::Enum, .category = "I/O Options", .elements = { {"never", ""}, {"naive", ""}, {"always", ""}, }, }, { // NostalgiaPoke .title = "Nost Screen Poke", .name = "nostpoke", .desc = "Enables emulation of touch gestures to make it easier to navigate the game without a touchscreen.\n\n" "This enables two things:\n" " 1. Swipe/Touch bindings in Buttons tab (Swipe Next Page, etc)\n" " 2. PIN pad bindings (make sure Unscramble Keypad patch is applied)).", .type = OptionType::Bool, .game_name = "Nostalgia", .category = "Game Options", }, { // ForceBackBufferCount .title = "V-Sync Buffering", .name = "vsyncbuffer", .desc = "Using triple buffering may improve cases of micro-stuttering but increases input latency.", .type = OptionType::Enum, .category = "Graphics (Common)", .elements = { {"2", "double buffer"}, {"3", "triple buffer"}, }, }, { // SDVXWindowedSubscreenSize .title = "SDVX Windowed Subscreen Size", .name = "sdvxwsubsize", .desc = "Size of the subscreen window. Defaults to (1920,1080).", .type = OptionType::Text, .setting_name = "1920,1080", .game_name = "Sound Voltex", .category = "Graphics (Windowed)", }, { // SDVXWindowedSubscreenPosition .title = "SDVX Windowed Subscreen Position", .name = "sdvxwsubpos", .desc = "Initial position of the subscreen window. Defaults to (0,0).", .type = OptionType::Text, .setting_name = "0,0", .game_name = "Sound Voltex", .category = "Graphics (Windowed)", }, { // SDVXWindowedSubscreenBorderless .title = "SDVX Windowed Subscreen Borderless", .name = "sdvxwsubborderless", .desc = "Remove window decoration from windowed subscreen.", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Graphics (Windowed)", }, { // SDVXWindowedSubscreenAlwaysOnTop .title = "SDVX Windowed Subscreen Always On Top", .name = "sdvxwsubtop", .desc = "Keep windowed subscreen on top.", .type = OptionType::Bool, .game_name = "Sound Voltex", .category = "Graphics (Windowed)", }, { // LovePlusCamEnable .title = "LovePlus Camera Enable", .name = "lovepluscam", .desc = "Allow game to access camera; camera must be compatible with game.", .type = OptionType::Bool, .game_name = "LovePlus", .category = "Game Options", }, { // LovePlusPrinterOutputPath .title = "LovePlus Printer Output Path", .name = "lpprinterpath", .desc = "Path to folder where images will be stored.", .type = OptionType::Text, .game_name = "LovePlus", .category = "Game Options (Advanced)", }, { .title = "LovePlus Printer Output Clear", .name = "lpprinterclear", .desc = "Clean up saved images in the output directory on startup.", .type = OptionType::Bool, .game_name = "LovePlus", .category = "Game Options (Advanced)", }, { .title = "LovePlus Printer Output Overwrite", .name = "lpprinteroverwrite", .desc = "Always overwrite the same file in output directory.", .type = OptionType::Bool, .game_name = "LovePlus", .category = "Game Options (Advanced)", }, { // LovePlusPrinterOutputFormat .title = "LovePlus Printer Output Format", .name = "lpprinterformat", .desc = "File format for printer output.", .type = OptionType::Text, .setting_name = "(png/bmp/tga/jpg)", .game_name = "LovePlus", .category = "Game Options (Advanced)", }, { .title = "LovePlus Printer JPG Quality", .name = "lpprinterjpgquality", .desc = "Quality setting in percent if JPG format is used.", .type = OptionType::Integer, .setting_name = "(0-100)", .game_name = "LovePlus", .category = "Game Options (Advanced)", }, { // OptionConflictResolution .title = "Command Line Args Override", .name = "cmdoverride", .desc = "By default, option values in spicecfg take precedence over command-line args, for legacy compat.\n" "When this is specified in command line, command-line args take precedence instead.", .type = OptionType::Bool, .category = "Development", .disabled = true, } }; 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 { auto _ = 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