mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-07-11 23:56:22 -07:00
Merge pull request #5517 from HarbourMasters/develop-blair
Develop blair
This commit is contained in:
commit
e1f6297807
16 changed files with 156 additions and 42 deletions
|
@ -15,7 +15,7 @@ extern "C"
|
||||||
#include <soh/Enhancements/randomizer/randomizer_inf.h>
|
#include <soh/Enhancements/randomizer/randomizer_inf.h>
|
||||||
|
|
||||||
#if defined(INCLUDE_GAME_PRINTF) && defined(_DEBUG)
|
#if defined(INCLUDE_GAME_PRINTF) && defined(_DEBUG)
|
||||||
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, __VA_ARGS__)
|
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, ##__VA_ARGS__)
|
#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, ##__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -519,6 +519,14 @@ typedef enum {
|
||||||
// - `*BgHeavyBlock`
|
// - `*BgHeavyBlock`
|
||||||
VB_FREEZE_LINK_FOR_BLOCK_THROW,
|
VB_FREEZE_LINK_FOR_BLOCK_THROW,
|
||||||
|
|
||||||
|
// #### `result`
|
||||||
|
// ```c
|
||||||
|
// true
|
||||||
|
// ```
|
||||||
|
// #### `args`
|
||||||
|
// - None
|
||||||
|
VB_FREEZE_LINK_FOR_FOREST_PILLARS,
|
||||||
|
|
||||||
// #### `result`
|
// #### `result`
|
||||||
// ```c
|
// ```c
|
||||||
// true
|
// true
|
||||||
|
|
|
@ -10,9 +10,10 @@
|
||||||
#include "soh/Enhancements/debugger/performanceTimer.h"
|
#include "soh/Enhancements/debugger/performanceTimer.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <soh/OTRGlobals.h>
|
||||||
|
|
||||||
|
#include "3drando/shops.hpp"
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern SaveContext gSaveContext;
|
|
||||||
extern PlayState* gPlayState;
|
extern PlayState* gPlayState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,17 +46,71 @@ bool LocationAccess::ConditionsMet(Region* parentRegion, bool calculatingAvailab
|
||||||
conditionsMet = true;
|
conditionsMet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return conditionsMet &&
|
return conditionsMet && CanBuy(calculatingAvailableChecks);
|
||||||
(calculatingAvailableChecks || CanBuy()); // TODO: run CanBuy when price is known due to settings
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LocationAccess::CanBuy() const {
|
static uint16_t GetMinimumPrice(const Rando::Location* loc) {
|
||||||
return CanBuyAnother(location);
|
extern PriceSettingsStruct shopsanityPrices;
|
||||||
|
extern PriceSettingsStruct scrubPrices;
|
||||||
|
extern PriceSettingsStruct merchantPrices;
|
||||||
|
PriceSettingsStruct priceSettings = loc->GetRCType() == RCTYPE_SHOP ? shopsanityPrices
|
||||||
|
: loc->GetRCType() == RCTYPE_SCRUB ? scrubPrices
|
||||||
|
: merchantPrices;
|
||||||
|
|
||||||
|
auto ctx = Rando::Context::GetInstance();
|
||||||
|
switch (ctx->GetOption(priceSettings.main).Get()) {
|
||||||
|
case RO_PRICE_VANILLA:
|
||||||
|
return loc->GetVanillaPrice();
|
||||||
|
case RO_PRICE_CHEAP_BALANCED:
|
||||||
|
return 0;
|
||||||
|
case RO_PRICE_BALANCED:
|
||||||
|
return 0;
|
||||||
|
case RO_PRICE_FIXED:
|
||||||
|
return ctx->GetOption(priceSettings.fixedPrice).Get() * 5;
|
||||||
|
case RO_PRICE_RANGE: {
|
||||||
|
uint16_t range1 = ctx->GetOption(priceSettings.range1).Get() * 5;
|
||||||
|
uint16_t range2 = ctx->GetOption(priceSettings.range1).Get() * 5;
|
||||||
|
return range1 < range2 ? range1 : range2;
|
||||||
|
}
|
||||||
|
case RO_PRICE_SET_BY_WALLET: {
|
||||||
|
if (ctx->GetOption(priceSettings.noWallet).Get()) {
|
||||||
|
return 0;
|
||||||
|
} else if (ctx->GetOption(priceSettings.childWallet).Get()) {
|
||||||
|
return 1;
|
||||||
|
} else if (ctx->GetOption(priceSettings.adultWallet).Get()) {
|
||||||
|
return 100;
|
||||||
|
} else if (ctx->GetOption(priceSettings.giantWallet).Get()) {
|
||||||
|
return 201;
|
||||||
|
} else {
|
||||||
|
return 501;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocationAccess::CanBuy(bool calculatingAvailableChecks) const {
|
||||||
|
const auto& loc = Rando::StaticData::GetLocation(location);
|
||||||
|
const auto& itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(location);
|
||||||
|
|
||||||
|
if (loc->GetRCType() == RCTYPE_SHOP || loc->GetRCType() == RCTYPE_SCRUB || loc->GetRCType() == RCTYPE_MERCHANT) {
|
||||||
|
// Checks should only be identified while playing
|
||||||
|
if (calculatingAvailableChecks && itemLoc->GetCheckStatus() != RCSHOW_IDENTIFIED) {
|
||||||
|
return CanBuyAnother(GetMinimumPrice(loc));
|
||||||
|
} else {
|
||||||
|
return CanBuyAnother(itemLoc->GetPrice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanBuyAnother(RandomizerCheck rc) {
|
bool CanBuyAnother(RandomizerCheck rc) {
|
||||||
uint16_t price = ctx->GetItemLocation(rc)->GetPrice();
|
return CanBuyAnother(ctx->GetItemLocation(rc)->GetPrice());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanBuyAnother(uint16_t price) {
|
||||||
if (price > 500) {
|
if (price > 500) {
|
||||||
return logic->HasItem(RG_TYCOON_WALLET);
|
return logic->HasItem(RG_TYCOON_WALLET);
|
||||||
} else if (price > 200) {
|
} else if (price > 200) {
|
||||||
|
@ -275,7 +330,7 @@ bool BeanPlanted(const RandomizerRegion region) {
|
||||||
if (gPlayState != nullptr && gPlayState->sceneNum == sceneID) {
|
if (gPlayState != nullptr && gPlayState->sceneNum == sceneID) {
|
||||||
swch = gPlayState->actorCtx.flags.swch;
|
swch = gPlayState->actorCtx.flags.swch;
|
||||||
} else if (sceneID != SCENE_ID_MAX) {
|
} else if (sceneID != SCENE_ID_MAX) {
|
||||||
swch = gSaveContext.sceneFlags[sceneID].swch;
|
swch = Rando::Context::GetInstance()->GetLogic()->GetSaveContext()->sceneFlags[sceneID].swch;
|
||||||
} else {
|
} else {
|
||||||
swch = 0;
|
swch = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,9 +100,10 @@ class LocationAccess {
|
||||||
std::string condition_str;
|
std::string condition_str;
|
||||||
|
|
||||||
// Makes sure shop locations are buyable
|
// Makes sure shop locations are buyable
|
||||||
bool CanBuy() const;
|
bool CanBuy(bool calculatingAvailableChecks) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool CanBuyAnother(uint16_t price);
|
||||||
bool CanBuyAnother(RandomizerCheck rc);
|
bool CanBuyAnother(RandomizerCheck rc);
|
||||||
|
|
||||||
namespace Rando {
|
namespace Rando {
|
||||||
|
|
|
@ -25,7 +25,6 @@ void RegionTable_Init_BottomOfTheWell() {
|
||||||
}, {
|
}, {
|
||||||
//Locations
|
//Locations
|
||||||
LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, logic->HasExplosives()),
|
LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, logic->HasExplosives()),
|
||||||
LOCATION(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, (logic->HasItem(RG_BRONZE_SCALE) || logic->LoweredWaterInsideBotw) && logic->CanUse(RG_STICKS) || logic->CanUse(RG_DINS_FIRE)),
|
|
||||||
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, logic->LoweredWaterInsideBotw),
|
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, logic->LoweredWaterInsideBotw),
|
||||||
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, logic->LoweredWaterInsideBotw),
|
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, logic->LoweredWaterInsideBotw),
|
||||||
LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_1, logic->CanBreakPots()),
|
LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_1, logic->CanBreakPots()),
|
||||||
|
|
|
@ -20,7 +20,7 @@ void RegionTable_Init_FireTemple() {
|
||||||
//Exits
|
//Exits
|
||||||
Entrance(RR_FIRE_TEMPLE_ENTRYWAY, []{return true;}),
|
Entrance(RR_FIRE_TEMPLE_ENTRYWAY, []{return true;}),
|
||||||
Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return logic->FireTimer() >= 24;}),
|
Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return logic->FireTimer() >= 24;}),
|
||||||
Entrance(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return Here(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}) && (logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsKeysanity);}),
|
Entrance(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return Here(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}) && (logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsFireLoopLocked);}),
|
||||||
Entrance(RR_FIRE_TEMPLE_LOOP_EXIT, []{return true;}),
|
Entrance(RR_FIRE_TEMPLE_LOOP_EXIT, []{return true;}),
|
||||||
Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 2) && logic->FireTimer() >= 24;}),
|
Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 2) && logic->FireTimer() >= 24;}),
|
||||||
});
|
});
|
||||||
|
@ -43,7 +43,7 @@ void RegionTable_Init_FireTemple() {
|
||||||
|
|
||||||
areaTable[RR_FIRE_TEMPLE_LOOP_ENEMIES] = Region("Fire Temple Loop Enemies", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, {
|
areaTable[RR_FIRE_TEMPLE_LOOP_ENEMIES] = Region("Fire Temple Loop Enemies", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, {
|
||||||
//Exits
|
//Exits
|
||||||
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsKeysanity;}),
|
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsFireLoopLocked;}),
|
||||||
Entrance(RR_FIRE_TEMPLE_LOOP_TILES, []{return Here(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return logic->CanKillEnemy(RE_TORCH_SLUG) && logic->CanKillEnemy(RE_FIRE_KEESE);});}),
|
Entrance(RR_FIRE_TEMPLE_LOOP_TILES, []{return Here(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return logic->CanKillEnemy(RE_TORCH_SLUG) && logic->CanKillEnemy(RE_FIRE_KEESE);});}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1387,6 +1387,7 @@ bool Logic::SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless
|
||||||
static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >=
|
static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >=
|
||||||
static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE))) { return FireTempleKeys >= requiredAmountGlitched;
|
static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE))) { return FireTempleKeys >= requiredAmountGlitched;
|
||||||
}*/
|
}*/
|
||||||
|
// If the Fire Temple loop lock is removed, Small key Count is set to 1 before starting
|
||||||
return GetSmallKeyCount(SCENE_FIRE_TEMPLE) >= requiredAmountGlitchless;
|
return GetSmallKeyCount(SCENE_FIRE_TEMPLE) >= requiredAmountGlitchless;
|
||||||
|
|
||||||
case RR_WATER_TEMPLE:
|
case RR_WATER_TEMPLE:
|
||||||
|
@ -2334,9 +2335,9 @@ void Logic::Reset() {
|
||||||
StartPerformanceTimer(PT_LOGIC_RESET);
|
StartPerformanceTimer(PT_LOGIC_RESET);
|
||||||
memset(inLogic, false, sizeof(inLogic));
|
memset(inLogic, false, sizeof(inLogic));
|
||||||
// Settings-dependent variables
|
// Settings-dependent variables
|
||||||
IsKeysanity = ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
|
IsFireLoopLocked = ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
|
||||||
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
|
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD) ||
|
||||||
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE);
|
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON);
|
||||||
|
|
||||||
// AmmoCanDrop = /*AmmoDrops.IsNot(AMMODROPS_NONE)*/ false; TODO: AmmoDrop setting
|
// AmmoCanDrop = /*AmmoDrops.IsNot(AMMODROPS_NONE)*/ false; TODO: AmmoDrop setting
|
||||||
|
|
||||||
|
@ -2398,7 +2399,7 @@ void Logic::Reset() {
|
||||||
|
|
||||||
// If not keysanity, start with 1 logical key to account for automatically unlocking the basement door in vanilla
|
// If not keysanity, start with 1 logical key to account for automatically unlocking the basement door in vanilla
|
||||||
// FiT
|
// FiT
|
||||||
if (!IsKeysanity && ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsVanilla()) {
|
if (!IsFireLoopLocked && ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsVanilla()) {
|
||||||
SetSmallKeyCount(SCENE_FIRE_TEMPLE, 1);
|
SetSmallKeyCount(SCENE_FIRE_TEMPLE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ class Logic {
|
||||||
bool LightTrialClear = false;
|
bool LightTrialClear = false;
|
||||||
|
|
||||||
// Logical keysanity
|
// Logical keysanity
|
||||||
bool IsKeysanity = false;
|
bool IsFireLoopLocked = false;
|
||||||
|
|
||||||
// Bottle Count
|
// Bottle Count
|
||||||
uint8_t Bottles = 0;
|
uint8_t Bottles = 0;
|
||||||
|
|
|
@ -3738,13 +3738,15 @@ void RandomizerSettingsWindow::DrawElement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
UIWidgets::Spacer(0);
|
UIWidgets::Spacer(0);
|
||||||
ImGui::BeginDisabled((gSaveContext.gameMode != GAMEMODE_FILE_SELECT) || GameInteractor::IsSaveLoaded());
|
UIWidgets::ButtonOptions options = UIWidgets::ButtonOptions().Size(ImVec2(250.f, 0.f)).Color(THEME_COLOR);
|
||||||
if (UIWidgets::Button("Generate Randomizer",
|
options.Disabled((gSaveContext.gameMode != GAMEMODE_FILE_SELECT) || GameInteractor::IsSaveLoaded());
|
||||||
UIWidgets::ButtonOptions().Size(ImVec2(250.f, 0.f)).Color(THEME_COLOR))) {
|
if (options.disabled) {
|
||||||
|
options.DisabledTooltip("Must be on File Select to generate a randomizer seed.");
|
||||||
|
}
|
||||||
|
if (UIWidgets::Button("Generate Randomizer", options)) {
|
||||||
ctx->SetSpoilerLoaded(false);
|
ctx->SetSpoilerLoaded(false);
|
||||||
GenerateRandomizer(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), 0) ? seedString : "");
|
GenerateRandomizer(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), 0) ? seedString : "");
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (!CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0)) {
|
if (!CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0)) {
|
||||||
|
|
|
@ -1967,7 +1967,7 @@ void RecalculateAvailableChecks() {
|
||||||
StartPerformanceTimer(PT_RECALCULATE_AVAILABLE_CHECKS);
|
StartPerformanceTimer(PT_RECALCULATE_AVAILABLE_CHECKS);
|
||||||
|
|
||||||
std::vector<RandomizerCheck> targetLocations;
|
std::vector<RandomizerCheck> targetLocations;
|
||||||
targetLocations.reserve(RR_MAX);
|
targetLocations.reserve(RC_MAX);
|
||||||
for (auto& location : Rando::StaticData::GetLocationTable()) {
|
for (auto& location : Rando::StaticData::GetLocationTable()) {
|
||||||
RandomizerCheck rc = location.GetRandomizerCheck();
|
RandomizerCheck rc = location.GetRandomizerCheck();
|
||||||
Rando::ItemLocation* itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
Rando::ItemLocation* itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||||
|
@ -1979,16 +1979,9 @@ void RecalculateAvailableChecks() {
|
||||||
|
|
||||||
std::vector<RandomizerCheck> availableChecks = ReachabilitySearch(targetLocations, RG_NONE, true);
|
std::vector<RandomizerCheck> availableChecks = ReachabilitySearch(targetLocations, RG_NONE, true);
|
||||||
for (auto& rc : availableChecks) {
|
for (auto& rc : availableChecks) {
|
||||||
const auto& location = Rando::StaticData::GetLocation(rc);
|
|
||||||
const auto& itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
const auto& itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||||
if (location->GetRCType() == RCTYPE_SHOP && itemLocation->GetCheckStatus() == RCSHOW_IDENTIFIED) {
|
|
||||||
if (CanBuyAnother(rc)) {
|
|
||||||
itemLocation->SetAvailable(true);
|
itemLocation->SetAvailable(true);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
itemLocation->SetAvailable(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalChecksAvailable = 0;
|
totalChecksAvailable = 0;
|
||||||
for (auto& [rcArea, vec] : checksByArea) {
|
for (auto& [rcArea, vec] : checksByArea) {
|
||||||
|
@ -2114,8 +2107,11 @@ void CheckTrackerSettingsWindow::DrawElement() {
|
||||||
"with your current progress.")
|
"with your current progress.")
|
||||||
.Color(THEME_COLOR))) {
|
.Color(THEME_COLOR))) {
|
||||||
enableAvailableChecks = CVarGetInteger(CVAR_TRACKER_CHECK("EnableAvailableChecks"), 0);
|
enableAvailableChecks = CVarGetInteger(CVAR_TRACKER_CHECK("EnableAvailableChecks"), 0);
|
||||||
|
|
||||||
|
if (GameInteractor::IsSaveLoaded(true)) {
|
||||||
RecalculateAvailableChecks();
|
RecalculateAvailableChecks();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
// Filtering settings
|
// Filtering settings
|
||||||
|
|
|
@ -269,9 +269,9 @@ extern "C" void Randomizer_InitSaveFile() {
|
||||||
|
|
||||||
// Remove One Time Scrubs with Scrubsanity off
|
// Remove One Time Scrubs with Scrubsanity off
|
||||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_OFF) {
|
if (Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_OFF) {
|
||||||
Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE);
|
Flags_SetItemGetInf(ITEMGETINF_DEKU_SCRUB_HEART_PIECE);
|
||||||
Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT);
|
Flags_SetInfTable(INFTABLE_BOUGHT_STICK_UPGRADE);
|
||||||
Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO);
|
Flags_SetInfTable(INFTABLE_BOUGHT_NUT_UPGRADE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int startingAge = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SELECTED_STARTING_AGE).Get();
|
int startingAge = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SELECTED_STARTING_AGE).Get();
|
||||||
|
|
|
@ -375,6 +375,11 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VB_FREEZE_LINK_FOR_FOREST_PILLARS:
|
||||||
|
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO)) {
|
||||||
|
*should = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case VB_SHOW_TITLE_CARD:
|
case VB_SHOW_TITLE_CARD:
|
||||||
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.DisableTitleCard"), IS_RANDO)) {
|
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.DisableTitleCard"), IS_RANDO)) {
|
||||||
*should = false;
|
*should = false;
|
||||||
|
|
|
@ -2447,15 +2447,15 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
|
||||||
// animation until the text box auto-dismisses.
|
// animation until the text box auto-dismisses.
|
||||||
// RANDOTODO: Implement a way to determine if an item came from a skulltula and
|
// RANDOTODO: Implement a way to determine if an item came from a skulltula and
|
||||||
// inject the auto-dismiss control code if it did.
|
// inject the auto-dismiss control code if it did.
|
||||||
if (CVarGetInteger(CVAR_ENHANCEMENT("SkulltulaFreeze"), 0) != 0 &&
|
bool gsTokensShuffled = Randomizer_GetSettingValue(RSK_SHUFFLE_TOKENS) != RO_TOKENSANITY_OFF;
|
||||||
!(IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_TOKENS) != RO_TOKENSANITY_OFF)) {
|
if (CVarGetInteger(CVAR_ENHANCEMENT("SkulltulaFreeze"), 0) != 0 && !(IS_RANDO && gsTokensShuffled)) {
|
||||||
textId = TEXT_GS_NO_FREEZE;
|
textId = TEXT_GS_NO_FREEZE;
|
||||||
} else {
|
} else {
|
||||||
textId = TEXT_GS_FREEZE;
|
textId = TEXT_GS_FREEZE;
|
||||||
}
|
}
|
||||||
// In vanilla, GS token count is incremented prior to the text box displaying
|
// In vanilla, GS token count is incremented prior to the text box displaying
|
||||||
// In rando we need to bump the token count by one to show the correct count
|
// In rando we need to bump the token count by one to show the correct count
|
||||||
s16 gsCount = gSaveContext.inventory.gsTokens + (IS_RANDO ? 1 : 0);
|
s16 gsCount = gSaveContext.inventory.gsTokens + ((IS_RANDO && gsTokensShuffled) ? 1 : 0);
|
||||||
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_FORMATTED);
|
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_FORMATTED);
|
||||||
messageEntry.Replace("[[gsCount]]", std::to_string(gsCount));
|
messageEntry.Replace("[[gsCount]]", std::to_string(gsCount));
|
||||||
} else if (CVarGetInteger(CVAR_ENHANCEMENT("SkulltulaFreeze"), 0) != 0 &&
|
} else if (CVarGetInteger(CVAR_ENHANCEMENT("SkulltulaFreeze"), 0) != 0 &&
|
||||||
|
|
|
@ -145,7 +145,47 @@ void Audio_osWritebackDCache(void* mem, s32 size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 osAiSetFrequency(u32 freq) {
|
s32 osAiSetFrequency(u32 freq) {
|
||||||
return 1;
|
// this is based off the math from the original method
|
||||||
|
/*
|
||||||
|
|
||||||
|
s32 osAiSetFrequency(u32 frequency) {
|
||||||
|
u8 bitrate;
|
||||||
|
f32 dacRateF = ((f32)osViClock / frequency) + 0.5f;
|
||||||
|
u32 dacRate = dacRateF;
|
||||||
|
|
||||||
|
if (dacRate < 132) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitrate = (dacRate / 66);
|
||||||
|
if (bitrate > 16) {
|
||||||
|
bitrate = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
HW_REG(AI_DACRATE_REG, u32) = dacRate - 1;
|
||||||
|
HW_REG(AI_BITRATE_REG, u32) = bitrate - 1;
|
||||||
|
return osViClock / (s32)dacRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// bitrate is unused
|
||||||
|
|
||||||
|
// osViClock comes from
|
||||||
|
// #define VI_NTSC_CLOCK 48681812 /* Hz = 48.681812 MHz */
|
||||||
|
// s32 osViClock = VI_NTSC_CLOCK;
|
||||||
|
|
||||||
|
// frequency was originally 32000
|
||||||
|
|
||||||
|
// given all of that, dacRate is
|
||||||
|
// (u32)(((f32)48681812 / 32000) + 0.5f)
|
||||||
|
// which evaluates to 1521 (which is > 132)
|
||||||
|
|
||||||
|
// this leaves us with a final calculation of
|
||||||
|
// 48681812 / 1521
|
||||||
|
// which evaluates to 32006
|
||||||
|
|
||||||
|
return 32006;
|
||||||
}
|
}
|
||||||
|
|
||||||
void osInvalDCache(void* vaddr, s32 nbytes) {
|
void osInvalDCache(void* vaddr, s32 nbytes) {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "z_bg_mori_kaitenkabe.h"
|
#include "z_bg_mori_kaitenkabe.h"
|
||||||
#include "objects/object_mori_objects/object_mori_objects.h"
|
#include "objects/object_mori_objects/object_mori_objects.h"
|
||||||
|
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||||
|
|
||||||
#define FLAGS 0
|
#define FLAGS 0
|
||||||
|
|
||||||
|
@ -97,7 +98,9 @@ void BgMoriKaitenkabe_Wait(BgMoriKaitenkabe* this, PlayState* play) {
|
||||||
if ((this->timer > (28 - CVarGetInteger(CVAR_ENHANCEMENT("FasterBlockPush"), 0) * 4)) &&
|
if ((this->timer > (28 - CVarGetInteger(CVAR_ENHANCEMENT("FasterBlockPush"), 0) * 4)) &&
|
||||||
!Player_InCsMode(play)) {
|
!Player_InCsMode(play)) {
|
||||||
BgMoriKaitenkabe_SetupRotate(this);
|
BgMoriKaitenkabe_SetupRotate(this);
|
||||||
|
if (GameInteractor_Should(VB_FREEZE_LINK_FOR_FOREST_PILLARS, true)) {
|
||||||
Player_SetCsActionWithHaltedActors(play, &this->dyna.actor, 8);
|
Player_SetCsActionWithHaltedActors(play, &this->dyna.actor, 8);
|
||||||
|
}
|
||||||
Math_Vec3f_Copy(&this->lockedPlayerPos, &player->actor.world.pos);
|
Math_Vec3f_Copy(&this->lockedPlayerPos, &player->actor.world.pos);
|
||||||
push.x = Math_SinS(this->dyna.unk_158);
|
push.x = Math_SinS(this->dyna.unk_158);
|
||||||
push.y = 0.0f;
|
push.y = 0.0f;
|
||||||
|
@ -131,7 +134,9 @@ void BgMoriKaitenkabe_Rotate(BgMoriKaitenkabe* this, PlayState* play) {
|
||||||
Math_StepToF(&this->rotSpeed, 0.6f, 0.02f);
|
Math_StepToF(&this->rotSpeed, 0.6f, 0.02f);
|
||||||
if (Math_StepToF(&this->rotYdeg, this->rotDirection * 45.0f, this->rotSpeed)) {
|
if (Math_StepToF(&this->rotYdeg, this->rotDirection * 45.0f, this->rotSpeed)) {
|
||||||
BgMoriKaitenkabe_SetupWait(this);
|
BgMoriKaitenkabe_SetupWait(this);
|
||||||
|
if (GameInteractor_Should(VB_FREEZE_LINK_FOR_FOREST_PILLARS, true)) {
|
||||||
Player_SetCsActionWithHaltedActors(play, thisx, 7);
|
Player_SetCsActionWithHaltedActors(play, thisx, 7);
|
||||||
|
}
|
||||||
if (this->rotDirection > 0.0f) {
|
if (this->rotDirection > 0.0f) {
|
||||||
thisx->home.rot.y += 0x2000;
|
thisx->home.rot.y += 0x2000;
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,8 +153,10 @@ void BgMoriKaitenkabe_Rotate(BgMoriKaitenkabe* this, PlayState* play) {
|
||||||
this->dyna.unk_150 = 0.0f;
|
this->dyna.unk_150 = 0.0f;
|
||||||
player->stateFlags2 &= ~PLAYER_STATE2_MOVING_DYNAPOLY;
|
player->stateFlags2 &= ~PLAYER_STATE2_MOVING_DYNAPOLY;
|
||||||
}
|
}
|
||||||
|
if (GameInteractor_Should(VB_FREEZE_LINK_FOR_FOREST_PILLARS, true)) {
|
||||||
Math_Vec3f_Copy(&player->actor.world.pos, &this->lockedPlayerPos);
|
Math_Vec3f_Copy(&player->actor.world.pos, &this->lockedPlayerPos);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BgMoriKaitenkabe_Update(Actor* thisx, PlayState* play) {
|
void BgMoriKaitenkabe_Update(Actor* thisx, PlayState* play) {
|
||||||
s32 pad;
|
s32 pad;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue