Merge branch 'rando-next' of https://github.com/HarbourMasters/Shipwright into get-item-rework-rando-next

Hopefully everything works here. Need to do some testing.
This commit is contained in:
Christopher Leggett 2022-08-13 22:43:19 -04:00
commit c8d085cb49
No known key found for this signature in database
GPG Key ID: 7093AE5FF7037D79
58 changed files with 3169 additions and 1688 deletions

View File

@ -9,7 +9,6 @@
#include "Cvar.h"
namespace Ship {
uint8_t* controllerBits;
void ControlDeck::Init(uint8_t* bits) {
ScanPhysicalDevices();
@ -187,4 +186,9 @@ namespace Ship {
std::shared_ptr<Controller> ControlDeck::GetPhysicalDeviceFromVirtualSlot(int slot) {
return GetPhysicalDevice(GetVirtualDevice(slot));
}
uint8_t* ControlDeck::GetControllerBits() {
return controllerBits;
}
}

View File

@ -18,8 +18,10 @@ namespace Ship {
size_t GetNumPhysicalDevices();
int GetVirtualDevice(int slot);
size_t GetNumVirtualDevices();
uint8_t* GetControllerBits();
private:
std::vector<int> virtualDevices;
std::vector<int> virtualDevices = {};
std::vector<std::shared_ptr<Controller>> physicalDevices = {};
uint8_t* controllerBits = nullptr;
};
}

View File

@ -1760,9 +1760,30 @@ namespace SohImGui {
needs_save = true;
customWindows["Item Tracker"].enabled = CVar_GetS32("gItemTrackerEnabled", 0);
}
InsertPadding();
if (ImGui::Button(GetWindowButtonText("Item Tracker Settings", CVar_GetS32("gItemTrackerSettingsEnabled", 0)).c_str(), buttonSize))
{
bool currentValue = CVar_GetS32("gItemTrackerSettingsEnabled", 0);
CVar_SetS32("gItemTrackerSettingsEnabled", !currentValue);
needs_save = true;
customWindows["Item Tracker Settings"].enabled = CVar_GetS32("gItemTrackerSettingsEnabled", 0);
}
ImGui::PopStyleVar(3);
ImGui::PopStyleColor(1);
PaddedSeparator();
if (ImGui::BeginMenu("Rando Enhancements"))
{
EnhancementCheckbox("Quest Item Fanfares", "gRandoQuestItemFanfares");
Tooltip(
"Play unique fanfares when obtaining quest items\n"
"(medallions/stones/songs). Note that these fanfares\n"
"are longer than usual."
);
ImGui::EndMenu();
}
ImGui::EndMenu();
}

View File

@ -2,7 +2,7 @@
namespace Ship
{
Vertex::Vertex()
ModelVertex::ModelVertex()
{
pos = Vec3f(0, 0, 0);
normal = Vec3f(0, 0, 0);
@ -10,7 +10,7 @@ namespace Ship
uv = Vec2f(0, 0);
}
Vertex::Vertex(BinaryReader* reader)
ModelVertex::ModelVertex(BinaryReader* reader)
{
pos = reader->ReadVec3f();
normal = reader->ReadVec3f();
@ -36,7 +36,7 @@ namespace Ship
uvCoords = reader->ReadUInt32();
boneWeights = reader->ReadUInt32();
Vertex* vtxData = new Vertex[numVerts];
ModelVertex* vtxData = new ModelVertex[numVerts];
uint32_t* indicesData = new uint32_t[numPolys];
if (vertices != 0)

View File

@ -43,15 +43,15 @@ namespace Ship
void ParseFileBinary(BinaryReader* reader, Resource* res) override;
};
struct Vertex
struct ModelVertex
{
Vec3f pos;
Vec3f normal;
Color3b color;
Vec2f uv;
Vertex();
Vertex(BinaryReader* reader);
ModelVertex();
ModelVertex(BinaryReader* reader);
};
class Model : public Resource
@ -62,7 +62,7 @@ namespace Ship
uint32_t numVerts;
uint32_t numPolys;
Vertex* vertices;
ModelVertex* vertices;
Vec2f* boneWeights;
uint32_t* indices;
};

View File

@ -174,6 +174,7 @@ source_group("Header Files\\soh\\Enhancements\\debugger" FILES ${Header_Files__s
set(Header_Files__soh__Enhancements__randomizer
"soh/Enhancements/randomizer/randomizer.h"
"soh/Enhancements/randomizer/randomizer_item_tracker.h"
"soh/Enhancements/randomizer/adult_trade_shuffle.h"
)
source_group("Header Files\\soh\\Enhancements\\randomizer" FILES ${Header_Files__soh__Enhancements__randomizer})
@ -274,6 +275,7 @@ source_group("Source Files\\soh\\Enhancements\\debugger" FILES ${Source_Files__s
set(Source_Files__soh__Enhancements__randomizer
"soh/Enhancements/randomizer/randomizer.cpp"
"soh/Enhancements/randomizer/randomizer_item_tracker.cpp"
"soh/Enhancements/randomizer/adult_trade_shuffle.c"
)
source_group("Source Files\\soh\\Enhancements\\randomizer" FILES ${Source_Files__soh__Enhancements__randomizer})

View File

@ -1057,6 +1057,7 @@ s32 Inventory_HasEmptyBottle(void);
s32 Inventory_HasSpecificBottle(u8 bottleItem);
void Inventory_UpdateBottleItem(GlobalContext* globalCtx, u8 item, u8 cButton);
s32 Inventory_ConsumeFairy(GlobalContext* globalCtx);
bool Inventory_HatchPocketCucco(GlobalContext* globalCtx);
void Interface_SetDoAction(GlobalContext* globalCtx, u16 action);
void Interface_SetNaviCall(GlobalContext* globalCtx, u16 naviCallState);
void Interface_LoadActionLabelB(GlobalContext* globalCtx, u16 action);

View File

@ -6,6 +6,8 @@
struct Player;
extern GetItemEntry sGetItemTable[195];
typedef enum {
/* 0 */ PLAYER_SWORD_NONE,
/* 1 */ PLAYER_SWORD_KOKIRI,
@ -366,6 +368,7 @@ typedef enum {
FLAG_SCENE_CLEAR,
FLAG_SCENE_COLLECTIBLE,
FLAG_EVENT_CHECK_INF,
FLAG_COW_MILKED
} FlagType;
typedef struct {
@ -627,9 +630,10 @@ typedef struct Player {
/* 0x0A86 */ s8 unk_A86;
/* 0x0A87 */ u8 unk_A87;
/* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position
/* 0x0A94 */ PendingFlag pendingFlag;
/* 0x0AA0 */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still?
/* 0x0AA1 */ GetItemEntry getItemEntry;
} Player; // size = 0xAA9
/* 0x0A89 */ bool pendingIceTrap;
/* 0x0A95 */ PendingFlag pendingFlag;
/* 0x0AA1 */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still?
/* 0x0AA2 */ GetItemEntry getItemEntry;
} Player; // size = 0xAAA
#endif

View File

@ -175,7 +175,7 @@ typedef struct {
/* 0x1422 */ s16 sunsSongState; // controls the effects of suns song
/* 0x1424 */ s16 healthAccumulator;
RandoSetting randoSettings[300];
ItemLocationRando itemLocations[500];
ItemLocationRando itemLocations[RC_MAX];
HintLocationRando hintLocations[50];
char childAltarText[250];
char adultAltarText[750];
@ -184,7 +184,9 @@ typedef struct {
u8 seedIcons[5];
u8 dungeonsDone[8];
u8 trialsDone[6];
u8 cowsMilked[10];
u8 temporaryWeapon;
u16 adultTradeItems;
} SaveContext; // size = 0x1428
typedef enum {

View File

@ -30,4 +30,7 @@ typedef struct {
#define GIMESSAGE_UNTRANSLATED(giid, iid, message) \
{ giid, iid, message, message, message }
#define GIMESSAGE_NO_GERMAN(giid, iid, english, french) \
{ giid, iid, english, english, french }
#endif

View File

@ -20,3 +20,13 @@ void InsertHelpHoverText(const std::string& text) {
ImGui::EndTooltip();
}
}
void PaddedSeparator(bool padTop, bool padBottom, float extraVerticalPadding) {
if (padTop) {
ImGui::Dummy(ImVec2(0.0f, extraVerticalPadding));
}
ImGui::Separator();
if (padBottom) {
ImGui::Dummy(ImVec2(0.0f, extraVerticalPadding));
}
}

View File

@ -6,3 +6,5 @@
void SetLastItemHoverText(const std::string& text);
void InsertHelpHoverText(const std::string& text);
void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalPadding = 0);

View File

@ -1,5 +1,6 @@
#include "debugSaveEditor.h"
#include "../../util.h"
#include "../../OTRGlobals.h"
#include "../libultraship/ImGuiImpl.h"
#include "ImGuiHelpers.h"
@ -14,6 +15,7 @@ extern "C" {
#include "variables.h"
#include "functions.h"
#include "macros.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
extern GlobalContext* gGlobalCtx;
#include "textures/icon_item_static/icon_item_static.h"
@ -525,6 +527,27 @@ void DrawInfoTab() {
ImGui::PopItemWidth();
}
void DrawBGSItemFlag(uint8_t itemID) {
const ItemMapEntry& slotEntry = itemMapping[itemID];
ImGui::Image(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1));
ImGui::SameLine();
int tradeIndex = itemID - ITEM_POCKET_EGG;
bool hasItem = (gSaveContext.adultTradeItems & (1 << tradeIndex)) != 0;
bool shouldHaveItem = hasItem;
ImGui::Checkbox(("##adultTradeFlag" + std::to_string(itemID)).c_str(), &shouldHaveItem);
if (hasItem != shouldHaveItem) {
if (shouldHaveItem) {
gSaveContext.adultTradeItems |= (1 << tradeIndex);
if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_NONE) {
INV_CONTENT(ITEM_TRADE_ADULT) = ITEM_POCKET_EGG + tradeIndex;
}
} else {
gSaveContext.adultTradeItems &= ~(1 << tradeIndex);
Inventory_ReplaceItem(gGlobalCtx, itemID, Randomizer_GetNextAdultTradeItem());
}
}
}
void DrawInventoryTab() {
static bool restrictToValid = true;
@ -566,6 +589,9 @@ void DrawInventoryTab() {
if (ImGui::BeginPopup(itemPopupPicker)) {
if (ImGui::Button("##itemNonePicker", ImVec2(32.0f, 32.0f))) {
gSaveContext.inventory.items[selectedIndex] = ITEM_NONE;
if (selectedIndex == SLOT_TRADE_ADULT) {
gSaveContext.adultTradeItems = 0;
}
ImGui::CloseCurrentPopup();
}
SetLastItemHoverText("None");
@ -596,6 +622,13 @@ void DrawInventoryTab() {
if (ImGui::ImageButton(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f),
ImVec2(0, 0), ImVec2(1, 1), 0)) {
gSaveContext.inventory.items[selectedIndex] = slotEntry.id;
// Set adult trade item flag if you're playing adult trade shuffle in rando
if (gSaveContext.n64ddFlag &&
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE);
selectedIndex == SLOT_TRADE_ADULT &&
slotEntry.id >= ITEM_POCKET_EGG && slotEntry.id <= ITEM_CLAIM_CHECK) {
gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(slotEntry.id);
}
ImGui::CloseCurrentPopup();
}
SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id));
@ -632,6 +665,16 @@ void DrawInventoryTab() {
ImGui::PopID();
}
}
// Trade quest flags are only used when shuffling the trade sequence, so
// don't show this if it isn't needed.
if (gSaveContext.n64ddFlag && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE)
&& ImGui::TreeNode("Adult trade quest items")) {
for (int i = ITEM_POCKET_EGG; i <= ITEM_CLAIM_CHECK; i++) {
DrawBGSItemFlag(i);
}
ImGui::TreePop();
}
}
// Draw a flag bitfield as an grid of checkboxes

View File

@ -103,11 +103,11 @@ public:
return false;
}
if ((type == ITEMTYPE_BOSSKEY && getItemId != 0x9A) && (BossKeysanity.Is(BOSSKEYSANITY_VANILLA) || BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON))) {
if ((type == ITEMTYPE_BOSSKEY && getItemId != 0xAD) && (BossKeysanity.Is(BOSSKEYSANITY_VANILLA) || BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON))) {
return false;
}
//Ganons Castle Boss Key
if (getItemId == 0x9A && (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA) || GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON))) {
if (getItemId == 0xAD && (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA) || GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON))) {
return false;
}

View File

