This commit is contained in:
Philip Dubé 2025-04-24 00:43:58 +00:00 committed by GitHub
commit 4ff84449be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 80 additions and 29 deletions

View file

@ -294,6 +294,14 @@ typedef enum {
// - `*ObjKibako2` // - `*ObjKibako2`
VB_CRATE_SETUP_DRAW, VB_CRATE_SETUP_DRAW,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_CRAWL,
// #### `result` // #### `result`
// ```c // ```c
// !Flags_GetItemGetInf(ITEMGETINF_1C) // !Flags_GetItemGetInf(ITEMGETINF_1C)

View file

@ -2097,6 +2097,7 @@ void StaticData::HintTable_Init_Item() {
}, },
{ CustomMessage("a master unlocker", /*german*/ "ein Meisterentsperrer", /*french*/ "un Kit de Déverrouillage") }); { CustomMessage("a master unlocker", /*german*/ "ein Meisterentsperrer", /*french*/ "un Kit de Déverrouillage") });
// /*spanish*/un desbloqueador maestro // /*spanish*/un desbloqueador maestro
hintTextTable[RHT_CRAWL] = HintText(CustomMessage("the ability to crawl", /*german*/"!!!", /*french*/"!!!"));
//RANDOTODO if these are ever used for anything other than name, they want abscure and ambiguous hints //RANDOTODO if these are ever used for anything other than name, they want abscure and ambiguous hints
hintTextTable[RHT_QUIVER_INF] = HintText(CustomMessage("an infinite Quiver", /*german*/"ein unendlicher Köcher", /*french*/"un Carquois Infini")); hintTextTable[RHT_QUIVER_INF] = HintText(CustomMessage("an infinite Quiver", /*german*/"ein unendlicher Köcher", /*french*/"un Carquois Infini"));

View file

