diff --git a/common/hooklib/path.c b/common/hooklib/path.c index f480c63..0480e77 100644 --- a/common/hooklib/path.c +++ b/common/hooklib/path.c @@ -200,6 +200,14 @@ static UINT WINAPI hook_GetDriveTypeW( LPCWSTR lpRootPathName ); +static BOOL WINAPI hook_GetDiskFreeSpaceW( + LPCWSTR lpRootPathName, + LPDWORD lpSectorsPerCluster, + LPDWORD lpBytesPerSector, + LPDWORD lpNumberOfFreeClusters, + LPDWORD lpTotalNumberOfClusters +); + /* Link pointers */ static BOOL (WINAPI *next_CreateDirectoryA)( @@ -395,6 +403,14 @@ static UINT (WINAPI *next_GetDriveTypeA)( LPCSTR lpRootPathName ); +static BOOL (WINAPI *next_GetDiskFreeSpaceW)( + LPCWSTR lpRootPathName, + LPDWORD lpSectorsPerCluster, + LPDWORD lpBytesPerSector, + LPDWORD lpNumberOfFreeClusters, + LPDWORD lpTotalNumberOfClusters +); + /* Hook table */ static const struct hook_symbol path_hook_syms[] = { @@ -538,6 +554,10 @@ static const struct hook_symbol path_hook_syms[] = { .name = "GetDriveTypeW", .patch = hook_GetDriveTypeW, .link = (void **) &next_GetDriveTypeW, + }, { + .name = "GetDiskFreeSpaceW", + .patch = hook_GetDiskFreeSpaceW, + .link = (void **) &next_GetDiskFreeSpaceW, } }; @@ -1720,6 +1740,30 @@ static UINT WINAPI hook_GetDriveTypeW( return result; } +static BOOL WINAPI hook_GetDiskFreeSpaceW( + LPCWSTR lpRootPathName, + LPDWORD lpSectorsPerCluster, + LPDWORD lpBytesPerSector, + LPDWORD lpNumberOfFreeClusters, + LPDWORD lpTotalNumberOfClusters +) { + wchar_t *trans; + UINT result; + BOOL ok; + + ok = path_transform_w(&trans, lpRootPathName); + + if (!ok) { + return FALSE; + } + + result = next_GetDiskFreeSpaceW(trans ? trans : lpRootPathName, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters); + + free(trans); + + return result; +} + char** str_split_a(char* a_str, const char a_delim) { char** result = 0; size_t count = 0; diff --git a/common/hooklib/printer_chc.c b/common/hooklib/printer_chc.c index 0100f2f..4d28b28 100644 --- a/common/hooklib/printer_chc.c +++ b/common/hooklib/printer_chc.c @@ -60,6 +60,7 @@ static int32_t MTF[9]; /* Printer status */ static uint8_t STATUS = 0; +static uint8_t printSide = 0; static ULONGLONG finishTime = 0; /* C3XXFWDLusb API hooks */ @@ -150,7 +151,7 @@ int WINAPI chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult); int WINAPI chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult); int WINAPI chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult); int WINAPI chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult); -int WINAPI chcusb_writeIred(uint8_t* a1, uint8_t* a2, uint16_t* rResult); +int WINAPI chcusb_writeIred(uint8_t* data, uint32_t* len, uint16_t* rResult); /* PrintDLL API hooks */ @@ -2375,6 +2376,7 @@ int WINAPI chcusb_endpage(uint16_t *rResult) { dprintf("Printer: Waiting for %dms...\n", printer_config.wait_time); } awaitingCardExit = true; + printSide = 0; *rResult = 0; return 1; @@ -2388,8 +2390,8 @@ int WINAPI chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { uint8_t metadata[44]; swprintf_s( dumpPath, MAX_PATH, - L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d.bmp", - printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); + L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d_%d.bmp", + printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, printSide); memcpy(metadata, cardRFID, 12); memcpy(metadata + 12, cardDataBuffer, 32); @@ -2399,6 +2401,8 @@ int WINAPI chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); dwprintf(L"Printer: File written: %s\n", dumpPath); + printSide++; + *rResult = 0; return 1; @@ -3074,8 +3078,21 @@ void printer_set_dimensions(int width, int height){ HEIGHT = height; } -int WINAPI chcusb_writeIred(uint8_t* a1, uint8_t* a2, uint16_t* rResult) { +int WINAPI chcusb_writeIred(uint8_t* data, uint32_t* len, uint16_t* rResult) { + dprintf("Printer: C3XXusb: %s(%d)\n", __func__, *len); + + SYSTEMTIME t; + GetLocalTime(&t); + + wchar_t dumpPath[MAX_PATH]; + swprintf_s( + dumpPath, MAX_PATH, + L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d_ir.bmp", + printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); + + WriteDataToBitmapFile(dumpPath, 8, WIDTH, HEIGHT, data, HOLO_SIZE, NULL, 0, rotate180); dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; return 1; } diff --git a/common/hooklib/reg.c b/common/hooklib/reg.c index d4a3bc3..27a6ba0 100644 --- a/common/hooklib/reg.c +++ b/common/hooklib/reg.c @@ -12,12 +12,15 @@ #include "util/dprintf.h" #include "util/str.h" +#define MAX_CONCURRENT_REG_HANDLES 4 + struct reg_hook_key { HKEY root; const wchar_t *name; const struct reg_hook_val *vals; size_t nvals; - HKEY handle; + HKEY handles[MAX_CONCURRENT_REG_HANDLES]; + size_t nhandles; }; /* Helper functions */ @@ -344,7 +347,7 @@ static LRESULT reg_hook_propagate_hr(HRESULT hr) static struct reg_hook_key *reg_hook_match_key_locked(HKEY handle) { struct reg_hook_key *key; - size_t i; + size_t i, j; if (handle == NULL || handle == INVALID_HANDLE_VALUE) { return NULL; @@ -353,8 +356,10 @@ static struct reg_hook_key *reg_hook_match_key_locked(HKEY handle) for (i = 0 ; i < reg_hook_nkeys ; i++) { key = ®_hook_keys[i]; - if (key->handle == handle) { - return key; + for (j = 0; j < key->nhandles; j++) { + if (key->handles[j] == handle) { + return key; + } } } @@ -414,9 +419,9 @@ static LSTATUS reg_hook_open_locked( return ERROR_SUCCESS; } - /* Assume only one handle will be open at a time */ + /* Assume only MAX_CONCURRENT_REG_HANDLES handles will be open at a time */ - if (key->handle != NULL) { + if (key->nhandles > MAX_CONCURRENT_REG_HANDLES) { return ERROR_SHARING_VIOLATION; } @@ -433,7 +438,7 @@ static LSTATUS reg_hook_open_locked( out); if (err == ERROR_SUCCESS) { - key->handle = *out; + key->handles[key->nhandles++] = *out; } return err; @@ -511,16 +516,22 @@ static LSTATUS WINAPI hook_RegCreateKeyExW( static LSTATUS WINAPI hook_RegCloseKey(HKEY handle) { struct reg_hook_key *key; - size_t i; + size_t i, j, k; EnterCriticalSection(®_hook_lock); for (i = 0 ; i < reg_hook_nkeys ; i++) { key = ®_hook_keys[i]; - if (key->handle == handle) { - //dprintf("Registry: Closed virtual key %S\n", key->name); - key->handle = NULL; + for (j = 0; j < key->nhandles; j++) { + if (key->handles[j] == handle) { + for (k = j; k < MAX_CONCURRENT_REG_HANDLES - 1; k++) { + key->handles[k] = key->handles[k + 1]; + } + key->handles[MAX_CONCURRENT_REG_HANDLES - 1] = NULL; + key->nhandles--; + //dprintf("Registry: Closed virtual key %S\n", key->name); + } } } diff --git a/common/platform/config.c b/common/platform/config.c index 75969bb..84268d0 100644 --- a/common/platform/config.c +++ b/common/platform/config.c @@ -170,6 +170,13 @@ void misc_config_load(struct misc_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"misc", L"enable", 1, filename); cfg->allowMasterKeyWrite = GetPrivateProfileIntW(L"misc", L"allowMasterKeyWrite", 0, filename); cfg->allowReboot = GetPrivateProfileIntW(L"misc", L"allowReboot", 0, filename); + GetPrivateProfileStringW( + L"misc", + L"nextProcessFilePath", + L"DEVICE\\NextProcess.txt", + cfg->nextProcessFile, + _countof(cfg->nextProcessFile), + filename); } void netenv_config_load(struct netenv_config *cfg, const wchar_t *filename) @@ -346,6 +353,7 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"vfs", L"enable", 1, filename); + cfg->allowAmfsDownloads = GetPrivateProfileIntW(L"vfs", L"allowAmfsDownloads", 0, filename); GetPrivateProfileStringW( L"vfs", diff --git a/common/platform/dns.c b/common/platform/dns.c index c10e0d0..3ad0d0a 100644 --- a/common/platform/dns.c +++ b/common/platform/dns.c @@ -177,15 +177,15 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } - // Disable api/polling to the original servers + // ABaaS log server, receives system and error logs stored in appdata - hr = dns_hook_push(L"*.amlog.sys-all.net", NULL); + hr = dns_hook_push(L"*.amlog.sys-all.net", cfg->startup); if (FAILED(hr)) { return hr; } - hr = dns_hook_push(L"*.d-amlog.sys-all.net", NULL); + hr = dns_hook_push(L"*.d-amlog.sys-all.net", cfg->startup); if (FAILED(hr)) { return hr; diff --git a/common/platform/misc.c b/common/platform/misc.c index 9ede751..9d447fb 100644 --- a/common/platform/misc.c +++ b/common/platform/misc.c @@ -12,6 +12,8 @@ #include "platform/misc.h" +#include + #include "util/dprintf.h" static BOOL WINAPI misc_ExitWindowsEx(unsigned int flags, uint32_t reason); @@ -22,6 +24,11 @@ static HRESULT misc_read_cpu_temp_error(void *bytes, uint32_t *nbytes); static HRESULT misc_read_cpu_temp_warning(void *bytes, uint32_t *nbytes); static HRESULT misc_read_platform_id(void *bytes, uint32_t *nbytes); static HRESULT misc_read_platform_name(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_main_nic(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_extend_nic(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_downloadui_done(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_next_process(void *bytes, uint32_t *nbytes); +static HRESULT misc_write_next_process(const void *bytes, uint32_t nbytes); static const struct hook_symbol misc_syms[] = { { @@ -44,11 +51,12 @@ static const struct reg_hook_val misc_master_keys[] = { .read = misc_read_app_loader_count, .type = REG_DWORD, }, { - /* Black-hole val, list it here so we don't get a warning msg */ .name = L"NextProcess", + .read = misc_read_next_process, + .write = misc_write_next_process, .type = REG_SZ, }, { - /* ditto */ + /* Black-hole val for reading, list it here so we don't get a warning msg */ .name = L"SystemError", .type = REG_SZ, } @@ -74,7 +82,28 @@ static const struct reg_hook_val misc_static_keys[] = { } }; +static const struct reg_hook_val misc_wireless_keys[] = { + { + .name = L"main_nic", + .read = misc_read_main_nic, + .type = REG_DWORD, + }, { + .name = L"extend_nic", + .read = misc_read_extend_nic, + .type = REG_DWORD, + } +}; + +static const struct reg_hook_val misc_downloadui_keys[] = { + { + .name = L"IsDone", + .read = misc_read_downloadui_done, + .type = REG_DWORD, + }, +}; + static wchar_t misc_platform_id[5]; +static const struct misc_config *config; HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id) { @@ -83,6 +112,8 @@ HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id) assert(cfg != NULL); assert(platform_id != NULL && strlen(platform_id) == 4); + config = cfg; + if (!cfg->enable) { return S_FALSE; } @@ -124,8 +155,29 @@ HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id) L"SYSTEM\\SEGA\\SystemProperty\\Master", misc_master_keys, _countof(misc_master_keys)); + + if (FAILED(hr)) { + return hr; + } } + hr = reg_hook_push_key( + HKEY_LOCAL_MACHINE, + L"SYSTEM\\SEGA\\SystemProperty\\wirelessNetwork", + misc_wireless_keys, + _countof(misc_wireless_keys)); + + if (FAILED(hr)) { + return hr; + } + + hr = reg_hook_push_key( + HKEY_LOCAL_MACHINE, + L"SYSTEM\\SEGA\\SystemProperty\\downloadui", + misc_downloadui_keys, + _countof(misc_downloadui_keys)); + + if (FAILED(hr)) { return hr; } @@ -136,6 +188,10 @@ HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id) hook_table_apply(NULL, "user32.dll", misc_syms, _countof(misc_syms)); } + if (PathFileExistsW(cfg->nextProcessFile)) { + DeleteFileW(cfg->nextProcessFile); + } + return S_OK; } @@ -175,3 +231,47 @@ static HRESULT misc_read_platform_name(void *bytes, uint32_t *nbytes) { return reg_hook_read_wstr(bytes, nbytes, L"ALLS MX2.1"); // TODO: Dynamic } + +static HRESULT misc_read_main_nic(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L""); +} + +static HRESULT misc_read_extend_nic(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L""); +} + +static HRESULT misc_read_downloadui_done(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_u32(bytes, nbytes, 1); +} + +static HRESULT misc_read_next_process(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L""); +} + +static HRESULT misc_write_next_process(const void *bytes, uint32_t nbytes) +{ + HRESULT hr; + DWORD dwBytesWritten; + + wchar_t* nextProcess = malloc(nbytes); + memcpy(nextProcess, bytes, nbytes); + + dprintf("Misc: Next Process: %ls\n", nextProcess); + + HANDLE hFile = CreateFileW(config->nextProcessFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("Misc: Error opening %ls for writing: %x\n", config->nextProcessFile, (int) hr); + return hr; + } + + WriteFile(hFile, nextProcess, nbytes, &dwBytesWritten, NULL); + + CloseHandle(hFile); + + return S_OK; +} \ No newline at end of file diff --git a/common/platform/misc.h b/common/platform/misc.h index e9695bc..dfc2241 100644 --- a/common/platform/misc.h +++ b/common/platform/misc.h @@ -8,6 +8,7 @@ struct misc_config { bool enable; bool allowReboot; bool allowMasterKeyWrite; + wchar_t nextProcessFile[MAX_PATH]; }; HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id); diff --git a/common/platform/vfs.c b/common/platform/vfs.c index ae5953e..1cfc5bd 100644 --- a/common/platform/vfs.c +++ b/common/platform/vfs.c @@ -41,6 +41,10 @@ static HRESULT vfs_custom_path_hook( const wchar_t *src, wchar_t *dest, size_t *count); +static HRESULT vfs_path_hook_tmp_icf( + const wchar_t *src, + wchar_t *dest, + size_t *count); static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); @@ -77,6 +81,9 @@ static const size_t vfs_option_len = _countof(vfs_option) - 1; static const wchar_t vfs_apm3[] = L"C:\\Mount\\Apm"; static const size_t vfs_apm3_len = _countof(vfs_apm3) - 1; +static const wchar_t vfs_tmp_icf[] = L"E:\\tmpIcf.icf"; +static const size_t vfs_tmp_icf_len = _countof(vfs_tmp_icf) - 1; + static const struct reg_hook_val vfs_reg_vals[] = { { .name = L"AMFS", @@ -168,6 +175,12 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id) vfs_fixup_path(vfs_config.option, _countof(vfs_config.option), true); } + hr = path_hook_push(vfs_path_hook_tmp_icf); + + if (FAILED(hr)) { + return hr; + } + hr = vfs_mkdir_rec(vfs_config.amfs); if (FAILED(hr)) { @@ -601,6 +614,29 @@ static HRESULT vfs_path_hook_apm( return S_OK; } +// Block writing of E:\tmpIcf.icf to intentionally break the download process if the user has not enabled it +static HRESULT vfs_path_hook_tmp_icf( + const wchar_t *src, + wchar_t *dest, + size_t *count) +{ + assert(src != NULL); + assert(count != NULL); + + /* Case-insensitive check to see if src starts with vfs_tmp_icf */ + + if (path_compare_w(src, vfs_tmp_icf, vfs_tmp_icf_len) != 0) { + return S_FALSE; + } + + if (vfs_config.allowAmfsDownloads) { + return S_FALSE; + } + + dprintf("Vfs: AMFS downloads are blocked\n"); + return E_FAIL; +} + static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes) { return reg_hook_read_wstr(bytes, nbytes, L"E:\\"); diff --git a/common/platform/vfs.h b/common/platform/vfs.h index 9ff8111..87a2d3e 100644 --- a/common/platform/vfs.h +++ b/common/platform/vfs.h @@ -15,6 +15,7 @@ struct vfs_config { wchar_t redirections_from[MAX_REDIRECTIONS][MAX_PATH]; int redirections_from_len[MAX_REDIRECTIONS]; wchar_t redirections_to[MAX_REDIRECTIONS][MAX_PATH]; + bool allowAmfsDownloads; }; HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id); diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index b833a1a..b1739f7 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -111,8 +111,9 @@ framed=0 dpiAware=1 [touch] -; WinTouch emulation setting. +; WinTouch emulation setting. (set to 0 for native touchscreens) enable=1 +; Enable coordinate remapping (set to 0 if windowed mode cursor offset occurs) remap=1 cursor=1 @@ -178,7 +179,7 @@ coin=0x72 mode=xinput [xinput] -; XInput bindings +; XInput bindings ; ; Left Stick Joystick ; Left Stick Click Reset Camera @@ -201,13 +202,13 @@ down=0x53 left=0x41 right=0x44 -; Dash button. Default is the Left Shift, +; Dash button. Default is the Left Shift, dash=0xA0 ; Cycle Target button. Default is the F key. target=0x46 -; Attack button, Default is the Right Mouse Button. +; Attack button, Default is the Right Mouse Button. attack=0x02 -; Noble Phantasm button. Default is the Spacebar +; Noble Phantasm button. Default is the Spacebar np=0x20 ; Center Camera, Default is the C key camera=0x43 diff --git a/doc/config/common.md b/doc/config/common.md index 920905b..cc2972b 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -59,7 +59,7 @@ This is required for some games (e.g. Chunithm) but not others (e.g. WACCA). Default: `1` -Changes the Aime card reader generation, this will also change the LED info +Changes the Aime card reader generation, this will also change the LED info provided for the game. - `1`: TN32MSEC003S H/W Ver3.0 / TN32MSEC003S F/W Ver1.2 @@ -198,7 +198,7 @@ resolves to one). Default: `title` -Leave it as `title` to use the title server returned by ALL.Net. Rewrites +Leave it as `title` to use the title server returned by ALL.Net. Rewrites the title server hostname for certain games, such as crossbeats REV. ### `router` @@ -485,9 +485,9 @@ integer `modelType` setting, but they are combined here for convenience. - `ACA`: ALLS UX/HX/MX `modelType` is one of the following: -- `1`: Server (SV) -- `2`: Satalite (ST) -- `3`: Live (LV) +- `1`: Server (SV) +- `2`: Satalite (ST) +- `3`: Live (LV) - `4`: Terminal (TN) It's safe to assume that every game you'll be playing with these tools will be a Satalite. @@ -513,7 +513,7 @@ Values are: Default: `DEVICE\\ca.crt` -Set the billing certificate path. This has to match the one used for the +Set the billing certificate path. This has to match the one used for the SSL billing server. The DER certificate must fit in 1024 bytes so it must be small. @@ -643,6 +643,28 @@ Default `DEVICE\sram.bin` Path to the storage file for SRAM emulation. +### `[touch]` + +Configure WinTouch emulation for mouse input. + +#### `enable` + +Default: `1` + +Enable WinTouch touchscreen emulation for the mouse. Disable to use a native WinTouch-compatible touchscreen. + +#### `remap` + +Default: `1` + +Enable coordinate remapping. Disable this if you running in windowed mode and find the touch position shifted when moving the window. + +#### `cursor` + +Default: `1` + +Display a cursor to indicate touch position. + ## `[vfs]` Configure Windows path redirection hooks. @@ -693,6 +715,12 @@ redirection0from=\\.\COM5 redirection0to=\\.\COM10 ``` +### `allowAmfsDownloads` + +Default: `0` + +Allows network services to download arbitrary files to the AMFS directory specified above. This has security implications, do not enable this, unless you trust your server operator. + ## `[epay]` Configure Thinca Payment (E-Money) emulation and hooks. @@ -756,7 +784,7 @@ The Windows directory is always excluded from virtualization. ## `[misc]` -Configure miscellaneous hooks and features. +Configure miscellaneous hooks and features. ### `allowMasterKeyWrite` @@ -769,3 +797,13 @@ Allows the game to write to specific registry keys relevant for the boot process Default: `0` Allows the game to reboot the computer. Only intended for owners of real hardware. + +### `nextProcessFilePath` + +Default: `DEVICE\NextProcess.txt` + +This is a file that will be set to the content of what would be written to the `NextProcess` registry key when the game is terminated. + +This allows whatever executed the game process to react what should happen next (System Test Mode selected, network delivery completed, ...) without requiring admin permissions. + +The file is deleted on startup of segatools. \ No newline at end of file diff --git a/docker-build.bat b/docker-build.bat index 822dc9b..5f17f4b 100644 --- a/docker-build.bat +++ b/docker-build.bat @@ -12,7 +12,7 @@ if ERRORLEVEL 1 ( goto failure ) -docker run -it --rm -v %~dp0:/segatools --name %CONTAINER_NAME% %IMAGE_NAME% +docker run -it --rm -v "%~dp0:/segatools" --name %CONTAINER_NAME% %IMAGE_NAME% if ERRORLEVEL 1 ( goto failure diff --git a/games/idacio/di-dev.c b/games/idacio/di-dev.c index c3b7bcc..a7758df 100644 --- a/games/idacio/di-dev.c +++ b/games/idacio/di-dev.c @@ -32,8 +32,8 @@ static uint8_t idac_di_rumble_duration; static uint8_t idac_di_base_damper; static uint8_t idac_di_deadband; -/* Fixed spring boost multiplier (1.5x) */ -static const float idac_di_spring_boost = 1.5f; +/* Fixed spring boost multiplier */ +static const float idac_di_spring_boost = 1.0f; HRESULT idac_di_dev_init(const struct idac_di_config* cfg, IDirectInputDevice8W* dev, HWND wnd) { diff --git a/games/idzio/di-dev.c b/games/idzio/di-dev.c index c0a5cff..84fc364 100644 --- a/games/idzio/di-dev.c +++ b/games/idzio/di-dev.c @@ -31,8 +31,8 @@ static uint8_t idz_di_rumble_duration; static uint8_t idz_di_base_damper; static uint8_t idz_di_deadband; -/* Fixed spring boost multiplier (1.5x) */ -static const float idz_di_spring_boost = 1.5f; +/* Fixed spring boost multiplier */ +static const float idz_di_spring_boost = 1.0f; HRESULT idz_di_dev_init(const struct idz_di_config* cfg, IDirectInputDevice8W* dev, HWND wnd) { diff --git a/games/swdcio/di-dev.c b/games/swdcio/di-dev.c index 9c5a6c8..2343347 100644 --- a/games/swdcio/di-dev.c +++ b/games/swdcio/di-dev.c @@ -32,8 +32,8 @@ static uint8_t swdc_di_rumble_duration; static uint8_t swdc_di_base_damper; static uint8_t swdc_di_deadband; -/* Fixed spring boost multiplier (1.5x) */ -static const float swdc_di_spring_boost = 1.5f; +/* Fixed spring boost multiplier */ +static const float swdc_di_spring_boost = 1.0f; HRESULT swdc_di_dev_init(const struct swdc_di_config* cfg, IDirectInputDevice8W* dev, HWND wnd) {