mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-22 06:13:45 -07:00
Merge branch 'develop' into SplitGF
This commit is contained in:
commit
216b666f24
50 changed files with 2438 additions and 3625 deletions
|
@ -12,7 +12,6 @@ extern "C"
|
|||
|
||||
#include "luslog.h"
|
||||
#include <soh/Enhancements/item-tables/ItemTableTypes.h>
|
||||
#include <soh/Enhancements/randomizer/randomizer_inf.h>
|
||||
|
||||
#if defined(INCLUDE_GAME_PRINTF) && defined(_DEBUG)
|
||||
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, ##__VA_ARGS__)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "z64math.h"
|
||||
#include "z64audio.h"
|
||||
#include "soh/Enhancements/randomizer/randomizerTypes.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer_inf.h"
|
||||
#include "soh/Enhancements/gameplaystats.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRushTypes.h"
|
||||
|
|
42
soh/soh/Enhancements/ExtraModes/RupeeDash.cpp
Normal file
42
soh/soh/Enhancements/ExtraModes/RupeeDash.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include <libultraship/bridge.h>
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
#include "variables.h"
|
||||
|
||||
extern "C" PlayState* gPlayState;
|
||||
|
||||
static constexpr int32_t CVAR_RUPEE_DASH_DEFAULT = 0;
|
||||
#define CVAR_RUPEE_DASH_NAME CVAR_ENHANCEMENT("RupeeDash")
|
||||
#define CVAR_RUPEE_DASH_VALUE CVarGetInteger(CVAR_RUPEE_DASH_NAME, CVAR_RUPEE_DASH_DEFAULT)
|
||||
|
||||
static constexpr int32_t CVAR_RUPEE_DASH_INTERVAL_DEFAULT = 5;
|
||||
#define CVAR_RUPEE_DASH_INTERVAL_NAME CVAR_ENHANCEMENT("RupeeDashInterval")
|
||||
#define CVAR_RUPEE_DASH_INTERVAL_TIME \
|
||||
CVarGetInteger(CVAR_RUPEE_DASH_INTERVAL_NAME, CVAR_RUPEE_DASH_INTERVAL_DEFAULT) * 20
|
||||
|
||||
void UpdateRupeeDash() {
|
||||
// Initialize Timer
|
||||
static uint16_t rupeeDashTimer = 0;
|
||||
|
||||
// Did time change by DashInterval?
|
||||
if (rupeeDashTimer < CVAR_RUPEE_DASH_INTERVAL_TIME) {
|
||||
rupeeDashTimer++;
|
||||
return;
|
||||
}
|
||||
|
||||
rupeeDashTimer = 0;
|
||||
if (gSaveContext.rupees > 0) {
|
||||
uint16_t walletSize = (CUR_UPG_VALUE(UPG_WALLET) + 1) * -1;
|
||||
Rupees_ChangeBy(walletSize);
|
||||
} else {
|
||||
Health_ChangeBy(gPlayState, -16);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterRupeeDash() {
|
||||
COND_HOOK(OnPlayerUpdate, CVAR_RUPEE_DASH_VALUE, UpdateRupeeDash);
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc_RupeeDash(RegisterRupeeDash, { CVAR_RUPEE_DASH_NAME });
|
|
@ -193,12 +193,10 @@ void ParsePreset(nlohmann::json& json, std::string name) {
|
|||
}
|
||||
|
||||
void LoadPresets() {
|
||||
if (!fs::exists(presetFolder)) {
|
||||
return;
|
||||
}
|
||||
if (!presets.empty()) {
|
||||
presets.clear();
|
||||
}
|
||||
if (fs::exists(presetFolder)) {
|
||||
for (auto const& preset : fs::directory_iterator(presetFolder)) {
|
||||
std::ifstream ifs(preset.path());
|
||||
|
||||
|
@ -211,6 +209,7 @@ void LoadPresets() {
|
|||
}
|
||||
ifs.close();
|
||||
}
|
||||
}
|
||||
auto initData = std::make_shared<Ship::ResourceInitData>();
|
||||
initData->Format = RESOURCE_FORMAT_BINARY;
|
||||
initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json);
|
||||
|
|
25
soh/soh/Enhancements/RebottleBlueFire.cpp
Normal file
25
soh/soh/Enhancements/RebottleBlueFire.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "src/overlays/actors/ovl_En_Ice_Hono/z_en_ice_hono.h"
|
||||
void EnIceHono_CapturableFlame(EnIceHono* thisx, PlayState* play);
|
||||
u32 EnIceHono_InBottleRange(EnIceHono* thisx, PlayState* play);
|
||||
}
|
||||
|
||||
extern PlayState* gPlayState;
|
||||
|
||||
void OnEnIceHonoUpdate(void* actor) {
|
||||
EnIceHono* thisx = (EnIceHono*)actor;
|
||||
if (thisx->actionFunc != EnIceHono_CapturableFlame && EnIceHono_InBottleRange(thisx, gPlayState)) {
|
||||
// GI_MAX in this case allows the player to catch the actor in a bottle
|
||||
Actor_OfferGetItem(&thisx->actor, gPlayState, GI_MAX, 60.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterRebottleBlueFire() {
|
||||
COND_ID_HOOK(OnActorUpdate, ACTOR_EN_ICE_HONO, CVarGetInteger(CVAR_ENHANCEMENT("RebottleBlueFire"), 0),
|
||||
OnEnIceHonoUpdate);
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(RegisterRebottleBlueFire, { CVAR_ENHANCEMENT("RebottleBlueFire") });
|
8
soh/soh/Enhancements/SkipAmyPuzzle.cpp
Normal file
8
soh/soh/Enhancements/SkipAmyPuzzle.cpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
|
||||
void RegisterSkipAmyPuzzle() {
|
||||
COND_VB_SHOULD(VB_AMY_SOLVE, CVarGetInteger(CVAR_ENHANCEMENT("SkipAmyPuzzle"), 0), { *should = true; });
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(RegisterSkipAmyPuzzle, { CVAR_ENHANCEMENT("SkipAmyPuzzle") });
|
|
@ -10,8 +10,6 @@ extern "C" {
|
|||
#include "variables.h"
|
||||
}
|
||||
|
||||
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
|
||||
|
||||
static bool sEnteredBlueWarp = false;
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "soh/Enhancements/nametag.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <map>
|
||||
|
@ -45,13 +46,6 @@ typedef struct {
|
|||
Vec3s rot;
|
||||
} ActorInfo;
|
||||
|
||||
typedef enum {
|
||||
LIST,
|
||||
TARGET,
|
||||
HELD,
|
||||
INTERACT,
|
||||
} RetrievalMethod;
|
||||
|
||||
std::array<const char*, 12> acMapping = {
|
||||
"Switch", "Background (Prop type 1)",
|
||||
"Player", "Bomb",
|
||||
|
@ -873,37 +867,14 @@ void ActorViewer_AddTagForAllActors() {
|
|||
|
||||
void ActorViewerWindow::DrawElement() {
|
||||
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
|
||||
static Actor* display;
|
||||
static Actor empty{};
|
||||
static Actor* fetch = NULL;
|
||||
static ActorInfo newActor = { 0, 0, { 0, 0, 0 }, { 0, 0, 0 } };
|
||||
static bool needs_reset = false;
|
||||
static ImU16 one = 1;
|
||||
static int actor;
|
||||
static int category = 0;
|
||||
static RetrievalMethod rm;
|
||||
static std::string filler = "Please select";
|
||||
static std::vector<Actor*> list;
|
||||
static u16 lastSceneId = 0;
|
||||
static std::string searchString = "";
|
||||
static s16 currentSelectedInDropdown;
|
||||
static std::vector<u16> actors;
|
||||
static s16 currentSelectedInDropdown = -1;
|
||||
static std::vector<u16> actorSearchResults;
|
||||
|
||||
if (gPlayState != nullptr) {
|
||||
needs_reset = lastSceneId != gPlayState->sceneNum;
|
||||
if (needs_reset) {
|
||||
display = ∅
|
||||
fetch = nullptr;
|
||||
actor = category = 0;
|
||||
filler = "Please Select";
|
||||
list.clear();
|
||||
needs_reset = false;
|
||||
searchString = "";
|
||||
currentSelectedInDropdown = -1;
|
||||
actors.clear();
|
||||
}
|
||||
lastSceneId = gPlayState->sceneNum;
|
||||
|
||||
if (ImGui::BeginChild("options", ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
|
||||
bool toggled = false;
|
||||
bool optionChange = false;
|
||||
|
@ -967,21 +938,19 @@ void ActorViewerWindow::DrawElement() {
|
|||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Actor", filler.c_str())) {
|
||||
if (gPlayState != nullptr && lastSceneId != gPlayState->sceneNum) {
|
||||
PopulateActorDropdown(category, list);
|
||||
lastSceneId = gPlayState->sceneNum;
|
||||
if (display == nullptr) {
|
||||
filler = "Please select";
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Actor", filler.c_str())) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
std::string label = std::to_string(i) + ": " + ActorDB::Instance->RetrieveEntry(list[i]->id).name;
|
||||
std::string description = GetActorDescription(list[i]->id);
|
||||
if (description != "")
|
||||
label += " (" + description + ")";
|
||||
|
||||
if (ImGui::Selectable(label.c_str())) {
|
||||
rm = LIST;
|
||||
if (ImGui::Selectable(label.c_str(), list[i] == display)) {
|
||||
display = list[i];
|
||||
actor = i;
|
||||
filler = label;
|
||||
break;
|
||||
}
|
||||
|
@ -992,6 +961,7 @@ void ActorViewerWindow::DrawElement() {
|
|||
|
||||
PushStyleHeader(THEME_COLOR);
|
||||
if (ImGui::TreeNode("Selected Actor")) {
|
||||
if (display != nullptr) {
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::Text("Name: %s", ActorDB::Instance->RetrieveEntry(display->id).name.c_str());
|
||||
|
@ -1054,61 +1024,42 @@ void ActorViewerWindow::DrawElement() {
|
|||
},
|
||||
"bgCheckFlags");
|
||||
|
||||
if (Button("Refresh", ButtonOptions().Color(THEME_COLOR))) {
|
||||
PopulateActorDropdown(category, list);
|
||||
switch (rm) {
|
||||
case INTERACT:
|
||||
case HELD:
|
||||
case TARGET:
|
||||
display = fetch;
|
||||
break;
|
||||
case LIST:
|
||||
display = list[actor];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Button("Go to Actor", ButtonOptions().Color(THEME_COLOR))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
Math_Vec3f_Copy(&player->actor.world.pos, &display->world.pos);
|
||||
Math_Vec3f_Copy(&player->actor.home.pos, &player->actor.world.pos);
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("Select an actor to display information.");
|
||||
}
|
||||
|
||||
if (Button("Fetch from Target",
|
||||
ButtonOptions()
|
||||
.Color(THEME_COLOR)
|
||||
.Tooltip("Grabs actor with target arrow above it. You might need C-Up for enemies"))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->talkActor;
|
||||
if (fetch != NULL) {
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
if (player->talkActor != NULL) {
|
||||
display = player->talkActor;
|
||||
category = display->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = TARGET;
|
||||
}
|
||||
}
|
||||
if (Button("Fetch from Held",
|
||||
ButtonOptions().Color(THEME_COLOR).Tooltip("Grabs actor that Link is holding"))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->heldActor;
|
||||
if (fetch != NULL) {
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
if (player->heldActor != NULL) {
|
||||
display = player->heldActor;
|
||||
category = display->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = HELD;
|
||||
}
|
||||
}
|
||||
if (Button("Fetch from Interaction",
|
||||
ButtonOptions().Color(THEME_COLOR).Tooltip("Grabs actor from \"interaction range\""))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->interactRangeActor;
|
||||
if (fetch != NULL) {
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
if (player->interactRangeActor != NULL) {
|
||||
display = player->interactRangeActor;
|
||||
category = display->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = INTERACT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1119,21 +1070,22 @@ void ActorViewerWindow::DrawElement() {
|
|||
// ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
|
||||
|
||||
if (InputString("Search Actor", &searchString, InputOptions().Color(THEME_COLOR))) {
|
||||
actors = GetActorsWithDescriptionContainingString(searchString);
|
||||
actorSearchResults = GetActorsWithDescriptionContainingString(searchString);
|
||||
currentSelectedInDropdown = -1;
|
||||
}
|
||||
|
||||
if (!SohUtils::IsStringEmpty(searchString) && !actors.empty()) {
|
||||
std::string preview = currentSelectedInDropdown == -1
|
||||
if (!SohUtils::IsStringEmpty(searchString) && !actorSearchResults.empty()) {
|
||||
std::string preview =
|
||||
currentSelectedInDropdown == -1
|
||||
? "Please Select"
|
||||
: ActorDB::Instance->RetrieveEntry(actors[currentSelectedInDropdown]).desc;
|
||||
: ActorDB::Instance->RetrieveEntry(actorSearchResults[currentSelectedInDropdown]).desc;
|
||||
PushStyleCombobox(THEME_COLOR);
|
||||
if (ImGui::BeginCombo("Results", preview.c_str())) {
|
||||
for (u8 i = 0; i < actors.size(); i++) {
|
||||
if (ImGui::Selectable(ActorDB::Instance->RetrieveEntry(actors[i]).desc.c_str(),
|
||||
for (u8 i = 0; i < actorSearchResults.size(); i++) {
|
||||
if (ImGui::Selectable(ActorDB::Instance->RetrieveEntry(actorSearchResults[i]).desc.c_str(),
|
||||
i == currentSelectedInDropdown)) {
|
||||
currentSelectedInDropdown = i;
|
||||
newActor.id = actors[i];
|
||||
newActor.id = actorSearchResults[i];
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
|
@ -1237,20 +1189,40 @@ void ActorViewerWindow::DrawElement() {
|
|||
PopStyleHeader();
|
||||
} else {
|
||||
ImGui::Text("Global Context needed for actor info!");
|
||||
if (needs_reset) {
|
||||
fetch = nullptr;
|
||||
actor = category = 0;
|
||||
filler = "Please Select";
|
||||
list.clear();
|
||||
needs_reset = false;
|
||||
searchString = "";
|
||||
currentSelectedInDropdown = -1;
|
||||
actors.clear();
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
void ActorViewerWindow::InitElement() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorSpawn>([this](void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
|
||||
// Reload actor list if the new actor belongs to the selected category
|
||||
if (category == actor->category) {
|
||||
PopulateActorDropdown(actor->category, list);
|
||||
}
|
||||
});
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorDestroy>([this](void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
|
||||
// If the actor belongs to the selected category, we need to manually remove it, as it has not been removed from
|
||||
// the global actor array yet
|
||||
if (category == actor->category) {
|
||||
list.erase(std::remove(list.begin(), list.end(), actor), list.end());
|
||||
}
|
||||
if (display == actor) {
|
||||
display = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([this](int16_t sceneNum) {
|
||||
display = nullptr;
|
||||
category = ACTORCAT_SWITCH;
|
||||
list.clear();
|
||||
});
|
||||
}
|
||||
|
||||
void ActorViewer_RegisterNameTagHooks() {
|
||||
COND_HOOK(OnActorInit, CVAR_ACTOR_NAME_TAGS_ENABLED,
|
||||
[](void* actor) { ActorViewer_AddTagForActor(static_cast<Actor*>(actor)); });
|
||||
|
|
|
@ -2,11 +2,20 @@
|
|||
|
||||
#include <libultraship/libultraship.h>
|
||||
|
||||
#include "z64actor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ActorViewerWindow final : public Ship::GuiWindow {
|
||||
public:
|
||||
using GuiWindow::GuiWindow;
|
||||
|
||||
void DrawElement() override;
|
||||
void InitElement() override{};
|
||||
void InitElement() override;
|
||||
void UpdateElement() override{};
|
||||
|
||||
private:
|
||||
Actor* display = nullptr;
|
||||
int category = ACTORCAT_SWITCH;
|
||||
std::vector<Actor*> list;
|
||||
};
|
||||
|
|
|
@ -554,6 +554,10 @@ void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t row, uint16_t& fl
|
|||
uint32_t bitMask = 1 << flagIndex;
|
||||
ImVec4 themeColor = ColorValues.at(THEME_COLOR);
|
||||
ImVec4 colorDark = { themeColor.x * 0.4f, themeColor.y * 0.4f, themeColor.z * 0.4f, themeColor.z };
|
||||
ImVec4& color = themeColor;
|
||||
if (!hasDescription) {
|
||||
color = colorDark;
|
||||
}
|
||||
PushStyleCheckbox(hasDescription ? themeColor : colorDark);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0f, 3.0f));
|
||||
bool flag = (flags & bitMask) != 0;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,15 +13,29 @@ extern "C" {
|
|||
#include <z64.h>
|
||||
}
|
||||
|
||||
const char* enemyCVarList[] = {
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Armos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Arwing"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.BabyDodongo"), CVAR_ENHANCEMENT("RandomizedEnemyList.Bari"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Beamos"), CVAR_ENHANCEMENT("RandomizedEnemyList.BigSkulltula"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.BigStalchild"), CVAR_ENHANCEMENT("RandomizedEnemyList.Biri"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.BlackKnuckle"), CVAR_ENHANCEMENT("RandomizedEnemyList.BlueTektite"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Bubble"), CVAR_ENHANCEMENT("RandomizedEnemyList.ClubMoblin"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.DarkLink"), CVAR_ENHANCEMENT("RandomizedEnemyList.Dinolfos"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Dodongo"), CVAR_ENHANCEMENT("RandomizedEnemyList.FireKeese"),
|
||||
#define CVAR_ENEMY_RANDOMIZER_NAME CVAR_ENHANCEMENT("RandomizedEnemies")
|
||||
#define CVAR_ENEMY_RANDOMIZER_DEFAULT ENEMY_RANDOMIZER_OFF
|
||||
#define CVAR_ENEMY_RANDOMIZER_VALUE CVarGetInteger(CVAR_ENEMY_RANDOMIZER_NAME, CVAR_ENEMY_RANDOMIZER_DEFAULT)
|
||||
|
||||
typedef struct EnemyEntry {
|
||||
int16_t id;
|
||||
int16_t params;
|
||||
} EnemyEntry;
|
||||
|
||||
bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId, int16_t params, float posX);
|
||||
bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy);
|
||||
EnemyEntry GetRandomizedEnemyEntry(uint32_t seed);
|
||||
|
||||
const char* enemyCVarList[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Anubis"), CVAR_ENHANCEMENT("RandomizedEnemyList.Armos"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Arwing"), CVAR_ENHANCEMENT("RandomizedEnemyList.BabyDodongo"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Bari"), CVAR_ENHANCEMENT("RandomizedEnemyList.Beamos"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.BigSkulltula"), CVAR_ENHANCEMENT("RandomizedEnemyList.BigStalchild"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Biri"), CVAR_ENHANCEMENT("RandomizedEnemyList.BlackKnuckle"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.BlueTektite"), CVAR_ENHANCEMENT("RandomizedEnemyList.Bubble"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.ClubMoblin"), CVAR_ENHANCEMENT("RandomizedEnemyList.DarkLink"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Dinolfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Dodongo"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.FireKeese"), /*CVAR_ENHANCEMENT("RandomizedEnemyList.FlareDancer"),*/
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.FloorTile"), CVAR_ENHANCEMENT("RandomizedEnemyList.Floormaster"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPeahat"), CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPot"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Freezard"), CVAR_ENHANCEMENT("RandomizedEnemyList.Gibdo"),
|
||||
|
@ -30,18 +44,20 @@ const char* enemyCVarList[] = {
|
|||
CVAR_ENHANCEMENT("RandomizedEnemyList.Keese"), CVAR_ENHANCEMENT("RandomizedEnemyList.LargeBaba"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.LikeLike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Lizalfos"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.MadScrub"), CVAR_ENHANCEMENT("RandomizedEnemyList.NormalWolfos"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.PeahatLarva"), CVAR_ENHANCEMENT("RandomizedEnemyList.Redead"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.RedTektite"), CVAR_ENHANCEMENT("RandomizedEnemyList.Shabom"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.ShellBlade"), CVAR_ENHANCEMENT("RandomizedEnemyList.Skulltula"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.PeahatLarva"), /*CVAR_ENHANCEMENT("RandomizedEnemyList.Poe"),*/
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Redead"), CVAR_ENHANCEMENT("RandomizedEnemyList.RedTektite"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Shabom"), CVAR_ENHANCEMENT("RandomizedEnemyList.ShellBlade"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Skulltula"), CVAR_ENHANCEMENT("RandomizedEnemyList.SkullKid"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.SmallBaba"), CVAR_ENHANCEMENT("RandomizedEnemyList.SmallStalchild"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Spike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stalfos"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Stinger"), CVAR_ENHANCEMENT("RandomizedEnemyList.Tailparasan"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.TorchSlug"), CVAR_ENHANCEMENT("RandomizedEnemyList.Wallmaster"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteKnuckle"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteWolfos"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.WitheredBaba"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.SpearMoblin"), CVAR_ENHANCEMENT("RandomizedEnemyList.Spike"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Stalfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stinger"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Tailparasan"), CVAR_ENHANCEMENT("RandomizedEnemyList.TorchSlug"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.Wallmaster"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteKnuckle"),
|
||||
CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteWolfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.WitheredBaba"),
|
||||
};
|
||||
|
||||
const char* enemyNameList[] = {
|
||||
const char* enemyNameList[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
|
||||
"Anubis",
|
||||
"Armos",
|
||||
"Arwing",
|
||||
"Baby Dodongo",
|
||||
|
@ -58,6 +74,7 @@ const char* enemyNameList[] = {
|
|||
"Dinolfos",
|
||||
"Dodongo",
|
||||
"Fire Keese",
|
||||
//"Flare Dancer",
|
||||
"Floor Tile",
|
||||
"Floormaster",
|
||||
"Flying Peahat",
|
||||
|
@ -75,13 +92,16 @@ const char* enemyNameList[] = {
|
|||
"Mad Scrub",
|
||||
"Wolfos (Normal)",
|
||||
"Peahat Larva",
|
||||
//"Poe",
|
||||
"Redead",
|
||||
"Red Tektite",
|
||||
"Shabom",
|
||||
"Shell Blade",
|
||||
"Skulltula",
|
||||
"Skull Kid",
|
||||
"Small Deku Baba",
|
||||
"Stalchild (Small)",
|
||||
"Spear Moblin",
|
||||
"Spike",
|
||||
"Stalfos",
|
||||
"Stinger",
|
||||
|
@ -94,6 +114,7 @@ const char* enemyNameList[] = {
|
|||
};
|
||||
|
||||
static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
|
||||
{ ACTOR_EN_ANUBICE_TAG, 1 }, // Anubis
|
||||
{ ACTOR_EN_AM, -1 }, // Armos
|
||||
{ ACTOR_EN_CLEAR_TAG, 1 }, // Arwing
|
||||
{ ACTOR_EN_DODOJR, 0 }, // Baby Dodongo
|
||||
|
@ -105,11 +126,13 @@ static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] =
|
|||
{ ACTOR_EN_IK, 2 }, // Iron Knuckle (black, standing)
|
||||
{ ACTOR_EN_TITE, -2 }, // Tektite (blue)
|
||||
{ ACTOR_EN_BB, -1 }, // Bubble (flying skull enemy) (blue)
|
||||
{ ACTOR_EN_MB, 0 }, // Moblins (Club)
|
||||
{ ACTOR_EN_MB, 0 }, // Club Moblin
|
||||
{ ACTOR_EN_TORCH2, 0 }, // Dark Link
|
||||
{ ACTOR_EN_ZF, -2 }, // Dinolfos
|
||||
{ ACTOR_EN_DODONGO, -1 }, // Dodongo
|
||||
{ ACTOR_EN_FIREFLY, 1 }, // Fire Keese
|
||||
// { ACTOR_EN_FD, 0 }, // Flare Dancer (possible cause of crashes because of spawning flame actors on
|
||||
// sloped ground)
|
||||
{ ACTOR_EN_YUKABYUN, 0 }, // Flying Floor Tile
|
||||
{ ACTOR_EN_FLOORMAS, 0 }, // Floormaster
|
||||
{ ACTOR_EN_PEEHAT, -1 }, // Flying Peahat (big grounded, doesn't spawn larva)
|
||||
|
@ -122,18 +145,30 @@ static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] =
|
|||
{ ACTOR_EN_ST, 2 }, // Skulltula (invisible)
|
||||
{ ACTOR_EN_FIREFLY, 2 }, // Regular Keese
|
||||
{ ACTOR_EN_DEKUBABA, 1 }, // Deku Baba (large)
|
||||
// Doesn't work (reliant on surface and also normally used in tandem with a leever spawner, kills itself too quickly
|
||||
// otherwise) { ACTOR_EN_REEBA, 0 }, // Leever
|
||||
{ ACTOR_EN_RR, 0 }, // Like-Like
|
||||
{ ACTOR_EN_ZF, -1 }, // Lizalfos
|
||||
{ ACTOR_EN_DEKUNUTS, 768 }, // Mad Scrub (triple attack) (projectiles don't work)
|
||||
{ ACTOR_EN_WF, 0 }, // Wolfos (normal)
|
||||
// Doesn't work (actor directly uses water box collision to handle hiding/popping up)
|
||||
// { ACTOR_EN_OKUTA, 0 }, // Octorok
|
||||
{ ACTOR_EN_PEEHAT, 1 }, // Flying Peahat Larva
|
||||
// Doesn't work (Seems to rely on other objects?)
|
||||
// { ACTOR_EN_POH, 0 }, // Poe
|
||||
// Doesn't work (Seems to rely on other objects?)
|
||||
// { ACTOR_EN_POH, 2 }, // Poe (composer Sharp)
|
||||
// Doesn't work (Seems to rely on other objects?)
|
||||
// { ACTOR_EN_POH, 3 }, // Poe (composer Flat)
|
||||
{ ACTOR_EN_RD, 1 }, // Redead (standing)
|
||||
{ ACTOR_EN_TITE, -1 }, // Tektite (red)
|
||||
{ ACTOR_EN_BUBBLE, 0 }, // Shabom (bubble)
|
||||
{ ACTOR_EN_SB, 0 }, // Shell Blade
|
||||
{ ACTOR_EN_ST, 0 }, // Skulltula (normal)
|
||||
{ ACTOR_EN_SKJ, 4159 }, // Skull Kid
|
||||
{ ACTOR_EN_DEKUBABA, 0 }, // Deku Baba (small)
|
||||
{ ACTOR_EN_SKB, 1 }, // Stalchild (small)
|
||||
{ ACTOR_EN_MB, -1 }, // Spear Moblin
|
||||
{ ACTOR_EN_NY, 0 }, // Spike (rolling enemy)
|
||||
{ ACTOR_EN_TEST, 2 }, // Stalfos
|
||||
{ ACTOR_EN_EIYER, 10 }, // Stinger (land) (One in formation, sink under floor and do not activate)
|
||||
|
@ -143,17 +178,10 @@ static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] =
|
|||
{ ACTOR_EN_IK, 3 }, // Iron Knuckle (white, standing)
|
||||
{ ACTOR_EN_WF, 1 }, // Wolfos (white)
|
||||
{ ACTOR_EN_KAREBABA, 0 }, // Withered Deku Baba
|
||||
|
||||
// Doesn't work {ACTOR_EN_POH, 0}, // Poe (Seems to rely on other objects?)
|
||||
// Doesn't work {ACTOR_EN_POH, 2}, // Poe (composer Sharp) (Seems to rely on other objects?)
|
||||
// Doesn't work {ACTOR_EN_POH, 3}, // Poe (composer Flat) (Seems to rely on other objects?)
|
||||
// Doesn't work {ACTOR_EN_OKUTA, 0}, // Octorok (actor directly uses water box collision to handle hiding/popping
|
||||
// up) Doesn't work {ACTOR_EN_REEBA, 0}, // Leever (reliant on surface and also normally used in tandem with a
|
||||
// leever spawner, kills itself too quickly otherwise) Kinda doesn't work { ACTOR_EN_FD, 0 }, // Flare Dancer (jumps
|
||||
// out of bounds a lot, and possible cause of crashes because of spawning a ton of flame actors)
|
||||
};
|
||||
|
||||
static int enemiesToRandomize[] = {
|
||||
ACTOR_EN_ANUBICE_TAG, // Anubis
|
||||
ACTOR_EN_FIREFLY, // Keese (including fire/ice)
|
||||
ACTOR_EN_TEST, // Stalfos
|
||||
ACTOR_EN_TITE, // Tektite
|
||||
|
@ -161,7 +189,7 @@ static int enemiesToRandomize[] = {
|
|||
ACTOR_EN_OKUTA, // Octorok
|
||||
ACTOR_EN_WALLMAS, // Wallmaster
|
||||
ACTOR_EN_DODONGO, // Dodongo
|
||||
// ACTOR_EN_REEBA, // Leever (reliant on spawner (z_e_encount1.c)
|
||||
// ACTOR_EN_REEBA, // Leever (reliant on spawner (z_en_encount1.c))
|
||||
ACTOR_EN_PEEHAT, // Flying Peahat, big one spawning larva, larva
|
||||
ACTOR_EN_ZF, // Lizalfos, Dinolfos
|
||||
ACTOR_EN_GOMA, // Gohma Larva (normal, eggs, gohma eggs)
|
||||
|
@ -184,8 +212,7 @@ static int enemiesToRandomize[] = {
|
|||
ACTOR_EN_FLOORMAS, // Floormaster
|
||||
ACTOR_EN_RD, // Redead, Gibdo
|
||||
ACTOR_EN_SW, // Skullwalltula
|
||||
// ACTOR_EN_FD, // Flare Dancer (can be randomized, but not randomized to, so keeping it in vanilla locations
|
||||
// means it at least shows up in the game)
|
||||
ACTOR_EN_FD, // Flare Dancer
|
||||
ACTOR_EN_SB, // Shell Blade
|
||||
ACTOR_EN_KAREBABA, // Withered Deku Baba
|
||||
ACTOR_EN_RR, // Like-Like
|
||||
|
@ -198,6 +225,7 @@ static int enemiesToRandomize[] = {
|
|||
ACTOR_EN_WF, // Wolfos
|
||||
ACTOR_EN_SKB, // Stalchild
|
||||
ACTOR_EN_CROW, // Guay
|
||||
ACTOR_EN_SKJ, // Skull Kid
|
||||
};
|
||||
|
||||
extern "C" uint8_t GetRandomizedEnemy(PlayState* play, int16_t* actorId, f32* posX, f32* posY, f32* posZ, int16_t* rotX,
|
||||
|
@ -322,7 +350,7 @@ static std::vector<EnemyEntry> selectedEnemyList;
|
|||
|
||||
void GetSelectedEnemies() {
|
||||
selectedEnemyList.clear();
|
||||
for (int i = 0; i < 49; i++) {
|
||||
for (int i = 0; i < RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE; i++) {
|
||||
if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0)) {
|
||||
selectedEnemyList.push_back(randomizedEnemySpawnTable[i]);
|
||||
} else if (CVarGetInteger(enemyCVarList[i], 1)) {
|
||||
|
@ -408,6 +436,8 @@ bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId,
|
|||
case ACTOR_EN_SB:
|
||||
case ACTOR_EN_NY:
|
||||
return (!(!isMQ && sceneNum == SCENE_WATER_TEMPLE && roomNum == 2));
|
||||
case ACTOR_EN_SKJ:
|
||||
return !(sceneNum == SCENE_LOST_WOODS && LINK_IS_CHILD);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
@ -419,19 +449,19 @@ bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId,
|
|||
}
|
||||
|
||||
bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy) {
|
||||
|
||||
uint32_t isMQ = ResourceMgr_IsSceneMasterQuest(sceneNum);
|
||||
|
||||
// Freezard - Child Link can only kill this with jump slash Deku Sticks or other equipment like bombs.
|
||||
// Beamos - Needs bombs.
|
||||
// Anubis - Needs fire.
|
||||
// Shell Blade & Spike - Child Link can't kill these with sword or Deku Stick.
|
||||
// Arwing & Dark Link - Both go out of bounds way too easily, softlocking the player.
|
||||
// Flare dancer, Arwing & Dark Link - Both go out of bounds way too easily, softlocking the player.
|
||||
// Wallmaster - Not easily visible, often makes players think they're softlocked and that there's no enemies left.
|
||||
// Club Moblin - Many issues with them falling or placing out of bounds. Maybe fixable in the future?
|
||||
bool enemiesToExcludeClearRooms = enemy.id == ACTOR_EN_FZ || enemy.id == ACTOR_EN_VM || enemy.id == ACTOR_EN_SB ||
|
||||
enemy.id == ACTOR_EN_NY || enemy.id == ACTOR_EN_CLEAR_TAG ||
|
||||
enemy.id == ACTOR_EN_WALLMAS || enemy.id == ACTOR_EN_TORCH2 ||
|
||||
enemy.id == ACTOR_EN_MB;
|
||||
bool enemiesToExcludeClearRooms =
|
||||
enemy.id == ACTOR_EN_FZ || enemy.id == ACTOR_EN_VM || enemy.id == ACTOR_EN_SB || enemy.id == ACTOR_EN_NY ||
|
||||
enemy.id == ACTOR_EN_CLEAR_TAG || enemy.id == ACTOR_EN_WALLMAS || enemy.id == ACTOR_EN_TORCH2 ||
|
||||
(enemy.id == ACTOR_EN_MB && enemy.params == 0) || enemy.id == ACTOR_EN_FD || enemy.id == ACTOR_EN_ANUBICE_TAG;
|
||||
|
||||
// Bari - Spawns 3 more enemies, potentially extremely difficult in timed rooms.
|
||||
bool enemiesToExcludeTimedRooms = enemiesToExcludeClearRooms || enemy.id == ACTOR_EN_VALI;
|
||||
|
@ -532,3 +562,16 @@ bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy) {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void FixClubMoblinScale(void* ptr) {
|
||||
Actor* actor = (Actor*)ptr;
|
||||
if (actor->params == -1) {
|
||||
Actor_SetScale(actor, 0.014f);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterEnemyRandomizer() {
|
||||
COND_ID_HOOK(OnActorInit, ACTOR_EN_MB, CVAR_ENEMY_RANDOMIZER_VALUE, FixClubMoblinScale);
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(RegisterEnemyRandomizer, { CVAR_ENEMY_RANDOMIZER_NAME });
|
|
@ -1,23 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <libultraship/bridge.h>
|
||||
#include <libultraship/libultra/types.h>
|
||||
|
||||
typedef struct EnemyEntry {
|
||||
int16_t id;
|
||||
int16_t params;
|
||||
} EnemyEntry;
|
||||
|
||||
#define RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE 49
|
||||
|
||||
bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId, int16_t params, float posX);
|
||||
bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy);
|
||||
EnemyEntry GetRandomizedEnemyEntry(uint32_t seed);
|
||||
#define RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE 52
|
||||
|
||||
extern const char* enemyCVarList[];
|
||||
extern const char* enemyNameList[];
|
||||
extern void GetSelectedEnemies();
|
||||
|
||||
#ifndef __cplusplus
|
||||
uint8_t GetRandomizedEnemy(PlayState* play, int16_t* actorId, f32* posX, f32* posY, f32* posZ, int16_t* rotX,
|
||||
struct PlayState;
|
||||
|
||||
uint8_t GetRandomizedEnemy(struct PlayState* play, int16_t* actorId, f32* posX, f32* posY, f32* posZ, int16_t* rotX,
|
||||
int16_t* rotY, int16_t* rotZ, int16_t* params);
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,7 @@ DEFINE_HOOK(OnOcarinaSongAction, ());
|
|||
DEFINE_HOOK(OnCuccoOrChickenHatch, ());
|
||||
DEFINE_HOOK(OnShopSlotChange, (uint8_t cursorIndex, int16_t price));
|
||||
DEFINE_HOOK(OnActorInit, (void* actor));
|
||||
DEFINE_HOOK(OnActorSpawn, (void* actor));
|
||||
DEFINE_HOOK(OnActorUpdate, (void* actor));
|
||||
DEFINE_HOOK(OnActorKill, (void* actor));
|
||||
DEFINE_HOOK(OnActorDestroy, (void* actor));
|
||||
|
|
|
@ -108,6 +108,13 @@ void GameInteractor_ExecuteOnActorInit(void* actor) {
|
|||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnActorInit>(actor);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnActorSpawn(void* actor) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnActorSpawn>(actor);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnActorSpawn>(((Actor*)actor)->id, actor);
|
||||
GameInteractor::Instance->ExecuteHooksForPtr<GameInteractor::OnActorSpawn>((uintptr_t)actor, actor);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnActorSpawn>(actor);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnActorUpdate(void* actor) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnActorUpdate>(actor);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnActorUpdate>(((Actor*)actor)->id, actor);
|
||||
|
|
|
@ -29,6 +29,7 @@ void GameInteractor_ExecuteOnSetDoAction(uint16_t action);
|
|||
void GameInteractor_ExecuteOnOcarinaSongAction();
|
||||
void GameInteractor_ExecuteOnCuccoOrChickenHatch();
|
||||
void GameInteractor_ExecuteOnActorInit(void* actor);
|
||||
void GameInteractor_ExecuteOnActorSpawn(void* actor);
|
||||
void GameInteractor_ExecuteOnActorUpdate(void* actor);
|
||||
void GameInteractor_ExecuteOnActorKill(void* actor);
|
||||
void GameInteractor_ExecuteOnActorDestroy(void* actor);
|
||||
|
|
|
@ -20,6 +20,14 @@ typedef enum {
|
|||
// - `int32_t` (entrance index) (promoted from `uint16_t` by va_arg)
|
||||
VB_ALLOW_ENTRANCE_CS_FOR_EITHER_AGE,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// sBgPoEventPuzzleState == 0xF
|
||||
// ```
|
||||
// #### `args`
|
||||
// - None
|
||||
VB_AMY_SOLVE,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// this->actor.textId == 0x401A
|
||||
|
|
|
@ -134,31 +134,6 @@ void RegisterOcarinaTimeTravel() {
|
|||
});
|
||||
}
|
||||
|
||||
void RegisterRupeeDash() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerUpdate>([]() {
|
||||
if (!CVarGetInteger(CVAR_ENHANCEMENT("RupeeDash"), 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize Timer
|
||||
static uint16_t rupeeDashTimer = 0;
|
||||
uint16_t rdmTime = CVarGetInteger(CVAR_ENHANCEMENT("RupeeDashInterval"), 5) * 20;
|
||||
|
||||
// Did time change by DashInterval?
|
||||
if (rupeeDashTimer >= rdmTime) {
|
||||
rupeeDashTimer = 0;
|
||||
if (gSaveContext.rupees > 0) {
|
||||
uint16_t walletSize = (CUR_UPG_VALUE(UPG_WALLET) + 1) * -1;
|
||||
Rupees_ChangeBy(walletSize);
|
||||
} else {
|
||||
Health_ChangeBy(gPlayState, -16);
|
||||
}
|
||||
} else {
|
||||
rupeeDashTimer++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static bool hasAffectedHealth = false;
|
||||
void UpdatePermanentHeartLossState() {
|
||||
if (!GameInteractor::IsSaveLoaded())
|
||||
|
@ -982,7 +957,6 @@ void InitMods() {
|
|||
TimeSavers_Register();
|
||||
RegisterTTS();
|
||||
RegisterOcarinaTimeTravel();
|
||||
RegisterRupeeDash();
|
||||
RegisterPermanentHeartLoss();
|
||||
RegisterDeleteFileOnDeath();
|
||||
RegisterHyperBosses();
|
||||
|
|
|
@ -1015,7 +1015,8 @@ static void RandomizeOwnDungeon(const Rando::DungeonInfo* dungeon) {
|
|||
|
||||
// filter out locations that may be required to have songs placed at them
|
||||
dungeonLocations = FilterFromPool(dungeonLocations, [ctx](const auto loc) {
|
||||
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_SONG_LOCATIONS)) {
|
||||
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_SONG_LOCATIONS) ||
|
||||
ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_OFF)) {
|
||||
return !(Rando::StaticData::GetLocation(loc)->GetRCType() == RCTYPE_SONG_LOCATION);
|
||||
}
|
||||
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_DUNGEON_REWARDS)) {
|
||||
|
@ -1344,8 +1345,8 @@ int Fill() {
|
|||
|
||||
StartPerformanceTimer(PT_LIMITED_CHECKS);
|
||||
// Then Place songs if song shuffle is set to specific locations
|
||||
if (ctx->GetOption(RSK_SHUFFLE_SONGS).IsNot(RO_SONG_SHUFFLE_ANYWHERE)) {
|
||||
|
||||
if (ctx->GetOption(RSK_SHUFFLE_SONGS).IsNot(RO_SONG_SHUFFLE_ANYWHERE) &&
|
||||
ctx->GetOption(RSK_SHUFFLE_SONGS).IsNot(RO_SONG_SHUFFLE_OFF)) {
|
||||
// Get each song
|
||||
std::vector<RandomizerGet> songs = FilterAndEraseFromPool(ItemPool, [](const auto i) {
|
||||
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_SONG;
|
||||
|
|
|
@ -1133,12 +1133,27 @@ void GenerateItemPool() {
|
|||
}
|
||||
}
|
||||
|
||||
// add extra songs only if song shuffle is anywhere
|
||||
if (ctx->GetOption(RSK_SHUFFLE_SONGS).IsNot(RO_SONG_SHUFFLE_OFF)) {
|
||||
AddItemsToPool(ItemPool, songList);
|
||||
// add extra songs only if song shuffle is anywhere
|
||||
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_ANYWHERE) &&
|
||||
ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
|
||||
AddItemsToPool(PendingJunkPool, songList);
|
||||
}
|
||||
} else {
|
||||
ctx->PlaceItemInLocation(RC_SHEIK_IN_FOREST, RG_MINUET_OF_FOREST, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SHEIK_IN_CRATER, RG_BOLERO_OF_FIRE, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SHEIK_IN_ICE_CAVERN, RG_SERENADE_OF_WATER, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SHEIK_AT_COLOSSUS, RG_REQUIEM_OF_SPIRIT, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SHEIK_IN_KAKARIKO, RG_NOCTURNE_OF_SHADOW, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SHEIK_AT_TEMPLE, RG_PRELUDE_OF_LIGHT, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SONG_FROM_IMPA, RG_ZELDAS_LULLABY, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SONG_FROM_MALON, RG_EPONAS_SONG, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SONG_FROM_SARIA, RG_SARIAS_SONG, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SONG_FROM_ROYAL_FAMILYS_TOMB, RG_SUNS_SONG, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SONG_FROM_OCARINA_OF_TIME, RG_SONG_OF_TIME, false, true);
|
||||
ctx->PlaceItemInLocation(RC_SONG_FROM_WINDMILL, RG_SONG_OF_STORMS, false, true);
|
||||
}
|
||||
|
||||
/*For item pool generation, dungeon items are either placed in their vanilla
|
||||
| location, or added to the pool now and filtered out later depending on when
|
||||
|
|
|
@ -9,8 +9,6 @@ extern PlayState* gPlayState;
|
|||
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
|
||||
}
|
||||
|
||||
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
|
||||
|
||||
using SceneDoorParamsPair = std::pair<int, int>;
|
||||
std::map<SceneDoorParamsPair, RandomizerInf> lookupTable = {
|
||||
// clang-format off
|
||||
|
|
|
@ -11,8 +11,7 @@ extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play);
|
|||
void ObjComb_RandomizerChooseItemDrop(ObjComb* objComb, PlayState* play) {
|
||||
s16 params = objComb->actor.params & 0x1F;
|
||||
|
||||
if (Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_BEEHIVES).Get() &&
|
||||
!Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
|
||||
if (RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES) && !Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
|
||||
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &objComb->actor.world.pos, ITEM00_SOH_DUMMY);
|
||||
item00->randoInf = objComb->beehiveIdentity.randomizerInf;
|
||||
item00->itemEntry =
|
||||
|
@ -41,8 +40,7 @@ void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
|
|||
s32 dmgFlags;
|
||||
|
||||
objComb->unk_1B0 -= 50;
|
||||
if (Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_BEEHIVES).Get() &&
|
||||
!Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
|
||||
if (RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES) && !Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
|
||||
if (objComb->unk_1B0 <= -5000) {
|
||||
objComb->unk_1B0 = 1500;
|
||||
}
|
||||
|
@ -85,7 +83,7 @@ void ObjComb_RandomizerUpdate(void* actor) {
|
|||
}
|
||||
|
||||
void RegisterShuffleBeehives() {
|
||||
bool shouldRegister = IS_RANDO && Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_BEEHIVES).Get();
|
||||
bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES);
|
||||
|
||||
COND_ID_HOOK(OnActorInit, ACTOR_OBJ_COMB, shouldRegister, ObjComb_RandomizerInit);
|
||||
COND_ID_HOOK(OnActorUpdate, ACTOR_OBJ_COMB, shouldRegister, ObjComb_RandomizerUpdate);
|
||||
|
|
|
@ -34,7 +34,7 @@ void EnCow_MoveForRandomizer(EnCow* enCow, PlayState* play) {
|
|||
}
|
||||
|
||||
void RegisterShuffleCows() {
|
||||
bool shouldRegister = IS_RANDO && Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_COWS).Get();
|
||||
bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_COWS);
|
||||
|
||||
COND_VB_SHOULD(VB_GIVE_ITEM_FROM_COW, shouldRegister, {
|
||||
EnCow* enCow = va_arg(args, EnCow*);
|
||||
|
|
|
@ -15,8 +15,6 @@ extern "C" {
|
|||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
|
||||
|
||||
extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play);
|
||||
|
||||
extern "C" void ObjKibako2_RandomizerDraw(Actor* thisx, PlayState* play) {
|
||||
|
@ -158,7 +156,7 @@ extern "C" void ObjKibako_RandomizerDraw(Actor* thisx, PlayState* play) {
|
|||
uint8_t ObjKibako2_RandomizerHoldsItem(ObjKibako2* crateActor, PlayState* play) {
|
||||
RandomizerCheck rc = crateActor->crateIdentity.randomizerCheck;
|
||||
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
||||
uint8_t crateSetting = Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_CRATES).Get();
|
||||
uint8_t crateSetting = RAND_GET_OPTION(RSK_SHUFFLE_CRATES);
|
||||
|
||||
// Don't pull randomized item if crate isn't randomized or is already checked
|
||||
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
|
||||
|
@ -174,7 +172,7 @@ uint8_t ObjKibako2_RandomizerHoldsItem(ObjKibako2* crateActor, PlayState* play)
|
|||
uint8_t ObjKibako_RandomizerHoldsItem(ObjKibako* smallCrateActor, PlayState* play) {
|
||||
RandomizerCheck rc = smallCrateActor->smallCrateIdentity.randomizerCheck;
|
||||
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
||||
uint8_t crateSetting = Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_CRATES).Get();
|
||||
uint8_t crateSetting = RAND_GET_OPTION(RSK_SHUFFLE_CRATES);
|
||||
|
||||
// Don't pull randomized item if crate isn't randomized or is already checked
|
||||
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
|
||||
|
@ -211,7 +209,7 @@ void ObjKibako_RandomizerSpawnCollectible(ObjKibako* smallCrateActor, PlayState*
|
|||
|
||||
void ObjKibako2_RandomizerInit(void* actorRef) {
|
||||
Actor* actor = static_cast<Actor*>(actorRef);
|
||||
uint8_t logicSetting = Rando::Context::GetInstance()->GetOption(RSK_LOGIC_RULES).Get();
|
||||
uint8_t logicSetting = RAND_GET_OPTION(RSK_LOGIC_RULES);
|
||||
|
||||
// don't shuffle two OOB crates in GF and don't shuffle child GV/GF crates when not in no logic
|
||||
if (actor->id != ACTOR_OBJ_KIBAKO2 ||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <z64.h>
|
||||
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
|
||||
#include "randomizer_inf.h"
|
||||
#include "randomizerTypes.h"
|
||||
|
||||
typedef struct FairyIdentity {
|
||||
RandomizerInf randomizerInf;
|
||||
|
|
|
@ -23,7 +23,7 @@ void ShuffleFreestanding_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* sh
|
|||
Rando::Location* loc =
|
||||
OTRGlobals::Instance->gRandomizer->GetCheckObjectFromActor(item00->actor.id, gPlayState->sceneNum, params);
|
||||
uint8_t isDungeon = loc->IsDungeon();
|
||||
uint8_t freestandingSetting = Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_FREESTANDING).Get();
|
||||
uint8_t freestandingSetting = RAND_GET_OPTION(RSK_SHUFFLE_FREESTANDING);
|
||||
RandomizerCheck randomizerCheck = loc->GetRandomizerCheck();
|
||||
bool checkObtained = Rando::Context::GetInstance()->GetItemLocation(randomizerCheck)->HasObtained();
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@ extern "C" {
|
|||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
|
||||
|
||||
extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play);
|
||||
|
||||
void DrawTypeOfGrass(EnKusa* grassActor, Gfx* bushDList, Gfx* grassDList, PlayState* play) {
|
||||
|
@ -96,7 +94,7 @@ uint8_t EnKusa_RandomizerHoldsItem(EnKusa* grassActor, PlayState* play) {
|
|||
RandomizerCheck rc = grassActor->grassIdentity.randomizerCheck;
|
||||
|
||||
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
||||
uint8_t grassSetting = Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_GRASS).Get();
|
||||
uint8_t grassSetting = RAND_GET_OPTION(RSK_SHUFFLE_GRASS);
|
||||
|
||||
// Don't pull randomized item if grass isn't randomized or is already checked
|
||||
if (!IS_RANDO || (grassSetting == RO_SHUFFLE_GRASS_OVERWORLD && isDungeon) ||
|
||||
|
|
|
@ -27,7 +27,7 @@ extern "C" void ObjTsubo_RandomizerDraw(Actor* thisx, PlayState* play) {
|
|||
uint8_t ObjTsubo_RandomizerHoldsItem(ObjTsubo* potActor, PlayState* play) {
|
||||
RandomizerCheck rc = potActor->potIdentity.randomizerCheck;
|
||||
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
||||
uint8_t potSetting = Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_POTS).Get();
|
||||
uint8_t potSetting = RAND_GET_OPTION(RSK_SHUFFLE_POTS);
|
||||
|
||||
// Don't pull randomized item if pot isn't randomized or is already checked
|
||||
if (!IS_RANDO || (potSetting == RO_SHUFFLE_POTS_OVERWORLD && isDungeon) ||
|
||||
|
@ -85,7 +85,7 @@ void ShufflePots_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va
|
|||
// Unlock early Ganon's Boss Key doors to allow access to the pots there when pots are shuffled in dungeon
|
||||
if (id == VB_LOCK_BOSS_DOOR) {
|
||||
DoorShutter* doorActor = va_arg(args, DoorShutter*);
|
||||
uint8_t shufflePotSetting = Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_POTS).Get();
|
||||
uint8_t shufflePotSetting = RAND_GET_OPTION(RSK_SHUFFLE_POTS);
|
||||
if (gPlayState->sceneNum == SCENE_GANONS_TOWER && doorActor->dyna.actor.world.pos.y == 800 &&
|
||||
(shufflePotSetting == RO_SHUFFLE_POTS_DUNGEONS || shufflePotSetting == RO_SHUFFLE_POTS_ALL)) {
|
||||
*should = false;
|
||||
|
|
26
soh/soh/Enhancements/randomizer/ShuffleSongs.cpp
Normal file
26
soh/soh/Enhancements/randomizer/ShuffleSongs.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "soh/ShipInit.hpp"
|
||||
#include "location.h"
|
||||
#include "static_data.h"
|
||||
|
||||
void Rando::StaticData::RegisterSongLocations() {
|
||||
static bool registered = false;
|
||||
if (registered)
|
||||
return;
|
||||
registered = true;
|
||||
// clang-format off
|
||||
locationTable[RC_SHEIK_IN_FOREST] = Location::Base(RC_SHEIK_IN_FOREST, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_SACRED_FOREST_MEADOW, 0x00, "Sheik in Forest", "Sheik in Forest", RHT_SHEIK_IN_FOREST, RG_MINUET_OF_FOREST, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_MINUET_OF_FOREST), true);
|
||||
locationTable[RC_SHEIK_IN_CRATER] = Location::Base(RC_SHEIK_IN_CRATER, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_DEATH_MOUNTAIN_CRATER, 0x00, "Sheik in Crater", "Sheik in Crater", RHT_SHEIK_IN_CRATER, RG_BOLERO_OF_FIRE, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_BOLERO_OF_FIRE), true);
|
||||
locationTable[RC_SHEIK_IN_ICE_CAVERN] = Location::Base(RC_SHEIK_IN_ICE_CAVERN, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_ICE_CAVERN, 0x00, "Sheik in Ice Cavern", "Sheik in Ice Cavern", RHT_SHEIK_IN_ICE_CAVERN, RG_SERENADE_OF_WATER, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SERENADE_OF_WATER), true);
|
||||
locationTable[RC_SHEIK_AT_COLOSSUS] = Location::Base(RC_SHEIK_AT_COLOSSUS, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_DESERT_COLOSSUS, 0x00, "Sheik at Colossus", "Sheik at Colossus", RHT_SHEIK_AT_COLOSSUS, RG_REQUIEM_OF_SPIRIT, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_REQUIEM_OF_SPIRIT), true);
|
||||
locationTable[RC_SHEIK_IN_KAKARIKO] = Location::Base(RC_SHEIK_IN_KAKARIKO, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_KAKARIKO_VILLAGE, 0x00, "Sheik in Kakariko", "Sheik in Kakariko", RHT_SHEIK_IN_KAKARIKO, RG_NOCTURNE_OF_SHADOW, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_BONGO_BONGO_ESCAPED_FROM_WELL), true);
|
||||
locationTable[RC_SHEIK_AT_TEMPLE] = Location::Base(RC_SHEIK_AT_TEMPLE, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_TEMPLE_OF_TIME, 0x00, "Sheik at Temple", "Sheik at Temple", RHT_SHEIK_AT_TEMPLE, RG_PRELUDE_OF_LIGHT, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_PRELUDE_OF_LIGHT), true);
|
||||
locationTable[RC_SONG_FROM_IMPA] = Location::Base(RC_SONG_FROM_IMPA, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, RCAREA_HYRULE_CASTLE, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, "Song from Impa", "Song from Impa", RHT_SONG_FROM_IMPA, RG_ZELDAS_LULLABY, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_ZELDAS_LULLABY), true);
|
||||
locationTable[RC_SONG_FROM_MALON] = Location::Base(RC_SONG_FROM_MALON, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_LON_LON_RANCH, 0x00, "Song from Malon", "Song from Malon", RHT_SONG_FROM_MALON, RG_EPONAS_SONG, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LEARNED_EPONA_SONG), true);
|
||||
locationTable[RC_SONG_FROM_SARIA] = Location::Base(RC_SONG_FROM_SARIA, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_SACRED_FOREST_MEADOW, 0x00, "Song from Saria", "Song from Saria", RHT_SONG_FROM_SARIA, RG_SARIAS_SONG, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SARIAS_SONG), true);
|
||||
locationTable[RC_SONG_FROM_ROYAL_FAMILYS_TOMB] = Location::Base(RC_SONG_FROM_ROYAL_FAMILYS_TOMB, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_ROYAL_FAMILYS_TOMB, 0x00, "Song from Royal Family's Tomb", "Song from Royal Family's Tomb", RHT_SONG_FROM_ROYAL_FAMILYS_TOMB, RG_SUNS_SONG, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SUNS_SONG), true);
|
||||
locationTable[RC_SONG_FROM_OCARINA_OF_TIME] = Location::Base(RC_SONG_FROM_OCARINA_OF_TIME, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_HYRULE_FIELD, 0x00, "Song from Ocarina of Time", "Song from Ocarina of Time", RHT_SONG_FROM_OCARINA_OF_TIME, RG_SONG_OF_TIME, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SONG_OF_TIME), true);
|
||||
locationTable[RC_SONG_FROM_WINDMILL] = Location::Base(RC_SONG_FROM_WINDMILL, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, RCAREA_KAKARIKO_VILLAGE, ACTOR_ID_MAX, SCENE_WINDMILL_AND_DAMPES_GRAVE, 0x00, "Song from Windmill", "Song from Windmill", RHT_SONG_FROM_WINDMILL, RG_SONG_OF_STORMS, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SONG_OF_STORMS), true);
|
||||
// clang-format-on
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initSongLocations(Rando::StaticData::RegisterSongLocations);
|
|
@ -179,6 +179,7 @@ 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_SONG_LOCATION && mOptions[RSK_SHUFFLE_SONGS].Is(RO_SONG_SHUFFLE_OFF)) ||
|
||||
(location.GetRCType() == RCTYPE_COW && mOptions[RSK_SHUFFLE_COWS].Is(RO_GENERIC_OFF)) ||
|
||||
(location.GetRandomizerCheck() == RC_LH_HYRULE_LOACH &&
|
||||
mOptions[RSK_FISHSANITY].IsNot(RO_FISHSANITY_HYRULE_LOACH)) ||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <map>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
|
||||
|
||||
/**
|
||||
* @brief Singleton for storing and accessing dynamic Randomizer-related data
|
||||
*
|
||||
|
|
|
@ -15,10 +15,6 @@ extern SaveContext gSaveContext;
|
|||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
#define FSi OTRGlobals::Instance->gRandoContext->GetFishsanity()
|
||||
|
||||
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
|
||||
|
||||
/**
|
||||
* @brief Parallel list of pond fish checks for both ages
|
||||
*/
|
||||
|
@ -488,15 +484,15 @@ void Fishsanity::OnItemReceiveHandler(GetItemEntry itemEntry) {
|
|||
// C interface
|
||||
extern "C" {
|
||||
bool Randomizer_GetPondFishShuffled() {
|
||||
return FSi->GetPondFishShuffled();
|
||||
return Rando::Context::GetInstance()->GetFishsanity()->GetPondFishShuffled();
|
||||
}
|
||||
|
||||
bool Randomizer_GetOverworldFishShuffled() {
|
||||
return FSi->GetOverworldFishShuffled();
|
||||
return Rando::Context::GetInstance()->GetFishsanity()->GetOverworldFishShuffled();
|
||||
}
|
||||
|
||||
bool Randomizer_IsAdultPond() {
|
||||
return FSi->IsAdultPond();
|
||||
return Rando::Context::GetInstance()->GetFishsanity()->IsAdultPond();
|
||||
}
|
||||
|
||||
void Fishsanity_DrawEffShadow(Actor* actor, Lights* lights, PlayState* play) {
|
||||
|
|
|
@ -71,8 +71,6 @@ extern void EnGe1_Wait_Archery(EnGe1* enGe1, PlayState* play);
|
|||
extern void EnGe1_SetAnimationIdle(EnGe1* enGe1);
|
||||
}
|
||||
|
||||
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
|
||||
|
||||
bool LocMatchesQuest(Rando::Location loc) {
|
||||
if (loc.GetQuest() == RCQUEST_BOTH) {
|
||||
return true;
|
||||
|
@ -2144,7 +2142,7 @@ void RandomizerOnActorUpdateHandler(void* refActor) {
|
|||
shutterDoor->unk_16E = 0;
|
||||
}
|
||||
} else if (actor->id == ACTOR_DOOR_GERUDO) {
|
||||
DoorGerudo* gerudoDoor = (DoorGerudo*)actor;
|
||||
DoorGerudo* gerudoDoor = reinterpret_cast<DoorGerudo*>(actor);
|
||||
gerudoDoor->actionFunc = func_8099485C;
|
||||
gerudoDoor->dyna.actor.world.pos.y = gerudoDoor->dyna.actor.home.pos.y + 200.0f;
|
||||
}
|
||||
|
|
|
@ -828,20 +828,6 @@ void Rando::StaticData::InitLocationTable() {
|
|||
locationTable[RC_DMC_GREAT_FAIRY_REWARD] = Location::Base(RC_DMC_GREAT_FAIRY_REWARD, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_DEATH_MOUNTAIN_CRATER, ACTOR_BG_DY_YOSEIZO, SCENE_GREAT_FAIRYS_FOUNTAIN_MAGIC, 2, "Great Fairy Reward", RHT_DMC_GREAT_FAIRY_REWARD, RG_PROGRESSIVE_MAGIC_METER, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DMC_GREAT_FAIRY_REWARD), true);
|
||||
locationTable[RC_OGC_GREAT_FAIRY_REWARD] = Location::Base(RC_OGC_GREAT_FAIRY_REWARD, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_HYRULE_CASTLE, ACTOR_BG_DY_YOSEIZO, SCENE_GREAT_FAIRYS_FOUNTAIN_MAGIC, 3, "OGC Great Fairy Reward", "OGC Great Fairy Reward", RHT_OGC_GREAT_FAIRY_REWARD, RG_DOUBLE_DEFENSE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_OGC_GREAT_FAIRY_REWARD), true);
|
||||
|
||||
// Songs
|
||||
locationTable[RC_SHEIK_IN_FOREST] = Location::Base(RC_SHEIK_IN_FOREST, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_SACRED_FOREST_MEADOW, 0x00, "Sheik in Forest", "Sheik in Forest", RHT_SHEIK_IN_FOREST, RG_MINUET_OF_FOREST, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_MINUET_OF_FOREST), true);
|
||||
locationTable[RC_SHEIK_IN_CRATER] = Location::Base(RC_SHEIK_IN_CRATER, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_DEATH_MOUNTAIN_CRATER, 0x00, "Sheik in Crater", "Sheik in Crater", RHT_SHEIK_IN_CRATER, RG_BOLERO_OF_FIRE, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_BOLERO_OF_FIRE), true);
|
||||
locationTable[RC_SHEIK_IN_ICE_CAVERN] = Location::Base(RC_SHEIK_IN_ICE_CAVERN, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_ICE_CAVERN, 0x00, "Sheik in Ice Cavern", "Sheik in Ice Cavern", RHT_SHEIK_IN_ICE_CAVERN, RG_SERENADE_OF_WATER, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SERENADE_OF_WATER), true);
|
||||
locationTable[RC_SHEIK_AT_COLOSSUS] = Location::Base(RC_SHEIK_AT_COLOSSUS, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_DESERT_COLOSSUS, 0x00, "Sheik at Colossus", "Sheik at Colossus", RHT_SHEIK_AT_COLOSSUS, RG_REQUIEM_OF_SPIRIT, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_REQUIEM_OF_SPIRIT), true);
|
||||
locationTable[RC_SHEIK_IN_KAKARIKO] = Location::Base(RC_SHEIK_IN_KAKARIKO, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_KAKARIKO_VILLAGE, 0x00, "Sheik in Kakariko", "Sheik in Kakariko", RHT_SHEIK_IN_KAKARIKO, RG_NOCTURNE_OF_SHADOW, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_BONGO_BONGO_ESCAPED_FROM_WELL), true);
|
||||
locationTable[RC_SHEIK_AT_TEMPLE] = Location::Base(RC_SHEIK_AT_TEMPLE, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_TEMPLE_OF_TIME, 0x00, "Sheik at Temple", "Sheik at Temple", RHT_SHEIK_AT_TEMPLE, RG_PRELUDE_OF_LIGHT, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_PRELUDE_OF_LIGHT), true);
|
||||
locationTable[RC_SONG_FROM_IMPA] = Location::Base(RC_SONG_FROM_IMPA, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, RCAREA_HYRULE_CASTLE, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, "Song from Impa", "Song from Impa", RHT_SONG_FROM_IMPA, RG_ZELDAS_LULLABY, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_ZELDAS_LULLABY), true);
|
||||
locationTable[RC_SONG_FROM_MALON] = Location::Base(RC_SONG_FROM_MALON, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_LON_LON_RANCH, 0x00, "Song from Malon", "Song from Malon", RHT_SONG_FROM_MALON, RG_EPONAS_SONG, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LEARNED_EPONA_SONG), true);
|
||||
locationTable[RC_SONG_FROM_SARIA] = Location::Base(RC_SONG_FROM_SARIA, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_SACRED_FOREST_MEADOW, 0x00, "Song from Saria", "Song from Saria", RHT_SONG_FROM_SARIA, RG_SARIAS_SONG, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SARIAS_SONG), true);
|
||||
locationTable[RC_SONG_FROM_ROYAL_FAMILYS_TOMB] = Location::Base(RC_SONG_FROM_ROYAL_FAMILYS_TOMB, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_ROYAL_FAMILYS_TOMB, 0x00, "Song from Royal Family's Tomb", "Song from Royal Family's Tomb", RHT_SONG_FROM_ROYAL_FAMILYS_TOMB, RG_SUNS_SONG, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SUNS_SONG), true);
|
||||
locationTable[RC_SONG_FROM_OCARINA_OF_TIME] = Location::Base(RC_SONG_FROM_OCARINA_OF_TIME, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, ACTOR_ID_MAX, SCENE_HYRULE_FIELD, 0x00, "Song from Ocarina of Time", "Song from Ocarina of Time", RHT_SONG_FROM_OCARINA_OF_TIME, RG_SONG_OF_TIME, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SONG_OF_TIME), true);
|
||||
locationTable[RC_SONG_FROM_WINDMILL] = Location::Base(RC_SONG_FROM_WINDMILL, RCQUEST_BOTH, RCTYPE_SONG_LOCATION, RCAREA_KAKARIKO_VILLAGE, ACTOR_ID_MAX, SCENE_WINDMILL_AND_DAMPES_GRAVE, 0x00, "Song from Windmill", "Song from Windmill", RHT_SONG_FROM_WINDMILL, RG_SONG_OF_STORMS, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_LEARNED_SONG_OF_STORMS), true);
|
||||
|
||||
/*-------------------------------
|
||||
--- SHOPS ---
|
||||
8 6 2 4
|
||||
|
|
|
@ -196,6 +196,8 @@ void Settings::CreateOptionDescriptions() {
|
|||
mOptionDescriptions[RSK_MIX_INTERIOR_ENTRANCES] = "Interior entrances will be part of the mixed pool.";
|
||||
mOptionDescriptions[RSK_MIX_GROTTO_ENTRANCES] = "Grotto entrances will be part of the mixed pool.";
|
||||
mOptionDescriptions[RSK_SHUFFLE_SONGS] =
|
||||
"Off - Songs will appear at their vanilla locations.\n"
|
||||
"\n"
|
||||
"Song locations - Songs will only appear at locations that normally teach songs.\n"
|
||||
"\n"
|
||||
"Dungeon rewards - Songs appear after beating a major dungeon boss.\n"
|
||||
|
|
|
@ -4393,7 +4393,7 @@ CustomMessage Randomizer::GetFishingPondOwnerMessage(u16 originalTextId) {
|
|||
"fischen!",
|
||||
"Désolé, mais l'étang est fermé.&J'ai perdu ma bonne %rCanne à Pêche%w...&Impossible de pêcher sans elle!");
|
||||
|
||||
if (Rando::Context::GetInstance()->GetOption(RSK_FISHING_POLE_HINT)) {
|
||||
if (GetRandoSettingValue(RSK_FISHING_POLE_HINT)) {
|
||||
messageEntry = messageEntry + CustomMessage(ctx->GetHint(RH_FISHING_POLE)->GetHintMessage());
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include "z64item.h"
|
||||
#include "randomizer_inf.h"
|
||||
|
||||
#define MAX_TRICK_NAME_SIZE 50
|
||||
|
||||
|
@ -214,6 +213,15 @@ typedef enum {
|
|||
LOGIC_MAX
|
||||
} LogicVal;
|
||||
|
||||
#define DEFINE_RAND_INF(enum) enum,
|
||||
|
||||
typedef enum {
|
||||
#include "randomizer_inf.h"
|
||||
RAND_INF_MAX,
|
||||
} RandomizerInf;
|
||||
|
||||
#undef DEFINE_RAND_INF
|
||||
|
||||
typedef enum {
|
||||
RA_NONE,
|
||||
RA_LINKS_POCKET,
|
||||
|
@ -6166,6 +6174,7 @@ typedef enum {
|
|||
|
||||
// Song shuffle Settings (Song locations, Dungeon rewards, anywhere)
|
||||
typedef enum {
|
||||
RO_SONG_SHUFFLE_OFF,
|
||||
RO_SONG_SHUFFLE_SONG_LOCATIONS,
|
||||
RO_SONG_SHUFFLE_DUNGEON_REWARDS,
|
||||
RO_SONG_SHUFFLE_ANYWHERE,
|
||||
|
|
|
@ -137,8 +137,10 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
|
|||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), RO_SHUFFLE_MERCHANTS_OFF) !=
|
||||
RO_SHUFFLE_MERCHANTS_OFF) &&
|
||||
(location.GetRCType() != RCTYPE_SONG_LOCATION ||
|
||||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleSongs"), RO_SONG_SHUFFLE_SONG_LOCATIONS) !=
|
||||
RO_SONG_SHUFFLE_SONG_LOCATIONS &&
|
||||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleSongs"), RO_SONG_SHUFFLE_SONG_LOCATIONS) !=
|
||||
RO_SONG_SHUFFLE_SONG_LOCATIONS) && // song locations
|
||||
RO_SONG_SHUFFLE_OFF)) && // song locations
|
||||
((location.GetRCType() != RCTYPE_BOSS_HEART_OR_OTHER_REWARD &&
|
||||
location.GetRandomizerCheck() != RC_SONG_FROM_IMPA &&
|
||||
location.GetRandomizerCheck() != RC_SHEIK_IN_ICE_CAVERN) ||
|
||||
|
|
|
@ -51,6 +51,7 @@ bool showBeans;
|
|||
bool showScrubs;
|
||||
bool showMajorScrubs;
|
||||
bool showMerchants;
|
||||
bool showSongs;
|
||||
bool showBeehives;
|
||||
bool showCows;
|
||||
bool showOverworldFreestanding;
|
||||
|
@ -1306,6 +1307,9 @@ void LoadSettings() {
|
|||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) ==
|
||||
RO_SHUFFLE_MERCHANTS_ALL
|
||||
: true;
|
||||
showSongs = IS_RANDO
|
||||
? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SONGS) != RO_SONG_SHUFFLE_OFF
|
||||
: false;
|
||||
showBeehives = IS_RANDO
|
||||
? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BEEHIVES) == RO_GENERIC_YES
|
||||
: false;
|
||||
|
@ -1516,6 +1520,7 @@ bool IsCheckShuffled(RandomizerCheck rc) {
|
|||
(showMajorScrubs && (rc == RC_LW_DEKU_SCRUB_NEAR_BRIDGE || // The 3 scrubs that are always randomized
|
||||
rc == RC_HF_DEKU_SCRUB_GROTTO || rc == RC_LW_DEKU_SCRUB_GROTTO_FRONT))) &&
|
||||
(loc->GetRCType() != RCTYPE_MERCHANT || showMerchants) &&
|
||||
(loc->GetRCType() != RCTYPE_SONG_LOCATION || showSongs) &&
|
||||
(loc->GetRCType() != RCTYPE_BEEHIVE || showBeehives) &&
|
||||
(loc->GetRCType() != RCTYPE_OCARINA || showOcarinas) &&
|
||||
(loc->GetRCType() != RCTYPE_SKULL_TOKEN || alwaysShowGS ||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -177,7 +177,7 @@ void Settings::CreateOptions() {
|
|||
OPT_U8(RSK_MQ_GANONS_CASTLE, "Ganon's Castle Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsGanonsCastle"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA);
|
||||
OPT_U8(RSK_SHUFFLE_DUNGEON_REWARDS, "Shuffle Dungeon Rewards", {"Vanilla", "End of Dungeons", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleDungeonReward"), mOptionDescriptions[RSK_SHUFFLE_DUNGEON_REWARDS], WidgetType::Combobox, RO_DUNGEON_REWARDS_END_OF_DUNGEON);
|
||||
OPT_U8(RSK_LINKS_POCKET, "Link's Pocket", {"Dungeon Reward", "Advancement", "Anything", "Nothing"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LinksPocket"), "", WidgetType::Combobox, RO_LINKS_POCKET_DUNGEON_REWARD);
|
||||
OPT_U8(RSK_SHUFFLE_SONGS, "Shuffle Songs", {"Song Locations", "Dungeon Rewards", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleSongs"), mOptionDescriptions[RSK_SHUFFLE_SONGS], WidgetType::Combobox, RO_SONG_SHUFFLE_SONG_LOCATIONS);
|
||||
OPT_U8(RSK_SHUFFLE_SONGS, "Shuffle Songs", {"Off", "Song Locations", "Dungeon Rewards", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleSongs"), mOptionDescriptions[RSK_SHUFFLE_SONGS], WidgetType::Combobox, RO_SONG_SHUFFLE_SONG_LOCATIONS);
|
||||
OPT_U8(RSK_SHOPSANITY, "Shop Shuffle", {"Off", "Specific Count", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Shopsanity"), mOptionDescriptions[RSK_SHOPSANITY], WidgetType::Combobox, RO_SHOPSANITY_OFF);
|
||||
OPT_U8(RSK_SHOPSANITY_COUNT, "Shops Item Count", {NumOpts(0, 7/*8*/)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityCount"), mOptionDescriptions[RSK_SHOPSANITY_COUNT], WidgetType::Slider, 0, false, IMFLAG_NONE);
|
||||
OPT_U8(RSK_SHOPSANITY_PRICES, "Shops Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), mOptionDescriptions[RSK_SHOPSANITY_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE);
|
||||
|
|
|
@ -49,6 +49,7 @@ class StaticData {
|
|||
static std::vector<RandomizerCheck> GetPondFishLocations();
|
||||
static std::vector<RandomizerCheck> GetOverworldFishLocations();
|
||||
static std::vector<RandomizerCheck> GetOverworldFairyLocations();
|
||||
static void RegisterSongLocations();
|
||||
static void RegisterBeehiveLocations();
|
||||
static void RegisterCowLocations();
|
||||
static void RegisterFishLocations();
|
||||
|
|
|
@ -28,6 +28,7 @@ extern "C" {
|
|||
#include "src/overlays/actors/ovl_En_Daiku/z_en_daiku.h"
|
||||
#include "src/overlays/actors/ovl_Bg_Spot02_Objects/z_bg_spot02_objects.h"
|
||||
#include "src/overlays/actors/ovl_Bg_Spot03_Taki/z_bg_spot03_taki.h"
|
||||
#include "src/overlays/actors/ovl_Bg_Spot06_Objects/z_bg_spot06_objects.h"
|
||||
#include "src/overlays/actors/ovl_Bg_Hidan_Kousi/z_bg_hidan_kousi.h"
|
||||
#include "src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h"
|
||||
#include "src/overlays/actors/ovl_En_Dnt_Demo/z_en_dnt_demo.h"
|
||||
|
@ -49,8 +50,6 @@ extern void EnRu2_SetEncounterSwitchFlag(EnRu2* enRu2, PlayState* play);
|
|||
extern void EnDaiku_EscapeSuccess(EnDaiku* enDaiku, PlayState* play);
|
||||
}
|
||||
|
||||
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
|
||||
|
||||
void EnMa1_EndTeachSong(EnMa1* enMa1, PlayState* play) {
|
||||
if (Message_GetState(&gPlayState->msgCtx) == TEXT_STATE_CLOSING) {
|
||||
Flags_SetRandomizerInf(RAND_INF_LEARNED_EPONA_SONG);
|
||||
|
@ -1386,3 +1385,15 @@ void TimeSaverRegisterHooks() {
|
|||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>(TimeSaverOnItemReceiveHandler);
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterSkipWaterTempleGateDelay() {
|
||||
COND_ID_HOOK(OnActorUpdate, ACTOR_BG_SPOT06_OBJECTS,
|
||||
CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO), [](void* actor) {
|
||||
BgSpot06Objects* spot06 = static_cast<BgSpot06Objects*>(actor);
|
||||
if (spot06->dyna.actor.params == 0) {
|
||||
spot06->timer = 0;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc skipWaterTempleGateDelay(RegisterSkipWaterTempleGateDelay);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
|
|
@ -792,6 +792,11 @@ void SohMenu::AddMenuEnhancements() {
|
|||
.CVar(CVAR_ENHANCEMENT("FastFarores"))
|
||||
.Options(CheckboxOptions().Tooltip("Greatly decreases cast time of Farore's Wind magic spell."));
|
||||
|
||||
AddWidget(path, "Bottles", WIDGET_SEPARATOR_TEXT);
|
||||
AddWidget(path, "Rebottle Blue Fire", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_ENHANCEMENT("RebottleBlueFire"))
|
||||
.Options(CheckboxOptions().Tooltip("Blue Fire dropped from bottle can be bottled."));
|
||||
|
||||
// Fixes
|
||||
path.sidebarName = "Fixes";
|
||||
AddSidebarEntry("Enhancements", path.sidebarName, 3);
|
||||
|
@ -1307,6 +1312,11 @@ void SohMenu::AddMenuEnhancements() {
|
|||
.Format("%d notes")
|
||||
.Tooltip("Adjust the number of notes you need to play to end the third round."));
|
||||
|
||||
AddWidget(path, "Forest Temple", WIDGET_SEPARATOR_TEXT);
|
||||
AddWidget(path, "Solve Amy's Puzzle", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_ENHANCEMENT("SkipAmyPuzzle"))
|
||||
.Options(CheckboxOptions().Tooltip("Amy's block pushing puzzle instantly solved."));
|
||||
|
||||
path.column = SECTION_COLUMN_3;
|
||||
AddWidget(path, "Fishing", WIDGET_SEPARATOR_TEXT);
|
||||
AddWidget(path, "Customize Behavior##Fishing", WIDGET_CVAR_CHECKBOX)
|
||||
|
|
|
@ -3401,6 +3401,8 @@ Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 pos
|
|||
Actor_Init(actor, play);
|
||||
gSegments[6] = temp;
|
||||
|
||||
GameInteractor_ExecuteOnActorSpawn(actor);
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "z_bg_po_event.h"
|
||||
#include "objects/object_po_sisters/object_po_sisters.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#define FLAGS 0
|
||||
|
||||
|
@ -333,7 +335,7 @@ void BgPoEvent_BlockIdle(BgPoEvent* this, PlayState* play) {
|
|||
Player* player = GET_PLAYER(play);
|
||||
Actor* amy;
|
||||
|
||||
if (sBgPoEventPuzzleState == 0xF) {
|
||||
if (GameInteractor_Should(VB_AMY_SOLVE, sBgPoEventPuzzleState == 0xF)) {
|
||||
this->actionFunc = BgPoEvent_BlockSolved;
|
||||
if ((this->type == 0) && (this->index == 0)) {
|
||||
amy = Actor_Spawn(&play->actorCtx, play, ACTOR_EN_PO_SISTERS, this->dyna.actor.world.pos.x + 30.0f,
|
||||
|
|
|
@ -154,17 +154,6 @@ void EnFu_WaitChild(EnFu* this, PlayState* play) {
|
|||
}
|
||||
}
|
||||
|
||||
void GivePlayerRandoRewardSongOfStorms(EnFu* windmillGuy, PlayState* play, RandomizerCheck check) {
|
||||
if (windmillGuy->actor.parent != NULL && windmillGuy->actor.parent->id == GET_PLAYER(play)->actor.id &&
|
||||
!Flags_GetTreasure(play, 0x1F)) {
|
||||
Flags_SetTreasure(play, 0x1F);
|
||||
windmillGuy->actionFunc = func_80A1DBD4;
|
||||
} else if (!Flags_GetTreasure(play, 0x1F)) {
|
||||
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(check, RG_SONG_OF_STORMS);
|
||||
GiveItemEntryFromActor(&windmillGuy->actor, play, getItemEntry, 10000.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void func_80A1DB60(EnFu* this, PlayState* play) {
|
||||
if (play->csCtx.state == CS_STATE_IDLE) {
|
||||
this->actionFunc = EnFu_WaitAdult;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "z_en_skj.h"
|
||||
#include "overlays/actors/ovl_En_Skjneedle/z_en_skjneedle.h"
|
||||
#include "objects/object_skj/object_skj.h"
|
||||
#include "soh/Enhancements/enhancementTypes.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "soh/OTRGlobals.h"
|
||||
#include "soh/ResourceManagerHelpers.h"
|
||||
|
@ -404,7 +405,9 @@ void EnSkj_Init(Actor* thisx, PlayState* play2) {
|
|||
default:
|
||||
this->actor.params = type;
|
||||
if (((this->actor.params != 0) && (this->actor.params != 1)) && (this->actor.params != 2)) {
|
||||
if (INV_CONTENT(ITEM_TRADE_ADULT) < ITEM_SAW) {
|
||||
if (INV_CONTENT(ITEM_TRADE_ADULT) < ITEM_SAW &&
|
||||
CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), ENEMY_RANDOMIZER_OFF) ==
|
||||
ENEMY_RANDOMIZER_OFF) {
|
||||
Actor_Kill(&this->actor);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1374,6 +1374,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) {
|
|||
} else {
|
||||
defaultName = &emptyNameNES;
|
||||
}
|
||||
this->charPage = FS_CHAR_PAGE_HIRA; // Default to Hiragana Keyboard
|
||||
} else { // GAME_REGION_NTSC
|
||||
defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES;
|
||||
}
|
||||
|
@ -1575,6 +1576,7 @@ void FileChoose_UpdateRandomizerMenu(GameState* thisx) {
|
|||
} else {
|
||||
defaultName = &emptyNameNES;
|
||||
}
|
||||
this->charPage = FS_CHAR_PAGE_HIRA; // Default to Hiragana Keyboard
|
||||
} else { // GAME_REGION_NTSC
|
||||
defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue