Merge pull request #1019 from garrettjoecox/shuffleCows

Add shuffleCows options for randomizer
This commit is contained in:
briaguya 2022-08-06 00:03:27 -04:00 committed by GitHub
commit 97d363c91e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 146 additions and 3 deletions

View File

@ -184,6 +184,7 @@ typedef struct {
u8 seedIcons[5];
u8 dungeonsDone[8];
u8 trialsDone[6];
u8 cowsMilked[10];
u8 temporaryWeapon;
} SaveContext; // size = 0x1428

View File

@ -2500,6 +2500,7 @@ 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]);

View File

@ -1394,6 +1394,7 @@ std::unordered_map<std::string, RandomizerSettingKey> SpoilerfileSettingNameToEn
{ "Open Settings:Token Count", RSK_RAINBOW_BRIDGE_TOKEN_COUNT },
{ "Open Settings:Random Ganon's Trials", RSK_RANDOM_TRIALS },
{ "Open Settings:Trial Count", RSK_TRIAL_COUNT },
{ "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS },
{ "Start with Deku Shield", RSK_STARTING_DEKU_SHIELD },
{ "Start with Kokiri Sword", RSK_STARTING_KOKIRI_SWORD },
{ "Start with Fairy Ocarina", RSK_STARTING_OCARINA },
@ -1602,6 +1603,7 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) {
numericValueString = it.value();
gSaveContext.randoSettings[index].value = std::stoi(numericValueString);
break;
case RSK_SHUFFLE_COWS:
case RSK_RANDOM_TRIALS:
if(it.value() == "Off") {
gSaveContext.randoSettings[index].value = 0;
@ -3438,6 +3440,7 @@ void GenerateRandomizerImgui() {
cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS] = CVar_GetS32("gRandomizeShuffleDungeonReward", 0);
cvarSettings[RSK_SHUFFLE_SONGS] = CVar_GetS32("gRandomizeShuffleSongs", 0);
cvarSettings[RSK_SHUFFLE_TOKENS] = CVar_GetS32("gRandomizeShuffleTokens", 0);
cvarSettings[RSK_SHUFFLE_COWS] = CVar_GetS32("gRandomizeShuffleCows", 0);
cvarSettings[RSK_SKIP_CHILD_ZELDA] = CVar_GetS32("gRandomizeSkipChildZelda", 0);
// if we skip child zelda, we start with zelda's letter, and malon starts
@ -3956,6 +3959,12 @@ void DrawRandoEditor(bool& open) {
"expected to be collected after getting Sun's Song.");
PaddedSeparator();
// Shuffle Cows
ImGui::Text(Settings::ShuffleCows.GetName().c_str());
InsertHelpHoverText("Cows give a randomized item from the pool upon performing Epona's Song in front of them.");
SohImGui::EnhancementCombobox("gRandomizeShuffleCows", randoShuffleCows, 2, 0);
PaddedSeparator();
if(CVar_GetS32("gRandomizeStartingKokiriSword", 0) == 0) {
// Shuffle Kokiri Sword
SohImGui::EnhancementCheckbox(Settings::ShuffleKokiriSword.GetName().c_str(), "gRandomizeShuffleKokiriSword");

View File

@ -975,6 +975,7 @@ typedef enum {
RSK_SHUFFLE_DUNGEON_REWARDS,
RSK_SHUFFLE_SONGS,
RSK_SHUFFLE_TOKENS,
RSK_SHUFFLE_COWS,
RSK_SHUFFLE_WEIRD_EGG,
RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD,
RSK_ITEM_POOL,

View File

@ -736,6 +736,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 +900,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 +1060,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

@ -5,6 +5,7 @@
#define NUM_DUNGEONS 8
#define NUM_TRIALS 6
#define NUM_COWS 10
/**
* Initialize new save.
@ -619,6 +620,11 @@ 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

View File

@ -18,6 +18,9 @@ void func_809E0070(Actor* thisx, GlobalContext* globalCtx);
void func_809DF494(EnCow* this, GlobalContext* globalCtx);
void func_809DF6BC(EnCow* this, GlobalContext* globalCtx);
struct CowInfo EnCow_GetInfo(EnCow* this, GlobalContext* globalCtx);
void EnCow_MoveForRandomizer(EnCow* this, GlobalContext* globalCtx);
GetItemID EnCow_GetRandomizerItem(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 +109,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,12 +216,116 @@ void func_809DF730(EnCow* this, GlobalContext* globalCtx) {
}
}
struct CowInfo {
int cowId;
RandomizerCheck randomizerCheck;
};
struct 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) {
struct CowInfo cowInfo = EnCow_GetInfo(this, globalCtx);
gSaveContext.cowsMilked[cowInfo.cowId] = 1;
}
GetItemID EnCow_GetRandomizerItem(EnCow* this, GlobalContext* globalCtx) {
GetItemID itemId = ITEM_NONE;
struct CowInfo cowInfo = EnCow_GetInfo(this, globalCtx);
if (!gSaveContext.cowsMilked[cowInfo.cowId]) {
itemId = Randomizer_GetItemIdFromKnownCheck(cowInfo.randomizerCheck, GI_MILK);
} else if (Inventory_HasEmptyBottle()) {
itemId = GI_MILK;
}
return itemId;
}
void func_809DF778(EnCow* this, GlobalContext* globalCtx) {
if (Actor_HasParent(&this->actor, globalCtx)) {
this->actor.parent = NULL;
this->actionFunc = func_809DF730;
} else {
func_8002F434(&this->actor, globalCtx, GI_MILK, 10000.0f, 100.0f);
if (gSaveContext.n64ddFlag) {
GetItemID itemId = EnCow_GetRandomizerItem(this, globalCtx);
func_8002F434(&this->actor, globalCtx, itemId, 10000.0f, 100.0f);
EnCow_SetCowMilked(this, globalCtx);
if (itemId == GI_ICE_TRAP) {
Message_StartTextbox(globalCtx, 0xF8, &this->actor);
}
} else {
func_8002F434(&this->actor, globalCtx, GI_MILK, 10000.0f, 100.0f);
}
}
}
@ -223,13 +334,15 @@ void func_809DF7D8(EnCow* this, GlobalContext* globalCtx) {
this->actor.flags &= ~ACTOR_FLAG_16;
Message_CloseTextbox(globalCtx);
this->actionFunc = func_809DF778;
func_8002F434(&this->actor, globalCtx, GI_MILK, 10000.0f, 100.0f);
if (!gSaveContext.n64ddFlag) {
func_8002F434(&this->actor, globalCtx, GI_MILK, 10000.0f, 100.0f);
}
}
}
void func_809DF870(EnCow* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_EVENT) && Message_ShouldAdvance(globalCtx)) {
if (Inventory_HasEmptyBottle()) {
if (Inventory_HasEmptyBottle() || (gSaveContext.n64ddFlag && EnCow_GetRandomizerItem(this, globalCtx) != ITEM_NONE)) {
Message_ContinueTextbox(globalCtx, 0x2007);
this->actionFunc = func_809DF7D8;
} else {