Merge develop-blair into available-checks-entrance-shuffle.

This commit is contained in:
Anthony Stewart 2025-05-18 19:59:47 -05:00
commit 8f18e610ca
31 changed files with 318 additions and 132 deletions

View file

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.26.0 FATAL_ERROR)
set(CMAKE_SYSTEM_VERSION 10.0 CACHE STRING "" FORCE)
set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_C_STANDARD 17 CACHE STRING "The C standard to use")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")

View file

@ -4,6 +4,7 @@ set(CMAKE_SYSTEM_VERSION 10.0 CACHE STRING "" FORCE)
project(soh LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_C_STANDARD 17 CACHE STRING "The C standard to use")
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
enable_language(OBJCXX)

View file

@ -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

View file

@ -544,7 +544,7 @@ typedef enum {
LANGUAGE_MAX
} Language;
#define TODO_TRANSLATE "__Translate_This__"
#define TODO_TRANSLATE "TranslateThis"
// TODO get these properties from the textures themselves
#define FONT_CHAR_TEX_WIDTH 16

View file

@ -265,6 +265,9 @@ void Draw_SfxTab(const std::string& tabId, SeqType type, const std::string& tabN
}
}
auto playingFromMenu = CVarGetInteger(CVAR_AUDIO("Playing"), 0);
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
// Longest text in Audio Editor
ImVec2 columnSize = ImGui::CalcTextSize("Navi - Look/Hey/Watchout (Target Enemy)");
ImGui::BeginTable(tabId.c_str(), 3, ImGuiTableFlags_SizingFixedFit);
@ -291,10 +294,13 @@ void Draw_SfxTab(const std::string& tabId, SeqType type, const std::string& tabN
const std::string lockedButton = ICON_FA_LOCK + hiddenKey;
const std::string unlockedButton = ICON_FA_UNLOCK + hiddenKey;
const int currentValue = CVarGetInteger(cvarKey.c_str(), defaultValue);
const bool isCurrentlyPlaying = currentValue == playingFromMenu || seqData.sequenceId == currentBGM;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", seqData.label.c_str());
ImGui::TextColored(
UIWidgets::ColorValues.at(isCurrentlyPlaying ? UIWidgets::Colors::Yellow : UIWidgets::Colors::White), "%s",
seqData.label.c_str());
ImGui::TableNextColumn();
ImGui::PushItemWidth(-FLT_MIN);
const int initialValue = map.contains(currentValue) ? currentValue : defaultValue;

View file

@ -642,10 +642,14 @@ void SohInputEditorWindow::DrawStickSection(uint8_t port, uint8_t stick, int32_t
ImGui::SameLine();
ImGui::BeginGroup();
DrawStickDirectionLine(ICON_FA_ARROW_UP, port, stick, Ship::UP, color);
DrawStickDirectionLine(ICON_FA_ARROW_DOWN, port, stick, Ship::DOWN, color);
DrawStickDirectionLine(ICON_FA_ARROW_LEFT, port, stick, Ship::LEFT, color);
DrawStickDirectionLine(ICON_FA_ARROW_RIGHT, port, stick, Ship::RIGHT, color);
DrawStickDirectionLine(StringHelper::Sprintf("%s##%d", ICON_FA_ARROW_UP, stick).c_str(), port, stick, Ship::UP,
color);
DrawStickDirectionLine(StringHelper::Sprintf("%s##%d", ICON_FA_ARROW_DOWN, stick).c_str(), port, stick, Ship::DOWN,
color);
DrawStickDirectionLine(StringHelper::Sprintf("%s##%d", ICON_FA_ARROW_LEFT, stick).c_str(), port, stick, Ship::LEFT,
color);
DrawStickDirectionLine(StringHelper::Sprintf("%s##%d", ICON_FA_ARROW_RIGHT, stick).c_str(), port, stick,
Ship::RIGHT, color);
ImGui::EndGroup();
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode(StringHelper::Sprintf("Analog Stick Options##%d", id).c_str())) {
@ -1335,12 +1339,12 @@ void SohInputEditorWindow::DrawOcarinaControlPanel() {
ImGui::AlignTextToFramePadding();
ImGui::BulletText("Disable song detection");
DrawButtonLine(ICON_FA_BAN, 0, BTN_CUSTOM_OCARINA_DISABLE_SONGS);
DrawButtonLine(ICON_FA_BAN "##DisableSongDetection", 0, BTN_CUSTOM_OCARINA_DISABLE_SONGS);
ImGui::AlignTextToFramePadding();
ImGui::BulletText("Pitch");
DrawButtonLine(ICON_FA_ARROW_UP, 0, BTN_CUSTOM_OCARINA_PITCH_UP);
DrawButtonLine(ICON_FA_ARROW_DOWN, 0, BTN_CUSTOM_OCARINA_PITCH_DOWN);
DrawButtonLine(ICON_FA_ARROW_UP "##Pitch", 0, BTN_CUSTOM_OCARINA_PITCH_UP);
DrawButtonLine(ICON_FA_ARROW_DOWN "##Pitch", 0, BTN_CUSTOM_OCARINA_PITCH_DOWN);
if (!CVarGetInteger(CVAR_SETTING("CustomOcarina.Enabled"), 0)) {
ImGui::EndDisabled();

View file

@ -155,12 +155,12 @@ const std::string CustomMessage::GetFrench(MessageFormat format) const {
}
const std::string CustomMessage::GetForCurrentLanguage(MessageFormat format) const {
return GetForLanguage(((Language)gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : gSaveContext.language,
format);
return GetForLanguage(
((Language)gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : (Language)gSaveContext.language, format);
}
const std::string CustomMessage::GetForLanguage(uint8_t language, MessageFormat format) const {
std::string output = messages[language] != TODO_TRANSLATE ? messages[language] : messages[LANGUAGE_ENG];
std::string output = !messages[language].starts_with(TODO_TRANSLATE) ? messages[language] : messages[LANGUAGE_ENG];
ProcessMessageFormat(output, format);
return output;
}

View file

@ -474,6 +474,14 @@ typedef enum {
// - `*BgHeavyBlock`
VB_FREEZE_LINK_FOR_BLOCK_THROW,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_FREEZE_LINK_FOR_FOREST_PILLARS,
// #### `result`
// ```c
// true
@ -1358,6 +1366,14 @@ typedef enum {
// - `*BgTreemouth`
VB_PLAY_DEKU_TREE_INTRO_CS,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*DemoKekkai`
VB_PLAY_DISPEL_BARRIER_CS,
// #### `result`
// ```c
// true
@ -1422,6 +1438,15 @@ typedef enum {
// - None
VB_PLAY_FIRE_ARROW_CS,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*EnHeishi2`
// - `bool` (clearCamera - true if the code clears a sub-camera, false otherwise)
VB_PLAY_GATE_OPENING_OR_CLOSING_CS,
// #### `result`
// ```c
// true

View file

@ -648,6 +648,8 @@ void ValidateEntrances(bool checkPoeCollectorAccess, bool checkOtherEntranceAcce
if (ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES).Is(RO_INTERIOR_ENTRANCE_SHUFFLE_OFF)) {
Rando::StaticData::RetrieveItem(RG_GUARD_HOUSE_KEY).ApplyEffect();
}
RegionTable(RR_ROOT)->adultNight = true;
RegionTable(RR_ROOT)->adultDay = true;
} else {
ApplyAllAdvancmentItems();
}

View file

@ -68,4 +68,4 @@ void GeneratePlaythrough();
bool CheckBeatable(RandomizerGet ignore=RG_NONE);
void ValidateEntrances(bool checkPoeCollectorAccess, bool checkOtherEntranceAccess);
void ValidateEntrances(bool checkPoeCollectorAccess, bool checkOtherEntranceAccess);

View file

@ -2412,13 +2412,13 @@ void StaticData::HintTable_Init() {
hintTextTable[RHT_ISOLATED_PLACE] = HintText(CustomMessage("an Isolated Place"));
hintTextTable[RHT_DUNGEON_ORDINARY] = HintText(CustomMessage(" It's ordinary.",
/*german*/ "&Sieht aus wie immer.",
/*french*/ "&Elle vous semble %rordinaire%w."));
hintTextTable[RHT_DUNGEON_ORDINARY] = HintText(CustomMessage("&It's %gordinary%w.",
/*german*/ "&Sieht aus %gwie immer%w.",
/*french*/ "&Elle vous semble %gordinaire%w."));
hintTextTable[RHT_DUNGEON_MASTERFUL] = HintText(CustomMessage(" It's masterful!",
/*german*/ "&Man kann darauf die Worte&%r\"Master Quest\"%w entziffern...",
/*french*/ "&Étrange... les mots %r\"Master&Quest\"%w sont gravés dessus."));
hintTextTable[RHT_DUNGEON_MASTERFUL] = HintText(CustomMessage("&It's %rmasterful%w!",
/*german*/ "&Man kann darauf die Worte %r\"Master_Quest\"%w entziffern...",
/*french*/ "&Étrange... les mots %r\"Master_Quest\"%w sont gravés dessus."));
// clang-format on
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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()),

View file

@ -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);});}),
});

View file

@ -658,7 +658,7 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE] = Region("Water Temple MQ Dragon Room Alcove", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->MQWaterDragonTorches, []{return true;}),
EventAccess(&logic->MQWaterDragonTorches, []{return logic->HasFireSource();}),
},
{
//Locations

View file

@ -1389,6 +1389,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:
@ -2338,9 +2339,9 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
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
@ -2403,7 +2404,7 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
// 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);
}
}
@ -2504,6 +2505,7 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
ForestOpenBossCorridor = false;
ShadowTrialFirstChest = false;
MQGTGMazeSwitch = false;
MQGTGRightSideSwitch = false;
GTGPlatformSilverRupees = false;
MQJabuHolesRoomDoor = false;
JabuWestTentacle = false;

