Skip to content

Commit

Permalink
Merge branch 'develop' into test-things-together-1
Browse files Browse the repository at this point in the history
  • Loading branch information
Sarge-117 committed Feb 15, 2025
2 parents 85e0518 + 20a9f41 commit 76f4908
Show file tree
Hide file tree
Showing 18 changed files with 111 additions and 148 deletions.
1 change: 0 additions & 1 deletion soh/include/functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,6 @@ uint16_t Interface_DrawTextLine(GraphicsContext* gfx, char text[], int16_t x, in
u8 Item_Give(PlayState* play, u8 item);
u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry);
u8 Item_CheckObtainability(u8 item);
void PerformAutosave(PlayState* play, u8 item);
void Inventory_DeleteItem(u16 item, u16 invSlot);
s32 Inventory_ReplaceItem(PlayState* play, u16 oldItem, u16 newItem);
s32 Inventory_HasEmptyBottle(void);
Expand Down
78 changes: 78 additions & 0 deletions soh/soh/Enhancements/Autosave.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <libultraship/bridge.h>
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Notification/Notification.h"
#include "soh/ShipInit.hpp"
#include "soh/SaveManager.h"

extern "C" {
extern PlayState* gPlayState;
#include "functions.h"
#include "variables.h"
}

static uint64_t lastSaveTimestamp = GetUnixTimestamp();

#define CVAR_AUTOSAVE_NAME CVAR_ENHANCEMENT("Autosave")
#define CVAR_AUTOSAVE_DEFAULT AUTOSAVE_OFF
#define CVAR_AUTOSAVE_VALUE CVarGetInteger(CVAR_AUTOSAVE_NAME, CVAR_AUTOSAVE_DEFAULT)
#define THREE_MINUTES_IN_UNIX 3 * 60000

typedef enum {
AUTOSAVE_OFF,
AUTOSAVE_ON,
} AutosaveOptions;

bool Autosave_CanSave() {

// Don't save when in title screen
// Don't save the first 60 frames to not save the magic meter when it's still in the animation of filling it.
// Don't save in Ganon's fight and chamber of sages because of master sword and remember save location issues.
if (!GameInteractor::IsSaveLoaded(true) || gPlayState->gameplayFrames < 60 ||
gPlayState->sceneNum == SCENE_GANON_BOSS || gPlayState->sceneNum == SCENE_CHAMBER_OF_THE_SAGES) {
return false;
}

return true;
}

void Autosave_PerformSave() {
Play_PerformSave(gPlayState);

// Send notification
Notification::Emit({
.message = "Game autosaved",
});
}

void Autosave_IntervalSave() {
// Check if the interval has passed in minutes.
uint64_t currentTimestamp = GetUnixTimestamp();
if ((currentTimestamp - lastSaveTimestamp) < THREE_MINUTES_IN_UNIX) {
return;
}

// If save available to create, do it and reset the interval.
// Interval gets extra check for being paused to avoid rare issues like bypassing shop
// rupees draining after buying an item. Since the interval can just retry until it
// passes, it can use more conditions without hampering the player experience.
if (Autosave_CanSave() && !GameInteractor::IsGameplayPaused()) {

// Reset timestamp, set icon timer to show autosave icon for 5 seconds (100 frames)
lastSaveTimestamp = currentTimestamp;

Autosave_PerformSave();
}
}

void Autosave_SoftResetSave() {
if (Autosave_CanSave()) {
Autosave_PerformSave();
}
}

void RegisterAutosave() {
COND_HOOK(GameInteractor::OnGameFrameUpdate, CVAR_AUTOSAVE_VALUE, Autosave_IntervalSave);
COND_HOOK(GameInteractor::OnExitGame, CVAR_AUTOSAVE_VALUE, [](int32_t fileNum) { Autosave_SoftResetSave(); });
}

