Adds analog camera and other controller options (#264)
* Added analog cam and camera inversion options to menu, initial implementation of analog cam * Automatically suppress inputs on the right stick while analog cam is active * Return to automatic camera mode when pressing target * Add aiming inversion options * Add analog camera inversion options
This commit is contained in:
parent
a4f61016bb
commit
3c34fa63c1
|
@ -106,7 +106,7 @@
|
||||||
type="range"
|
type="range"
|
||||||
min="0"
|
min="0"
|
||||||
max="100"
|
max="100"
|
||||||
style="flex: 1; margin: 0dp;"
|
style="flex: 1; margin: 0dp; nav-down: #bg_input_enabled"
|
||||||
data-value="joystick_deadzone"
|
data-value="joystick_deadzone"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -154,7 +154,7 @@
|
||||||
data-checked="autosave_mode"
|
data-checked="autosave_mode"
|
||||||
value="On"
|
value="On"
|
||||||
id="autosave_enabled"
|
id="autosave_enabled"
|
||||||
style="nav-up: #bg_input_enabled; nav-down: #analog_cam_enabled"
|
style="nav-up: #bg_input_enabled; nav-down: #camera_inversion_none"
|
||||||
/>
|
/>
|
||||||
<label class="config-option__tab-label" for="autosave_enabled">On</label>
|
<label class="config-option__tab-label" for="autosave_enabled">On</label>
|
||||||
|
|
||||||
|
@ -166,11 +166,149 @@
|
||||||
data-checked="autosave_mode"
|
data-checked="autosave_mode"
|
||||||
value="Off"
|
value="Off"
|
||||||
id="autosave_disabled"
|
id="autosave_disabled"
|
||||||
style="nav-up: #bg_input_disabled; nav-down: #analog_cam_disabled"
|
style="nav-up: #bg_input_disabled; nav-down: #camera_inversion_x"
|
||||||
/>
|
/>
|
||||||
<label class="config-option__tab-label" for="autosave_disabled">Off</label>
|
<label class="config-option__tab-label" for="autosave_disabled">Off</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- camera inversion -->
|
||||||
|
<div class="config-option" data-event-mouseover="set_cur_config_index(7)">
|
||||||
|
<label class="config-option__title">Aiming Camera Mode</label>
|
||||||
|
<div class="config-option__list">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(7)"
|
||||||
|
name="camera_invert_mode"
|
||||||
|
data-checked="camera_invert_mode"
|
||||||
|
value="InvertNone"
|
||||||
|
id="camera_inversion_none"
|
||||||
|
style="nav-up: #autosave_enabled; nav-down: #analog_cam_enabled"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="camera_inversion_none">None</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(7)"
|
||||||
|
name="camera_invert_mode"
|
||||||
|
data-checked="camera_invert_mode"
|
||||||
|
value="InvertX"
|
||||||
|
id="camera_inversion_x"
|
||||||
|
style="nav-up: #autosave_disabled; nav-down: #analog_cam_disabled"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="camera_inversion_x">Invert X</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(7)"
|
||||||
|
name="camera_invert_mode"
|
||||||
|
data-checked="camera_invert_mode"
|
||||||
|
value="InvertY"
|
||||||
|
id="camera_inversion_y"
|
||||||
|
style="nav-up: #autosave_disabled; nav-down: #analog_cam_disabled"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="camera_inversion_y">Invert Y</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(7)"
|
||||||
|
name="camera_invert_mode"
|
||||||
|
data-checked="camera_invert_mode"
|
||||||
|
value="InvertBoth"
|
||||||
|
id="camera_inversion_both"
|
||||||
|
style="nav-up: #autosave_disabled; nav-down: #analog_cam_disabled"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="camera_inversion_both">Invert Both</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- analog camera -->
|
||||||
|
<div class="config-option" data-event-mouseover="set_cur_config_index(8)">
|
||||||
|
<label class="config-option__title">Analog Camera</label>
|
||||||
|
<div class="config-option__list">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(8)"
|
||||||
|
name="analog_cam_mode"
|
||||||
|
data-checked="analog_cam_mode"
|
||||||
|
value="On"
|
||||||
|
id="analog_cam_enabled"
|
||||||
|
style="nav-up: #camera_inversion_none; nav-down: #analog_camera_inversion_none"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="analog_cam_enabled">On</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(8)"
|
||||||
|
name="analog_cam_mode"
|
||||||
|
data-checked="analog_cam_mode"
|
||||||
|
value="Off"
|
||||||
|
id="analog_cam_disabled"
|
||||||
|
style="nav-up: #camera_inversion_x; nav-down: #analog_camera_inversion_x"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="analog_cam_disabled">Off</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- analog camera inversion -->
|
||||||
|
<div class="config-option" data-event-mouseover="set_cur_config_index(9)">
|
||||||
|
<label class="config-option__title">Analog Camera Mode</label>
|
||||||
|
<div class="config-option__list">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(9)"
|
||||||
|
name="analog_camera_invert_mode"
|
||||||
|
data-checked="analog_camera_invert_mode"
|
||||||
|
value="InvertNone"
|
||||||
|
id="analog_camera_inversion_none"
|
||||||
|
style="nav-up: #analog_cam_enabled;"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="analog_camera_inversion_none">None</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(9)"
|
||||||
|
name="analog_camera_invert_mode"
|
||||||
|
data-checked="analog_camera_invert_mode"
|
||||||
|
value="InvertX"
|
||||||
|
id="analog_camera_inversion_x"
|
||||||
|
style="nav-up: #analog_cam_disabled;"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="analog_camera_inversion_x">Invert X</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(9)"
|
||||||
|
name="analog_camera_invert_mode"
|
||||||
|
data-checked="analog_camera_invert_mode"
|
||||||
|
value="InvertY"
|
||||||
|
id="analog_camera_inversion_y"
|
||||||
|
style="nav-up: #analog_cam_disabled;"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="analog_camera_inversion_y">Invert Y</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-event-blur="set_cur_config_index(-1)"
|
||||||
|
data-event-focus="set_cur_config_index(9)"
|
||||||
|
name="analog_camera_invert_mode"
|
||||||
|
data-checked="analog_camera_invert_mode"
|
||||||
|
value="InvertBoth"
|
||||||
|
id="analog_camera_inversion_both"
|
||||||
|
style="nav-up: #analog_cam_disabled;"
|
||||||
|
/>
|
||||||
|
<label class="config-option__tab-label" for="analog_camera_inversion_both">Invert Both</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Descriptions -->
|
<!-- Descriptions -->
|
||||||
<div class="config__wrapper">
|
<div class="config__wrapper">
|
||||||
|
@ -209,6 +347,21 @@
|
||||||
<br/>
|
<br/>
|
||||||
<b>If autosaving is disabled, existing autosaves will be deleted when loaded.</b>
|
<b>If autosaving is disabled, existing autosaves will be deleted when loaded.</b>
|
||||||
</p>
|
</p>
|
||||||
|
<p data-if="cur_config_index == 7">
|
||||||
|
Inverts the camera controls for first-person aiming. <b>Invert Y</b> is the default and matches the original game.
|
||||||
|
</p>
|
||||||
|
<p data-if="cur_config_index == 8">
|
||||||
|
Enables an analog "free" camera similar to later entries in the series that's mapped to the right analog stick on the controller.
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
When you move the right stick, the camera will enter free mode and stop centering behind Link. Press the <b>Target</b> button at any time to go back into the normal camera mode. The camera will also return to normal mode after a cutscene plays or when you move between areas.
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
This option also enables right stick control while looking and aiming.
|
||||||
|
</p>
|
||||||
|
<p data-if="cur_config_index == 9">
|
||||||
|
Inverts the camera controls for the analog camera if it's enabled. <b>None</b> is the default.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -28,13 +28,27 @@ namespace recomp {
|
||||||
OptionCount
|
OptionCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class AnalogCamMode {
|
||||||
|
On,
|
||||||
|
Off,
|
||||||
|
OptionCount
|
||||||
|
};
|
||||||
|
|
||||||
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::AutosaveMode, {
|
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::AutosaveMode, {
|
||||||
{recomp::AutosaveMode::On, "On"},
|
{recomp::AutosaveMode::On, "On"},
|
||||||
{recomp::AutosaveMode::Off, "Off"}
|
{recomp::AutosaveMode::Off, "Off"}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::AnalogCamMode, {
|
||||||
|
{recomp::AnalogCamMode::On, "On"},
|
||||||
|
{recomp::AnalogCamMode::Off, "Off"}
|
||||||
|
});
|
||||||
|
|
||||||
AutosaveMode get_autosave_mode();
|
AutosaveMode get_autosave_mode();
|
||||||
void set_autosave_mode(AutosaveMode mode);
|
void set_autosave_mode(AutosaveMode mode);
|
||||||
|
|
||||||
|
AnalogCamMode get_analog_cam_mode();
|
||||||
|
void set_analog_cam_mode(AnalogCamMode mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -67,6 +67,7 @@ namespace recomp {
|
||||||
bool get_input_digital(const std::span<const recomp::InputField> fields);
|
bool get_input_digital(const std::span<const recomp::InputField> fields);
|
||||||
void get_gyro_deltas(float* x, float* y);
|
void get_gyro_deltas(float* x, float* y);
|
||||||
void get_mouse_deltas(float* x, float* y);
|
void get_mouse_deltas(float* x, float* y);
|
||||||
|
void get_right_analog(float* x, float* y);
|
||||||
|
|
||||||
enum class InputDevice {
|
enum class InputDevice {
|
||||||
Controller,
|
Controller,
|
||||||
|
@ -133,6 +134,8 @@ namespace recomp {
|
||||||
void set_gyro_sensitivity(int strength);
|
void set_gyro_sensitivity(int strength);
|
||||||
void set_mouse_sensitivity(int strength);
|
void set_mouse_sensitivity(int strength);
|
||||||
void set_joystick_deadzone(int strength);
|
void set_joystick_deadzone(int strength);
|
||||||
|
void apply_joystick_deadzone(float x_in, float y_in, float* x_out, float* y_out);
|
||||||
|
void set_right_analog_suppressed(bool suppressed);
|
||||||
|
|
||||||
enum class TargetingMode {
|
enum class TargetingMode {
|
||||||
Switch,
|
Switch,
|
||||||
|
@ -162,6 +165,27 @@ namespace recomp {
|
||||||
BackgroundInputMode get_background_input_mode();
|
BackgroundInputMode get_background_input_mode();
|
||||||
void set_background_input_mode(BackgroundInputMode mode);
|
void set_background_input_mode(BackgroundInputMode mode);
|
||||||
|
|
||||||
|
enum class CameraInvertMode {
|
||||||
|
InvertNone,
|
||||||
|
InvertX,
|
||||||
|
InvertY,
|
||||||
|
InvertBoth,
|
||||||
|
OptionCount
|
||||||
|
};
|
||||||
|
|
||||||
|
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::CameraInvertMode, {
|
||||||
|
{recomp::CameraInvertMode::InvertNone, "InvertNone"},
|
||||||
|
{recomp::CameraInvertMode::InvertX, "InvertX"},
|
||||||
|
{recomp::CameraInvertMode::InvertY, "InvertY"},
|
||||||
|
{recomp::CameraInvertMode::InvertBoth, "InvertBoth"}
|
||||||
|
});
|
||||||
|
|
||||||
|
CameraInvertMode get_camera_invert_mode();
|
||||||
|
void set_camera_invert_mode(CameraInvertMode mode);
|
||||||
|
|
||||||
|
CameraInvertMode get_analog_camera_invert_mode();
|
||||||
|
void set_analog_camera_invert_mode(CameraInvertMode mode);
|
||||||
|
|
||||||
bool game_input_disabled();
|
bool game_input_disabled();
|
||||||
bool all_input_disabled();
|
bool all_input_disabled();
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef __CAMERA_PATCHES_H__
|
||||||
|
#define __CAMERA_PATCHES_H__
|
||||||
|
|
||||||
|
#include "z64camera.h"
|
||||||
|
|
||||||
|
#define RELOAD_PARAMS(camera) ((camera->animState == 0) || (camera->animState == 10) || (camera->animState == 20))
|
||||||
|
#define CAM_RODATA_SCALE(x) ((x)*100.0f)
|
||||||
|
#define CAM_RODATA_UNSCALE(x) ((x)*0.01f)
|
||||||
|
|
||||||
|
// Load the next value from camera read-only data stored in CameraModeValue
|
||||||
|
#define GET_NEXT_RO_DATA(values) ((values++)->val)
|
||||||
|
// Load the next value and scale down from camera read-only data stored in CameraModeValue
|
||||||
|
#define GET_NEXT_SCALED_RO_DATA(values) CAM_RODATA_UNSCALE(GET_NEXT_RO_DATA(values))
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,4 +1,5 @@
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
|
#include "camera_patches.h"
|
||||||
#include "transform_ids.h"
|
#include "transform_ids.h"
|
||||||
#include "z64cutscene.h"
|
#include "z64cutscene.h"
|
||||||
#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h"
|
#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h"
|
||||||
|
@ -286,11 +287,6 @@ void Camera_ScaledStepToCeilVec3f(Vec3f* target, Vec3f* cur, f32 xzStepScale, f3
|
||||||
void Camera_SetFocalActorAtOffset(Camera* camera, Vec3f* focalActorPos);
|
void Camera_SetFocalActorAtOffset(Camera* camera, Vec3f* focalActorPos);
|
||||||
void Camera_SetUpdateRatesSlow(Camera* camera);
|
void Camera_SetUpdateRatesSlow(Camera* camera);
|
||||||
Vec3f Camera_Vec3sToVec3f(Vec3s* src);
|
Vec3f Camera_Vec3sToVec3f(Vec3s* src);
|
||||||
#define RELOAD_PARAMS(camera) ((camera->animState == 0) || (camera->animState == 10) || (camera->animState == 20))
|
|
||||||
#define CAM_RODATA_SCALE(x) ((x)*100.0f)
|
|
||||||
#define CAM_RODATA_UNSCALE(x) ((x)*0.01f)
|
|
||||||
#define GET_NEXT_RO_DATA(values) ((values++)->val)
|
|
||||||
#define GET_NEXT_SCALED_RO_DATA(values) CAM_RODATA_UNSCALE(GET_NEXT_RO_DATA(values))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for many fixed-based camera settings i.e. camera is fixed in rotation, and often position (but not always)
|
* Used for many fixed-based camera settings i.e. camera is fixed in rotation, and often position (but not always)
|
||||||
|
|
230
patches/input.c
230
patches/input.c
|
@ -13,12 +13,44 @@ s32 func_8082EF20(Player* this);
|
||||||
s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
||||||
s32 pad;
|
s32 pad;
|
||||||
s16 var_s0;
|
s16 var_s0;
|
||||||
|
// @recomp Get the aiming camera inversion state.
|
||||||
|
s32 inverted_x, inverted_y;
|
||||||
|
recomp_get_inverted_axes(&inverted_x, &inverted_y);
|
||||||
|
// @recomp Get the analog camera input values if analog cam is enabled.
|
||||||
|
s32 analog_x = 0;
|
||||||
|
s32 analog_y = 0;
|
||||||
|
if (recomp_analog_cam_enabled()) {
|
||||||
|
float analog_x_float = 0.0f;
|
||||||
|
float analog_y_float = 0.0f;
|
||||||
|
recomp_get_camera_inputs(&analog_x_float, &analog_y_float);
|
||||||
|
// Scale by 127 to match what ultramodern does, then clamp to 60 to match the game's handling.
|
||||||
|
analog_x = (s32)(analog_x_float * 127.0f);
|
||||||
|
analog_x = CLAMP(analog_x, -60, 60);
|
||||||
|
analog_y = (s32)(analog_y_float * -127.0f);
|
||||||
|
analog_y = CLAMP(analog_y, -60, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
// recomp_printf("stick_x: %d stick_y: %d analog_x: %d analog_y: %d\n",
|
||||||
|
// play->state.input[0].rel.stick_x, play->state.input[0].rel.stick_y,
|
||||||
|
// analog_x, analog_y);
|
||||||
|
|
||||||
if (!func_800B7128(this) && !func_8082EF20(this) && !arg2) {
|
if (!func_800B7128(this) && !func_8082EF20(this) && !arg2) {
|
||||||
var_s0 = play->state.input[0].rel.stick_y * 0xF0;
|
// @recomp Add in the analog camera Y input. Clamp to prevent moving the camera twice as fast if both sticks are held.
|
||||||
|
var_s0 = CLAMP(play->state.input[0].rel.stick_y + analog_y, -61, 61) * 0xF0;
|
||||||
|
|
||||||
|
// @recomp Invert the Y axis accordingly (default is inverted, so negate if not inverted).
|
||||||
|
if (!inverted_y) {
|
||||||
|
var_s0 = -var_s0;
|
||||||
|
}
|
||||||
Math_SmoothStepToS(&this->actor.focus.rot.x, var_s0, 0xE, 0xFA0, 0x1E);
|
Math_SmoothStepToS(&this->actor.focus.rot.x, var_s0, 0xE, 0xFA0, 0x1E);
|
||||||
|
|
||||||
var_s0 = play->state.input[0].rel.stick_x * -0x10;
|
// @recomp Add in the analog camera X input. Clamp to prevent moving the camera twice as fast if both sticks are held.
|
||||||
|
var_s0 = CLAMP(play->state.input[0].rel.stick_x + analog_x, -61, 61) * -0x10;
|
||||||
|
|
||||||
|
// @recomp Invert the X axis accordingly
|
||||||
|
if (inverted_x) {
|
||||||
|
var_s0 = -var_s0;
|
||||||
|
}
|
||||||
var_s0 = CLAMP(var_s0, -0xBB8, 0xBB8);
|
var_s0 = CLAMP(var_s0, -0xBB8, 0xBB8);
|
||||||
this->actor.focus.rot.y += var_s0;
|
this->actor.focus.rot.y += var_s0;
|
||||||
}
|
}
|
||||||
|
@ -62,8 +94,15 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
||||||
|
|
||||||
s16 temp3;
|
s16 temp3;
|
||||||
|
|
||||||
temp3 = ((play->state.input[0].rel.stick_y >= 0) ? 1 : -1) *
|
// @recomp Invert the Y axis accordingly (default is inverted, so negate if not inverted).
|
||||||
(s32)((1.0f - Math_CosS(play->state.input[0].rel.stick_y * 0xC8)) * 1500.0f);
|
// Also add in the analog camera Y input. Clamp to prevent moving the camera twice as fast if both sticks are held.
|
||||||
|
s32 stick_y = CLAMP(play->state.input[0].rel.stick_y + analog_y, -61, 61);
|
||||||
|
if (!inverted_y) {
|
||||||
|
stick_y = -stick_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp3 = ((stick_y >= 0) ? 1 : -1) *
|
||||||
|
(s32)((1.0f - Math_CosS(stick_y * 0xC8)) * 1500.0f);
|
||||||
this->actor.focus.rot.x += temp3 + (s32)(target_aim_x - applied_aim_x);
|
this->actor.focus.rot.x += temp3 + (s32)(target_aim_x - applied_aim_x);
|
||||||
applied_aim_x = target_aim_x;
|
applied_aim_x = target_aim_x;
|
||||||
|
|
||||||
|
@ -75,8 +114,15 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var_s0 = this->actor.focus.rot.y - this->actor.shape.rot.y;
|
var_s0 = this->actor.focus.rot.y - this->actor.shape.rot.y;
|
||||||
temp3 = ((play->state.input[0].rel.stick_x >= 0) ? 1 : -1) *
|
|
||||||
(s32)((1.0f - Math_CosS(play->state.input[0].rel.stick_x * 0xC8)) * -1500.0f);
|
// @recomp Invert the X axis accordingly. Also add in the analog camera Y input.
|
||||||
|
// Clamp to prevent moving the camera twice as fast if both sticks are held.
|
||||||
|
s32 stick_x = CLAMP(play->state.input[0].rel.stick_x + analog_x, -61, 61);
|
||||||
|
if (inverted_x) {
|
||||||
|
stick_x = -stick_x;
|
||||||
|
}
|
||||||
|
temp3 = ((stick_x >= 0) ? 1 : -1) *
|
||||||
|
(s32)((1.0f - Math_CosS(stick_x * 0xC8)) * -1500.0f);
|
||||||
var_s0 += temp3 + (s32)(target_aim_y - applied_aim_y);
|
var_s0 += temp3 + (s32)(target_aim_y - applied_aim_y);
|
||||||
applied_aim_y = target_aim_y;
|
applied_aim_y = target_aim_y;
|
||||||
|
|
||||||
|
@ -88,6 +134,133 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
||||||
return func_80832754(this, (play->unk_1887C != 0) || func_800B7128(this) || func_8082EF20(this));
|
return func_80832754(this, (play->unk_1887C != 0) || func_800B7128(this) || func_8082EF20(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern Input* sPlayerControlInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update for using telescopes. SCENE_AYASHIISHOP acts quite differently: it has a different camera mode and cannot use
|
||||||
|
* zooming.
|
||||||
|
*
|
||||||
|
* - Stick inputs move the view; shape.rot.y is used as a base position which cannot be looked too far away from. (This
|
||||||
|
* is not necessarily the same as the original angle of the spawn.)
|
||||||
|
* - A can be used to zoom (except in SCENE_AYASHIISHOP)
|
||||||
|
* - B exits, using the RESPAWN_MODE_DOWN entrance
|
||||||
|
*/
|
||||||
|
// @recomp Patched for aiming inversion and supporting the right stick in dual analog.
|
||||||
|
void func_8083A98C(Actor* thisx, PlayState* play2) {
|
||||||
|
PlayState* play = play2;
|
||||||
|
Player* this = (Player*)thisx;
|
||||||
|
s32 camMode;
|
||||||
|
|
||||||
|
if (play->csCtx.state != CS_STATE_IDLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @recomp Get the aiming camera inversion state.
|
||||||
|
s32 inverted_x, inverted_y;
|
||||||
|
recomp_get_inverted_axes(&inverted_x, &inverted_y);
|
||||||
|
// @recomp Get the analog camera input values if analog cam is enabled.
|
||||||
|
s32 analog_x = 0;
|
||||||
|
s32 analog_y = 0;
|
||||||
|
if (recomp_analog_cam_enabled()) {
|
||||||
|
float analog_x_float = 0.0f;
|
||||||
|
float analog_y_float = 0.0f;
|
||||||
|
recomp_get_camera_inputs(&analog_x_float, &analog_y_float);
|
||||||
|
// Scale by 127 to match what ultramodern does, then clamp to 60 to match the game's handling.
|
||||||
|
analog_x = (s32)(analog_x_float * 127.0f);
|
||||||
|
analog_x = CLAMP(analog_x, -60, 60);
|
||||||
|
analog_y = (s32)(analog_y_float * -127.0f);
|
||||||
|
analog_y = CLAMP(analog_y, -60, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DECR(this->av2.actionVar2) != 0) {
|
||||||
|
camMode = (play->sceneId != SCENE_AYASHIISHOP) ? CAM_MODE_FIRSTPERSON : CAM_MODE_DEKUHIDE;
|
||||||
|
|
||||||
|
// Show controls overlay. SCENE_AYASHIISHOP does not have Zoom, so has a different one.
|
||||||
|
if (this->av2.actionVar2 == 1) {
|
||||||
|
Message_StartTextbox(play, (play->sceneId == SCENE_AYASHIISHOP) ? 0x2A00 : 0x5E6, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// @recomp Manual relocation, TODO remove when automated.
|
||||||
|
Input* player_control_input = play->state.input;
|
||||||
|
*(Input**)KaleidoManager_GetRamAddr(&sPlayerControlInput) = player_control_input;
|
||||||
|
if (play->view.fovy >= 25.0f) {
|
||||||
|
s16 prevFocusX = thisx->focus.rot.x;
|
||||||
|
s16 prevFocusY = thisx->focus.rot.y;
|
||||||
|
s16 inputY;
|
||||||
|
s16 inputX;
|
||||||
|
s16 newYaw; // from base position shape.rot.y
|
||||||
|
|
||||||
|
// @recomp Add in the analog camera Y input. Clamp to prevent moving the camera twice as fast if both sticks are held.
|
||||||
|
// Pitch:
|
||||||
|
inputY = CLAMP(player_control_input->rel.stick_y + analog_y, -60, 60) * 4;
|
||||||
|
// @recomp Invert the Y axis accordingly (default is inverted, so negate if not inverted).
|
||||||
|
if (!inverted_y) {
|
||||||
|
inputY = -inputY;
|
||||||
|
}
|
||||||
|
// Add input, clamped to prevent turning too fast
|
||||||
|
thisx->focus.rot.x += CLAMP(inputY, -0x12C, 0x12C);
|
||||||
|
// Prevent looking too far up or down
|
||||||
|
thisx->focus.rot.x = CLAMP(thisx->focus.rot.x, -0x2EE0, 0x2EE0);
|
||||||
|
|
||||||
|
// @recomp Add in the analog camera X input. Clamp to prevent moving the camera twice as fast if both sticks are held.
|
||||||
|
// Yaw: shape.rot.y is used as a fixed starting position
|
||||||
|
inputX = CLAMP(player_control_input->rel.stick_x + analog_x, -60, 60) * -4;
|
||||||
|
// @recomp Invert the X axis accordingly.
|
||||||
|
if (inverted_x) {
|
||||||
|
inputX = -inputX;
|
||||||
|
}
|
||||||
|
// Start from current position: no input -> no change
|
||||||
|
newYaw = thisx->focus.rot.y - thisx->shape.rot.y;
|
||||||
|
// Add input, clamped to prevent turning too fast
|
||||||
|
newYaw += CLAMP(inputX, -0x12C, 0x12C);
|
||||||
|
// Prevent looking too far left or right of base position
|
||||||
|
newYaw = CLAMP(newYaw, -0x3E80, 0x3E80);
|
||||||
|
thisx->focus.rot.y = thisx->shape.rot.y + newYaw;
|
||||||
|
|
||||||
|
if (play->sceneId == SCENE_00KEIKOKU) {
|
||||||
|
f32 focusDeltaX = (s16)(thisx->focus.rot.x - prevFocusX);
|
||||||
|
f32 focusDeltaY = (s16)(thisx->focus.rot.y - prevFocusY);
|
||||||
|
|
||||||
|
Audio_PlaySfx_AtPosWithFreq(&gSfxDefaultPos, NA_SE_PL_TELESCOPE_MOVEMENT - SFX_FLAG,
|
||||||
|
sqrtf(SQ(focusDeltaX) + SQ(focusDeltaY)) / 300.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (play->sceneId == SCENE_AYASHIISHOP) {
|
||||||
|
camMode = CAM_MODE_DEKUHIDE;
|
||||||
|
} else if (CHECK_BTN_ALL(player_control_input->cur.button, BTN_A)) { // Zoom
|
||||||
|
camMode = CAM_MODE_TARGET;
|
||||||
|
} else {
|
||||||
|
camMode = CAM_MODE_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit
|
||||||
|
if (CHECK_BTN_ALL(player_control_input->press.button, BTN_B)) {
|
||||||
|
Message_CloseTextbox(play);
|
||||||
|
|
||||||
|
if (play->sceneId == SCENE_00KEIKOKU) {
|
||||||
|
gSaveContext.respawn[RESPAWN_MODE_DOWN].entrance = ENTRANCE(ASTRAL_OBSERVATORY, 2);
|
||||||
|
} else {
|
||||||
|
u16 entrance;
|
||||||
|
|
||||||
|
if (play->sceneId == SCENE_AYASHIISHOP) {
|
||||||
|
entrance = ENTRANCE(CURIOSITY_SHOP, 3);
|
||||||
|
} else {
|
||||||
|
entrance = ENTRANCE(PIRATES_FORTRESS_INTERIOR, 8);
|
||||||
|
}
|
||||||
|
gSaveContext.respawn[RESPAWN_MODE_DOWN].entrance = entrance;
|
||||||
|
}
|
||||||
|
|
||||||
|
func_80169EFC(&play->state);
|
||||||
|
gSaveContext.respawnFlag = -2;
|
||||||
|
play->transitionType = TRANS_TYPE_CIRCLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Camera_ChangeSetting(Play_GetCamera(play, CAM_ID_MAIN), CAM_SET_TELESCOPE);
|
||||||
|
Camera_ChangeMode(Play_GetCamera(play, CAM_ID_MAIN), camMode);
|
||||||
|
}
|
||||||
|
|
||||||
u32 sPlayerItemButtons[] = {
|
u32 sPlayerItemButtons[] = {
|
||||||
BTN_B,
|
BTN_B,
|
||||||
BTN_CLEFT,
|
BTN_CLEFT,
|
||||||
|
@ -95,18 +268,6 @@ u32 sPlayerItemButtons[] = {
|
||||||
BTN_CRIGHT,
|
BTN_CRIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
// u32 sPlayerItemButtonsDualAnalog[] = {
|
|
||||||
// BTN_B,
|
|
||||||
// BTN_DLEFT,
|
|
||||||
// BTN_DDOWN,
|
|
||||||
// BTN_DRIGHT
|
|
||||||
// };
|
|
||||||
|
|
||||||
// u32 prev_item_buttons = 0;
|
|
||||||
// u32 cur_item_buttons = 0;
|
|
||||||
// u32 pressed_item_buttons = 0;
|
|
||||||
// u32 released_item_buttons = 0;
|
|
||||||
|
|
||||||
// D-Pad items
|
// D-Pad items
|
||||||
|
|
||||||
#define EXTRA_ITEM_SLOT_COUNT 4
|
#define EXTRA_ITEM_SLOT_COUNT 4
|
||||||
|
@ -129,31 +290,6 @@ typedef enum {
|
||||||
EQUIP_SLOT_EX_DDOWN,
|
EQUIP_SLOT_EX_DDOWN,
|
||||||
} EquipSlotEx;
|
} EquipSlotEx;
|
||||||
|
|
||||||
// static inline void dup_to_cup(u16* button) {
|
|
||||||
// if (*button & BTN_DUP) {
|
|
||||||
// *button |= BTN_CUP;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
void GameState_GetInput(GameState* gameState) {
|
|
||||||
PadMgr_GetInput(gameState->input, true);
|
|
||||||
|
|
||||||
// if (recomp_camera_mode == RECOMP_CAMERA_DUALANALOG) {
|
|
||||||
// gameState->input[0].cur.button &= ~BTN_CUP;
|
|
||||||
// gameState->input[0].press.button &= ~BTN_CUP;
|
|
||||||
// gameState->input[0].rel.button &= ~BTN_CUP;
|
|
||||||
// dup_to_cup(&gameState->input[0].cur.button);
|
|
||||||
// dup_to_cup(&gameState->input[0].press.button);
|
|
||||||
// dup_to_cup(&gameState->input[0].rel.button);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// prev_item_buttons = cur_item_buttons;
|
|
||||||
// recomp_get_item_inputs(&cur_item_buttons);
|
|
||||||
// u32 button_diff = prev_item_buttons ^ cur_item_buttons;
|
|
||||||
// pressed_item_buttons = cur_item_buttons & button_diff;
|
|
||||||
// released_item_buttons = prev_item_buttons & button_diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ExButtonMapping {
|
struct ExButtonMapping {
|
||||||
u32 button;
|
u32 button;
|
||||||
EquipSlotEx slot;
|
EquipSlotEx slot;
|
||||||
|
@ -215,9 +351,6 @@ u8* get_button_item_equip_ptr(u32 form, u32 button) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern Input* sPlayerControlInput;
|
|
||||||
|
|
||||||
// Return currently-pressed button, in order of priority D-Pad, B, CLEFT, CDOWN, CRIGHT.
|
// Return currently-pressed button, in order of priority D-Pad, B, CLEFT, CDOWN, CRIGHT.
|
||||||
EquipSlot func_8082FDC4(void) {
|
EquipSlot func_8082FDC4(void) {
|
||||||
EquipSlot i;
|
EquipSlot i;
|
||||||
|
@ -320,7 +453,8 @@ void Player_Action_86(Player *this, PlayState *play) {
|
||||||
s32 sp48 = false;
|
s32 sp48 = false;
|
||||||
|
|
||||||
func_808323C0(this, play->playerCsIds[PLAYER_CS_ID_MASK_TRANSFORMATION]);
|
func_808323C0(this, play->playerCsIds[PLAYER_CS_ID_MASK_TRANSFORMATION]);
|
||||||
sPlayerControlInput = play->state.input;
|
// @recomp Manual relocation, TODO remove when automated.
|
||||||
|
*(Input**)KaleidoManager_GetRamAddr(&sPlayerControlInput) = play->state.input;
|
||||||
|
|
||||||
Camera_ChangeMode(GET_ACTIVE_CAM(play),
|
Camera_ChangeMode(GET_ACTIVE_CAM(play),
|
||||||
(this->transformation == PLAYER_FORM_HUMAN) ? CAM_MODE_NORMAL : CAM_MODE_JUMP);
|
(this->transformation == PLAYER_FORM_HUMAN) ? CAM_MODE_NORMAL : CAM_MODE_JUMP);
|
||||||
|
@ -349,7 +483,7 @@ void Player_Action_86(Player *this, PlayState *play) {
|
||||||
(sp48 =
|
(sp48 =
|
||||||
((this->transformation != PLAYER_FORM_HUMAN) || CHECK_WEEKEVENTREG(D_8085D908[GET_PLAYER_FORM])) &&
|
((this->transformation != PLAYER_FORM_HUMAN) || CHECK_WEEKEVENTREG(D_8085D908[GET_PLAYER_FORM])) &&
|
||||||
// @recomp Patched to also check for d-pad buttons for skipping the transformation cutscene.
|
// @recomp Patched to also check for d-pad buttons for skipping the transformation cutscene.
|
||||||
CHECK_BTN_ANY(sPlayerControlInput->press.button,
|
CHECK_BTN_ANY(play->state.input[0].press.button,
|
||||||
BTN_CRIGHT | BTN_CLEFT | BTN_CDOWN | BTN_CUP | BTN_B | BTN_A | BTN_DRIGHT | BTN_DLEFT | BTN_DDOWN | BTN_DUP)))) {
|
BTN_CRIGHT | BTN_CLEFT | BTN_CDOWN | BTN_CUP | BTN_B | BTN_A | BTN_DRIGHT | BTN_DLEFT | BTN_DDOWN | BTN_DUP)))) {
|
||||||
R_PLAY_FILL_SCREEN_ON = 45;
|
R_PLAY_FILL_SCREEN_ON = 45;
|
||||||
R_PLAY_FILL_SCREEN_R = 220;
|
R_PLAY_FILL_SCREEN_R = 220;
|
||||||
|
|
|
@ -12,6 +12,11 @@ extern RecompCameraMode recomp_camera_mode;
|
||||||
|
|
||||||
DECLARE_FUNC(void, recomp_get_gyro_deltas, float* x, float* y);
|
DECLARE_FUNC(void, recomp_get_gyro_deltas, float* x, float* y);
|
||||||
DECLARE_FUNC(void, recomp_get_mouse_deltas, float* x, float* y);
|
DECLARE_FUNC(void, recomp_get_mouse_deltas, float* x, float* y);
|
||||||
DECLARE_FUNC(int, recomp_get_targeting_mode);
|
DECLARE_FUNC(s32, recomp_get_targeting_mode);
|
||||||
|
DECLARE_FUNC(void, recomp_get_inverted_axes, s32* x, s32* y);
|
||||||
|
DECLARE_FUNC(s32, recomp_analog_cam_enabled);
|
||||||
|
DECLARE_FUNC(void, recomp_get_analog_inverted_axes, s32* x, s32* y);
|
||||||
|
DECLARE_FUNC(void, recomp_get_camera_inputs, float* x, float* y);
|
||||||
|
DECLARE_FUNC(void, recomp_set_right_analog_suppressed, s32 suppressed);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "z64viscvg.h"
|
#include "z64viscvg.h"
|
||||||
#include "z64vismono.h"
|
#include "z64vismono.h"
|
||||||
#include "z64viszbuf.h"
|
#include "z64viszbuf.h"
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
void recomp_set_current_frame_poll_id();
|
void recomp_set_current_frame_poll_id();
|
||||||
void PadMgr_HandleRetrace(void);
|
void PadMgr_HandleRetrace(void);
|
||||||
|
@ -62,11 +63,16 @@ void PadMgr_HandleRetrace(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern u8 sOcarinaInstrumentId;
|
||||||
|
|
||||||
void poll_inputs(void) {
|
void poll_inputs(void) {
|
||||||
OSMesgQueue* serialEventQueue = PadMgr_AcquireSerialEventQueue();
|
OSMesgQueue* serialEventQueue = PadMgr_AcquireSerialEventQueue();
|
||||||
// Begin reading controller data
|
// Begin reading controller data
|
||||||
osContStartReadData(serialEventQueue);
|
osContStartReadData(serialEventQueue);
|
||||||
|
|
||||||
|
// Suppress the right analog stick if analog camera is active unless the ocarina is in use.
|
||||||
|
recomp_set_right_analog_suppressed(recomp_analog_cam_enabled() && sOcarinaInstrumentId == OCARINA_INSTRUMENT_OFF);
|
||||||
|
|
||||||
// Wait for controller data
|
// Wait for controller data
|
||||||
osRecvMesg(serialEventQueue, NULL, OS_MESG_BLOCK);
|
osRecvMesg(serialEventQueue, NULL, OS_MESG_BLOCK);
|
||||||
osContGetReadData(sPadMgrInstance->pads);
|
osContGetReadData(sPadMgrInstance->pads);
|
||||||
|
|
|
@ -16,6 +16,7 @@ void Play_Main(GameState* thisx) {
|
||||||
// @recomp
|
// @recomp
|
||||||
debug_play_update(this);
|
debug_play_update(this);
|
||||||
controls_play_update(this);
|
controls_play_update(this);
|
||||||
|
analog_cam_pre_play_update(this);
|
||||||
matrix_play_update(this);
|
matrix_play_update(this);
|
||||||
|
|
||||||
// @recomp avoid unused variable warning
|
// @recomp avoid unused variable warning
|
||||||
|
@ -33,6 +34,7 @@ void Play_Main(GameState* thisx) {
|
||||||
camera_pre_play_update(this);
|
camera_pre_play_update(this);
|
||||||
Play_Update(this);
|
Play_Update(this);
|
||||||
camera_post_play_update(this);
|
camera_post_play_update(this);
|
||||||
|
analog_cam_post_play_update(this);
|
||||||
autosave_post_play_update(this);
|
autosave_post_play_update(this);
|
||||||
this->state.gfxCtx = gfxCtx;
|
this->state.gfxCtx = gfxCtx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
void debug_play_update(PlayState* play);
|
void debug_play_update(PlayState* play);
|
||||||
void camera_pre_play_update(PlayState* play);
|
void camera_pre_play_update(PlayState* play);
|
||||||
void camera_post_play_update(PlayState* play);
|
void camera_post_play_update(PlayState* play);
|
||||||
|
void analog_cam_pre_play_update(PlayState* play);
|
||||||
|
void analog_cam_post_play_update(PlayState* play);
|
||||||
void matrix_play_update(PlayState* play);
|
void matrix_play_update(PlayState* play);
|
||||||
void autosave_post_play_update(PlayState* play);
|
void autosave_post_play_update(PlayState* play);
|
||||||
|
|
||||||
|
|
|
@ -52,5 +52,10 @@ osGetTime_recomp = 0x8F000088;
|
||||||
recomp_autosave_enabled = 0x8F00008C;
|
recomp_autosave_enabled = 0x8F00008C;
|
||||||
recomp_load_overlays = 0x8F000090;
|
recomp_load_overlays = 0x8F000090;
|
||||||
osInvalICache_recomp = 0x8F000094;
|
osInvalICache_recomp = 0x8F000094;
|
||||||
|
recomp_analog_cam_enabled = 0x8F000098;
|
||||||
|
recomp_get_camera_inputs = 0x8F00009C;
|
||||||
|
recomp_set_right_analog_suppressed = 0x8F0000A0;
|
||||||
|
recomp_get_inverted_axes = 0x8F0000A4;
|
||||||
recomp_high_precision_fb_enabled = 0x8F0000A8;
|
recomp_high_precision_fb_enabled = 0x8F0000A8;
|
||||||
recomp_get_resolution_scale = 0x8F0000AC;
|
recomp_get_resolution_scale = 0x8F0000AC;
|
||||||
|
recomp_get_analog_inverted_axes = 0x8F0000B0;
|
||||||
|
|
|
@ -165,6 +165,9 @@ void save_general_config(const std::filesystem::path& path) {
|
||||||
config_json["mouse_sensitivity"] = recomp::get_mouse_sensitivity();
|
config_json["mouse_sensitivity"] = recomp::get_mouse_sensitivity();
|
||||||
config_json["joystick_deadzone"] = recomp::get_joystick_deadzone();
|
config_json["joystick_deadzone"] = recomp::get_joystick_deadzone();
|
||||||
config_json["autosave_mode"] = recomp::get_autosave_mode();
|
config_json["autosave_mode"] = recomp::get_autosave_mode();
|
||||||
|
config_json["camera_invert_mode"] = recomp::get_camera_invert_mode();
|
||||||
|
config_json["analog_cam_mode"] = recomp::get_analog_cam_mode();
|
||||||
|
config_json["analog_camera_invert_mode"] = recomp::get_analog_camera_invert_mode();
|
||||||
config_json["debug_mode"] = recomp::get_debug_mode_enabled();
|
config_json["debug_mode"] = recomp::get_debug_mode_enabled();
|
||||||
config_file << std::setw(4) << config_json;
|
config_file << std::setw(4) << config_json;
|
||||||
}
|
}
|
||||||
|
@ -177,6 +180,9 @@ void set_general_settings_from_json(const nlohmann::json& config_json) {
|
||||||
recomp::set_mouse_sensitivity(from_or_default(config_json, "mouse_sensitivity", is_steam_deck ? 50 : 0));
|
recomp::set_mouse_sensitivity(from_or_default(config_json, "mouse_sensitivity", is_steam_deck ? 50 : 0));
|
||||||
recomp::set_joystick_deadzone(from_or_default(config_json, "joystick_deadzone", 5));
|
recomp::set_joystick_deadzone(from_or_default(config_json, "joystick_deadzone", 5));
|
||||||
recomp::set_autosave_mode(from_or_default(config_json, "autosave_mode", recomp::AutosaveMode::On));
|
recomp::set_autosave_mode(from_or_default(config_json, "autosave_mode", recomp::AutosaveMode::On));
|
||||||
|
recomp::set_camera_invert_mode(from_or_default(config_json, "camera_invert_mode", recomp::CameraInvertMode::InvertY));
|
||||||
|
recomp::set_analog_cam_mode(from_or_default(config_json, "analog_cam_mode", recomp::AnalogCamMode::Off));
|
||||||
|
recomp::set_analog_camera_invert_mode(from_or_default(config_json, "analog_camera_invert_mode", recomp::CameraInvertMode::InvertNone));
|
||||||
recomp::set_debug_mode_enabled(from_or_default(config_json, "debug_mode", false));
|
recomp::set_debug_mode_enabled(from_or_default(config_json, "debug_mode", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,33 +95,7 @@ void recomp::get_n64_input(uint16_t* buttons_out, float* x_out, float* y_out) {
|
||||||
float joystick_y = recomp::get_input_analog(controller_input_mappings[(size_t)GameInput::Y_AXIS_POS])
|
float joystick_y = recomp::get_input_analog(controller_input_mappings[(size_t)GameInput::Y_AXIS_POS])
|
||||||
- recomp::get_input_analog(controller_input_mappings[(size_t)GameInput::Y_AXIS_NEG]);
|
- recomp::get_input_analog(controller_input_mappings[(size_t)GameInput::Y_AXIS_NEG]);
|
||||||
|
|
||||||
if(fabsf(joystick_x) < joystick_deadzone) {
|
recomp::apply_joystick_deadzone(joystick_x, joystick_y, &joystick_x, &joystick_y);
|
||||||
joystick_x = 0.0f;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(joystick_x > 0.0f) {
|
|
||||||
joystick_x -= joystick_deadzone;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
joystick_x += joystick_deadzone;
|
|
||||||
}
|
|
||||||
|
|
||||||
joystick_x /= (1.0f - joystick_deadzone);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fabsf(joystick_y) < joystick_deadzone) {
|
|
||||||
joystick_y = 0.0f;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(joystick_y > 0.0f) {
|
|
||||||
joystick_y -= joystick_deadzone;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
joystick_y += joystick_deadzone;
|
|
||||||
}
|
|
||||||
|
|
||||||
joystick_y /= (1.0f - joystick_deadzone);
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_x = recomp::get_input_analog(keyboard_input_mappings[(size_t)GameInput::X_AXIS_POS])
|
cur_x = recomp::get_input_analog(keyboard_input_mappings[(size_t)GameInput::X_AXIS_POS])
|
||||||
- recomp::get_input_analog(keyboard_input_mappings[(size_t)GameInput::X_AXIS_NEG]) + joystick_x;
|
- recomp::get_input_analog(keyboard_input_mappings[(size_t)GameInput::X_AXIS_NEG]) + joystick_x;
|
||||||
|
|
|
@ -483,7 +483,9 @@ bool controller_button_state(int32_t input_id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float controller_axis_state(int32_t input_id) {
|
static std::atomic_bool right_analog_suppressed = false;
|
||||||
|
|
||||||
|
float controller_axis_state(int32_t input_id, bool allow_suppression) {
|
||||||
if (abs(input_id) - 1 < SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_MAX) {
|
if (abs(input_id) - 1 < SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_MAX) {
|
||||||
SDL_GameControllerAxis axis = (SDL_GameControllerAxis)(abs(input_id) - 1);
|
SDL_GameControllerAxis axis = (SDL_GameControllerAxis)(abs(input_id) - 1);
|
||||||
bool negative_range = input_id < 0;
|
bool negative_range = input_id < 0;
|
||||||
|
@ -496,6 +498,12 @@ float controller_axis_state(int32_t input_id) {
|
||||||
if (negative_range) {
|
if (negative_range) {
|
||||||
cur_val = -cur_val;
|
cur_val = -cur_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if this input is a right analog axis and suppress it accordingly.
|
||||||
|
if (allow_suppression && right_analog_suppressed.load() &&
|
||||||
|
(axis == SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX || axis == SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY)) {
|
||||||
|
cur_val = 0;
|
||||||
|
}
|
||||||
ret += std::clamp(cur_val, 0.0f, 1.0f);
|
ret += std::clamp(cur_val, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,7 +526,7 @@ float recomp::get_input_analog(const recomp::InputField& field) {
|
||||||
case InputType::ControllerDigital:
|
case InputType::ControllerDigital:
|
||||||
return controller_button_state(field.input_id) ? 1.0f : 0.0f;
|
return controller_button_state(field.input_id) ? 1.0f : 0.0f;
|
||||||
case InputType::ControllerAnalog:
|
case InputType::ControllerAnalog:
|
||||||
return controller_axis_state(field.input_id);
|
return controller_axis_state(field.input_id, true);
|
||||||
case InputType::Mouse:
|
case InputType::Mouse:
|
||||||
// TODO mouse support
|
// TODO mouse support
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
@ -549,7 +557,7 @@ bool recomp::get_input_digital(const recomp::InputField& field) {
|
||||||
return controller_button_state(field.input_id);
|
return controller_button_state(field.input_id);
|
||||||
case InputType::ControllerAnalog:
|
case InputType::ControllerAnalog:
|
||||||
// TODO adjustable threshold
|
// TODO adjustable threshold
|
||||||
return controller_axis_state(field.input_id) >= axis_threshold;
|
return controller_axis_state(field.input_id, true) >= axis_threshold;
|
||||||
case InputType::Mouse:
|
case InputType::Mouse:
|
||||||
// TODO mouse support
|
// TODO mouse support
|
||||||
return false;
|
return false;
|
||||||
|
@ -580,6 +588,55 @@ void recomp::get_mouse_deltas(float* x, float* y) {
|
||||||
*y = cur_mouse_delta[1] * sensitivity;
|
*y = cur_mouse_delta[1] * sensitivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void recomp::apply_joystick_deadzone(float x_in, float y_in, float* x_out, float* y_out) {
|
||||||
|
float joystick_deadzone = (float)recomp::get_joystick_deadzone() / 100.0f;
|
||||||
|
|
||||||
|
if(fabsf(x_in) < joystick_deadzone) {
|
||||||
|
x_in = 0.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(x_in > 0.0f) {
|
||||||
|
x_in -= joystick_deadzone;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x_in += joystick_deadzone;
|
||||||
|
}
|
||||||
|
|
||||||
|
x_in /= (1.0f - joystick_deadzone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fabsf(y_in) < joystick_deadzone) {
|
||||||
|
y_in = 0.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(y_in > 0.0f) {
|
||||||
|
y_in -= joystick_deadzone;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
y_in += joystick_deadzone;
|
||||||
|
}
|
||||||
|
|
||||||
|
y_in /= (1.0f - joystick_deadzone);
|
||||||
|
}
|
||||||
|
|
||||||
|
*x_out = x_in;
|
||||||
|
*y_out = y_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomp::get_right_analog(float* x, float* y) {
|
||||||
|
float x_val =
|
||||||
|
controller_axis_state((SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX + 1), false) -
|
||||||
|
controller_axis_state(-(SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX + 1), false);
|
||||||
|
float y_val =
|
||||||
|
controller_axis_state((SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY + 1), false) -
|
||||||
|
controller_axis_state(-(SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY + 1), false);
|
||||||
|
recomp::apply_joystick_deadzone(x_val, y_val, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomp::set_right_analog_suppressed(bool suppressed) {
|
||||||
|
right_analog_suppressed.store(suppressed);
|
||||||
|
}
|
||||||
|
|
||||||
bool recomp::game_input_disabled() {
|
bool recomp::game_input_disabled() {
|
||||||
// Disable input if any menu is open.
|
// Disable input if any menu is open.
|
||||||
return recomp::get_current_menu() != recomp::Menu::None;
|
return recomp::get_current_menu() != recomp::Menu::None;
|
||||||
|
|
|
@ -110,3 +110,59 @@ extern "C" void recomp_high_precision_fb_enabled(uint8_t * rdram, recomp_context
|
||||||
extern "C" void recomp_get_resolution_scale(uint8_t* rdram, recomp_context* ctx) {
|
extern "C" void recomp_get_resolution_scale(uint8_t* rdram, recomp_context* ctx) {
|
||||||
_return(ctx, ultramodern::get_resolution_scale());
|
_return(ctx, ultramodern::get_resolution_scale());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void recomp_get_inverted_axes(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
s32* x_out = _arg<0, s32*>(rdram, ctx);
|
||||||
|
s32* y_out = _arg<1, s32*>(rdram, ctx);
|
||||||
|
|
||||||
|
recomp::CameraInvertMode mode = recomp::get_camera_invert_mode();
|
||||||
|
|
||||||
|
*x_out = (mode == recomp::CameraInvertMode::InvertX || mode == recomp::CameraInvertMode::InvertBoth);
|
||||||
|
*y_out = (mode == recomp::CameraInvertMode::InvertY || mode == recomp::CameraInvertMode::InvertBoth);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void recomp_get_analog_inverted_axes(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
s32* x_out = _arg<0, s32*>(rdram, ctx);
|
||||||
|
s32* y_out = _arg<1, s32*>(rdram, ctx);
|
||||||
|
|
||||||
|
recomp::CameraInvertMode mode = recomp::get_analog_camera_invert_mode();
|
||||||
|
|
||||||
|
*x_out = (mode == recomp::CameraInvertMode::InvertX || mode == recomp::CameraInvertMode::InvertBoth);
|
||||||
|
*y_out = (mode == recomp::CameraInvertMode::InvertY || mode == recomp::CameraInvertMode::InvertBoth);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void recomp_analog_cam_enabled(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
_return<s32>(ctx, recomp::get_analog_cam_mode() == recomp::AnalogCamMode::On);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void recomp_get_camera_inputs(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
float* x_out = _arg<0, float*>(rdram, ctx);
|
||||||
|
float* y_out = _arg<1, float*>(rdram, ctx);
|
||||||
|
|
||||||
|
// TODO expose this in the menu
|
||||||
|
constexpr float radial_deadzone = 0.05f;
|
||||||
|
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
recomp::get_right_analog(&x, &y);
|
||||||
|
|
||||||
|
float magnitude = sqrtf(x * x + y * y);
|
||||||
|
|
||||||
|
if (magnitude < radial_deadzone) {
|
||||||
|
*x_out = 0.0f;
|
||||||
|
*y_out = 0.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float x_normalized = x / magnitude;
|
||||||
|
float y_normalized = y / magnitude;
|
||||||
|
|
||||||
|
*x_out = x_normalized * ((magnitude - radial_deadzone) / (1 - radial_deadzone));
|
||||||
|
*y_out = y_normalized * ((magnitude - radial_deadzone) / (1 - radial_deadzone));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void recomp_set_right_analog_suppressed(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
s32 suppressed = _arg<0, s32>(rdram, ctx);
|
||||||
|
|
||||||
|
recomp::set_right_analog_suppressed(suppressed);
|
||||||
|
}
|
||||||
|
|
|
@ -278,6 +278,9 @@ struct ControlOptionsContext {
|
||||||
recomp::TargetingMode targeting_mode;
|
recomp::TargetingMode targeting_mode;
|
||||||
recomp::BackgroundInputMode background_input_mode;
|
recomp::BackgroundInputMode background_input_mode;
|
||||||
recomp::AutosaveMode autosave_mode;
|
recomp::AutosaveMode autosave_mode;
|
||||||
|
recomp::CameraInvertMode camera_invert_mode;
|
||||||
|
recomp::AnalogCamMode analog_cam_mode;
|
||||||
|
recomp::CameraInvertMode analog_camera_invert_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
ControlOptionsContext control_options_context;
|
ControlOptionsContext control_options_context;
|
||||||
|
@ -365,6 +368,39 @@ void recomp::set_autosave_mode(recomp::AutosaveMode mode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recomp::CameraInvertMode recomp::get_camera_invert_mode() {
|
||||||
|
return control_options_context.camera_invert_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomp::set_camera_invert_mode(recomp::CameraInvertMode mode) {
|
||||||
|
control_options_context.camera_invert_mode = mode;
|
||||||
|
if (general_model_handle) {
|
||||||
|
general_model_handle.DirtyVariable("camera_invert_mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recomp::AnalogCamMode recomp::get_analog_cam_mode() {
|
||||||
|
return control_options_context.analog_cam_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomp::set_analog_cam_mode(recomp::AnalogCamMode mode) {
|
||||||
|
control_options_context.analog_cam_mode = mode;
|
||||||
|
if (general_model_handle) {
|
||||||
|
general_model_handle.DirtyVariable("analog_cam_mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recomp::CameraInvertMode recomp::get_analog_camera_invert_mode() {
|
||||||
|
return control_options_context.analog_camera_invert_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomp::set_analog_camera_invert_mode(recomp::CameraInvertMode mode) {
|
||||||
|
control_options_context.analog_camera_invert_mode = mode;
|
||||||
|
if (general_model_handle) {
|
||||||
|
general_model_handle.DirtyVariable("analog_camera_invert_mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct SoundOptionsContext {
|
struct SoundOptionsContext {
|
||||||
std::atomic<int> main_volume; // Option to control the volume of all sound
|
std::atomic<int> main_volume; // Option to control the volume of all sound
|
||||||
std::atomic<int> bgm_volume;
|
std::atomic<int> bgm_volume;
|
||||||
|
@ -864,6 +900,9 @@ public:
|
||||||
bind_option(constructor, "targeting_mode", &control_options_context.targeting_mode);
|
bind_option(constructor, "targeting_mode", &control_options_context.targeting_mode);
|
||||||
bind_option(constructor, "background_input_mode", &control_options_context.background_input_mode);
|
bind_option(constructor, "background_input_mode", &control_options_context.background_input_mode);
|
||||||
bind_option(constructor, "autosave_mode", &control_options_context.autosave_mode);
|
bind_option(constructor, "autosave_mode", &control_options_context.autosave_mode);
|
||||||
|
bind_option(constructor, "camera_invert_mode", &control_options_context.camera_invert_mode);
|
||||||
|
bind_option(constructor, "analog_cam_mode", &control_options_context.analog_cam_mode);
|
||||||
|
bind_option(constructor, "analog_camera_invert_mode", &control_options_context.analog_camera_invert_mode);
|
||||||
|
|
||||||
general_model_handle = constructor.GetModelHandle();
|
general_model_handle = constructor.GetModelHandle();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue