add toggle for double SoT

This commit is contained in:
danielryb 2024-06-19 23:58:43 +02:00
parent 2d0ce9f68d
commit a6e69066b2
12 changed files with 216 additions and 86 deletions

View File

@ -268,7 +268,7 @@
data-checked="analog_camera_invert_mode" data-checked="analog_camera_invert_mode"
value="InvertNone" value="InvertNone"
id="analog_camera_inversion_none" id="analog_camera_inversion_none"
style="nav-up: #analog_cam_enabled;" style="nav-up: #analog_cam_enabled; nav-down: #dsot_enabled"
/> />
<label class="config-option__tab-label" for="analog_camera_inversion_none">None</label> <label class="config-option__tab-label" for="analog_camera_inversion_none">None</label>
@ -280,7 +280,7 @@
data-checked="analog_camera_invert_mode" data-checked="analog_camera_invert_mode"
value="InvertX" value="InvertX"
id="analog_camera_inversion_x" id="analog_camera_inversion_x"
style="nav-up: #analog_cam_disabled;" style="nav-up: #analog_cam_disabled; nav-down: #dsot_disabled"
/> />
<label class="config-option__tab-label" for="analog_camera_inversion_x">Invert X</label> <label class="config-option__tab-label" for="analog_camera_inversion_x">Invert X</label>
@ -292,7 +292,7 @@
data-checked="analog_camera_invert_mode" data-checked="analog_camera_invert_mode"
value="InvertY" value="InvertY"
id="analog_camera_inversion_y" id="analog_camera_inversion_y"
style="nav-up: #analog_cam_disabled;" style="nav-up: #analog_cam_disabled; nav-down: #dsot_disabled"
/> />
<label class="config-option__tab-label" for="analog_camera_inversion_y">Invert Y</label> <label class="config-option__tab-label" for="analog_camera_inversion_y">Invert Y</label>
@ -304,11 +304,40 @@
data-checked="analog_camera_invert_mode" data-checked="analog_camera_invert_mode"
value="InvertBoth" value="InvertBoth"
id="analog_camera_inversion_both" id="analog_camera_inversion_both"
style="nav-up: #analog_cam_disabled;" style="nav-up: #analog_cam_disabled; nav-down: #dsot_disabled"
/> />
<label class="config-option__tab-label" for="analog_camera_inversion_both">Invert Both</label> <label class="config-option__tab-label" for="analog_camera_inversion_both">Invert Both</label>
</div> </div>
</div> </div>
<!-- better double song of time -->
<div class="config-option" data-event-mouseover="set_cur_config_index(10)">
<label class="config-option__title">Better Double Song of Time</label>
<div class="config-option__list">
<input
type="radio"
data-event-blur="set_cur_config_index(-1)"
data-event-focus="set_cur_config_index(10)"
name="dsot_mode"
data-checked="dsot_mode"
value="On"
id="dsot_enabled"
style="nav-up: #analog_camera_inversion_none"
/>
<label class="config-option__tab-label" for="dsot_enabled">On</label>
<input
type="radio"
data-event-blur="set_cur_config_index(-1)"
data-event-focus="set_cur_config_index(10)"
name="dsot_mode"
data-checked="dsot_mode"
value="Off"
id="dsot_disabled"
style="nav-up: #analog_camera_inversion_x"
/>
<label class="config-option__tab-label" for="dsot_disabled">Off</label>
</div>
</div>
</div> </div>
<!-- Descriptions --> <!-- Descriptions -->
<div class="config__wrapper"> <div class="config__wrapper">
@ -362,6 +391,12 @@
<p data-if="cur_config_index == 9"> <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. Inverts the camera controls for the analog camera if it's enabled. <b>None</b> is the default.
</p> </p>
<p data-if="cur_config_index == 10">
Enables hour selection for Double Song of Time.
<br/>
<br/>
To select an hour move the left analog stick in horizontal axis.
</p>
</div> </div>
</div> </div>
</form> </form>

View File

