diff --git a/bindings.ini b/bindings.ini index 902f623748..6add482c64 100644 --- a/bindings.ini +++ b/bindings.ini @@ -92,23 +92,34 @@ F = Y R = A Space = X V = LB -1 = Up -2 = Down -3 = Left -4 = Right +X = Up Z = Down +Left = Left +Right = Right +T = Left +Y = Right LShift = RB ;Tidle on US keyboard "`" ' = Start Enter = Start ;Back is unused but for any mods that utilize it. P = Back -Up = RS-Up -Down = RS-Down -Left = RS-Left -Right = RS-Right +O = RS-Up +L = RS-Down +k = RS-Left +; = RS-Right B = RS H = RS +1 = weapon1 +2 = weapon2 +3 = weapon3 +4 = weapon4 +5 = weapon5 +6 = weapon6 +7 = weapon7 +8 = weapon8 +9 = weapon9 +0 = weapon10 [545107D1 Vehicle - Saints Row 1] W = A @@ -119,9 +130,8 @@ Q = LB E = RB CapsLock = RS Ctrl = LS -C = LS B = RS -H = RS +H = LS LClick = RT RClick = LT Mouse5 = B @@ -129,24 +139,33 @@ Tab = B F = Y R = A Space = LT -V = LB -1 = Up -2 = Down -3 = Left -4 = Right +X = Up Z = Down -MWheelDown = Left -MWheelUp = Right +Left = Left +Right = Right +C = Left +V = Right +T = Left +Y = Right LShift = RB ;Tidle on US keyboard "`" ' = Start Enter = Start ;Back is unused but for any mods that utilize it. P = Back -Up = RS-Up -Down = RS-Down -Left = RS-Left -Right = RS-Right +O = RS-Up +L = RS-Down +k = RS-Left +; = RS-Right +1 = weapon1 +2 = weapon2 +3 = weapon3 +4 = weapon4 +5 = weapon5 +6 = weapon6 +7 = weapon7 +8 = weapon8 +9 = weapon9 [555307DC Default - Far Cry Instincts Predator] CapsLock = Modifier diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index ade5ba1b1d..806b7d2885 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -99,12 +99,6 @@ DEFINE_bool( "(Saints Row 2) Switches fineaim (ADS) from a toggle to hold press.", "MouseHook"); -DEFINE_bool(sr_havok_fix_frametime, false, - "(Saints Row 1&2) Fixes cutscene object synchronization and doors " - "teleporting on high fps, as seen in Juiced Patch. (Causes " - "Performance loss at a higher FPSes.) ", - "MouseHook"); - DEFINE_bool(sr1_increase_vehicle_rotation_limit, true, "(Saints Row 1) Patch vehicle vertical rotation limit to be mostly " "the same " @@ -1692,8 +1686,6 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, uint32_t mousefix_addr2; uint32_t mousefix_addr3; uint32_t aim_assist_xbtl; // File declares aim_assist values. - uint32_t havok_write_frametime_address1; - uint32_t havok_write_frametime_address2; uint32_t vehicle_rotationXWrite_addr_start; // lfs f0, (flt_827F9B04 - // 0x827F99A0)(r31) -- no // idea how I figured this, @@ -1706,15 +1698,12 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, uint32_t min_float_addr_lis1; uint32_t write_max_value1; // making it same as on-foot causes the camera // to clip. - uint32_t havok_value_address; - uint32_t fps_1over60_value; }; std::vector supported_builds = { // TU1 Release build {0x82050304, 0x7361696E, 0x60000000, 0x8249db00, 0x8249dd28, 0x8249dd50, - 0x82079cbc, 0x82195324, 0x8225BD8C, 0x8211D604, 0x82772D90, 0x8211FC8C, - 0x82772DB0, 0xC108C88C, 0xC00BC88C, 0xC0C8B850, 0x8208C88C, 0x835F2684, - 0x3c888889}, + 0x82079cbc, 0x8211D604, 0x82772D90, 0x8211FC8C, 0x82772DB0, 0xC108C88C, + 0xC00BC88C, 0xC0C8B850, 0x8208C88C}, }; for (auto& build : supported_builds) { auto* test_addr = (xe::be*)module->memory()->TranslateVirtual( @@ -1729,14 +1718,6 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, if (cvars::disable_autoaim && build.aim_assist_xbtl) { patch_addr(build.aim_assist_xbtl, build.beNOP); } - if (cvars::sr_havok_fix_frametime && - build.havok_write_frametime_address1 && - build.havok_write_frametime_address2) { - patch_addr(build.havok_write_frametime_address1, build.beNOP); - patch_addr(build.havok_write_frametime_address2, build.beNOP); - // in case user boots game with inputs other than winkey. - patch_addr(build.havok_value_address, build.fps_1over60_value); - } if (cvars::sr_better_drive_cam && build.vehicle_rotationXWrite_addr_start) { uint32_t addr = build.vehicle_rotationXWrite_addr_start; @@ -1804,9 +1785,6 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, uint32_t Vehicle_RotationXWrite_addr1; uint32_t Vehicle_RotationXWrite_addr2; // Handbrake. uint32_t aim_assist_xbtl; // File declares aim_assist values. - uint32_t havok_write_frametime_address1; - uint32_t havok_value_address; - uint32_t fps_1over60_value; }; std::vector supported_builds = { @@ -1816,8 +1794,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, 0x8247832c, 0x821a4b84, 0x824e6a68, 0x824e7f50, 0x824e6b8c, 0x82478934, 0x824e6b2c, 0x82478330, 0x82478094, 0x821a4b88, 0x82B7A5AC, 0x82B7A5A8, 0x82B77C04, 0x82B77C08, 0x82B77C0C, 0x82B77C08, 0x82B77C10, 0x821A4D20, - 0x821A4D18, 0x821a1f74, 0x821A2A2C, 0x820A61C0, 0x8221CEAC, 0x837DB620, - 0x3c888889}, + 0x821A4D18, 0x821a1f74, 0x821A2A2C, 0x820A61C0}, }; for (auto& build : supported_builds) { @@ -1868,10 +1845,6 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, if (cvars::disable_autoaim && build.aim_assist_xbtl) { patch_addr(build.aim_assist_xbtl, build.beNOP); } - if (cvars::sr_havok_fix_frametime && build.havok_write_frametime_address1) - patch_addr(build.havok_write_frametime_address1, build.beNOP); - // in case user boots game with inputs other than winkey. - patch_addr(build.havok_value_address, build.fps_1over60_value); break; } } diff --git a/src/xenia/hid/winkey/hookables/SaintsRow1.cc b/src/xenia/hid/winkey/hookables/SaintsRow1.cc index ba76a38436..31c1de1e68 100644 --- a/src/xenia/hid/winkey/hookables/SaintsRow1.cc +++ b/src/xenia/hid/winkey/hookables/SaintsRow1.cc @@ -27,7 +27,6 @@ DECLARE_double(sensitivity); DECLARE_bool(invert_y); DECLARE_bool(invert_x); DECLARE_double(right_stick_hold_time_workaround); -DECLARE_bool(sr_havok_fix_frametime); DECLARE_bool(swap_wheel); DECLARE_double(menu_sensitivity); @@ -41,14 +40,19 @@ struct GameBuildAddrs { uint32_t x_address; uint32_t y_address; uint32_t fineaim_y_address; + uint32_t player_address; uint32_t map_x_address; uint32_t map_zoom_address; uint32_t pause_screen_section_address; + uint32_t current_diversion_type_addr; // 0x82F062EF different candidate uint32_t vehicle_address; uint32_t weapon_wheel_address; uint32_t weapon_wheel_slot_address; uint32_t menu_status_address; - uint32_t havok_frametime_address; + // ACTUAL pause flag, menu_status_address acts more like if can player control + // (kind of the real player paused controls flag is at 0x8283CA7B, will need + // to use this if problems arise.) + uint32_t world_paused_address; uint32_t current_frametime_address; // x_axis_addition = // -(float)((float)_FP12 / // current_frametime); @@ -59,14 +63,24 @@ struct GameBuildAddrs { // Tervel's sr1fineaim plugin. uint32_t slow_pan_horizontal_multiplier_address; + uint32_t change_weapon_function_addr; + uint32_t limit_weapons_function_addr; + uint32_t allowable_weapons_melee_array; + uint32_t can_spin_player_flag_addr; + uint32_t rims_jobs_address_ptr; + uint32_t customization_screen_zoom_level_addr; + uint32_t mp_flag_1; + uint32_t mp_flag_2; }; std::map supported_builds{ {SaintsRow1Game::GameBuild::Unknown, {" ", NULL, NULL}}, {SaintsRow1Game::GameBuild::SaintsRow1_TU1, - {"1.0.1", 0x827f9af8, 0x827F9B00, 0x827F9BA4, 0x835F2B80, 0x827CF9CC, - 0x835F279B, 0x82932407, 0x8283CA7B, 0x835F2883, 0x835F27A3, 0x835F2684, - 0x827CA69C, 0x827F9AD8, 0x827F9B58, 0x827F99C7, 0x827F956C}}}; + {"1.0.1", 0x827f9af8, 0x827F9B00, 0x827F9BA4, 0x82F7EB04, 0x835F2B80, + 0x827CF9CC, 0x835F279B, 0x82EDE231, 0x82932407, 0x8283CA7B, 0x835F2883, + 0x835F27A3, 0x835F2527, 0x827CA69C, 0x827F9AD8, 0x827F9B58, 0x827F99A3, + 0x827F956C, 0x822AEB78, 0x822ADC10, 0x827D0484, 0x835F1A58, 0x837DD080, + 0x827F95B4, 0x835F33DF, 0x835F3522}}}; SaintsRow1Game::~SaintsRow1Game() = default; @@ -106,7 +120,6 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, return false; } - // REMOVE THIS FOR RELEASE NEEDS TO BE A PATCH! // xtbl edits can't be made into a patch most likely? xe::be* ingamesens_x = kernel_memory()->TranslateVirtual*>( @@ -126,7 +139,7 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, supported_builds[game_build_].ingame_sens + 0x4); if (*ingamesens_x != 0.01999999955f || *ingamesens_y != 0.01999999955f) { - *ingamesens_x = 0.01999999955f; + *ingamesens_x = 0.01999999955f; // 3CA3D70A *ingamesens_y = 0.01999999955f; } @@ -141,12 +154,6 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, supported_builds[game_build_].current_frametime_address); float frametime = *ingame_frametime; - if (cvars::sr_havok_fix_frametime && !isTervelPlugin()) - FixHavokFrameTime(frametime); - - // float correctFrametime = 1 / *currentFPS; - - //*frametime = correctFrametime * 2; auto now = std::chrono::steady_clock::now(); auto elapsed_x = std::chrono::duration_cast( @@ -156,7 +163,8 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, now - last_movement_time_y_) .count(); - if (!(inFirstPerson() && isTervelPlugin()) && !inMapScreen()) { + if (!(isTervelPlugin() && inFirstPerson()) && !inMapScreen() && + !(canspinplayer && isPaused())) { // Declare static variables for last deltas static int last_x_delta = 0; static int last_y_delta = 0; @@ -200,10 +208,22 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, if ((!input_state.mouse.x_delta && !input_state.mouse.y_delta && !input_state.mouse.wheel_delta)) return false; + player = *kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].player_address); - if (inMapScreen()) MapCursor(input_state); + if (isPaused()) { + if (inMapScreen()) MapCursor(input_state); + if (*kernel_memory()->TranslateVirtual( + supported_builds[game_build_].world_paused_address) != 0) { + return false; + } + if (RotatePlayerinCustomization(input_state) == true) { + return false; + } - if (isPaused()) return false; + return false; + } + if (input_state.mouse.wheel_delta) WeaponWheelScrollWheel(input_state); xe::be* addition_x = kernel_memory()->TranslateVirtual*>( supported_builds[game_build_].x_address); @@ -223,7 +243,7 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, static xe::be* fine_aim_x = NULL; static xe::be* fine_aim_y = NULL; - if (inFirstPerson() && isTervelPlugin()) { + if (isTervelPlugin() && inFirstPerson()) { divider_x = 15.f; frametime = 1.f; @@ -245,8 +265,9 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, // division over 1350 is assuming if frametime is 1/30, this should fix // sensitivity fluctuation due to framerate as that's what the game does at // 8249DD28(TU1); x_axis_addition = -(float)((float)_FP12 / frametime); - // stuttering might still occur due to framerates, as it's expected each - // frame? -= isn't ideal but that's the only way it works. - Clippy95 + // stuttering might still occur due to framerates, as it's expected to be set + // frame? -= isn't the ideal method but doing = causes it be less accurate + // somehow. - Clippy95 if (!cvars::invert_x) { degree_x += ((input_state.mouse.x_delta / divider_x) * (float)cvars::sensitivity) / @@ -256,7 +277,7 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, ((input_state.mouse.x_delta / divider_x) * (float)cvars::sensitivity) / frametime; } - if (!(inFirstPerson() && isTervelPlugin())) + if (!(isTervelPlugin() && inFirstPerson())) *addition_x = degree_x; else if (*fine_aim_x != NULL) *fine_aim_x = DegreetoRadians(degree_x); @@ -269,29 +290,16 @@ bool SaintsRow1Game::DoHooks(uint32_t user_index, RawInputState& input_state, } degree_y += delta_y; + degree_y = std::clamp(degree_y, -90.f, 90.f); *radian_y = DegreetoRadians(degree_y); - if ((inFirstPerson() && isTervelPlugin())) { + if ((isTervelPlugin() && inFirstPerson())) { degree_y = RadianstoDegree(*fine_aim_y); degree_y += delta_y; + degree_y = std::clamp(degree_y, -90.f, 90.f); *fine_aim_y = DegreetoRadians(degree_y); } - if (*wheel_status == 1) WeaponWheelScrollWheel(input_state); - return true; -} - -void SaintsRow1Game::FixHavokFrameTime(float frametime) { - XThread* current_thread = XThread::GetCurrentThread(); - if (!current_thread) return; - xe::be* havok_frametime = - kernel_memory()->TranslateVirtual*>( - supported_builds[game_build_].havok_frametime_address); - if (frametime < 0.03333333333f) { - frametime = frametime / 2.f; - if (*havok_frametime != frametime) *havok_frametime = frametime; - } else { - if (*havok_frametime != 0.01666666666f) *havok_frametime = 0.01666666666f; - } + return true; } bool SaintsRow1Game::isTervelPlugin() { @@ -324,7 +332,18 @@ bool SaintsRow1Game::isTervelPlugin() { bool SaintsRow1Game::inFirstPerson() { auto* firstperson = kernel_memory()->TranslateVirtual( supported_builds[game_build_].isfirstperson_address); - if (*firstperson && *firstperson == 1) + if (*firstperson && *firstperson == 8) + return true; + else + return false; +} + +bool SaintsRow1Game::isMP() { + auto* mp1 = kernel_memory()->TranslateVirtual( + supported_builds[game_build_].mp_flag_1); + auto* mp2 = kernel_memory()->TranslateVirtual( + supported_builds[game_build_].mp_flag_2); + if (*mp2 == 1 || *mp1 == 1) return true; else return false; @@ -340,21 +359,123 @@ bool SaintsRow1Game::isPaused() { return false; } +bool SaintsRow1Game::RotatePlayerinCustomization(RawInputState& input_state) { + if (player == NULL) return false; + canspinplayer = *kernel_memory()->TranslateVirtual( + supported_builds[game_build_].can_spin_player_flag_addr); + if (canspinplayer != 1) return false; + + float mousex = + (input_state.mouse.x_delta / 5.f) * (float)cvars::menu_sensitivity; + xe::be* zoom_level = kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].customization_screen_zoom_level_addr); + + // this is absoloute player rotation, this isn't fixed to the player + // customization screens + xe::be* player_x_sin = + kernel_memory()->TranslateVirtual*>(player + 0x40); + + xe::be* player_x_cos = + kernel_memory()->TranslateVirtual*>(player + 0x38); + + float min_zoom = 0.75f; + float max_zoom = 3.f; + if (vehicle_status == 1) { // maybe read of rims jobs flags instead? + // 828522D5,828527FD, 82852A91, 82852D25 + min_zoom = 3.f; + max_zoom = 9.f; + xe::be* rims_jobs_vehicle_pointer = multi_pointer( + supported_builds[game_build_].rims_jobs_address_ptr, {0x20, 0x98}); + if (*rims_jobs_vehicle_pointer == NULL) return false; + player_x_sin = kernel_memory()->TranslateVirtual*>( + *rims_jobs_vehicle_pointer + 0x40); + player_x_cos = kernel_memory()->TranslateVirtual*>( + *rims_jobs_vehicle_pointer + 0x38); + mousex = std::clamp(mousex, -24.f, + 24.f); // random value to limit mouse delta otherwise + // the cars starts freaking out + } + + float zoom = *zoom_level; + zoom = RadianstoDegree(zoom); // probably not really in radians.. + zoom -= input_state.mouse.wheel_delta / 7.5f; + zoom += (input_state.mouse.y_delta / 8.f) * (float)cvars::menu_sensitivity; + *zoom_level = std::clamp(DegreetoRadians(zoom), min_zoom, max_zoom); + float x = atan2(*player_x_sin, *player_x_cos); + x = RadianstoDegree(x); + + x += mousex; + if (x > 180.0f) { + x -= 360.0f; + } else if (x < -180.0f) { + x += 360.0f; + } + x = DegreetoRadians(x); + *player_x_sin = sin(x); + *player_x_cos = cos(x); + return true; +} + +bool SaintsRow1Game::CantSwitchWeapons() { + if (isAnimStatus(animstatus::DEAD) || isAnimStatus(animstatus::JUMPING) || + isAnimStatus(animstatus::RAGDOLL) || + IsPlayerStatus1(playerstatus1::BUSY) || + IsPlayerStatus1(playerstatus1::SPRINTING) || + IsPlayerStatus1(playerstatus1::STANDINGUP) || + IsPlayerStatus1(playerstatus1::JUMPING1)) + return true; + else + return false; +} + void SaintsRow1Game::WeaponWheelScrollWheel(RawInputState& input_state) { + if (player == NULL || isAnimStatus(animstatus::DEAD)) return; + // This probably works fine but might need more testing, and It'd be more + // accurate to the SR2 PC port,BUT I prefer being able to switch weapons while + // sprinting, make this part of a WeaponSwitchHandler cvar in the future? + if (isMP()) + if (CantSwitchWeapons()) return; + auto* weapon_slot = kernel_memory()->TranslateVirtual( supported_builds[game_build_].weapon_wheel_slot_address); + xe::be* current_weapon = + kernel_memory()->TranslateVirtual*>(player + 0xDDC); + if (input_state.mouse.wheel_delta) { - int16_t slot = static_cast(*weapon_slot); + SelectableWeaponsHack(); // controls if we can use the 4 + // un-usable weapons, + // 827D0484, 827D04C0, 827D04D4, 827D04E8, calling it here + // doesn't work unless we at least open the wheel in a + // vehicle once, then it works expect for melees? + // call_argless_function(0x822ADD48); + int16_t original_slot = static_cast(*weapon_slot); + int16_t slot = original_slot; + + uint32_t old_weapon = *current_weapon; + bool weapon_switched = false; + + int direction = (input_state.mouse.wheel_delta > 0) ? 1 : -1; + + if (cvars::swap_wheel) { + direction = -direction; + } + + for (int attempts = 0; attempts < 8; ++attempts) { + slot = (slot + direction + 8) % 8; - // one scroll of the wheel_delta seems to always return 120? - if (!cvars::swap_wheel) - slot += static_cast(input_state.mouse.wheel_delta / 120); - else - slot -= static_cast(input_state.mouse.wheel_delta / 120); + *weapon_slot = static_cast(slot); - slot = slot % 8; + call_argless_function(supported_builds[game_build_] + .change_weapon_function_addr); // set weapon - *weapon_slot = static_cast(slot); + if (*current_weapon != old_weapon) { + weapon_switched = true; + break; + } + } + if (!weapon_switched) { + *weapon_slot = static_cast(original_slot); + } } } @@ -362,7 +483,10 @@ bool SaintsRow1Game::inMapScreen() { auto* pause_screen = kernel_memory()->TranslateVirtual( supported_builds[game_build_].pause_screen_section_address); - if (*pause_screen == 26 && isPaused()) + auto* map_usable = kernel_memory()->TranslateVirtual( + supported_builds[game_build_].current_diversion_type_addr); + + if ((*pause_screen == 26 || *map_usable == 210) && isPaused()) return true; else return false; @@ -409,18 +533,26 @@ void SaintsRow1Game::MapCursor(RawInputState& input_state) { *map_zoom_be = map_zoom; } +void SaintsRow1Game::call_argless_function(uint32_t function_address) { + XThread* current_thread = XThread::GetCurrentThread(); + if (!current_thread) { + return; + } + kernel_state()->processor()->Execute(current_thread->thread_state(), + function_address); + return; +} + std::string SaintsRow1Game::ChooseBinds() { wheel_status = kernel_memory()->TranslateVirtual( supported_builds[game_build_].weapon_wheel_address); - auto* menu_status = kernel_memory()->TranslateVirtual( - supported_builds[game_build_].menu_status_address); - auto* vehicle_status = kernel_memory()->TranslateVirtual( + vehicle_status = *kernel_memory()->TranslateVirtual( supported_builds[game_build_].vehicle_address); - if (*wheel_status == 1 || (menu_status && *menu_status != 2)) { + if (*wheel_status == 1 || isPaused()) { return "Default"; } - if (vehicle_status && *vehicle_status == 1) { + if (vehicle_status && vehicle_status == 1) { return "Vehicle"; } @@ -452,10 +584,84 @@ bool SaintsRow1Game::ModifierKeyHandler(uint32_t user_index, return true; } +bool SaintsRow1Game::isAnimStatus(uint8_t type) { + if (player == NULL) return false; + auto* anim_status = + kernel_memory()->TranslateVirtual(player + 0x1FF); + + if (*anim_status == type) + return true; + else + return false; +} + +bool SaintsRow1Game::IsPlayerStatus1(uint32_t type) { + if (player == NULL) return false; + auto* player_status1 = + kernel_memory()->TranslateVirtual*>(player + 0x1180); + + if (*player_status1 == type) + return true; + else + return false; +} + +void SaintsRow1Game::SelectableWeaponsHack() { + /*Opening weapon wheel does call limit_weapons_function_addr correctly, so + * skip our attempt at re-creating it.*/ + if (*wheel_status) return; + call_argless_function( + supported_builds[game_build_] + .limit_weapons_function_addr); // Ideally this should have done + // everything that this function does, + // but calling it doesn't seem to do + // the job fully?? + auto* melee_slot = kernel_memory()->TranslateVirtual( + supported_builds[game_build_].allowable_weapons_melee_array); + auto* shotgun_slot = kernel_memory()->TranslateVirtual( + supported_builds[game_build_].allowable_weapons_melee_array + 0x3C); + auto* ar_slot = kernel_memory()->TranslateVirtual( + supported_builds[game_build_].allowable_weapons_melee_array + 0x50); + auto* rpg_slot = kernel_memory()->TranslateVirtual( + supported_builds[game_build_].allowable_weapons_melee_array + 0x64); + + if (isAnimStatus(animstatus::DRIVING) && vehicle_status) { + *melee_slot = 1; + *shotgun_slot = 1; + *ar_slot = 1; + *rpg_slot = 1; + } else if (isAnimStatus(animstatus::PASSANGER) && vehicle_status) { + *melee_slot = 1; + *shotgun_slot = 0; + *ar_slot = 0; + *rpg_slot = 0; + } else if (vehicle_status == 0) { + *melee_slot = 0; + *shotgun_slot = 0; + *ar_slot = 0; + *rpg_slot = 0; + } +} + void SaintsRow1Game::WeaponSwitchHandler(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state, int weapon, - uint16_t buttons) {} + uint16_t buttons) { + if (isPaused() || isAnimStatus(animstatus::DEAD)) return; + // This probably works fine but might need more testing, and It'd be more + // accurate to the SR2 PC port,BUT I prefer being able to switch weapons while + // sprinting, make this part of a WeaponSwitchHandler cvar in the future? + if (isMP()) + if (CantSwitchWeapons()) return; + auto* weapon_slot = kernel_memory()->TranslateVirtual( + supported_builds[game_build_].weapon_wheel_slot_address); + SelectableWeaponsHack(); + if (weapon) { + *weapon_slot = std::clamp(weapon - 1, 0, 7); + call_argless_function( + supported_builds[game_build_].change_weapon_function_addr); + } +} } // namespace winkey } // namespace hid diff --git a/src/xenia/hid/winkey/hookables/SaintsRow1.h b/src/xenia/hid/winkey/hookables/SaintsRow1.h index 485c984958..1f1be54de2 100644 --- a/src/xenia/hid/winkey/hookables/SaintsRow1.h +++ b/src/xenia/hid/winkey/hookables/SaintsRow1.h @@ -30,16 +30,22 @@ class SaintsRow1Game : public HookableGame { bool DoHooks(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state); - void FixHavokFrameTime(float frametime); bool isTervelPlugin(); bool inFirstPerson(); + bool isMP(); bool isPaused(); + bool RotatePlayerinCustomization(RawInputState& input_state); + bool CantSwitchWeapons(); void WeaponWheelScrollWheel(RawInputState& input_state); bool inMapScreen(); void MapCursor(RawInputState& input_state); + void call_argless_function(uint32_t function_address); std::string ChooseBinds(); bool ModifierKeyHandler(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state); + bool isAnimStatus(uint8_t type); + bool IsPlayerStatus1(uint32_t type); + void SelectableWeaponsHack(); void WeaponSwitchHandler(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state, int weapon, uint16_t buttons); @@ -52,6 +58,28 @@ class SaintsRow1Game : public HookableGame { std::chrono::steady_clock::time_point last_movement_time_y_; uint8_t tervelplugin_status; uint8_t* wheel_status; + uint32_t player; + uint8_t vehicle_status; + uint8_t canspinplayer; + enum animstatus { + JUMPING = 2, + PASSANGER = 10, + DRIVING = 11, + DEAD = 7, + RAGDOLL = 4, + + }; + enum playerstatus1 { + NORMAL = 4287, + SPRINTING = 178, + JUMPING1 = 8, + DRIVING1 = 4304, + STANDINGUP = 32, + // this could be from interacting with menus or opening doors, or getting in + // a car.. + BUSY = 0, + + }; }; } // namespace winkey diff --git a/src/xenia/hid/winkey/hookables/SaintsRow2.cc b/src/xenia/hid/winkey/hookables/SaintsRow2.cc index e663226549..98c29607b7 100644 --- a/src/xenia/hid/winkey/hookables/SaintsRow2.cc +++ b/src/xenia/hid/winkey/hookables/SaintsRow2.cc @@ -28,7 +28,6 @@ DECLARE_bool(invert_y); DECLARE_bool(invert_x); DECLARE_bool(disable_autoaim); DECLARE_double(right_stick_hold_time_workaround); -DECLARE_bool(sr_havok_fix_frametime); DECLARE_bool(sr2_hold_fine_aim); const uint32_t kTitleIdSaintsRow2 = 0x545107FC; @@ -54,6 +53,9 @@ struct GameBuildAddrs { // manage player's fineaim. uint32_t player_pointer_address; uint32_t sniper_zoom_function_address; + uint32_t clamp_value_to_subtract; + uint32_t clamp_current_min; + uint32_t clamp_current_max; }; std::map supported_builds{ @@ -61,7 +63,7 @@ std::map supported_builds{ {SaintsRow2Game::GameBuild::SaintsRow2_TU3, {"8.0.3", 0x82B7A570, 0x82B7A590, 0x82B7ABC4, 0x837B79C3, 0x82B58DA3, 0x82BCBA78, 0x82B7A4BC, 0x837DB620, 0x82B7A518, 0x837B7BBB, 0x826CB818, - 0x835BF42C, 0x826CBB40}}}; + 0x835BF42C, 0x826CBB40, 0x82B7AC58, 0x82B7AC4C, 0x82B7AC50}}}; SaintsRow2Game::~SaintsRow2Game() = default; @@ -109,8 +111,6 @@ bool SaintsRow2Game::DoHooks(uint32_t user_index, RawInputState& input_state, now - last_movement_time_y_) .count(); - if (cvars::sr_havok_fix_frametime) FixHavokFrameTime(); - // Declare static variables for last deltas static int last_x_delta = 0; static int last_y_delta = 0; @@ -196,7 +196,7 @@ bool SaintsRow2Game::DoHooks(uint32_t user_index, RawInputState& input_state, float degree_x = RadianstoDegree(*radian_x); float degree_y = RadianstoDegree(*radian_y); - float divisor = 7.5f; + float divisor = 6.0f; if (*sniper_status == 0) divisor = 10.f; xe::be* currentFOV = @@ -222,6 +222,19 @@ bool SaintsRow2Game::DoHooks(uint32_t user_index, RawInputState& input_state, degree_y -= (input_state.mouse.y_delta / divisor) * (float)cvars::sensitivity; } + // re-implemenation of SR1&2's dynamic clamping because internal clamping + // can break and it doesn't work well with mousehook on-foot. + xe::be* value_to_subtract = + kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].clamp_value_to_subtract); + xe::be* min = kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].clamp_current_min); + xe::be* max = kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].clamp_current_max); + + degree_y = std::clamp(degree_y, RadianstoDegree(*min - *value_to_subtract), + RadianstoDegree(*max - *value_to_subtract)); + *radian_y = DegreetoRadians(degree_y); } return true; @@ -296,27 +309,6 @@ void SaintsRow2Game::WeaponSwitchHandler(uint32_t user_index, X_INPUT_STATE* out_state, int weapon, uint16_t buttons) {} -void SaintsRow2Game::FixHavokFrameTime() { - XThread* current_thread = XThread::GetCurrentThread(); - if (!current_thread) return; - xe::be* havok_frametime = - kernel_memory()->TranslateVirtual*>( - supported_builds[game_build_].havok_frametime_address); - - xe::be* current_frametime = - kernel_memory()->TranslateVirtual*>( - supported_builds[game_build_].current_frametime_address); - - float frametime = *current_frametime; - - if (frametime < 0.03333333333f) { - frametime = frametime / 2.f; - if (*havok_frametime != frametime) *havok_frametime = frametime; - } else { - if (*havok_frametime != 0.01666666666f) *havok_frametime = 0.01666666666f; - } -} - uint64_t SaintsRow2Game::reset_fineaim(uint32_t function_address, uint32_t player_ptr, uint32_t a2, uint32_t a3) { diff --git a/src/xenia/hid/winkey/hookables/SaintsRow2.h b/src/xenia/hid/winkey/hookables/SaintsRow2.h index c908f567db..5f5ff4ad54 100644 --- a/src/xenia/hid/winkey/hookables/SaintsRow2.h +++ b/src/xenia/hid/winkey/hookables/SaintsRow2.h @@ -40,8 +40,6 @@ class SaintsRow2Game : public HookableGame { X_INPUT_STATE* out_state, int weapon, uint16_t buttons); - void FixHavokFrameTime(); - uint64_t reset_fineaim(uint32_t function_address, uint32_t player_ptr, uint32_t a2, uint32_t a3);