@ -591,6 +591,10 @@ void GenerateItemPool() {
AddItemToMainPool(RG_PROGRESSIVE_SCALE); AddItemToMainPool(RG_PROGRESSIVE_SCALE);
} }
if (ctx->GetOption(RSK_SHUFFLE_CRAWL)) {
AddItemToMainPool(RG_CRAWL);
}
if (ctx->GetOption(RSK_SHUFFLE_BEEHIVES)) { if (ctx->GetOption(RSK_SHUFFLE_BEEHIVES)) {
// 32 total beehive locations // 32 total beehive locations
AddItemToPool(PendingJunkPool, RG_RED_RUPEE, 23); AddItemToPool(PendingJunkPool, RG_RED_RUPEE, 23);

View file

@ -781,6 +781,9 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
va_copy(args, originalArgs); va_copy(args, originalArgs);
switch (id) { switch (id) {
case VB_CRAWL:
*should = !RAND_GET_OPTION(RSK_SHUFFLE_CRAWL) || Flags_GetRandomizerInf(RAND_INF_CAN_CRAWL);
break;
case VB_ALLOW_ENTRANCE_CS_FOR_EITHER_AGE: { case VB_ALLOW_ENTRANCE_CS_FOR_EITHER_AGE: {
s32 entranceIndex = va_arg(args, s32); s32 entranceIndex = va_arg(args, s32);

View file

@ -352,6 +352,9 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_BRONZE_SCALE] = Item(RG_BRONZE_SCALE, Text{ "Bronze Scale", "Écaille de Bronze", "Bronzene Schuppe" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, LOGIC_PROGRESSIVE_WALLET, RHT_BRONZE_SCALE, RG_BRONZE_SCALE, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_BRONZE_SCALE] = Item(RG_BRONZE_SCALE, Text{ "Bronze Scale", "Écaille de Bronze", "Bronzene Schuppe" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, LOGIC_PROGRESSIVE_WALLET, RHT_BRONZE_SCALE, RG_BRONZE_SCALE, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_BRONZE_SCALE].SetCustomDrawFunc(Randomizer_DrawBronzeScale); itemTable[RG_BRONZE_SCALE].SetCustomDrawFunc(Randomizer_DrawBronzeScale);
itemTable[RG_CRAWL] = Item(RG_CRAWL, Text{ "Crawl", "Ramper", "Kriechen" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, LOGIC_PROGRESSIVE_WALLET, RHT_CRAWL, RG_CRAWL, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_CRAWL].SetCustomDrawFunc(Randomizer_DrawBronzeScale);
itemTable[RG_BOMBCHU_BAG] = Item(RG_BOMBCHU_BAG, Text{ "Bombchu Bag", "Sac de Missiles Teigneux", "Krabbelminentasche" }, ITEMTYPE_ITEM, RG_BOMBCHU_BAG, true, LOGIC_BOMBCHUS, RHT_BOMBCHU_BAG, RG_BOMBCHU_BAG, OBJECT_GI_BOMB_2, GID_BOMBCHU, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_BOMBCHU_BAG] = Item(RG_BOMBCHU_BAG, Text{ "Bombchu Bag", "Sac de Missiles Teigneux", "Krabbelminentasche" }, ITEMTYPE_ITEM, RG_BOMBCHU_BAG, true, LOGIC_BOMBCHUS, RHT_BOMBCHU_BAG, RG_BOMBCHU_BAG, OBJECT_GI_BOMB_2, GID_BOMBCHU, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_BOMBCHU_BAG].SetCustomDrawFunc(Randomizer_DrawBombchuBag); itemTable[RG_BOMBCHU_BAG].SetCustomDrawFunc(Randomizer_DrawBombchuBag);

View file

@ -10,8 +10,8 @@ void RegionTable_Init_BottomOfTheWell() {
areaTable[RR_BOTTOM_OF_THE_WELL_ENTRYWAY] = Region("Bottom of the Well Entryway", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, {}, { areaTable[RR_BOTTOM_OF_THE_WELL_ENTRYWAY] = Region("Bottom of the Well Entryway", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits //Exits
//Technically involves an fake wall, but passing it lensless is intended in vanilla and it is well telegraphed //Technically involves an fake wall, but passing it lensless is intended in vanilla and it is well telegraphed
Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla() && logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla() && logic->CanUse(RG_CRAWL) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsMQ() && logic->IsChild;}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsMQ() && logic->CanUse(RG_CRAWL);}),
Entrance(RR_KAK_WELL, []{return true;}), Entrance(RR_KAK_WELL, []{return true;}),
}); });
@ -33,12 +33,12 @@ void RegionTable_Init_BottomOfTheWell() {
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_POT, (logic->CanBreakPots() && logic->LoweredWaterInsideBotw) || logic->CanUse(RG_BOOMERANG)), LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_POT, (logic->CanBreakPots() && logic->LoweredWaterInsideBotw) || logic->CanUse(RG_BOOMERANG)),
}, { }, {
//Exits //Exits
Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, []{return logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, []{return logic->CanUse(RG_CRAWL) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}),
Entrance(RR_BOTTOM_OF_THE_WELL_BEHIND_FAKE_WALLS, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), Entrance(RR_BOTTOM_OF_THE_WELL_BEHIND_FAKE_WALLS, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}),
Entrance(RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), Entrance(RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}),
Entrance(RR_BOTTOM_OF_THE_WELL_KEESE_BEAMOS_ROOM, []{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}), Entrance(RR_BOTTOM_OF_THE_WELL_KEESE_BEAMOS_ROOM, []{return logic->CanUse(RG_CRAWL) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}),
Entrance(RR_BOTTOM_OF_THE_WELL_COFFIN_ROOM, []{return logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE);}), Entrance(RR_BOTTOM_OF_THE_WELL_COFFIN_ROOM, []{return logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE);}),
Entrance(RR_BOTTOM_OF_THE_WELL_DEAD_HAND_ROOM, []{return logic->LoweredWaterInsideBotw && logic->IsChild;}), Entrance(RR_BOTTOM_OF_THE_WELL_DEAD_HAND_ROOM, []{return logic->LoweredWaterInsideBotw && logic->CanUse(RG_CRAWL);}),
//Falling down into basement requires nothing, but falling down somewhere specific requires lens or lens trick //Falling down into basement requires nothing, but falling down somewhere specific requires lens or lens trick
//kinda questionable given several drops are blocked by rocks, but that's how it was handled before and on N64 //kinda questionable given several drops are blocked by rocks, but that's how it was handled before and on N64
Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return true;}), Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return true;}),
@ -80,7 +80,7 @@ void RegionTable_Init_BottomOfTheWell() {
LOCATION(RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_POT_1, logic->CanBreakPots() && (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH))), LOCATION(RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_POT_1, logic->CanBreakPots() && (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH))),
}, { }, {
//Exits //Exits
Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH));}), Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return logic->CanUse(RG_CRAWL) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH));}),
Entrance(RR_BOTTOM_OF_THE_WELL_LIKE_LIKE_CAGE, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), Entrance(RR_BOTTOM_OF_THE_WELL_LIKE_LIKE_CAGE, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}),
//not sure if this lens check is needed, these holes are a bit too easy to find, but it matches existing logic //not sure if this lens check is needed, these holes are a bit too easy to find, but it matches existing logic
Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}),
@ -126,7 +126,7 @@ void RegionTable_Init_BottomOfTheWell() {
}, { }, {
//Exits //Exits
//This assumes we spawned in dead hand's room, if whatever trick made this relevant instead puts us in the previous room, remove the kill Dead Hand check. //This assumes we spawned in dead hand's room, if whatever trick made this relevant instead puts us in the previous room, remove the kill Dead Hand check.
Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return logic->IsChild && logic->CanKillEnemy(RE_DEAD_HAND);}), Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return logic->CanUse(RG_CRAWL) && logic->CanKillEnemy(RE_DEAD_HAND);}),
}); });
areaTable[RR_BOTTOM_OF_THE_WELL_BASEMENT] = Region("Bottom of the Well Basement", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_BOTTOM_OF_THE_WELL_BASEMENT] = Region("Bottom of the Well Basement", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, {
@ -159,7 +159,7 @@ void RegionTable_Init_BottomOfTheWell() {
LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_BEHIND_ROCKS_GRASS_9, logic->CanCutShrubs() && logic->BlastOrSmash()), LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_BEHIND_ROCKS_GRASS_9, logic->CanCutShrubs() && logic->BlastOrSmash()),
}, { }, {
//Exits //Exits
Entrance(RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM, []{return logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), Entrance(RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM, []{return logic->CanUse(RG_CRAWL) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}),
//It's possible to abuse boulder's limited range of collision detection to detonate the flowers through the boulder with bow, but this is a glitch //It's possible to abuse boulder's limited range of collision detection to detonate the flowers through the boulder with bow, but this is a glitch
//the exact range is just past the furthest away plank in the green goo section //the exact range is just past the furthest away plank in the green goo section
Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS, []{return Here(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || (logic->CanUse(RG_STICKS) && ctx->GetTrickOption(RT_BOTW_BASEMENT));});}), Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS, []{return Here(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || (logic->CanUse(RG_STICKS) && ctx->GetTrickOption(RT_BOTW_BASEMENT));});}),
@ -206,11 +206,11 @@ void RegionTable_Init_BottomOfTheWell() {
LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BOMB_RIGHT_HEART, logic->HasExplosives()), LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BOMB_RIGHT_HEART, logic->HasExplosives()),
}, { }, {
//Exits //Exits
Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, []{return logic->IsChild;}), Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, []{return logic->CanUse(RG_CRAWL);}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_WEST_ROOM_SWITCH, []{return Here(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash();}) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_WEST_ROOM_SWITCH, []{return Here(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash();}) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM, []{return (logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE)) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM, []{return (logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE)) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_LOCKED_CAGE, []{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2) && logic->CanUseProjectile();}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_LOCKED_CAGE, []{return logic->CanUse(RG_CRAWL) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2) && logic->CanUseProjectile();}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_ROOM, []{return logic->IsChild && logic->LoweredWaterInsideBotw;}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_ROOM, []{return logic->CanUse(RG_CRAWL) && logic->LoweredWaterInsideBotw;}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, []{return logic->CanUse(RG_ZELDAS_LULLABY);}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, []{return true;}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, []{return true;}),
}); });
@ -240,7 +240,7 @@ void RegionTable_Init_BottomOfTheWell() {
EventAccess(&logic->OpenedMiddleHoleMQBotw, []{return logic->HasExplosives();}), EventAccess(&logic->OpenedMiddleHoleMQBotw, []{return logic->HasExplosives();}),
}, {}, { }, {}, {
//Exits //Exits
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->CanUse(RG_CRAWL) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}),
}); });
areaTable[RR_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_ROOM] = Region("Bottom of the Well MQ Dead Hand Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_ROOM] = Region("Bottom of the Well MQ Dead Hand Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, {
@ -254,7 +254,7 @@ void RegionTable_Init_BottomOfTheWell() {
}, { }, {
//Exits //Exits
//This assumes we spawned in dead hand's room, if whatever trick made this relevant instead puts us in the previous room, remove the kill Dead Hand check. //This assumes we spawned in dead hand's room, if whatever trick made this relevant instead puts us in the previous room, remove the kill Dead Hand check.
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->IsChild && logic->CanKillEnemy(RE_DEAD_HAND);}), Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->CanUse(RG_CRAWL) && logic->CanKillEnemy(RE_DEAD_HAND);}),
}); });
areaTable[RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE] = Region("Bottom of the Well MQ Middle", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE] = Region("Bottom of the Well MQ Middle", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, {

View file

@ -149,7 +149,7 @@ void RegionTable_Init_DekuTree() {
//Exits //Exits
Entrance(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, []{return true;}), Entrance(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, []{return true;}),
Entrance(RR_DEKU_TREE_BASEMENT_BACK_ROOM, []{return Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}) && Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->BlastOrSmash();});}), Entrance(RR_DEKU_TREE_BASEMENT_BACK_ROOM, []{return Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}) && Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->BlastOrSmash();});}),
Entrance(RR_DEKU_TREE_BASEMENT_UPPER, []{return Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}) && logic->IsChild;}), Entrance(RR_DEKU_TREE_BASEMENT_UPPER, []{return Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}) && logic->CanUse(RG_CRAWL);}),
}); });
areaTable[RR_DEKU_TREE_BASEMENT_BACK_ROOM] = Region("Deku Tree Basement Back Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_DEKU_TREE_BASEMENT_BACK_ROOM] = Region("Deku Tree Basement Back Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {
@ -167,7 +167,7 @@ void RegionTable_Init_DekuTree() {
}, {}, { }, {}, {
//Exits //Exits
Entrance(RR_DEKU_TREE_BASEMENT_LOWER, []{return true;}), Entrance(RR_DEKU_TREE_BASEMENT_LOWER, []{return true;}),
Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->IsChild;}), Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->CanUse(RG_CRAWL);}),
Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return Here(RR_DEKU_TREE_BASEMENT_UPPER, []{return logic->HasFireSourceWithTorch() || (ctx->GetTrickOption(RT_DEKU_B1_BOW_WEBS) && logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));});}), Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return Here(RR_DEKU_TREE_BASEMENT_UPPER, []{return logic->HasFireSourceWithTorch() || (ctx->GetTrickOption(RT_DEKU_B1_BOW_WEBS) && logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));});}),
}); });
@ -384,7 +384,7 @@ void RegionTable_Init_DekuTree() {
LOCATION(RC_DEKU_TREE_MQ_BASEMENT_GRAVES_GRASS_5, logic->CanCutShrubs()), LOCATION(RC_DEKU_TREE_MQ_BASEMENT_GRAVES_GRASS_5, logic->CanCutShrubs()),
}, { }, {
//Exits //Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->IsChild && Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}), Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->CanUse(RG_CRAWL) && Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return true;}), Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return true;}),
//Using a bow to get past here as adult is a bit precise on standing position but simple, doing as as child requires a side-hop with the bow out to shoot through the torch and may be trick worthy //Using a bow to get past here as adult is a bit precise on standing position but simple, doing as as child requires a side-hop with the bow out to shoot through the torch and may be trick worthy
Entrance(RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM, []{return Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}), Entrance(RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM, []{return Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}),
@ -412,7 +412,7 @@ void RegionTable_Init_DekuTree() {
LOCATION(RC_DEKU_TREE_MQ_BASEMENT_UPPER_GRASS_3, logic->CanCutShrubs()), LOCATION(RC_DEKU_TREE_MQ_BASEMENT_UPPER_GRASS_3, logic->CanCutShrubs()),
}, { }, {
//Exits //Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->IsChild;}), Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->CanUse(RG_CRAWL);}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT, []{return true;}), Entrance(RR_DEKU_TREE_MQ_BASEMENT, []{return true;}),
//If strength 0 is shuffled, add hovers or block push to the stick check //If strength 0 is shuffled, add hovers or block push to the stick check
//recoiling to skip swim is possible, but would be a trick //recoiling to skip swim is possible, but would be a trick

View file

@ -23,7 +23,7 @@ void RegionTable_Init_SpiritTemple() {
}, { }, {
//Exits //Exits
Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, []{return true;}), Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, []{return true;}),
Entrance(RR_SPIRIT_TEMPLE_CHILD, []{return logic->IsChild;}), Entrance(RR_SPIRIT_TEMPLE_CHILD, []{return logic->CanUse(RG_CRAWL);}),
Entrance(RR_SPIRIT_TEMPLE_EARLY_ADULT, []{return logic->CanUse(RG_SILVER_GAUNTLETS);}), Entrance(RR_SPIRIT_TEMPLE_EARLY_ADULT, []{return logic->CanUse(RG_SILVER_GAUNTLETS);}),
}); });
@ -43,7 +43,7 @@ void RegionTable_Init_SpiritTemple() {
LOCATION(RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2, logic->CanBreakSmallCrates()), LOCATION(RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2, logic->CanBreakSmallCrates()),
}, { }, {
//Exits //Exits
Entrance(RR_SPIRIT_TEMPLE_CHILD_CLIMB, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}), Entrance(RR_SPIRIT_TEMPLE_CHILD_CLIMB, []{return logic->CanUse(RG_CRAWL) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}),
}); });
areaTable[RR_SPIRIT_TEMPLE_CHILD_CLIMB] = Region("Child Spirit Temple Climb", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_SPIRIT_TEMPLE_CHILD_CLIMB] = Region("Child Spirit Temple Climb", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {
@ -165,7 +165,7 @@ void RegionTable_Init_SpiritTemple() {
}, { }, {
//Exits //Exits
Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, []{return true;}), Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, []{return true;}),
Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->IsChild;}), Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanUse(RG_CRAWL);}),
Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH, []{return logic->CanUse(RG_LONGSHOT) && logic->CanUse(RG_BOMBCHU_5);}), Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH, []{return logic->CanUse(RG_LONGSHOT) && logic->CanUse(RG_BOMBCHU_5);}),
}); });
@ -183,7 +183,7 @@ void RegionTable_Init_SpiritTemple() {
//Exits //Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH, []{return Here(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanKillEnemy(RE_TORCH_SLUG);});}), Entrance(RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH, []{return Here(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanKillEnemy(RE_TORCH_SLUG);});}),
Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH, []{return Here(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanKillEnemy(RE_TORCH_SLUG);});}), Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH, []{return Here(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanKillEnemy(RE_TORCH_SLUG);});}),
Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH, []{return logic->IsChild && logic->MQSpiritCrawlBoulder;}), Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH, []{return logic->CanUse(RG_CRAWL) && logic->MQSpiritCrawlBoulder;}),
}); });
areaTable[RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH] = Region("Spirit Temple MQ 1F Gibdo Room South", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { areaTable[RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH] = Region("Spirit Temple MQ 1F Gibdo Room South", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, {
@ -249,7 +249,7 @@ void RegionTable_Init_SpiritTemple() {
EventAccess(&logic->MQSpiritCrawlBoulder, []{return logic->CanUse(RG_BOMBCHU_5) || (ctx->GetTrickOption(RT_RUSTED_SWITCHES) && logic->CanUse(RG_MEGATON_HAMMER));}), EventAccess(&logic->MQSpiritCrawlBoulder, []{return logic->CanUse(RG_BOMBCHU_5) || (ctx->GetTrickOption(RT_RUSTED_SWITCHES) && logic->CanUse(RG_MEGATON_HAMMER));}),
}, {}, { }, {}, {
//Exits //Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->IsChild && logic->MQSpiritCrawlBoulder;}), Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanUse(RG_CRAWL) && logic->MQSpiritCrawlBoulder;}),
//This tracks possible child access, if adult has not entered STATUE_ROOM. Certain Child Access is checked for separately as 7 Keys //This tracks possible child access, if adult has not entered STATUE_ROOM. Certain Child Access is checked for separately as 7 Keys
Entrance(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}), Entrance(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}),
}); });