@ -79,6 +79,17 @@ namespace zelda64 {
{zelda64::AnalogCamMode::Off, "Off"} {zelda64::AnalogCamMode::Off, "Off"}
}); });
enum class DsotMode {
On,
Off,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(zelda64::DsotMode, {
{zelda64::DsotMode::On, "On"},
{zelda64::DsotMode::Off, "Off"}
});
AutosaveMode get_autosave_mode(); AutosaveMode get_autosave_mode();
void set_autosave_mode(AutosaveMode mode); void set_autosave_mode(AutosaveMode mode);
@ -86,6 +97,9 @@ namespace zelda64 {
void set_analog_cam_mode(AnalogCamMode mode); void set_analog_cam_mode(AnalogCamMode mode);
void open_quit_game_prompt(); void open_quit_game_prompt();
DsotMode get_dsot_mode();
void set_dsot_mode(DsotMode mode);
}; };
#endif #endif

View File

@ -3,6 +3,16 @@
void dsot_load_day_number_texture(PlayState* play, s32 day); void dsot_load_day_number_texture(PlayState* play, s32 day);
void dsot_actor_fixes(PlayState* play); void dsot_actor_fixes(PlayState* play);
bool dsot_on;
void dsot_determine_enabled(void) {
dsot_on = recomp_dsot_enabled();
}
bool dsot_enabled(void) {
return dsot_on;
}
u8 choiceHour; u8 choiceHour;
void dsot_init_hour_selection(PlayState* play) { void dsot_init_hour_selection(PlayState* play) {

View File

@ -338,8 +338,8 @@ void EnTest6_DoubleSoTCutscene(EnTest6* this, PlayState* play) {
SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_FANFARE, 20); SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_FANFARE, 20);
} }
// @recomp Advance hour as Double SoT ends. // @recomp Replace DSoT functionality if the option for it is enabled.
if (this->timer == 15) { if (dsot_enabled() && this->timer == 15) {
dsot_advance_hour(play); dsot_advance_hour(play);
} }
@ -586,7 +586,18 @@ void EnTest6_SharedSoTCutscene(EnTest6* this, PlayState* play) {
return; return;
case SOTCS_CUEID_DOUBLE_END: case SOTCS_CUEID_DOUBLE_END:
// @recomp Disable scene reset after Double SoT ends. // @recomp Replace DSoT functionality if the option for it is enabled.
if (!dsot_enabled() && (CURRENT_TIME > CLOCK_TIME(12, 0))) {
Play_SetRespawnData(&play->state, RESPAWN_MODE_RETURN, ((void)0, gSaveContext.save.entrance),
player->unk_3CE, PLAYER_PARAMS(0xFF, PLAYER_INITMODE_B), &player->unk_3C0,
player->unk_3CC);
this->drawType = SOTCS_DRAW_TYPE_NONE;
play->transitionTrigger = TRANS_TRIGGER_START;
play->nextEntrance = gSaveContext.respawn[RESPAWN_MODE_RETURN].entrance;
play->transitionType = TRANS_TYPE_FADE_BLACK;
gSaveContext.respawnFlag = 2;
play->msgCtx.ocarinaMode = OCARINA_MODE_END;
}
return; return;
} }
} }

View File