@ -229,11 +229,11 @@ void ItemTable_Init() { //English name
itemTable[BUY_BOMBCHU_20] = Item(Text{"Buy Bombchu (20)", "Acheter: Missiles (20)", "Comprar bombchus (20)"}, ITEMTYPE_SHOP, 0x16, true, &BuyBombchus20, BOMBCHU_20, 180);
itemTable[BUY_BOMBCHU_5] = Item(Text{"Buy Bombchu (5)", "Acheter: Missiles (5)", "Comprar bombchus (5)"}, ITEMTYPE_SHOP, 0x18, true, &BuyBombchus5, BOMBCHU_5, 60);
itemTable[BUY_DEKU_SEEDS_30] = Item(Text{"Buy Deku Seeds (30)", "Acheter: Graines Mojo (30)", "Comprar semillas deku (30)"}, ITEMTYPE_SHOP, 0x1D, true, &BuySeed, DEKU_SEEDS_30, 30);
itemTable[SOLD_OUT] = Item(Text{"Sold Out", "Vendu", "Vendido"}, ITEMTYPE_SHOP, 0x26, false, &noVariable, NONE, 0);
itemTable[SOLD_OUT] = Item(Text{"Sold Out", "Rupture de stock", "Vendido"}, ITEMTYPE_SHOP, 0x26, false, &noVariable, NONE, 0);
itemTable[BUY_BLUE_FIRE] = Item(Text{"Buy Blue Fire", "Acheter: Flamme Bleue", "Comprar fuego azul"}, ITEMTYPE_SHOP, 0x27, true, &BlueFireAccess, BOTTLE_WITH_BLUE_FIRE, 300);
itemTable[BUY_BOTTLE_BUG] = Item(Text{"Buy Bottle Bug", "Acheter: Insecte en bouteille", "Comprar bichos"}, ITEMTYPE_SHOP, 0x28, true, &BugsAccess, BOTTLE_WITH_BUGS, 50);
itemTable[BUY_POE] = Item(Text{"Buy Poe", "Acheter: Esprit", "Comprar Poe"}, ITEMTYPE_SHOP, 0x2A, false, &noVariable, BOTTLE_WITH_BIG_POE, 30);
itemTable[BUY_FAIRYS_SPIRIT] = Item(Text{"Buy Fairy's Spirit", "Acheter: Esprit de Fée", "Comprar hada"}, ITEMTYPE_SHOP, 0x2B, true, &FairyAccess, BOTTLE_WITH_FAIRY, 50);
itemTable[BUY_POE] = Item(Text{"Buy Poe", "Acheter: Esprit", "Comprar Poe"}, ITEMTYPE_SHOP, 0x2A, false, &noVariable, BOTTLE_WITH_BIG_POE, 30);
itemTable[BUY_FAIRYS_SPIRIT] = Item(Text{"Buy Fairy's Spirit", "Acheter: Esprit de Fée", "Comprar hada"}, ITEMTYPE_SHOP, 0x2B, true, &FairyAccess, BOTTLE_WITH_FAIRY, 50);
itemTable[BUY_ARROWS_10] = Item(Text{"Buy Arrows (10)", "Acheter: Flèches (10)", "Comprar flechas (10)"}, ITEMTYPE_SHOP, 0x2C, true, &BuyArrow, ARROWS_10, 20);
itemTable[BUY_BOMBS_20] = Item(Text{"Buy Bombs (20)", "Acheter: Bombes (20)", "Comprar bombas (20)"}, ITEMTYPE_SHOP, 0x2D, true, &BuyBomb, BOMBS_20, 80);
itemTable[BUY_BOMBS_30] = Item(Text{"Buy Bombs (30)", "Acheter: Bombes (30)", "Comprar bombas (30)"}, ITEMTYPE_SHOP, 0x2E, true, &BuyBomb, BOMBS_20, 120);

View File

@ -165,6 +165,11 @@ void LocationTable_Init() {
//Zoras River
locationTable[ZR_OPEN_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x09, "ZR Open Grotto Chest", ZR_OPEN_GROTTO_CHEST, RED_RUPEE, {Category::cZorasRiver, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_MAGIC_BEAN_SALESMAN] = ItemLocation::Base (0x54, 0x16, "ZR Magic Bean Salesman", ZR_MAGIC_BEAN_SALESMAN, MAGIC_BEAN, {Category::cZorasRiver,}, SpoilerCollectionCheck::MagicBeans(0x54, 0x01), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_FROGS_ZELDAS_LULLABY] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Zelda's Lullaby", ZR_FROGS_ZELDAS_LULLABY, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_FROGS_EPONAS_SONG] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Epona's Song", ZR_FROGS_EPONAS_SONG, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_FROGS_SARIAS_SONG] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Saria's Song", ZR_FROGS_SARIAS_SONG, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_FROGS_SUNS_SONG] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Sun's Song", ZR_FROGS_SUNS_SONG, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_FROGS_SONG_OF_TIME] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Song of Time", ZR_FROGS_SONG_OF_TIME, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_FROGS_IN_THE_RAIN] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs in the Rain", ZR_FROGS_IN_THE_RAIN, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_FROGS_OCARINA_GAME] = ItemLocation::Base (0x54, 0x76, "ZR Frogs Ocarina Game", ZR_FROGS_OCARINA_GAME, PIECE_OF_HEART, {Category::cZorasRiver, Category::cMinigame,}, SpoilerCollectionCheck::EventChkInf(0xD0), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
locationTable[ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH] = ItemLocation::Collectable(0x54, 0x04, "ZR Near Open Grotto Freestanding PoH", ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER);
@ -1302,6 +1307,11 @@ std::vector<uint32_t> overworldLocations = {
//Zoras River
ZR_OPEN_GROTTO_CHEST,
ZR_MAGIC_BEAN_SALESMAN,
ZR_FROGS_ZELDAS_LULLABY,
ZR_FROGS_EPONAS_SONG,
ZR_FROGS_SARIAS_SONG,
ZR_FROGS_SUNS_SONG,
ZR_FROGS_SONG_OF_TIME,
ZR_FROGS_IN_THE_RAIN,
ZR_FROGS_OCARINA_GAME,
ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH,

View File

@ -729,6 +729,16 @@ void GenerateItemPool() {
PlaceItemInLocation(WASTELAND_BOMBCHU_SALESMAN, BOMBCHU_10, false, true);
}
if (ShuffleFrogSongRupees) {
AddItemToMainPool(PURPLE_RUPEE, 5);
} else {
PlaceItemInLocation(ZR_FROGS_ZELDAS_LULLABY, PURPLE_RUPEE, false, true);
PlaceItemInLocation(ZR_FROGS_EPONAS_SONG, PURPLE_RUPEE, false, true);
PlaceItemInLocation(ZR_FROGS_SARIAS_SONG, PURPLE_RUPEE, false, true);
PlaceItemInLocation(ZR_FROGS_SUNS_SONG, PURPLE_RUPEE, false, true);
PlaceItemInLocation(ZR_FROGS_SONG_OF_TIME, PURPLE_RUPEE, false, true);
}
if (ShuffleAdultTradeQuest) {
AddItemToMainPool(POCKET_EGG);
AddItemToMainPool(COJIRO);

View File

@ -472,6 +472,11 @@ typedef enum {
//ZORA'S_RIVER
ZR_MAGIC_BEAN_SALESMAN,
ZR_OPEN_GROTTO_CHEST,
ZR_FROGS_ZELDAS_LULLABY,
ZR_FROGS_EPONAS_SONG,
ZR_FROGS_SARIAS_SONG,
ZR_FROGS_SUNS_SONG,
ZR_FROGS_SONG_OF_TIME,
ZR_FROGS_IN_THE_RAIN,
ZR_FROGS_OCARINA_GAME,
ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH,

View File

@ -31,6 +31,21 @@ void AreaTable_Init_ZorasDomain() {
LocationAccess(ZR_FROGS_IN_THE_RAIN, {[]{return IsChild && CanPlay(SongOfStorms);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SongOfStorms;}}),
LocationAccess(ZR_FROGS_ZELDAS_LULLABY, {[]{return IsChild && CanPlay(ZeldasLullaby);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && ZeldasLullaby;}}),
LocationAccess(ZR_FROGS_EPONAS_SONG, {[]{return IsChild && CanPlay(EponasSong);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && EponasSong;}}),
LocationAccess(ZR_FROGS_SARIAS_SONG, {[]{return IsChild && CanPlay(SariasSong);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SariasSong;}}),
LocationAccess(ZR_FROGS_SUNS_SONG, {[]{return IsChild && CanPlay(SunsSong);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SunsSong;}}),
LocationAccess(ZR_FROGS_SONG_OF_TIME, {[]{return IsChild && CanPlay(SongOfTime);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SongOfTime;}}),
LocationAccess(ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, {[]{return IsChild || CanUse(HOVER_BOOTS) || (IsAdult && LogicZoraRiverLower);}}),
LocationAccess(ZR_NEAR_DOMAIN_FREESTANDING_POH, {[]{return IsChild || CanUse(HOVER_BOOTS) || (IsAdult && LogicZoraRiverUpper);}}),
LocationAccess(ZR_GS_LADDER, {[]{return IsChild && AtNight && CanChildAttack && CanGetNightTimeGS;}}),

View File

@ -385,6 +385,13 @@ string_view merchantsHintsDesc = "These hints will make Medigoron and the
"The Clearer Hints setting will affect how they\n" //
"refer to the item."; //
/*------------------------------ //
| SHUFFLE FROG SONG RUPEES | //
------------------------------*/ //
string_view frogSongRupeesDesc = "Enabling this adds 5 Purple Rupees to the item\n" //
"pool and shuffles the rewards from playing Zelda's\n"
"Lullaby, Epona's Song, Saria's Song, Sun's Song,\n"
"and Song of Time to the frogs in Zora's River.\n";//
/*------------------------------ //
| SHUFFLE ADULT TRADE | //
------------------------------*/ //
string_view adultTradeDesc = "Enabling this adds all of the adult trade quest\n"//
@ -586,6 +593,13 @@ string_view kingZoraSpeedRandom = "King Zora will move out of the way in 1
string_view completeMaskDesc = "Once the happy mask shop is opened, all masks\n" //
"will be available to be borrowed."; //
/*------------------------------ //
| ENABLE GLITCH CUTSCENES | //
------------------------------*/ //
string_view glitchCutscenesDesc = "The cutscenes of the Poes in Forest Temple and\n" //
"Darunia in Fire Temple will not be skipped.\n" //
"These cutscenes are only useful for glitched\n" //
"gameplay and can be safely skipped otherwise."; //
/*------------------------------ //
| QUICK TEXT | //
------------------------------*/ //
string_view quickTextDesc0 = "Quick text will be unchanged, requiring\n" //

View File

@ -126,6 +126,8 @@ extern string_view magicBeansDesc;
extern string_view merchantsDesc;
extern string_view merchantsHintsDesc;
extern string_view frogSongRupeesDesc;
extern string_view adultTradeDesc;
extern string_view chestMinigameDesc;
@ -196,6 +198,8 @@ extern string_view kingZoraSpeedRandom;
extern string_view completeMaskDesc;
extern string_view glitchCutscenesDesc;
extern string_view quickTextDesc0;
extern string_view quickTextDesc1;
extern string_view quickTextDesc2;

View File

@ -52,19 +52,19 @@ namespace Settings {
// Setting name, Options, Setting Descriptions (assigned in setting_descriptions.cpp) Category (default: Setting),Default index (default: 0), Default hidden (default: false)
//Open Settings Any option index past the last description will use the last description
Option RandomizeOpen = Option::Bool("Randomize Settings", {"No","Yes"}, {openRandomize}, OptionCategory::Toggle);
Option OpenForest = Option::U8 ("Forest", {"Closed", "Open", "Closed Deku"}, {forestClosed, forestOpen, forestClosedDeku}, OptionCategory::Setting, OPENFOREST_OPEN);
Option OpenForest = Option::U8 ("Forest", {"Closed", "Closed Deku", "Open"}, {forestClosed, forestClosedDeku, forestOpen}, OptionCategory::Setting, OPENFOREST_CLOSED);
Option OpenKakariko = Option::U8 ("Kakariko Gate", {"Closed", "Open"}, {kakGateClosed, kakGateOpen});
Option OpenDoorOfTime = Option::U8 ("Door of Time", {"Open", "Closed", "Intended"}, {doorOfTimeOpen, doorOfTimeClosed, doorOfTimeIntended});
Option ZorasFountain = Option::U8 ("Zora's Fountain", {"Normal", "Adult", "Open"}, {fountainNormal, fountainAdult, fountainOpen});
Option OpenDoorOfTime = Option::U8 ("Door of Time", {"Closed", "Song only", "Open"}, {doorOfTimeIntended, doorOfTimeClosed, doorOfTimeOpen});
Option ZorasFountain = Option::U8 ("Zora's Fountain", {"Closed", "Closed as child", "Open"}, {fountainNormal, fountainAdult, fountainOpen});
Option GerudoFortress = Option::U8 ("Gerudo Fortress", {"Normal", "Fast", "Open"}, {gerudoNormal, gerudoFast, gerudoOpen});
Option Bridge = Option::U8 ("Rainbow Bridge", {"Open", "Vanilla", "Stones", "Medallions", "Rewards", "Dungeons", "Tokens"}, {bridgeOpen, bridgeVanilla, bridgeStones, bridgeMedallions, bridgeRewards, bridgeDungeons, bridgeTokens}, OptionCategory::Setting, RAINBOWBRIDGE_VANILLA);
Option BridgeStoneCount = Option::U8 (" Stone Count", {NumOpts(0, 3)}, {bridgeStoneCountDesc}, OptionCategory::Setting, 1, true);
Option BridgeMedallionCount= Option::U8 (" Medallion Count", {NumOpts(0, 6)}, {bridgeMedallionCountDesc}, OptionCategory::Setting, 1, true);
Option BridgeRewardCount = Option::U8 (" Reward Count", {NumOpts(0, 9)}, {bridgeRewardCountDesc}, OptionCategory::Setting, 1, true);
Option BridgeDungeonCount = Option::U8 (" Dungeon Count", {NumOpts(0, 8)}, {bridgeDungeonCountDesc}, OptionCategory::Setting, 1, true);
Option BridgeTokenCount = Option::U8 (" Token Count", {NumOpts(0, 100)}, {bridgeTokenCountDesc}, OptionCategory::Setting, 1, true);
Option Bridge = Option::U8 ("Rainbow Bridge", {"Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens"}, {bridgeVanilla, bridgeOpen, bridgeStones, bridgeMedallions, bridgeRewards, bridgeDungeons, bridgeTokens}, OptionCategory::Setting, RAINBOWBRIDGE_VANILLA);
Option BridgeStoneCount = Option::U8 ("Stone Count", {NumOpts(0, 3)}, {bridgeStoneCountDesc}, OptionCategory::Setting, 1, true);
Option BridgeMedallionCount= Option::U8 ("Medallion Count", {NumOpts(0, 6)}, {bridgeMedallionCountDesc}, OptionCategory::Setting, 1, true);
Option BridgeRewardCount = Option::U8 ("Reward Count", {NumOpts(0, 9)}, {bridgeRewardCountDesc}, OptionCategory::Setting, 1, true);
Option BridgeDungeonCount = Option::U8 ("Dungeon Count", {NumOpts(0, 8)}, {bridgeDungeonCountDesc}, OptionCategory::Setting, 1, true);
Option BridgeTokenCount = Option::U8 ("Token Count", {NumOpts(0, 100)}, {bridgeTokenCountDesc}, OptionCategory::Setting, 1, true);
Option RandomGanonsTrials = Option::Bool("Random Ganon's Trials", {"Off", "On"}, {randomGanonsTrialsDesc}, OptionCategory::Setting, ON);
Option GanonsTrialsCount = Option::U8 (" Trial Count", {NumOpts(0, 6)}, {ganonsTrialCountDesc}, OptionCategory::Setting, 1, true);
Option GanonsTrialsCount = Option::U8 ("Trial Count", {NumOpts(0, 6)}, {ganonsTrialCountDesc}, OptionCategory::Setting, 1, true);
std::vector<Option *> openOptions = {
&RandomizeOpen,
&OpenForest,
@ -87,10 +87,10 @@ namespace Settings {
Option StartingAge = Option::U8 ("Starting Age", {"Adult", "Child", "Random"}, {ageDesc}, OptionCategory::Setting, AGE_CHILD);
uint8_t ResolvedStartingAge;
Option ShuffleEntrances = Option::Bool("Shuffle Entrances", {"Off", "On"}, {shuffleEntrancesDesc});
Option ShuffleDungeonEntrances = Option::U8 (" Dungeon Entrances", {"Off", "On", "On + Ganon"}, {dungeonEntrancesDesc});
Option ShuffleOverworldEntrances = Option::Bool(" Overworld Entrances", {"Off", "On"}, {overworldEntrancesDesc});
Option ShuffleInteriorEntrances = Option::U8 (" Interior Entrances", {"Off", "Simple", "All"}, {interiorEntrancesOff, interiorEntrancesSimple, interiorEntrancesAll});
Option ShuffleGrottoEntrances = Option::Bool(" Grottos Entrances", {"Off", "On"}, {grottoEntrancesDesc});
Option ShuffleDungeonEntrances = Option::U8 ("Dungeon Entrances", {"Off", "On", "On + Ganon"}, {dungeonEntrancesDesc});
Option ShuffleOverworldEntrances = Option::Bool("Overworld Entrances", {"Off", "On"}, {overworldEntrancesDesc});
Option ShuffleInteriorEntrances = Option::U8 ("Interior Entrances", {"Off", "Simple", "All"}, {interiorEntrancesOff, interiorEntrancesSimple, interiorEntrancesAll});
Option ShuffleGrottoEntrances = Option::Bool("Grottos Entrances", {"Off", "On"}, {grottoEntrancesDesc});
Option BombchusInLogic = Option::Bool("Bombchus in Logic", {"Off", "On"}, {bombchuLogicDesc});
Option AmmoDrops = Option::U8 ("Ammo Drops", {"On", "On + Bombchu", "Off"}, {defaultAmmoDropsDesc, bombchuDropsDesc, noAmmoDropsDesc}, OptionCategory::Setting, AMMODROPS_BOMBCHU);
Option HeartDropRefill = Option::U8 ("Heart Drops and Refills",{"On", "No Drop", "No Refill", "Off"}, {defaultHeartDropsDesc, noHeartDropsDesc, noHeartRefillDesc, scarceHeartsDesc}, OptionCategory::Setting, HEARTDROPREFILL_VANILLA);
@ -98,18 +98,18 @@ namespace Settings {
uint8_t MQSet;
bool DungeonModesKnown[12];
Option SetDungeonTypes = Option::Bool("Set Dungeon Types", {"Off", "On"}, {setDungeonTypesDesc});
Option MQDeku = Option::U8 (" Deku Tree", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQDodongo = Option::U8 (" Dodongo's Cavern", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQJabu = Option::U8 (" Jabu-Jabu's Belly", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQForest = Option::U8 (" Forest Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQFire = Option::U8 (" Fire Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQWater = Option::U8 (" Water Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQSpirit = Option::U8 (" Spirit Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQShadow = Option::U8 (" Shadow Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQBotW = Option::U8 (" Bottom of the Well", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQIceCavern = Option::U8 (" Ice Cavern", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQGTG = Option::U8 (" Training Grounds", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQCastle = Option::U8 (" Ganon's Castle", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQDeku = Option::U8 ("Deku Tree", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQDodongo = Option::U8 ("Dodongo's Cavern", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQJabu = Option::U8 ("Jabu-Jabu's Belly", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQForest = Option::U8 ("Forest Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQFire = Option::U8 ("Fire Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQWater = Option::U8 ("Water Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQSpirit = Option::U8 ("Spirit Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQShadow = Option::U8 ("Shadow Temple", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQBotW = Option::U8 ("Bottom of the Well", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQIceCavern = Option::U8 ("Ice Cavern", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQGTG = Option::U8 ("Training Grounds", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
Option MQCastle = Option::U8 ("Ganon's Castle", {"Vanilla", "Master Quest", "Random"}, {setDungeonTypesDesc});
std::vector<Option *> worldOptions = {
&RandomizeWorld,
&StartingAge,
@ -153,9 +153,9 @@ namespace Settings {
//Shuffle Settings
Option RandomizeShuffle = Option::Bool("Randomize Settings", {"No","Yes"}, {shuffleRandomize}, OptionCategory::Toggle);
Option ShuffleRewards = Option::U8 ("Shuffle Dungeon Rewards",{"End of Dungeons", "Any Dungeon", "Overworld", "Anywhere"}, {shuffleRewardsEndOfDungeon, shuffleRewardsAnyDungeon, shuffleRewardsOverworld, shuffleRewardsAnywhere});
Option ShuffleRewards = Option::U8 ("Shuffle Dungeon Rewards",{"End of dungeons", "Any dungeon", "Overworld", "Anywhere"}, {shuffleRewardsEndOfDungeon, shuffleRewardsAnyDungeon, shuffleRewardsOverworld, shuffleRewardsAnywhere});
Option LinksPocketItem = Option::U8 ("Link's Pocket", {"Dungeon Reward", "Advancement", "Anything", "Nothing"}, {linksPocketDungeonReward, linksPocketAdvancement, linksPocketAnything, linksPocketNothing});
Option ShuffleSongs = Option::U8 ("Shuffle Songs", {"Song Locations", "Dungeon Rewards", "Anywhere"}, {songsSongLocations, songsDungeonRewards, songsAllLocations});
Option ShuffleSongs = Option::U8 ("Shuffle Songs", {"Song locations", "Dungeon rewards", "Anywhere"}, {songsSongLocations, songsDungeonRewards, songsAllLocations});
Option Shopsanity = Option::U8 ("Shopsanity", {MultiVecOpts({{"Off"}, NumOpts(0, 4), {"Random"}})}, {shopsOff, shopsZero, shopsOne, shopsTwo, shopsThree, shopsFour, shopsRandom});
Option Tokensanity = Option::U8 ("Tokensanity", {"Off", "Dungeons", "Overworld", "All Tokens"}, {tokensOff, tokensDungeon, tokensOverworld, tokensAllTokens});
Option Scrubsanity = Option::U8 ("Scrub Shuffle", {"Off", "Affordable", "Expensive", "Random Prices"}, {scrubsOff, scrubsAffordable, scrubsExpensive, scrubsRandomPrices});
@ -163,9 +163,10 @@ namespace Settings {
Option ShuffleKokiriSword = Option::Bool("Shuffle Kokiri Sword", {"Off", "On"}, {kokiriSwordDesc});
Option ShuffleOcarinas = Option::Bool("Shuffle Ocarinas", {"Off", "On"}, {ocarinasDesc});
Option ShuffleWeirdEgg = Option::Bool("Shuffle Weird Egg", {"Off", "On"}, {weirdEggDesc});
Option ShuffleGerudoToken = Option::Bool("Shuffle Gerudo Membership Card", {"Off", "On"}, {gerudoTokenDesc});
Option ShuffleGerudoToken = Option::Bool("Shuffle Gerudo Card", {"Off", "On"}, {gerudoTokenDesc});
Option ShuffleMagicBeans = Option::Bool("Shuffle Magic Beans", {"Off", "On"}, {magicBeansDesc});
Option ShuffleMerchants = Option::U8 ("Shuffle Merchants", {"Off", "On (No Hints)", "On (With Hints)"}, {merchantsDesc, merchantsHintsDesc});
Option ShuffleFrogSongRupees = Option::Bool("Shuffle Frog Song Rupees",{"Off", "On"}, {frogSongRupeesDesc});
Option ShuffleAdultTradeQuest = Option::Bool("Shuffle Adult Trade", {"Off", "On"}, {adultTradeDesc});
Option ShuffleChestMinigame = Option::U8 ("Shuffle Chest Minigame", {"Off", "On (Separate)", "On (Pack)"}, {chestMinigameDesc});
std::vector<Option *> shuffleOptions = {
@ -183,6 +184,7 @@ namespace Settings {
&ShuffleGerudoToken,
&ShuffleMagicBeans,
&ShuffleMerchants,
&ShuffleFrogSongRupees,
&ShuffleAdultTradeQuest,
&ShuffleChestMinigame,
};
@ -197,24 +199,24 @@ namespace Settings {
{gerudoKeysVanilla, gerudoKeysAnyDungeon, gerudoKeysOverworld, gerudoKeysAnywhere});
Option BossKeysanity = Option::U8 ("Boss Keys", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"},
{bossKeyStartWith, bossKeyVanilla, bossKeyOwnDungeon, bossKeyAnyDungeon, bossKeyOverworld, bossKeyAnywhere}, OptionCategory::Setting, BOSSKEYSANITY_OWN_DUNGEON);
Option GanonsBossKey = Option::U8 ("Ganon's Boss Key", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere", "LACS-Vanilla", "LACS-Medallions", "LACS-Stones", "LACS-Rewards", "LACS-Dungeons", "LACS-Tokens"},
{ganonKeyStartWith, ganonKeyVanilla, ganonKeyOwnDungeon, ganonKeyAnyDungeon, ganonKeyOverworld, ganonKeyAnywhere, ganonKeyLACS}, OptionCategory::Setting, GANONSBOSSKEY_OWN_DUNGEON);
Option GanonsBossKey = Option::U8 ("Ganon's Boss Key", {"Vanilla", "Own dungeon", "Start with", "Any Dungeon", "Overworld", "Anywhere", "LACS-Vanilla", "LACS-Medallions", "LACS-Stones", "LACS-Rewards", "LACS-Dungeons", "LACS-Tokens"},
{ganonKeyVanilla, ganonKeyOwnDungeon, ganonKeyStartWith, ganonKeyAnyDungeon, ganonKeyOverworld, ganonKeyAnywhere, ganonKeyLACS}, OptionCategory::Setting, GANONSBOSSKEY_VANILLA);
uint8_t LACSCondition = 0;
Option LACSMedallionCount = Option::U8 (" Medallion Count", {NumOpts(0, 6)}, {lacsMedallionCountDesc}, OptionCategory::Setting, 1, true);
Option LACSStoneCount = Option::U8 (" Stone Count", {NumOpts(0, 3)}, {lacsStoneCountDesc}, OptionCategory::Setting, 1, true);
Option LACSRewardCount = Option::U8 (" Reward Count", {NumOpts(0, 9)}, {lacsRewardCountDesc}, OptionCategory::Setting, 1, true);
Option LACSDungeonCount = Option::U8 (" Dungeon Count", {NumOpts(0, 8)}, {lacsDungeonCountDesc}, OptionCategory::Setting, 1, true);
Option LACSTokenCount = Option::U8 (" Token Count", {NumOpts(0, 100)}, {lacsTokenCountDesc}, OptionCategory::Setting, 1, true);
Option LACSMedallionCount = Option::U8 ("Medallion Count", {NumOpts(0, 6)}, {lacsMedallionCountDesc}, OptionCategory::Setting, 1, true);
Option LACSStoneCount = Option::U8 ("Stone Count", {NumOpts(0, 3)}, {lacsStoneCountDesc}, OptionCategory::Setting, 1, true);
Option LACSRewardCount = Option::U8 ("Reward Count", {NumOpts(0, 9)}, {lacsRewardCountDesc}, OptionCategory::Setting, 1, true);
Option LACSDungeonCount = Option::U8 ("Dungeon Count", {NumOpts(0, 8)}, {lacsDungeonCountDesc}, OptionCategory::Setting, 1, true);
Option LACSTokenCount = Option::U8 ("Token Count", {NumOpts(0, 100)}, {lacsTokenCountDesc}, OptionCategory::Setting, 1, true);
Option KeyRings = Option::Bool("Key Rings", {"Off", "On"}, {keyRingDesc});
Option RingFortress = Option::Bool(" Gerudo Fortress", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingForest = Option::Bool(" Forest Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingFire = Option::Bool(" Fire Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingWater = Option::Bool(" Water Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingSpirit = Option::Bool(" Spirit Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingShadow = Option::Bool(" Shadow Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingWell = Option::Bool(" Bottom of the Well", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingGtg = Option::Bool(" GTG", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingCastle = Option::Bool(" Ganon's Castle", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingFortress = Option::Bool("Gerudo Fortress", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingForest = Option::Bool("Forest Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingFire = Option::Bool("Fire Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingWater = Option::Bool("Water Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingSpirit = Option::Bool("Spirit Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingShadow = Option::Bool("Shadow Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingWell = Option::Bool("Bottom of the Well", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingGtg = Option::Bool("GTG", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
Option RingCastle = Option::Bool("Ganon's Castle", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting);
std::vector<Option *> shuffleDungeonItemOptions = {
&RandomizeDungeon,
@ -263,8 +265,9 @@ namespace Settings {
Option NumRequiredCuccos = Option::U8 ("Cuccos to return", {NumOpts(0, 7)}, {numRequiredCuccosDesc});
Option KingZoraSpeed = Option::U8 ("King Zora Speed", {"Fast", "Vanilla", "Random"}, {kingZoraSpeedFast, kingZoraSpeedVanilla, kingZoraSpeedRandom});
Option CompleteMaskQuest = Option::Bool("Complete Mask Quest", {"Off", "On"}, {completeMaskDesc});
Option EnableGlitchCutscenes = Option::Bool("Enable Glitch-Useful Cutscenes", {"Off", "On"}, {glitchCutscenesDesc});
Option QuickText = Option::U8 ("Quick Text", {"0: Vanilla", "1: Skippable", "2: Instant", "3: Turbo"}, {quickTextDesc0, quickTextDesc1, quickTextDesc2, quickTextDesc3}, OptionCategory::Setting, QUICKTEXT_INSTANT);
Option SkipSongReplays = Option::U8 (" Skip Song Replays", {"Don't Skip", "Skip (No SFX)", "Skip (Keep SFX)"}, {skipSongReplaysDesc});
Option SkipSongReplays = Option::U8 ("Skip Song Replays", {"Don't Skip", "Skip (No SFX)", "Skip (Keep SFX)"}, {skipSongReplaysDesc});
Option KeepFWWarpPoint = Option::Bool("Keep FW Warp Point", {"Off", "On"}, {keepFWWarpPointDesc});
Option FastBunnyHood = Option::Bool("Fast Bunny Hood", {"Off", "On"}, {fastBunnyHoodDesc});
std::vector<Option *> timesaverOptions = {
@ -279,6 +282,7 @@ namespace Settings {
&NumRequiredCuccos,
&KingZoraSpeed,
&CompleteMaskQuest,
&EnableGlitchCutscenes,
&QuickText,
&SkipSongReplays,
&KeepFWWarpPoint,
@ -287,8 +291,8 @@ namespace Settings {
//Misc Settings
Option GossipStoneHints = Option::U8 ("Gossip Stone Hints", {"No Hints", "Need Nothing", "Mask of Truth", "Stone of Agony"}, {gossipStonesHintsDesc}, OptionCategory::Setting, HINTS_NEED_NOTHING);
Option ClearerHints = Option::U8 (" Hint Clarity", {"Obscure", "Ambiguous", "Clear"}, {obscureHintsDesc, ambiguousHintsDesc, clearHintsDesc});
Option HintDistribution = Option::U8 (" Hint Distribution", {"Useless", "Balanced", "Strong", "Very Strong"}, {uselessHintsDesc, balancedHintsDesc, strongHintsDesc, veryStrongHintsDesc}, OptionCategory::Setting, 1); // Balanced
Option ClearerHints = Option::U8 ("Hint Clarity", {"Obscure", "Ambiguous", "Clear"}, {obscureHintsDesc, ambiguousHintsDesc, clearHintsDesc});
Option HintDistribution = Option::U8 ("Hint Distribution", {"Useless", "Balanced", "Strong", "Very Strong"}, {uselessHintsDesc, balancedHintsDesc, strongHintsDesc, veryStrongHintsDesc}, OptionCategory::Setting, 1); // Balanced
Option CompassesShowReward = Option::U8 ("Compasses Show Rewards", {"No", "Yes"}, {compassesShowRewardsDesc}, OptionCategory::Setting, 1);
Option CompassesShowWotH = Option::U8 ("Compasses Show WotH", {"No", "Yes"}, {compassesShowWotHDesc}, OptionCategory::Setting, 1);
Option MapsShowDungeonMode = Option::U8 ("Maps Show Dungeon Modes",{"No", "Yes"}, {mapsShowDungeonModesDesc}, OptionCategory::Setting, 1);
@ -321,22 +325,22 @@ namespace Settings {
//Item Usability Settings
Option FaroresWindAnywhere = Option::Bool("Farore's Wind Anywhere", {"Disabled", "Enabled"}, {faroresWindAnywhereDesc});
Option AgeItemsToggle = Option::U8 ("Lift Age Restrictions", {"All Disabled", "All Enabled", "Choose"}, {ageRestrictionsDesc});
Option StickAsAdult = Option::Bool(" Adult Deku Stick", {"Disabled", "Enabled"}, {adultStickDesc});
Option BoomerangAsAdult = Option::Bool(" Adult Boomerang", {"Disabled", "Enabled"}, {adultBoomerangDesc});
Option HammerAsChild = Option::Bool(" Child Hammer", {"Disabled", "Enabled"}, {childHammerDesc});
Option SlingshotAsAdult = Option::Bool(" Adult Slingshot", {"Disabled", "Enabled"}, {adultSlingshotDesc});
Option BowAsChild = Option::Bool(" Child Bow", {"Disabled", "Enabled"}, {childBowDesc});
Option HookshotAsChild = Option::Bool(" Child Hookshot", {"Disabled", "Enabled"}, {childHookshotDesc});
Option IronBootsAsChild = Option::Bool(" Child Iron Boots", {"Disabled", "Enabled"}, {childIronBootsDesc});
Option HoverBootsAsChild = Option::Bool(" Child Hover Boots", {"Disabled", "Enabled"}, {childHoverBootsDesc});
Option MasksAsAdult = Option::Bool(" Adult Masks", {"Disabled", "Enabled"}, {adultMasksDesc});
Option KokiriSwordAsAdult = Option::Bool(" Adult Kokiri Sword", {"Disabled", "Enabled"}, {adultKokiriSwordDesc});
Option MasterSwordAsChild = Option::Bool(" Child Master Sword", {"Disabled", "Enabled"}, {childMasterSwordDesc});
Option BiggoronSwordAsChild= Option::Bool(" Child Biggoron Sword", {"Disabled", "Enabled"}, {childBiggoronSwordDesc});
Option DekuShieldAsAdult = Option::Bool(" Adult Deku Shield", {"Disabled", "Enabled"}, {adultDekuShieldDesc});
Option MirrorShieldAsChild = Option::Bool(" Child Mirror Shield", {"Disabled", "Enabled"}, {childMirrorShieldDesc});
Option GoronTunicAsChild = Option::Bool(" Child Goron Tunic", {"Disabled", "Enabled"}, {childGoronTunicDesc});
Option ZoraTunicAsChild = Option::Bool(" Child Zora Tunic", {"Disabled", "Enabled"}, {childZoraTunicDesc});
Option StickAsAdult = Option::Bool("Adult Deku Stick", {"Disabled", "Enabled"}, {adultStickDesc});
Option BoomerangAsAdult = Option::Bool("Adult Boomerang", {"Disabled", "Enabled"}, {adultBoomerangDesc});
Option HammerAsChild = Option::Bool("Child Hammer", {"Disabled", "Enabled"}, {childHammerDesc});
Option SlingshotAsAdult = Option::Bool("Adult Slingshot", {"Disabled", "Enabled"}, {adultSlingshotDesc});
Option BowAsChild = Option::Bool("Child Bow", {"Disabled", "Enabled"}, {childBowDesc});
Option HookshotAsChild = Option::Bool("Child Hookshot", {"Disabled", "Enabled"}, {childHookshotDesc});
Option IronBootsAsChild = Option::Bool("Child Iron Boots", {"Disabled", "Enabled"}, {childIronBootsDesc});
Option HoverBootsAsChild = Option::Bool("Child Hover Boots", {"Disabled", "Enabled"}, {childHoverBootsDesc});
Option MasksAsAdult = Option::Bool("Adult Masks", {"Disabled", "Enabled"}, {adultMasksDesc});
Option KokiriSwordAsAdult = Option::Bool("Adult Kokiri Sword", {"Disabled", "Enabled"}, {adultKokiriSwordDesc});
Option MasterSwordAsChild = Option::Bool("Child Master Sword", {"Disabled", "Enabled"}, {childMasterSwordDesc});
Option BiggoronSwordAsChild= Option::Bool("Child Biggoron Sword", {"Disabled", "Enabled"}, {childBiggoronSwordDesc});
Option DekuShieldAsAdult = Option::Bool("Adult Deku Shield", {"Disabled", "Enabled"}, {adultDekuShieldDesc});
Option MirrorShieldAsChild = Option::Bool("Child Mirror Shield", {"Disabled", "Enabled"}, {childMirrorShieldDesc});
Option GoronTunicAsChild = Option::Bool("Child Goron Tunic", {"Disabled", "Enabled"}, {childGoronTunicDesc});
Option ZoraTunicAsChild = Option::Bool("Child Zora Tunic", {"Disabled", "Enabled"}, {childZoraTunicDesc});
Option GkDurability = Option::U8 ("GK Durability", {"Vanilla", "Random Risk", "Random Safe"}, {gkDurabilityVanilla, gkDurabilityRandomRisk, gkDurabilityRandomSafe});
std::vector<Option *> itemUsabilityOptions = {
&FaroresWindAnywhere,
@ -430,7 +434,7 @@ namespace Settings {
Option StartingStickCapacity = Option::U8 ("Deku Stick Capacity", {NumOpts(10, 30, 10, {}, " Deku Sticks")}, {""});
Option StartingNutCapacity = Option::U8 ("Deku Nut Capacity", {NumOpts(20, 40, 10, {}, " Deku Nuts")}, {""});
Option StartingSlingshot = Option::U8 ("Slingshot", {"Off", "Slingshot (30)", "Slingshot (40)", "Slingshot (50)"}, {""});
Option StartingOcarina = Option::U8 ("Ocarina", {"Off", "Fairy Ocarina", "Ocarina of Time"}, {""});
Option StartingOcarina = Option::U8 ("Start with Fairy Ocarina", {"Off", "Fairy Ocarina", "Ocarina of Time"}, {""});
Option StartingBombBag = Option::U8 ("Bombs", {"Off", "Bomb Bag (20)", "Bomb Bag (30)", "Bomb Bag (40)"}, {""});
Option StartingBombchus = Option::U8 ("Bombchus", {"Off", "20 Bombchus", "50 Bombchus"}, {""});
Option StartingBoomerang = Option::U8 ("Boomerang", {"Off", "On"}, {""});
@ -507,9 +511,9 @@ namespace Settings {
&StartingPreludeOfLight,
};
Option StartingKokiriSword = Option::U8 ("Kokiri Sword", {"Off", "On"}, {""});
Option StartingKokiriSword = Option::U8 ("Start with Kokiri Sword", {"Off", "On"}, {""});
Option StartingBiggoronSword = Option::U8 ("Biggoron Sword", {"Off", "Giant's Knife", "Biggoron Sword"}, {""});
Option StartingDekuShield = Option::U8 ("Deku Shield", {"Off", "On"}, {""});
Option StartingDekuShield = Option::U8 ("Start with Deku Shield", {"Off", "On"}, {""});
Option StartingHylianShield = Option::U8 ("Hylian Shield", {"Off", "On"}, {""});
Option StartingMirrorShield = Option::U8 ("Mirror Shield", {"Off", "On"}, {""});
Option StartingGoronTunic = Option::U8 ("Goron Tunic", {"Off", "On"}, {""});
@ -1263,6 +1267,7 @@ namespace Settings {
ctx.shuffleGerudoToken = (ShuffleGerudoToken) ? 1 : 0;
ctx.shuffleMagicBeans = (ShuffleMagicBeans) ? 1 : 0;
ctx.shuffleMerchants = ShuffleMerchants.Value<uint8_t>();
ctx.shuffleFrogSongRupees= (ShuffleFrogSongRupees) ? 1 : 0;
ctx.shuffleAdultTradeQuest = (ShuffleAdultTradeQuest) ? 1 : 0;
ctx.shuffleChestMinigame = ShuffleChestMinigame.Value<uint8_t>();
@ -1299,6 +1304,7 @@ namespace Settings {
ctx.numRequiredCuccos = NumRequiredCuccos.Value<uint8_t>();
ctx.kingZoraSpeed = KingZoraSpeed.Value<uint8_t>();
ctx.completeMaskQuest = CompleteMaskQuest ? 1 : 0;
ctx.enableGlitchCutscenes = EnableGlitchCutscenes ? 1 : 0;
ctx.quickText = QuickText.Value<uint8_t>();
ctx.skipSongReplays = SkipSongReplays.Value<uint8_t>();
ctx.keepFWWarpPoint = KeepFWWarpPoint ? 1 : 0;
@ -1724,6 +1730,21 @@ namespace Settings {
IncludeAndHide({WASTELAND_BOMBCHU_SALESMAN});
}
//Force include frog song rupees if they're not shuffled
if (ShuffleFrogSongRupees) {
Unhide({ZR_FROGS_ZELDAS_LULLABY});
Unhide({ZR_FROGS_EPONAS_SONG});
Unhide({ZR_FROGS_SARIAS_SONG});
Unhide({ZR_FROGS_SUNS_SONG});
Unhide({ZR_FROGS_SONG_OF_TIME});
} else {
IncludeAndHide({ZR_FROGS_ZELDAS_LULLABY});
IncludeAndHide({ZR_FROGS_EPONAS_SONG});
IncludeAndHide({ZR_FROGS_SARIAS_SONG});
IncludeAndHide({ZR_FROGS_SUNS_SONG});
IncludeAndHide({ZR_FROGS_SONG_OF_TIME});
}
//Force include adult trade quest if Shuffle Adult Trade Quest is off
std::vector<uint32_t> adultTradeLocations = {KAK_TRADE_POCKET_CUCCO, LW_TRADE_COJIRO, KAK_TRADE_ODD_MUSHROOM, LW_TRADE_ODD_POTION, GV_TRADE_SAW, DMT_TRADE_BROKEN_SWORD, ZD_TRADE_PRESCRIPTION, LH_TRADE_FROG, DMT_TRADE_EYEDROPS};
if (ShuffleAdultTradeQuest) {
@ -2261,6 +2282,7 @@ namespace Settings {
&ShuffleCows,
&ShuffleMagicBeans,
&ShuffleMerchants,
&ShuffleFrogSongRupees,
&ShuffleAdultTradeQuest,
&GossipStoneHints,
};
@ -2463,6 +2485,17 @@ namespace Settings {
//Function to set flags depending on settings
void UpdateSettings(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettings) {
// RANDTODO: Switch this back once all logic options are implemented
// Logic.SetSelectedIndex(cvarSettings[RSK_LOGIC_RULES]);
switch (cvarSettings[RSK_LOGIC_RULES]) {
case 0:
Logic.SetSelectedIndex(0);
break;
case 1:
Logic.SetSelectedIndex(2);
break;
}
OpenForest.SetSelectedIndex(cvarSettings[RSK_FOREST]);
OpenKakariko.SetSelectedIndex(cvarSettings[RSK_KAK_GATE]);
ZorasFountain.SetSelectedIndex(cvarSettings[RSK_ZORAS_FOUNTAIN]);
@ -2488,6 +2521,8 @@ namespace Settings {
ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]);
ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]);
Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]);
ShuffleCows.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_COWS]);
ShuffleKokiriSword.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_KOKIRI_SWORD]);
ShuffleOcarinas.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OCARINA]);
@ -2503,6 +2538,9 @@ namespace Settings {
SkipChildStealth.SetSelectedIndex(cvarSettings[RSK_SKIP_CHILD_STEALTH]);
ShuffleGerudoToken.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD]);
ShuffleFrogSongRupees.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_FROG_SONG_RUPEES]);
ShuffleAdultTradeQuest.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_ADULT_TRADE]);
// the checkbox works because 0 is "Off" and 1 is "Fairy Ocarina"
StartingOcarina.SetSelectedIndex(cvarSettings[RSK_STARTING_OCARINA]);
@ -2511,14 +2549,7 @@ namespace Settings {
StartingDekuShield.SetSelectedIndex(cvarSettings[RSK_STARTING_DEKU_SHIELD]);
StartingKokiriSword.SetSelectedIndex(cvarSettings[RSK_STARTING_KOKIRI_SWORD]);
if(cvarSettings[RSK_STARTING_MAPS_COMPASSES]) {
// "Start With" is index 0
MapsAndCompasses.SetSelectedIndex(0);
} else {
// We don't support maps/compasses outside of their own dungeon yet
// "Own Dungeon" is index 2
MapsAndCompasses.SetSelectedIndex(2);
}
MapsAndCompasses.SetSelectedIndex(cvarSettings[RSK_STARTING_MAPS_COMPASSES]);
StartingConsumables.SetSelectedIndex(cvarSettings[RSK_STARTING_CONSUMABLES]);
StartingMaxRupees.SetSelectedIndex(cvarSettings[RSK_FULL_WALLETS]);
@ -2530,6 +2561,9 @@ namespace Settings {
ItemPoolValue.SetSelectedIndex(cvarSettings[RSK_ITEM_POOL]);
IceTrapValue.SetSelectedIndex(cvarSettings[RSK_ICE_TRAPS]);
Keysanity.SetSelectedIndex(cvarSettings[RSK_KEYSANITY]);
GerudoKeys.SetSelectedIndex(cvarSettings[RSK_GERUDO_KEYS]);
BossKeysanity.SetSelectedIndex(cvarSettings[RSK_BOSS_KEYSANITY]);
GanonsBossKey.SetSelectedIndex(cvarSettings[RSK_GANONS_BOSS_KEY]);
NumRequiredCuccos.SetSelectedIndex(cvarSettings[RSK_CUCCO_COUNT]);
@ -2539,6 +2573,12 @@ namespace Settings {
SkipTowerEscape.SetSelectedIndex(cvarSettings[RSK_SKIP_TOWER_ESCAPE]);
CompleteMaskQuest.SetSelectedIndex(cvarSettings[RSK_COMPLETE_MASK_QUEST]);
EnableGlitchCutscenes.SetSelectedIndex(cvarSettings[RSK_ENABLE_GLITCH_CUTSCENES]);
NightGSExpectSuns.SetSelectedIndex(cvarSettings[RSK_SKULLS_SUNS_SONG]);
// RANDOTODO implement chest shuffle with keysanity
// ShuffleChestMinigame.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]);

View File

@ -34,8 +34,8 @@ typedef enum {
typedef enum {
OPENFOREST_CLOSED,
OPENFOREST_OPEN,
OPENFOREST_CLOSED_DEKU,
OPENFOREST_OPEN,
} OpenForestSetting;
typedef enum {
@ -44,9 +44,9 @@ typedef enum {
} OpenKakarikoSetting;
typedef enum {
OPENDOOROFTIME_OPEN,
OPENDOOROFTIME_CLOSED,
OPENDOOROFTIME_INTENDED,
OPENDOOROFTIME_CLOSED,
OPENDOOROFTIME_OPEN,
} OpenDoorOfTimeSetting;
typedef enum {
@ -62,8 +62,8 @@ typedef enum {
} GerudoFortressSetting;
typedef enum {
RAINBOWBRIDGE_OPEN,
RAINBOWBRIDGE_VANILLA,
RAINBOWBRIDGE_OPEN,
RAINBOWBRIDGE_STONES,
RAINBOWBRIDGE_MEDALLIONS,
RAINBOWBRIDGE_REWARDS,
@ -212,9 +212,9 @@ typedef enum {
} BossKeysanitySetting;
typedef enum {
GANONSBOSSKEY_START_WITH,
GANONSBOSSKEY_VANILLA,
GANONSBOSSKEY_OWN_DUNGEON,
GANONSBOSSKEY_START_WITH,
GANONSBOSSKEY_ANY_DUNGEON,
GANONSBOSSKEY_OVERWORLD,
GANONSBOSSKEY_ANYWHERE,
@ -403,6 +403,7 @@ typedef struct {
uint8_t shuffleGerudoToken;
uint8_t shuffleMagicBeans;
uint8_t shuffleMerchants;
uint8_t shuffleFrogSongRupees;
uint8_t shuffleAdultTradeQuest;
uint8_t shuffleChestMinigame;
@ -439,6 +440,7 @@ typedef struct {
uint8_t numRequiredCuccos;
uint8_t kingZoraSpeed;
uint8_t completeMaskQuest;
uint8_t enableGlitchCutscenes;
uint8_t quickText;
uint8_t skipSongReplays;
uint8_t keepFWWarpPoint;
@ -904,6 +906,7 @@ void UpdateSettings(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettin
extern Option ShuffleGerudoToken;
extern Option ShuffleMagicBeans;
extern Option ShuffleMerchants;
extern Option ShuffleFrogSongRupees;
extern Option ShuffleAdultTradeQuest;
extern Option ShuffleChestMinigame;
@ -940,6 +943,7 @@ void UpdateSettings(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettin
extern Option NumRequiredCuccos;
extern Option KingZoraSpeed;
extern Option CompleteMaskQuest;
extern Option EnableGlitchCutscenes;
extern Option QuickText;
extern Option SkipSongReplays;
extern Option KeepFWWarpPoint;

View File

@ -347,7 +347,9 @@ static void WriteSettings(const bool printAll = false) {
setting->GetName() == "Cuccos to return" ||
setting->GetName() == "Skip Epona Race" ||
setting->GetName() == "Skip Tower Escape" ||
setting->GetName() == "Skip Child Stealth") {
setting->GetName() == "Skip Child Stealth" ||
setting->GetName() == "Complete Mask Quest" ||
setting->GetName() == "Enable Glitch-Useful Cutscenes") {
std::string settingName = menu->name + ":" + setting->GetName();
jsonData["settings"][settingName] = setting->GetSelectedOptionText();
}
@ -426,11 +428,11 @@ static void WriteStartingInventory() {
// doesn't work, and because it'd be bad to set every single possible starting
// inventory item as "false" in the json, we're just going to check
// to see if the name is one of the 3 we're using rn
if(setting->GetName() == "Deku Shield" || setting->GetName() == "Kokiri Sword" || setting->GetName() == "Ocarina") {
jsonData["settings"]["Start With " + setting->GetName()] = setting->GetSelectedOptionText();
}
if (setting->GetName() == "Start with Consumables" || setting->GetName() == "Start with Max Rupees") {
if (setting->GetName() == "Start with Consumables" ||
setting->GetName() == "Start with Max Rupees" ||
setting->GetName() == "Start with Fairy Ocarina" ||
setting->GetName() == "Start with Kokiri Sword" ||
setting->GetName() == "Start with Deku Shield") {
jsonData["settings"][setting->GetName()] = setting->GetSelectedOptionText();
}
}

View File

@ -0,0 +1,33 @@
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#include "functions.h"
#include "variables.h"
#include "macros.h"
void Randomizer_ConsumeAdultTradeItem(GlobalContext* globalCtx, u8 itemId) {
gSaveContext.adultTradeItems &= ~ADULT_TRADE_FLAG(itemId);
Inventory_ReplaceItem(globalCtx, itemId, Randomizer_GetNextAdultTradeItem());
}
u8 Randomizer_GetNextAdultTradeItem() {
const u8 numTradeItems = ITEM_CLAIM_CHECK - ITEM_POCKET_EGG + 1;
u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_ADULT) - ITEM_POCKET_EGG;
for (int i = 0; i < numTradeItems; i++) {
u8 tradeIndex = (currentTradeItemIndex + i + 1) % numTradeItems;
if (gSaveContext.adultTradeItems & (1 << tradeIndex)) {
return ITEM_POCKET_EGG + tradeIndex;
}
}
return ITEM_NONE;
}
u8 Randomizer_GetPrevAdultTradeItem() {
const u8 numTradeItems = ITEM_CLAIM_CHECK - ITEM_POCKET_EGG + 1;
u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_ADULT) - ITEM_POCKET_EGG;
for (int i = 0; i < numTradeItems; i++) {
u8 tradeIndex = (currentTradeItemIndex - i - 1 + numTradeItems) % numTradeItems;
if (gSaveContext.adultTradeItems & (1 << tradeIndex)) {
return ITEM_POCKET_EGG + tradeIndex;
}
}
return ITEM_NONE;
}

View File

@ -0,0 +1,13 @@
#ifndef Z_ADULT_TRADE_SHUFFLE_H
#define Z_ADULT_TRADE_SHUFFLE_H
#include <z64.h>
#define ADULT_TRADE_FLAG(itemId) (1 << (itemId - ITEM_POCKET_EGG))
#define PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(itemID) (gSaveContext.adultTradeItems & ADULT_TRADE_FLAG(itemID))
void Randomizer_ConsumeAdultTradeItem(GlobalContext* globalCtx, u8 itemId);
u8 Randomizer_GetNextAdultTradeItem();
u8 Randomizer_GetPrevAdultTradeItem();
#endif

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@ typedef struct {
} Sprite;
typedef enum {
RC_UNKNOWN_CHECK,
RC_LINKS_POCKET,
RC_QUEEN_GOHMA,
RC_KING_DODONGO,
@ -757,7 +758,7 @@ typedef enum {
RC_ZR_NEAR_DOMAIN_GOSSIP_STONE,
RC_ZR_NEAR_GROTTOS_GOSSIP_STONE,
RC_ZR_OPEN_GROTTO_GOSSIP_STONE,
RC_UNKNOWN_CHECK
RC_MAX
} RandomizerCheck;
// based on https://github.com/TestRunnerSRL/OoT-Randomizer/blob/e337d7f603b91a6bacb618fb32cc7fd70ed9ffca/ItemList.py
@ -960,6 +961,7 @@ typedef enum {
typedef enum {
RSK_NONE,
RSK_LOGIC_RULES,
RSK_FOREST,
RSK_KAK_GATE,
RSK_DOOR_OF_TIME,
@ -978,16 +980,22 @@ typedef enum {
RSK_STARTING_DEKU_SHIELD,
RSK_STARTING_KOKIRI_SWORD,
RSK_SHUFFLE_KOKIRI_SWORD,
RSK_STARTING_MAPS_COMPASSES, //RANDOTODO more options for this, rn it's just start with or own dungeon
RSK_STARTING_MAPS_COMPASSES,
RSK_SHUFFLE_DUNGEON_REWARDS,
RSK_SHUFFLE_SONGS,
RSK_SHUFFLE_TOKENS,
RSK_SHUFFLE_COWS,
RSK_SHUFFLE_WEIRD_EGG,
RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD,
RSK_SHUFFLE_FROG_SONG_RUPEES,
RSK_ITEM_POOL,
RSK_ICE_TRAPS,
RSK_GOSSIP_STONE_HINTS,
RSK_HINT_CLARITY,
RSK_HINT_DISTRIBUTION,
RSK_KEYSANITY,
RSK_GERUDO_KEYS,
RSK_BOSS_KEYSANITY,
RSK_GANONS_BOSS_KEY,
RSK_SKIP_CHILD_STEALTH,
RSK_SKIP_CHILD_ZELDA,
@ -1004,5 +1012,9 @@ typedef enum {
RSK_CUCCO_COUNT,
RSK_BIG_POE_COUNT,
RSK_SKIP_EPONA_RACE,
RSK_SKIP_TOWER_ESCAPE
RSK_SKIP_TOWER_ESCAPE,
RSK_COMPLETE_MASK_QUEST,
RSK_ENABLE_GLITCH_CUTSCENES,
RSK_SKULLS_SUNS_SONG,
RSK_SHUFFLE_ADULT_TRADE
} RandomizerSettingKey;

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
#pragma once
void InitItemTracker();
void DrawItemTracker(bool& open);
void DrawItemTracker(bool& open);
void DrawItemAmmo(int itemId);

View File

@ -1726,7 +1726,15 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) {
}
if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) {
if (CVar_GetS32("gInjectSkulltulaCount", 0) != 0) {
if (CVar_GetS32("gSkulltulaFreeze", 0) != 0) {
// The freeze text cannot be manually dismissed and must be auto-dismissed.
// This is fine and even wanted when skull tokens are not shuffled, but when
// when they are shuffled we don't want to be able to manually dismiss the box.
// Otherwise if we get a token from a chest or an NPC we get stuck in the ItemGet
// animation until the text box auto-dismisses.
// RANDOTODO: Implement a way to determine if an item came from a skulltula and
// inject the auto-dismiss control code if it did.
if (CVar_GetS32("gSkulltulaFreeze", 0) != 0 &&
!(gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_TOKENS) > 0)) {
textId = TEXT_GS_NO_FREEZE;
} else {
textId = TEXT_GS_FREEZE;

View File

@ -88,6 +88,8 @@ void SaveManager::LoadRandomizerVersion1() {
for (int i = 0; i < ARRAY_COUNT(gSaveContext.ganonText); i++) {
SaveManager::Instance->LoadData("gt" + std::to_string(i), gSaveContext.ganonText[i]);
}
SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems);
}
void SaveManager::SaveRandomizer() {
@ -130,6 +132,8 @@ void SaveManager::SaveRandomizer() {
for (int i = 0; i < ARRAY_COUNT(gSaveContext.ganonText); i++) {
SaveManager::Instance->SaveData("gt" + std::to_string(i), gSaveContext.ganonText[i]);
}
SaveManager::Instance->SaveData("adultTradeItems", gSaveContext.adultTradeItems);
}
void SaveManager::Init() {
@ -736,6 +740,10 @@ void SaveManager::LoadBaseVersion1() {
SaveManager::Instance->LoadArray("trialsDone", ARRAY_COUNT(gSaveContext.trialsDone),
[](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.trialsDone[i]); });
SaveManager::Instance->LoadArray("cowsMilked", ARRAY_COUNT(gSaveContext.cowsMilked), [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.cowsMilked[i]);
});
}
void SaveManager::LoadBaseVersion2() {
@ -896,6 +904,10 @@ void SaveManager::LoadBaseVersion2() {
SaveManager::Instance->LoadArray("trialsDone", ARRAY_COUNT(gSaveContext.trialsDone),
[](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.trialsDone[i]); });
SaveManager::Instance->LoadArray("cowsMilked", ARRAY_COUNT(gSaveContext.cowsMilked), [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.cowsMilked[i]);
});
}
void SaveManager::SaveBase() {
@ -1052,6 +1064,10 @@ void SaveManager::SaveBase() {
SaveManager::Instance->SaveArray("trialsDone", ARRAY_COUNT(gSaveContext.trialsDone),
[](size_t i) { SaveManager::Instance->SaveData("", gSaveContext.trialsDone[i]); });
SaveManager::Instance->SaveArray("cowsMilked", ARRAY_COUNT(gSaveContext.cowsMilked), [](size_t i) {
SaveManager::Instance->SaveData("", gSaveContext.cowsMilked[i]);
});
}
void SaveManager::SaveArray(const std::string& name, const size_t size, SaveArrayFunc func) {

View File

@ -1246,6 +1246,7 @@ void Audio_StepFreqLerp(FreqLerp* lerp);
void func_800F56A8(void);
void Audio_PlayNatureAmbienceSequence(u8 natureAmbienceId);
s32 Audio_SetGanonDistVol(u8 targetVol);
void Audio_PlayFanfare_Rando(ItemID getItemId);
// Function originally not called, so repurposing for DPad input
void func_800EC960(u8 dpad) {
@ -3889,6 +3890,49 @@ void Audio_ResetSfxChannelState(void) {
sAudioCodeReverb = 0;
}
// Function to play "get-item" fanfares according to the type of item obtained (used in rando)
// Longer fanfares for medallions/stones/songs are behind the Cvar
void Audio_PlayFanfare_Rando(ItemID getItemId) {
s32 temp1;
if (((getItemId >= GI_RUPEE_GREEN) && (getItemId <= GI_RUPEE_RED)) ||
((getItemId >= GI_RUPEE_PURPLE) && (getItemId <= GI_RUPEE_GOLD)) ||
((getItemId >= GI_RUPEE_GREEN_LOSE) && (getItemId <= GI_RUPEE_PURPLE_LOSE)) || (getItemId == GI_HEART)) {
Audio_PlaySoundGeneral(NA_SE_SY_GET_BOXITEM, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
} else {
if ((getItemId == GI_HEART_CONTAINER_2) || (getItemId == GI_HEART_CONTAINER) ||
((getItemId == GI_HEART_PIECE) && ((gSaveContext.inventory.questItems & 0xF0000000) == 0x40000000))) {
temp1 = NA_BGM_HEART_GET | 0x900;
} else {
temp1 = (getItemId == GI_HEART_PIECE) ? NA_BGM_SMALL_ITEM_GET : NA_BGM_ITEM_GET | 0x900;
}
// If we get a skulltula token or the "WINNER" heart, play "get small item"
if (getItemId == GI_SKULL_TOKEN || getItemId == GI_HEART_PIECE_WIN) {
temp1 = NA_BGM_SMALL_ITEM_GET | 0x900;
}
// But if the "WINNER" heart is the 4th heart piece collected, play "get heart container"
if (getItemId == GI_HEART_PIECE_WIN && ((gSaveContext.inventory.questItems & 0xF0000000) == 0x40000000)) {
temp1 = NA_BGM_HEART_GET | 0x900;
}
// If the setting is toggled on and we get special quest items (longer fanfares):
if (CVar_GetS32("gRandoQuestItemFanfares", 0) != 0) {
// If we get a medallion, play the "get a medallion" fanfare
if ((getItemId >= RG_FOREST_MEDALLION) && (getItemId <= RG_LIGHT_MEDALLION)) {
temp1 = NA_BGM_MEDALLION_GET | 0x900;
}
// If it's a Spiritual Stone, play the "get a spiritual stone" fanfare
if ((getItemId >= RG_KOKIRI_EMERALD) && (getItemId <= RG_ZORA_SAPPHIRE)) {
temp1 = NA_BGM_SPIRITUAL_STONE | 0x900;
}
// If the item we're getting is a song, play the "learned a song" fanfare
if ((getItemId >= RG_ZELDAS_LULLABY) && (getItemId <= RG_PRELUDE_OF_LIGHT)) {
temp1 = NA_BGM_OCA_FAIRY_GET | 0x900;
}
}
Audio_PlayFanfare(temp1);
}
}
void func_800F3F3C(u8 arg0) {
if (gSoundBankMuted[0] != 1) {
Audio_StartSeq(SEQ_PLAYER_BGM_SUB, 0, NA_BGM_VARIOUS_SFX);

View File

@ -1966,6 +1966,10 @@ s32 GiveItemWithoutActor(GlobalContext* globalCtx, s32 getItemId) {
player->getItemId = getItemId;
player->interactRangeActor = &player->actor;
player->getItemDirection = player->actor.shape.rot.y;
// Player state 26 = Player is frozen
if (player->stateFlags1 & (PLAYER_STATE1_26)) {
player->pendingIceTrap = false;
}
return true;
}
}

View File

@ -33,19 +33,21 @@ void GameOver_Update(GlobalContext* globalCtx) {
gSaveContext.eventInf[1] &= ~1;
// search inventory for spoiling items and revert if necessary
for (i = 0; i < ARRAY_COUNT(gSpoilingItems); i++) {
if (INV_CONTENT(ITEM_POCKET_EGG) == gSpoilingItems[i]) {
INV_CONTENT(gSpoilingItemReverts[i]) = gSpoilingItemReverts[i];
if (!(gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE))) {
for (i = 0; i < ARRAY_COUNT(gSpoilingItems); i++) {
if (INV_CONTENT(ITEM_POCKET_EGG) == gSpoilingItems[i]) {
INV_CONTENT(gSpoilingItemReverts[i]) = gSpoilingItemReverts[i];
// search c buttons for the found spoiling item and revert if necessary
for (j = 1; j < ARRAY_COUNT(gSaveContext.equips.buttonItems); j++) {
if (gSaveContext.equips.buttonItems[j] == gSpoilingItems[i]) {
gSaveContext.equips.buttonItems[j] = gSpoilingItemReverts[i];
Interface_LoadItemIcon1(globalCtx, j);
// search c buttons for the found spoiling item and revert if necessary
for (j = 1; j < ARRAY_COUNT(gSaveContext.equips.buttonItems); j++) {
if (gSaveContext.equips.buttonItems[j] == gSpoilingItems[i]) {
gSaveContext.equips.buttonItems[j] = gSpoilingItemReverts[i];
Interface_LoadItemIcon1(globalCtx, j);
}
}
}
}
}
}
// restore "temporary B" to the B Button if not a sword item
if (gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KOKIRI &&

View File

@ -2101,7 +2101,7 @@ void func_80075B44(GlobalContext* globalCtx) {
gSaveContext.dogIsLost = true;
func_80078884(NA_SE_EV_CHICKEN_CRY_M);
if ((Inventory_ReplaceItem(globalCtx, ITEM_WEIRD_EGG, ITEM_CHICKEN) ||
Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO)) &&
Inventory_HatchPocketCucco(globalCtx)) &&
globalCtx->csCtx.state == 0 && !Player_InCsMode(globalCtx)) {
Message_StartTextbox(globalCtx, 0x3066, NULL);
}

View File

@ -1663,6 +1663,7 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) {
gSaveContext.eventInf[0] = gSaveContext.eventInf[1] = gSaveContext.eventInf[2] = gSaveContext.eventInf[3] = 0;
}
// RANDOTODO: Use this for ice trap messages
if (CustomMessage_RetrieveIfExists(globalCtx)) {
osSyncPrintf("Found custom message");
} else if (sTextIsCredits) {

View File

@ -3,6 +3,7 @@
#include "textures/parameter_static/parameter_static.h"
#include "textures/do_action_static/do_action_static.h"
#include "textures/icon_item_static/icon_item_static.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#ifdef _MSC_VER
#include <stdlib.h>
@ -1686,29 +1687,6 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
}
return ITEM_NONE;
} else if (item == ITEM_KEY_SMALL) {
// Small key exceptions for rando.
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;
@ -2100,6 +2078,10 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
gSaveContext.itemGetInf[1] |= 0x8000;
}
if (item >= ITEM_POCKET_EGG) {
gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item);
}
temp = INV_CONTENT(item);
INV_CONTENT(item) = item;
@ -2241,6 +2223,98 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) {
return ITEM_NONE;
}
}
} else if ((item >= RG_GERUDO_FORTRESS_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)) {
int mapIndex = gSaveContext.mapIndex;
switch (item) {
case RG_DEKU_TREE_MAP:
case RG_DEKU_TREE_COMPASS:
mapIndex = SCENE_YDAN;
break;
case RG_DODONGOS_CAVERN_MAP:
case RG_DODONGOS_CAVERN_COMPASS:
mapIndex = SCENE_DDAN;
break;
case RG_JABU_JABUS_BELLY_MAP:
case RG_JABU_JABUS_BELLY_COMPASS:
mapIndex = SCENE_BDAN;
break;
case RG_FOREST_TEMPLE_MAP:
case RG_FOREST_TEMPLE_COMPASS:
case RG_FOREST_TEMPLE_SMALL_KEY:
case RG_FOREST_TEMPLE_BOSS_KEY:
mapIndex = SCENE_BMORI1;
break;
case RG_FIRE_TEMPLE_MAP:
case RG_FIRE_TEMPLE_COMPASS:
case RG_FIRE_TEMPLE_SMALL_KEY:
case RG_FIRE_TEMPLE_BOSS_KEY:
mapIndex = SCENE_HIDAN;
break;
case RG_WATER_TEMPLE_MAP:
case RG_WATER_TEMPLE_COMPASS:
case RG_WATER_TEMPLE_SMALL_KEY:
case RG_WATER_TEMPLE_BOSS_KEY:
mapIndex = SCENE_MIZUSIN;
break;
case RG_SPIRIT_TEMPLE_MAP:
case RG_SPIRIT_TEMPLE_COMPASS:
case RG_SPIRIT_TEMPLE_SMALL_KEY:
case RG_SPIRIT_TEMPLE_BOSS_KEY:
mapIndex = SCENE_JYASINZOU;
break;
case RG_SHADOW_TEMPLE_MAP:
case RG_SHADOW_TEMPLE_COMPASS:
case RG_SHADOW_TEMPLE_SMALL_KEY:
case RG_SHADOW_TEMPLE_BOSS_KEY:
mapIndex = SCENE_HAKADAN;
break;
case RG_BOTTOM_OF_THE_WELL_MAP:
case RG_BOTTOM_OF_THE_WELL_COMPASS:
case RG_BOTTOM_OF_THE_WELL_SMALL_KEY:
mapIndex = SCENE_HAKADANCH;
break;
case RG_ICE_CAVERN_MAP:
case RG_ICE_CAVERN_COMPASS:
mapIndex = SCENE_ICE_DOUKUTO;
break;
case RG_GANONS_CASTLE_BOSS_KEY:
mapIndex = SCENE_GANON;
break;
case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY:
mapIndex = SCENE_MEN;
break;
case RG_GERUDO_FORTRESS_SMALL_KEY:
mapIndex = SCENE_GERUDOWAY;
break;
case RG_GANONS_CASTLE_SMALL_KEY:
mapIndex = SCENE_GANONTIKA;
break;
}
if ((item >= RG_GERUDO_FORTRESS_SMALL_KEY) && (item <= RG_GANONS_CASTLE_SMALL_KEY)) {
if (gSaveContext.inventory.dungeonKeys[mapIndex] < 0) {
gSaveContext.inventory.dungeonKeys[mapIndex] = 1;
return RG_NONE;
} else {
gSaveContext.inventory.dungeonKeys[mapIndex]++;
return RG_NONE;
}
} else {
int bitmask;
if ((item >= RG_DEKU_TREE_MAP) && (item <= RG_ICE_CAVERN_MAP)) {
bitmask = gBitFlags[2];
} else if ((item >= RG_DEKU_TREE_COMPASS) && (item <= RG_ICE_CAVERN_COMPASS)) {
bitmask = gBitFlags[1];
} else {
bitmask = gBitFlags[0];
}
gSaveContext.inventory.dungeonItems[mapIndex] |= bitmask;
return RG_NONE;
}
}
temp = gSaveContext.inventory.items[slot];
@ -2303,6 +2377,13 @@ u8 Item_CheckObtainability(u8 item) {
} else {
return ITEM_NONE;
}
} else if ( gSaveContext.n64ddFlag &&
((item >= RG_GERUDO_FORTRESS_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))
) {
return ITEM_NONE;
} else if ((item == ITEM_KEY_BOSS) || (item == ITEM_COMPASS) || (item == ITEM_DUNGEON_MAP)) {
return ITEM_NONE;
} else if (item == ITEM_KEY_SMALL) {
@ -2504,6 +2585,21 @@ s32 Inventory_ConsumeFairy(GlobalContext* globalCtx) {
return 0;
}
bool Inventory_HatchPocketCucco(GlobalContext* globalCtx) {
if (!gSaveContext.n64ddFlag) {
return Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO);
}
if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) {
return 0;
}
gSaveContext.adultTradeItems &= ~ADULT_TRADE_FLAG(ITEM_POCKET_EGG);
gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(ITEM_POCKET_CUCCO);
Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO);
return 1;
}
void func_80086D5C(s32* buf, u16 size) {
u16 i;

View File

@ -400,7 +400,7 @@ void Gameplay_Init(GameState* thisx) {
gSaveContext.bgsDayCount++;
gSaveContext.dogIsLost = true;
if (Inventory_ReplaceItem(globalCtx, ITEM_WEIRD_EGG, ITEM_CHICKEN) ||
Inventory_ReplaceItem(globalCtx, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO)) {
Inventory_HatchPocketCucco(globalCtx)) {
Message_StartTextbox(globalCtx, 0x3066, NULL);
}
gSaveContext.nextDayTime = 0xFFFE;

View File

@ -23,6 +23,8 @@
#include "overlays/actors/ovl_Bg_Dodoago/z_bg_dodoago.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define ENTRANCE(scene, spawn, continueBgm, displayTitleCard, fadeIn, fadeOut) \
{ \
scene, spawn, \
@ -2136,7 +2138,11 @@ void func_8009EE44(GlobalContext* globalCtx) {
gDPPipeSync(POLY_OPA_DISP++);
gDPSetEnvColor(POLY_OPA_DISP++, 128, 128, 128, 128);
if ((globalCtx->roomCtx.unk_74[0] == 0) && (INV_CONTENT(ITEM_COJIRO) == ITEM_COJIRO)) {
bool playerHasCojiro = INV_CONTENT(ITEM_COJIRO) == ITEM_COJIRO;
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) {
playerHasCojiro = PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_COJIRO);
}
if ((globalCtx->roomCtx.unk_74[0] == 0) && playerHasCojiro) {
if (globalCtx->roomCtx.unk_74[1] == 50) {
func_8002F7DC(&GET_PLAYER(globalCtx)->actor, NA_SE_EV_CHICKEN_CRY_M);
globalCtx->roomCtx.unk_74[0] = 1;

View File

@ -6,6 +6,7 @@
#define NUM_DUNGEONS 8
#define NUM_TRIALS 6
#define NUM_COWS 10
/**
* Initialize new save.
@ -416,6 +417,95 @@ void GiveLinkDungeonReward(uint16_t getItemId) {
}
}
void GiveLinkDungeonItem(GetItemID getItemId) {
int mapIndex;
switch (getItemId) {
case RG_DEKU_TREE_MAP:
case RG_DEKU_TREE_COMPASS:
mapIndex = SCENE_YDAN;
break;
case RG_DODONGOS_CAVERN_MAP:
case RG_DODONGOS_CAVERN_COMPASS:
mapIndex = SCENE_DDAN;
break;
case RG_JABU_JABUS_BELLY_MAP:
case RG_JABU_JABUS_BELLY_COMPASS:
mapIndex = SCENE_BDAN;
break;
case RG_FOREST_TEMPLE_MAP:
case RG_FOREST_TEMPLE_COMPASS:
case RG_FOREST_TEMPLE_SMALL_KEY:
case RG_FOREST_TEMPLE_BOSS_KEY:
mapIndex = SCENE_BMORI1;
break;
case RG_FIRE_TEMPLE_MAP:
case RG_FIRE_TEMPLE_COMPASS:
case RG_FIRE_TEMPLE_SMALL_KEY:
case RG_FIRE_TEMPLE_BOSS_KEY:
mapIndex = SCENE_HIDAN;
break;
case RG_WATER_TEMPLE_MAP:
case RG_WATER_TEMPLE_COMPASS:
case RG_WATER_TEMPLE_SMALL_KEY:
case RG_WATER_TEMPLE_BOSS_KEY:
mapIndex = SCENE_MIZUSIN;
break;
case RG_SPIRIT_TEMPLE_MAP:
case RG_SPIRIT_TEMPLE_COMPASS:
case RG_SPIRIT_TEMPLE_SMALL_KEY:
case RG_SPIRIT_TEMPLE_BOSS_KEY:
mapIndex = SCENE_JYASINZOU;
break;
case RG_SHADOW_TEMPLE_MAP:
case RG_SHADOW_TEMPLE_COMPASS:
case RG_SHADOW_TEMPLE_SMALL_KEY:
case RG_SHADOW_TEMPLE_BOSS_KEY:
mapIndex = SCENE_HAKADAN;
break;
case RG_BOTTOM_OF_THE_WELL_MAP:
case RG_BOTTOM_OF_THE_WELL_COMPASS:
case RG_BOTTOM_OF_THE_WELL_SMALL_KEY:
mapIndex = SCENE_HAKADANCH;
break;
case RG_ICE_CAVERN_MAP:
case RG_ICE_CAVERN_COMPASS:
mapIndex = SCENE_ICE_DOUKUTO;
break;
case RG_GANONS_CASTLE_BOSS_KEY:
mapIndex = SCENE_GANON;
break;
case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY:
mapIndex = SCENE_MEN;
break;
case RG_GERUDO_FORTRESS_SMALL_KEY:
mapIndex = SCENE_GERUDOWAY;
break;
case RG_GANONS_CASTLE_SMALL_KEY:
mapIndex = SCENE_GANONTIKA;
break;
}
if ((getItemId >= RG_GERUDO_FORTRESS_SMALL_KEY) && (getItemId <= RG_GANONS_CASTLE_SMALL_KEY)) {
if (gSaveContext.inventory.dungeonKeys[mapIndex] < 0) {
gSaveContext.inventory.dungeonKeys[mapIndex] = 1;
} else {
gSaveContext.inventory.dungeonKeys[mapIndex]++;
}
} else {
int bitmask;
if ((getItemId >= RG_DEKU_TREE_MAP) && (getItemId <= RG_ICE_CAVERN_MAP)) {
bitmask = gBitFlags[2];
} else if ((getItemId >= RG_DEKU_TREE_COMPASS) && (getItemId <= RG_ICE_CAVERN_COMPASS)) {
bitmask = gBitFlags[1];
} else {
bitmask = gBitFlags[0];
}
gSaveContext.inventory.dungeonItems[mapIndex] |= bitmask;
}
}
void GiveLinksPocketMedallion() {
GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(RC_LINKS_POCKET, RG_NONE);
@ -563,13 +653,15 @@ void Sram_OpenSave() {
gSaveContext.equips.equipment |= 2;
}
for (i = 0; i < ARRAY_COUNT(gSpoilingItems); i++) {
if (INV_CONTENT(ITEM_TRADE_ADULT) == gSpoilingItems[i]) {
INV_CONTENT(gSpoilingItemReverts[i]) = gSpoilingItemReverts[i];
if (!(gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE))) {
for (i = 0; i < ARRAY_COUNT(gSpoilingItems); i++) {
if (INV_CONTENT(ITEM_TRADE_ADULT) == gSpoilingItems[i]) {
INV_CONTENT(gSpoilingItemReverts[i]) = gSpoilingItemReverts[i];
for (j = 1; j < ARRAY_COUNT(gSaveContext.equips.buttonItems); j++) {
if (gSaveContext.equips.buttonItems[j] == gSpoilingItems[i]) {
gSaveContext.equips.buttonItems[j] = gSpoilingItemReverts[i];
for (j = 1; j < ARRAY_COUNT(gSaveContext.equips.buttonItems); j++) {
if (gSaveContext.equips.buttonItems[j] == gSpoilingItems[i]) {
gSaveContext.equips.buttonItems[j] = gSpoilingItemReverts[i];
}
}
}
}
@ -620,14 +712,20 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
gSaveContext.trialsDone[i] = 0;
}
// Sets all cows to unmilked when generating a rando save.
for (u8 i = 0; i < NUM_COWS; i++) {
gSaveContext.cowsMilked[i] = 0;
}
// Set Cutscene flags to skip them
gSaveContext.eventChkInf[0xC] |= 0x10; // returned to tot with medallions
gSaveContext.eventChkInf[0xC] |= 0x20; //sheik at tot pedestal
gSaveContext.eventChkInf[4] |= 0x20; // master sword pulled
gSaveContext.eventChkInf[4] |= 0x8000; // entered master sword chamber
gSaveContext.infTable[0] |= 1;
// RANDTODO: Don't skip this scene if Don't Skip Glitch Useful Cutscenes is enabled.
gSaveContext.infTable[17] |= 0x400; // Darunia in Fire Temple
if (!Randomizer_GetSettingValue(RSK_ENABLE_GLITCH_CUTSCENES)) {
gSaveContext.infTable[17] |= 0x400; // Darunia in Fire Temple
}
gSaveContext.cutsceneIndex = 0;
Flags_SetEventChkInf(5);
@ -682,11 +780,12 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY;
}
if(Randomizer_GetSettingValue(RSK_STARTING_MAPS_COMPASSES)) {
// "Start with" == 0 for Maps and Compasses
if(Randomizer_GetSettingValue(RSK_STARTING_MAPS_COMPASSES) == 0) {
uint32_t mapBitMask = 1 << 1;
uint32_t compassBitMask = 1 << 2;
uint32_t startingDungeonItemsBitMask = mapBitMask | compassBitMask;
for(int scene = 0; scene <= 9; scene++) {
for(int scene = SCENE_YDAN; scene <= SCENE_ICE_DOUKUTO; scene++) {
gSaveContext.inventory.dungeonItems[scene] |= startingDungeonItemsBitMask;
}
}
@ -762,6 +861,13 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
GiveLinkMagic(giid);
} else if (giid == RG_DOUBLE_DEFENSE) {
GiveLinkDoubleDefense();
} else if (
(giid >= RG_GERUDO_FORTRESS_SMALL_KEY && giid <= RG_GANONS_CASTLE_SMALL_KEY) ||
(giid >= RG_FOREST_TEMPLE_BOSS_KEY && giid <= RG_GANONS_CASTLE_BOSS_KEY) ||
(giid >= RG_DEKU_TREE_MAP && giid <= RG_ICE_CAVERN_MAP) ||
(giid >= RG_DEKU_TREE_COMPASS && giid <= RG_ICE_CAVERN_COMPASS)
) {
GiveLinkDungeonItem(giid);
} else {
s32 iid = Randomizer_GetItemIDFromGetItemID(giid);
if (iid != -1) INV_CONTENT(iid) = iid;
@ -788,9 +894,31 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
GiveLinkRupees(9001);
}
// For Ganon's boss key "Start With" is 0
if(Randomizer_GetSettingValue(RSK_GANONS_BOSS_KEY) == 0) {
gSaveContext.inventory.dungeonItems[10] |= 1;
// "Start with" == 0 for Keysanity
if(Randomizer_GetSettingValue(RSK_KEYSANITY) == 0) {
// TODO: If master quest there are different key counts
gSaveContext.inventory.dungeonKeys[SCENE_BMORI1] = 5; // Forest
gSaveContext.inventory.dungeonKeys[SCENE_HIDAN] = 8; // Fire
gSaveContext.inventory.dungeonKeys[SCENE_MIZUSIN] = 6; // Water
gSaveContext.inventory.dungeonKeys[SCENE_JYASINZOU] = 5; // Spirit
gSaveContext.inventory.dungeonKeys[SCENE_HAKADAN] = 5; // Shadow
gSaveContext.inventory.dungeonKeys[SCENE_HAKADANCH] = 2; // BotW
gSaveContext.inventory.dungeonKeys[SCENE_MEN] = 9; // GTG
gSaveContext.inventory.dungeonKeys[SCENE_GANONTIKA] = 2; // Ganon
}
// "Start with" == 0 for Boss Kesanity
if(Randomizer_GetSettingValue(RSK_BOSS_KEYSANITY) == 0) {
gSaveContext.inventory.dungeonItems[SCENE_BMORI1] |= 1; // Forest
gSaveContext.inventory.dungeonItems[SCENE_HIDAN] |= 1; // Fire
gSaveContext.inventory.dungeonItems[SCENE_MIZUSIN] |= 1; // Water
gSaveContext.inventory.dungeonItems[SCENE_JYASINZOU] |= 1; // Spirit
gSaveContext.inventory.dungeonItems[SCENE_HAKADAN] |= 1; // Shadow
}
// "Start with" == 2 for Ganon's Boss Key
if(Randomizer_GetSettingValue(RSK_GANONS_BOSS_KEY) == 2) {
gSaveContext.inventory.dungeonItems[SCENE_GANON] |= 1;
}
HIGH_SCORE(HS_POE_POINTS) = 1000 - (100 * Randomizer_GetSettingValue(RSK_BIG_POE_COUNT));
@ -852,6 +980,21 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
GiveLinkGerudoCard();
}
}
// 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
gSaveContext.itemGetInf[3] |= 0x200; // Sold Skull Mask
gSaveContext.itemGetInf[3] |= 0x400; // Sold Spooky Mask
gSaveContext.itemGetInf[3] |= 0x800; // bunny hood related
gSaveContext.itemGetInf[3] |= 0x8000; // Obtained Mask of Truth
gSaveContext.eventChkInf[8] |= 0x8000; // sold all masks
}
}
Save_SaveFile();

View File

@ -18,6 +18,8 @@ void func_809E0070(Actor* thisx, GlobalContext* globalCtx);
void func_809DF494(EnCow* this, GlobalContext* globalCtx);
void func_809DF6BC(EnCow* this, GlobalContext* globalCtx);
CowInfo EnCow_GetInfo(EnCow* this, GlobalContext* globalCtx);
void EnCow_MoveForRandomizer(EnCow* this, GlobalContext* globalCtx);
void func_809DF778(EnCow* this, GlobalContext* globalCtx);
void func_809DF7D8(EnCow* this, GlobalContext* globalCtx);
void func_809DF870(EnCow* this, GlobalContext* globalCtx);
@ -106,6 +108,10 @@ void EnCow_Init(Actor* thisx, GlobalContext* globalCtx) {
EnCow* this = (EnCow*)thisx;
s32 pad;
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_COWS)) {
EnCow_MoveForRandomizer(thisx, globalCtx);
}
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 72.0f);
switch (this->actor.params) {
case 0:
@ -209,6 +215,85 @@ void func_809DF730(EnCow* this, GlobalContext* globalCtx) {
}
}
CowInfo EnCow_GetInfo(EnCow* this, GlobalContext* globalCtx) {
struct CowInfo cowInfo;
cowInfo.cowId = -1;
cowInfo.randomizerCheck = RC_UNKNOWN_CHECK;
switch (globalCtx->sceneNum) {
case SCENE_SOUKO: // Lon Lon Tower
if (this->actor.world.pos.x == -229 && this->actor.world.pos.z == 157) {
cowInfo.cowId = 0;
cowInfo.randomizerCheck = RC_LLR_TOWER_LEFT_COW;
} else if (this->actor.world.pos.x == -142 && this->actor.world.pos.z == -140) {
cowInfo.cowId = 1;
cowInfo.randomizerCheck = RC_LLR_TOWER_RIGHT_COW;
}
break;
case SCENE_MALON_STABLE:
if (this->actor.world.pos.x == 116 && this->actor.world.pos.z == -254) {
cowInfo.cowId = 2;
cowInfo.randomizerCheck = RC_LLR_STABLES_RIGHT_COW;
} else if (this->actor.world.pos.x == -122 && this->actor.world.pos.z == -254) {
cowInfo.cowId = 3;
cowInfo.randomizerCheck = RC_LLR_STABLES_LEFT_COW;
}
break;
case SCENE_KAKUSIANA: // Grotto
if (this->actor.world.pos.x == 2444 && this->actor.world.pos.z == -471) {
cowInfo.cowId = 4;
cowInfo.randomizerCheck = RC_DMT_COW_GROTTO_COW;
} else if (this->actor.world.pos.x == 3485 && this->actor.world.pos.z == -291) {
cowInfo.cowId = 5;
cowInfo.randomizerCheck = RC_HF_COW_GROTTO_COW;
}
break;
case SCENE_LINK_HOME:
cowInfo.cowId = 6;
cowInfo.randomizerCheck = RC_KF_LINKS_HOUSE_COW;
break;
case SCENE_LABO: // Impa's house
cowInfo.cowId = 7;
cowInfo.randomizerCheck = RC_KAK_IMPAS_HOUSE_COW;
break;
case SCENE_SPOT09: // Gerudo Valley
cowInfo.cowId = 8;
cowInfo.randomizerCheck = RC_GV_COW;
break;
case SCENE_SPOT08: // Jabu's Belly
cowInfo.cowId = 9;
cowInfo.randomizerCheck = RC_JABU_JABUS_BELLY_MQ_COW;
break;
}
return cowInfo;
}
void EnCow_MoveForRandomizer(EnCow* this, GlobalContext* globalCtx) {
// Only move the cow body (the tail will be moved with the body)
if (this->actor.params != 0) {
return;
}
// Move left cow in lon lon tower
if (globalCtx->sceneNum == SCENE_SOUKO && this->actor.world.pos.x == -108 && this->actor.world.pos.z == -65) {
this->actor.world.pos.x = -229.0f;
this->actor.world.pos.z = 157.0f;
this->actor.shape.rot.y = 15783.0f;
// Move right cow in lon lon stable
} else if (globalCtx->sceneNum == SCENE_MALON_STABLE && this->actor.world.pos.x == -3 && this->actor.world.pos.z == -254) {
this->actor.world.pos.x += 119.0f;
}
}
void EnCow_SetCowMilked(EnCow* this, GlobalContext* globalCtx) {
CowInfo cowInfo = EnCow_GetInfo(this, globalCtx);
Player* player = GET_PLAYER(globalCtx);
player->pendingFlag.flagID = cowInfo.cowId;
player->pendingFlag.flagType = FLAG_COW_MILKED;
}
void func_809DF778(EnCow* this, GlobalContext* globalCtx) {
if (Actor_HasParent(&this->actor, globalCtx)) {
this->actor.parent = NULL;
@ -250,6 +335,23 @@ void func_809DF8FC(EnCow* this, GlobalContext* globalCtx) {
func_809DF494(this, globalCtx);
}
bool EnCow_HasBeenMilked(EnCow* this, GlobalContext* globalCtx) {
CowInfo cowInfo = EnCow_GetInfo(this, globalCtx);
return gSaveContext.cowsMilked[cowInfo.cowId];
}
void EnCow_GivePlayerRandomizedItem(EnCow* this, GlobalContext* globalCtx) {
if (!EnCow_HasBeenMilked(this, globalCtx)) {
CowInfo cowInfo = EnCow_GetInfo(this, globalCtx);
GetItemID itemId = Randomizer_GetItemIdFromKnownCheck(cowInfo.randomizerCheck, GI_MILK);
func_8002F434(&this->actor, globalCtx, itemId, 10000.0f, 100.0f);
} else {
// once we've gotten the rando reward from the cow,
// return them to the their default action function
this->actionFunc = func_809DF96C;
}
}
void func_809DF96C(EnCow* this, GlobalContext* globalCtx) {
if ((globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_00) || (globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_04)) {
if (DREG(53) != 0) {
@ -260,6 +362,19 @@ void func_809DF96C(EnCow* this, GlobalContext* globalCtx) {
if ((this->actor.xzDistToPlayer < 150.0f) &&
(ABS((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) < 0x61A8)) {
DREG(53) = 0;
// when randomized with cowsanity, if we haven't gotten the
// reward from this cow yet, give that, otherwise use the
// vanilla cow behavior
if (gSaveContext.n64ddFlag &&
Randomizer_GetSettingValue(RSK_SHUFFLE_COWS) &&
!EnCow_HasBeenMilked(this, globalCtx)) {
EnCow_SetCowMilked(this, globalCtx);
// setting the ocarina mode here prevents intermittent issues
// with the item get not triggering until walking away
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_00;
this->actionFunc = EnCow_GivePlayerRandomizedItem;
return;
}
this->actionFunc = func_809DF8FC;
this->actor.flags |= ACTOR_FLAG_16;
func_8002F2CC(&this->actor, globalCtx, 170.0f);

View File

@ -21,4 +21,9 @@ typedef struct EnCow {
/* 0x027C */ EnCowActionFunc actionFunc;
} EnCow; // size = 0x0280
typedef struct CowInfo {
int cowId;
RandomizerCheck randomizerCheck;
} CowInfo;
#endif

View File

@ -6,6 +6,7 @@
#include "z_en_ds.h"
#include "objects/object_ds/object_ds.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3)
@ -91,7 +92,12 @@ void EnDs_GiveOddPotion(EnDs* this, GlobalContext* globalCtx) {
this->actionFunc = EnDs_DisplayOddPotionText;
gSaveContext.timer2State = 0;
} else {
func_8002F434(&this->actor, globalCtx, GI_ODD_POTION, 10000.0f, 50.0f);
u32 itemId = GI_ODD_POTION;
if (gSaveContext.n64ddFlag) {
itemId = Randomizer_GetItemIdFromKnownCheck(RC_KAK_TRADE_ODD_MUSHROOM, GI_ODD_POTION);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_ODD_MUSHROOM);
}
func_8002F434(&this->actor, globalCtx, itemId, 10000.0f, 50.0f);
}
}
@ -99,7 +105,12 @@ void EnDs_TalkAfterBrewOddPotion(EnDs* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_EVENT) && Message_ShouldAdvance(globalCtx)) {
Message_CloseTextbox(globalCtx);
this->actionFunc = EnDs_GiveOddPotion;
func_8002F434(&this->actor, globalCtx, GI_ODD_POTION, 10000.0f, 50.0f);
u32 itemId = GI_ODD_POTION;
if (gSaveContext.n64ddFlag) {
itemId = Randomizer_GetItemIdFromKnownCheck(RC_KAK_TRADE_ODD_MUSHROOM, GI_ODD_POTION);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_ODD_MUSHROOM);
}
func_8002F434(&this->actor, globalCtx, itemId, 10000.0f, 50.0f);
}
}
@ -120,7 +131,7 @@ void EnDs_BrewOddPotion2(EnDs* this, GlobalContext* globalCtx) {
this->brewTimer -= 1;
} else {
this->actionFunc = EnDs_BrewOddPotion3;
this->brewTimer = 60;
this->brewTimer = gSaveContext.n64ddFlag ? 0 : 60;
Flags_UnsetSwitch(globalCtx, 0x3F);
}
}
@ -130,7 +141,7 @@ void EnDs_BrewOddPotion1(EnDs* this, GlobalContext* globalCtx) {
this->brewTimer -= 1;
} else {
this->actionFunc = EnDs_BrewOddPotion2;
this->brewTimer = 20;
this->brewTimer = gSaveContext.n64ddFlag ? 0 : 20;
}
Math_StepToF(&this->unk_1E4, 1.0f, 0.01f);
@ -144,7 +155,7 @@ void EnDs_OfferOddPotion(EnDs* this, GlobalContext* globalCtx) {
switch (globalCtx->msgCtx.choiceIndex) {
case 0: // yes
this->actionFunc = EnDs_BrewOddPotion1;
this->brewTimer = 60;
this->brewTimer = gSaveContext.n64ddFlag ? 0 : 60;
Flags_SetSwitch(globalCtx, 0x3F);
globalCtx->msgCtx.msgMode = MSGMODE_PAUSED;
player->exchangeItemId = EXCH_ITEM_NONE;

View File

@ -43,6 +43,7 @@ void EnFr_OcarinaMistake(EnFr* this, GlobalContext* globalCtx);
void EnFr_SetupReward(EnFr* this, GlobalContext* globalCtx, u8 unkCondition);
void EnFr_PrintTextBox(EnFr* this, GlobalContext* globalCtx);
void EnFr_TalkBeforeReward(EnFr* this, GlobalContext* globalCtx);
RandomizerCheck EnFr_RandomizerCheckFromSongIndex(u16 songIndex);
void EnFr_SetReward(EnFr* this, GlobalContext* globalCtx);
// Deactivate
@ -920,6 +921,23 @@ void EnFr_TalkBeforeReward(EnFr* this, GlobalContext* globalCtx) {
}
}
RandomizerCheck EnFr_RandomizerCheckFromSongIndex(u16 songIndex) {
switch (songIndex) {
case FROG_ZL:
return RC_ZR_FROGS_ZELDAS_LULLABY;
case FROG_EPONA:
return RC_ZR_FROGS_EPONAS_SONG;
case FROG_SARIA:
return RC_ZR_FROGS_SARIAS_SONG;
case FROG_SUNS:
return RC_ZR_FROGS_SUNS_SONG;
case FROG_SOT:
return RC_ZR_FROGS_SONG_OF_TIME;
default:
return RC_UNKNOWN_CHECK;
}
}
void EnFr_SetReward(EnFr* this, GlobalContext* globalCtx) {
u16 songIndex;
@ -930,7 +948,11 @@ void EnFr_SetReward(EnFr* this, GlobalContext* globalCtx) {
if ((songIndex >= FROG_ZL) && (songIndex <= FROG_SOT)) {
if (!(gSaveContext.eventChkInf[13] & sSongIndex[songIndex])) {
gSaveContext.eventChkInf[13] |= sSongIndex[songIndex];
this->reward = GI_RUPEE_PURPLE;
if (!gSaveContext.n64ddFlag) {
this->reward = GI_RUPEE_PURPLE;
} else {
this->reward = Randomizer_GetItemIdFromKnownCheck(EnFr_RandomizerCheckFromSongIndex(songIndex), GI_RUPEE_PURPLE);
}
} else {
this->reward = GI_RUPEE_BLUE;
}
@ -1016,7 +1038,7 @@ void EnFr_GiveReward(EnFr* this, GlobalContext* globalCtx) {
}
void EnFr_SetIdle(EnFr* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx) || (gSaveContext.n64ddFlag && this->reward == GI_ICE_TRAP)) {
this->actionFunc = EnFr_Idle;
}
}

View File

@ -3,6 +3,7 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_oF1d_map/object_oF1d_map.h"
#include "soh/frame_interpolation.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
@ -961,9 +962,17 @@ void EnGo_GetItem(EnGo* this, GlobalContext* globalCtx) {
}
if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_EYEDROPS) {
getItemId = GI_CLAIM_CHECK;
if (gSaveContext.n64ddFlag) {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_DMT_TRADE_EYEDROPS, GI_CLAIM_CHECK);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_EYEDROPS);
}
}
if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_SWORD_BROKEN) {
getItemId = GI_PRESCRIPTION;
if (gSaveContext.n64ddFlag) {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_DMT_TRADE_BROKEN_SWORD, GI_PRESCRIPTION);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_SWORD_BROKEN);
}
}
}

View File

@ -3,6 +3,7 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_oF1d_map/object_oF1d_map.h"
#include "soh/frame_interpolation.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
@ -652,7 +653,12 @@ s16 EnGo2_GetStateGoronDmtBiggoron(GlobalContext* globalCtx, EnGo2* this) {
if (Message_ShouldAdvance(globalCtx)) {
if ((this->actor.textId == 0x3054) || (this->actor.textId == 0x3055)) {
if (globalCtx->msgCtx.choiceIndex == 0) {
EnGo2_GetItem(this, globalCtx, GI_PRESCRIPTION);
u32 getItemId = GI_PRESCRIPTION;
if (gSaveContext.n64ddFlag) {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_DMT_TRADE_BROKEN_SWORD, GI_PRESCRIPTION);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_SWORD_BROKEN);
}
EnGo2_GetItem(this, globalCtx, getItemId);
this->actionFunc = EnGo2_SetupGetItem;
return 2;
}
@ -1847,12 +1853,14 @@ void EnGo2_BiggoronEyedrops(EnGo2* this, GlobalContext* globalCtx) {
this->actor.flags &= ~ACTOR_FLAG_0;
this->actor.shape.rot.y += 0x5B0;
this->unk_26E = 1;
this->animTimer = this->skelAnime.endFrame + 60.0f + 60.0f; // eyeDrops animation timer
this->animTimer = gSaveContext.n64ddFlag ? 0 : (this->skelAnime.endFrame + 60.0f + 60.0f); // eyeDrops animation timer
this->eyeMouthTexState = 2;
this->unk_20C = 0;
this->goronState++;
func_800F483C(0x28, 5);
OnePointCutscene_Init(globalCtx, 4190, -99, &this->actor, MAIN_CAM);
if (!gSaveContext.n64ddFlag) {
OnePointCutscene_Init(globalCtx, 4190, -99, &this->actor, MAIN_CAM);
}
break;
case 1:
if (DECR(this->animTimer)) {
@ -1879,7 +1887,12 @@ void EnGo2_BiggoronEyedrops(EnGo2* this, GlobalContext* globalCtx) {
this->unk_26E = 2;
this->skelAnime.playSpeed = 0.0f;
this->skelAnime.curFrame = this->skelAnime.endFrame;
EnGo2_GetItem(this, globalCtx, GI_CLAIM_CHECK);
u32 getItemId = GI_CLAIM_CHECK;
if (gSaveContext.n64ddFlag) {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_DMT_TRADE_EYEDROPS, GI_CLAIM_CHECK);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_EYEDROPS);
}
EnGo2_GetItem(this, globalCtx, getItemId);
this->actionFunc = EnGo2_SetupGetItem;
this->goronState = 0;
}

View File

@ -7,6 +7,7 @@
#include "z_en_hs.h"
#include "vt.h"
#include "objects/object_hs/object_hs.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3)
@ -78,7 +79,25 @@ void EnHs_Init(Actor* thisx, GlobalContext* globalCtx) {
// "chicken shop (adult era)"
osSyncPrintf(VT_FGCOL(CYAN) " ヒヨコの店(大人の時) \n" VT_RST);
func_80A6E3A0(this, func_80A6E9AC);
if (gSaveContext.itemGetInf[3] & 1) {
bool shouldSpawn;
bool tradedMushroom = gSaveContext.itemGetInf[3] & 1;
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) {
// To explain the logic because Fado and Grog are linked:
// - If you have Cojiro, then spawn Grog and not Fado.
// - If you don't have Cojiro but do have Odd Potion, spawn Fado and not Grog.
// - If you don't have either, spawn Grog if you haven't traded the Odd Mushroom.
// - If you don't have either but have traded the mushroom, don't spawn either.
if (PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_COJIRO)) {
shouldSpawn = true;
} else if (PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_ODD_POTION)) {
shouldSpawn = false;
} else {
shouldSpawn = !tradedMushroom;
}
} else {
shouldSpawn = !tradedMushroom;
}
if (!shouldSpawn) {
// "chicken shop closed"
osSyncPrintf(VT_FGCOL(CYAN) " ヒヨコ屋閉店 \n" VT_RST);
Actor_Kill(&this->actor);
@ -127,7 +146,9 @@ void func_80A6E5EC(EnHs* this, GlobalContext* globalCtx) {
void func_80A6E630(EnHs* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
func_80088AA0(180);
if (!gSaveContext.n64ddFlag) {
func_80088AA0(180);
}
func_80A6E3A0(this, func_80A6E6B0);
gSaveContext.eventInf[1] &= ~1;
}
@ -156,7 +177,12 @@ void func_80A6E740(EnHs* this, GlobalContext* globalCtx) {
this->actor.parent = NULL;
func_80A6E3A0(this, func_80A6E630);
} else {
func_8002F434(&this->actor, globalCtx, GI_ODD_MUSHROOM, 10000.0f, 50.0f);
s32 itemId = GI_ODD_MUSHROOM;
if (gSaveContext.n64ddFlag) {
itemId = Randomizer_GetItemIdFromKnownCheck(RC_LW_TRADE_COJIRO, GI_ODD_MUSHROOM);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_COJIRO);
}
func_8002F434(&this->actor, globalCtx, itemId, 10000.0f, 50.0f);
}
this->unk_2A8 |= 1;
@ -167,7 +193,12 @@ void func_80A6E7BC(EnHs* this, GlobalContext* globalCtx) {
switch (globalCtx->msgCtx.choiceIndex) {
case 0:
func_80A6E3A0(this, func_80A6E740);
func_8002F434(&this->actor, globalCtx, GI_ODD_MUSHROOM, 10000.0f, 50.0f);
s32 itemId = GI_ODD_MUSHROOM;
if (gSaveContext.n64ddFlag) {
itemId = Randomizer_GetItemIdFromKnownCheck(RC_LW_TRADE_COJIRO, GI_ODD_MUSHROOM);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_COJIRO);
}
func_8002F434(&this->actor, globalCtx, itemId, 10000.0f, 50.0f);
break;
case 1:
Message_ContinueTextbox(globalCtx, 0x10B4);

View File

@ -10,6 +10,7 @@
#include "objects/object_km1/object_km1.h"
#include "objects/object_kw1/object_kw1.h"
#include "vt.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3 | ACTOR_FLAG_4)
@ -1025,7 +1026,20 @@ s32 EnKo_CanSpawn(EnKo* this, GlobalContext* globalCtx) {
}
case SCENE_SPOT10:
return (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_ODD_POTION) ? true : false;
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) {
// To explain the logic because Fado and Grog are linked:
// - If you have Cojiro, then spawn Grog and not Fado.
// - If you don't have Cojiro but do have Odd Potion, spawn Fado and not Grog.
// - If you don't have either, spawn Grog if you haven't traded the Odd Mushroom.
// - If you don't have either but have traded the mushroom, don't spawn either.
if (PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_COJIRO)) {
return false;
} else {
return PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_ODD_POTION);
}
} else {
return (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_ODD_POTION) ? true : false;
}
default:
return false;
}
@ -1216,7 +1230,12 @@ void func_80A99504(EnKo* this, GlobalContext* globalCtx) {
this->actor.parent = NULL;
this->actionFunc = func_80A99560;
} else {
func_8002F434(&this->actor, globalCtx, GI_SAW, 120.0f, 10.0f);
s32 itemId = GI_SAW;
if (gSaveContext.n64ddFlag) {
itemId = Randomizer_GetItemIdFromKnownCheck(RC_LW_TRADE_ODD_POTION, GI_SAW);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_ODD_POTION);
}
func_8002F434(&this->actor, globalCtx, itemId, 120.0f, 10.0f);
}
}

View File

@ -6,6 +6,7 @@
#include "z_en_kz.h"
#include "objects/object_kz/object_kz.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3)
@ -465,6 +466,7 @@ void EnKz_SetupGetItem(EnKz* this, GlobalContext* globalCtx) {
if (gSaveContext.n64ddFlag) {
if (this->isTrading) {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_ZD_TRADE_PRESCRIPTION, GI_FROG);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_PRESCRIPTION);
Flags_SetTreasure(globalCtx, 0x1F);
} else {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_ZD_KING_ZORA_THAWED, GI_TUNIC_ZORA);
@ -480,7 +482,7 @@ void EnKz_SetupGetItem(EnKz* this, GlobalContext* globalCtx) {
void EnKz_StartTimer(EnKz* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_FROG) {
if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_FROG && !gSaveContext.n64ddFlag) {
func_80088AA0(180); // start timer2 with 3 minutes
gSaveContext.eventInf[1] &= ~1;
}

View File

@ -6,6 +6,7 @@
#include "z_en_mk.h"
#include "objects/object_mk/object_mk.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3 | ACTOR_FLAG_4)
@ -93,17 +94,29 @@ void func_80AACA94(EnMk* this, GlobalContext* globalCtx) {
if (Actor_HasParent(&this->actor, globalCtx) != 0) {
this->actor.parent = NULL;
this->actionFunc = func_80AACA40;
func_80088AA0(240);
gSaveContext.eventInf[1] &= ~1;
if (!gSaveContext.n64ddFlag) {
func_80088AA0(240);
gSaveContext.eventInf[1] &= ~1;
}
} else {
func_8002F434(&this->actor, globalCtx, GI_EYEDROPS, 10000.0f, 50.0f);
s32 getItemID = GI_EYEDROPS;
if (gSaveContext.n64ddFlag) {
getItemID = Randomizer_GetItemIdFromKnownCheck(RC_LH_TRADE_FROG, GI_EYEDROPS);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_FROG);
}
func_8002F434(&this->actor, globalCtx, getItemID, 10000.0f, 50.0f);
}
}
void func_80AACB14(EnMk* this, GlobalContext* globalCtx) {
if (Actor_TextboxIsClosing(&this->actor, globalCtx)) {
this->actionFunc = func_80AACA94;
func_8002F434(&this->actor, globalCtx, GI_EYEDROPS, 10000.0f, 50.0f);
s32 getItemID = GI_EYEDROPS;
if (gSaveContext.n64ddFlag) {
getItemID = Randomizer_GetItemIdFromKnownCheck(RC_LH_TRADE_FROG, GI_EYEDROPS);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_FROG);
}
func_8002F434(&this->actor, globalCtx, getItemID, 10000.0f, 50.0f);
}
}
@ -129,7 +142,7 @@ void func_80AACC04(EnMk* this, GlobalContext* globalCtx) {
if (this->timer > 0) {
this->timer--;
} else {
this->timer = 16;
this->timer = gSaveContext.n64ddFlag ? 0 : 16;
this->actionFunc = func_80AACBAC;
Animation_Change(&this->skelAnime, &object_mk_Anim_000D88, 1.0f, 0.0f,
Animation_GetLastFrame(&object_mk_Anim_000D88), ANIMMODE_LOOP, -4.0f);
@ -142,7 +155,7 @@ void func_80AACCA0(EnMk* this, GlobalContext* globalCtx) {
this->timer--;
this->actor.shape.rot.y += 0x800;
} else {
this->timer = 120;
this->timer = gSaveContext.n64ddFlag ? 0 : 120;
this->actionFunc = func_80AACC04;
Animation_Change(&this->skelAnime, &object_mk_Anim_000724, 1.0f, 0.0f,
Animation_GetLastFrame(&object_mk_Anim_000724), ANIMMODE_LOOP, -4.0f);
@ -158,7 +171,7 @@ void func_80AACD48(EnMk* this, GlobalContext* globalCtx) {
this->actionFunc = func_80AACCA0;
globalCtx->msgCtx.msgMode = MSGMODE_PAUSED;
player->exchangeItemId = EXCH_ITEM_NONE;
this->timer = 16;
this->timer = gSaveContext.n64ddFlag ? 0 : 16;
Animation_Change(&this->skelAnime, &object_mk_Anim_000D88, 1.0f, 0.0f,
Animation_GetLastFrame(&object_mk_Anim_000D88), ANIMMODE_LOOP, -4.0f);
this->flags &= ~2;

View File

@ -3,6 +3,7 @@
#include "objects/object_os_anime/object_os_anime.h"
#include "overlays/actors/ovl_En_Niw/z_en_niw.h"
#include "vt.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3 | ACTOR_FLAG_4)
@ -454,8 +455,13 @@ void func_80ABAC00(EnNiwLady* this, GlobalContext* globalCtx) {
if (LINK_IS_ADULT) {
getItemId = !(gSaveContext.itemGetInf[2] & 0x1000) ? GI_POCKET_EGG : GI_COJIRO;
if (gSaveContext.n64ddFlag && getItemId == GI_POCKET_EGG) {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_KAK_ANJU_AS_ADULT, GI_POCKET_EGG);
if (gSaveContext.n64ddFlag) {
if (getItemId == GI_POCKET_EGG) {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_KAK_ANJU_AS_ADULT, GI_POCKET_EGG);
} else {
getItemId = Randomizer_GetItemIdFromKnownCheck(RC_KAK_TRADE_POCKET_CUCCO, GI_COJIRO);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_POCKET_CUCCO);
}
}
}
func_8002F434(&this->actor, globalCtx, getItemId, 200.0f, 100.0f);

View File

@ -183,7 +183,7 @@ void EnPoSisters_Init(Actor* thisx, GlobalContext* globalCtx) {
this->epoch++;
// Skip Poe Intro Cutscene
if (gSaveContext.n64ddFlag && thisx->params == 4124) {
if (gSaveContext.n64ddFlag && thisx->params == 4124 && !Randomizer_GetSettingValue(RSK_ENABLE_GLITCH_CUTSCENES)) {
Flags_SetSwitch(globalCtx, 0x1B);
Actor_Kill(thisx);
}

View File

@ -18,6 +18,10 @@ void func_80AFB768(EnSi* this, GlobalContext* globalCtx);
void func_80AFB89C(EnSi* this, GlobalContext* globalCtx);
void func_80AFB950(EnSi* this, GlobalContext* globalCtx);
s32 textId = 0xB4;
s32 giveItemId = ITEM_SKULL_TOKEN;
s32 getItemId;
static ColliderCylinderInit sCylinderInit = {
{
COLTYPE_NONE,
@ -93,12 +97,36 @@ void func_80AFB768(EnSi* this, GlobalContext* globalCtx) {
if (this->collider.base.ocFlags2 & OC2_HIT_PLAYER) {
this->collider.base.ocFlags2 &= ~OC2_HIT_PLAYER;
Item_Give(globalCtx, ITEM_SKULL_TOKEN);
if (CVar_GetS32("gSkulltulaFreeze", 0) != 1) {
if (gSaveContext.n64ddFlag) {
GetItemEntry getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum);
getItemId = getItem.getItemId;
if (getItem.getItemId == RG_ICE_TRAP) {
player->pendingIceTrap = true;
textId = 0xF8;
} 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->getItemEntry = getItem;
player->getItemId = getItemId;
} 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, 0xB4, NULL);
Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET);
Message_StartTextbox(globalCtx, textId, NULL);
if (gSaveContext.n64ddFlag) {
Audio_PlayFanfare_Rando(getItemId);
} else {
Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET);
}
this->actionFunc = func_80AFB950;
} else {
Collider_UpdateCylinder(&this->actor, &this->collider);
@ -117,9 +145,32 @@ void func_80AFB89C(EnSi* this, GlobalContext* globalCtx) {
this->actor.shape.rot.y += 0x400;
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) {
Item_Give(globalCtx, ITEM_SKULL_TOKEN);
Message_StartTextbox(globalCtx, 0xB4, NULL);
Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET);
if (gSaveContext.n64ddFlag) {
GetItemEntry getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum);
getItemId = getItem.getItemId;
if (getItemId == RG_ICE_TRAP) {
player->pendingIceTrap = true;
textId = 0xF8;
} 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;
} else {
Item_Give(globalCtx, giveItemId);
}
Message_StartTextbox(globalCtx, textId, NULL);
if (gSaveContext.n64ddFlag) {
Audio_PlayFanfare_Rando(getItemId);
} else {
Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET);
}
this->actionFunc = func_80AFB950;
}
}
@ -127,7 +178,8 @@ void func_80AFB89C(EnSi* this, GlobalContext* globalCtx) {
void func_80AFB950(EnSi* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if (Message_GetState(&globalCtx->msgCtx) != TEXT_STATE_CLOSING && CVar_GetS32("gSkulltulaFreeze", 0) != 1) {
if (Message_GetState(&globalCtx->msgCtx) != TEXT_STATE_CLOSING &&
((CVar_GetS32("gSkulltulaFreeze", 0) != 1 || giveItemId != ITEM_SKULL_TOKEN) && getItemId != GI_ICE_TRAP)) {
player->actor.freezeTimer = 10;
} else {
SET_GS_FLAGS((this->actor.params & 0x1F00) >> 8, this->actor.params & 0xFF);
@ -150,6 +202,17 @@ void EnSi_Draw(Actor* thisx, GlobalContext* globalCtx) {
if (this->actionFunc != func_80AFB950) {
func_8002ED80(&this->actor, globalCtx, 0);
func_8002EBCC(&this->actor, globalCtx, 0);
GetItem_Draw(globalCtx, GID_SKULL_TOKEN_2);
if (!gSaveContext.n64ddFlag) {
GetItem_Draw(globalCtx, GID_SKULL_TOKEN_2);
} else {
GetItemEntry getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum);
EnItem00_CustomItemsParticles(&this->actor, globalCtx, getItem);
if (getItem.itemId != ITEM_SKULL_TOKEN) {
f32 mtxScale = 1.5f;
Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY);
}
GetItem_Draw(globalCtx, getItem.gid);
}
}
}

View File

@ -613,9 +613,9 @@ void func_80B0D878(EnSw* this, GlobalContext* globalCtx) {
x = (this->unk_364.x * 10.0f);
y = (this->unk_364.y * 10.0f);
z = (this->unk_364.z * 10.0f);
temp_v0 =
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_SI, this->actor.world.pos.x + x,
this->actor.world.pos.y + y, this->actor.world.pos.z + z, 0, 0, 0, this->actor.params);
temp_v0 = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_SI,
this->actor.world.pos.x + x, this->actor.world.pos.y + y,
this->actor.world.pos.z + z, 0, 0, 0, this->actor.params);
if (temp_v0 != NULL) {
temp_v0->parent = NULL;
}

View File

@ -6,6 +6,7 @@
#include "z_en_toryo.h"
#include "objects/object_toryo/object_toryo.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3)
@ -313,7 +314,12 @@ void func_80B20768(EnToryo* this, GlobalContext* globalCtx) {
this->actor.parent = NULL;
this->unk_1E4 = 5;
} else {
func_8002F434(&this->actor, globalCtx, GI_SWORD_BROKEN, 100.0f, 10.0f);
s32 itemId = GI_SWORD_BROKEN;
if (gSaveContext.n64ddFlag) {
itemId = Randomizer_GetItemIdFromKnownCheck(RC_GV_TRADE_SAW, GI_SWORD_BROKEN);
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_SAW);
}
func_8002F434(&this->actor, globalCtx, itemId, 100.0f, 10.0f);
}
return;
}

View File

@ -6083,8 +6083,8 @@ void Player_SetPendingFlag(Player* this, GlobalContext* globalCtx) {
case FLAG_SCENE_TREASURE:
Flags_SetTreasure(globalCtx, this->pendingFlag.flagID);
break;
case FLAG_EVENT_CHECK_INF:
Flags_SetEventChkInf(this->pendingFlag.flagID);
case FLAG_COW_MILKED:
gSaveContext.cowsMilked[this->pendingFlag.flagID] = 1;
break;
case FLAG_NONE:
default:
@ -10889,6 +10889,10 @@ void Player_UpdateCommon(Player* this, GlobalContext* globalCtx, Input* input) {
Collider_ResetQuadAC(globalCtx, &this->shieldQuad.base);
Collider_ResetQuadAT(globalCtx, &this->shieldQuad.base);
if (this->pendingIceTrap) {
GiveItemWithoutActor(globalCtx, GI_ICE_TRAP);
}
}
static Vec3f D_80854838 = { 0.0f, 0.0f, -30.0f };

View File

@ -1,5 +1,7 @@
#include "z_kaleido_scope.h"
#include "textures/parameter_static/parameter_static.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#include "soh/Enhancements/randomizer/randomizerTypes.h"
u8 gAmmoItems[] = {
ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_NONE, ITEM_NONE, ITEM_SLINGSHOT, ITEM_NONE,
@ -10,6 +12,7 @@ static s16 sEquipState = 0;
static s16 sEquipAnimTimer = 0;
static s16 sEquipMoveTimer = 10;
bool gSelectingMask;
bool gSelectingAdultTrade;
static s16 sAmmoVtxOffset[] = {
0, 2, 4, 6, 99, 99, 8, 99, 10, 99, 99, 99, 99, 99, 12,
@ -109,7 +112,7 @@ void KaleidoScope_DrawItemSelect(GlobalContext* globalCtx) {
pauseCtx->nameColorSet = 0;
if ((pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM)) {
moveCursorResult = 0 || gSelectingMask;
moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade;
oldCursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM];
cursorItem = pauseCtx->cursorItem[PAUSE_ITEM];
@ -283,7 +286,7 @@ void KaleidoScope_DrawItemSelect(GlobalContext* globalCtx) {
if (pauseCtx->cursorSpecialPos == 0) {
if (cursorItem != PAUSE_ITEM_NONE) {
if ((ABS(pauseCtx->stickRelY) > 30) || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN | BTN_DUP))) {
moveCursorResult = 0 || gSelectingMask;
moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade;
cursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM];
cursorY = pauseCtx->cursorY[PAUSE_ITEM];
@ -351,8 +354,16 @@ void KaleidoScope_DrawItemSelect(GlobalContext* globalCtx) {
KaleidoScope_SetCursorVtx(pauseCtx, index, pauseCtx->itemVtx);
if ((pauseCtx->debugState == 0) && (pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0)) {
if (CVar_GetS32("gMaskSelect", 0) && (gSaveContext.eventChkInf[8] & 0x8000) &&
cursorSlot == SLOT_TRADE_CHILD && CHECK_BTN_ALL(input->press.button, BTN_A)) {
// only allow mask select when:
// the shop is open:
// * zelda's letter check: gSaveContext.eventChkInf[4] & 1
// * kak gate check: gSaveContext.infTable[7] & 0x40
// and the mask quest is complete: gSaveContext.eventChkInf[8] & 0x8000
if (CVar_GetS32("gMaskSelect", 0) &&
(gSaveContext.eventChkInf[8] & 0x8000) &&
cursorSlot == SLOT_TRADE_CHILD && CHECK_BTN_ALL(input->press.button, BTN_A) &&
(gSaveContext.eventChkInf[4] & 1) &&
(gSaveContext.infTable[7] & 0x40)) {
Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
gSelectingMask = !gSelectingMask;
}
@ -385,6 +396,24 @@ void KaleidoScope_DrawItemSelect(GlobalContext* globalCtx) {
}
gSelectingMask = cursorSlot == SLOT_TRADE_CHILD;
}
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) &&
cursorSlot == SLOT_TRADE_ADULT && CHECK_BTN_ALL(input->press.button, BTN_A)) {
Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
gSelectingAdultTrade = !gSelectingAdultTrade;
}
if (gSelectingAdultTrade) {
pauseCtx->cursorColorSet = 8;
if (((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP))) {
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
Inventory_ReplaceItem(globalCtx, INV_CONTENT(ITEM_TRADE_ADULT), Randomizer_GetNextAdultTradeItem());
} else if (((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN))) {
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
Inventory_ReplaceItem(globalCtx, INV_CONTENT(ITEM_TRADE_ADULT), Randomizer_GetPrevAdultTradeItem());
}
gSelectingAdultTrade = cursorSlot == SLOT_TRADE_ADULT;
}
u16 buttonsToCheck = BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT;
if (CVar_GetS32("gDpadEquips", 0) && (!CVar_GetS32("gDpadPauseName", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) {
buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT;
@ -510,6 +539,7 @@ void KaleidoScope_SetupItemEquip(GlobalContext* globalCtx, u16 item, u16 slot, s
Input* input = &globalCtx->state.input[0];
PauseContext* pauseCtx = &globalCtx->pauseCtx;
gSelectingMask = false;
gSelectingAdultTrade = false;
if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) {
pauseCtx->equipTargetCBtn = 0;