View file

@ -34,8 +34,8 @@ void RegionTable_Init_CastleGrounds() {
}, { }, {
//Exits //Exits
Entrance(RR_CASTLE_GROUNDS, []{return true;}), Entrance(RR_CASTLE_GROUNDS, []{return true;}),
Entrance(RR_HC_GARDEN, []{return logic->CanUse(RG_WEIRD_EGG) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}), Entrance(RR_HC_GARDEN, []{return logic->CanUse(RG_CRAWL) && (logic->CanUse(RG_WEIRD_EGG) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash()));}),
Entrance(RR_HC_GREAT_FAIRY_FOUNTAIN, []{return logic->BlastOrSmash();}), Entrance(RR_HC_GREAT_FAIRY_FOUNTAIN, []{return logic->CanUse(RG_CRAWL) && logic->BlastOrSmash();}),
Entrance(RR_HC_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}), Entrance(RR_HC_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}),
}); });

View file

@ -12,7 +12,7 @@ void RegionTable_Init_KokiriForest() {
EventAccess(&logic->ShowedMidoSwordAndShield, []{return logic->ShowedMidoSwordAndShield || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD));}), EventAccess(&logic->ShowedMidoSwordAndShield, []{return logic->ShowedMidoSwordAndShield || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD));}),
}, { }, {
//Locations //Locations
LOCATION(RC_KF_KOKIRI_SWORD_CHEST, logic->IsChild), LOCATION(RC_KF_KOKIRI_SWORD_CHEST, logic->CanUse(RG_CRAWL)),
LOCATION(RC_KF_GS_KNOW_IT_ALL_HOUSE, logic->IsChild && logic->CanAttack() && (/*TODO: HasNightStart ||*/ logic->CanLeaveForest() || logic->CanUse(RG_SUNS_SONG)) && logic->CanGetNightTimeGS()), LOCATION(RC_KF_GS_KNOW_IT_ALL_HOUSE, logic->IsChild && logic->CanAttack() && (/*TODO: HasNightStart ||*/ logic->CanLeaveForest() || logic->CanUse(RG_SUNS_SONG)) && logic->CanGetNightTimeGS()),
LOCATION(RC_KF_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), LOCATION(RC_KF_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()),
LOCATION(RC_KF_GS_HOUSE_OF_TWINS, logic->IsAdult && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_KF_ADULT_GS) && logic->CanUse(RG_HOVER_BOOTS))) && logic->CanGetNightTimeGS()), LOCATION(RC_KF_GS_HOUSE_OF_TWINS, logic->IsAdult && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_KF_ADULT_GS) && logic->CanUse(RG_HOVER_BOOTS))) && logic->CanGetNightTimeGS()),
@ -27,8 +27,8 @@ void RegionTable_Init_KokiriForest() {
LOCATION(RC_KF_SOUTH_GRASS_EAST_RUPEE, logic->IsChild), LOCATION(RC_KF_SOUTH_GRASS_EAST_RUPEE, logic->IsChild),
LOCATION(RC_KF_NORTH_GRASS_WEST_RUPEE, logic->IsChild), LOCATION(RC_KF_NORTH_GRASS_WEST_RUPEE, logic->IsChild),
LOCATION(RC_KF_NORTH_GRASS_EAST_RUPEE, logic->IsChild), LOCATION(RC_KF_NORTH_GRASS_EAST_RUPEE, logic->IsChild),
LOCATION(RC_KF_BOULDER_RUPEE_1, logic->IsChild), LOCATION(RC_KF_BOULDER_RUPEE_1, logic->CanUse(RG_CRAWL)),
LOCATION(RC_KF_BOULDER_RUPEE_2, logic->IsChild), LOCATION(RC_KF_BOULDER_RUPEE_2, logic->CanUse(RG_CRAWL)),
LOCATION(RC_KF_BEAN_RUPEE_1, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), LOCATION(RC_KF_BEAN_RUPEE_1, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
LOCATION(RC_KF_BEAN_RUPEE_2, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), LOCATION(RC_KF_BEAN_RUPEE_2, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
LOCATION(RC_KF_BEAN_RUPEE_3, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), LOCATION(RC_KF_BEAN_RUPEE_3, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),

View file

@ -55,7 +55,7 @@ void RegionTable_Init_LonLonRanch() {
areaTable[RR_LLR_TOWER] = Region("LLR Tower", "LLR Tower", {}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_LLR_TOWER] = Region("LLR Tower", "LLR Tower", {}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations //Locations
LOCATION(RC_LLR_FREESTANDING_POH, logic->IsChild), LOCATION(RC_LLR_FREESTANDING_POH, logic->IsChild && logic->HasItem(RG_CRAWL)),
LOCATION(RC_LLR_TOWER_LEFT_COW, logic->CanUse(RG_EPONAS_SONG)), LOCATION(RC_LLR_TOWER_LEFT_COW, logic->CanUse(RG_EPONAS_SONG)),
LOCATION(RC_LLR_TOWER_RIGHT_COW, logic->CanUse(RG_EPONAS_SONG)), LOCATION(RC_LLR_TOWER_RIGHT_COW, logic->CanUse(RG_EPONAS_SONG)),
}, { }, {

View file

@ -221,6 +221,8 @@ bool Logic::HasItem(RandomizerGet itemName) {
return CurrentUpgrade(UPG_SCALE) >= 1; return CurrentUpgrade(UPG_SCALE) >= 1;
case RG_GOLDEN_SCALE: case RG_GOLDEN_SCALE:
return CurrentUpgrade(UPG_SCALE) >= 2; return CurrentUpgrade(UPG_SCALE) >= 2;
case RG_CRAWL:
return CheckRandoInf(RAND_INF_CAN_CRAWL);
case RG_POCKET_EGG: case RG_POCKET_EGG:
return CheckRandoInf(RAND_INF_ADULT_TRADES_HAS_POCKET_EGG); return CheckRandoInf(RAND_INF_ADULT_TRADES_HAS_POCKET_EGG);
case RG_COJIRO: case RG_COJIRO:
@ -376,6 +378,8 @@ bool Logic::CanUse(RandomizerGet itemName) {
return HasItem(RG_CHILD_WALLET); // as long as you have enough rubies return HasItem(RG_CHILD_WALLET); // as long as you have enough rubies
case RG_EPONA: case RG_EPONA:
return IsAdult && CanUse(RG_EPONAS_SONG); return IsAdult && CanUse(RG_EPONAS_SONG);
case RG_CRAWL:
return IsChild;
// Bottle Items // Bottle Items
case RG_BOTTLE_WITH_BUGS: case RG_BOTTLE_WITH_BUGS:
@ -1625,6 +1629,9 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
case RG_CLAIM_CHECK: case RG_CLAIM_CHECK:
SetRandoInf(randoGet - RG_COJIRO + RAND_INF_ADULT_TRADES_HAS_COJIRO, state); SetRandoInf(randoGet - RG_COJIRO + RAND_INF_ADULT_TRADES_HAS_COJIRO, state);
break; break;
case RG_CRAWL:
SetRandoInf(RAND_INF_CAN_CRAWL, state);
break;
case RG_PROGRESSIVE_HOOKSHOT: { case RG_PROGRESSIVE_HOOKSHOT: {
uint8_t i; uint8_t i;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
@ -2388,6 +2395,11 @@ void Logic::Reset() {
SetRandoInf(RAND_INF_CAN_SWIM, true); SetRandoInf(RAND_INF_CAN_SWIM, true);
} }
// If we're not shuffling crawl, we start with it
if (ctx->GetOption(RSK_SHUFFLE_CRAWL).Is(false)) {
SetRandoInf(RAND_INF_CAN_CRAWL, true);
}
// If we're not shuffling child's wallet, we start with it // If we're not shuffling child's wallet, we start with it
if (ctx->GetOption(RSK_SHUFFLE_CHILD_WALLET).Is(false)) { if (ctx->GetOption(RSK_SHUFFLE_CHILD_WALLET).Is(false)) {
SetRandoInf(RAND_INF_HAS_WALLET, true); SetRandoInf(RAND_INF_HAS_WALLET, true);

View file

@ -247,6 +247,7 @@ void Settings::CreateOptionDescriptions() {
"\n" "\n"
"If you enter a water entrance without swim you will be respawned on land to prevent infinite death loops.\n" "If you enter a water entrance without swim you will be respawned on land to prevent infinite death loops.\n"
"If you void out in Water Temple you will immediately be kicked out to prevent a softlock."; "If you void out in Water Temple you will immediately be kicked out to prevent a softlock.";
mOptionDescriptions[RSK_SHUFFLE_CRAWL] = "Shuffles the ability to use crawlspaces into the item pool.";
mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG] = "Shuffles the Weird Egg from Malon in to the item pool. Enabling " mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG] = "Shuffles the Weird Egg from Malon in to the item pool. Enabling "
"\"Skip Child Zelda\" disables this feature.\n" "\"Skip Child Zelda\" disables this feature.\n"
"\n" "\n"

View file

@ -5165,7 +5165,7 @@ CustomMessage Randomizer::GetGoronMessage(u16 index) {
void Randomizer::CreateCustomMessages() { void Randomizer::CreateCustomMessages() {
// RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED // RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED
// with GIMESSAGE(getItemID, itemID, english, german, french). // with GIMESSAGE(getItemID, itemID, english, german, french).
const std::array<GetItemMessage, 112> getItemMessages = { { const std::array<GetItemMessage, 113> getItemMessages = { {
GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, "You found %gGreg%w!", "%gGreg%w! Du hast ihn wirklich gefunden!", GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, "You found %gGreg%w!", "%gGreg%w! Du hast ihn wirklich gefunden!",
"Félicitation! Vous avez trouvé %gGreg%w!"), "Félicitation! Vous avez trouvé %gGreg%w!"),
GIMESSAGE(RG_MASTER_SWORD, ITEM_SWORD_MASTER, "You found the %gMaster Sword%w!", GIMESSAGE(RG_MASTER_SWORD, ITEM_SWORD_MASTER, "You found the %gMaster Sword%w!",
@ -5493,6 +5493,9 @@ void Randomizer::CreateCustomMessages() {
GIMESSAGE(RG_BRONZE_SCALE, ITEM_SCALE_SILVER, "You got the %rBronze Scale%w!&The power of buoyancy is yours!", GIMESSAGE(RG_BRONZE_SCALE, ITEM_SCALE_SILVER, "You got the %rBronze Scale%w!&The power of buoyancy is yours!",
"Du hast die %rBronzene Schuppe%w erhalten!&Die Macht der Schwungkraft ist dein!", "Du hast die %rBronzene Schuppe%w erhalten!&Die Macht der Schwungkraft ist dein!",
"Vous obtenez l'%rÉcaille de Bronze%w!&Le pouvoir de la flottabilité est&à vous!"), "Vous obtenez l'%rÉcaille de Bronze%w!&Le pouvoir de la flottabilité est&à vous!"),
GIMESSAGE_NO_GERMAN(RG_CRAWL, ITEM_SCALE_SILVER,
"You got the %rAbility to Crawl%w!&The power of kneecaps is yours!",
"Vous obtenez la %rCapacité à Ramper%w!"),
GIMESSAGE(RG_FISHING_POLE, ITEM_FISHING_POLE, "You found a lost %rFishing Pole%w!&Time to hit the pond!", GIMESSAGE(RG_FISHING_POLE, ITEM_FISHING_POLE, "You found a lost %rFishing Pole%w!&Time to hit the pond!",
"Du hast eine verlorene %rAngelrute%w gefunden!&Zeit, im Teich zu angeln!", "Du hast eine verlorene %rAngelrute%w gefunden!&Zeit, im Teich zu angeln!",
"Vous obtenez une %rCanne à pêche%w&perdue!&Il est temps d'aller à %gl'étang%w!"), "Vous obtenez une %rCanne à pêche%w&perdue!&Il est temps d'aller à %gl'étang%w!"),
@ -5604,6 +5607,7 @@ extern "C" u8 Return_Item_Entry(GetItemEntry itemEntry, u8 returnItem);
std::map<RandomizerGet, RandomizerInf> randomizerGetToRandInf = { std::map<RandomizerGet, RandomizerInf> randomizerGetToRandInf = {
{ RG_FISHING_POLE, RAND_INF_FISHING_POLE_FOUND }, { RG_FISHING_POLE, RAND_INF_FISHING_POLE_FOUND },
{ RG_BRONZE_SCALE, RAND_INF_CAN_SWIM }, { RG_BRONZE_SCALE, RAND_INF_CAN_SWIM },
{ RG_CRAWL, RAND_INF_CAN_CRAWL },
{ RG_QUIVER_INF, RAND_INF_HAS_INFINITE_QUIVER }, { RG_QUIVER_INF, RAND_INF_HAS_INFINITE_QUIVER },
{ RG_BOMB_BAG_INF, RAND_INF_HAS_INFINITE_BOMB_BAG }, { RG_BOMB_BAG_INF, RAND_INF_HAS_INFINITE_BOMB_BAG },
{ RG_BULLET_BAG_INF, RAND_INF_HAS_INFINITE_BULLET_BAG }, { RG_BULLET_BAG_INF, RAND_INF_HAS_INFINITE_BULLET_BAG },

View file

@ -3956,6 +3956,7 @@ typedef enum {
RG_HINT, RG_HINT,
RG_TYCOON_WALLET, RG_TYCOON_WALLET,
RG_BRONZE_SCALE, RG_BRONZE_SCALE,
RG_CRAWL,
RG_CHILD_WALLET, RG_CHILD_WALLET,
RG_BOMBCHU_BAG, RG_BOMBCHU_BAG,
RG_QUIVER_INF, RG_QUIVER_INF,
@ -5153,6 +5154,7 @@ typedef enum {
RHT_OCARINA_C_LEFT_BUTTON, RHT_OCARINA_C_LEFT_BUTTON,
RHT_OCARINA_C_RIGHT_BUTTON, RHT_OCARINA_C_RIGHT_BUTTON,
RHT_BRONZE_SCALE, RHT_BRONZE_SCALE,
RHT_CRAWL,
RHT_FISHING_POLE, RHT_FISHING_POLE,
RHT_SKELETON_KEY, RHT_SKELETON_KEY,
RHT_EPONA, RHT_EPONA,
@ -5700,6 +5702,7 @@ typedef enum {
RSK_SHUFFLE_OCARINA, RSK_SHUFFLE_OCARINA,
RSK_SHUFFLE_OCARINA_BUTTONS, RSK_SHUFFLE_OCARINA_BUTTONS,
RSK_SHUFFLE_SWIM, RSK_SHUFFLE_SWIM,
RSK_SHUFFLE_CRAWL,
RSK_STARTING_DEKU_SHIELD, RSK_STARTING_DEKU_SHIELD,
RSK_STARTING_KOKIRI_SWORD, RSK_STARTING_KOKIRI_SWORD,
RSK_STARTING_MASTER_SWORD, RSK_STARTING_MASTER_SWORD,

View file

@ -1002,6 +1002,7 @@ typedef enum {
RAND_INF_CAUGHT_LOACH, RAND_INF_CAUGHT_LOACH,
RAND_INF_CAN_SWIM, RAND_INF_CAN_SWIM,
RAND_INF_CAN_CRAWL,
RAND_INF_HAS_WALLET, RAND_INF_HAS_WALLET,

View file

@ -256,6 +256,10 @@ extern "C" void Randomizer_InitSaveFile() {
Flags_SetRandomizerInf(RAND_INF_CAN_SWIM); Flags_SetRandomizerInf(RAND_INF_CAN_SWIM);
} }
if (Randomizer_GetSettingValue(RSK_SHUFFLE_CRAWL) == RO_GENERIC_OFF) {
Flags_SetRandomizerInf(RAND_INF_CAN_CRAWL);
}
if (Randomizer_GetSettingValue(RSK_SHUFFLE_CHILD_WALLET) == RO_GENERIC_OFF) { if (Randomizer_GetSettingValue(RSK_SHUFFLE_CHILD_WALLET) == RO_GENERIC_OFF) {
Flags_SetRandomizerInf(RAND_INF_HAS_WALLET); Flags_SetRandomizerInf(RAND_INF_HAS_WALLET);
} }

View file

@ -211,6 +211,7 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_SHUFFLE_OCARINA, "Shuffle Ocarinas", CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), mOptionDescriptions[RSK_SHUFFLE_OCARINA]); OPT_BOOL(RSK_SHUFFLE_OCARINA, "Shuffle Ocarinas", CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), mOptionDescriptions[RSK_SHUFFLE_OCARINA]);
OPT_BOOL(RSK_SHUFFLE_OCARINA_BUTTONS, "Shuffle Ocarina Buttons", CVAR_RANDOMIZER_SETTING("ShuffleOcarinaButtons"), mOptionDescriptions[RSK_SHUFFLE_OCARINA_BUTTONS]); OPT_BOOL(RSK_SHUFFLE_OCARINA_BUTTONS, "Shuffle Ocarina Buttons", CVAR_RANDOMIZER_SETTING("ShuffleOcarinaButtons"), mOptionDescriptions[RSK_SHUFFLE_OCARINA_BUTTONS]);
OPT_BOOL(RSK_SHUFFLE_SWIM, "Shuffle Swim", CVAR_RANDOMIZER_SETTING("ShuffleSwim"), mOptionDescriptions[RSK_SHUFFLE_SWIM]); OPT_BOOL(RSK_SHUFFLE_SWIM, "Shuffle Swim", CVAR_RANDOMIZER_SETTING("ShuffleSwim"), mOptionDescriptions[RSK_SHUFFLE_SWIM]);
OPT_BOOL(RSK_SHUFFLE_CRAWL, "Shuffle Crawl", CVAR_RANDOMIZER_SETTING("ShuffleCrawl"), mOptionDescriptions[RSK_SHUFFLE_CRAWL]);
OPT_BOOL(RSK_SHUFFLE_WEIRD_EGG, "Shuffle Weird Egg", CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]); OPT_BOOL(RSK_SHUFFLE_WEIRD_EGG, "Shuffle Weird Egg", CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]);
OPT_BOOL(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, "Shuffle Gerudo Membership Card", CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD]); OPT_BOOL(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, "Shuffle Gerudo Membership Card", CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD]);
OPT_U8(RSK_SHUFFLE_POTS, "Shuffle Pots", {"Off", "Dungeons", "Overworld", "All Pots"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShufflePots"), mOptionDescriptions[RSK_SHUFFLE_POTS], WidgetType::Combobox, RO_SHUFFLE_POTS_OFF); OPT_U8(RSK_SHUFFLE_POTS, "Shuffle Pots", {"Off", "Dungeons", "Overworld", "All Pots"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShufflePots"), mOptionDescriptions[RSK_SHUFFLE_POTS], WidgetType::Combobox, RO_SHUFFLE_POTS_OFF);
@ -1214,6 +1215,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_OCARINA], &mOptions[RSK_SHUFFLE_OCARINA],
&mOptions[RSK_SHUFFLE_OCARINA_BUTTONS], &mOptions[RSK_SHUFFLE_OCARINA_BUTTONS],
&mOptions[RSK_SHUFFLE_SWIM], &mOptions[RSK_SHUFFLE_SWIM],
&mOptions[RSK_SHUFFLE_CRAWL],
&mOptions[RSK_SHUFFLE_WEIRD_EGG], &mOptions[RSK_SHUFFLE_WEIRD_EGG],
&mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD], &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD],
&mOptions[RSK_SHUFFLE_FISHING_POLE], &mOptions[RSK_SHUFFLE_FISHING_POLE],
@ -1491,6 +1493,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_OCARINA], &mOptions[RSK_SHUFFLE_OCARINA],
&mOptions[RSK_SHUFFLE_OCARINA_BUTTONS], &mOptions[RSK_SHUFFLE_OCARINA_BUTTONS],
&mOptions[RSK_SHUFFLE_SWIM], &mOptions[RSK_SHUFFLE_SWIM],
&mOptions[RSK_SHUFFLE_CRAWL],
&mOptions[RSK_SHUFFLE_WEIRD_EGG], &mOptions[RSK_SHUFFLE_WEIRD_EGG],
&mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD], &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD],
&mOptions[RSK_SHUFFLE_MERCHANTS], &mOptions[RSK_SHUFFLE_MERCHANTS],

View file

@ -7629,6 +7629,10 @@ s32 Player_TryEnteringCrawlspace(Player* this, PlayState* play, u32 interactWall
s32 i; s32 i;
if (!LINK_IS_ADULT && !(this->stateFlags1 & PLAYER_STATE1_IN_WATER) && (interactWallFlags & 0x30)) { if (!LINK_IS_ADULT && !(this->stateFlags1 & PLAYER_STATE1_IN_WATER) && (interactWallFlags & 0x30)) {
if (!GameInteractor_Should(VB_CRAWL, true)) {
return false;
}
wallPoly = this->actor.wallPoly; wallPoly = this->actor.wallPoly;
CollisionPoly_GetVerticesByBgId(wallPoly, this->actor.wallBgId, &play->colCtx, wallVertices); CollisionPoly_GetVerticesByBgId(wallPoly, this->actor.wallBgId, &play->colCtx, wallVertices);