Merge branch 'aManchipelago' into AddArchipelagoClientLib

This commit is contained in:
Jerom Venneker
2025-06-08 13:32:36 +02:00
21 changed files with 220 additions and 160 deletions

View 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") });

View File

@@ -10,8 +10,6 @@ extern "C" {
#include "variables.h" #include "variables.h"
} }
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
static bool sEnteredBlueWarp = false; static bool sEnteredBlueWarp = false;
/** /**

View File

@@ -13,15 +13,29 @@ extern "C" {
#include <z64.h> #include <z64.h>
} }
const char* enemyCVarList[] = { #define CVAR_ENEMY_RANDOMIZER_NAME CVAR_ENHANCEMENT("RandomizedEnemies")
CVAR_ENHANCEMENT("RandomizedEnemyList.Armos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Arwing"), #define CVAR_ENEMY_RANDOMIZER_DEFAULT ENEMY_RANDOMIZER_OFF
CVAR_ENHANCEMENT("RandomizedEnemyList.BabyDodongo"), CVAR_ENHANCEMENT("RandomizedEnemyList.Bari"), #define CVAR_ENEMY_RANDOMIZER_VALUE CVarGetInteger(CVAR_ENEMY_RANDOMIZER_NAME, CVAR_ENEMY_RANDOMIZER_DEFAULT)
CVAR_ENHANCEMENT("RandomizedEnemyList.Beamos"), CVAR_ENHANCEMENT("RandomizedEnemyList.BigSkulltula"),
CVAR_ENHANCEMENT("RandomizedEnemyList.BigStalchild"), CVAR_ENHANCEMENT("RandomizedEnemyList.Biri"), typedef struct EnemyEntry {
CVAR_ENHANCEMENT("RandomizedEnemyList.BlackKnuckle"), CVAR_ENHANCEMENT("RandomizedEnemyList.BlueTektite"), int16_t id;
CVAR_ENHANCEMENT("RandomizedEnemyList.Bubble"), CVAR_ENHANCEMENT("RandomizedEnemyList.ClubMoblin"), int16_t params;
CVAR_ENHANCEMENT("RandomizedEnemyList.DarkLink"), CVAR_ENHANCEMENT("RandomizedEnemyList.Dinolfos"), } EnemyEntry;
CVAR_ENHANCEMENT("RandomizedEnemyList.Dodongo"), CVAR_ENHANCEMENT("RandomizedEnemyList.FireKeese"),
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.FloorTile"), CVAR_ENHANCEMENT("RandomizedEnemyList.Floormaster"),
CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPeahat"), CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPot"), CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPeahat"), CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPot"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Freezard"), CVAR_ENHANCEMENT("RandomizedEnemyList.Gibdo"), 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.Keese"), CVAR_ENHANCEMENT("RandomizedEnemyList.LargeBaba"),
CVAR_ENHANCEMENT("RandomizedEnemyList.LikeLike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Lizalfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.LikeLike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Lizalfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.MadScrub"), CVAR_ENHANCEMENT("RandomizedEnemyList.NormalWolfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.MadScrub"), CVAR_ENHANCEMENT("RandomizedEnemyList.NormalWolfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.PeahatLarva"), CVAR_ENHANCEMENT("RandomizedEnemyList.Redead"), CVAR_ENHANCEMENT("RandomizedEnemyList.PeahatLarva"), /*CVAR_ENHANCEMENT("RandomizedEnemyList.Poe"),*/
CVAR_ENHANCEMENT("RandomizedEnemyList.RedTektite"), CVAR_ENHANCEMENT("RandomizedEnemyList.Shabom"), CVAR_ENHANCEMENT("RandomizedEnemyList.Redead"), CVAR_ENHANCEMENT("RandomizedEnemyList.RedTektite"),
CVAR_ENHANCEMENT("RandomizedEnemyList.ShellBlade"), CVAR_ENHANCEMENT("RandomizedEnemyList.Skulltula"), 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.SmallBaba"), CVAR_ENHANCEMENT("RandomizedEnemyList.SmallStalchild"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Spike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stalfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.SpearMoblin"), CVAR_ENHANCEMENT("RandomizedEnemyList.Spike"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Stinger"), CVAR_ENHANCEMENT("RandomizedEnemyList.Tailparasan"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stalfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stinger"),
CVAR_ENHANCEMENT("RandomizedEnemyList.TorchSlug"), CVAR_ENHANCEMENT("RandomizedEnemyList.Wallmaster"), CVAR_ENHANCEMENT("RandomizedEnemyList.Tailparasan"), CVAR_ENHANCEMENT("RandomizedEnemyList.TorchSlug"),
CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteKnuckle"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteWolfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Wallmaster"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteKnuckle"),
CVAR_ENHANCEMENT("RandomizedEnemyList.WitheredBaba"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteWolfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.WitheredBaba"),
}; };
const char* enemyNameList[] = { const char* enemyNameList[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
"Anubis",
"Armos", "Armos",
"Arwing", "Arwing",
"Baby Dodongo", "Baby Dodongo",
@@ -58,6 +74,7 @@ const char* enemyNameList[] = {
"Dinolfos", "Dinolfos",
"Dodongo", "Dodongo",
"Fire Keese", "Fire Keese",
//"Flare Dancer",
"Floor Tile", "Floor Tile",
"Floormaster", "Floormaster",
"Flying Peahat", "Flying Peahat",
@@ -75,13 +92,16 @@ const char* enemyNameList[] = {
"Mad Scrub", "Mad Scrub",
"Wolfos (Normal)", "Wolfos (Normal)",
"Peahat Larva", "Peahat Larva",
//"Poe",
"Redead", "Redead",
"Red Tektite", "Red Tektite",
"Shabom", "Shabom",
"Shell Blade", "Shell Blade",
"Skulltula", "Skulltula",
"Skull Kid",
"Small Deku Baba", "Small Deku Baba",
"Stalchild (Small)", "Stalchild (Small)",
"Spear Moblin",
"Spike", "Spike",
"Stalfos", "Stalfos",
"Stinger", "Stinger",
@@ -94,6 +114,7 @@ const char* enemyNameList[] = {
}; };
static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = { static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
{ ACTOR_EN_ANUBICE_TAG, 1 }, // Anubis
{ ACTOR_EN_AM, -1 }, // Armos { ACTOR_EN_AM, -1 }, // Armos
{ ACTOR_EN_CLEAR_TAG, 1 }, // Arwing { ACTOR_EN_CLEAR_TAG, 1 }, // Arwing
{ ACTOR_EN_DODOJR, 0 }, // Baby Dodongo { 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_IK, 2 }, // Iron Knuckle (black, standing)
{ ACTOR_EN_TITE, -2 }, // Tektite (blue) { ACTOR_EN_TITE, -2 }, // Tektite (blue)
{ ACTOR_EN_BB, -1 }, // Bubble (flying skull enemy) (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_TORCH2, 0 }, // Dark Link
{ ACTOR_EN_ZF, -2 }, // Dinolfos { ACTOR_EN_ZF, -2 }, // Dinolfos
{ ACTOR_EN_DODONGO, -1 }, // Dodongo { ACTOR_EN_DODONGO, -1 }, // Dodongo
{ ACTOR_EN_FIREFLY, 1 }, // Fire Keese { 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_YUKABYUN, 0 }, // Flying Floor Tile
{ ACTOR_EN_FLOORMAS, 0 }, // Floormaster { ACTOR_EN_FLOORMAS, 0 }, // Floormaster
{ ACTOR_EN_PEEHAT, -1 }, // Flying Peahat (big grounded, doesn't spawn larva) { 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_ST, 2 }, // Skulltula (invisible)
{ ACTOR_EN_FIREFLY, 2 }, // Regular Keese { ACTOR_EN_FIREFLY, 2 }, // Regular Keese
{ ACTOR_EN_DEKUBABA, 1 }, // Deku Baba (large) { 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_RR, 0 }, // Like-Like
{ ACTOR_EN_ZF, -1 }, // Lizalfos { ACTOR_EN_ZF, -1 }, // Lizalfos
{ ACTOR_EN_DEKUNUTS, 768 }, // Mad Scrub (triple attack) (projectiles don't work) { ACTOR_EN_DEKUNUTS, 768 }, // Mad Scrub (triple attack) (projectiles don't work)
{ ACTOR_EN_WF, 0 }, // Wolfos (normal) { 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 { 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_RD, 1 }, // Redead (standing)
{ ACTOR_EN_TITE, -1 }, // Tektite (red) { ACTOR_EN_TITE, -1 }, // Tektite (red)
{ ACTOR_EN_BUBBLE, 0 }, // Shabom (bubble) { ACTOR_EN_BUBBLE, 0 }, // Shabom (bubble)
{ ACTOR_EN_SB, 0 }, // Shell Blade { ACTOR_EN_SB, 0 }, // Shell Blade
{ ACTOR_EN_ST, 0 }, // Skulltula (normal) { ACTOR_EN_ST, 0 }, // Skulltula (normal)
{ ACTOR_EN_SKJ, 4159 }, // Skull Kid
{ ACTOR_EN_DEKUBABA, 0 }, // Deku Baba (small) { ACTOR_EN_DEKUBABA, 0 }, // Deku Baba (small)
{ ACTOR_EN_SKB, 1 }, // Stalchild (small) { ACTOR_EN_SKB, 1 }, // Stalchild (small)
{ ACTOR_EN_MB, -1 }, // Spear Moblin
{ ACTOR_EN_NY, 0 }, // Spike (rolling enemy) { ACTOR_EN_NY, 0 }, // Spike (rolling enemy)
{ ACTOR_EN_TEST, 2 }, // Stalfos { ACTOR_EN_TEST, 2 }, // Stalfos
{ ACTOR_EN_EIYER, 10 }, // Stinger (land) (One in formation, sink under floor and do not activate) { 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_IK, 3 }, // Iron Knuckle (white, standing)
{ ACTOR_EN_WF, 1 }, // Wolfos (white) { ACTOR_EN_WF, 1 }, // Wolfos (white)
{ ACTOR_EN_KAREBABA, 0 }, // Withered Deku Baba { 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[] = { static int enemiesToRandomize[] = {
ACTOR_EN_ANUBICE_TAG, // Anubis
ACTOR_EN_FIREFLY, // Keese (including fire/ice) ACTOR_EN_FIREFLY, // Keese (including fire/ice)
ACTOR_EN_TEST, // Stalfos ACTOR_EN_TEST, // Stalfos
ACTOR_EN_TITE, // Tektite ACTOR_EN_TITE, // Tektite
@@ -161,7 +189,7 @@ static int enemiesToRandomize[] = {
ACTOR_EN_OKUTA, // Octorok ACTOR_EN_OKUTA, // Octorok
ACTOR_EN_WALLMAS, // Wallmaster ACTOR_EN_WALLMAS, // Wallmaster
ACTOR_EN_DODONGO, // Dodongo 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_PEEHAT, // Flying Peahat, big one spawning larva, larva
ACTOR_EN_ZF, // Lizalfos, Dinolfos ACTOR_EN_ZF, // Lizalfos, Dinolfos
ACTOR_EN_GOMA, // Gohma Larva (normal, eggs, gohma eggs) ACTOR_EN_GOMA, // Gohma Larva (normal, eggs, gohma eggs)
@@ -184,8 +212,7 @@ static int enemiesToRandomize[] = {
ACTOR_EN_FLOORMAS, // Floormaster ACTOR_EN_FLOORMAS, // Floormaster
ACTOR_EN_RD, // Redead, Gibdo ACTOR_EN_RD, // Redead, Gibdo
ACTOR_EN_SW, // Skullwalltula ACTOR_EN_SW, // Skullwalltula
// ACTOR_EN_FD, // Flare Dancer (can be randomized, but not randomized to, so keeping it in vanilla locations ACTOR_EN_FD, // Flare Dancer
// means it at least shows up in the game)
ACTOR_EN_SB, // Shell Blade ACTOR_EN_SB, // Shell Blade
ACTOR_EN_KAREBABA, // Withered Deku Baba ACTOR_EN_KAREBABA, // Withered Deku Baba
ACTOR_EN_RR, // Like-Like ACTOR_EN_RR, // Like-Like
@@ -198,6 +225,7 @@ static int enemiesToRandomize[] = {
ACTOR_EN_WF, // Wolfos ACTOR_EN_WF, // Wolfos
ACTOR_EN_SKB, // Stalchild ACTOR_EN_SKB, // Stalchild
ACTOR_EN_CROW, // Guay 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, 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() { void GetSelectedEnemies() {
selectedEnemyList.clear(); 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)) { if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0)) {
selectedEnemyList.push_back(randomizedEnemySpawnTable[i]); selectedEnemyList.push_back(randomizedEnemySpawnTable[i]);
} else if (CVarGetInteger(enemyCVarList[i], 1)) { } 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_SB:
case ACTOR_EN_NY: case ACTOR_EN_NY:
return (!(!isMQ && sceneNum == SCENE_WATER_TEMPLE && roomNum == 2)); return (!(!isMQ && sceneNum == SCENE_WATER_TEMPLE && roomNum == 2));
case ACTOR_EN_SKJ:
return !(sceneNum == SCENE_LOST_WOODS && LINK_IS_CHILD);
default: default:
return 1; 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) { bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy) {
uint32_t isMQ = ResourceMgr_IsSceneMasterQuest(sceneNum); uint32_t isMQ = ResourceMgr_IsSceneMasterQuest(sceneNum);
// Freezard - Child Link can only kill this with jump slash Deku Sticks or other equipment like bombs. // Freezard - Child Link can only kill this with jump slash Deku Sticks or other equipment like bombs.
// Beamos - Needs bombs. // Beamos - Needs bombs.
// Anubis - Needs fire.
// Shell Blade & Spike - Child Link can't kill these with sword or Deku Stick. // 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. // 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? // 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 || bool enemiesToExcludeClearRooms =
enemy.id == ACTOR_EN_NY || enemy.id == ACTOR_EN_CLEAR_TAG || enemy.id == ACTOR_EN_FZ || enemy.id == ACTOR_EN_VM || enemy.id == ACTOR_EN_SB || enemy.id == ACTOR_EN_NY ||
enemy.id == ACTOR_EN_WALLMAS || enemy.id == ACTOR_EN_TORCH2 || enemy.id == ACTOR_EN_CLEAR_TAG || enemy.id == ACTOR_EN_WALLMAS || enemy.id == ACTOR_EN_TORCH2 ||
enemy.id == ACTOR_EN_MB; (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. // Bari - Spawns 3 more enemies, potentially extremely difficult in timed rooms.
bool enemiesToExcludeTimedRooms = enemiesToExcludeClearRooms || enemy.id == ACTOR_EN_VALI; bool enemiesToExcludeTimedRooms = enemiesToExcludeClearRooms || enemy.id == ACTOR_EN_VALI;
@@ -532,3 +562,16 @@ bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy) {
return 1; 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 });

View File

@@ -1,23 +1,16 @@
#pragma once #pragma once
#include <libultraship/bridge.h> #include <libultraship/libultra/types.h>
typedef struct EnemyEntry { #define RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE 52
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);
extern const char* enemyCVarList[]; extern const char* enemyCVarList[];
extern const char* enemyNameList[]; extern const char* enemyNameList[];
extern void GetSelectedEnemies(); extern void GetSelectedEnemies();
#ifndef __cplusplus #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); int16_t* rotY, int16_t* rotZ, int16_t* params);
#endif #endif

View File

@@ -20,6 +20,14 @@ typedef enum {
// - `int32_t` (entrance index) (promoted from `uint16_t` by va_arg) // - `int32_t` (entrance index) (promoted from `uint16_t` by va_arg)
VB_ALLOW_ENTRANCE_CS_FOR_EITHER_AGE, VB_ALLOW_ENTRANCE_CS_FOR_EITHER_AGE,
// #### `result`
// ```c
// sBgPoEventPuzzleState == 0xF
// ```
// #### `args`
// - None
VB_AMY_SOLVE,
// #### `result` // #### `result`
// ```c // ```c
// this->actor.textId == 0x401A // this->actor.textId == 0x401A

View File

@@ -9,8 +9,6 @@ extern PlayState* gPlayState;
#include "src/overlays/actors/ovl_En_Door/z_en_door.h" #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>; using SceneDoorParamsPair = std::pair<int, int>;
std::map<SceneDoorParamsPair, RandomizerInf> lookupTable = { std::map<SceneDoorParamsPair, RandomizerInf> lookupTable = {
// clang-format off // clang-format off

View File

@@ -11,8 +11,7 @@ extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play);
void ObjComb_RandomizerChooseItemDrop(ObjComb* objComb, PlayState* play) { void ObjComb_RandomizerChooseItemDrop(ObjComb* objComb, PlayState* play) {
s16 params = objComb->actor.params & 0x1F; s16 params = objComb->actor.params & 0x1F;
if (Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_BEEHIVES).Get() && if (RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES) && !Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
!Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &objComb->actor.world.pos, ITEM00_SOH_DUMMY); EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &objComb->actor.world.pos, ITEM00_SOH_DUMMY);
item00->randoInf = objComb->beehiveIdentity.randomizerInf; item00->randoInf = objComb->beehiveIdentity.randomizerInf;
item00->itemEntry = item00->itemEntry =
@@ -41,8 +40,7 @@ void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
s32 dmgFlags; s32 dmgFlags;
objComb->unk_1B0 -= 50; objComb->unk_1B0 -= 50;
if (Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_BEEHIVES).Get() && if (RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES) && !Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
!Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
if (objComb->unk_1B0 <= -5000) { if (objComb->unk_1B0 <= -5000) {
objComb->unk_1B0 = 1500; objComb->unk_1B0 = 1500;
} }
@@ -85,7 +83,7 @@ void ObjComb_RandomizerUpdate(void* actor) {
} }
void RegisterShuffleBeehives() { 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(OnActorInit, ACTOR_OBJ_COMB, shouldRegister, ObjComb_RandomizerInit);
COND_ID_HOOK(OnActorUpdate, ACTOR_OBJ_COMB, shouldRegister, ObjComb_RandomizerUpdate); COND_ID_HOOK(OnActorUpdate, ACTOR_OBJ_COMB, shouldRegister, ObjComb_RandomizerUpdate);

View File

@@ -34,7 +34,7 @@ void EnCow_MoveForRandomizer(EnCow* enCow, PlayState* play) {
} }
void RegisterShuffleCows() { 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, { COND_VB_SHOULD(VB_GIVE_ITEM_FROM_COW, shouldRegister, {
EnCow* enCow = va_arg(args, EnCow*); EnCow* enCow = va_arg(args, EnCow*);

View File

@@ -15,8 +15,6 @@ extern "C" {
extern PlayState* gPlayState; extern PlayState* gPlayState;
} }
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play); extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play);
extern "C" void ObjKibako2_RandomizerDraw(Actor* thisx, 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) { uint8_t ObjKibako2_RandomizerHoldsItem(ObjKibako2* crateActor, PlayState* play) {
RandomizerCheck rc = crateActor->crateIdentity.randomizerCheck; RandomizerCheck rc = crateActor->crateIdentity.randomizerCheck;
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon(); 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 // Don't pull randomized item if crate isn't randomized or is already checked
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) || 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) { uint8_t ObjKibako_RandomizerHoldsItem(ObjKibako* smallCrateActor, PlayState* play) {
RandomizerCheck rc = smallCrateActor->smallCrateIdentity.randomizerCheck; RandomizerCheck rc = smallCrateActor->smallCrateIdentity.randomizerCheck;
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon(); 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 // Don't pull randomized item if crate isn't randomized or is already checked
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) || if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
@@ -211,7 +209,7 @@ void ObjKibako_RandomizerSpawnCollectible(ObjKibako* smallCrateActor, PlayState*
void ObjKibako2_RandomizerInit(void* actorRef) { void ObjKibako2_RandomizerInit(void* actorRef) {
Actor* actor = static_cast<Actor*>(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 // 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 || if (actor->id != ACTOR_OBJ_KIBAKO2 ||

View File

@@ -23,7 +23,7 @@ void ShuffleFreestanding_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* sh
Rando::Location* loc = Rando::Location* loc =
OTRGlobals::Instance->gRandomizer->GetCheckObjectFromActor(item00->actor.id, gPlayState->sceneNum, params); OTRGlobals::Instance->gRandomizer->GetCheckObjectFromActor(item00->actor.id, gPlayState->sceneNum, params);
uint8_t isDungeon = loc->IsDungeon(); 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(); RandomizerCheck randomizerCheck = loc->GetRandomizerCheck();
bool checkObtained = Rando::Context::GetInstance()->GetItemLocation(randomizerCheck)->HasObtained(); bool checkObtained = Rando::Context::GetInstance()->GetItemLocation(randomizerCheck)->HasObtained();

View File

@@ -11,8 +11,6 @@ extern "C" {
extern PlayState* gPlayState; extern PlayState* gPlayState;
} }
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play); extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play);
void DrawTypeOfGrass(EnKusa* grassActor, Gfx* bushDList, Gfx* grassDList, 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; RandomizerCheck rc = grassActor->grassIdentity.randomizerCheck;
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon(); 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 // Don't pull randomized item if grass isn't randomized or is already checked
if (!IS_RANDO || (grassSetting == RO_SHUFFLE_GRASS_OVERWORLD && isDungeon) || if (!IS_RANDO || (grassSetting == RO_SHUFFLE_GRASS_OVERWORLD && isDungeon) ||

View File

@@ -27,7 +27,7 @@ extern "C" void ObjTsubo_RandomizerDraw(Actor* thisx, PlayState* play) {
uint8_t ObjTsubo_RandomizerHoldsItem(ObjTsubo* potActor, PlayState* play) { uint8_t ObjTsubo_RandomizerHoldsItem(ObjTsubo* potActor, PlayState* play) {
RandomizerCheck rc = potActor->potIdentity.randomizerCheck; RandomizerCheck rc = potActor->potIdentity.randomizerCheck;
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon(); 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 // Don't pull randomized item if pot isn't randomized or is already checked
if (!IS_RANDO || (potSetting == RO_SHUFFLE_POTS_OVERWORLD && isDungeon) || 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 // 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) { if (id == VB_LOCK_BOSS_DOOR) {
DoorShutter* doorActor = va_arg(args, DoorShutter*); 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 && if (gPlayState->sceneNum == SCENE_GANONS_TOWER && doorActor->dyna.actor.world.pos.y == 800 &&
(shufflePotSetting == RO_SHUFFLE_POTS_DUNGEONS || shufflePotSetting == RO_SHUFFLE_POTS_ALL)) { (shufflePotSetting == RO_SHUFFLE_POTS_DUNGEONS || shufflePotSetting == RO_SHUFFLE_POTS_ALL)) {
*should = false; *should = false;

View File

@@ -15,6 +15,7 @@
#include <map> #include <map>
#include <nlohmann/json.hpp> #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 * @brief Singleton for storing and accessing dynamic Randomizer-related data

View File

@@ -15,10 +15,6 @@ extern SaveContext gSaveContext;
extern PlayState* gPlayState; 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 * @brief Parallel list of pond fish checks for both ages
*/ */
@@ -488,15 +484,15 @@ void Fishsanity::OnItemReceiveHandler(GetItemEntry itemEntry) {
// C interface // C interface
extern "C" { extern "C" {
bool Randomizer_GetPondFishShuffled() { bool Randomizer_GetPondFishShuffled() {
return FSi->GetPondFishShuffled(); return Rando::Context::GetInstance()->GetFishsanity()->GetPondFishShuffled();
} }
bool Randomizer_GetOverworldFishShuffled() { bool Randomizer_GetOverworldFishShuffled() {
return FSi->GetOverworldFishShuffled(); return Rando::Context::GetInstance()->GetFishsanity()->GetOverworldFishShuffled();
} }
bool Randomizer_IsAdultPond() { bool Randomizer_IsAdultPond() {
return FSi->IsAdultPond(); return Rando::Context::GetInstance()->GetFishsanity()->IsAdultPond();
} }
void Fishsanity_DrawEffShadow(Actor* actor, Lights* lights, PlayState* play) { void Fishsanity_DrawEffShadow(Actor* actor, Lights* lights, PlayState* play) {

View File

@@ -72,8 +72,6 @@ extern void EnGe1_Wait_Archery(EnGe1* enGe1, PlayState* play);
extern void EnGe1_SetAnimationIdle(EnGe1* enGe1); extern void EnGe1_SetAnimationIdle(EnGe1* enGe1);
} }
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get()
bool LocMatchesQuest(Rando::Location loc) { bool LocMatchesQuest(Rando::Location loc) {
if (loc.GetQuest() == RCQUEST_BOTH) { if (loc.GetQuest() == RCQUEST_BOTH) {
return true; return true;
@@ -2225,7 +2223,7 @@ void RandomizerOnActorUpdateHandler(void* refActor) {
shutterDoor->unk_16E = 0; shutterDoor->unk_16E = 0;
} }
} else if (actor->id == ACTOR_DOOR_GERUDO) { } else if (actor->id == ACTOR_DOOR_GERUDO) {
DoorGerudo* gerudoDoor = (DoorGerudo*)actor; DoorGerudo* gerudoDoor = reinterpret_cast<DoorGerudo*>(actor);
gerudoDoor->actionFunc = func_8099485C; gerudoDoor->actionFunc = func_8099485C;
gerudoDoor->dyna.actor.world.pos.y = gerudoDoor->dyna.actor.home.pos.y + 200.0f; gerudoDoor->dyna.actor.world.pos.y = gerudoDoor->dyna.actor.home.pos.y + 200.0f;
} }

View File

@@ -4398,7 +4398,7 @@ CustomMessage Randomizer::GetFishingPondOwnerMessage(u16 originalTextId) {
"fischen!", "fischen!",
"Désolé, mais l'étang est fermé.&J'ai perdu ma bonne %rCanne à Pêche%w...&Impossible de pêcher sans elle!"); "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()); messageEntry = messageEntry + CustomMessage(ctx->GetHint(RH_FISHING_POLE)->GetHintMessage());
} }

View File

@@ -28,6 +28,7 @@ extern "C" {
#include "src/overlays/actors/ovl_En_Daiku/z_en_daiku.h" #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_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_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_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_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h"
#include "src/overlays/actors/ovl_En_Dnt_Demo/z_en_dnt_demo.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); 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) { void EnMa1_EndTeachSong(EnMa1* enMa1, PlayState* play) {
if (Message_GetState(&gPlayState->msgCtx) == TEXT_STATE_CLOSING) { if (Message_GetState(&gPlayState->msgCtx) == TEXT_STATE_CLOSING) {
Flags_SetRandomizerInf(RAND_INF_LEARNED_EPONA_SONG); Flags_SetRandomizerInf(RAND_INF_LEARNED_EPONA_SONG);
@@ -1386,3 +1385,15 @@ void TimeSaverRegisterHooks() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>(TimeSaverOnItemReceiveHandler); 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);

View File

@@ -1312,6 +1312,11 @@ void SohMenu::AddMenuEnhancements() {
.Format("%d notes") .Format("%d notes")
.Tooltip("Adjust the number of notes you need to play to end the third round.")); .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; path.column = SECTION_COLUMN_3;
AddWidget(path, "Fishing", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Fishing", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Customize Behavior##Fishing", WIDGET_CVAR_CHECKBOX) AddWidget(path, "Customize Behavior##Fishing", WIDGET_CVAR_CHECKBOX)

View File

@@ -6,6 +6,8 @@
#include "z_bg_po_event.h" #include "z_bg_po_event.h"
#include "objects/object_po_sisters/object_po_sisters.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 #define FLAGS 0
@@ -333,7 +335,7 @@ void BgPoEvent_BlockIdle(BgPoEvent* this, PlayState* play) {
Player* player = GET_PLAYER(play); Player* player = GET_PLAYER(play);
Actor* amy; Actor* amy;
if (sBgPoEventPuzzleState == 0xF) { if (GameInteractor_Should(VB_AMY_SOLVE, sBgPoEventPuzzleState == 0xF)) {
this->actionFunc = BgPoEvent_BlockSolved; this->actionFunc = BgPoEvent_BlockSolved;
if ((this->type == 0) && (this->index == 0)) { 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, amy = Actor_Spawn(&play->actorCtx, play, ACTOR_EN_PO_SISTERS, this->dyna.actor.world.pos.x + 30.0f,

View File

@@ -1,6 +1,7 @@
#include "z_en_skj.h" #include "z_en_skj.h"
#include "overlays/actors/ovl_En_Skjneedle/z_en_skjneedle.h" #include "overlays/actors/ovl_En_Skjneedle/z_en_skjneedle.h"
#include "objects/object_skj/object_skj.h" #include "objects/object_skj/object_skj.h"
#include "soh/Enhancements/enhancementTypes.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/OTRGlobals.h" #include "soh/OTRGlobals.h"
#include "soh/ResourceManagerHelpers.h" #include "soh/ResourceManagerHelpers.h"
@@ -404,7 +405,9 @@ void EnSkj_Init(Actor* thisx, PlayState* play2) {
default: default:
this->actor.params = type; this->actor.params = type;
if (((this->actor.params != 0) && (this->actor.params != 1)) && (this->actor.params != 2)) { 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); Actor_Kill(&this->actor);
return; return;
} }

View File

@@ -1381,6 +1381,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) {
} else { } else {
defaultName = &emptyNameNES; defaultName = &emptyNameNES;
} }
this->charPage = FS_CHAR_PAGE_HIRA; // Default to Hiragana Keyboard
} else { // GAME_REGION_NTSC } else { // GAME_REGION_NTSC
defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES; defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES;
} }
@@ -1582,6 +1583,7 @@ void FileChoose_UpdateRandomizerMenu(GameState* thisx) {
} else { } else {
defaultName = &emptyNameNES; defaultName = &emptyNameNES;
} }
this->charPage = FS_CHAR_PAGE_HIRA; // Default to Hiragana Keyboard
} else { // GAME_REGION_NTSC } else { // GAME_REGION_NTSC
defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES; defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES;
} }