Various adjustments to goron related vanilla behavior hooks

This commit is contained in:
Garrett Cox 2024-02-23 12:43:27 -06:00
parent b293cac51c
commit 13a113c362
8 changed files with 101 additions and 185 deletions

View File

@ -201,8 +201,8 @@ typedef enum {
// Opt: *uint16_t
// Vanilla condition: false
GI_VB_OVERRIDE_LINK_THE_GORON_DIALOGUE,
// Opt: *EnGo2
GI_VB_EN_GO2_RESET_AFTER_GET_ITEM,
// Vanilla condition: CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON)
GI_VB_GORONS_CONSIDER_TUNIC_COLLECTED,
// Opt: *EnSyatekiMan
// Vanilla condition: (this->getItemId == GI_QUIVER_40) || (this->getItemId == GI_QUIVER_50)
GI_VB_BE_ELIGIBLE_FOR_ADULT_SHOOTING_GAME_REWARD,
@ -273,9 +273,7 @@ typedef enum {
// Vanilla condition: !CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_ZORA)
GI_VB_GIVE_ITEM_FROM_THAWING_KING_ZORA,
// Opt: *EnGo2
GI_VB_GIVE_ITEM_FROM_ROLLING_GORON_AS_CHILD,
// Opt: *EnGo2
GI_VB_GIVE_ITEM_FROM_ROLLING_GORON_AS_ADULT,
GI_VB_GIVE_ITEM_FROM_GORON,
// Opt: *EnJs
GI_VB_GIVE_ITEM_FROM_CARPET_SALESMAN,
// Opt: *EnGm
@ -333,16 +331,10 @@ typedef enum {
GI_VB_TRADE_ODD_POTION,
// Opt: *EnToryo
GI_VB_TRADE_SAW,
// Opt: *EnGo2
GI_VB_TRADE_BROKEN_SWORD,
// Opt: *EnKz,
GI_VB_TRADE_PRESCRIPTION,
// Opt: *EnMk
GI_VB_TRADE_FROG,
// Opt: *EnGo2
GI_VB_TRADE_EYEDROPS,
// Opt: *EnGo2
GI_VB_TRADE_CLAIM_CHECK,
GI_VB_TRADE_TIMER_ODD_MUSHROOM,
GI_VB_TRADE_TIMER_EYEDROPS,

View File

@ -34,6 +34,7 @@ extern PlayState* gPlayState;
RandomizerCheck GetRandomizerCheckFromFlag(int16_t flagType, int16_t flag) {
for (auto& loc : Rando::StaticData::GetLocationTable()) {
if (loc.GetCollectionCheck().flag == flag && (
(flagType == FLAG_INF_TABLE && loc.GetCollectionCheck().type == SPOILER_CHK_INF_TABLE) ||
(flagType == FLAG_EVENT_CHECK_INF && loc.GetCollectionCheck().type == SPOILER_CHK_EVENT_CHK_INF) ||
(flagType == FLAG_ITEM_GET_INF && loc.GetCollectionCheck().type == SPOILER_CHK_ITEM_GET_INF) ||
(flagType == FLAG_RANDOMIZER_INF && loc.GetCollectionCheck().type == SPOILER_CHK_RANDOMIZER_INF)
@ -104,6 +105,18 @@ static RandomizerCheck randomizerQueuedCheck = RC_UNKNOWN_CHECK;
static GetItemEntry randomizerQueuedItemEntry = GET_ITEM_NONE;
void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) {
// Consume adult trade items
if (RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE) && flagType == FLAG_RANDOMIZER_INF) {
switch (flag) {
case RAND_INF_ADULT_TRADES_DMT_TRADE_BROKEN_SWORD:
Randomizer_ConsumeAdultTradeItem(gPlayState, ITEM_SWORD_BROKEN);
break;
case RAND_INF_ADULT_TRADES_DMT_TRADE_EYEDROPS:
Randomizer_ConsumeAdultTradeItem(gPlayState, ITEM_EYEDROPS);
break;
}
}
RandomizerCheck rc = GetRandomizerCheckFromFlag(flagType, flag);
if (rc == RC_UNKNOWN_CHECK) return;
@ -453,8 +466,9 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void
break;
}
case GI_VB_BIGGORON_CONSIDER_TRADE_COMPLETE: {
*should = INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_CLAIM_CHECK && Flags_GetRandomizerInf(RAND_INF_ADULT_TRADES_DMT_TRADE_CLAIM_CHECK);
// This being true will prevent other biggoron trades, there are already safegaurds in place to prevent
// claim check from being traded multiple times, so we don't really need the quest to ever be considered "complete"
*should = false;
break;
}
case GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED: {
@ -465,46 +479,8 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void
*should = Flags_GetEventChkInf(EVENTCHKINF_USED_DODONGOS_CAVERN_BLUE_WARP);
break;
}
case GI_VB_OVERRIDE_LINK_THE_GORON_DIALOGUE: {
u16* textId = static_cast<u16*>(optionalArg);
*should = true;
// For rando, prioritize opening the doors in GC when Link the goron has been stopped when
// the doors are not opened, otherwise let him talk about the DMC exit or that gorons are saved
if (!Flags_GetInfTable(INFTABLE_STOPPED_GORON_LINKS_ROLLING)) {
*textId = 0x3030;
} else if (!Flags_GetInfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED)) {
*textId = 0x3036;
} else if (Flags_GetEventChkInf(EVENTCHKINF_USED_FIRE_TEMPLE_BLUE_WARP)) {
*textId = 0x3041;
} else {
*textId = Flags_GetInfTable(INFTABLE_SPOKE_TO_GORON_LINK) ? 0x3038 : 0x3037;
}
break;
}
case GI_VB_EN_GO2_RESET_AFTER_GET_ITEM: {
EnGo2* enGo2 = static_cast<EnGo2*>(optionalArg);
// For randomizer, handle updating the states for the gorons after receiving the item based on
// the goron type rather then the item being received
switch (enGo2->actor.params & 0x1F) {
case GORON_DMT_BIGGORON:
// Resolves #1301. unk_13EE is used to set the opacity of the HUD. The trade sequence discussion
// with Biggoron sets the HUD to transparent, and it is restored at z_message_PAL:3549, but by
// specifically watching for trade sequence items, this leaves it transparent for non-trade sequence
// items (in rando) so we fix that here
gSaveContext.unk_13EE = 0x32;
break;
case GORON_CITY_LINK:
EnGo2_GetItemAnimation(enGo2, gPlayState);
break;
case GORON_CITY_ROLLING_BIG:
EnGo2_RollingAnimation(enGo2, gPlayState);
enGo2->actionFunc = (EnGo2ActionFunc)EnGo2_GoronRollingBigContinueRolling;
break;
default:
enGo2->actionFunc = func_80A46B40;
break;
}
case GI_VB_GORONS_CONSIDER_TUNIC_COLLECTED: {
*should = Flags_GetInfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED);
break;
}
case GI_VB_GIVE_ITEM_FROM_ITEM_00: {
@ -589,15 +565,6 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void
*should = false;
break;
}
case GI_VB_GIVE_ITEM_FROM_ROLLING_GORON_AS_ADULT: {
EnGo2* enGo2 = static_cast<EnGo2*>(optionalArg);
*should = false;
if (!Flags_GetRandomizerInf(RAND_INF_ROLLING_GORON_AS_ADULT)) {
Flags_SetInfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED);
enGo2->interactInfo.talkState = NPC_TALK_STATE_ACTION;
}
break;
}
case GI_VB_GIVE_ITEM_FROM_CARPET_SALESMAN: {
*should = RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_OFF ||
// If the rando check has already been awarded, use vanilla behavior.
@ -695,16 +662,6 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void
*should = false;
break;
}
case GI_VB_TRADE_BROKEN_SWORD: {
Randomizer_ConsumeAdultTradeItem(gPlayState, ITEM_SWORD_BROKEN);
*should = false;
break;
}
case GI_VB_TRADE_EYEDROPS: {
Randomizer_ConsumeAdultTradeItem(gPlayState, ITEM_EYEDROPS);
*should = false;
break;
}
case GI_VB_DESPAWN_HORSE_RACE_COW: {
if (!RAND_GET_OPTION(RSK_SHUFFLE_COWS)) {
break;
@ -806,12 +763,11 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void
*should = eligible;
break;
}
case GI_VB_TRADE_CLAIM_CHECK:
case GI_VB_TRADE_TIMER_ODD_MUSHROOM:
case GI_VB_TRADE_TIMER_EYEDROPS:
case GI_VB_TRADE_TIMER_FROG:
case GI_VB_ANJU_SET_OBTAINED_TRADE_ITEM:
case GI_VB_GIVE_ITEM_FROM_ROLLING_GORON_AS_CHILD:
case GI_VB_GIVE_ITEM_FROM_GORON:
case GI_VB_GIVE_ITEM_FROM_LAB_DIVE:
case GI_VB_GIVE_ITEM_FROM_SKULL_KID_SARIAS_SONG:
case GI_VB_GIVE_ITEM_FROM_MAN_ON_ROOF:

View File

@ -16,10 +16,10 @@ class SpoilerCollectionCheck {
public:
SpoilerCollectionCheckType type = SPOILER_CHK_NONE;
uint8_t scene = 0;
uint8_t flag = 0;
uint16_t flag = 0;
SpoilerCollectionCheck() = default;
SpoilerCollectionCheck(const SpoilerCollectionCheckType type_, const uint8_t scene_, const uint8_t flag_)
SpoilerCollectionCheck(const SpoilerCollectionCheckType type_, const uint8_t scene_, const uint16_t flag_)
: type(type_), scene(scene_), flag(flag_) {
}
@ -39,8 +39,8 @@ class SpoilerCollectionCheck {
return SpoilerCollectionCheck(SPOILER_CHK_EVENT_CHK_INF, 0xFF, flag);
}
static auto InfTable(const uint8_t offset, const uint8_t bit) {
return SpoilerCollectionCheck(SPOILER_CHK_INF_TABLE, offset, bit);
static auto InfTable(const uint16_t flag) {
return SpoilerCollectionCheck(SPOILER_CHK_INF_TABLE, 0xFF, flag);
}
static auto Collectable(const uint8_t scene, const uint8_t flag) {

View File

@ -651,7 +651,7 @@ void Rando::StaticData::InitLocationTable() { //
locationTable[RC_GV_DEKU_SCRUB_GROTTO_FRONT] = Location::GrottoScrub(RC_GV_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GERUDO_VALLEY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xF0), 0x3A, "Deku Scrub Grotto Front", "GV Deku Scrub Grotto Front", RHT_GV_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, { Category::cDekuScrub }, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_FRONT), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY);
// Gerudo Fortress
locationTable[RC_GF_CHEST] = Location::Chest(RC_GF_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GERUDO_FORTRESS, ACTOR_EN_BOX, SCENE_GERUDOS_FORTRESS, 1984, 0x00, "Chest", "GF Chest", RHT_GF_CHEST, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY, true);
locationTable[RC_GF_HBA_1000_POINTS] = Location::Base(RC_GF_HBA_1000_POINTS, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GERUDO_FORTRESS, ACTOR_ID_MAX, SCENE_GERUDOS_FORTRESS, 0x00, 0x3E, "GF HBA 1000 Points", "GF HBA 1000 Points", RHT_GF_HBA_1000_POINTS, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(0x19, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY, true);
locationTable[RC_GF_HBA_1000_POINTS] = Location::Base(RC_GF_HBA_1000_POINTS, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GERUDO_FORTRESS, ACTOR_ID_MAX, SCENE_GERUDOS_FORTRESS, 0x00, 0x3E, "GF HBA 1000 Points", "GF HBA 1000 Points", RHT_GF_HBA_1000_POINTS, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(INFTABLE_190), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY, true);
locationTable[RC_GF_HBA_1500_POINTS] = Location::Base(RC_GF_HBA_1500_POINTS, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GERUDO_FORTRESS, ACTOR_ID_MAX, SCENE_GERUDOS_FORTRESS, 0x00, 0x30, "GF HBA 1500 Points", "GF HBA 1500 Points", RHT_GF_HBA_1500_POINTS, RG_PROGRESSIVE_BOW, {}, SpoilerCollectionCheck::ItemGetInf(15), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY, true);
// RandoTodo: Do we replace these with the RC_HIDEOUT keys or keep these?
locationTable[RC_GF_GERUDO_MEMBERSHIP_CARD] = Location::Base(RC_GF_GERUDO_MEMBERSHIP_CARD, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GERUDO_FORTRESS, ACTOR_ID_MAX, SCENE_THIEVES_HIDEOUT, 0x00, 0x3A, "GF Gerudo Membership Card", "GF Gerudo Membership Card", RHT_GF_GERUDO_MEMBERSHIP_CARD, RG_GERUDO_MEMBERSHIP_CARD, {}, SpoilerCollectionCheck::GerudoToken(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY, true);
@ -671,7 +671,7 @@ void Rando::StaticData::InitLocationTable() { //
locationTable[RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = Location::Base(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_BOMBCHU_BOWLING_ALLEY, 0x00, 0x33, "Bombchu Bowling First Prize", "MK Bombchu Bowling First Prize", RHT_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, RG_PROGRESSIVE_BOMB_BAG, {}, SpoilerCollectionCheck::ItemGetInf(17), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE, true);
locationTable[RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = Location::Base(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_BOMBCHU_BOWLING_ALLEY, 0x00, 0x3E, "Bombchu Bowling Second Prize", "MK Bombchu Bowling Second Prize", RHT_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(18), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE, true);
locationTable[RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS] = Location::Base(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_BOMBCHU_BOWLING_ALLEY, 0x00, 0x00, "Bombchu Bowling Bombchus", "MK Bombchu Bowling Bombchus", RHT_MARKET_BOMBCHU_BOWLING_BOMBCHUS, RG_BOMBCHU_DROP, {}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
locationTable[RC_MARKET_LOST_DOG] = Location::Base(RC_MARKET_LOST_DOG, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_DOG_LADY_HOUSE, 0x00, 0x3E, "Lost Dog", "MK Lost Dog", RHT_MARKET_LOST_DOG, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(0x19, 0x09), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE, true);
locationTable[RC_MARKET_LOST_DOG] = Location::Base(RC_MARKET_LOST_DOG, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_DOG_LADY_HOUSE, 0x00, 0x3E, "Lost Dog", "MK Lost Dog", RHT_MARKET_LOST_DOG, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(INFTABLE_191), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE, true);
locationTable[RC_MARKET_SHOOTING_GALLERY_REWARD] = Location::Base(RC_MARKET_SHOOTING_GALLERY_REWARD, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_SHOOTING_GALLERY, 0x00, 0x60, "Shooting Gallery", "MK Shooting Gallery", RHT_MARKET_SHOOTING_GALLERY_REWARD, RG_PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(ITEMGETINF_0D), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE, true);
locationTable[RC_MARKET_10_BIG_POES] = Location::Base(RC_MARKET_10_BIG_POES, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_MARKET_GUARD_HOUSE, 0x00, 0x0F, "10 Big Poes", "MK 10 Big Poes", RHT_MARKET_10_BIG_POES, RG_EMPTY_BOTTLE, {}, SpoilerCollectionCheck::RandomizerInf(RAND_INF_10_BIG_POES), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE, true);
locationTable[RC_MARKET_TREASURE_CHEST_GAME_ITEM_1] = Location::Chest(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, RCQUEST_BOTH, RCTYPE_CHEST_GAME, RCAREA_MARKET, ACTOR_EN_BOX, SCENE_TREASURE_BOX_SHOP, 0x00, 0x01, "Chest Game First Room Chest", "MK Chest Game First Room Chest", RHT_MARKET_TREASURE_CHEST_GAME_ITEM_1, RG_TREASURE_GAME_SMALL_KEY, { Category::cChestMinigame }, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE);
@ -719,8 +719,8 @@ void Rando::StaticData::InitLocationTable() { //
locationTable[RC_GC_MAZE_LEFT_CHEST] = Location::Chest(RC_GC_MAZE_LEFT_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_EN_BOX, SCENE_GORON_CITY, 23232, 0x00, "Maze Left Chest", "GC Maze Left Chest", RHT_GC_MAZE_LEFT_CHEST, RG_HUGE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY);
locationTable[RC_GC_MAZE_RIGHT_CHEST] = Location::Chest(RC_GC_MAZE_RIGHT_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_EN_BOX, SCENE_GORON_CITY, 23201, 0x01, "Maze Right Chest", "GC Maze Right Chest", RHT_GC_MAZE_RIGHT_CHEST, RG_PURPLE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY);
locationTable[RC_GC_MAZE_CENTER_CHEST] = Location::Chest(RC_GC_MAZE_CENTER_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_EN_BOX, SCENE_GORON_CITY, 23202, 0x02, "Maze Center Chest", "GC Maze Center Chest", RHT_GC_MAZE_CENTER_CHEST, RG_PURPLE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY);
locationTable[RC_GC_ROLLING_GORON_AS_CHILD] = Location::Base(RC_GC_ROLLING_GORON_AS_CHILD, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, 0x34, "Rolling Goron as Child", "GC Rolling Goron as Child", RHT_GC_ROLLING_GORON_AS_CHILD, RG_PROGRESSIVE_BOMB_BAG, {}, SpoilerCollectionCheck::RandomizerInf(RAND_INF_ROLLING_GORON_AS_CHILD), SpoilerCollectionCheckGroup::GROUP_GORON_CITY, true);
locationTable[RC_GC_ROLLING_GORON_AS_ADULT] = Location::Base(RC_GC_ROLLING_GORON_AS_ADULT, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, 0x2C, "Rolling Goron as Adult", "GC Rolling Goron as Adult", RHT_GC_ROLLING_GORON_AS_ADULT, RG_GORON_TUNIC, {}, SpoilerCollectionCheck::RandomizerInf(RAND_INF_ROLLING_GORON_AS_ADULT), SpoilerCollectionCheckGroup::GROUP_GORON_CITY, true);
locationTable[RC_GC_ROLLING_GORON_AS_CHILD] = Location::Base(RC_GC_ROLLING_GORON_AS_CHILD, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, 0x34, "Rolling Goron as Child", "GC Rolling Goron as Child", RHT_GC_ROLLING_GORON_AS_CHILD, RG_PROGRESSIVE_BOMB_BAG, {}, SpoilerCollectionCheck::InfTable(INFTABLE_11E), SpoilerCollectionCheckGroup::GROUP_GORON_CITY, true);
locationTable[RC_GC_ROLLING_GORON_AS_ADULT] = Location::Base(RC_GC_ROLLING_GORON_AS_ADULT, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, 0x2C, "Rolling Goron as Adult", "GC Rolling Goron as Adult", RHT_GC_ROLLING_GORON_AS_ADULT, RG_GORON_TUNIC, {}, SpoilerCollectionCheck::InfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED), SpoilerCollectionCheckGroup::GROUP_GORON_CITY, true);
locationTable[RC_GC_DARUNIAS_JOY] = Location::Base(RC_GC_DARUNIAS_JOY, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, 0x54, "Darunias Joy", "GC Darunias Joy", RHT_GC_DARUNIAS_JOY, RG_PROGRESSIVE_STRENGTH, {}, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DARUNIAS_JOY), SpoilerCollectionCheckGroup::GROUP_GORON_CITY, true);
locationTable[RC_GC_POT_FREESTANDING_POH] = Location::Collectable(RC_GC_POT_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_GORON_CITY, ACTOR_EN_ITEM00, SCENE_GORON_CITY, 7942, 0x1F, "Pot Freestanding PoH", "GC Pot Freestanding PoH", RHT_GC_POT_FREESTANDING_POH, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY, true);
locationTable[RC_GC_DEKU_SCRUB_GROTTO_LEFT] = Location::GrottoScrub(RC_GC_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GORON_CITY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xFB), 0x30, "Deku Scrub Grotto Left", "GC Deku Scrub Grotto Left", RHT_GC_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, { Category::cDekuScrub }, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_LEFT), SpoilerCollectionCheckGroup::GROUP_GORON_CITY);

View File

@ -274,8 +274,6 @@ typedef enum {
RAND_INF_LEARNED_EPONA_SONG,
RAND_INF_DARUNIAS_JOY,
RAND_INF_KING_ZORA_THAWED,
RAND_INF_ROLLING_GORON_AS_CHILD,
RAND_INF_ROLLING_GORON_AS_ADULT,
// If you add anything to this list, you need to update the size of randomizerInf in z64save.h to be ceil(RAND_INF_MAX / 16)

View File

@ -401,6 +401,17 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void*
}
break;
}
case GI_VB_OVERRIDE_LINK_THE_GORON_DIALOGUE: {
if (CVarGetInteger("gTimeSavers.SkipMiscInteractions", IS_RANDO)) {
u16* textId = static_cast<u16*>(opt);
// If the doors are not open yet, prioritize opening them
if (!Flags_GetInfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED)) {
*textId = 0x3036;
*should = true;
}
}
break;
}
case GI_VB_PLAY_EYEDROP_CREATION_ANIM:
case GI_VB_PLAY_EYEDROPS_CS:
case GI_VB_PLAY_DROP_FISH_FOR_JABU_CS:

View File

@ -971,7 +971,6 @@ void EnGo_GetItem(EnGo* this, PlayState* play) {
if ((this->actor.params & 0xF0) == 0) {
getItemId = GI_TUNIC_GORON;
Flags_SetRandomizerInf(RAND_INF_ROLLING_GORON_AS_ADULT);
}
yDist = fabsf(this->actor.yDistToPlayer) + 1.0f;

View File

@ -142,7 +142,6 @@ typedef enum {
/* 10 */ ENGO2_ANIM_10,
/* 11 */ ENGO2_ANIM_11,
/* 12 */ ENGO2_ANIM_12,
/* 13 */ ENGO2_ANIM_13, // Added to fix spinning goron issue for biggoron
} EnGo2Animation;
static AnimationInfo sAnimationInfo[] = {
@ -152,7 +151,7 @@ static AnimationInfo sAnimationInfo[] = {
{ &gGoronAnim_002D80, 1.0f, 0.0f, -1.0f, 0x02, -8.0f }, { &gGoronAnim_00161C, 1.0f, 0.0f, -1.0f, 0x00, -8.0f },
{ &gGoronAnim_001A00, 1.0f, 0.0f, -1.0f, 0x00, -8.0f }, { &gGoronAnim_0021D0, 1.0f, 0.0f, -1.0f, 0x00, -8.0f },
{ &gGoronAnim_004930, 0.0f, 0.0f, -1.0f, 0x01, -8.0f }, { &gGoronAnim_000750, 1.0f, 0.0f, -1.0f, 0x00, -8.0f },
{ &gGoronAnim_000D5C, 1.0f, 0.0f, -1.0f, 0x00, -8.0f }, { &gGoronAnim_004930, 0.0f, 1.0f, -1.0f, 0x01, 0.0f },
{ &gGoronAnim_000D5C, 1.0f, 0.0f, -1.0f, 0x00, -8.0f },
};
static EnGo2DustEffectData sDustEffectData[2][4] = {
@ -284,15 +283,10 @@ s32 EnGo2_SpawnDust(EnGo2* this, u8 initialTimer, f32 scale, f32 scaleStep, s32
void EnGo2_GetItem(EnGo2* this, PlayState* play, s32 getItemId) {
this->getItemId = getItemId;
func_8002F434(&this->actor, play, getItemId, this->actor.xzDistToPlayer + 1.0f,
fabsf(this->actor.yDistToPlayer) + 1.0f);
}
void EnGo2_GetItemEntry(EnGo2* this, PlayState* play, GetItemEntry getItemEntry) {
this->getItemId = getItemEntry.getItemId;
this->getItemEntry = getItemEntry;
GiveItemEntryFromActor(&this->actor, play, getItemEntry, this->actor.xzDistToPlayer + 1.0f,
fabsf(this->actor.yDistToPlayer) + 1.0f);
if (GameInteractor_Should(GI_VB_GIVE_ITEM_FROM_GORON, true, this)) {
func_8002F434(&this->actor, play, getItemId, this->actor.xzDistToPlayer + 1.0f,
fabsf(this->actor.yDistToPlayer) + 1.0f);
}
}
s32 EnGo2_GetDialogState(EnGo2* this, PlayState* play) {
@ -335,7 +329,7 @@ u16 EnGo2_GoronFireGenericGetTextId(EnGo2* this) {
u16 EnGo2_GetTextIdGoronCityRollingBig(PlayState* play, EnGo2* this) {
if (Flags_GetInfTable(INFTABLE_11E)) {
return 0x3013;
} else if (GameInteractor_Should(GI_VB_BE_ELIGIBLE_FOR_CHILD_ROLLING_GORON_REWARD, CUR_CAPACITY(UPG_BOMB_BAG) >= 2, this)
} else if (GameInteractor_Should(GI_VB_BE_ELIGIBLE_FOR_CHILD_ROLLING_GORON_REWARD, CUR_CAPACITY(UPG_BOMB_BAG) >= 20, this)
&& this->waypoint > 7 && this->waypoint < 12) {
return 0x3012;
} else {
@ -351,14 +345,9 @@ s16 EnGo2_UpdateTalkStateGoronCityRollingBig(PlayState* play, EnGo2* this) {
if (Message_ShouldAdvance(play)) {
if (this->actor.textId == 0x3012) {
this->actionFunc = EnGo2_SetupGetItem;
if(GameInteractor_Should(GI_VB_GIVE_ITEM_FROM_ROLLING_GORON_AS_CHILD, true, this)) {
EnGo2_GetItem(this, play, CUR_CAPACITY(UPG_BOMB_BAG) == 30 ? GI_BOMB_BAG_40 : GI_BOMB_BAG_30);
} else {
this->actionFunc = EnGo2_SetGetItem;
}
EnGo2_GetItem(this, play, CUR_CAPACITY(UPG_BOMB_BAG) == 30 ? GI_BOMB_BAG_40 : GI_BOMB_BAG_30);
Message_CloseTextbox(play);
Flags_SetInfTable(INFTABLE_11E);
Flags_SetRandomizerInf(RAND_INF_ROLLING_GORON_AS_CHILD);
return NPC_TALK_STATE_ACTION;
} else {
return NPC_TALK_STATE_ACTION;
@ -511,9 +500,9 @@ u16 EnGo2_GetTextIdGoronCityLink(PlayState* play, EnGo2* this) {
return overrideTextId;
}
if (CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE)) {
if (GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL)) {
return Flags_GetInfTable(INFTABLE_10F) ? 0x3042 : 0x3041;
} else if (CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON)) {
} else if (GameInteractor_Should(GI_VB_GORONS_CONSIDER_TUNIC_COLLECTED, CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON), NULL)) {
return Flags_GetInfTable(INFTABLE_SPOKE_TO_GORON_LINK) ? 0x3038 : 0x3037;
} else if (Flags_GetInfTable(INFTABLE_STOPPED_GORON_LINKS_ROLLING)) {
this->unk_20C = 0;
@ -529,16 +518,9 @@ s16 EnGo2_UpdateTalkStateGoronCityLink(PlayState* play, EnGo2* this) {
case TEXT_STATE_CLOSING:
switch (this->actor.textId) {
case 0x3036:
Flags_SetRandomizerInf(RAND_INF_ROLLING_GORON_AS_ADULT);
this->interactInfo.talkState = NPC_TALK_STATE_IDLE;
if (GameInteractor_Should(GI_VB_GIVE_ITEM_FROM_ROLLING_GORON_AS_ADULT, true, this)) {
EnGo2_GetItem(this, play, GI_TUNIC_GORON);
this->actionFunc = EnGo2_SetupGetItem;
return NPC_TALK_STATE_ACTION;
} else {
this->actionFunc = EnGo2_SetGetItem;
return this->interactInfo.talkState;
}
EnGo2_GetItem(this, play, GI_TUNIC_GORON);
this->actionFunc = EnGo2_SetupGetItem;
return NPC_TALK_STATE_ACTION;
case 0x3037:
Flags_SetInfTable(INFTABLE_SPOKE_TO_GORON_LINK);
default:
@ -608,18 +590,14 @@ s16 EnGo2_UpdateTalkStateGoronDmtBiggoron(PlayState* play, EnGo2* this) {
switch (EnGo2_GetDialogState(this, play)) {
case TEXT_STATE_DONE:
if (this->actor.textId == 0x305E) {
if (GameInteractor_Should(GI_VB_BIGGORON_CONSIDER_SWORD_COLLECTED, gSaveContext.bgsFlag, NULL)) {
return NPC_TALK_STATE_IDLE;
}
Flags_SetRandomizerInf(RAND_INF_ADULT_TRADES_DMT_TRADE_CLAIM_CHECK);
if (GameInteractor_Should(GI_VB_TRADE_CLAIM_CHECK, true, this)) {
if (!GameInteractor_Should(GI_VB_BIGGORON_CONSIDER_SWORD_COLLECTED, gSaveContext.bgsFlag, NULL)) {
Flags_SetRandomizerInf(RAND_INF_ADULT_TRADES_DMT_TRADE_CLAIM_CHECK);
EnGo2_GetItem(this, play, GI_SWORD_BGS);
this->actionFunc = EnGo2_SetupGetItem;
return NPC_TALK_STATE_ACTION;
} else {
this->actionFunc = EnGo2_SetGetItem;
return NPC_TALK_STATE_IDLE;
}
return NPC_TALK_STATE_ACTION;
} else {
return NPC_TALK_STATE_IDLE;
}
@ -645,12 +623,8 @@ s16 EnGo2_UpdateTalkStateGoronDmtBiggoron(PlayState* play, EnGo2* this) {
if ((this->actor.textId == 0x3054) || (this->actor.textId == 0x3055)) {
if (play->msgCtx.choiceIndex == 0) {
Flags_SetRandomizerInf(RAND_INF_ADULT_TRADES_DMT_TRADE_BROKEN_SWORD);
if (GameInteractor_Should(GI_VB_TRADE_BROKEN_SWORD, true, this)) {
EnGo2_GetItem(this, play, GI_PRESCRIPTION);
this->actionFunc = EnGo2_SetupGetItem;
} else {
this->actionFunc = EnGo2_SetGetItem;
}
EnGo2_GetItem(this, play, GI_PRESCRIPTION);
this->actionFunc = EnGo2_SetupGetItem;
return NPC_TALK_STATE_ACTION;
}
this->actor.textId = 0x3056;
@ -1056,7 +1030,10 @@ void EnGo2_BiggoronSetTextId(EnGo2* this, PlayState* play, Player* player) {
}
player->actor.textId = this->actor.textId;
} else if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_CLAIM_CHECK) {
} else if (
!GameInteractor_Should(GI_VB_BIGGORON_CONSIDER_SWORD_COLLECTED, gSaveContext.bgsFlag, NULL) &&
(INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_CLAIM_CHECK)
) {
if (func_8002F368(play) == EXCH_ITEM_CLAIM_CHECK) {
if (GameInteractor_Should(GI_VB_BIGGORON_CONSIDER_SWORD_FORGED, Environment_GetBgsDayCount() >= 3, NULL)) {
textId = 0x305E;
@ -1193,8 +1170,10 @@ s32 EnGo2_IsCameraModified(EnGo2* this, PlayState* play) {
(this->actor.params & 0x1F) == GORON_CITY_STAIRWELL || (this->actor.params & 0x1F) == GORON_DMT_BIGGORON ||
(this->actor.params & 0x1F) == GORON_MARKET_BAZAAR) {
return true;
} else if (GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL) &&
CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON)) {
} else if (
!GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL) &&
GameInteractor_Should(GI_VB_GORONS_CONSIDER_TUNIC_COLLECTED, CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON), NULL)
) {
return true;
} else {
return false;
@ -1251,8 +1230,10 @@ void EnGo2_SelectGoronWakingUp(EnGo2* this) {
EnGo2_BiggoronWakingUp(this);
break;
case GORON_CITY_LINK:
if (GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL) &&
CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON)) {
if (
!GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL) &&
GameInteractor_Should(GI_VB_GORONS_CONSIDER_TUNIC_COLLECTED, CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON), NULL)
) {
EnGo2_WakingUp(this);
break;
}
@ -1349,25 +1330,10 @@ void EnGo2_WakeUp(EnGo2* this, PlayState* play) {
}
if ((this->actor.params & 0x1F) == GORON_DMT_BIGGORON) {
OnePointCutscene_Init(play, 4200, -99, &this->actor, MAIN_CAM);
// There is an issue interpolating between ENGO2_ANIM_0 and ENGO2_ANIM_1/10, the goron
// is technically in the same position at the end of ANIM_0 and beginning of ANIM_1/10
// but something isn't getting translated correctly causing the 360 degree spin before
// then continuing the wake up animation like normal. One solution is to use ANIM_0
// which uses the same frame data as ANIM_1/10 but no morph frames, but only when the
// current animation frame is at 0, meaning no morphing is necessary anyway.
// ANIM_13 is ANIM_0 but with the startFrame and mode adjusted for biggoron.
if (this->skelAnime.curFrame == 0.0f && !CVarGetInteger("gUnfixGoronSpin", 0)) {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENGO2_ANIM_13);
} else {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENGO2_ANIM_10);
}
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENGO2_ANIM_10);
this->skelAnime.playSpeed = 0.5f;
} else {
if (this->skelAnime.curFrame == 0.0f && !CVarGetInteger("gUnfixGoronSpin", 0)) {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENGO2_ANIM_0);
} else {
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENGO2_ANIM_1);
}
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENGO2_ANIM_1);
this->skelAnime.playSpeed = 1.0f;
}
this->actionFunc = func_80A46B40;
@ -1589,14 +1555,13 @@ void EnGo2_Init(Actor* thisx, PlayState* play) {
this->unk_216 = this->actor.shape.rot.z;
this->trackingMode = NPC_TRACKING_NONE;
this->path = Path_GetByIndex(play, (this->actor.params & 0x3E0) >> 5, 0x1F);
this->getItemEntry = (GetItemEntry)GET_ITEM_NONE;
switch (this->actor.params & 0x1F) {
case GORON_CITY_ENTRANCE:
case GORON_CITY_ISLAND:
case GORON_CITY_LOWEST_FLOOR:
case GORON_CITY_STAIRWELL:
case GORON_CITY_LOST_WOODS:
if (GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL) && LINK_IS_ADULT) {
if (!GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL) && LINK_IS_ADULT) {
Actor_Kill(&this->actor);
}
this->actionFunc = EnGo2_CurledUp;
@ -1611,8 +1576,10 @@ void EnGo2_Init(Actor* thisx, PlayState* play) {
if ((Flags_GetInfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED))) {
Path_CopyLastPoint(this->path, &this->actor.world.pos);
this->actor.home.pos = this->actor.world.pos;
if (GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL) &&
CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON)) {
if (
!GameInteractor_Should(GI_VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED, CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE), NULL) &&
GameInteractor_Should(GI_VB_GORONS_CONSIDER_TUNIC_COLLECTED, CHECK_OWNED_EQUIP(EQUIP_TYPE_TUNIC, EQUIP_INV_TUNIC_GORON), NULL)
) {
EnGo2_GetItemAnimation(this, play);
} else {
this->actionFunc = EnGo2_CurledUp;
@ -1828,7 +1795,7 @@ void EnGo2_ReverseRolling(EnGo2* this, PlayState* play) {
}
void EnGo2_SetupGetItem(EnGo2* this, PlayState* play) {
if (Actor_HasParent(&this->actor, play)) {
if (Actor_HasParent(&this->actor, play) || !GameInteractor_Should(GI_VB_GIVE_ITEM_FROM_GORON, true, NULL)) {
this->actor.parent = NULL;
this->actionFunc = EnGo2_SetGetItem;
} else {
@ -1837,30 +1804,29 @@ void EnGo2_SetupGetItem(EnGo2* this, PlayState* play) {
}
void EnGo2_SetGetItem(EnGo2* this, PlayState* play) {
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(play)) {
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(play) || !GameInteractor_Should(GI_VB_GIVE_ITEM_FROM_GORON, true, NULL)) {
this->interactInfo.talkState = NPC_TALK_STATE_IDLE;
if (GameInteractor_Should(GI_VB_EN_GO2_RESET_AFTER_GET_ITEM, true, this)) {
switch (this->getItemId) {
case GI_CLAIM_CHECK:
Environment_ClearBgsDayCount();
EnGo2_GetItemAnimation(this, play);
return;
case GI_TUNIC_GORON:
Flags_SetInfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED);
EnGo2_GetItemAnimation(this, play);
return;
case GI_SWORD_BGS:
switch (this->getItemId) {
case GI_CLAIM_CHECK:
Environment_ClearBgsDayCount();
EnGo2_GetItemAnimation(this, play);
return;
case GI_TUNIC_GORON:
Flags_SetInfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED);
EnGo2_GetItemAnimation(this, play);
return;
case GI_SWORD_BGS:
if (GameInteractor_Should(GI_VB_GIVE_ITEM_FROM_GORON, true, NULL)) {
gSaveContext.bgsFlag = true;
break;
case GI_BOMB_BAG_30:
case GI_BOMB_BAG_40:
EnGo2_RollingAnimation(this, play);
this->actionFunc = EnGo2_GoronRollingBigContinueRolling;
return;
}
this->actionFunc = func_80A46B40;
}
break;
case GI_BOMB_BAG_30:
case GI_BOMB_BAG_40:
EnGo2_RollingAnimation(this, play);
this->actionFunc = EnGo2_GoronRollingBigContinueRolling;
return;
}
this->actionFunc = func_80A46B40;
}
}
@ -1905,15 +1871,9 @@ void EnGo2_BiggoronEyedrops(EnGo2* this, PlayState* play) {
this->trackingMode = NPC_TRACKING_HEAD_AND_TORSO;
this->skelAnime.playSpeed = 0.0f;
this->skelAnime.curFrame = this->skelAnime.endFrame;
Flags_SetRandomizerInf(RAND_INF_ADULT_TRADES_DMT_TRADE_EYEDROPS);
if(GameInteractor_Should(GI_VB_TRADE_EYEDROPS, true, this)) {
u32 getItemId = GI_CLAIM_CHECK;
EnGo2_GetItem(this, play, getItemId);
this->actionFunc = EnGo2_SetupGetItem;
} else {
this->actionFunc = EnGo2_SetGetItem;
}
EnGo2_GetItem(this, play, GI_CLAIM_CHECK);
this->actionFunc = EnGo2_SetupGetItem;
this->goronState = 0;
}
break;