static RegisterShipInitFunc initFunc(RegisterAutosave, { CVAR_AUTOSAVE_NAME });
4 changes: 4 additions & 0 deletions soh/soh/Enhancements/Autosave.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
typedef enum {
AUTOSAVE_OFF,
AUTOSAVE_ON,
} AutosaveOptions;
7 changes: 0 additions & 7 deletions soh/soh/Enhancements/boss-rush/BossRush.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,13 +522,6 @@ void BossRush_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
}
break;
}
// Replace the blue warp transitions with ones that lead back to the chamber of sages
case VB_BLUE_WARP_APPLY_ENTRANCE_AND_CUTSCENE: {
DoorWarp1* blueWarp = va_arg(args, DoorWarp1*);
BossRush_HandleBlueWarp(gPlayState, blueWarp->actor.world.pos.x, blueWarp->actor.world.pos.z);
*should = false;
break;
}
// Spawn clean blue warps (no ruto, adult animation, etc)
case VB_SPAWN_BLUE_WARP: {
switch (gPlayState->sceneNum) {
Expand Down
1 change: 0 additions & 1 deletion soh/soh/Enhancements/debugconsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ static bool ResetHandler(std::shared_ptr<Ship::Console> Console, std::vector<std
ERROR_MESSAGE("gGameState == nullptr");
return 1;
}

SET_NEXT_GAMESTATE(gGameState, TitleSetup_Init, GameState);
gGameState->running = false;
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnExitGame>(gSaveContext.fileNum);
Expand Down
9 changes: 0 additions & 9 deletions soh/soh/Enhancements/enhancementTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,6 @@ typedef enum {
ENEMY_RANDOMIZER_RANDOM_SEEDED,
} EnemyRandomizerMode;

typedef enum {
AUTOSAVE_OFF,
AUTOSAVE_LOCATION_AND_MAJOR_ITEMS,
AUTOSAVE_LOCATION_AND_ALL_ITEMS,
AUTOSAVE_LOCATION,
AUTOSAVE_MAJOR_ITEMS,
AUTOSAVE_ALL_ITEMS
} AutosaveType;

typedef enum {
BOOTSEQUENCE_DEFAULT,
BOOTSEQUENCE_AUTHENTIC,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,6 @@ typedef enum {
// - None
VB_BIGGORON_CONSIDER_TRADE_COMPLETE,

// # UNUSED
VB_BLUE_WARP_APPLY_ENTRANCE_AND_CUTSCENE,

// #### `result`
// Actor is ACTOR_EN_ELF, ACTOR_EN_FISH, ACTOR_EN_ICE_HONO, or ACTOR_EN_INSECT
// ```c
Expand Down Expand Up @@ -335,9 +332,6 @@ typedef enum {
// - None
VB_DEKU_STICK_BURN_OUT,

// # UNUSED
VB_DEKU_UPDATE_BURNING_DEKU_STICK,

// #### `result`
// ```c
// Flags_GetItemGetInf(ITEMGETINF_30)
Expand Down Expand Up @@ -730,12 +724,6 @@ typedef enum {
// - None
VB_GIVE_ITEM_GERUDO_MEMBERSHIP_CARD,

// # UNUSED
VB_GIVE_ITEM_GORON_RUBY,

// # UNUSED
VB_GIVE_ITEM_KOKIRI_EMERALD,

// #### `result`
// ```c
// true
Expand Down Expand Up @@ -904,9 +892,6 @@ typedef enum {
// - None
VB_GIVE_ITEM_ZELDAS_LULLABY,

// # UNUSED
VB_GIVE_ITEM_ZORA_SAPPHIRE,

// #### `result`
// ```c
// false
Expand Down Expand Up @@ -1390,9 +1375,6 @@ typedef enum {
// - None
VB_PLAY_NABOORU_CAPTURED_CS,

// # UNUSED
VB_PLAY_ODD_POTION_ANIM,

// #### `result`
// ```c
// true
Expand Down
82 changes: 0 additions & 82 deletions soh/soh/Enhancements/mods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,87 +135,6 @@ void RegisterOcarinaTimeTravel() {
});
}

void AutoSave(GetItemEntry itemEntry) {
u8 item = itemEntry.itemId;
bool performSave = false;
// Don't autosave immediately after buying items from shops to prevent getting them for free!
// Don't autosave in the Chamber of Sages since resuming from that map breaks the game
// Don't autosave during the Ganon fight when picking up the Master Sword
if ((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) != AUTOSAVE_OFF) && (gPlayState != NULL) && (gSaveContext.ship.pendingSale == ITEM_NONE) &&
(gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0) && (gPlayState->sceneNum != SCENE_GANON_BOSS) && (gPlayState->sceneNum != SCENE_CHAMBER_OF_THE_SAGES)) {
if (((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS) || (CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_ALL_ITEMS)) && (item != ITEM_NONE)) {
// Autosave for all items
performSave = true;

} else if (((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_MAJOR_ITEMS) || (CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_MAJOR_ITEMS)) && (item != ITEM_NONE)) {
// Autosave for major items
if (itemEntry.modIndex == 0) {
switch (item) {
case ITEM_STICK:
case ITEM_NUT:
case ITEM_BOMB:
case ITEM_BOW:
case ITEM_SEEDS:
case ITEM_FISHING_POLE:
case ITEM_MAGIC_SMALL:
case ITEM_MAGIC_LARGE:
case ITEM_INVALID_4:
case ITEM_INVALID_5:
case ITEM_INVALID_6:
case ITEM_INVALID_7:
case ITEM_HEART:
case ITEM_RUPEE_GREEN:
case ITEM_RUPEE_BLUE:
case ITEM_RUPEE_RED:
case ITEM_RUPEE_PURPLE:
case ITEM_RUPEE_GOLD:
case ITEM_INVALID_8:
case ITEM_STICKS_5:
case ITEM_STICKS_10:
case ITEM_NUTS_5:
case ITEM_NUTS_10:
case ITEM_BOMBS_5:
case ITEM_BOMBS_10:
case ITEM_BOMBS_20:
case ITEM_BOMBS_30:
case ITEM_ARROWS_SMALL:
case ITEM_ARROWS_MEDIUM:
case ITEM_ARROWS_LARGE:
case ITEM_SEEDS_30:
case ITEM_NONE:
break;
case ITEM_BOMBCHU:
case ITEM_BOMBCHUS_5:
case ITEM_BOMBCHUS_20:
if (!CVarGetInteger(CVAR_ENHANCEMENT("EnableBombchuDrops"), 0)) {
performSave = true;
}
break;
default:
performSave = true;
break;
}
} else if (itemEntry.modIndex == 1 && item != RG_ICE_TRAP) {
performSave = true;
}
} else if (CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_MAJOR_ITEMS ||
CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS ||
CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_LOCATION) {
performSave = true;
}
if (performSave) {
Play_PerformSave(gPlayState);
performSave = false;
}
}
}

void RegisterAutoSave() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>([](GetItemEntry itemEntry) { AutoSave(itemEntry); });
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSaleEnd>([](GetItemEntry itemEntry) { AutoSave(itemEntry); });
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnTransitionEnd>([](int32_t sceneNum) { AutoSave(GET_ITEM_NONE); });
}

void RegisterRupeeDash() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerUpdate>([]() {
if (!CVarGetInteger(CVAR_ENHANCEMENT("RupeeDash"), 0)) {
Expand Down Expand Up @@ -1178,7 +1097,6 @@ void InitMods() {
TimeSavers_Register();
RegisterTTS();
RegisterOcarinaTimeTravel();
RegisterAutoSave();
RegisterDaytimeGoldSkultullas();
RegisterRupeeDash();
RegisterShadowTag();
Expand Down
5 changes: 2 additions & 3 deletions soh/soh/Enhancements/presets.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ const std::vector<const char*> enhancementsCvars = {
CVAR_ENHANCEMENT("GSCutscene"),
CVAR_ENHANCEMENT("RestoreRBAValues"),
CVAR_ENHANCEMENT("SkipSaveConfirmation"),
CVAR_ENHANCEMENT("Autosave"),
CVAR_ENHANCEMENT("DisableCritWiggle"),
CVAR_ENHANCEMENT("ChestSizeDependsStoneOfAgony"),
CVAR_ENHANCEMENT("SkipArrowAnimation"),
Expand Down Expand Up @@ -754,7 +753,7 @@ const std::vector<PresetEntry> enhancedPresetEntries = {
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AnubisFix"), 1),

// Autosave
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_LOCATION_AND_MAJOR_ITEMS),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("Autosave"), 1),

// Bombchu shop doesn't sell out, and 10 bombchus cost 99 instead of 100
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("BetterBombchuShopping"), 1),
Expand Down Expand Up @@ -887,7 +886,7 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AnubisFix"), 1),

// Autosave
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_LOCATION_AND_MAJOR_ITEMS),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("Autosave"), 1),

// Customize Fishing Behaviour
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("CustomizeFishing"), 1),
Expand Down
2 changes: 1 addition & 1 deletion soh/soh/Enhancements/randomizer/3drando/fill.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ void ValidateEntrances(bool checkPoeCollectorAccess, bool checkOtherEntranceAcce
auto message = "Location " +
Rando::StaticData::GetLocation(ctx->GetItemLocation(loc)->GetRandomizerCheck())->GetName() +
" not reachable\n";
SPDLOG_DEBUG(message);
LUSLOG_DEBUG("%s", message.c_str());
#ifndef ENABLE_DEBUG
break;
#endif
Expand Down
13 changes: 12 additions & 1 deletion soh/soh/Enhancements/randomizer/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,19 @@ void Context::GenerateLocationPool() {
location.GetRandomizerCheck() == RC_LW_DEKU_SCRUB_NEAR_BRIDGE ||
location.GetRandomizerCheck() == RC_HF_DEKU_SCRUB_GROTTO
)) ||
(location.GetRCType() == RCTYPE_ADULT_TRADE && mOptions[RSK_SHUFFLE_ADULT_TRADE].Is(RO_GENERIC_OFF)) ||
(location.GetRCType() == RCTYPE_COW && mOptions[RSK_SHUFFLE_COWS].Is(RO_GENERIC_OFF)) ||
(location.GetRCType() == RCTYPE_FISH && mOptions[RSK_FISHSANITY].Is(RO_FISHSANITY_OFF)) ||
(location.GetRandomizerCheck() == RC_LH_HYRULE_LOACH && mOptions[RSK_FISHSANITY].IsNot(RO_FISHSANITY_HYRULE_LOACH)) ||
(location.GetRCType() == RCTYPE_FISH && (
mOptions[RSK_FISHSANITY].Is(RO_FISHSANITY_OFF) || mOptions[RSK_FISHSANITY].Is(RO_FISHSANITY_HYRULE_LOACH) ||
(mOptions[RSK_FISHSANITY].Is(RO_FISHSANITY_OVERWORLD) && location.GetScene() == SCENE_FISHING_POND) ||
(mOptions[RSK_FISHSANITY].Is(RO_FISHSANITY_POND) && location.GetScene() != SCENE_FISHING_POND) ||
((mOptions[RSK_FISHSANITY].Is(RO_FISHSANITY_POND) || mOptions[RSK_FISHSANITY].Is(RO_FISHSANITY_BOTH)) &&
(mOptions[RSK_FISHSANITY_AGE_SPLIT].Is(RO_GENERIC_OFF) && (
location.GetRandomizerCheck() >= RC_LH_ADULT_FISH_1 && location.GetRandomizerCheck() <= RC_LH_ADULT_LOACH)
)
)
)) ||
(location.GetRCType() == RCTYPE_POT && mOptions[RSK_SHUFFLE_POTS].Is(RO_SHUFFLE_POTS_OFF)) ||
(location.GetRCType() == RCTYPE_FAIRY && !mOptions[RSK_SHUFFLE_FAIRIES]) ||
(location.GetRCType() == RCTYPE_FREESTANDING &&
Expand Down
3 changes: 0 additions & 3 deletions soh/soh/Enhancements/randomizer/hook_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1671,9 +1671,6 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
case VB_GIVE_ITEM_STRENGTH_1:
case VB_GIVE_ITEM_ZELDAS_LETTER:
case VB_GIVE_ITEM_OCARINA_OF_TIME:
case VB_GIVE_ITEM_KOKIRI_EMERALD:
case VB_GIVE_ITEM_GORON_RUBY:
case VB_GIVE_ITEM_ZORA_SAPPHIRE:
case VB_GIVE_ITEM_LIGHT_MEDALLION:
case VB_GIVE_ITEM_FOREST_MEDALLION:
case VB_GIVE_ITEM_FIRE_MEDALLION:
Expand Down
4 changes: 4 additions & 0 deletions soh/soh/Enhancements/randomizer/randomizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "soh/util.h"
#include "fishsanity.h"
#include "randomizerTypes.h"
#include "soh/Notification/Notification.h"

extern std::map<RandomizerCheckArea, std::string> rcAreaNames;

Expand Down Expand Up @@ -4147,6 +4148,9 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
gSaveContext.ship.stats.gameComplete = 1;
Flags_SetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY);
Play_PerformSave(play);
Notification::Emit({
.message = "Game autosaved",
});
GameInteractor_SetTriforceHuntCreditsWarpActive(true);
}

Expand Down
Loading

0 comments on commit 76f4908

Please sign in to comment.