View file

@ -59,7 +59,7 @@ class Logic {
bool LightTrialClear = false;
// Logical keysanity
bool IsKeysanity = false;
bool IsFireLoopLocked = false;
// Bottle Count
uint8_t Bottles = 0;

View file

@ -65,7 +65,7 @@ const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi";
const std::string Randomizer::IceTrapRandoMessageTableID = "RandomizerIceTrap";
const std::string Randomizer::randoMiscHintsTableID = "RandomizerMiscHints";
static const char* englishRupeeNames[190] = {
static const char* englishRupeeNames[188] = {
"[P]",
"Bad RNG Rolls",
"Baht",
@ -111,8 +111,6 @@ static const char* englishRupeeNames[190] = {
"Dimes",
"Dinars",
"DNA",
"Doge",
"Dogecoin",
"Doll Hairs",
"Dollars",
"Dollarydoos",
@ -258,25 +256,25 @@ static const char* englishRupeeNames[190] = {
"Zorkmids",
};
static const char* germanRupeeNames[80] = {
"Baht", "Bananen", "Bitcoin", "Bonbons", "Bratwürste", "Brause UFOs", "Brötchen", "Cent",
"Diamanten", "Dinar", "Diridari", "Dogecoin", "Dollar", "Draken", "ECU", "Elexit",
"Erz", "Erzbrocken", "Euro", "EXP", "Forint", "Franken", "Freunde", "Gil",
"Gold", "Groschen", "Gulden", "Gummibären", "Heller", "Juwelen", "Karolin", "Kartoffeln",
"Kies", "Knete", "Knochen", "Kohle", "Kraniche", "Kreuzer", "Kronen", "Kronkorken",
"Kröten", "Lira", "Mark", "Mäuse", "Monde", "Moorhühner", "Moos", "Münzen",
"Naira", "Penunze", "Pesa", "Pfandflaschen", "Pfennig", "Pfund", "Pilze", "Plastiks",
"Pokédollar", "Radieschen", "Rand", "Rappen", "Real", "Rial", "Riyal", "Rubine",
"Rupien", "Saphire", "Schilling", "Seelen", "Septime", "Smaragde", "Steine", "Sterne",
"Sternis", "Tael", "Taler", "Wagenchips", "Won", "Yen", "Yuan", "Zenny",
static const char* germanRupeeNames[79] = {
"Baht", "Bananen", "Bitcoin", "Bonbons", "Bratwürste", "Brause UFOs", "Brötchen", "Cent",
"Diamanten", "Dinar", "Diridari", "Dollar", "Draken", "ECU", "Elexit", "Erz",
"Erzbrocken", "Euro", "EXP", "Forint", "Franken", "Freunde", "Gil", "Gold",
"Groschen", "Gulden", "Gummibären", "Heller", "Juwelen", "Karolin", "Kartoffeln", "Kies",
"Knete", "Knochen", "Kohle", "Kraniche", "Kreuzer", "Kronen", "Kronkorken", "Kröten",
"Lira", "Mark", "Mäuse", "Monde", "Moorhühner", "Moos", "Münzen", "Naira",
"Penunze", "Pesa", "Pfandflaschen", "Pfennig", "Pfund", "Pilze", "Plastiks", "Pokédollar",
"Radieschen", "Rand", "Rappen", "Real", "Rial", "Riyal", "Rubine", "Rupien",
"Saphire", "Schilling", "Seelen", "Septime", "Smaragde", "Steine", "Sterne", "Sternis",
"Tael", "Taler", "Wagenchips", "Won", "Yen", "Yuan", "Zenny",
};
static const char* frenchRupeeNames[40] = {
"Anneaux", "Baguettes", "Balles", "Bananes", "Bitcoin", "Blés", "Bling", "Capsules",
"Centimes", "Champignons", "Clochettes", "Crédits", "Croissants", "Diamants", "Dogecoin", "Dollars",
"Émeraudes", "Éthers", "Étoiles", "Euros", "Florens", "Francs", "Galds", "Gils",
"Grouses", "Halos", "Joyaux", "Lunes", "Mailles", "Munnies", "Orbes", "Orens",
"Pépètes", "Pièces", "Plastyks", "Pokédollars", "Pokémon", "Radis", "Rubis", "Zennies",
static const char* frenchRupeeNames[39] = {
"Anneaux", "Baguettes", "Balles", "Bananes", "Bitcoin", "Blés", "Bling", "Capsules",
"Centimes", "Champignons", "Clochettes", "Crédits", "Croissants", "Diamants", "Dollars", "Émeraudes",
"Éthers", "Étoiles", "Euros", "Florens", "Francs", "Galds", "Gils", "Grouses",
"Halos", "Joyaux", "Lunes", "Mailles", "Munnies", "Orbes", "Orens", "Pépètes",
"Pièces", "Plastyks", "Pokédollars", "Pokémon", "Radis", "Rubis", "Zennies",
};
Randomizer::Randomizer() {
@ -3726,13 +3724,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)) {
@ -4515,6 +4515,9 @@ CustomMessage Randomizer::GetMapGetItemMessageWithHint(GetItemEntry itemEntry) {
messageEntry.Replace("[[typeHint]]", Rando::StaticData::hintTextTable[RHT_DUNGEON_ORDINARY].GetHintMessage());
}
// BUG: the icon is not in the message yet so are not accounted for, so overflows are possible
messageEntry.AutoFormat();
return messageEntry;
}

View file

@ -1995,7 +1995,7 @@ void RecalculateAvailableChecks(RandomizerRegion startingRegion /* = RR_ROOT */)
const auto& ctx = Rando::Context::GetInstance();
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 = ctx->GetItemLocation(rc);
@ -2007,17 +2007,8 @@ void RecalculateAvailableChecks(RandomizerRegion startingRegion /* = RR_ROOT */)
std::vector<RandomizerCheck> availableChecks = ReachabilitySearch(targetLocations, RG_NONE, true, startingRegion);
for (auto& rc : availableChecks) {
const auto& location = Rando::StaticData::GetLocation(rc);
const auto& itemLocation = ctx->GetItemLocation(rc);
const auto& region = areaTable[itemLocation->GetParentRegionKey()];
if (location->GetRCType() == RCTYPE_SHOP && itemLocation->GetCheckStatus() == RCSHOW_IDENTIFIED) {
if (CanBuyAnother(rc)) {
itemLocation->SetAvailable(true);
}
} else {
itemLocation->SetAvailable(true);
}
itemLocation->SetAvailable(true);
}
totalChecksAvailable = 0;
@ -2144,7 +2135,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();

View file

@ -1532,8 +1532,9 @@ void ItemTrackerWindow::DrawElement() {
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Notes"), SECTION_DISPLAY_HIDDEN) ==
SECTION_DISPLAY_MAIN_WINDOW &&
CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) ==
TRACKER_DISPLAY_ALWAYS) {
(CVarGetInteger(CVAR_TRACKER_ITEM("WindowType"), TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_FLOATING &&
CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) ==
TRACKER_DISPLAY_ALWAYS)) {
DrawNotes();
}
EndFloatingWindows();
@ -1642,7 +1643,10 @@ void ItemTrackerWindow::DrawElement() {
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Notes"), SECTION_DISPLAY_HIDDEN) ==
SECTION_DISPLAY_SEPARATE &&
CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) {
(CVarGetInteger(CVAR_TRACKER_ITEM("WindowType"), TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_WINDOW ||
(CVarGetInteger(CVAR_TRACKER_ITEM("WindowType"), TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_FLOATING &&
CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) !=
TRACKER_DISPLAY_COMBO_BUTTON))) {
ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver);
BeginFloatingWindows("Personal Notes", ImGuiWindowFlags_NoFocusOnAppearing);
DrawNotes(true);
@ -1943,7 +1947,10 @@ void ItemTrackerSettingsWindow::DrawElement() {
shouldUpdateVectors = true;
}
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) {
if (CVarGetInteger(CVAR_TRACKER_ITEM("WindowType"), TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_WINDOW ||
(CVarGetInteger(CVAR_TRACKER_ITEM("WindowType"), TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_FLOATING &&
CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) !=
TRACKER_DISPLAY_COMBO_BUTTON)) {
if (CVarCombobox("Personal notes", CVAR_TRACKER_ITEM("DisplayType.Notes"), displayTypes,
ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_HIDDEN)

View file

@ -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();

View file

@ -250,7 +250,7 @@ void Settings::CreateOptions() {
OPT_U8(RSK_LACS_REWARD_COUNT, "GCBK Reward Count", {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardCount"), "", WidgetType::Slider, 9, true);
OPT_U8(RSK_LACS_DUNGEON_COUNT, "GCBK Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsDungeonCount"), "", WidgetType::Slider, 8, true);
OPT_U8(RSK_LACS_TOKEN_COUNT, "GCBK Token Count", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsTokenCount"), "", WidgetType::Slider, 100, true);
OPT_U8(RSK_LACS_OPTIONS, "GCBK LACS Reward Options", {"Standard Reward", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardOptions"), "", WidgetType::Combobox, RO_LACS_STANDARD_REWARD);
OPT_U8(RSK_LACS_OPTIONS, "GCBK LACS Reward Options", {"Standard Reward", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardOptions"), mOptionDescriptions[RSK_LACS_OPTIONS], WidgetType::Combobox, RO_LACS_STANDARD_REWARD);
OPT_U8(RSK_KEYRINGS, "Key Rings", {"Off", "Random", "Count", "Selection"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), mOptionDescriptions[RSK_KEYRINGS], WidgetType::Combobox, RO_KEYRINGS_OFF);
OPT_U8(RSK_KEYRINGS_RANDOM_COUNT, "Keyring Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsRandomCount"), "", WidgetType::Slider, 8);
OPT_U8(RSK_KEYRINGS_GERUDO_FORTRESS, "Gerudo Fortress Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", WidgetType::Combobox, 0);

View file

@ -13,12 +13,14 @@ extern "C" {
#include "src/overlays/actors/ovl_Bg_Treemouth/z_bg_treemouth.h"
#include "src/overlays/actors/ovl_En_Owl/z_en_owl.h"
#include "src/overlays/actors/ovl_En_Go2/z_en_go2.h"
#include "src/overlays/actors/ovl_En_Heishi2/z_en_heishi2.h"
#include "src/overlays/actors/ovl_En_Ko/z_en_ko.h"
#include "src/overlays/actors/ovl_En_Ma1/z_en_ma1.h"
#include "src/overlays/actors/ovl_En_Ru2/z_en_ru2.h"
#include "src/overlays/actors/ovl_En_Zl4/z_en_zl4.h"
#include "src/overlays/actors/ovl_En_Box/z_en_box.h"
#include "src/overlays/actors/ovl_Demo_Im/z_demo_im.h"
#include "src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.h"
#include "src/overlays/actors/ovl_En_Sa/z_en_sa.h"
#include "src/overlays/actors/ovl_Bg_Ddan_Kd/z_bg_ddan_kd.h"
#include "src/overlays/actors/ovl_En_Tk/z_en_tk.h"
@ -217,6 +219,25 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Entrances"), IS_RANDO) &&
(entranceFlag != EVENTCHKINF_EPONA_OBTAINED) && entranceIndex != ENTR_SPIRIT_TEMPLE_BOSS_ENTRANCE) {
*should = false;
// Check for dispulsion of Ganon's Tower barrier
switch (entranceIndex) {
case ENTR_INSIDE_GANONS_CASTLE_2:
case ENTR_INSIDE_GANONS_CASTLE_3:
case ENTR_INSIDE_GANONS_CASTLE_4:
case ENTR_INSIDE_GANONS_CASTLE_5:
case ENTR_INSIDE_GANONS_CASTLE_6:
case ENTR_INSIDE_GANONS_CASTLE_7:
if (Flags_GetEventChkInf(EVENTCHKINF_COMPLETED_FOREST_TRIAL) &&
Flags_GetEventChkInf(EVENTCHKINF_COMPLETED_WATER_TRIAL) &&
Flags_GetEventChkInf(EVENTCHKINF_COMPLETED_SHADOW_TRIAL) &&
Flags_GetEventChkInf(EVENTCHKINF_COMPLETED_FIRE_TRIAL) &&
Flags_GetEventChkInf(EVENTCHKINF_COMPLETED_LIGHT_TRIAL) &&
Flags_GetEventChkInf(EVENTCHKINF_COMPLETED_SPIRIT_TRIAL)) {
Flags_SetEventChkInf(EVENTCHKINF_DISPELLED_GANONS_TOWER_BARRIER);
}
break;
}
}
break;
}
@ -275,6 +296,11 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
}
switch (actor->id) {
case ACTOR_OBJ_SWITCH: {
if ((actor->params == 8224 && gPlayState->sceneNum == SCENE_DODONGOS_CAVERN) ||
(actor->params == 6979 && gPlayState->sceneNum == SCENE_WATER_TEMPLE) &&
CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) {
break;
}
ObjSwitch* switchActor = (ObjSwitch*)actor;
switchActor->cooldownTimer = 0;
*should = false;
@ -349,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;
@ -441,6 +472,26 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
*should = false;
}
break;
case VB_PLAY_DISPEL_BARRIER_CS: {
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO)) {
static s16 trialEntrances[] = {
0,
ENTR_INSIDE_GANONS_CASTLE_3,
ENTR_INSIDE_GANONS_CASTLE_6,
ENTR_INSIDE_GANONS_CASTLE_5,
ENTR_INSIDE_GANONS_CASTLE_4,
ENTR_INSIDE_GANONS_CASTLE_7,
ENTR_INSIDE_GANONS_CASTLE_2,
};
RateLimitedSuccessChime();
DemoKekkai* kekkai = va_arg(args, DemoKekkai*);
gPlayState->nextEntranceIndex = trialEntrances[kekkai->actor.params];
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
gPlayState->transitionType = TRANS_TYPE_FADE_BLACK;
*should = false;
}
break;
}
case VB_OWL_INTERACTION: {
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipOwlInteractions"), IS_RANDO) && *should) {
EnOwl* enOwl = va_arg(args, EnOwl*);
@ -720,6 +771,18 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
break;
}
case VB_PLAY_GATE_OPENING_OR_CLOSING_CS: {
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) {
EnHeishi2* enHeishi2 = va_arg(args, EnHeishi2*);
enHeishi2->unk_2F2[0] = 0;
// The second argument determines whether the vanilla code should be run anyway. It
// should be set to `true` ONLY IF said code calls `Play_ClearCamera`, false otherwise.
bool clearCamera = (bool)va_arg(args, int);
*should = clearCamera && enHeishi2->cameraId != MAIN_CAM;
}
break;
}
case VB_PLAY_RAINBOW_BRIDGE_CS: {
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) {
*should = false;

View file

@ -2437,15 +2437,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 &&

View file

@ -336,8 +336,8 @@ void SohMenu::AddMenuEnhancements() {
.CVar(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"))
.Options(CheckboxOptions().Tooltip(
"Don't skip cutscenes that are associated with useful glitches. Currently, it is "
"only the Fire Temple Darunia CS, Forest Temple Poe Sisters CS, and the Box Skip One "
"Point in Jabu."));
"only the Fire Temple Darunia CS, Forest Temple Poe Sisters CS, Dodongo Boss "
"Door Switch CS, Water Temple Dragon Switch CS, and the Box Skip One Point in Jabu."));
AddWidget(path, "Text", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Skip Pickup Messages", WIDGET_CVAR_CHECKBOX)

View file

@ -4112,7 +4112,8 @@ void Interface_DrawItemButtons(PlayState* play) {
if (CVarGetInteger(CVAR_COSMETIC("HUD.CDownButton.UseMargins"), 0) != 0) {
X_Margins_CD = Left_HUD_Margin;
};
C_Down_BTN_Pos[0] = (CVarGetInteger(CVAR_COSMETIC("HUD.CDownButton.PosX"), 0) + X_Margins_CD);
C_Down_BTN_Pos[0] =
OTRGetDimensionFromLeftEdge(CVarGetInteger(CVAR_COSMETIC("HUD.CDownButton.PosX"), 0) + X_Margins_CD);
} else if (CVarGetInteger(CVAR_COSMETIC("HUD.CDownButton.PosType"), 0) == ANCHOR_RIGHT) {
if (CVarGetInteger(CVAR_COSMETIC("HUD.CDownButton.UseMargins"), 0) != 0) {
X_Margins_CD = Right_HUD_Margin;

View file

@ -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) {

View file

@ -7,6 +7,7 @@
#include "z_demo_kekkai.h"
#include "objects/object_demo_kekkai/object_demo_kekkai.h"
#include "scenes/dungeons/ganontika/ganontika_scene.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ResourceManagerHelpers.h"
#define FLAGS (ACTOR_FLAG_UPDATE_CULLING_DISABLED | ACTOR_FLAG_DRAW_CULLING_DISABLED)
@ -257,13 +258,15 @@ void DemoKekkai_TrialBarrierIdle(Actor* thisx, PlayState* play) {
CollisionCheck_SetAT(play, &play->colChkCtx, &this->collider1.base);
CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider1.base);
if (this->collider2.base.acFlags & AC_HIT) {
Sfx_PlaySfxCentered(NA_SE_SY_CORRECT_CHIME);
// "I got it"
LOG_STRING("当ったよ");
this->actor.update = DemoKekkai_TrialBarrierDispel;
this->timer = 0;
play->csCtx.segment = SEGMENTED_TO_VIRTUAL(sSageCutscenes[this->actor.params]);
gSaveContext.cutsceneTrigger = 1;
if (GameInteractor_Should(VB_PLAY_DISPEL_BARRIER_CS, true, this)) {
Sfx_PlaySfxCentered(NA_SE_SY_CORRECT_CHIME);
// "I got it"
LOG_STRING("当ったよ");
this->actor.update = DemoKekkai_TrialBarrierDispel;
this->timer = 0;
play->csCtx.segment = SEGMENTED_TO_VIRTUAL(sSageCutscenes[this->actor.params]);
gSaveContext.cutsceneTrigger = 1;
}
}
CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider2.base);
func_8002F974(&this->actor, NA_SE_EV_TOWER_ENERGY - SFX_FLAG);

View file

@ -6,7 +6,7 @@
struct DemoKekkai;
typedef void (*DemoKekkaiUpdateFunc)(struct DemoKekkai* this, PlayState* play);
typedef void (*DemoKekkaiUpdateFunc)(struct DemoKekkai* thisx, PlayState* play);
typedef struct DemoKekkai {
/* 0x0000 */ Actor actor;

View file

@ -314,19 +314,21 @@ void func_80A5372C(EnHeishi2* this, PlayState* play) {
f32 frameCount = Animation_GetLastFrame(&gEnHeishiIdleAnim);
Animation_Change(&this->skelAnime, &gEnHeishiIdleAnim, 1.0f, 0.0f, (s16)frameCount, ANIMMODE_LOOP, -10.0f);
this->unk_2F2[0] = 200;
this->cameraId = Play_CreateSubCamera(play);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_WAIT);
Play_ChangeCameraStatus(play, this->cameraId, CAM_STAT_ACTIVE);
this->unk_280.x = 947.0f;
this->unk_280.y = 1195.0f;
this->unk_280.z = 2682.0f;
if (GameInteractor_Should(VB_PLAY_GATE_OPENING_OR_CLOSING_CS, true, this, false)) {
this->unk_2F2[0] = 200;
this->cameraId = Play_CreateSubCamera(play);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_WAIT);
Play_ChangeCameraStatus(play, this->cameraId, CAM_STAT_ACTIVE);
this->unk_280.x = 947.0f;
this->unk_280.y = 1195.0f;
this->unk_280.z = 2682.0f;
this->unk_28C.x = 1164.0f;
this->unk_28C.y = 1145.0f;
this->unk_28C.z = 3014.0f;
this->unk_28C.x = 1164.0f;
this->unk_28C.y = 1145.0f;
this->unk_28C.z = 3014.0f;
Play_CameraSetAtEye(play, this->cameraId, &this->unk_280, &this->unk_28C);
Play_CameraSetAtEye(play, this->cameraId, &this->unk_280, &this->unk_28C);
}
this->actionFunc = func_80A53850;
}
@ -334,11 +336,15 @@ void func_80A53850(EnHeishi2* this, PlayState* play) {
BgSpot15Saku* gate;
SkelAnime_Update(&this->skelAnime);
Play_CameraSetAtEye(play, this->cameraId, &this->unk_280, &this->unk_28C);
if (GameInteractor_Should(VB_PLAY_GATE_OPENING_OR_CLOSING_CS, true, this, false)) {
Play_CameraSetAtEye(play, this->cameraId, &this->unk_280, &this->unk_28C);
}
gate = (BgSpot15Saku*)this->gate;
if ((this->unk_2F2[0] == 0) || (gate->unk_168 == 0)) {
Play_ClearCamera(play, this->cameraId);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_ACTIVE);
if (GameInteractor_Should(VB_PLAY_GATE_OPENING_OR_CLOSING_CS, true, this, true)) {
Play_ClearCamera(play, this->cameraId);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_ACTIVE);
}
Message_CloseTextbox(play);
this->unk_30C = 1;
Player_SetCsActionWithHaltedActors(play, NULL, 7);
@ -479,23 +485,25 @@ void func_80A53DF8(EnHeishi2* this, PlayState* play) {
f32 frameCount = Animation_GetLastFrame(&gEnHeishiIdleAnim);
Animation_Change(&this->skelAnime, &gEnHeishiIdleAnim, 1.0f, 0.0f, (s16)frameCount, ANIMMODE_LOOP, -10.0f);
this->unk_2F2[0] = 200;
this->cameraId = Play_CreateSubCamera(play);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_WAIT);
Play_ChangeCameraStatus(play, this->cameraId, CAM_STAT_ACTIVE);
this->unk_2BC.x = -71.0f;
this->unk_280.x = -71.0f;
this->unk_2BC.y = 571.0f;
this->unk_280.y = 571.0f;
this->unk_2BC.z = -1487.0f;
this->unk_280.z = -1487.0f;
this->unk_298.x = 181.0f;
this->unk_28C.x = 181.0f;
this->unk_298.y = 417.0f;
this->unk_28C.y = 417.0f;
this->unk_298.z = -1079.0f;
this->unk_28C.z = -1079.0f;
Play_CameraSetAtEye(play, this->cameraId, &this->unk_280, &this->unk_28C);
if (GameInteractor_Should(VB_PLAY_GATE_OPENING_OR_CLOSING_CS, true, this, false)) {
this->unk_2F2[0] = 200;
this->cameraId = Play_CreateSubCamera(play);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_WAIT);
Play_ChangeCameraStatus(play, this->cameraId, CAM_STAT_ACTIVE);
this->unk_2BC.x = -71.0f;
this->unk_280.x = -71.0f;
this->unk_2BC.y = 571.0f;
this->unk_280.y = 571.0f;
this->unk_2BC.z = -1487.0f;
this->unk_280.z = -1487.0f;
this->unk_298.x = 181.0f;
this->unk_28C.x = 181.0f;
this->unk_298.y = 417.0f;
this->unk_28C.y = 417.0f;
this->unk_298.z = -1079.0f;
this->unk_28C.z = -1079.0f;
Play_CameraSetAtEye(play, this->cameraId, &this->unk_280, &this->unk_28C);
}
this->actionFunc = func_80A53F30;
}
@ -503,11 +511,15 @@ void func_80A53F30(EnHeishi2* this, PlayState* play) {
BgGateShutter* gate;
SkelAnime_Update(&this->skelAnime);
Play_CameraSetAtEye(play, this->cameraId, &this->unk_280, &this->unk_28C);
if (GameInteractor_Should(VB_PLAY_GATE_OPENING_OR_CLOSING_CS, true, this, false)) {
Play_CameraSetAtEye(play, this->cameraId, &this->unk_280, &this->unk_28C);
}
gate = (BgGateShutter*)this->gate;
if ((this->unk_2F2[0] == 0) || (gate->openingState == 0)) {
Play_ClearCamera(play, this->cameraId);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_ACTIVE);
if (GameInteractor_Should(VB_PLAY_GATE_OPENING_OR_CLOSING_CS, true, this, true)) {
Play_ClearCamera(play, this->cameraId);
Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_ACTIVE);
}
if ((this->unk_30A != 2)) {
if (this->unk_30A == 0) {
this->actor.textId = 0x2015;