@ -452,23 +452,43 @@ void Message_Update(PlayState* play) {
} }
} else if ((msgCtx->textboxEndType == TEXTBOX_ENDTYPE_10) && } else if ((msgCtx->textboxEndType == TEXTBOX_ENDTYPE_10) &&
(play->msgCtx.ocarinaMode == OCARINA_MODE_PROCESS_DOUBLE_TIME)) { (play->msgCtx.ocarinaMode == OCARINA_MODE_PROCESS_DOUBLE_TIME)) {
// @recomp // @recomp Replace DSoT functionality if the option for it is enabled.
dsot_handle_hour_selection(play); if (dsot_enabled()) {
// @recomp
dsot_handle_hour_selection(play);
if (Message_ShouldAdvance(play)) { if (Message_ShouldAdvance(play)) {
if (msgCtx->choiceIndex == 0) { if (msgCtx->choiceIndex == 0) {
Audio_PlaySfx_MessageDecide(); Audio_PlaySfx_MessageDecide();
play->msgCtx.ocarinaMode = OCARINA_MODE_APPLY_DOUBLE_SOT; play->msgCtx.ocarinaMode = OCARINA_MODE_APPLY_DOUBLE_SOT;
gSaveContext.timerStates[TIMER_ID_MOON_CRASH] = TIMER_STATE_OFF; gSaveContext.timerStates[TIMER_ID_MOON_CRASH] = TIMER_STATE_OFF;
} else { } else {
Audio_PlaySfx_MessageCancel(); Audio_PlaySfx_MessageCancel();
play->msgCtx.ocarinaMode = OCARINA_MODE_END; play->msgCtx.ocarinaMode = OCARINA_MODE_END;
// @recomp // @recomp
dsot_cancel_hour_selection(play); dsot_cancel_hour_selection(play);
}
Message_CloseTextbox(play);
}
} else {
if (Message_ShouldAdvance(play)) {
if (msgCtx->choiceIndex == 0) {
Audio_PlaySfx_MessageDecide();
if (gSaveContext.save.isNight != 0) {
gSaveContext.save.time = CLOCK_TIME(6, 0);
} else {
gSaveContext.save.time = CLOCK_TIME(18, 0);
}
play->msgCtx.ocarinaMode = OCARINA_MODE_APPLY_DOUBLE_SOT;
gSaveContext.timerStates[TIMER_ID_MOON_CRASH] = TIMER_STATE_OFF;
} else {
Audio_PlaySfx_MessageCancel();
play->msgCtx.ocarinaMode = OCARINA_MODE_END;
}
Message_CloseTextbox(play);
} }
Message_CloseTextbox(play);
} }
} else if ((msgCtx->textboxEndType != TEXTBOX_ENDTYPE_10) || } else if ((msgCtx->textboxEndType != TEXTBOX_ENDTYPE_10) ||
(pauseCtx->state != PAUSE_STATE_OWL_WARP_CONFIRM)) { (pauseCtx->state != PAUSE_STATE_OWL_WARP_CONFIRM)) {
@ -659,49 +679,66 @@ void Message_Update(PlayState* play) {
play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_RESTRICTED_SONG; play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_RESTRICTED_SONG;
} }
} else if (sLastPlayedSong == OCARINA_SONG_DOUBLE_TIME) { } else if (sLastPlayedSong == OCARINA_SONG_DOUBLE_TIME) {
// @recomp Patch Song of Double Time.
if (interfaceCtx->restrictions.songOfDoubleTime == 0) { if (interfaceCtx->restrictions.songOfDoubleTime == 0) {
if ((CURRENT_DAY != 3) || (CURRENT_TIME < CLOCK_TIME(5, 0)) || (CURRENT_TIME >= CLOCK_TIME(6, 0))) { // @recomp
Message_StartTextbox(play, D_801D0464[0], NULL); dsot_determine_enabled();
// @recomp Replace message text. // @recomp Replace DSoT functionality if the option for it is enabled.
char *buf = play->msgCtx.font.msgBuf.schar; if (dsot_enabled()) {
buf[25] = ' '; if ((CURRENT_DAY != 3) || (CURRENT_TIME < CLOCK_TIME(5, 0)) || (CURRENT_TIME >= CLOCK_TIME(6, 0))) {
buf[26] = 1; Message_StartTextbox(play, D_801D0464[0], NULL);
buf[27] = 'S';
buf[28] = 'e';
buf[29] = 'l';
buf[30] = 'e';
buf[31] = 'c';
buf[32] = 't';
buf[33] = 'e';
buf[34] = 'd';
buf[35] = ' ';
buf[36] = 'H';
buf[37] = 'o';
buf[38] = 'u';
buf[39] = 'r';
buf[40] = 0;
buf[41] = '?';
buf[42] = 17;
buf[43] = 17;
buf[44] = 2;
buf[45] = -62;
buf[46] = 'Y';
buf[47] = 'e';
buf[48] = 's';
buf[49] = 17;
buf[50] = 'N';
buf[51] = 'o';
buf[52] = -65;
play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_DOUBLE_TIME; // @recomp Replace message text.
char *buf = play->msgCtx.font.msgBuf.schar;
buf[25] = ' ';
buf[26] = 1;
buf[27] = 'S';
buf[28] = 'e';
buf[29] = 'l';
buf[30] = 'e';
buf[31] = 'c';
buf[32] = 't';
buf[33] = 'e';
buf[34] = 'd';
buf[35] = ' ';
buf[36] = 'H';
buf[37] = 'o';
buf[38] = 'u';
buf[39] = 'r';
buf[40] = 0;
buf[41] = '?';
buf[42] = 17;
buf[43] = 17;
buf[44] = 2;
buf[45] = -62;
buf[46] = 'Y';
buf[47] = 'e';
buf[48] = 's';
buf[49] = 17;
buf[50] = 'N';
buf[51] = 'o';
buf[52] = -65;
// @recomp play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_DOUBLE_TIME;
dsot_init_hour_selection(play);
// @recomp
dsot_init_hour_selection(play);
} else {
Message_StartTextbox(play, 0x1B94, NULL);
play->msgCtx.ocarinaMode = OCARINA_MODE_END;
}
} else { } else {
Message_StartTextbox(play, 0x1B94, NULL); if ((CURRENT_DAY != 3) || (gSaveContext.save.isNight == 0)) {
play->msgCtx.ocarinaMode = OCARINA_MODE_END; if (gSaveContext.save.isNight) {
Message_StartTextbox(play, D_801D0464[CURRENT_DAY - 1], NULL);
} else {
Message_StartTextbox(play, D_801D045C[CURRENT_DAY - 1], NULL);
}
play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_DOUBLE_TIME;
} else {
Message_StartTextbox(play, 0x1B94, NULL);
play->msgCtx.ocarinaMode = OCARINA_MODE_END;
}
} }
} else { } else {
sLastPlayedSong = 0xFF; sLastPlayedSong = 0xFF;

View File

@ -11,5 +11,6 @@ DECLARE_FUNC(void, recomp_handle_quicksave_actions_main, OSMesgQueue* enter_mq,
DECLARE_FUNC(u16, recomp_get_pending_warp); DECLARE_FUNC(u16, recomp_get_pending_warp);
DECLARE_FUNC(u32, recomp_get_pending_set_time); DECLARE_FUNC(u32, recomp_get_pending_set_time);
DECLARE_FUNC(s32, recomp_autosave_enabled); DECLARE_FUNC(s32, recomp_autosave_enabled);
DECLARE_FUNC(s32, recomp_dsot_enabled);
#endif #endif

View File

@ -108,6 +108,8 @@ void draw_autosave_icon(PlayState* play);
void recomp_crash(const char* err); void recomp_crash(const char* err);
void dsot_determine_enabled(void);
bool dsot_enabled(void);
void dsot_init_hour_selection(PlayState* play); void dsot_init_hour_selection(PlayState* play);
void dsot_handle_hour_selection(PlayState* play); void dsot_handle_hour_selection(PlayState* play);
void dsot_cancel_hour_selection(PlayState* play); void dsot_cancel_hour_selection(PlayState* play);

View File

@ -60,3 +60,4 @@ 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; recomp_get_analog_inverted_axes = 0x8F0000B0;
recomp_dsot_enabled = 0x8F0000B4;

View File

@ -990,8 +990,8 @@ void Message_DrawTextBox(PlayState* play, Gfx** gfxP) {
gSPPopMatrix(gfx++, G_MTX_MODELVIEW); gSPPopMatrix(gfx++, G_MTX_MODELVIEW);
} }
// @recomp Draw clock for Double SoT. // @recomp Replace DSoT functionality if the option for it is enabled.
if (play->msgCtx.ocarinaMode == OCARINA_MODE_PROCESS_DOUBLE_TIME) { if (dsot_enabled() && (play->msgCtx.ocarinaMode == OCARINA_MODE_PROCESS_DOUBLE_TIME)) {
dsot_draw_clock(play); dsot_draw_clock(play);
} }

View File

@ -221,6 +221,7 @@ bool save_general_config(const std::filesystem::path& path) {
config_json["analog_cam_mode"] = zelda64::get_analog_cam_mode(); config_json["analog_cam_mode"] = zelda64::get_analog_cam_mode();
config_json["analog_camera_invert_mode"] = zelda64::get_analog_camera_invert_mode(); config_json["analog_camera_invert_mode"] = zelda64::get_analog_camera_invert_mode();
config_json["debug_mode"] = zelda64::get_debug_mode_enabled(); config_json["debug_mode"] = zelda64::get_debug_mode_enabled();
config_json["dsot_mode"] = zelda64::get_dsot_mode();
return save_json_with_backups(path, config_json); return save_json_with_backups(path, config_json);
} }
@ -237,6 +238,7 @@ void set_general_settings_from_json(const nlohmann::json& config_json) {
zelda64::set_analog_cam_mode(from_or_default(config_json, "analog_cam_mode", zelda64::AnalogCamMode::Off)); zelda64::set_analog_cam_mode(from_or_default(config_json, "analog_cam_mode", zelda64::AnalogCamMode::Off));
zelda64::set_analog_camera_invert_mode(from_or_default(config_json, "analog_camera_invert_mode", zelda64::CameraInvertMode::InvertNone)); zelda64::set_analog_camera_invert_mode(from_or_default(config_json, "analog_camera_invert_mode", zelda64::CameraInvertMode::InvertNone));
zelda64::set_debug_mode_enabled(from_or_default(config_json, "debug_mode", false)); zelda64::set_debug_mode_enabled(from_or_default(config_json, "debug_mode", false));
zelda64::set_dsot_mode(from_or_default(config_json, "dsot_mode", zelda64::DsotMode::On));
} }
bool load_general_config(const std::filesystem::path& path) { bool load_general_config(const std::filesystem::path& path) {

View File

@ -95,6 +95,10 @@ extern "C" void recomp_autosave_enabled(uint8_t* rdram, recomp_context* ctx) {
_return(ctx, static_cast<s32>(zelda64::get_autosave_mode() == zelda64::AutosaveMode::On)); _return(ctx, static_cast<s32>(zelda64::get_autosave_mode() == zelda64::AutosaveMode::On));
} }
extern "C" void recomp_dsot_enabled(uint8_t* rdram, recomp_context* ctx) {
_return(ctx, static_cast<s32>(zelda64::get_dsot_mode() == zelda64::DsotMode::On));
}
extern "C" void recomp_load_overlays(uint8_t * rdram, recomp_context * ctx) { extern "C" void recomp_load_overlays(uint8_t * rdram, recomp_context * ctx) {
u32 rom = _arg<0, u32>(rdram, ctx); u32 rom = _arg<0, u32>(rdram, ctx);
PTR(void) ram = _arg<1, PTR(void)>(rdram, ctx); PTR(void) ram = _arg<1, PTR(void)>(rdram, ctx);

View File

@ -281,6 +281,7 @@ struct ControlOptionsContext {
zelda64::CameraInvertMode camera_invert_mode; zelda64::CameraInvertMode camera_invert_mode;
zelda64::AnalogCamMode analog_cam_mode; zelda64::AnalogCamMode analog_cam_mode;
zelda64::CameraInvertMode analog_camera_invert_mode; zelda64::CameraInvertMode analog_camera_invert_mode;
zelda64::DsotMode dsot_mode;
}; };
ControlOptionsContext control_options_context; ControlOptionsContext control_options_context;
@ -401,6 +402,17 @@ void zelda64::set_analog_camera_invert_mode(zelda64::CameraInvertMode mode) {
} }
} }
zelda64::DsotMode zelda64::get_dsot_mode() {
return control_options_context.dsot_mode;
}
void zelda64::set_dsot_mode(zelda64::DsotMode mode) {
control_options_context.dsot_mode = mode;
if (general_model_handle) {
general_model_handle.DirtyVariable("dsot_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;
@ -903,6 +915,7 @@ public:
bind_option(constructor, "camera_invert_mode", &control_options_context.camera_invert_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_cam_mode", &control_options_context.analog_cam_mode);
bind_option(constructor, "analog_camera_invert_mode", &control_options_context.analog_camera_invert_mode); bind_option(constructor, "analog_camera_invert_mode", &control_options_context.analog_camera_invert_mode);
bind_option(constructor, "dsot_mode", &control_options_context.dsot_mode);
general_model_handle = constructor.GetModelHandle(); general_model_handle = constructor.GetModelHandle();
} }