mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-02-23 06:02:08 -05:00
Merge remote-tracking branch 'upstream/rando-next' into bombchu-logic
This commit is contained in:
commit
ea9db56914
@ -87,6 +87,7 @@ set(Source_Files__Controller
|
||||
"KeyboardController.cpp"
|
||||
"KeyboardController.h"
|
||||
"UltraController.h"
|
||||
"DummyController.cpp"
|
||||
"DummyController.h"
|
||||
)
|
||||
|
||||
|
@ -389,4 +389,20 @@ namespace Ship {
|
||||
Commands[command] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Console::GetCurrentChannel() {
|
||||
return currentChannel;
|
||||
}
|
||||
|
||||
bool Console::IsOpened() {
|
||||
return opened;
|
||||
}
|
||||
|
||||
void Console::Close() {
|
||||
opened = false;
|
||||
}
|
||||
|
||||
void Console::Open() {
|
||||
opened = true;
|
||||
}
|
||||
}
|
@ -93,10 +93,9 @@ namespace Ship {
|
||||
void Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, ...);
|
||||
bool HasCommand(const std::string& command);
|
||||
void AddCommand(const std::string& command, CommandEntry entry);
|
||||
|
||||
std::string GetCurrentChannel() { return currentChannel; }
|
||||
bool IsOpened() { return opened; }
|
||||
void Close() { opened = false; }
|
||||
void Open() { opened = true; }
|
||||
std::string GetCurrentChannel();
|
||||
bool IsOpened();
|
||||
void Close();
|
||||
void Open();
|
||||
};
|
||||
}
|
@ -21,7 +21,7 @@ namespace Ship {
|
||||
size_t GetNumVirtualDevices();
|
||||
uint8_t* GetControllerBits();
|
||||
private:
|
||||
std::vector<int> virtualDevices = {};
|
||||
std::vector<int32_t> virtualDevices = {};
|
||||
std::vector<std::shared_ptr<Controller>> physicalDevices = {};
|
||||
uint8_t* controllerBits = nullptr;
|
||||
};
|
||||
|
@ -112,4 +112,16 @@ namespace Ship {
|
||||
std::shared_ptr<DeviceProfile> Controller::getProfile(int32_t virtualSlot) {
|
||||
return profiles[virtualSlot];
|
||||
}
|
||||
|
||||
std::shared_ptr<ControllerAttachment> Controller::GetAttachment() {
|
||||
return Attachment;
|
||||
}
|
||||
|
||||
bool Controller::IsRumbling() {
|
||||
return isRumbling;
|
||||
}
|
||||
|
||||
std::string Controller::GetGuid() {
|
||||
return GUID;
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ namespace Ship {
|
||||
public:
|
||||
virtual ~Controller() = default;
|
||||
Controller();
|
||||
void Read(OSContPad* pad, int32_t virtualSlot);
|
||||
virtual void ReadFromSource(int32_t virtualSlot) = 0;
|
||||
virtual void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) = 0;
|
||||
virtual bool Connected() const = 0;
|
||||
@ -49,8 +48,12 @@ namespace Ship {
|
||||
virtual void CreateDefaultBinding(int32_t virtualSlot) = 0;
|
||||
virtual void ClearRawPress() = 0;
|
||||
virtual int32_t ReadRawPress() = 0;
|
||||
virtual const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) = 0;
|
||||
virtual const std::string GetControllerName() = 0;
|
||||
void Read(OSContPad* pad, int32_t virtualSlot);
|
||||
void SetButtonMapping(int32_t virtualSlot, int32_t n64Button, int32_t dwScancode);
|
||||
std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; }
|
||||
std::shared_ptr<ControllerAttachment> GetAttachment();
|
||||
std::shared_ptr<DeviceProfile> getProfile(int32_t virtualSlot);
|
||||
int8_t& getLeftStickX(int32_t virtualSlot);
|
||||
int8_t& getLeftStickY(int32_t virtualSlot);
|
||||
int8_t& getRightStickX(int32_t virtualSlot);
|
||||
@ -58,11 +61,8 @@ namespace Ship {
|
||||
int32_t& getPressedButtons(int32_t virtualSlot);
|
||||
float& getGyroX(int32_t virtualSlot);
|
||||
float& getGyroY(int32_t virtualSlot);
|
||||
std::shared_ptr<DeviceProfile> getProfile(int32_t virtualSlot);
|
||||
bool IsRumbling() { return isRumbling; }
|
||||
std::string GetGuid() { return GUID; }
|
||||
virtual const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) = 0;
|
||||
virtual const std::string GetControllerName() = 0;
|
||||
bool IsRumbling();
|
||||
std::string GetGuid();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ControllerAttachment> Attachment;
|
||||
|
61
libultraship/libultraship/DummyController.cpp
Normal file
61
libultraship/libultraship/DummyController.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include "DummyController.h"
|
||||
|
||||
namespace Ship {
|
||||
DummyController::DummyController(const std::string& CUID, const std::string& KeyName, bool Connected) {
|
||||
GUID = CUID;
|
||||
isConnected = Connected;
|
||||
ButtonName = KeyName;
|
||||
}
|
||||
|
||||
void DummyController::ReadFromSource(int32_t virtualSlot) {
|
||||
|
||||
}
|
||||
|
||||
const std::string DummyController::GetControllerName() {
|
||||
return GUID;
|
||||
}
|
||||
|
||||
const std::string DummyController::GetButtonName(int32_t virtualSlot, int32_t n64Button) {
|
||||
return ButtonName;
|
||||
}
|
||||
|
||||
void DummyController::WriteToSource(int32_t virtualSlot, ControllerCallback* controller){
|
||||
|
||||
}
|
||||
|
||||
bool DummyController::Connected() const {
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
bool DummyController::CanRumble() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DummyController::CanGyro() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DummyController::CreateDefaultBinding(int32_t slot) {
|
||||
|
||||
}
|
||||
|
||||
std::string DummyController::GetControllerType() {
|
||||
return "Unk";
|
||||
}
|
||||
|
||||
std::string DummyController::GetConfSection() {
|
||||
return "Unk";
|
||||
}
|
||||
|
||||
std::string DummyController::GetBindingConfSection() {
|
||||
return "Unk";
|
||||
}
|
||||
|
||||
void DummyController::ClearRawPress() {
|
||||
|
||||
}
|
||||
|
||||
int32_t DummyController::ReadRawPress() {
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -7,31 +7,25 @@
|
||||
namespace Ship {
|
||||
class DummyController final : public Controller {
|
||||
public:
|
||||
DummyController(const std::string& CUID, const std::string& KeyName, bool Connected) {
|
||||
GUID = CUID;
|
||||
isConnected = Connected;
|
||||
ButtonName = KeyName;
|
||||
}
|
||||
|
||||
DummyController(const std::string& CUID, const std::string& KeyName, bool Connected);
|
||||
std::map<std::vector<std::string>, int32_t> ReadButtonPress();
|
||||
void ReadFromSource(int32_t slot) override {}
|
||||
const std::string GetControllerName() override { return GUID; }
|
||||
const std::string GetButtonName(int slot, int n64Button) override { return ButtonName; }
|
||||
void WriteToSource(int32_t slot, ControllerCallback* controller) override { }
|
||||
bool Connected() const override { return isConnected; }
|
||||
bool CanRumble() const override { return false; }
|
||||
bool CanGyro() const override { return false; }
|
||||
|
||||
void ClearRawPress() override {}
|
||||
int32_t ReadRawPress() override { return -1; }
|
||||
bool HasPadConf() const { return true; }
|
||||
std::optional<std::string> GetPadConfSection() { return "Unk"; }
|
||||
void CreateDefaultBinding(int32_t slot) override {}
|
||||
void ReadFromSource(int32_t virtualSlot) override;
|
||||
const std::string GetControllerName() override;
|
||||
const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override;
|
||||
void WriteToSource(int32_t slot, ControllerCallback* controller) override;
|
||||
bool Connected() const override;
|
||||
bool CanRumble() const override;
|
||||
bool CanGyro() const override;
|
||||
void ClearRawPress() override;
|
||||
int32_t ReadRawPress() override;
|
||||
bool HasPadConf() const;
|
||||
std::optional<std::string> GetPadConfSection();
|
||||
void CreateDefaultBinding(int32_t virtualSlot) override;
|
||||
protected:
|
||||
std::string ButtonName;
|
||||
bool isConnected = false;
|
||||
std::string GetControllerType() { return "Unk"; }
|
||||
std::string GetConfSection() { return "Unk"; }
|
||||
std::string GetBindingConfSection() { return "Unk"; }
|
||||
std::string GetControllerType();
|
||||
std::string GetConfSection();
|
||||
std::string GetBindingConfSection();
|
||||
};
|
||||
}
|
5
libultraship/libultraship/Hooks.cpp
Normal file
5
libultraship/libultraship/Hooks.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "Hooks.h"
|
||||
|
||||
namespace Ship {
|
||||
|
||||
}
|
@ -2011,7 +2011,9 @@ namespace SohImGui {
|
||||
);
|
||||
PaddedEnhancementCheckbox("Key Colors Match Dungeon", "gRandoMatchKeyColors", true, false);
|
||||
Tooltip(
|
||||
"Matches the color of small keys and boss keys to the dungeon they belong to. This helps identify keys from afar and adds a little bit of flair.");
|
||||
"Matches the color of small keys and boss keys to the dungeon they belong to. "
|
||||
"This helps identify keys from afar and adds a little bit of flair.\n\nThis only "
|
||||
"applies to seeds with keys and boss keys shuffled to Any Dungeon, Overworld, or Anywhere.");
|
||||
PaddedEnhancementCheckbox("Quest Item Fanfares", "gRandoQuestItemFanfares", true, false);
|
||||
Tooltip(
|
||||
"Play unique fanfares when obtaining quest items "
|
||||
|
@ -100,4 +100,28 @@ namespace Ship {
|
||||
const std::string KeyboardController::GetControllerName() {
|
||||
return "Keyboard";
|
||||
}
|
||||
|
||||
bool KeyboardController::Connected() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyboardController::CanRumble() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyboardController::CanGyro() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void KeyboardController::ClearRawPress() {
|
||||
lastKey = -1;
|
||||
}
|
||||
|
||||
void KeyboardController::SetLastScancode(int32_t key) {
|
||||
lastScancode = key;
|
||||
}
|
||||
|
||||
int32_t KeyboardController::GetLastScancode() {
|
||||
return lastScancode;
|
||||
}
|
||||
}
|
||||
|
@ -9,26 +9,18 @@ namespace Ship {
|
||||
|
||||
void ReadFromSource(int32_t virtualSlot) override;
|
||||
void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override;
|
||||
bool Connected() const override { return true; }
|
||||
bool CanRumble() const override { return false; }
|
||||
bool CanGyro() const override { return false; }
|
||||
const std::string GetControllerName() override;
|
||||
const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override;
|
||||
bool PressButton(int32_t dwScancode);
|
||||
bool ReleaseButton(int32_t dwScancode);
|
||||
|
||||
void ClearRawPress() override {
|
||||
lastKey = -1;
|
||||
}
|
||||
|
||||
bool Connected() const override;
|
||||
bool CanRumble() const override;
|
||||
bool CanGyro() const override;
|
||||
void ClearRawPress() override;
|
||||
int32_t ReadRawPress() override;
|
||||
void ReleaseAllButtons();
|
||||
|
||||
void SetLastScancode(int32_t key) {
|
||||
lastScancode = key;
|
||||
}
|
||||
|
||||
int32_t GetLastScancode() { return lastScancode; }
|
||||
void SetLastScancode(int32_t key);
|
||||
int32_t GetLastScancode();
|
||||
void CreateDefaultBinding(int32_t virtualSlot) override;
|
||||
|
||||
protected:
|
||||
|
@ -333,4 +333,17 @@ namespace Ship {
|
||||
const std::string* ResourceMgr::HashToString(uint64_t Hash) const {
|
||||
return OTR->HashToString(Hash);
|
||||
}
|
||||
|
||||
std::shared_ptr<Archive> ResourceMgr::GetArchive() {
|
||||
return OTR;
|
||||
}
|
||||
|
||||
std::shared_ptr<Window> ResourceMgr::GetContext() {
|
||||
return Context;
|
||||
}
|
||||
|
||||
std::shared_ptr<Resource> ResourceMgr::LoadResource(const std::string& FilePath) {
|
||||
return LoadResource(FilePath.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,20 +23,17 @@ namespace Ship {
|
||||
bool IsRunning();
|
||||
bool DidLoadSuccessfully();
|
||||
|
||||
std::shared_ptr<Archive> GetArchive() { return OTR; }
|
||||
std::shared_ptr<Window> GetContext() { return Context; }
|
||||
|
||||
std::shared_ptr<Archive> GetArchive();
|
||||
std::shared_ptr<Window> GetContext();
|
||||
const std::string* HashToString(uint64_t Hash) const;
|
||||
|
||||
void InvalidateResourceCache();
|
||||
|
||||
uint32_t GetGameVersion();
|
||||
void SetGameVersion(uint32_t newGameVersion);
|
||||
std::shared_ptr<File> LoadFileAsync(const std::string& FilePath);
|
||||
std::shared_ptr<File> LoadFile(const std::string& FilePath);
|
||||
std::shared_ptr<Resource> GetCachedFile(const char* FilePath) const;
|
||||
std::shared_ptr<Resource> LoadResource(const char* FilePath);
|
||||
std::shared_ptr<Resource> LoadResource(const std::string& FilePath) { return LoadResource(FilePath.c_str()); }
|
||||
std::shared_ptr<Resource> LoadResource(const std::string& FilePath);
|
||||
std::variant<std::shared_ptr<Resource>, std::shared_ptr<ResourcePromise>> LoadResourceAsync(const char* FilePath);
|
||||
std::shared_ptr<std::vector<std::shared_ptr<Resource>>> CacheDirectory(const std::string& SearchMask);
|
||||
std::shared_ptr<std::vector<std::shared_ptr<ResourcePromise>>> CacheDirectoryAsync(const std::string& SearchMask);
|
||||
|
@ -12,6 +12,10 @@ extern "C" uint8_t __osMaxControllers;
|
||||
|
||||
namespace Ship {
|
||||
|
||||
SDLController::SDLController(int32_t physicalSlot) : Controller(), Cont(nullptr), physicalSlot(physicalSlot) {
|
||||
|
||||
}
|
||||
|
||||
bool SDLController::Open() {
|
||||
const auto NewCont = SDL_GameControllerOpen(physicalSlot);
|
||||
|
||||
@ -450,4 +454,23 @@ namespace Ship {
|
||||
profile->GyroData[DRIFT_Y] = 0.0f;
|
||||
profile->GyroData[GYRO_SENSITIVITY] = 1.0f;
|
||||
}
|
||||
|
||||
bool SDLController::Connected() const {
|
||||
return Cont != nullptr;
|
||||
}
|
||||
|
||||
bool SDLController::CanGyro() const {
|
||||
return supportsGyro;
|
||||
}
|
||||
|
||||
bool SDLController::CanRumble() const {
|
||||
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
|
||||
return SDL_GameControllerHasRumble(Cont);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDLController::ClearRawPress() {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,19 @@
|
||||
namespace Ship {
|
||||
class SDLController : public Controller {
|
||||
public:
|
||||
SDLController(int32_t physicalSlot);
|
||||
void ReadFromSource(int32_t virtualSlot) override;
|
||||
const std::string GetControllerName() override;
|
||||
const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override;
|
||||
void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override;
|
||||
bool Connected() const override;
|
||||
bool CanGyro() const override;
|
||||
bool CanRumble() const override;
|
||||
bool Open();
|
||||
void ClearRawPress() override;
|
||||
int32_t ReadRawPress() override;
|
||||
|
||||
protected:
|
||||
inline static const char* AxisNames[] = {
|
||||
"Left Stick X",
|
||||
"Left Stick Y",
|
||||
@ -15,25 +28,6 @@ namespace Ship {
|
||||
"Start Button"
|
||||
};
|
||||
|
||||
SDLController(int32_t physicalSlot) : Controller(), Cont(nullptr), physicalSlot(physicalSlot) { }
|
||||
void ReadFromSource(int32_t virtualSlot) override;
|
||||
const std::string GetControllerName() override;
|
||||
const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override;
|
||||
void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override;
|
||||
bool Connected() const override { return Cont != nullptr; }
|
||||
bool CanGyro() const override { return supportsGyro; }
|
||||
bool CanRumble() const override {
|
||||
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
|
||||
return SDL_GameControllerHasRumble(Cont);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Open();
|
||||
void ClearRawPress() override {}
|
||||
int32_t ReadRawPress() override;
|
||||
|
||||
protected:
|
||||
void CreateDefaultBinding(int32_t virtualSlot) override;
|
||||
|
||||
private:
|
||||
|
@ -581,4 +581,52 @@ namespace Ship {
|
||||
|
||||
saveFile.close();
|
||||
}
|
||||
|
||||
bool Window::IsFullscreen() {
|
||||
return bIsFullscreen;
|
||||
}
|
||||
|
||||
uint32_t Window::GetMenuBar() {
|
||||
return dwMenubar;
|
||||
}
|
||||
|
||||
void Window::SetMenuBar(uint32_t dwMenuBar) {
|
||||
this->dwMenubar = dwMenuBar;
|
||||
}
|
||||
|
||||
std::string Window::GetName() {
|
||||
return Name;
|
||||
}
|
||||
|
||||
std::shared_ptr<ControlDeck> Window::GetControlDeck() {
|
||||
return ControllerApi;
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioPlayer> Window::GetAudioPlayer() {
|
||||
return APlayer;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceMgr> Window::GetResourceManager() {
|
||||
return ResMan;
|
||||
}
|
||||
|
||||
std::shared_ptr<Mercury> Window::GetConfig() {
|
||||
return Config;
|
||||
}
|
||||
|
||||
std::shared_ptr<spdlog::logger> Window::GetLogger() {
|
||||
return Logger;
|
||||
}
|
||||
|
||||
const char* Window::GetKeyName(int32_t scancode) {
|
||||
return WmApi->get_key_name(scancode);
|
||||
}
|
||||
|
||||
int32_t Window::GetLastScancode() {
|
||||
return lastScancode;
|
||||
}
|
||||
|
||||
void Window::SetLastScancode(int32_t scanCode) {
|
||||
lastScancode = scanCode;
|
||||
}
|
||||
}
|
||||
|
@ -36,20 +36,20 @@ namespace Ship {
|
||||
void ToggleFullscreen();
|
||||
void SetFullscreen(bool bIsFullscreen);
|
||||
void ShowCursor(bool hide);
|
||||
bool IsFullscreen() { return bIsFullscreen; }
|
||||
uint32_t GetCurrentWidth();
|
||||
uint32_t GetCurrentHeight();
|
||||
uint32_t GetMenuBar() { return dwMenubar; }
|
||||
void SetMenuBar(uint32_t dwMenuBar) { this->dwMenubar = dwMenuBar; }
|
||||
std::string GetName() { return Name; }
|
||||
std::shared_ptr<ControlDeck> GetControlDeck() { return ControllerApi; };
|
||||
std::shared_ptr<AudioPlayer> GetAudioPlayer() { return APlayer; }
|
||||
std::shared_ptr<ResourceMgr> GetResourceManager() { return ResMan; }
|
||||
std::shared_ptr<Mercury> GetConfig() { return Config; }
|
||||
std::shared_ptr<spdlog::logger> GetLogger() { return Logger; }
|
||||
const char* GetKeyName(int32_t scancode) { return WmApi->get_key_name(scancode); }
|
||||
int32_t GetLastScancode() { return lastScancode; }
|
||||
void SetLastScancode(int32_t scanCode) { lastScancode = scanCode; }
|
||||
bool IsFullscreen();
|
||||
uint32_t GetMenuBar();
|
||||
void SetMenuBar(uint32_t dwMenuBar);
|
||||
std::string GetName();
|
||||
std::shared_ptr<ControlDeck> GetControlDeck();
|
||||
std::shared_ptr<AudioPlayer> GetAudioPlayer();
|
||||
std::shared_ptr<ResourceMgr> GetResourceManager();
|
||||
std::shared_ptr<Mercury> GetConfig();
|
||||
std::shared_ptr<spdlog::logger> GetLogger();
|
||||
const char* GetKeyName(int32_t scancode);
|
||||
int32_t GetLastScancode();
|
||||
void SetLastScancode(int32_t scanCode);
|
||||
|
||||
protected:
|
||||
Window() = default;
|
||||
|
@ -260,5 +260,6 @@ extern GraphicsContext* __gfxCtx;
|
||||
|
||||
#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1)
|
||||
|
||||
#define NUM_TRIALS 6
|
||||
|
||||
#endif
|
||||
|
@ -183,7 +183,7 @@ typedef struct {
|
||||
char ganonHintText[150];
|
||||
char ganonText[250];
|
||||
u8 seedIcons[5];
|
||||
u16 randomizerInf[2];
|
||||
u16 randomizerInf[4];
|
||||
u8 temporaryWeapon;
|
||||
u16 adultTradeItems;
|
||||
} SaveContext; // size = 0x1428
|
||||
|
@ -17,7 +17,8 @@ typedef enum {
|
||||
TEXT_BLUE_RUPEE = 0xCC,
|
||||
TEXT_RED_RUPEE = 0xF0,
|
||||
TEXT_PURPLE_RUPEE = 0xF1,
|
||||
TEXT_HUGE_RUPEE = 0xF2
|
||||
TEXT_HUGE_RUPEE = 0xF2,
|
||||
TEXT_BEAN_SALESMAN = 0x405E
|
||||
} TextIDs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1039,6 +1039,19 @@ int Fill() {
|
||||
//Fast fill for the rest of the pool
|
||||
std::vector<uint32_t> remainingPool = FilterAndEraseFromPool(ItemPool, [](const auto i) { return true; });
|
||||
FastFill(remainingPool, GetAllEmptyLocations(), false);
|
||||
|
||||
//Add prices for scrubsanity, this is unique to SoH because we write/read scrub prices to/from the spoilerfile.
|
||||
if (Scrubsanity.Is(SCRUBSANITY_AFFORDABLE)) {
|
||||
for (size_t i = 0; i < ScrubLocations.size(); i++) {
|
||||
Location(ScrubLocations[i])->SetScrubsanityPrice(10);
|
||||
}
|
||||
} else if (Scrubsanity.Is(SCRUBSANITY_RANDOM_PRICES)) {
|
||||
for (size_t i = 0; i < ScrubLocations.size(); i++) {
|
||||
int randomPrice = GetRandomScrubPrice();
|
||||
Location(ScrubLocations[i])->SetScrubsanityPrice(randomPrice);
|
||||
}
|
||||
}
|
||||
|
||||
GeneratePlaythrough();
|
||||
//Successful placement, produced beatable result
|
||||
if(playthroughBeatable && !placementFailure) {
|
||||
|
@ -1011,6 +1011,56 @@ std::vector<std::vector<uint32_t>> ShopLocationLists = {
|
||||
GC_ShopLocations,
|
||||
};
|
||||
|
||||
//List of scrubs, used for pricing the scrubs
|
||||
std::vector<uint32_t> ScrubLocations = {
|
||||
LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT,
|
||||
LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT,
|
||||
LW_DEKU_SCRUB_NEAR_BRIDGE,
|
||||
LW_DEKU_SCRUB_GROTTO_REAR,
|
||||
LW_DEKU_SCRUB_GROTTO_FRONT,
|
||||
SFM_DEKU_SCRUB_GROTTO_REAR,
|
||||
SFM_DEKU_SCRUB_GROTTO_FRONT,
|
||||
HF_DEKU_SCRUB_GROTTO,
|
||||
LH_DEKU_SCRUB_GROTTO_LEFT,
|
||||
LH_DEKU_SCRUB_GROTTO_RIGHT,
|
||||
LH_DEKU_SCRUB_GROTTO_CENTER,
|
||||
GV_DEKU_SCRUB_GROTTO_REAR,
|
||||
GV_DEKU_SCRUB_GROTTO_FRONT,
|
||||
COLOSSUS_DEKU_SCRUB_GROTTO_REAR,
|
||||
COLOSSUS_DEKU_SCRUB_GROTTO_FRONT,
|
||||
GC_DEKU_SCRUB_GROTTO_LEFT,
|
||||
GC_DEKU_SCRUB_GROTTO_RIGHT,
|
||||
GC_DEKU_SCRUB_GROTTO_CENTER,
|
||||
DMC_DEKU_SCRUB,
|
||||
DMC_DEKU_SCRUB_GROTTO_LEFT,
|
||||
DMC_DEKU_SCRUB_GROTTO_RIGHT,
|
||||
DMC_DEKU_SCRUB_GROTTO_CENTER,
|
||||
ZR_DEKU_SCRUB_GROTTO_REAR,
|
||||
ZR_DEKU_SCRUB_GROTTO_FRONT,
|
||||
LLR_DEKU_SCRUB_GROTTO_LEFT,
|
||||
LLR_DEKU_SCRUB_GROTTO_RIGHT,
|
||||
LLR_DEKU_SCRUB_GROTTO_CENTER,
|
||||
DEKU_TREE_MQ_DEKU_SCRUB,
|
||||
DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT,
|
||||
DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS,
|
||||
DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT,
|
||||
DODONGOS_CAVERN_DEKU_SCRUB_LOBBY,
|
||||
DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR,
|
||||
DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT,
|
||||
DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE,
|
||||
DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS,
|
||||
JABU_JABUS_BELLY_DEKU_SCRUB,
|
||||
GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT,
|
||||
GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT,
|
||||
GANONS_CASTLE_DEKU_SCRUB_RIGHT,
|
||||
GANONS_CASTLE_DEKU_SCRUB_LEFT,
|
||||
GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT,
|
||||
GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT,
|
||||
GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER,
|
||||
GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT,
|
||||
GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT,
|
||||
};
|
||||
|
||||
//List of gossip stone locations for hints
|
||||
std::vector<uint32_t> gossipStoneLocations = {
|
||||
DMC_GOSSIP_STONE,
|
||||
|
@ -257,8 +257,8 @@ public:
|
||||
}
|
||||
|
||||
void SetPrice(uint16_t price_) {
|
||||
//don't override price if the price was set for shopsanity
|
||||
if (hasShopsanityPrice) {
|
||||
//don't override price if the price was set for shopsanity/scrubsanity
|
||||
if (hasShopsanityPrice || hasScrubsanityPrice) {
|
||||
return;
|
||||
}
|
||||
price = price_;
|
||||
@ -269,10 +269,19 @@ public:
|
||||
hasShopsanityPrice = true;
|
||||
}
|
||||
|
||||
void SetScrubsanityPrice(uint16_t price_) {
|
||||
price = price_;
|
||||
hasScrubsanityPrice = true;
|
||||
}
|
||||
|
||||
bool HasShopsanityPrice() const {
|
||||
return hasShopsanityPrice;
|
||||
}
|
||||
|
||||
bool HasScrubsanityPrice() const {
|
||||
return hasScrubsanityPrice;
|
||||
}
|
||||
|
||||
bool IsExcluded() const {
|
||||
return excludedOption.Value<bool>();
|
||||
}
|
||||
@ -426,6 +435,7 @@ public:
|
||||
isHintable = false;
|
||||
price = 0;
|
||||
hasShopsanityPrice = false;
|
||||
hasScrubsanityPrice = false;
|
||||
hidden = false;
|
||||
}
|
||||
|
||||
@ -451,6 +461,7 @@ private:
|
||||
bool isHintable = false;
|
||||
uint32_t parentRegion = NONE;
|
||||
bool hasShopsanityPrice = false;
|
||||
bool hasScrubsanityPrice = false;
|
||||
bool hidden = false;
|
||||
};
|
||||
|
||||
@ -467,6 +478,8 @@ ItemLocation* Location(uint32_t locKey);
|
||||
|
||||
extern std::vector<std::vector<uint32_t>> ShopLocationLists;
|
||||
|
||||
extern std::vector<uint32_t> ScrubLocations;
|
||||
|
||||
extern std::vector<uint32_t> gossipStoneLocations;
|
||||
|
||||
extern std::vector<uint32_t> dungeonRewardLocations;
|
||||
|
@ -2517,21 +2517,20 @@ namespace Settings {
|
||||
BridgeRewardCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_REWARD_COUNT]);
|
||||
BridgeDungeonCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT]);
|
||||
BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]);
|
||||
RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]);
|
||||
// RANDTODO: Switch this back once Ganon's Trials Count is properly implemented.
|
||||
//GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]);
|
||||
switch (cvarSettings[RSK_TRIAL_COUNT]) {
|
||||
case 0:
|
||||
GanonsTrialsCount.SetSelectedIndex(6);
|
||||
break;
|
||||
case 1:
|
||||
GanonsTrialsCount.SetSelectedIndex(0);
|
||||
break;
|
||||
if (cvarSettings[RSK_RANDOM_TRIALS] == 2) {
|
||||
RandomGanonsTrials.SetSelectedIndex(1);
|
||||
} else {
|
||||
RandomGanonsTrials.SetSelectedIndex(0);
|
||||
}
|
||||
if (cvarSettings[RSK_RANDOM_TRIALS] == 0) {
|
||||
GanonsTrialsCount.SetSelectedIndex(0);
|
||||
} else {
|
||||
GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]);
|
||||
}
|
||||
|
||||
ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]);
|
||||
ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]);
|
||||
Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]);
|
||||
Scrubsanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SCRUBS]);
|
||||
ShuffleCows.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_COWS]);
|
||||
ShuffleKokiriSword.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_KOKIRI_SWORD]);
|
||||
ShuffleOcarinas.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OCARINA]);
|
||||
@ -2551,6 +2550,7 @@ namespace Settings {
|
||||
ShuffleFrogSongRupees.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_FROG_SONG_RUPEES]);
|
||||
|
||||
ShuffleAdultTradeQuest.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_ADULT_TRADE]);
|
||||
ShuffleMagicBeans.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_MAGIC_BEANS]);
|
||||
|
||||
// the checkbox works because 0 is "Off" and 1 is "Fairy Ocarina"
|
||||
StartingOcarina.SetSelectedIndex(cvarSettings[RSK_STARTING_OCARINA]);
|
||||
|
@ -501,25 +501,23 @@ static void WriteMasterQuestDungeons(tinyxml2::XMLDocument& spoilerLog) {
|
||||
}
|
||||
}
|
||||
|
||||
// Writes the required trails to the spoiler log, if there are any.
|
||||
static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) {
|
||||
auto parentNode = spoilerLog.NewElement("required-trials");
|
||||
|
||||
for (const auto* trial : Trial::trialList) {
|
||||
if (trial->IsSkipped()) {
|
||||
continue;
|
||||
// Writes the required trials to the spoiler log, if there are any.
|
||||
static void WriteRequiredTrials() {
|
||||
for (const auto& trial : Trial::trialList) {
|
||||
if (trial->IsRequired()) {
|
||||
std::string trialName;
|
||||
switch (gSaveContext.language) {
|
||||
case LANGUAGE_FRA:
|
||||
trialName = trial->GetName().GetFrench();
|
||||
break;
|
||||
case LANGUAGE_ENG:
|
||||
default:
|
||||
trialName = trial->GetName().GetEnglish();
|
||||
break;
|
||||
}
|
||||
jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName));
|
||||
}
|
||||
}
|
||||
|
||||
auto node = parentNode->InsertNewChildElement("trial");
|
||||
// PURPLE TODO: LOCALIZATION
|
||||
std::string name = trial->GetName().GetEnglish();
|
||||
name[0] = toupper(name[0]); // Capitalize T in "The"
|
||||
node->SetAttribute("name", name.c_str());
|
||||
}
|
||||
|
||||
if (!parentNode->NoChildren()) {
|
||||
spoilerLog.RootElement()->InsertEndChild(parentNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Writes the intended playthrough to the spoiler log, separated into spheres.
|
||||
@ -673,15 +671,24 @@ static void WriteHints(int language) {
|
||||
static void WriteAllLocations(int language) {
|
||||
for (const uint32_t key : allLocations) {
|
||||
ItemLocation* location = Location(key);
|
||||
std::string placedItemName;
|
||||
|
||||
switch (language) {
|
||||
case 0:
|
||||
default:
|
||||
jsonData["locations"][location->GetName()] = location->GetPlacedItemName().english;
|
||||
break;
|
||||
case 2:
|
||||
jsonData["locations"][location->GetName()] = location->GetPlacedItemName().french;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
placedItemName = location->GetPlacedItemName().english;
|
||||
break;
|
||||
case 2:
|
||||
placedItemName = location->GetPlacedItemName().french;
|
||||
break;
|
||||
}
|
||||
|
||||
// Eventually check for other things here like fake name
|
||||
if (location->HasScrubsanityPrice() || location->HasShopsanityPrice()) {
|
||||
jsonData["locations"][location->GetName()]["item"] = placedItemName;
|
||||
jsonData["locations"][location->GetName()]["price"] = location->GetPrice();
|
||||
} else {
|
||||
jsonData["locations"][location->GetName()] = placedItemName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -714,7 +721,7 @@ const char* SpoilerLog_Write(int language) {
|
||||
// WriteEnabledGlitches(spoilerLog);
|
||||
//}
|
||||
//WriteMasterQuestDungeons(spoilerLog);
|
||||
//WriteRequiredTrials(spoilerLog);
|
||||
WriteRequiredTrials();
|
||||
WritePlaythrough();
|
||||
//WriteWayOfTheHeroLocation(spoilerLog);
|
||||
|
||||
@ -764,7 +771,7 @@ bool PlacementLog_Write() {
|
||||
WriteEnabledTricks(placementLog);
|
||||
WriteEnabledGlitches(placementLog);
|
||||
WriteMasterQuestDungeons(placementLog);
|
||||
WriteRequiredTrials(placementLog);
|
||||
//WriteRequiredTrials(placementLog);
|
||||
|
||||
placementtxt = "\n" + placementtxt;
|
||||
|
||||
|
@ -7,12 +7,12 @@ TrialInfo::TrialInfo(Text name_)
|
||||
|
||||
TrialInfo::~TrialInfo() = default;
|
||||
|
||||
TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la forêt", /*spanish*/"la prueba del bosque"});
|
||||
TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du feu", /*spanish*/"la prueba del fuego"});
|
||||
TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'eau", /*spanish*/"la prueba del agua"});
|
||||
TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'esprit", /*spanish*/"la prueba del espíritu"});
|
||||
TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'ombre", /*spanish*/"la prueba de las sombras"});
|
||||
TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la lumière", /*spanish*/"la prueba de la luz"});
|
||||
TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la Forêt", /*spanish*/"la prueba del bosque"});
|
||||
TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du Feu", /*spanish*/"la prueba del fuego"});
|
||||
TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'Eau", /*spanish*/"la prueba del agua"});
|
||||
TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'Esprit", /*spanish*/"la prueba del espíritu"});
|
||||
TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'Ombre", /*spanish*/"la prueba de las sombras"});
|
||||
TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la Lumière", /*spanish*/"la prueba de la luz"});
|
||||
|
||||
const TrialArray trialList = {
|
||||
&ForestTrial,
|
||||
|
@ -32,7 +32,7 @@ u8 generated;
|
||||
|
||||
const std::string Randomizer::getItemMessageTableID = "Randomizer";
|
||||
const std::string Randomizer::hintMessageTableID = "RandomizerHints";
|
||||
const std::string Randomizer::scrubMessageTableID = "RandomizerScrubs";
|
||||
const std::string Randomizer::merchantMessageTableID = "RandomizerMerchants";
|
||||
const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees";
|
||||
const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi";
|
||||
|
||||
@ -104,8 +104,24 @@ Sprite* Randomizer::GetSeedTexture(uint8_t index) {
|
||||
Randomizer::~Randomizer() {
|
||||
this->randoSettings.clear();
|
||||
this->itemLocations.clear();
|
||||
this->randomizerMerchantPrices.clear();
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, RandomizerInf> spoilerFileTrialToEnum = {
|
||||
{ "the Forest Trial", RAND_INF_TRIALS_DONE_FOREST_TRIAL },
|
||||
{ "l'épreuve de la Forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL },
|
||||
{ "the Fire Trial", RAND_INF_TRIALS_DONE_FIRE_TRIAL },
|
||||
{ "l'épreuve du Feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL },
|
||||
{ "the Water Trial", RAND_INF_TRIALS_DONE_WATER_TRIAL },
|
||||
{ "l'épreuve de l'Eau", RAND_INF_TRIALS_DONE_WATER_TRIAL },
|
||||
{ "the Spirit Trial", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL },
|
||||
{ "l'épreuve de l'Esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL },
|
||||
{ "the Shadow Trial", RAND_INF_TRIALS_DONE_SHADOW_TRIAL },
|
||||
{ "l'épreuve de l'Ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL },
|
||||
{ "the Light Trial", RAND_INF_TRIALS_DONE_LIGHT_TRIAL },
|
||||
{ "l'épreuve de la Lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL }
|
||||
};
|
||||
|
||||
std::unordered_map<s16, s16> getItemIdToItemId = {
|
||||
{ GI_BOW, ITEM_BOW },
|
||||
{ GI_ARROW_FIRE, ITEM_ARROW_FIRE },
|
||||
@ -546,9 +562,11 @@ std::unordered_map<std::string, RandomizerSettingKey> SpoilerfileSettingNameToEn
|
||||
{ "Open Settings:Random Ganon's Trials", RSK_RANDOM_TRIALS },
|
||||
{ "Open Settings:Trial Count", RSK_TRIAL_COUNT },
|
||||
{ "Shuffle Settings:Shuffle Gerudo Card", RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD },
|
||||
{ "Shuffle Settings:Scrub Shuffle", RSK_SHUFFLE_SCRUBS },
|
||||
{ "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS },
|
||||
{ "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS },
|
||||
{ "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE },
|
||||
{ "Shuffle Settings:Shuffle Magic Beans", RSK_SHUFFLE_MAGIC_BEANS},
|
||||
{ "Start with Deku Shield", RSK_STARTING_DEKU_SHIELD },
|
||||
{ "Start with Kokiri Sword", RSK_STARTING_KOKIRI_SWORD },
|
||||
{ "Start with Fairy Ocarina", RSK_STARTING_OCARINA },
|
||||
@ -671,6 +689,12 @@ void Randomizer::LoadItemLocations(const char* spoilerFileName, bool silent) {
|
||||
itemLocations[RC_UNKNOWN_CHECK] = RG_NONE;
|
||||
}
|
||||
|
||||
void Randomizer::LoadRequiredTrials(const char* spoilerFileName) {
|
||||
if (strcmp(spoilerFileName, "") != 0) {
|
||||
ParseRequiredTrialsFile(spoilerFileName);
|
||||
}
|
||||
}
|
||||
|
||||
void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) {
|
||||
std::ifstream spoilerFileStream(sanitize(spoilerFileName));
|
||||
if (!spoilerFileStream)
|
||||
@ -773,9 +797,21 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) {
|
||||
numericValueString = it.value();
|
||||
gSaveContext.randoSettings[index].value = std::stoi(numericValueString);
|
||||
break;
|
||||
case RSK_SHUFFLE_SCRUBS:
|
||||
if(it.value() == "Off") {
|
||||
gSaveContext.randoSettings[index].value = 0;
|
||||
} else if(it.value() == "Affordable") {
|
||||
gSaveContext.randoSettings[index].value = 1;
|
||||
} else if(it.value() == "Expensive") {
|
||||
gSaveContext.randoSettings[index].value = 2;
|
||||
} else if(it.value() == "Random Prices") {
|
||||
gSaveContext.randoSettings[index].value = 3;
|
||||
}
|
||||
break;
|
||||
case RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD:
|
||||
case RSK_SHUFFLE_COWS:
|
||||
case RSK_SHUFFLE_ADULT_TRADE:
|
||||
case RSK_SHUFFLE_MAGIC_BEANS:
|
||||
case RSK_RANDOM_TRIALS:
|
||||
case RSK_STARTING_DEKU_SHIELD:
|
||||
case RSK_STARTING_KOKIRI_SWORD:
|
||||
@ -841,6 +877,16 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) {
|
||||
gSaveContext.randoSettings[index].value = 3;
|
||||
}
|
||||
break;
|
||||
case RSK_GERUDO_KEYS:
|
||||
if (it.value() == "Vanilla") {
|
||||
gSaveContext.randoSettings[index].value = 0;
|
||||
} else if (it.value() == "Any Dungeon") {
|
||||
gSaveContext.randoSettings[index].value = 1;
|
||||
} else if (it.value() == "Overworld") {
|
||||
gSaveContext.randoSettings[index].value = 2;
|
||||
} else if (it.value() == "Anywhere") {
|
||||
gSaveContext.randoSettings[index].value = 3;
|
||||
}
|
||||
case RSK_KEYSANITY:
|
||||
if(it.value() == "Start With") {
|
||||
gSaveContext.randoSettings[index].value = 0;
|
||||
@ -1078,6 +1124,25 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
|
||||
}
|
||||
}
|
||||
|
||||
void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) {
|
||||
std::ifstream spoilerFileStream(sanitize(spoilerFileName));
|
||||
if (!spoilerFileStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
json spoilerFileJson;
|
||||
spoilerFileStream >> spoilerFileJson;
|
||||
json trialsJson = spoilerFileJson["requiredTrials"];
|
||||
|
||||
for (auto it = trialsJson.begin(); it != trialsJson.end(); it++) {
|
||||
this->trialsRequired[spoilerFileTrialToEnum[it.value()]] = true;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) {
|
||||
std::ifstream spoilerFileStream(sanitize(spoilerFileName));
|
||||
if (!spoilerFileStream)
|
||||
@ -1104,9 +1169,10 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent
|
||||
for (auto itemit = itemJson.begin(); itemit != itemJson.end(); ++itemit) {
|
||||
// todo handle prices
|
||||
if (itemit.key() == "item") {
|
||||
|
||||
gSaveContext.itemLocations[index].check = SpoilerfileCheckNameToEnum[it.key()];
|
||||
gSaveContext.itemLocations[index].get = SpoilerfileGetNameToEnum[itemit.value()];
|
||||
} else if (itemit.key() == "price") {
|
||||
randomizerMerchantPrices[gSaveContext.itemLocations[index].check] = itemit.value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1127,6 +1193,10 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent
|
||||
}
|
||||
}
|
||||
|
||||
bool Randomizer::IsTrialRequired(RandomizerInf trial) {
|
||||
return this->trialsRequired.contains(trial);
|
||||
}
|
||||
|
||||
s16 Randomizer::GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) {
|
||||
s16 itemId = GetItemFromActor(actorId, actorParams, sceneNum, ogId);
|
||||
return itemId;
|
||||
@ -1199,8 +1269,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) {
|
||||
|
||||
case RG_MAGIC_BEAN:
|
||||
return GI_BEAN;
|
||||
case RG_MAGIC_BEAN_PACK:
|
||||
return GI_BEAN; //todo make it 10 of them
|
||||
|
||||
case RG_WEIRD_EGG:
|
||||
return GI_WEIRD_EGG;
|
||||
@ -1360,6 +1428,70 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) {
|
||||
case RG_BOTTLE_WITH_MILK:
|
||||
return GI_MILK_BOTTLE;
|
||||
|
||||
case RG_DEKU_TREE_MAP:
|
||||
case RG_DODONGOS_CAVERN_MAP:
|
||||
case RG_JABU_JABUS_BELLY_MAP:
|
||||
case RG_FOREST_TEMPLE_MAP:
|
||||
case RG_FIRE_TEMPLE_MAP:
|
||||
case RG_WATER_TEMPLE_MAP:
|
||||
case RG_SPIRIT_TEMPLE_MAP:
|
||||
case RG_SHADOW_TEMPLE_MAP:
|
||||
case RG_BOTTOM_OF_THE_WELL_MAP:
|
||||
case RG_ICE_CAVERN_MAP:
|
||||
if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) {
|
||||
return GI_MAP;
|
||||
} else {
|
||||
return randoGet;
|
||||
}
|
||||
|
||||
case RG_DEKU_TREE_COMPASS:
|
||||
case RG_DODONGOS_CAVERN_COMPASS:
|
||||
case RG_JABU_JABUS_BELLY_COMPASS:
|
||||
case RG_FOREST_TEMPLE_COMPASS:
|
||||
case RG_FIRE_TEMPLE_COMPASS:
|
||||
case RG_WATER_TEMPLE_COMPASS:
|
||||
case RG_SPIRIT_TEMPLE_COMPASS:
|
||||
case RG_SHADOW_TEMPLE_COMPASS:
|
||||
case RG_BOTTOM_OF_THE_WELL_COMPASS:
|
||||
case RG_ICE_CAVERN_COMPASS:
|
||||
if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) {
|
||||
return GI_COMPASS;
|
||||
} else {
|
||||
return randoGet;
|
||||
}
|
||||
|
||||
case RG_FOREST_TEMPLE_BOSS_KEY:
|
||||
case RG_FIRE_TEMPLE_BOSS_KEY:
|
||||
case RG_WATER_TEMPLE_BOSS_KEY:
|
||||
case RG_SPIRIT_TEMPLE_BOSS_KEY:
|
||||
case RG_SHADOW_TEMPLE_BOSS_KEY:
|
||||
case RG_GANONS_CASTLE_BOSS_KEY:
|
||||
if (GetRandoSettingValue(RSK_BOSS_KEYSANITY) < 3) {
|
||||
return GI_KEY_BOSS;
|
||||
} else {
|
||||
return randoGet;
|
||||
}
|
||||
|
||||
case RG_FOREST_TEMPLE_SMALL_KEY:
|
||||
case RG_FIRE_TEMPLE_SMALL_KEY:
|
||||
case RG_WATER_TEMPLE_SMALL_KEY:
|
||||
case RG_SPIRIT_TEMPLE_SMALL_KEY:
|
||||
case RG_SHADOW_TEMPLE_SMALL_KEY:
|
||||
case RG_BOTTOM_OF_THE_WELL_SMALL_KEY:
|
||||
case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY:
|
||||
case RG_GANONS_CASTLE_SMALL_KEY:
|
||||
if (GetRandoSettingValue(RSK_KEYSANITY) < 3) {
|
||||
return GI_KEY_SMALL;
|
||||
} else {
|
||||
return randoGet;
|
||||
}
|
||||
case RG_GERUDO_FORTRESS_SMALL_KEY:
|
||||
if (GetRandoSettingValue(RSK_GERUDO_KEYS) == 0) {
|
||||
return GI_KEY_SMALL;
|
||||
} else {
|
||||
return randoGet;
|
||||
}
|
||||
|
||||
// todo test this with keys in own dungeon
|
||||
case RG_TREASURE_GAME_SMALL_KEY:
|
||||
return GI_DOOR_KEY;
|
||||
@ -1570,6 +1702,61 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) {
|
||||
case RG_BUY_RED_POTION_40:
|
||||
case RG_BUY_RED_POTION_50:
|
||||
return true;
|
||||
case RG_FOREST_TEMPLE_SMALL_KEY:
|
||||
case RG_FIRE_TEMPLE_SMALL_KEY:
|
||||
case RG_WATER_TEMPLE_SMALL_KEY:
|
||||
case RG_SPIRIT_TEMPLE_SMALL_KEY:
|
||||
case RG_SHADOW_TEMPLE_SMALL_KEY:
|
||||
case RG_BOTTOM_OF_THE_WELL_SMALL_KEY:
|
||||
case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY:
|
||||
case RG_GANONS_CASTLE_SMALL_KEY:
|
||||
if (GetRandoSettingValue(RSK_KEYSANITY) > 2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case RG_GERUDO_FORTRESS_SMALL_KEY:
|
||||
if (GetRandoSettingValue(RSK_GERUDO_KEYS) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case RG_FOREST_TEMPLE_BOSS_KEY:
|
||||
case RG_FIRE_TEMPLE_BOSS_KEY:
|
||||
case RG_WATER_TEMPLE_BOSS_KEY:
|
||||
case RG_SPIRIT_TEMPLE_BOSS_KEY:
|
||||
case RG_SHADOW_TEMPLE_BOSS_KEY:
|
||||
if (GetRandoSettingValue(RSK_BOSS_KEYSANITY) > 2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case RG_GANONS_CASTLE_BOSS_KEY:
|
||||
if (GetRandoSettingValue(RSK_GANONS_BOSS_KEY) > 2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case RG_DEKU_TREE_COMPASS:
|
||||
case RG_DODONGOS_CAVERN_COMPASS:
|
||||
case RG_JABU_JABUS_BELLY_COMPASS:
|
||||
case RG_FOREST_TEMPLE_COMPASS:
|
||||
case RG_FIRE_TEMPLE_COMPASS:
|
||||
case RG_WATER_TEMPLE_COMPASS:
|
||||
case RG_SPIRIT_TEMPLE_COMPASS:
|
||||
case RG_SHADOW_TEMPLE_COMPASS:
|
||||
case RG_BOTTOM_OF_THE_WELL_COMPASS:
|
||||
case RG_ICE_CAVERN_COMPASS:
|
||||
case RG_DEKU_TREE_MAP:
|
||||
case RG_DODONGOS_CAVERN_MAP:
|
||||
case RG_JABU_JABUS_BELLY_MAP:
|
||||
case RG_FOREST_TEMPLE_MAP:
|
||||
case RG_FIRE_TEMPLE_MAP:
|
||||
case RG_WATER_TEMPLE_MAP:
|
||||
case RG_SPIRIT_TEMPLE_MAP:
|
||||
case RG_SHADOW_TEMPLE_MAP:
|
||||
case RG_BOTTOM_OF_THE_WELL_MAP:
|
||||
case RG_ICE_CAVERN_MAP:
|
||||
if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) > 2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -1596,6 +1783,280 @@ std::string Randomizer::GetGanonHintText() const {
|
||||
return ganonHintText;
|
||||
}
|
||||
|
||||
ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData) {
|
||||
struct ScrubIdentity scrubIdentity;
|
||||
|
||||
scrubIdentity.randomizerCheck = RC_UNKNOWN_CHECK;
|
||||
scrubIdentity.getItemId = GI_NONE;
|
||||
scrubIdentity.itemPrice = -1;
|
||||
scrubIdentity.isShuffled = GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) > 0;
|
||||
|
||||
// Based on z_en_dns.c 93-113
|
||||
switch (actorParams) {
|
||||
case 0x00:
|
||||
scrubIdentity.getItemId = GI_NUTS_5_2;
|
||||
break;
|
||||
case 0x01:
|
||||
scrubIdentity.getItemId = GI_STICKS_1;
|
||||
break;
|
||||
case 0x02:
|
||||
scrubIdentity.getItemId = GI_HEART_PIECE;
|
||||
break;
|
||||
case 0x03:
|
||||
scrubIdentity.getItemId = GI_SEEDS_30;
|
||||
break;
|
||||
case 0x04:
|
||||
scrubIdentity.getItemId = GI_SHIELD_DEKU;
|
||||
break;
|
||||
case 0x05:
|
||||
scrubIdentity.getItemId = GI_BOMBS_5;
|
||||
break;
|
||||
case 0x06:
|
||||
scrubIdentity.getItemId = GI_ARROWS_LARGE;
|
||||
break;
|
||||
case 0x07:
|
||||
scrubIdentity.getItemId = GI_POTION_RED;
|
||||
break;
|
||||
case 0x08:
|
||||
scrubIdentity.getItemId = GI_POTION_GREEN;
|
||||
break;
|
||||
case 0x09:
|
||||
scrubIdentity.getItemId = GI_STICK_UPGRADE_20;
|
||||
break;
|
||||
case 0x0A:
|
||||
scrubIdentity.getItemId = GI_NUT_UPGRADE_30;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Handle MQ scrubs
|
||||
switch (sceneNum) {
|
||||
case SCENE_DDAN: // Dodongo's Cavern
|
||||
switch (actorParams) {
|
||||
case 0x00:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT;
|
||||
scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT;
|
||||
break;
|
||||
case 0x01:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS;
|
||||
scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT;
|
||||
scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT;
|
||||
break;
|
||||
case 0x04:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY;
|
||||
scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SCENE_BDAN: // Jabu Jabu's Belly
|
||||
switch (actorParams) {
|
||||
case 0x00:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_JABU_JABUS_BELLY_DEKU_SCRUB;
|
||||
scrubIdentity.randomizerCheck = RC_JABU_JABUS_BELLY_DEKU_SCRUB;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SCENE_GANONTIKA: // Ganon's Castle
|
||||
switch (actorParams) {
|
||||
case 0x05:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT;
|
||||
scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT;
|
||||
scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT;
|
||||
break;
|
||||
case 0x07:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_RIGHT;
|
||||
scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT;
|
||||
break;
|
||||
case 0x08:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_LEFT;
|
||||
scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_LEFT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SCENE_KAKUSIANA: // Grotto
|
||||
switch (respawnData) {
|
||||
case 0xE6: // Hyrule Field Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x02:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO;
|
||||
scrubIdentity.randomizerCheck = RC_HF_DEKU_SCRUB_GROTTO;
|
||||
scrubIdentity.isShuffled = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xEB: // ZR Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x07:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_REAR;
|
||||
scrubIdentity.randomizerCheck = RC_ZR_DEKU_SCRUB_GROTTO_REAR;
|
||||
break;
|
||||
case 0x08:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_FRONT;
|
||||
scrubIdentity.randomizerCheck = RC_ZR_DEKU_SCRUB_GROTTO_FRONT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xEE: // Sacred Forest Meadow Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x07:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_REAR;
|
||||
scrubIdentity.randomizerCheck = RC_SFM_DEKU_SCRUB_GROTTO_REAR;
|
||||
break;
|
||||
case 0x08:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_FRONT;
|
||||
scrubIdentity.randomizerCheck = RC_SFM_DEKU_SCRUB_GROTTO_FRONT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xEF: // Lake Hylia Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x00:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_LEFT;
|
||||
scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_LEFT;
|
||||
break;
|
||||
case 0x05:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_RIGHT;
|
||||
scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_RIGHT;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_CENTER;
|
||||
scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_CENTER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xF0: // Gerudo Valley Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x07:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_REAR;
|
||||
scrubIdentity.randomizerCheck = RC_GV_DEKU_SCRUB_GROTTO_REAR;
|
||||
break;
|
||||
case 0x08:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_FRONT;
|
||||
scrubIdentity.randomizerCheck = RC_GV_DEKU_SCRUB_GROTTO_FRONT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xF5: // Lost Woods Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_REAR;
|
||||
scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_GROTTO_REAR;
|
||||
break;
|
||||
case 0x0A:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT;
|
||||
scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_GROTTO_FRONT;
|
||||
scrubIdentity.isShuffled = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xF9: // Death Mountain Crater Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x00:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_LEFT;
|
||||
scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_LEFT;
|
||||
break;
|
||||
case 0x05:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_RIGHT;
|
||||
scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_RIGHT;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_CENTER;
|
||||
scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_CENTER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xFB: // Gerudo City Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x00:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_LEFT;
|
||||
scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_LEFT;
|
||||
break;
|
||||
case 0x05:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_RIGHT;
|
||||
scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_RIGHT;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_CENTER;
|
||||
scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_CENTER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xFC: // Lon Lon Ranch Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x00:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_LEFT;
|
||||
scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_LEFT;
|
||||
break;
|
||||
case 0x05:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_RIGHT;
|
||||
scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_RIGHT;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_CENTER;
|
||||
scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_CENTER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xFD: // Desert Colossus Scrub Grotto
|
||||
switch (actorParams) {
|
||||
case 0x07:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_REAR;
|
||||
scrubIdentity.randomizerCheck = RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR;
|
||||
break;
|
||||
case 0x08:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT;
|
||||
scrubIdentity.randomizerCheck = RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SCENE_SPOT10: // Lost woods
|
||||
switch (actorParams) {
|
||||
case 0x00:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT;
|
||||
scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT;
|
||||
break;
|
||||
case 0x01:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT;
|
||||
scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT;
|
||||
break;
|
||||
case 0x09:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE;
|
||||
scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_BRIDGE;
|
||||
scrubIdentity.isShuffled = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SCENE_SPOT17: // Death Mountain Crater
|
||||
switch (actorParams) {
|
||||
case 0x05:
|
||||
scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB;
|
||||
scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (randomizerMerchantPrices.find(scrubIdentity.randomizerCheck) != randomizerMerchantPrices.end()) {
|
||||
scrubIdentity.itemPrice = randomizerMerchantPrices[scrubIdentity.randomizerCheck];
|
||||
}
|
||||
|
||||
return scrubIdentity;
|
||||
}
|
||||
|
||||
u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) {
|
||||
return this->randoSettings[randoSettingKey];
|
||||
}
|
||||
@ -2189,10 +2650,6 @@ RandomizerCheck Randomizer::GetCheckFromActor(s16 sceneNum, s16 actorId, s16 act
|
||||
break;
|
||||
case 62:
|
||||
switch (actorParams) {
|
||||
case 2:
|
||||
return RC_HF_DEKU_SCRUB_GROTTO;
|
||||
case 10:
|
||||
return RC_LW_DEKU_SCRUB_GROTTO_FRONT;
|
||||
case 22988:
|
||||
return RC_KF_STORMS_GROTTO_CHEST;
|
||||
case -22988:
|
||||
@ -2457,8 +2914,6 @@ RandomizerCheck Randomizer::GetCheckFromActor(s16 sceneNum, s16 actorId, s16 act
|
||||
break;
|
||||
case 91:
|
||||
switch (actorParams) {
|
||||
case 9:
|
||||
return RC_LW_DEKU_SCRUB_NEAR_BRIDGE;
|
||||
case 14365:
|
||||
return RC_LW_GOSSIP_STONE;
|
||||
case 27905:
|
||||
@ -2623,8 +3078,10 @@ void GenerateRandomizerImgui() {
|
||||
cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS] = CVar_GetS32("gRandomizeShuffleDungeonReward", 0);
|
||||
cvarSettings[RSK_SHUFFLE_SONGS] = CVar_GetS32("gRandomizeShuffleSongs", 0);
|
||||
cvarSettings[RSK_SHUFFLE_TOKENS] = CVar_GetS32("gRandomizeShuffleTokens", 0);
|
||||
cvarSettings[RSK_SHUFFLE_SCRUBS] = CVar_GetS32("gRandomizeShuffleScrubs", 0);
|
||||
cvarSettings[RSK_SHUFFLE_COWS] = CVar_GetS32("gRandomizeShuffleCows", 0);
|
||||
cvarSettings[RSK_SHUFFLE_ADULT_TRADE] = CVar_GetS32("gRandomizeShuffleAdultTrade", 0);
|
||||
cvarSettings[RSK_SHUFFLE_MAGIC_BEANS] = CVar_GetS32("gRandomizeShuffleBeans", 0);
|
||||
cvarSettings[RSK_BOMBCHUS_IN_LOGIC] = CVar_GetS32("gRandomizeBombchusInLogic", 0);
|
||||
cvarSettings[RSK_SKIP_CHILD_ZELDA] = CVar_GetS32("gRandomizeSkipChildZelda", 0);
|
||||
|
||||
@ -2706,7 +3163,7 @@ void DrawRandoEditor(bool& open) {
|
||||
const char* randoGerudoFortress[3] = { "Normal", "Fast", "Open" };
|
||||
const char* randoRainbowBridge[7] = { "Vanilla", "Always open", "Stones", "Medallions",
|
||||
"Dungeon rewards", "Dungeons", "Tokens" };
|
||||
const char* randoGanonsTrial[2] = { "Off", "On" };
|
||||
const char* randoGanonsTrial[3] = { "Skip", "Set Number", "Random Number" };
|
||||
|
||||
// World Settings
|
||||
const char* randoStartingAge[3] = { "Child", "Adult", "Random" };
|
||||
@ -3080,21 +3537,18 @@ void DrawRandoEditor(bool& open) {
|
||||
PaddedSeparator();
|
||||
|
||||
// Random Ganon's Trials
|
||||
/*
|
||||
ImGui::Text("Random Ganon's Trials");
|
||||
InsertHelpHoverText("Sets a random number or required trials to enter\nGanon's Tower.");
|
||||
SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 2, 0);
|
||||
if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) {
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Text("Ganon's Trials");
|
||||
InsertHelpHoverText("Sets the number of Ganon's Trials required to dispel the barrier\n\n"
|
||||
"Skip - No Trials are required and the barrier is already dispelled.\n\n"
|
||||
"Set Number - Select a number of trials that will be required from the"
|
||||
"slider below. Which specific trials you need to complete will be random.\n\n"
|
||||
"Random Number - A Random number and set of trials will be required.");
|
||||
SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0);
|
||||
if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) {
|
||||
SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount",
|
||||
"gRandomizeGanonTrialCount", 0, 6, "", 6);
|
||||
"gRandomizeGanonTrialCount", 1, 6, "", 6);
|
||||
InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower.");
|
||||
RANDTODO: Switch back to slider when pre-completing some of Ganon's Trials is properly implemnted.
|
||||
}
|
||||
*/
|
||||
SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount");
|
||||
InsertHelpHoverText(
|
||||
"Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower.");
|
||||
}
|
||||
|
||||
// COLUMN 2 - Shuffle Settings
|
||||
@ -3120,6 +3574,20 @@ void DrawRandoEditor(bool& open) {
|
||||
SohImGui::EnhancementCombobox("gRandomizeShuffleSongs", randoShuffleSongs, 3, 0);
|
||||
PaddedSeparator();
|
||||
|
||||
// Shuffle Scrubs
|
||||
ImGui::Text(Settings::Scrubsanity.GetName().c_str());
|
||||
InsertHelpHoverText(
|
||||
"Off - Scrubs will not be shuffled. The 3 Scrubs that give one-time items in the vanilla game (PoH, Deku Nut capacity, and Deku Stick capacity) will have random items.\n"
|
||||
"\n"
|
||||
"Affordable - Scrubs will be shuffled and their item will cost 10 rupees.\n"
|
||||
"\n"
|
||||
"Expensive - Scrubs will be shuffled and their item will cost the vanilla price.\n"
|
||||
"\n"
|
||||
"Random - Scrubs will be shuffled and their item will cost will be between 0-95 rupees.\n"
|
||||
);
|
||||
SohImGui::EnhancementCombobox("gRandomizeShuffleScrubs", randoShuffleScrubs, 4, 0);
|
||||
PaddedSeparator();
|
||||
|
||||
// Shuffle Tokens
|
||||
ImGui::Text(Settings::Tokensanity.GetName().c_str());
|
||||
InsertHelpHoverText("Shuffles Golden Skulltula Tokens into the item pool. This means "
|
||||
@ -3140,10 +3608,10 @@ void DrawRandoEditor(bool& open) {
|
||||
"expected to be collected after getting Sun's Song.");
|
||||
PaddedSeparator();
|
||||
|
||||
|
||||
// Shuffle Cows
|
||||
SohImGui::EnhancementCheckbox(Settings::ShuffleCows.GetName().c_str(), "gRandomizeShuffleCows");
|
||||
InsertHelpHoverText(
|
||||
"Cows give a randomized item from the pool upon performing Epona's Song in front of them.");
|
||||
InsertHelpHoverText("Cows give a randomized item from the pool upon performing Epona's Song in front of them.");
|
||||
PaddedSeparator();
|
||||
|
||||
// Shuffle Adult Trade Quest
|
||||
@ -3159,6 +3627,11 @@ void DrawRandoEditor(bool& open) {
|
||||
"If disabled, only the Claim Check will be found in the pool.");
|
||||
PaddedSeparator();
|
||||
|
||||
SohImGui::EnhancementCheckbox(Settings::ShuffleMagicBeans.GetName().c_str(), "gRandomizeShuffleBeans");
|
||||
InsertHelpHoverText("Enabling this adds a pack of 10 beans to the item pool and changes the Magic Bean Salesman to sell a"
|
||||
"random item at a price of 60 rupees.");
|
||||
PaddedSeparator();
|
||||
|
||||
if (CVar_GetS32("gRandomizeStartingKokiriSword", 0) == 0) {
|
||||
// Shuffle Kokiri Sword
|
||||
SohImGui::EnhancementCheckbox(Settings::ShuffleKokiriSword.GetName().c_str(),
|
||||
@ -3745,12 +4218,20 @@ void CreateGetItemMessages(std::vector<GetItemMessage> messageEntries) {
|
||||
}
|
||||
}
|
||||
|
||||
void CreateScrubMessages() {
|
||||
// Currently these are generated at runtime, one for each price between 0-95. We're soon going to migrate this
|
||||
// to being generated at save load, with only messages specific to each scrub.
|
||||
void CreateMerchantMessages() {
|
||||
CustomMessageManager* customMessageManager = CustomMessageManager::Instance;
|
||||
customMessageManager->AddCustomMessageTable(Randomizer::scrubMessageTableID);
|
||||
const std::vector<u8> prices = { 10, 40 };
|
||||
for (u8 price : prices) {
|
||||
customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, price,
|
||||
customMessageManager->AddCustomMessageTable(Randomizer::merchantMessageTableID);
|
||||
customMessageManager->CreateMessage(Randomizer::merchantMessageTableID, 0,
|
||||
{ TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM,
|
||||
"\x12\x38\x82\All right! You win! In return for&sparing me, I will give you a&%gmysterious item%w!&Please, take it!\x07\x10\xA3",
|
||||
"\x12\x38\x82\In Ordnung! Du gewinnst! Im Austausch&dafür, dass du mich verschont hast,&werde ich dir einen %gmysteriösen&Gegenstand%w geben! Bitte nimm ihn!\x07\x10\xA3",
|
||||
"\x12\x38\x82\D'accord! Vous avez gagné! En échange&de m'épargner, je vous donnerai un &%gobjet mystérieux%w! S'il vous plaît,&prenez-le!\x07\x10\xA3",
|
||||
});
|
||||
|
||||
for (u32 price = 5; price <= 95; price += 5) {
|
||||
customMessageManager->CreateMessage(Randomizer::merchantMessageTableID, price,
|
||||
{ TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM,
|
||||
"\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" +
|
||||
std::to_string(price) + " Rupees%w it is!\x07\x10\xA3",
|
||||
@ -3761,6 +4242,18 @@ void CreateScrubMessages() {
|
||||
std::to_string(price) + " Rubis%w!\x07\x10\xA3"
|
||||
});
|
||||
}
|
||||
customMessageManager->CreateMessage(
|
||||
Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN,
|
||||
{
|
||||
TEXTBOX_TYPE_BLACK,
|
||||
TEXTBOX_POS_BOTTOM,
|
||||
"I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth "
|
||||
"beans!^Anyway, want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w",
|
||||
"Möchten Sie einen geheimnisvollen&Gegenstand für 60 Rubine?\x1B&%gJa&Nein%w",
|
||||
"J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça "
|
||||
"me courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&"
|
||||
"%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w",
|
||||
});
|
||||
}
|
||||
|
||||
void CreateRupeeMessages() {
|
||||
@ -3905,75 +4398,122 @@ void Randomizer::CreateCustomMessages() {
|
||||
const std::vector<GetItemMessage> getItemMessages = {
|
||||
GIMESSAGE(RG_ICE_TRAP, ITEM_NONE, "\x08\x06\x30You are a %bFOWL%w!\x0E\x20",
|
||||
"\x08\x06\x15 Du bist ein %bDUMMKOPF%w!\x0E\x20", "\x08\x06\x50%bIDIOT%w\x0E\x20"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE,
|
||||
"You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!",
|
||||
"Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"),
|
||||
GIMESSAGE_NO_GERMAN(
|
||||
RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!",
|
||||
"Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE,
|
||||
"You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!",
|
||||
"Vous obtenez une %rBouteille avec&une Âme%w! Vendez-la au Marchand&d'Âme"),
|
||||
"You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!",
|
||||
"Vous obtenez une %rBouteille avec&une Âme%w! Vendez-la au Marchand&d'Âme"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE,
|
||||
"You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!",
|
||||
"Vous obtenez une %rBouteille avec&une Potion Bleue%w! Buvez-la pour&restaurer votre %rénergie vitale%w&ainsi que votre %gmagie%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FISH, ITEM_FISH,
|
||||
"You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!",
|
||||
"Vous obtenez une %rBouteille avec&un Poisson%w! Il a l'air délicieux!&Il paraîtrait que %bJabu-Jabu %wen&serait friand!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BUGS, ITEM_BUG,
|
||||
"You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!",
|
||||
"Vous obtenez une %rBouteille avec&des Insectes%w! Ils adorent creuser&dans la terre meuble!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FAIRY, ITEM_FAIRY,
|
||||
"You got a %rFairy in a Bottle%w!&Use it wisely!",
|
||||
"Vous obtenez une %rBouteille avec&une Fée%w! Faites-en bon usage!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED,
|
||||
"You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!",
|
||||
"Vous obtenez une %rBouteille avec&une Potion Rouge%w! Buvez-la pour&restaurer votre %rénergie vitale%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN,
|
||||
"You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!",
|
||||
"Vous obtenez une %rBouteille avec&une Potion Verte%w! Buvez-la pour&restaurer votre %gmagie%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_POE, ITEM_POE,
|
||||
"You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this...",
|
||||
"Vous obtenez une %rBouteille avec&un Esprit%w! Ça intéresserait&peut-être le vendeur d'Âme "),
|
||||
"You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!",
|
||||
"Vous obtenez une %rBouteille avec&une Potion Bleue%w! Buvez-la pour&restaurer votre "
|
||||
"%rénergie vitale%w&ainsi que votre %gmagie%w!"),
|
||||
GIMESSAGE_NO_GERMAN(
|
||||
RG_BOTTLE_WITH_FISH, ITEM_FISH,
|
||||
"You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!",
|
||||
"Vous obtenez une %rBouteille avec&un Poisson%w! Il a l'air délicieux!&Il paraîtrait que %bJabu-Jabu "
|
||||
"%wen&serait friand!"),
|
||||
GIMESSAGE_NO_GERMAN(
|
||||
RG_BOTTLE_WITH_BUGS, ITEM_BUG, "You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!",
|
||||
"Vous obtenez une %rBouteille avec&des Insectes%w! Ils adorent creuser&dans la terre meuble!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FAIRY, ITEM_FAIRY, "You got a %rFairy in a Bottle%w!&Use it wisely!",
|
||||
"Vous obtenez une %rBouteille avec&une Fée%w! Faites-en bon usage!"),
|
||||
GIMESSAGE_NO_GERMAN(
|
||||
RG_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED,
|
||||
"You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!",
|
||||
"Vous obtenez une %rBouteille avec&une Potion Rouge%w! Buvez-la pour&restaurer votre %rénergie vitale%w!"),
|
||||
GIMESSAGE_NO_GERMAN(
|
||||
RG_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN,
|
||||
"You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!",
|
||||
"Vous obtenez une %rBouteille avec&une Potion Verte%w! Buvez-la pour&restaurer votre %gmagie%w!"),
|
||||
GIMESSAGE_NO_GERMAN(
|
||||
RG_BOTTLE_WITH_POE, ITEM_POE,
|
||||
"You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this...",
|
||||
"Vous obtenez une %rBouteille avec&un Esprit%w! Ça intéresserait&peut-être le vendeur d'Âme "),
|
||||
|
||||
GIMESSAGE_NO_GERMAN(RG_GERUDO_FORTRESS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yThieves Hideout &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yRepaire des Voleurs%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %gForest Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %gTemple de la Forêt%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rFire Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %rTemple du Feu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %bWater Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %bTemple de l'Eau%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %ySpirit Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yTemple de l'Esprit%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pShadow Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %pTemple de l'Ombre%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pBottom of the &Well %wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %Puits%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yGerudo Training &Grounds %wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yGymnase Gerudo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %Château de Ganon%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_GERUDO_FORTRESS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yThieves Hideout &%wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %yRepaire des Voleurs%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %gForest Temple &%wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %gTemple de la Forêt%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rFire Temple &%wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %rTemple du Feu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %bWater Temple &%wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %bTemple de l'Eau%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %ySpirit Temple &%wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %yTemple de l'Esprit%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pShadow Temple &%wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %pTemple de l'Ombre%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_SMALL_KEY, ITEM_KEY_SMALL,
|
||||
"You found a %pBottom of the &Well %wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %Puits%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, ITEM_KEY_SMALL,
|
||||
"You found a %yGerudo Training &Grounds %wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %yGymnase Gerudo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wSmall Key!",
|
||||
"Vous obtenez une %rPetite Clé %w&du %Château de Ganon%w!"),
|
||||
|
||||
GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %gForest Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%gTemple de la Forêt%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rFire Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%rTemple du Feu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %bWater Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%bTemple de l'Eau%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %ySpirit Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%yTemple de l'Esprit%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %pShadow Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%pTemple de l'Ombre%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rGanon's Castle &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%rChâteau de Ganon%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %gForest Temple &%wBoss Key!",
|
||||
"Vous obtenez la %rClé d'or %wdu&%gTemple de la Forêt%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rFire Temple &%wBoss Key!",
|
||||
"Vous obtenez la %rClé d'or %wdu&%rTemple du Feu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %bWater Temple &%wBoss Key!",
|
||||
"Vous obtenez la %rClé d'or %wdu&%bTemple de l'Eau%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %ySpirit Temple &%wBoss Key!",
|
||||
"Vous obtenez la %rClé d'or %wdu&%yTemple de l'Esprit%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %pShadow Temple &%wBoss Key!",
|
||||
"Vous obtenez la %rClé d'or %wdu&%pTemple de l'Ombre%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rGanon's Castle &%wBoss Key!",
|
||||
"Vous obtenez la %rClé d'or %wdu&%rChâteau de Ganon%w!"),
|
||||
|
||||
GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, "You found the %gDeku Tree &%wMap!", "Vous obtenez la %rCarte %wde&l'%gArbre Mojo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %rDodongo's Cavern &%wMap!", "Vous obtenez la %rCarte %wde la&%rCaverne Dodongo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, "You found the %bJabu Jabu's Belly &%wMap!", "Vous obtenez la %rCarte %wdu &%bVentre de Jabu-Jabu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %gForest Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%gTemple de la Forêt%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %rFire Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%rTemple du Feu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %bWater Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%bTemple de l'Eau%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %ySpirit Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%yTemple de l'Esprit%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %pShadow Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%pTemple de l'Ombre%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, "You found the %pBottom of the &Well %wMap!", "Vous obtenez la %rCarte %wdu &%pPuits%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %cIce Cavern &%wMap!", "Vous obtenez la %rCarte %wde &la %cCaverne Polaire%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, "You found the %gDeku Tree &%wMap!",
|
||||
"Vous obtenez la %rCarte %wde&l'%gArbre Mojo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %rDodongo's Cavern &%wMap!",
|
||||
"Vous obtenez la %rCarte %wde la&%rCaverne Dodongo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, "You found the %bJabu Jabu's Belly &%wMap!",
|
||||
"Vous obtenez la %rCarte %wdu &%bVentre de Jabu-Jabu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %gForest Temple &%wMap!",
|
||||
"Vous obtenez la %rCarte %wdu &%gTemple de la Forêt%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %rFire Temple &%wMap!",
|
||||
"Vous obtenez la %rCarte %wdu &%rTemple du Feu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %bWater Temple &%wMap!",
|
||||
"Vous obtenez la %rCarte %wdu &%bTemple de l'Eau%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %ySpirit Temple &%wMap!",
|
||||
"Vous obtenez la %rCarte %wdu &%yTemple de l'Esprit%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %pShadow Temple &%wMap!",
|
||||
"Vous obtenez la %rCarte %wdu &%pTemple de l'Ombre%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, "You found the %pBottom of the &Well %wMap!",
|
||||
"Vous obtenez la %rCarte %wdu &%pPuits%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %cIce Cavern &%wMap!",
|
||||
"Vous obtenez la %rCarte %wde &la %cCaverne Polaire%w!"),
|
||||
|
||||
GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_COMPASS, ITEM_COMPASS, "You found the %gDeku Tree &%wCompass!", "Vous obtenez la %rBoussole %wde&l'%gArbre Mojo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, "You found the %rDodongo's Cavern &%wCompass!", "Vous obtenez la %rBoussole %wde la&%rCaverne Dodongo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, "You found the %bJabu Jabu's Belly &%wCompass!", "Vous obtenez la %rBoussole %wdu &%bVentre de Jabu-Jabu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %gForest Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%gTemple de la Forêt%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %rFire Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%rTemple du Feu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %bWater Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%bTemple de l'Eau%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %ySpirit Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%yTemple de l'Esprit%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %pShadow Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%pTemple de l'Ombre%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS, "You found the %pBottom of the &Well %wCompass!", "Vous obtenez la %rBoussole %wdu &%pPuits%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_COMPASS, ITEM_COMPASS, "You found the %cIce Cavern &%wCompass!", "Vous obtenez la %rBoussole %wde &la %cCaverne Polaire%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_COMPASS, ITEM_COMPASS, "You found the %gDeku Tree &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wde&l'%gArbre Mojo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, "You found the %rDodongo's Cavern &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wde la&%rCaverne Dodongo%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, "You found the %bJabu Jabu's Belly &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wdu &%bVentre de Jabu-Jabu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %gForest Temple &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wdu &%gTemple de la Forêt%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %rFire Temple &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wdu &%rTemple du Feu%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %bWater Temple &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wdu &%bTemple de l'Eau%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %ySpirit Temple &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wdu &%yTemple de l'Esprit%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %pShadow Temple &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wdu &%pTemple de l'Ombre%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS,
|
||||
"You found the %pBottom of the &Well %wCompass!",
|
||||
"Vous obtenez la %rBoussole %wdu &%pPuits%w!"),
|
||||
GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_COMPASS, ITEM_COMPASS, "You found the %cIce Cavern &%wCompass!",
|
||||
"Vous obtenez la %rBoussole %wde &la %cCaverne Polaire%w!"),
|
||||
GIMESSAGE(RG_MAGIC_BEAN_PACK, ITEM_BEAN,
|
||||
"You got a %rPack of Magic Beans%w!&Find a suitable spot for a garden&and plant them. Then, wait for&something fun to happen!",
|
||||
"Du hast eine %rPackung&Magic Beans%w! Finde&einen geeigneten Platz fur einen&Garten und pflanze sie. Dann^warte auf etwas Lustiges passiert!",
|
||||
"Vous avez un %rPack de&haricots magiques%w ! Trouvez&un endroit convenable pour un&jardin et plantez-les.^Ensuite, attendez quelque&chose d'amusant doit arriver !")
|
||||
};
|
||||
CreateGetItemMessages(getItemMessages);
|
||||
CreateScrubMessages();
|
||||
CreateMerchantMessages();
|
||||
CreateRupeeMessages();
|
||||
CreateNaviRandoMessages();
|
||||
}
|
||||
@ -4070,6 +4610,7 @@ void InitRandoItemTable() {
|
||||
GET_ITEM(RG_SHADOW_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_SHADOW_TEMPLE_COMPASS),
|
||||
GET_ITEM(RG_BOTTOM_OF_THE_WELL_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_BOTTOM_OF_THE_WELL_COMPASS),
|
||||
GET_ITEM(RG_ICE_CAVERN_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_ICE_CAVERN_COMPASS),
|
||||
GET_ITEM(RG_MAGIC_BEAN_PACK, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_MAGIC_BEAN_PACK)
|
||||
};
|
||||
ItemTableManager::Instance->AddItemTable(MOD_RANDOMIZER);
|
||||
for (int i = 0; i < ARRAY_COUNT(extendedVanillaGetItemTable); i++) {
|
||||
|
@ -14,15 +14,18 @@ class Randomizer {
|
||||
private:
|
||||
std::unordered_map<RandomizerCheck, RandomizerGet> itemLocations;
|
||||
std::unordered_map<RandomizerCheck, std::string> hintLocations;
|
||||
std::unordered_map<RandomizerInf, bool> trialsRequired;
|
||||
std::string childAltarText;
|
||||
std::string adultAltarText;
|
||||
std::string ganonHintText;
|
||||
std::string ganonText;
|
||||
std::unordered_map<RandomizerSettingKey, u8> randoSettings;
|
||||
std::unordered_map<RandomizerCheck, u16> randomizerMerchantPrices;
|
||||
s16 GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId);
|
||||
s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId);
|
||||
void ParseRandomizerSettingsFile(const char* spoilerFileName);
|
||||
void ParseHintLocationsFile(const char* spoilerFileName);
|
||||
void ParseRequiredTrialsFile(const char* spoilerFileName);
|
||||
void ParseItemLocationsFile(const char* spoilerFileName, bool silent);
|
||||
bool IsItemVanilla(RandomizerGet randoGet);
|
||||
|
||||
@ -33,7 +36,7 @@ class Randomizer {
|
||||
|
||||
static const std::string getItemMessageTableID;
|
||||
static const std::string hintMessageTableID;
|
||||
static const std::string scrubMessageTableID;
|
||||
static const std::string merchantMessageTableID;
|
||||
static const std::string rupeeMessageTableID;
|
||||
static const std::string NaviRandoMessageTableID;
|
||||
|
||||
@ -43,13 +46,16 @@ class Randomizer {
|
||||
bool SpoilerFileExists(const char* spoilerFileName);
|
||||
void LoadRandomizerSettings(const char* spoilerFileName);
|
||||
void LoadHintLocations(const char* spoilerFileName);
|
||||
void LoadItemLocations(const char* spoilerFileName, bool silent);
|
||||
void LoadRequiredTrials(const char* spoilerFileName);
|
||||
void LoadItemLocations(const char* spoilerFileName,bool silent);
|
||||
bool IsTrialRequired(RandomizerInf trial);
|
||||
u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey);
|
||||
RandomizerCheck GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams);
|
||||
std::string GetChildAltarText() const;
|
||||
std::string GetAdultAltarText() const;
|
||||
std::string GetGanonText() const;
|
||||
std::string GetGanonHintText() const;
|
||||
ScrubIdentity IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData);
|
||||
s16 GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
|
||||
s16 GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum);
|
||||
static void CreateCustomMessages();
|
||||
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "z64item.h"
|
||||
#include "randomizer_inf.h"
|
||||
|
||||
// This should probably go in a less rando-specific location
|
||||
// but the best location will probably be in the modding engine
|
||||
@ -987,6 +989,7 @@ typedef enum {
|
||||
RSK_SHUFFLE_DUNGEON_REWARDS,
|
||||
RSK_SHUFFLE_SONGS,
|
||||
RSK_SHUFFLE_TOKENS,
|
||||
RSK_SHUFFLE_SCRUBS,
|
||||
RSK_SHUFFLE_COWS,
|
||||
RSK_SHUFFLE_WEIRD_EGG,
|
||||
RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD,
|
||||
@ -1014,5 +1017,14 @@ typedef enum {
|
||||
RSK_ENABLE_GLITCH_CUTSCENES,
|
||||
RSK_SKULLS_SUNS_SONG,
|
||||
RSK_SHUFFLE_ADULT_TRADE,
|
||||
RSK_SHUFFLE_MAGIC_BEANS,
|
||||
RSK_BOMBCHUS_IN_LOGIC
|
||||
} RandomizerSettingKey;
|
||||
|
||||
typedef struct ScrubIdentity {
|
||||
RandomizerInf randomizerInf;
|
||||
RandomizerCheck randomizerCheck;
|
||||
GetItemID getItemId;
|
||||
int32_t itemPrice;
|
||||
bool isShuffled;
|
||||
} ScrubIdentity;
|
||||
|
@ -29,6 +29,43 @@ typedef enum {
|
||||
RAND_INF_COWS_MILKED_JABU_JABUS_BELLY_MQ_COW,
|
||||
RAND_INF_COWS_MILKED_HF_COW_GROTTO_GOSSIP_STONE,
|
||||
|
||||
RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT,
|
||||
RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS,
|
||||
RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT,
|
||||
RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY,
|
||||
RAND_INF_SCRUBS_PURCHASED_JABU_JABUS_BELLY_DEKU_SCRUB,
|
||||
RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT,
|
||||
RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT,
|
||||
RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_RIGHT,
|
||||
RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_LEFT,
|
||||
RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO,
|
||||
RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_REAR,
|
||||
RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_FRONT,
|
||||
RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_REAR,
|
||||
RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_FRONT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_LEFT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_RIGHT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_CENTER,
|
||||
RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_REAR,
|
||||
RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_FRONT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_REAR,
|
||||
RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT,
|
||||
RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_LEFT,
|
||||
RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_RIGHT,
|
||||
RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_CENTER,
|
||||
RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_LEFT,
|
||||
RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_RIGHT,
|
||||
RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_CENTER,
|
||||
RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_LEFT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_RIGHT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_CENTER,
|
||||
RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_REAR,
|
||||
RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT,
|
||||
RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE,
|
||||
RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB,
|
||||
|
||||
// If you add anything to this list, you need to update the size of randomizerInf in z64save.h to be ceil(RAND_INF_MAX / 16)
|
||||
|
||||
RAND_INF_MAX,
|
||||
|
@ -1562,10 +1562,18 @@ extern "C" void Randomizer_LoadHintLocations(const char* spoilerFileName) {
|
||||
OTRGlobals::Instance->gRandomizer->LoadHintLocations(spoilerFileName);
|
||||
}
|
||||
|
||||
extern "C" void Randomizer_LoadRequiredTrials(const char* spoilerFileName) {
|
||||
OTRGlobals::Instance->gRandomizer->LoadRequiredTrials(spoilerFileName);
|
||||
}
|
||||
|
||||
extern "C" void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent) {
|
||||
OTRGlobals::Instance->gRandomizer->LoadItemLocations(spoilerFileName, silent);
|
||||
}
|
||||
|
||||
extern "C" bool Randomizer_IsTrialRequired(RandomizerInf trial) {
|
||||
return OTRGlobals::Instance->gRandomizer->IsTrialRequired(trial);
|
||||
}
|
||||
|
||||
extern "C" bool SpoilerFileExists(const char* spoilerFileName) {
|
||||
return OTRGlobals::Instance->gRandomizer->SpoilerFileExists(spoilerFileName);
|
||||
}
|
||||
@ -1578,18 +1586,12 @@ extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 sceneNum, s16 actorI
|
||||
return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams);
|
||||
}
|
||||
|
||||
extern "C" CustomMessageEntry Randomizer_GetScrubMessage(u16 scrubTextId) {
|
||||
int price = 0;
|
||||
switch (scrubTextId) {
|
||||
case TEXT_SCRUB_POH:
|
||||
price = 10;
|
||||
break;
|
||||
case TEXT_SCRUB_STICK_UPGRADE:
|
||||
case TEXT_SCRUB_NUT_UPGRADE:
|
||||
price = 40;
|
||||
break;
|
||||
}
|
||||
return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, price);
|
||||
extern "C" ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData) {
|
||||
return OTRGlobals::Instance->gRandomizer->IdentifyScrub(sceneNum, actorParams, respawnData);
|
||||
}
|
||||
|
||||
extern "C" CustomMessageEntry Randomizer_GetScrubMessage(s16 itemPrice) {
|
||||
return CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, itemPrice);
|
||||
}
|
||||
|
||||
extern "C" CustomMessageEntry Randomizer_GetNaviMessage() {
|
||||
@ -1650,15 +1652,14 @@ extern "C" GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomi
|
||||
return ItemTable_RetrieveEntry(getItemModIndex, itemID);
|
||||
}
|
||||
|
||||
extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor) {
|
||||
return gSaveContext.n64ddFlag && (actor->parent != NULL) &&
|
||||
Randomizer_GetItemFromKnownCheck(randomizerCheck, ogId).getItemId == RG_ICE_TRAP;
|
||||
}
|
||||
|
||||
extern "C" bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId) {
|
||||
return gSaveContext.n64ddFlag && Randomizer_GetItemFromKnownCheck(randomizerCheck, ogId).getItemId == RG_ICE_TRAP;
|
||||
}
|
||||
|
||||
extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor) {
|
||||
return Randomizer_ItemIsIceTrap(randomizerCheck, ogId) && actor->parent != NULL;
|
||||
}
|
||||
|
||||
extern "C" CustomMessageEntry Randomizer_GetCustomGetItemMessage(Player* player) {
|
||||
s16 giid;
|
||||
if (player->getItemEntry.objectId != OBJECT_INVALID) {
|
||||
@ -1718,8 +1719,8 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) {
|
||||
} else {
|
||||
messageEntry = Randomizer_GetGanonHintText();
|
||||
}
|
||||
} else if (textId == TEXT_SCRUB_POH || textId == TEXT_SCRUB_STICK_UPGRADE || textId == TEXT_SCRUB_NUT_UPGRADE) {
|
||||
messageEntry = Randomizer_GetScrubMessage(textId);
|
||||
} else if (textId >= 0x9000 && textId <= 0x905F) {
|
||||
messageEntry = Randomizer_GetScrubMessage((textId & ((1 << 8) - 1)));
|
||||
} else if (CVar_GetS32("gRandomizeRupeeNames", 0) &&
|
||||
(textId == TEXT_BLUE_RUPEE || textId == TEXT_RED_RUPEE || textId == TEXT_PURPLE_RUPEE ||
|
||||
textId == TEXT_HUGE_RUPEE)) {
|
||||
@ -1727,6 +1728,8 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) {
|
||||
// In rando, replace Navi's general overworld hints with rando-related gameplay tips
|
||||
} else if (CVar_GetS32("gRandoRelevantNavi", 1) && textId >= 0x0140 && textId <= 0x015F) {
|
||||
messageEntry = Randomizer_GetNaviMessage();
|
||||
} else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESMAN) {
|
||||
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN);
|
||||
} else if (Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) &&
|
||||
(textId == TEXT_BUY_BOMBCHU_10_DESC || textId == TEXT_BUY_BOMBCHU_10_PROMPT)) {
|
||||
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId);
|
||||
|
@ -96,8 +96,11 @@ Sprite* GetSeedTexture(uint8_t index);
|
||||
void Randomizer_LoadSettings(const char* spoilerFileName);
|
||||
u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
|
||||
RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum);
|
||||
ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData);
|
||||
void Randomizer_LoadHintLocations(const char* spoilerFileName);
|
||||
void Randomizer_LoadRequiredTrials(const char* spoilerFileName);
|
||||
void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent);
|
||||
bool Randomizer_IsTrialRequired(RandomizerInf trial);
|
||||
GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum);
|
||||
GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
|
||||
bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor);
|
||||
|
@ -1290,6 +1290,7 @@ void EnItem00_CustomItemsParticles(Actor* Parent, GlobalContext* globalCtx, GetI
|
||||
switch (giEntry.itemId) {
|
||||
case RG_MAGIC_SINGLE:
|
||||
case RG_MAGIC_DOUBLE:
|
||||
case RG_MAGIC_BEAN_PACK:
|
||||
color_slot = 0;
|
||||
break;
|
||||
case RG_DOUBLE_DEFENSE:
|
||||
|
@ -1642,12 +1642,16 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
|
||||
} else if ((item >= ITEM_SWORD_KOKIRI) && (item <= ITEM_SWORD_BGS)) {
|
||||
gSaveContext.inventory.equipment |= gBitFlags[item - ITEM_SWORD_KOKIRI] << gEquipShifts[EQUIP_SWORD];
|
||||
|
||||
// Both Giant's Knife and Biggoron Sword have the same Item ID, so this part handles both of them
|
||||
if (item == ITEM_SWORD_BGS) {
|
||||
gSaveContext.swordHealth = 8;
|
||||
|
||||
if (ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xF
|
||||
||(gSaveContext.n64ddFlag && ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xE)) { // In rando, when buying Giant's Knife, also check
|
||||
gSaveContext.inventory.equipment ^= 8 << gEquipShifts[EQUIP_SWORD]; // for 0xE in case we don't have Kokiri Sword
|
||||
// In rando, when buying Giant's Knife, also check
|
||||
// for 0xE in case we don't have Kokiri Sword
|
||||
if (ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xF || (gSaveContext.n64ddFlag && ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xE)) {
|
||||
|
||||
gSaveContext.inventory.equipment ^= 8 << gEquipShifts[EQUIP_SWORD];
|
||||
|
||||
if (gSaveContext.equips.buttonItems[0] == ITEM_SWORD_KNIFE) {
|
||||
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_BGS;
|
||||
Interface_LoadItemIcon1(globalCtx, 0);
|
||||
@ -1686,6 +1690,28 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
|
||||
}
|
||||
return ITEM_NONE;
|
||||
} else if (item == ITEM_KEY_SMALL) {
|
||||
// Small key exceptions for rando with keysanity off.
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
if (globalCtx->sceneNum == 10) { // ganon's tower -> ganon's castle
|
||||
if (gSaveContext.inventory.dungeonKeys[13] < 0) {
|
||||
gSaveContext.inventory.dungeonKeys[13] = 1;
|
||||
return ITEM_NONE;
|
||||
} else {
|
||||
gSaveContext.inventory.dungeonKeys[13]++;
|
||||
return ITEM_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (globalCtx->sceneNum == 92) { // Desert Colossus -> Spirit Temple.
|
||||
if (gSaveContext.inventory.dungeonKeys[6] < 0) {
|
||||
gSaveContext.inventory.dungeonKeys[6] = 1;
|
||||
return ITEM_NONE;
|
||||
} else {
|
||||
gSaveContext.inventory.dungeonKeys[6]++;
|
||||
return ITEM_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) {
|
||||
gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1;
|
||||
return ITEM_NONE;
|
||||
@ -2177,6 +2203,14 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) {
|
||||
return RG_NONE;
|
||||
}
|
||||
|
||||
if (item == RG_MAGIC_BEAN_PACK) {
|
||||
if (INV_CONTENT(ITEM_BEAN) == ITEM_NONE) {
|
||||
INV_CONTENT(ITEM_BEAN) = ITEM_BEAN;
|
||||
AMMO(ITEM_BEAN) = 10;
|
||||
}
|
||||
return RG_NONE;
|
||||
}
|
||||
|
||||
if (item == RG_DOUBLE_DEFENSE) {
|
||||
gSaveContext.doubleDefense = true;
|
||||
gSaveContext.inventory.defenseHearts = 20;
|
||||
@ -2223,9 +2257,9 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) {
|
||||
}
|
||||
}
|
||||
} else if ((item >= RG_FOREST_TEMPLE_SMALL_KEY && item <= RG_GANONS_CASTLE_SMALL_KEY) ||
|
||||
(item >= RG_FOREST_TEMPLE_BOSS_KEY && item <= RG_GANONS_CASTLE_BOSS_KEY) ||
|
||||
(item >= RG_DEKU_TREE_MAP && item <= RG_ICE_CAVERN_MAP) ||
|
||||
(item >= RG_DEKU_TREE_COMPASS && item <= RG_ICE_CAVERN_COMPASS)) {
|
||||
(item >= RG_FOREST_TEMPLE_BOSS_KEY && item <= RG_GANONS_CASTLE_BOSS_KEY) ||
|
||||
(item >= RG_DEKU_TREE_MAP && item <= RG_ICE_CAVERN_MAP) ||
|
||||
(item >= RG_DEKU_TREE_COMPASS && item <= RG_ICE_CAVERN_COMPASS)) {
|
||||
int mapIndex = gSaveContext.mapIndex;
|
||||
switch (item) {
|
||||
case RG_DEKU_TREE_MAP:
|
||||
@ -2323,7 +2357,6 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) {
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
u8 Item_CheckObtainability(u8 item) {
|
||||
s16 i;
|
||||
s16 slot = SLOT(item);
|
||||
|
@ -255,10 +255,10 @@ void GivePlayerRandoRewardSariaGift(GlobalContext* globalCtx, RandomizerCheck ch
|
||||
if (gSaveContext.entranceIndex == 0x05E0) {
|
||||
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(check, RG_ZELDAS_LULLABY);
|
||||
|
||||
if ((!Flags_GetEventChkInf(0xC1) || (player->getItemId == getItemEntry.getItemId && getItemEntry.getItemId != GI_ICE_TRAP)) &&
|
||||
player != NULL && !Player_InBlockingCsMode(globalCtx, player)) {
|
||||
if (!Flags_GetEventChkInf(0xC1) && player != NULL && !Player_InBlockingCsMode(globalCtx, player)) {
|
||||
GiveItemEntryWithoutActor(globalCtx, getItemEntry);
|
||||
Flags_SetEventChkInf(0xC1);
|
||||
player->pendingFlag.flagType = FLAG_EVENT_CHECK_INF;
|
||||
player->pendingFlag.flagID = 0xC1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,11 @@
|
||||
#include <string.h>
|
||||
#include <soh/Enhancements/randomizer/randomizerTypes.h>
|
||||
#include <soh/Enhancements/randomizer/randomizer_inf.h>
|
||||
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
|
||||
|
||||
#define NUM_DUNGEONS 8
|
||||
#define NUM_TRIALS 6
|
||||
#define NUM_COWS 10
|
||||
#define NUM_SCRUBS 35
|
||||
|
||||
/**
|
||||
* Initialize new save.
|
||||
@ -308,6 +309,11 @@ void GiveLinkDekuNutUpgrade(GetItemID giid) {
|
||||
}
|
||||
}
|
||||
|
||||
void GiveLinkSkullToken() {
|
||||
gSaveContext.inventory.questItems |= gBitFlags[QUEST_SKULL_TOKEN];
|
||||
gSaveContext.inventory.gsTokens++;
|
||||
}
|
||||
|
||||
void GiveLinkMagic(GetItemID giid) {
|
||||
if (giid == RG_MAGIC_SINGLE) {
|
||||
gSaveContext.magicLevel = 1;
|
||||
@ -507,6 +513,53 @@ void GiveLinkDungeonItem(GetItemID getItemId) {
|
||||
}
|
||||
}
|
||||
|
||||
void GiveLinkAdultTradeItem(GetItemID giid) {
|
||||
ItemID item;
|
||||
switch (giid) {
|
||||
case GI_POCKET_EGG:
|
||||
item = ITEM_POCKET_EGG;
|
||||
break;
|
||||
case GI_POCKET_CUCCO:
|
||||
item = ITEM_POCKET_CUCCO;
|
||||
break;
|
||||
case GI_COJIRO:
|
||||
item = ITEM_COJIRO;
|
||||
break;
|
||||
case GI_ODD_MUSHROOM:
|
||||
item = ITEM_ODD_MUSHROOM;
|
||||
break;
|
||||
case GI_ODD_POTION:
|
||||
item = ITEM_ODD_POTION;
|
||||
break;
|
||||
case GI_SAW:
|
||||
item = ITEM_SAW;
|
||||
break;
|
||||
case GI_SWORD_BROKEN:
|
||||
item = ITEM_SWORD_BROKEN;
|
||||
break;
|
||||
case GI_PRESCRIPTION:
|
||||
item = ITEM_PRESCRIPTION;
|
||||
break;
|
||||
case GI_FROG:
|
||||
item = ITEM_FROG;
|
||||
break;
|
||||
case GI_EYEDROPS:
|
||||
item = ITEM_EYEDROPS;
|
||||
break;
|
||||
case GI_CLAIM_CHECK:
|
||||
item = ITEM_CLAIM_CHECK;
|
||||
break;
|
||||
}
|
||||
if ((item == ITEM_SAW) && CVar_GetS32("gDekuNutUpgradeFix", 0) == 0) {
|
||||
gSaveContext.itemGetInf[1] |= 0x8000;
|
||||
}
|
||||
|
||||
if (item >= ITEM_POCKET_EGG) {
|
||||
gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item);
|
||||
}
|
||||
INV_CONTENT(ITEM_TRADE_ADULT) = item;
|
||||
}
|
||||
|
||||
void GiveLinksPocketMedallion() {
|
||||
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, RG_NONE);
|
||||
|
||||
@ -708,6 +761,15 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
|
||||
gSaveContext.randomizerInf[i] = 0;
|
||||
}
|
||||
|
||||
// Set all trials to cleared if trial count is random or anything other than 6
|
||||
if (Randomizer_GetSettingValue(RSK_RANDOM_TRIALS) || (Randomizer_GetSettingValue(RSK_TRIAL_COUNT) != 6)) {
|
||||
for (u16 i = RAND_INF_TRIALS_DONE_LIGHT_TRIAL; i <= RAND_INF_TRIALS_DONE_SHADOW_TRIAL; i++) {
|
||||
if (!Randomizer_IsTrialRequired(i)) {
|
||||
Flags_SetRandomizerInf(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set Cutscene flags to skip them
|
||||
gSaveContext.eventChkInf[0xC] |= 0x10; // returned to tot with medallions
|
||||
gSaveContext.eventChkInf[0xC] |= 0x20; //sheik at tot pedestal
|
||||
@ -734,6 +796,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
|
||||
gSaveContext.eventChkInf[3] |= 0x800;
|
||||
gSaveContext.eventChkInf[12] |= 1;
|
||||
|
||||
// shuffle adult trade quest
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) {
|
||||
gSaveContext.adultTradeItems = 0;
|
||||
}
|
||||
|
||||
// Give Link's pocket item
|
||||
GiveLinksPocketMedallion();
|
||||
|
||||
@ -791,7 +858,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
|
||||
s32 giid = getItem.getItemId;
|
||||
|
||||
if (getItem.modIndex == MOD_NONE) {
|
||||
if(getItem.itemId >= ITEM_KOKIRI_EMERALD && getItem.itemId <= ITEM_MEDALLION_LIGHT) {
|
||||
if (getItem.itemId >= ITEM_MEDALLION_FOREST && getItem.itemId <= ITEM_ZORA_SAPPHIRE) {
|
||||
GiveLinkDungeonReward(getItem.getItemId);
|
||||
} else if (giid == GI_RUPEE_GREEN || giid == GI_RUPEE_BLUE || giid == GI_RUPEE_RED ||
|
||||
giid == GI_RUPEE_PURPLE || giid == GI_RUPEE_GOLD) {
|
||||
@ -848,6 +915,10 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
|
||||
GiveLinkDekuStickUpgrade(giid);
|
||||
} else if (giid == GI_NUT_UPGRADE_30 || giid == GI_NUT_UPGRADE_40) {
|
||||
GiveLinkDekuNutUpgrade(giid);
|
||||
} else if (giid == GI_SKULL_TOKEN) {
|
||||
GiveLinkSkullToken();
|
||||
} else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK || giid == GI_COJIRO) {
|
||||
GiveLinkAdultTradeItem(giid);
|
||||
} else {
|
||||
s32 iid = getItem.itemId;
|
||||
if (iid != -1) INV_CONTENT(iid) = iid;
|
||||
@ -964,11 +1035,6 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
|
||||
}
|
||||
}
|
||||
|
||||
// shuffle adult trade quest
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) {
|
||||
gSaveContext.adultTradeItems = 0;
|
||||
}
|
||||
|
||||
// complete mask quest
|
||||
if (Randomizer_GetSettingValue(RSK_COMPLETE_MASK_QUEST)) {
|
||||
gSaveContext.itemGetInf[3] |= 0x100; // Sold Keaton Mask
|
||||
|
@ -64,12 +64,33 @@ static u8 sEnergyColors[] = {
|
||||
/* Forest prim */ 255, 255, 170, /* env */ 0, 200, 0,
|
||||
};
|
||||
|
||||
// Translates from the barrier's actor params to their corresponding randInf flags.
|
||||
RandomizerInf trialParamToRandInf(u16 params) {
|
||||
switch (params) {
|
||||
case KEKKAI_LIGHT:
|
||||
return RAND_INF_TRIALS_DONE_LIGHT_TRIAL;
|
||||
case KEKKAI_FOREST:
|
||||
return RAND_INF_TRIALS_DONE_FOREST_TRIAL;
|
||||
case KEKKAI_FIRE:
|
||||
return RAND_INF_TRIALS_DONE_FIRE_TRIAL;
|
||||
case KEKKAI_WATER:
|
||||
return RAND_INF_TRIALS_DONE_WATER_TRIAL;
|
||||
case KEKKAI_SPIRIT:
|
||||
return RAND_INF_TRIALS_DONE_SPIRIT_TRIAL;
|
||||
case KEKKAI_SHADOW:
|
||||
return RAND_INF_TRIALS_DONE_SHADOW_TRIAL;
|
||||
}
|
||||
}
|
||||
|
||||
s32 DemoKekkai_CheckEventFlag(s32 params) {
|
||||
static s32 eventFlags[] = { 0xC3, 0xBC, 0xBF, 0xBE, 0xBD, 0xAD, 0xBB };
|
||||
|
||||
if ((params < KEKKAI_TOWER) || (params > KEKKAI_FOREST)) {
|
||||
return true;
|
||||
}
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
return Flags_GetRandomizerInf(trialParamToRandInf(params));
|
||||
}
|
||||
return Flags_GetEventChkInf(eventFlags[params]);
|
||||
}
|
||||
|
||||
@ -128,8 +149,7 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
this->collider2.dim.yShift = 300;
|
||||
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
int trialsToComplete = Randomizer_GetSettingValue(RSK_TRIAL_COUNT);
|
||||
if (trialsToComplete <= TrialsDoneCount()) {
|
||||
if (TrialsDoneCount() == NUM_TRIALS) {
|
||||
Actor_Kill(thisx);
|
||||
return;
|
||||
}
|
||||
@ -141,6 +161,10 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
case KEKKAI_SHADOW:
|
||||
case KEKKAI_SPIRIT:
|
||||
case KEKKAI_FOREST:
|
||||
if (gSaveContext.n64ddFlag && Flags_GetRandomizerInf(trialParamToRandInf(thisx->params))) {
|
||||
Actor_Kill(thisx);
|
||||
return;
|
||||
}
|
||||
this->energyAlpha = 1.0f;
|
||||
this->orbScale = 1.0f;
|
||||
Actor_SetScale(thisx, 0.1f);
|
||||
@ -247,26 +271,9 @@ void DemoKekkai_TrialBarrierDispel(Actor* thisx, GlobalContext* globalCtx) {
|
||||
DemoKekkai* this = (DemoKekkai*)thisx;
|
||||
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
switch (thisx->params) {
|
||||
case KEKKAI_WATER:
|
||||
Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_WATER_TRIAL);
|
||||
break;
|
||||
case KEKKAI_LIGHT:
|
||||
Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_LIGHT_TRIAL);
|
||||
break;
|
||||
case KEKKAI_FIRE:
|
||||
Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_FIRE_TRIAL);
|
||||
break;
|
||||
case KEKKAI_SHADOW:
|
||||
Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_SHADOW_TRIAL);
|
||||
break;
|
||||
case KEKKAI_SPIRIT:
|
||||
Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_SPIRIT_TRIAL);
|
||||
break;
|
||||
case KEKKAI_FOREST:
|
||||
Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_FOREST_TRIAL);
|
||||
break;
|
||||
}
|
||||
Flags_SetRandomizerInf(trialParamToRandInf(thisx->params));
|
||||
// May or may not be needed. Not sure if needed for anything
|
||||
// that randoInf isn't already covering. Leaving it for safety.
|
||||
Flags_SetEventChkInf(eventFlags[thisx->params]);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ void EnDns_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnDns_Update(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnDns_Draw(Actor* thisx, GlobalContext* globalCtx);
|
||||
|
||||
u32 EnDns_RandomizerPurchaseableCheck(EnDns* this);
|
||||
u32 func_809EF5A4(EnDns* this);
|
||||
u32 func_809EF658(EnDns* this);
|
||||
u32 func_809EF70C(EnDns* this);
|
||||
@ -24,6 +25,7 @@ u32 func_809EF854(EnDns* this);
|
||||
u32 func_809EF8F4(EnDns* this);
|
||||
u32 func_809EF9A4(EnDns* this);
|
||||
|
||||
void EnDns_RandomizerPurchase(EnDns* this);
|
||||
void func_809EF9F8(EnDns* this);
|
||||
void func_809EFA28(EnDns* this);
|
||||
void func_809EFA58(EnDns* this);
|
||||
@ -155,7 +157,6 @@ void EnDns_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
Collider_InitCylinder(globalCtx, &this->collider);
|
||||
Collider_SetCylinderType1(globalCtx, &this->collider, &this->actor, &sCylinderInit);
|
||||
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 35.0f);
|
||||
this->actor.textId = D_809F040C[this->actor.params];
|
||||
Actor_SetScale(&this->actor, 0.01f);
|
||||
this->actor.colChkInfo.mass = MASS_IMMOVABLE;
|
||||
this->maintainCollider = 1;
|
||||
@ -164,7 +165,27 @@ void EnDns_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
this->actor.speedXZ = 0.0f;
|
||||
this->actor.velocity.y = 0.0f;
|
||||
this->actor.gravity = -1.0f;
|
||||
this->actor.textId = D_809F040C[this->actor.params];
|
||||
this->dnsItemEntry = sItemEntries[this->actor.params];
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
// Ugly, but the best way we can identify which grotto we are in, same method 3DRando uses, but we'll need to account for entrance rando
|
||||
s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1);
|
||||
this->scrubIdentity = Randomizer_IdentifyScrub(globalCtx->sceneNum, this->actor.params, respawnData);
|
||||
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == 1 || Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == 3 && this->scrubIdentity.itemPrice != -1) {
|
||||
this->dnsItemEntry->itemPrice = this->scrubIdentity.itemPrice;
|
||||
}
|
||||
|
||||
if (this->scrubIdentity.isShuffled) {
|
||||
this->dnsItemEntry->getItemId = this->scrubIdentity.getItemId;
|
||||
this->dnsItemEntry->purchaseableCheck = EnDns_RandomizerPurchaseableCheck;
|
||||
this->dnsItemEntry->setRupeesAndFlags = EnDns_RandomizerPurchase;
|
||||
this->dnsItemEntry->itemAmount = 1;
|
||||
// Currently the textID is simply identified by the item price since that is the only thing
|
||||
// unique to it, later on this will change to identifying by scrubIdentity.randomizerInf
|
||||
this->actor.textId = 0x9000 + this->dnsItemEntry->itemPrice;
|
||||
}
|
||||
}
|
||||
this->actionFunc = EnDns_SetupWait;
|
||||
}
|
||||
|
||||
@ -185,6 +206,13 @@ void EnDns_ChangeAnim(EnDns* this, u8 index) {
|
||||
|
||||
/* Item give checking functions */
|
||||
|
||||
u32 EnDns_RandomizerPurchaseableCheck(EnDns* this) {
|
||||
if (gSaveContext.rupees < this->dnsItemEntry->itemPrice || Flags_GetRandomizerInf(this->scrubIdentity.randomizerInf)) {
|
||||
return 0;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
u32 func_809EF5A4(EnDns* this) {
|
||||
if ((CUR_CAPACITY(UPG_NUTS) != 0) && (AMMO(ITEM_NUT) >= CUR_CAPACITY(UPG_NUTS))) {
|
||||
return 1;
|
||||
@ -281,6 +309,10 @@ u32 func_809EF9A4(EnDns* this) {
|
||||
}
|
||||
|
||||
/* Paying and flagging functions */
|
||||
void EnDns_RandomizerPurchase(EnDns* this) {
|
||||
Rupees_ChangeBy(-this->dnsItemEntry->itemPrice);
|
||||
Flags_SetRandomizerInf(this->scrubIdentity.randomizerInf);
|
||||
}
|
||||
|
||||
void func_809EF9F8(EnDns* this) {
|
||||
Rupees_ChangeBy(-this->dnsItemEntry->itemPrice);
|
||||
@ -369,31 +401,25 @@ void EnDns_Talk(EnDns* this, GlobalContext* globalCtx) {
|
||||
}
|
||||
|
||||
void func_809EFDD0(EnDns* this, GlobalContext* globalCtx) {
|
||||
if (this->actor.params == 0x9) {
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_STICK_UPGRADE_30, this->actor.id, this->actor.params, globalCtx->sceneNum);
|
||||
GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 130.0f, 100.0f);
|
||||
} else if (CUR_UPG_VALUE(UPG_STICKS) < 2) {
|
||||
func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_20, 130.0f, 100.0f);
|
||||
if (!gSaveContext.n64ddFlag || !this->scrubIdentity.isShuffled) {
|
||||
if (this->actor.params == 0x9) {
|
||||
if (CUR_UPG_VALUE(UPG_STICKS) < 2) {
|
||||
func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_20, 130.0f, 100.0f);
|
||||
} else {
|
||||
func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_30, 130.0f, 100.0f);
|
||||
}
|
||||
} else if (this->actor.params == 0xA) {
|
||||
if (CUR_UPG_VALUE(UPG_NUTS) < 2) {
|
||||
func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_30, 130.0f, 100.0f);
|
||||
} else {
|
||||
func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_40, 130.0f, 100.0f);
|
||||
}
|
||||
} else {
|
||||
func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_30, 130.0f, 100.0f);
|
||||
}
|
||||
} else if (this->actor.params == 0xA) {
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_NUT_UPGRADE_40, this->actor.id, this->actor.params, globalCtx->sceneNum);
|
||||
GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 130.0f, 100.0f);
|
||||
} else if (CUR_UPG_VALUE(UPG_NUTS) < 2) {
|
||||
func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_30, 130.0f, 100.0f);
|
||||
} else {
|
||||
func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_40, 130.0f, 100.0f);
|
||||
func_8002F434(&this->actor, globalCtx, this->dnsItemEntry->getItemId, 130.0f, 100.0f);
|
||||
}
|
||||
} else {
|
||||
if (!gSaveContext.n64ddFlag) {
|
||||
func_8002F434(&this->actor, globalCtx, this->dnsItemEntry->getItemId, 130.0f, 100.0f);
|
||||
} else {
|
||||
GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(this->dnsItemEntry->getItemId, this->actor.id, this->actor.params, globalCtx->sceneNum);
|
||||
GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 130.0f, 100.0f);
|
||||
}
|
||||
GetItemEntry itemEntry = Randomizer_GetItemFromKnownCheck(this->scrubIdentity.randomizerCheck, this->scrubIdentity.getItemId);
|
||||
GiveItemEntryFromActor(&this->actor, globalCtx, itemEntry, 130.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,6 +515,11 @@ void EnDns_Update(Actor* thisx, GlobalContext* globalCtx) {
|
||||
|
||||
this->dustTimer++;
|
||||
this->actor.textId = D_809F040C[this->actor.params];
|
||||
if (gSaveContext.n64ddFlag && this->scrubIdentity.isShuffled) {
|
||||
// Currently the textID is simply identified by the item price since that is the only thing
|
||||
// unique to it, later on this will change to identifying by scrubIdentity.randomizerInf
|
||||
this->actor.textId = 0x9000 + this->dnsItemEntry->itemPrice;
|
||||
}
|
||||
Actor_SetFocus(&this->actor, 60.0f);
|
||||
Actor_SetScale(&this->actor, 0.01f);
|
||||
SkelAnime_Update(&this->skelAnime);
|
||||
|
@ -32,6 +32,7 @@ typedef struct EnDns {
|
||||
/* 0x02BD */ u8 dropCollectible;
|
||||
/* 0x02C0 */ DnsItemEntry* dnsItemEntry;
|
||||
/* 0x02C4 */ f32 yInitPos;
|
||||
/* */ ScrubIdentity scrubIdentity;
|
||||
} EnDns; // size = 0x02C8
|
||||
|
||||
#endif
|
||||
|
@ -90,7 +90,16 @@ static void* sEyeTextures[] = {
|
||||
gMalonChildEyeClosedTex,
|
||||
};
|
||||
|
||||
bool Randomizer_ObtainedMalonHCReward() {
|
||||
return Flags_GetEventChkInf(0x12);
|
||||
}
|
||||
|
||||
u16 EnMa1_GetText(GlobalContext* globalCtx, Actor* thisx) {
|
||||
// Special case for Malon Hyrule Castle Text. Placing it here at the beginning
|
||||
// has the added benefit of circumventing mask text if wearing bunny hood.
|
||||
if (gSaveContext.n64ddFlag && globalCtx->sceneNum == SCENE_SPOT15) {
|
||||
return Randomizer_ObtainedMalonHCReward() ? 0x2044 : 0x2043;
|
||||
}
|
||||
u16 faceReaction = Text_GetFaceReaction(globalCtx, 0x17);
|
||||
|
||||
if (faceReaction != 0) {
|
||||
@ -191,25 +200,34 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) {
|
||||
if (!LINK_IS_CHILD) {
|
||||
return 0;
|
||||
}
|
||||
// Causes Malon to appear in the market if you haven't met her yet.
|
||||
if (((globalCtx->sceneNum == SCENE_MARKET_NIGHT) || (globalCtx->sceneNum == SCENE_MARKET_DAY)) &&
|
||||
!(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) {
|
||||
return 1;
|
||||
}
|
||||
if ((globalCtx->sceneNum == SCENE_SPOT15) && !(gSaveContext.eventChkInf[1] & 0x10)) {
|
||||
if (gSaveContext.infTable[8] & 0x800) {
|
||||
return 1;
|
||||
} else {
|
||||
gSaveContext.infTable[8] |= 0x800;
|
||||
return 0;
|
||||
if ((globalCtx->sceneNum == SCENE_SPOT15) && // if we're at hyrule castle
|
||||
(!(gSaveContext.eventChkInf[1] & 0x10) || // and talon hasn't left
|
||||
(gSaveContext.n64ddFlag &&
|
||||
!Randomizer_ObtainedMalonHCReward()))) { // or we're rando'd and haven't gotten malon's HC check
|
||||
if (gSaveContext.infTable[8] & 0x800) { // if we've met malon
|
||||
return 1; // make her appear at the castle
|
||||
} else { // if we haven't met malon
|
||||
gSaveContext.infTable[8] |= 0x800; // set the flag for meeting malon
|
||||
return 0; // don't make her appear at the castle
|
||||
}
|
||||
}
|
||||
// Malon asleep in her bed if Talon has left Hyrule Castle and it is nighttime.
|
||||
if ((globalCtx->sceneNum == SCENE_SOUKO) && IS_NIGHT && (gSaveContext.eventChkInf[1] & 0x10)) {
|
||||
return 1;
|
||||
}
|
||||
// Don't spawn Malon if none of the above are true and we are not in Lon Lon Ranch.
|
||||
if (globalCtx->sceneNum != SCENE_SPOT20) {
|
||||
return 0;
|
||||
}
|
||||
if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10)) {
|
||||
// If we've gotten this far, we're in Lon Lon Ranch. Spawn Malon if it is daytime, Talon has left Hyrule Castle, and
|
||||
// either we are not randomized, or we are and we have received Malon's item at Hyrule Castle.
|
||||
if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) &&
|
||||
((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -290,10 +308,16 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
this->actor.targetMode = 6;
|
||||
this->unk_1E8.unk_00 = 0;
|
||||
|
||||
if (!(gSaveContext.eventChkInf[1] & 0x10) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) ||
|
||||
// To avoid missing a check, we want Malon to have the actionFunc for singing, but not reacting to Ocarina, if any of
|
||||
// the following are true.
|
||||
// 1. Talon has not left Hyrule Castle.
|
||||
// 2. We are Randomized and have not obtained Malon's Weird Egg Check.
|
||||
// 3. We are not Randomized and have obtained Epona's Song
|
||||
if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) ||
|
||||
(gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) {
|
||||
this->actionFunc = func_80AA0D88;
|
||||
EnMa1_ChangeAnim(this, ENMA1_ANIM_2);
|
||||
// If none of the above conditions were true, set Malon up to teach Epona's Song.
|
||||
} else {
|
||||
if (gSaveContext.n64ddFlag) { // Skip straight to "let's sing it together" textbox in the ranch
|
||||
gSaveContext.eventChkInf[1] |= 0x40;
|
||||
@ -322,9 +346,16 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) {
|
||||
}
|
||||
}
|
||||
|
||||
if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10)) {
|
||||
// We want to Kill Malon's Actor outside of randomizer when Talon is freed. In Randomizer we don't kill Malon's
|
||||
// Actor here, otherwise if we wake up Talon first and then get her check she will spontaneously
|
||||
// disappear.
|
||||
if ((globalCtx->sceneNum == SCENE_SPOT15) && (!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10)) {
|
||||
Actor_Kill(&this->actor);
|
||||
} else if (!(gSaveContext.eventChkInf[1] & 0x10) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) {
|
||||
// We want Malon to give the Weird Egg Check (see function below) in the following situations:
|
||||
// 1. Talon as not left Hyrule Castle (Vanilla) OR
|
||||
// 2. We haven't obtained Malon's Weird Egg Check (Randomizer only) OR
|
||||
// 3. We have Epona's Song? (Vanilla only, not sure why it's here but I didn't write that one)
|
||||
} else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) {
|
||||
if (this->unk_1E8.unk_00 == 2) {
|
||||
this->actionFunc = func_80AA0EA0;
|
||||
globalCtx->msgCtx.stateTimer = 4;
|
||||
|
@ -125,11 +125,19 @@ void EnMs_Talk(EnMs* this, GlobalContext* globalCtx) {
|
||||
} else if (Message_ShouldAdvance(globalCtx)) {
|
||||
switch (globalCtx->msgCtx.choiceIndex) {
|
||||
case 0: // yes
|
||||
if (gSaveContext.rupees < sPrices[BEANS_BOUGHT]) {
|
||||
if (gSaveContext.rupees <
|
||||
((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS))
|
||||
? 60
|
||||
: sPrices[BEANS_BOUGHT])) {
|
||||
Message_ContinueTextbox(globalCtx, 0x4069); // not enough rupees text
|
||||
return;
|
||||
}
|
||||
func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f);
|
||||
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) {
|
||||
GiveItemEntryFromActor(&this->actor, globalCtx,
|
||||
Randomizer_GetItemFromKnownCheck(RC_ZR_MAGIC_BEAN_SALESMAN, GI_BEAN), 90.0f, 10.0f);
|
||||
} else {
|
||||
func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f);
|
||||
}
|
||||
this->actionFunc = EnMs_Sell;
|
||||
return;
|
||||
case 1: // no
|
||||
@ -142,11 +150,18 @@ void EnMs_Talk(EnMs* this, GlobalContext* globalCtx) {
|
||||
|
||||
void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) {
|
||||
if (Actor_HasParent(&this->actor, globalCtx)) {
|
||||
Rupees_ChangeBy(-sPrices[BEANS_BOUGHT]);
|
||||
Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? -60 : -sPrices[BEANS_BOUGHT]);
|
||||
this->actor.parent = NULL;
|
||||
this->actionFunc = EnMs_TalkAfterPurchase;
|
||||
this->actionFunc =
|
||||
(gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? EnMs_Wait : EnMs_TalkAfterPurchase;
|
||||
} else {
|
||||
func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f);
|
||||
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) {
|
||||
GiveItemEntryFromActor(&this->actor, globalCtx,
|
||||
Randomizer_GetItemFromKnownCheck(RC_ZR_MAGIC_BEAN_SALESMAN, GI_BEAN), 90.0f, 10.0f);
|
||||
BEANS_BOUGHT = 10;
|
||||
} else {
|
||||
func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,15 @@ void EnShopnuts_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit);
|
||||
Collider_UpdateCylinder(&this->actor, &this->collider);
|
||||
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1);
|
||||
ScrubIdentity scrubIdentity = Randomizer_IdentifyScrub(globalCtx->sceneNum, this->actor.params, respawnData);
|
||||
|
||||
if (scrubIdentity.isShuffled && Flags_GetRandomizerInf(scrubIdentity.randomizerInf)) {
|
||||
Actor_Kill(&this->actor);
|
||||
}
|
||||
}
|
||||
|
||||
if (((this->actor.params == 0x0002) && (gSaveContext.itemGetInf[0] & 0x800)) ||
|
||||
((this->actor.params == 0x0009) && (gSaveContext.infTable[25] & 4)) ||
|
||||
((this->actor.params == 0x000A) && (gSaveContext.infTable[25] & 8))) {
|
||||
|
@ -17,7 +17,8 @@ s32 func_80AFB748(EnSi* this, GlobalContext* globalCtx);
|
||||
void func_80AFB768(EnSi* this, GlobalContext* globalCtx);
|
||||
void func_80AFB89C(EnSi* this, GlobalContext* globalCtx);
|
||||
void func_80AFB950(EnSi* this, GlobalContext* globalCtx);
|
||||
void Randomizer_GrantSkullReward(EnSi* this, GlobalContext* globalCtx);
|
||||
void Randomizer_UpdateSkullReward(EnSi* this, GlobalContext* globalCtx);
|
||||
void Randomizer_GiveSkullReward(EnSi* this, GlobalContext* globalCtx);
|
||||
|
||||
s32 textId = 0xB4;
|
||||
s32 giveItemId = ITEM_SKULL_TOKEN;
|
||||
@ -99,21 +100,25 @@ void func_80AFB768(EnSi* this, GlobalContext* globalCtx) {
|
||||
|
||||
if (this->collider.base.ocFlags2 & OC2_HIT_PLAYER) {
|
||||
this->collider.base.ocFlags2 &= ~OC2_HIT_PLAYER;
|
||||
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
Randomizer_GrantSkullReward(this, globalCtx);
|
||||
Randomizer_UpdateSkullReward(this, globalCtx);
|
||||
} else {
|
||||
Item_Give(globalCtx, giveItemId);
|
||||
}
|
||||
if ((CVar_GetS32("gSkulltulaFreeze", 0) != 1 || giveItemId != ITEM_SKULL_TOKEN) && getItemId != RG_ICE_TRAP) {
|
||||
player->actor.freezeTimer = 20;
|
||||
}
|
||||
|
||||
Message_StartTextbox(globalCtx, textId, NULL);
|
||||
|
||||
if (gSaveContext.n64ddFlag && getItemId != RG_ICE_TRAP) {
|
||||
Randomizer_GiveSkullReward(this, globalCtx);
|
||||
Audio_PlayFanfare_Rando(getItem);
|
||||
} else {
|
||||
Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET);
|
||||
}
|
||||
|
||||
player->getItemEntry = (GetItemEntry)GET_ITEM_NONE;
|
||||
this->actionFunc = func_80AFB950;
|
||||
} else {
|
||||
@ -133,16 +138,20 @@ void func_80AFB89C(EnSi* this, GlobalContext* globalCtx) {
|
||||
|
||||
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) {
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
Randomizer_GrantSkullReward(this, globalCtx);
|
||||
Randomizer_UpdateSkullReward(this, globalCtx);
|
||||
} else {
|
||||
Item_Give(globalCtx, giveItemId);
|
||||
}
|
||||
|
||||
Message_StartTextbox(globalCtx, textId, NULL);
|
||||
|
||||
if (gSaveContext.n64ddFlag && getItemId != RG_ICE_TRAP) {
|
||||
Randomizer_GiveSkullReward(this, globalCtx);
|
||||
Audio_PlayFanfare_Rando(getItem);
|
||||
} else {
|
||||
Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET);
|
||||
}
|
||||
|
||||
player->getItemEntry = (GetItemEntry)GET_ITEM_NONE;
|
||||
this->actionFunc = func_80AFB950;
|
||||
}
|
||||
@ -190,7 +199,7 @@ void EnSi_Draw(Actor* thisx, GlobalContext* globalCtx) {
|
||||
}
|
||||
}
|
||||
|
||||
void Randomizer_GrantSkullReward(EnSi* this, GlobalContext* globalCtx) {
|
||||
void Randomizer_UpdateSkullReward(EnSi* this, GlobalContext* globalCtx) {
|
||||
Player* player = GET_PLAYER(globalCtx);
|
||||
|
||||
getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum);
|
||||
@ -201,12 +210,20 @@ void Randomizer_GrantSkullReward(EnSi* this, GlobalContext* globalCtx) {
|
||||
} else {
|
||||
textId = getItem.textId;
|
||||
giveItemId = getItem.itemId;
|
||||
if (getItem.modIndex == MOD_NONE) {
|
||||
Item_Give(globalCtx, giveItemId);
|
||||
} else if (getItem.modIndex == MOD_RANDOMIZER) {
|
||||
Randomizer_Item_Give(globalCtx, getItem);
|
||||
}
|
||||
}
|
||||
// player->getItemId = getItemId;
|
||||
player->getItemEntry = getItem;
|
||||
}
|
||||
|
||||
void Randomizer_GiveSkullReward(EnSi* this, GlobalContext* globalCtx) {
|
||||
Player* player = GET_PLAYER(globalCtx);
|
||||
|
||||
if (getItem.modIndex == MOD_NONE) {
|
||||
Item_Give(globalCtx, giveItemId);
|
||||
} else if (getItem.modIndex == MOD_RANDOMIZER) {
|
||||
Randomizer_Item_Give(globalCtx, getItem);
|
||||
}
|
||||
// RANDOTOD: Move this into Item_Give() or some other more central location
|
||||
if (getItem.getItemId == GI_SWORD_BGS) {
|
||||
gSaveContext.bgsFlag = true;
|
||||
}
|
||||
}
|
||||
|
@ -135,6 +135,27 @@ void ObjectKankyo_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
this->effects[5].size = 0.0f;
|
||||
}
|
||||
|
||||
if (gSaveContext.n64ddFlag) {
|
||||
if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_FOREST_TRIAL)) {
|
||||
this->effects[0].size = 0.0f;
|
||||
}
|
||||
if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_WATER_TRIAL)) {
|
||||
this->effects[1].size = 0.0f;
|
||||
}
|
||||
if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_SHADOW_TRIAL)) {
|
||||
this->effects[2].size = 0.0f;
|
||||
}
|
||||
if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_FIRE_TRIAL)) {
|
||||
this->effects[3].size = 0.0f;
|
||||
}
|
||||
if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_LIGHT_TRIAL)) {
|
||||
this->effects[4].size = 0.0f;
|
||||
}
|
||||
if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_SPIRIT_TRIAL)) {
|
||||
this->effects[5].size = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (gSaveContext.cutsceneTrigger != 0) {
|
||||
if (gSaveContext.entranceIndex == 0x0538) {
|
||||
this->effects[0].size = 0.1f;
|
||||
|
@ -6108,7 +6108,7 @@ s32 func_8083E5A8(Player* this, GlobalContext* globalCtx) {
|
||||
}
|
||||
|
||||
GetItemEntry giEntry;
|
||||
if (this->getItemEntry.objectId == OBJECT_INVALID) {
|
||||
if (this->getItemEntry.objectId == OBJECT_INVALID || (this->getItemId != this->getItemEntry.getItemId)) {
|
||||
giEntry = ItemTable_Retrieve(this->getItemId);
|
||||
} else {
|
||||
giEntry = this->getItemEntry;
|
||||
@ -6165,7 +6165,7 @@ s32 func_8083E5A8(Player* this, GlobalContext* globalCtx) {
|
||||
}
|
||||
} else if (CHECK_BTN_ALL(sControlInput->press.button, BTN_A) && !(this->stateFlags1 & PLAYER_STATE1_11) &&
|
||||
!(this->stateFlags2 & PLAYER_STATE2_10)) {
|
||||
if (this->getItemId != GI_NONE && this->getItemEntry.objectId != OBJECT_INVALID) {
|
||||
if (this->getItemId != GI_NONE) {
|
||||
GetItemEntry giEntry;
|
||||
if (this->getItemEntry.objectId == OBJECT_INVALID) {
|
||||
giEntry = ItemTable_Retrieve(-this->getItemId);
|
||||
@ -9687,8 +9687,8 @@ void func_808473D4(GlobalContext* globalCtx, Player* this) {
|
||||
else if ((!(this->stateFlags1 & PLAYER_STATE1_11) || (heldActor == NULL)) &&
|
||||
(interactRangeActor != NULL) &&
|
||||
((!sp1C && (this->getItemId == GI_NONE)) ||
|
||||
((this->getItemId < 0 && this->getItemEntry.getItemId < 0) && !(this->stateFlags1 & PLAYER_STATE1_27)))) {
|
||||
if (this->getItemId < 0 && this->getItemEntry.getItemId < 0) {
|
||||
(this->getItemId < 0 && !(this->stateFlags1 & PLAYER_STATE1_27)))) {
|
||||
if (this->getItemId < 0) {
|
||||
doAction = DO_ACTION_OPEN;
|
||||
} else if ((interactRangeActor->id == ACTOR_BG_TOKI_SWD) && LINK_IS_ADULT) {
|
||||
doAction = DO_ACTION_DROP;
|
||||
|
@ -433,6 +433,7 @@ void FileChoose_UpdateMainMenu(GameState* thisx) {
|
||||
const char* fileLoc = CVar_GetString("gSpoilerLog", "");
|
||||
Randomizer_LoadSettings(fileLoc);
|
||||
Randomizer_LoadHintLocations(fileLoc);
|
||||
Randomizer_LoadRequiredTrials(fileLoc);
|
||||
Randomizer_LoadItemLocations(fileLoc, silent);
|
||||
fileSelectSpoilerFileLoaded = true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user