mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-07-11 15:46:19 -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>
|
||||
|
||||
#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
|
||||
#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
|
|
@ -519,6 +519,14 @@ typedef enum {
|
|||
// - `*BgHeavyBlock`
|
||||
VB_FREEZE_LINK_FOR_BLOCK_THROW,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
// ```
|
||||
// #### `args`
|
||||
// - None
|
||||
VB_FREEZE_LINK_FOR_FOREST_PILLARS,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
#include "soh/Enhancements/debugger/performanceTimer.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <soh/OTRGlobals.h>
|
||||
|
||||
#include "3drando/shops.hpp"
|
||||
extern "C" {
|
||||
extern SaveContext gSaveContext;
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
|
@ -45,17 +46,71 @@ bool LocationAccess::ConditionsMet(Region* parentRegion, bool calculatingAvailab
|
|||
conditionsMet = true;
|
||||
}
|
||||
|
||||
return conditionsMet &&
|
||||
(calculatingAvailableChecks || CanBuy()); // TODO: run CanBuy when price is known due to settings
|
||||
return conditionsMet && CanBuy(calculatingAvailableChecks);
|
||||
}
|
||||
|
||||
bool LocationAccess::CanBuy() const {
|
||||
return CanBuyAnother(location);
|
||||
static uint16_t GetMinimumPrice(const Rando::Location* loc) {
|
||||
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) {
|
||||
uint16_t price = ctx->GetItemLocation(rc)->GetPrice();
|
||||
return CanBuyAnother(ctx->GetItemLocation(rc)->GetPrice());
|
||||
}
|
||||
|
||||
bool CanBuyAnother(uint16_t price) {
|
||||
if (price > 500) {
|
||||
return logic->HasItem(RG_TYCOON_WALLET);
|
||||
} else if (price > 200) {
|
||||
|
@ -275,7 +330,7 @@ bool BeanPlanted(const RandomizerRegion region) {
|
|||
if (gPlayState != nullptr && gPlayState->sceneNum == sceneID) {
|
||||
swch = gPlayState->actorCtx.flags.swch;
|
||||
} else if (sceneID != SCENE_ID_MAX) {
|
||||
swch = gSaveContext.sceneFlags[sceneID].swch;
|
||||
swch = Rando::Context::GetInstance()->GetLogic()->GetSaveContext()->sceneFlags[sceneID].swch;
|
||||
} else {
|
||||
swch = 0;
|
||||
}
|
||||
|
|
|
@ -100,9 +100,10 @@ class LocationAccess {
|
|||
std::string condition_str;
|
||||
|
||||
// Makes sure shop locations are buyable
|
||||
bool CanBuy() const;
|
||||
bool CanBuy(bool calculatingAvailableChecks) const;
|
||||
};
|
||||
|
||||
bool CanBuyAnother(uint16_t price);
|
||||
bool CanBuyAnother(RandomizerCheck rc);
|
||||
|
||||
namespace Rando {
|
||||
|
|
|
@ -25,7 +25,6 @@ void RegionTable_Init_BottomOfTheWell() {
|
|||
}, {
|
||||
//Locations
|
||||
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_LEFT_CHEST, logic->LoweredWaterInsideBotw),
|
||||
LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_1, logic->CanBreakPots()),
|
||||
|
|
|
@ -20,7 +20,7 @@ void RegionTable_Init_FireTemple() {
|
|||
//Exits
|
||||
Entrance(RR_FIRE_TEMPLE_ENTRYWAY, []{return true;}),
|
||||
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_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, {}, {}, {
|
||||
//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);});}),
|
||||
});
|
||||
|
||||
|
|
|
@ -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))) { 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;
|
||||
|
||||
case RR_WATER_TEMPLE:
|
||||
|
@ -2334,9 +2335,9 @@ void Logic::Reset() {
|
|||
StartPerformanceTimer(PT_LOGIC_RESET);
|
||||
memset(inLogic, false, sizeof(inLogic));
|
||||
// Settings-dependent variables
|
||||
IsKeysanity = 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_ANYWHERE);
|
||||
IsFireLoopLocked = 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_ANY_DUNGEON);
|
||||
|
||||
// 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
|
||||
// FiT
|
||||
if (!IsKeysanity && ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsVanilla()) {
|
||||
if (!IsFireLoopLocked && ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsVanilla()) {
|
||||
SetSmallKeyCount(SCENE_FIRE_TEMPLE, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ class Logic {
|
|||
bool LightTrialClear = false;
|
||||
|
||||
// Logical keysanity
|
||||
bool IsKeysanity = false;
|
||||
bool IsFireLoopLocked = false;
|
||||
|
||||
// Bottle Count
|
||||
uint8_t Bottles = 0;
|
||||
|
|
|
@ -3738,13 +3738,15 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||
}
|
||||
|
||||
UIWidgets::Spacer(0);
|
||||
ImGui::BeginDisabled((gSaveContext.gameMode != GAMEMODE_FILE_SELECT) || GameInteractor::IsSaveLoaded());
|
||||
if (UIWidgets::Button("Generate Randomizer",
|
||||
UIWidgets::ButtonOptions().Size(ImVec2(250.f, 0.f)).Color(THEME_COLOR))) {
|
||||
UIWidgets::ButtonOptions options = UIWidgets::ButtonOptions().Size(ImVec2(250.f, 0.f)).Color(THEME_COLOR);
|
||||
options.Disabled((gSaveContext.gameMode != GAMEMODE_FILE_SELECT) || GameInteractor::IsSaveLoaded());
|
||||
if (options.disabled) {
|
||||
options.DisabledTooltip("Must be on File Select to generate a randomizer seed.");
|
||||
}
|
||||
if (UIWidgets::Button("Generate Randomizer", options)) {
|
||||
ctx->SetSpoilerLoaded(false);
|
||||
GenerateRandomizer(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), 0) ? seedString : "");
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
if (!CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0)) {
|
||||
|
|
|
@ -1967,7 +1967,7 @@ void RecalculateAvailableChecks() {
|
|||
StartPerformanceTimer(PT_RECALCULATE_AVAILABLE_CHECKS);
|
||||
|
||||
std::vector<RandomizerCheck> targetLocations;
|
||||
targetLocations.reserve(RR_MAX);
|
||||
targetLocations.reserve(RC_MAX);
|
||||
for (auto& location : Rando::StaticData::GetLocationTable()) {
|
||||
RandomizerCheck rc = location.GetRandomizerCheck();
|
||||
Rando::ItemLocation* itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||
|
@ -1979,15 +1979,8 @@ void RecalculateAvailableChecks() {
|
|||
|
||||
std::vector<RandomizerCheck> availableChecks = ReachabilitySearch(targetLocations, RG_NONE, true);
|
||||
for (auto& rc : availableChecks) {
|
||||
const auto& location = Rando::StaticData::GetLocation(rc);
|
||||
const auto& itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||
if (location->GetRCType() == RCTYPE_SHOP && itemLocation->GetCheckStatus() == RCSHOW_IDENTIFIED) {
|
||||
if (CanBuyAnother(rc)) {
|
||||
itemLocation->SetAvailable(true);
|
||||
}
|
||||
} else {
|
||||
itemLocation->SetAvailable(true);
|
||||
}
|
||||
itemLocation->SetAvailable(true);
|
||||
}
|
||||
|
||||
totalChecksAvailable = 0;
|
||||
|
@ -2114,7 +2107,10 @@ void CheckTrackerSettingsWindow::DrawElement() {
|
|||
"with your current progress.")
|
||||
.Color(THEME_COLOR))) {
|
||||
enableAvailableChecks = CVarGetInteger(CVAR_TRACKER_CHECK("EnableAvailableChecks"), 0);
|
||||
RecalculateAvailableChecks();
|
||||
|
||||
if (GameInteractor::IsSaveLoaded(true)) {
|
||||
RecalculateAvailableChecks();
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
|
|
|
@ -269,9 +269,9 @@ extern "C" void Randomizer_InitSaveFile() {
|
|||
|
||||
// Remove One Time Scrubs with Scrubsanity off
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_OFF) {
|
||||
Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE);
|
||||
Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT);
|
||||
Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO);
|
||||
Flags_SetItemGetInf(ITEMGETINF_DEKU_SCRUB_HEART_PIECE);
|
||||
Flags_SetInfTable(INFTABLE_BOUGHT_STICK_UPGRADE);
|
||||
Flags_SetInfTable(INFTABLE_BOUGHT_NUT_UPGRADE);
|
||||
}
|
||||
|
||||
int startingAge = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SELECTED_STARTING_AGE).Get();
|
||||
|
|
|
@ -375,6 +375,11 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
|
|||
}
|
||||
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:
|
||||
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.DisableTitleCard"), IS_RANDO)) {
|
||||
*should = false;
|
||||
|
|
|
@ -2447,15 +2447,15 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
|
|||
// animation until the text box auto-dismisses.
|
||||
// RANDOTODO: Implement a way to determine if an item came from a skulltula and
|
||||
// inject the auto-dismiss control code if it did.
|
||||
if (CVarGetInteger(CVAR_ENHANCEMENT("SkulltulaFreeze"), 0) != 0 &&
|
||||
!(IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_TOKENS) != RO_TOKENSANITY_OFF)) {
|
||||
bool gsTokensShuffled = Randomizer_GetSettingValue(RSK_SHUFFLE_TOKENS) != RO_TOKENSANITY_OFF;
|
||||
if (CVarGetInteger(CVAR_ENHANCEMENT("SkulltulaFreeze"), 0) != 0 && !(IS_RANDO && gsTokensShuffled)) {
|
||||
textId = TEXT_GS_NO_FREEZE;
|
||||
} else {
|
||||
textId = TEXT_GS_FREEZE;
|
||||
}
|
||||
// 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
|
||||
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.Replace("[[gsCount]]", std::to_string(gsCount));
|
||||
} else if (CVarGetInteger(CVAR_ENHANCEMENT("SkulltulaFreeze"), 0) != 0 &&
|
||||
|
|
|
@ -145,7 +145,47 @@ void Audio_osWritebackDCache(void* mem, s32 size) {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "z_bg_mori_kaitenkabe.h"
|
||||
#include "objects/object_mori_objects/object_mori_objects.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS 0
|
||||
|
||||
|
@ -97,7 +98,9 @@ void BgMoriKaitenkabe_Wait(BgMoriKaitenkabe* this, PlayState* play) {
|
|||
if ((this->timer > (28 - CVarGetInteger(CVAR_ENHANCEMENT("FasterBlockPush"), 0) * 4)) &&
|
||||
!Player_InCsMode(play)) {
|
||||
BgMoriKaitenkabe_SetupRotate(this);
|
||||
Player_SetCsActionWithHaltedActors(play, &this->dyna.actor, 8);
|
||||
if (GameInteractor_Should(VB_FREEZE_LINK_FOR_FOREST_PILLARS, true)) {
|
||||
Player_SetCsActionWithHaltedActors(play, &this->dyna.actor, 8);
|
||||
}
|
||||
Math_Vec3f_Copy(&this->lockedPlayerPos, &player->actor.world.pos);
|
||||
push.x = Math_SinS(this->dyna.unk_158);
|
||||
push.y = 0.0f;
|
||||
|
@ -131,7 +134,9 @@ void BgMoriKaitenkabe_Rotate(BgMoriKaitenkabe* this, PlayState* play) {
|
|||
Math_StepToF(&this->rotSpeed, 0.6f, 0.02f);
|
||||
if (Math_StepToF(&this->rotYdeg, this->rotDirection * 45.0f, this->rotSpeed)) {
|
||||
BgMoriKaitenkabe_SetupWait(this);
|
||||
Player_SetCsActionWithHaltedActors(play, thisx, 7);
|
||||
if (GameInteractor_Should(VB_FREEZE_LINK_FOR_FOREST_PILLARS, true)) {
|
||||
Player_SetCsActionWithHaltedActors(play, thisx, 7);
|
||||
}
|
||||
if (this->rotDirection > 0.0f) {
|
||||
thisx->home.rot.y += 0x2000;
|
||||
} else {
|
||||
|
@ -148,7 +153,9 @@ void BgMoriKaitenkabe_Rotate(BgMoriKaitenkabe* this, PlayState* play) {
|
|||
this->dyna.unk_150 = 0.0f;
|
||||
player->stateFlags2 &= ~PLAYER_STATE2_MOVING_DYNAPOLY;
|
||||
}
|
||||
Math_Vec3f_Copy(&player->actor.world.pos, &this->lockedPlayerPos);
|
||||
if (GameInteractor_Should(VB_FREEZE_LINK_FOR_FOREST_PILLARS, true)) {
|
||||
Math_Vec3f_Copy(&player->actor.world.pos, &this->lockedPlayerPos);
|
||||
}
|
||||
}
|
||||
|
||||
void BgMoriKaitenkabe_Update(Actor* thisx, PlayState* play) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue