mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-06-24 18:03:13 -04:00
Fix Guard pots being breakable with hookshot in logic (#6671)
implement ItemUseAllowed
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
#include "soh/Enhancements/randomizer/3drando/random.hpp"
|
||||
#include "soh/Enhancements/randomizer/randomizer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <fstream>
|
||||
#include <spdlog/spdlog.h>
|
||||
extern "C" {
|
||||
|
||||
@@ -196,7 +196,7 @@ void RegionTable_Init_Kakariko() {
|
||||
}, {
|
||||
//Locations
|
||||
LOCATION(RC_KAK_WINDMILL_FREESTANDING_POH, logic->CanUse(RG_BOOMERANG)),
|
||||
LOCATION(RC_SONG_FROM_WINDMILL, logic->IsAdult && logic->HasItem(RG_FAIRY_OCARINA)),
|
||||
LOCATION(RC_SONG_FROM_WINDMILL, logic->IsAdult && logic->CanUse(RG_FAIRY_OCARINA)),
|
||||
}, {
|
||||
//Exits
|
||||
ENTRANCE(RR_KAKARIKO_VILLAGE, true),
|
||||
@@ -228,7 +228,7 @@ void RegionTable_Init_Kakariko() {
|
||||
|
||||
areaTable[RR_KAK_SHOOTING_GALLERY] = Region("Kak Shooting Gallery", SCENE_SHOOTING_GALLERY, {}, {
|
||||
//Locations
|
||||
LOCATION(RC_KAK_SHOOTING_GALLERY_REWARD, logic->IsAdult && logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_FAIRY_BOW)),
|
||||
LOCATION(RC_KAK_SHOOTING_GALLERY_REWARD, logic->IsAdult && logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->HasItem(RG_FAIRY_BOW)),
|
||||
LOCATION(RC_KAK_SHOOTING_GALLERY_RECTANGLE_SIGN, logic->IsAdult && logic->CanRead()),
|
||||
}, {
|
||||
//Exits
|
||||
@@ -247,7 +247,7 @@ void RegionTable_Init_Kakariko() {
|
||||
LOCATION(RC_KAK_POTION_SHOP_ITEM_8, logic->IsAdult && logic->HasItem(RG_SPEAK_HYLIAN) && GetCheckPrice() <= GetWalletCapacity()),
|
||||
}, {
|
||||
//Exits
|
||||
ENTRANCE(RR_KAKARIKO_VILLAGE, true),
|
||||
ENTRANCE(RR_KAKARIKO_VILLAGE, true),
|
||||
ENTRANCE(RR_KAK_BEHIND_POTION_SHOP, logic->IsAdult),
|
||||
});
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ void RegionTable_Init_KokiriForest() {
|
||||
areaTable[RR_KF_LINKS_HOUSE] = Region("KF Link's House", SCENE_LINKS_HOUSE, {}, {
|
||||
//Locations
|
||||
LOCATION(RC_KF_LINKS_HOUSE_COW, logic->IsAdult && logic->CanUse(RG_EPONAS_SONG) && logic->Get(LOGIC_LINKS_COW)),
|
||||
LOCATION(RC_KF_LINKS_HOUSE_POT, logic->HasItem(RG_POWER_BRACELET)), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_KF_LINKS_HOUSE_POT, logic->CanBreakPots()),
|
||||
LOCATION(RC_KF_LINKS_HOUSE_SIGN, logic->CanRead()),
|
||||
}, {
|
||||
//Exits
|
||||
@@ -229,8 +229,8 @@ void RegionTable_Init_KokiriForest() {
|
||||
|
||||
areaTable[RR_KF_HOUSE_OF_TWINS] = Region("KF House of Twins", SCENE_TWINS_HOUSE, {}, {
|
||||
//Locations
|
||||
LOCATION(RC_KF_TWINS_HOUSE_POT_1, logic->HasItem(RG_POWER_BRACELET)), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_KF_TWINS_HOUSE_POT_2, logic->HasItem(RG_POWER_BRACELET)), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_KF_TWINS_HOUSE_POT_1, logic->CanBreakPots()),
|
||||
LOCATION(RC_KF_TWINS_HOUSE_POT_2, logic->CanBreakPots()),
|
||||
}, {
|
||||
//Exits
|
||||
ENTRANCE(RR_KOKIRI_FOREST, true),
|
||||
@@ -238,8 +238,8 @@ void RegionTable_Init_KokiriForest() {
|
||||
|
||||
areaTable[RR_KF_KNOW_IT_ALL_HOUSE] = Region("KF Know It All House", SCENE_KNOW_IT_ALL_BROS_HOUSE, {}, {
|
||||
// Locations
|
||||
LOCATION(RC_KF_BROTHERS_HOUSE_POT_1, logic->HasItem(RG_POWER_BRACELET)), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_KF_BROTHERS_HOUSE_POT_2, logic->HasItem(RG_POWER_BRACELET)), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_KF_BROTHERS_HOUSE_POT_1, logic->CanBreakPots()),
|
||||
LOCATION(RC_KF_BROTHERS_HOUSE_POT_2, logic->CanBreakPots()),
|
||||
}, {
|
||||
//Exits
|
||||
ENTRANCE(RR_KOKIRI_FOREST, true),
|
||||
|
||||
@@ -123,16 +123,30 @@ void RegionTable_Init_LakeHylia() {
|
||||
|
||||
areaTable[RR_LH_LAB] = Region("LH Lab", SCENE_LAKESIDE_LABORATORY, {}, {
|
||||
//Locations
|
||||
LOCATION(RC_LH_LAB_DIVE, (logic->HasItem(RG_GOLDEN_SCALE) || (ctx->GetTrickOption(RT_LH_LAB_DIVING) && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->HasItem(RG_BRONZE_SCALE))) && logic->HasItem(RG_SPEAK_HYLIAN)),
|
||||
LOCATION(RC_LH_LAB_DIVE, logic->HasItem(RG_GOLDEN_SCALE) && logic->HasItem(RG_SPEAK_HYLIAN)),
|
||||
LOCATION(RC_LH_TRADE_FROG, logic->IsAdult && logic->CanUse(RG_EYEBALL_FROG)),
|
||||
LOCATION(RC_LH_GS_LAB_CRATE, logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->CanBreakCrates()),
|
||||
LOCATION(RC_LH_LAB_FRONT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)),
|
||||
LOCATION(RC_LH_LAB_LEFT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)),
|
||||
LOCATION(RC_LH_LAB_RIGHT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)),
|
||||
LOCATION(RC_LH_LAB_CRATE, logic->CanUse(RG_IRON_BOOTS) && logic->CanBreakCrates()),
|
||||
LOCATION(RC_LH_LAB_FRONT_RUPEE, logic->HasItem(RG_GOLDEN_SCALE)),
|
||||
LOCATION(RC_LH_LAB_LEFT_RUPEE, logic->HasItem(RG_GOLDEN_SCALE)),
|
||||
LOCATION(RC_LH_LAB_RIGHT_RUPEE, logic->HasItem(RG_GOLDEN_SCALE)),
|
||||
}, {
|
||||
//Exits
|
||||
ENTRANCE(RR_LAKE_HYLIA, true),
|
||||
ENTRANCE(RR_LAKE_HYLIA, true),
|
||||
ENTRANCE(RR_LH_LAB_UNDERWATER, logic->CanUse(RG_IRON_BOOTS)),
|
||||
});
|
||||
|
||||
//Assumes checking logic->CanUse(RG_IRON_BOOTS) on access
|
||||
areaTable[RR_LH_LAB_UNDERWATER] = Region("LH Lab Underwater", SCENE_LAKESIDE_LABORATORY, {}, {
|
||||
//Locations
|
||||
//Assumes RR_LH_LAB access
|
||||
LOCATION(RC_LH_LAB_DIVE, (ctx->GetTrickOption(RT_LH_LAB_DIVING) && logic->CanUse(RG_HOOKSHOT) && logic->HasItem(RG_BRONZE_SCALE)) && logic->HasItem(RG_SPEAK_HYLIAN)),
|
||||
LOCATION(RC_LH_GS_LAB_CRATE, logic->CanUse(RG_HOOKSHOT) && logic->CanBreakCrates()),
|
||||
LOCATION(RC_LH_LAB_FRONT_RUPEE, true),
|
||||
LOCATION(RC_LH_LAB_LEFT_RUPEE, true),
|
||||
LOCATION(RC_LH_LAB_RIGHT_RUPEE, true),
|
||||
LOCATION(RC_LH_LAB_CRATE, logic->CanBreakCrates()),
|
||||
}, {
|
||||
//Exits
|
||||
ENTRANCE(RR_LH_LAB, logic->HasItem(RG_BRONZE_SCALE)),
|
||||
});
|
||||
|
||||
// TODO: should some of these helpers be done via events instead?
|
||||
|
||||
@@ -39,9 +39,9 @@ void RegionTable_Init_LonLonRanch() {
|
||||
areaTable[RR_LLR_TALONS_HOUSE] = Region("LLR Talons House", SCENE_LON_LON_BUILDINGS, {}, {
|
||||
//Locations
|
||||
LOCATION(RC_LLR_TALONS_CHICKENS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->IsChild && logic->AtDay && logic->HasItem(RG_ZELDAS_LETTER) && logic->HasItem(RG_POWER_BRACELET)),
|
||||
LOCATION(RC_LLR_TALONS_HOUSE_POT_1, logic->HasItem(RG_POWER_BRACELET) || logic->CanUseSword()), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_LLR_TALONS_HOUSE_POT_2, logic->HasItem(RG_POWER_BRACELET) || logic->CanUseSword()), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_LLR_TALONS_HOUSE_POT_3, logic->HasItem(RG_POWER_BRACELET) || logic->CanUseSword()), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_LLR_TALONS_HOUSE_POT_1, logic->CanBreakPots()),
|
||||
LOCATION(RC_LLR_TALONS_HOUSE_POT_2, logic->CanBreakPots()),
|
||||
LOCATION(RC_LLR_TALONS_HOUSE_POT_3, logic->CanBreakPots()),
|
||||
}, {
|
||||
//Exits
|
||||
ENTRANCE(RR_LON_LON_RANCH, true),
|
||||
|
||||
@@ -15,18 +15,18 @@ void RegionTable_Init_Market() {
|
||||
areaTable[RR_THE_MARKET] = Region("Market", SCENE_MARKET_DAY, {}, {
|
||||
//Locations
|
||||
//RANDOTODO add item avalibility to regions to remove need to hardcode logic in limited item use situations
|
||||
LOCATION(RC_MARKET_GRASS_1, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))),
|
||||
LOCATION(RC_MARKET_GRASS_2, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))),
|
||||
LOCATION(RC_MARKET_GRASS_3, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))),
|
||||
LOCATION(RC_MARKET_GRASS_4, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))),
|
||||
LOCATION(RC_MARKET_GRASS_5, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))),
|
||||
LOCATION(RC_MARKET_GRASS_6, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))),
|
||||
LOCATION(RC_MARKET_GRASS_7, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))),
|
||||
LOCATION(RC_MARKET_GRASS_8, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))),
|
||||
LOCATION(RC_MK_NEAR_BAZAAR_CRATE_1, logic->IsChild /*&& logic->CanRoll()*/),
|
||||
LOCATION(RC_MK_NEAR_BAZAAR_CRATE_2, logic->IsChild /*&& logic->CanRoll()*/),
|
||||
LOCATION(RC_MK_SHOOTING_GALLERY_CRATE_1, logic->IsChild /*&& logic->CanRoll()*/),
|
||||
LOCATION(RC_MK_SHOOTING_GALLERY_CRATE_2, logic->IsChild /*&& logic->CanRoll()*/),
|
||||
LOCATION(RC_MARKET_GRASS_1, logic->IsChild && logic->CanCutShrubs()),
|
||||
LOCATION(RC_MARKET_GRASS_2, logic->IsChild && logic->CanCutShrubs()),
|
||||
LOCATION(RC_MARKET_GRASS_3, logic->IsChild && logic->CanCutShrubs()),
|
||||
LOCATION(RC_MARKET_GRASS_4, logic->IsChild && logic->CanCutShrubs()),
|
||||
LOCATION(RC_MARKET_GRASS_5, logic->IsChild && logic->CanCutShrubs()),
|
||||
LOCATION(RC_MARKET_GRASS_6, logic->IsChild && logic->CanCutShrubs()),
|
||||
LOCATION(RC_MARKET_GRASS_7, logic->IsChild && logic->CanCutShrubs()),
|
||||
LOCATION(RC_MARKET_GRASS_8, logic->IsChild && logic->CanCutShrubs()),
|
||||
LOCATION(RC_MK_NEAR_BAZAAR_CRATE_1, logic->IsChild && logic->CanBreakCrates()),
|
||||
LOCATION(RC_MK_NEAR_BAZAAR_CRATE_2, logic->IsChild && logic->CanBreakCrates()),
|
||||
LOCATION(RC_MK_SHOOTING_GALLERY_CRATE_1, logic->IsChild && logic->CanBreakCrates()),
|
||||
LOCATION(RC_MK_SHOOTING_GALLERY_CRATE_2, logic->IsChild && logic->CanBreakCrates()),
|
||||
LOCATION(RC_MARKET_TREE, logic->IsChild && logic->CanBonkTrees()),
|
||||
LOCATION(RC_MKT_WONDER_DAY_1, logic->IsChild && logic->AtDay),
|
||||
LOCATION(RC_MKT_WONDER_DAY_2, logic->IsChild && logic->AtDay),
|
||||
@@ -247,9 +247,9 @@ void RegionTable_Init_Market() {
|
||||
|
||||
areaTable[RR_MARKET_MAN_IN_GREEN_HOUSE] = Region("Market Man in Green House", SCENE_BACK_ALLEY_HOUSE, {}, {
|
||||
// Locations
|
||||
LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_1, logic->HasItem(RG_POWER_BRACELET)), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_2, logic->HasItem(RG_POWER_BRACELET)), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_3, logic->HasItem(RG_POWER_BRACELET)), // TODO: CanBreakPots() restricted
|
||||
LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_1, logic->CanBreakPots()),
|
||||
LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_2, logic->CanBreakPots()),
|
||||
LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_3, logic->CanBreakPots()),
|
||||
}, {
|
||||
//Exits
|
||||
ENTRANCE(RR_MARKET_BACK_ALLEY, true),
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "soh/resource/type/scenecommand/SetTransitionActorList.h"
|
||||
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
|
||||
#include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
|
||||
#include "location_access.h"
|
||||
|
||||
namespace Rando {
|
||||
|
||||
@@ -299,12 +300,219 @@ bool Logic::HasItem(RandomizerGet itemName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* based on sRestrictionFlags in z_parameter.c */
|
||||
bool Logic::ItemUseAllowed(RandomizerGet itemName) {
|
||||
switch (itemName) {
|
||||
case RG_KOKIRI_SWORD:
|
||||
case RG_MASTER_SWORD:
|
||||
case RG_GIANTS_KNIFE:
|
||||
case RG_BIGGORON_SWORD:
|
||||
return BAllowed();
|
||||
case RG_DEKU_SHIELD:
|
||||
case RG_HYLIAN_SHIELD:
|
||||
case RG_MIRROR_SHIELD:
|
||||
case RG_GORON_TUNIC:
|
||||
case RG_ZORA_TUNIC:
|
||||
case RG_IRON_BOOTS:
|
||||
case RG_HOVER_BOOTS:
|
||||
case RG_MAGIC_SINGLE:
|
||||
case RG_SILVER_GAUNTLETS:
|
||||
case RG_GOLDEN_GAUNTLETS:
|
||||
case RG_ZELDAS_LULLABY:
|
||||
case RG_EPONAS_SONG:
|
||||
case RG_PRELUDE_OF_LIGHT:
|
||||
case RG_SARIAS_SONG:
|
||||
case RG_SONG_OF_TIME:
|
||||
case RG_BOLERO_OF_FIRE:
|
||||
case RG_REQUIEM_OF_SPIRIT:
|
||||
case RG_SONG_OF_STORMS:
|
||||
case RG_MINUET_OF_FOREST:
|
||||
case RG_SERENADE_OF_WATER:
|
||||
case RG_NOCTURNE_OF_SHADOW:
|
||||
case RG_CRAWL:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// hacky fix for underwater sections TODO this properly with a flag in regions
|
||||
if (CurrentRegionKey == RR_LH_LAB_UNDERWATER) {
|
||||
return itemName == RG_HOOKSHOT || itemName == RG_LONGSHOT;
|
||||
}
|
||||
|
||||
switch (RegionTable(CurrentRegionKey)->scene) {
|
||||
case SCENE_DEKU_TREE:
|
||||
case SCENE_DODONGOS_CAVERN:
|
||||
case SCENE_JABU_JABU:
|
||||
case SCENE_FOREST_TEMPLE:
|
||||
case SCENE_FIRE_TEMPLE:
|
||||
case SCENE_WATER_TEMPLE:
|
||||
case SCENE_SPIRIT_TEMPLE:
|
||||
case SCENE_SHADOW_TEMPLE:
|
||||
case SCENE_BOTTOM_OF_THE_WELL:
|
||||
case SCENE_ICE_CAVERN:
|
||||
case SCENE_ID_MAX:
|
||||
return true;
|
||||
case SCENE_HYRULE_FIELD:
|
||||
case SCENE_GANONS_TOWER:
|
||||
case SCENE_GERUDO_TRAINING_GROUND:
|
||||
case SCENE_THIEVES_HIDEOUT:
|
||||
case SCENE_INSIDE_GANONS_CASTLE:
|
||||
case SCENE_GREAT_FAIRYS_FOUNTAIN_MAGIC:
|
||||
case SCENE_FAIRYS_FOUNTAIN:
|
||||
case SCENE_GREAT_FAIRYS_FOUNTAIN_SPELLS:
|
||||
case SCENE_GROTTOS:
|
||||
case SCENE_GRAVE_WITH_FAIRYS_FOUNTAIN:
|
||||
case SCENE_REDEAD_GRAVE:
|
||||
case SCENE_ROYAL_FAMILYS_TOMB:
|
||||
case SCENE_KAKARIKO_VILLAGE:
|
||||
case SCENE_GRAVEYARD:
|
||||
case SCENE_ZORAS_RIVER:
|
||||
case SCENE_KOKIRI_FOREST:
|
||||
case SCENE_SACRED_FOREST_MEADOW:
|
||||
case SCENE_LAKE_HYLIA:
|
||||
case SCENE_ZORAS_DOMAIN:
|
||||
case SCENE_ZORAS_FOUNTAIN:
|
||||
case SCENE_GERUDO_VALLEY:
|
||||
case SCENE_LOST_WOODS:
|
||||
case SCENE_DESERT_COLOSSUS:
|
||||
case SCENE_GERUDOS_FORTRESS:
|
||||
case SCENE_HAUNTED_WASTELAND:
|
||||
case SCENE_HYRULE_CASTLE:
|
||||
case SCENE_DEATH_MOUNTAIN_TRAIL:
|
||||
case SCENE_DEATH_MOUNTAIN_CRATER:
|
||||
case SCENE_GORON_CITY:
|
||||
case SCENE_LON_LON_RANCH:
|
||||
case SCENE_OUTSIDE_GANONS_CASTLE:
|
||||
return !(itemName == RG_FARORES_WIND);
|
||||
case SCENE_GANONS_TOWER_COLLAPSE_INTERIOR:
|
||||
case SCENE_INSIDE_GANONS_CASTLE_COLLAPSE:
|
||||
case SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR:
|
||||
return !(itemName == RG_FARORES_WIND || itemName == RG_FAIRY_OCARINA || itemName == RG_OCARINA_OF_TIME);
|
||||
case SCENE_CASTLE_COURTYARD_ZELDA:
|
||||
return !(StaticData::restrictSpells.contains(itemName) || itemName == RG_FAIRY_OCARINA ||
|
||||
itemName == RG_OCARINA_OF_TIME);
|
||||
case SCENE_DEKU_TREE_BOSS:
|
||||
case SCENE_DODONGOS_CAVERN_BOSS:
|
||||
case SCENE_JABU_JABU_BOSS:
|
||||
case SCENE_FOREST_TEMPLE_BOSS:
|
||||
case SCENE_FIRE_TEMPLE_BOSS:
|
||||
case SCENE_WATER_TEMPLE_BOSS:
|
||||
case SCENE_SPIRIT_TEMPLE_BOSS:
|
||||
case SCENE_SHADOW_TEMPLE_BOSS:
|
||||
case SCENE_GANONDORF_BOSS:
|
||||
case SCENE_GANON_BOSS:
|
||||
return !(StaticData::restrictTrade.contains(itemName) || itemName == RG_FARORES_WIND ||
|
||||
itemName == RG_FAIRY_OCARINA || itemName == RG_OCARINA_OF_TIME);
|
||||
case SCENE_WINDMILL_AND_DAMPES_GRAVE:
|
||||
return !(StaticData::restrictSpells.contains(itemName));
|
||||
case SCENE_MARKET_GUARD_HOUSE:
|
||||
return !(StaticData::restrictSpells.contains(itemName) || itemName == RG_HOOKSHOT ||
|
||||
itemName == RG_LONGSHOT);
|
||||
case SCENE_MARKET_ENTRANCE_DAY: // test
|
||||
case SCENE_MARKET_ENTRANCE_NIGHT:
|
||||
case SCENE_MARKET_ENTRANCE_RUINS:
|
||||
case SCENE_BACK_ALLEY_DAY:
|
||||
case SCENE_BACK_ALLEY_NIGHT:
|
||||
case SCENE_MARKET_DAY:
|
||||
case SCENE_MARKET_NIGHT:
|
||||
case SCENE_MARKET_RUINS:
|
||||
case SCENE_TEMPLE_OF_TIME_EXTERIOR_DAY:
|
||||
case SCENE_TEMPLE_OF_TIME_EXTERIOR_NIGHT:
|
||||
case SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS:
|
||||
case SCENE_KNOW_IT_ALL_BROS_HOUSE:
|
||||
case SCENE_TWINS_HOUSE:
|
||||
case SCENE_MIDOS_HOUSE:
|
||||
case SCENE_SARIAS_HOUSE:
|
||||
case SCENE_KAKARIKO_CENTER_GUEST_HOUSE:
|
||||
case SCENE_BACK_ALLEY_HOUSE:
|
||||
case SCENE_BAZAAR:
|
||||
case SCENE_KOKIRI_SHOP:
|
||||
case SCENE_GORON_SHOP:
|
||||
case SCENE_ZORA_SHOP:
|
||||
case SCENE_POTION_SHOP_KAKARIKO:
|
||||
case SCENE_BOMBCHU_SHOP:
|
||||
case SCENE_HAPPY_MASK_SHOP:
|
||||
case SCENE_LINKS_HOUSE:
|
||||
case SCENE_DOG_LADY_HOUSE:
|
||||
case SCENE_STABLE:
|
||||
case SCENE_IMPAS_HOUSE:
|
||||
case SCENE_LAKESIDE_LABORATORY:
|
||||
case SCENE_CARPENTERS_TENT:
|
||||
case SCENE_GRAVEKEEPERS_HUT:
|
||||
case SCENE_TEMPLE_OF_TIME:
|
||||
case SCENE_LON_LON_BUILDINGS:
|
||||
case SCENE_HOUSE_OF_SKULLTULA:
|
||||
return StaticData::allowBottleMaskTrade.contains(itemName) || itemName == RG_FAIRY_OCARINA ||
|
||||
itemName == RG_OCARINA_OF_TIME;
|
||||
case SCENE_TREASURE_BOX_SHOP:
|
||||
return StaticData::allowBottleMaskTrade.contains(itemName) || itemName == RG_LENS_OF_TRUTH;
|
||||
case SCENE_POTION_SHOP_GRANNY:
|
||||
return StaticData::allowBottleMaskTrade.contains(itemName);
|
||||
case SCENE_SHOOTING_GALLERY:
|
||||
case SCENE_CASTLE_COURTYARD_GUARDS_DAY:
|
||||
case SCENE_CASTLE_COURTYARD_GUARDS_NIGHT:
|
||||
case SCENE_BOMBCHU_BOWLING_ALLEY:
|
||||
return StaticData::allowMasks.contains(itemName);
|
||||
case SCENE_FISHING_POND:
|
||||
return itemName == RG_FISHING_POLE;
|
||||
default:
|
||||
SPDLOG_INFO("ItemUseAllowed reached `default` with item {} in Scene {}.", static_cast<uint32_t>(itemName),
|
||||
static_cast<uint32_t>(RegionTable(CurrentRegionKey)->scene));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Logic::BAllowed() {
|
||||
// hacky fix for underwater sections TODO this properly with a flag in regions
|
||||
if (CurrentRegionKey == RR_LH_LAB_UNDERWATER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (RegionTable(CurrentRegionKey)->scene) {
|
||||
case SCENE_TREASURE_BOX_SHOP:
|
||||
case SCENE_KNOW_IT_ALL_BROS_HOUSE:
|
||||
case SCENE_TWINS_HOUSE:
|
||||
case SCENE_MIDOS_HOUSE:
|
||||
case SCENE_SARIAS_HOUSE:
|
||||
case SCENE_KAKARIKO_CENTER_GUEST_HOUSE:
|
||||
case SCENE_BACK_ALLEY_HOUSE:
|
||||
case SCENE_BAZAAR:
|
||||
case SCENE_KOKIRI_SHOP:
|
||||
case SCENE_GORON_SHOP:
|
||||
case SCENE_ZORA_SHOP:
|
||||
case SCENE_POTION_SHOP_KAKARIKO:
|
||||
case SCENE_BOMBCHU_SHOP:
|
||||
case SCENE_HAPPY_MASK_SHOP:
|
||||
case SCENE_LINKS_HOUSE:
|
||||
case SCENE_DOG_LADY_HOUSE:
|
||||
case SCENE_STABLE:
|
||||
case SCENE_IMPAS_HOUSE:
|
||||
case SCENE_LAKESIDE_LABORATORY:
|
||||
case SCENE_CARPENTERS_TENT:
|
||||
case SCENE_GRAVEKEEPERS_HUT:
|
||||
case SCENE_SHOOTING_GALLERY:
|
||||
case SCENE_BOMBCHU_BOWLING_ALLEY:
|
||||
case SCENE_POTION_SHOP_GRANNY:
|
||||
case SCENE_CASTLE_COURTYARD_GUARDS_DAY:
|
||||
case SCENE_CASTLE_COURTYARD_GUARDS_NIGHT:
|
||||
case SCENE_FISHING_POND:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Can the passed in item be used?
|
||||
// RANDOTODO catch magic items explicitly and add an assert on miss.
|
||||
bool Logic::CanUse(RandomizerGet itemName) {
|
||||
if (!HasItem(itemName))
|
||||
return false;
|
||||
|
||||
if (!ItemUseAllowed(itemName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (itemName) {
|
||||
// Magic items
|
||||
case RG_MAGIC_SINGLE:
|
||||
@@ -392,28 +600,28 @@ bool Logic::CanUse(RandomizerGet itemName) {
|
||||
case RG_ZELDAS_LULLABY:
|
||||
case RG_EPONAS_SONG:
|
||||
case RG_PRELUDE_OF_LIGHT:
|
||||
return HasItem(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_C_LEFT_BUTTON) &&
|
||||
return CanUse(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_C_LEFT_BUTTON) &&
|
||||
HasItem(RG_OCARINA_C_RIGHT_BUTTON) && HasItem(RG_OCARINA_C_UP_BUTTON);
|
||||
case RG_SARIAS_SONG:
|
||||
return HasItem(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_C_LEFT_BUTTON) &&
|
||||
return CanUse(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_C_LEFT_BUTTON) &&
|
||||
HasItem(RG_OCARINA_C_RIGHT_BUTTON) && HasItem(RG_OCARINA_C_DOWN_BUTTON);
|
||||
case RG_SUNS_SONG:
|
||||
return HasItem(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_C_RIGHT_BUTTON) && HasItem(RG_OCARINA_C_UP_BUTTON) &&
|
||||
return CanUse(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_C_RIGHT_BUTTON) && HasItem(RG_OCARINA_C_UP_BUTTON) &&
|
||||
HasItem(RG_OCARINA_C_DOWN_BUTTON);
|
||||
case RG_SONG_OF_TIME:
|
||||
case RG_BOLERO_OF_FIRE:
|
||||
case RG_REQUIEM_OF_SPIRIT:
|
||||
return HasItem(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_A_BUTTON) && HasItem(RG_OCARINA_C_RIGHT_BUTTON) &&
|
||||
return CanUse(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_A_BUTTON) && HasItem(RG_OCARINA_C_RIGHT_BUTTON) &&
|
||||
HasItem(RG_OCARINA_C_DOWN_BUTTON);
|
||||
case RG_SONG_OF_STORMS:
|
||||
return HasItem(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_A_BUTTON) && HasItem(RG_OCARINA_C_UP_BUTTON) &&
|
||||
HasItem(RG_OCARINA_C_DOWN_BUTTON);
|
||||
case RG_MINUET_OF_FOREST:
|
||||
return HasItem(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_A_BUTTON) && HasItem(RG_OCARINA_C_LEFT_BUTTON) &&
|
||||
return CanUse(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_A_BUTTON) && HasItem(RG_OCARINA_C_LEFT_BUTTON) &&
|
||||
HasItem(RG_OCARINA_C_RIGHT_BUTTON) && HasItem(RG_OCARINA_C_UP_BUTTON);
|
||||
case RG_SERENADE_OF_WATER:
|
||||
case RG_NOCTURNE_OF_SHADOW:
|
||||
return HasItem(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_A_BUTTON) && HasItem(RG_OCARINA_C_LEFT_BUTTON) &&
|
||||
return CanUse(RG_FAIRY_OCARINA) && HasItem(RG_OCARINA_A_BUTTON) && HasItem(RG_OCARINA_C_LEFT_BUTTON) &&
|
||||
HasItem(RG_OCARINA_C_RIGHT_BUTTON) && HasItem(RG_OCARINA_C_DOWN_BUTTON);
|
||||
|
||||
// Misc. Items
|
||||
@@ -432,6 +640,10 @@ bool Logic::CanUse(RandomizerGet itemName) {
|
||||
case RG_BOTTLE_WITH_FAIRY:
|
||||
return Get(LOGIC_FAIRY_ACCESS);
|
||||
|
||||
case RG_FAIRY_OCARINA:
|
||||
case RG_OCARINA_OF_TIME:
|
||||
return true;
|
||||
|
||||
default:
|
||||
SPDLOG_INFO("CanUse reached `default` for {}. using HasItem is a minor Optimisation.",
|
||||
static_cast<uint32_t>(itemName));
|
||||
@@ -1730,6 +1942,53 @@ std::map<uint32_t, uint32_t> BottleRandomizerGetToItemID = {
|
||||
uint32_t HookshotLookup[3] = { ITEM_NONE, ITEM_HOOKSHOT, ITEM_LONGSHOT };
|
||||
uint32_t OcarinaLookup[3] = { ITEM_NONE, ITEM_OCARINA_FAIRY, ITEM_OCARINA_TIME };
|
||||
|
||||
std::set<RandomizerGet> StaticData::restrictFW = { RG_FARORES_WIND };
|
||||
|
||||
std::set<RandomizerGet> StaticData::restrictSpells = { RG_FARORES_WIND, RG_DINS_FIRE, RG_NAYRUS_LOVE };
|
||||
|
||||
std::set<RandomizerGet> StaticData::restrictTrade = {
|
||||
RG_POCKET_EGG, RG_COJIRO, RG_ODD_MUSHROOM, RG_ODD_POTION, RG_POACHERS_SAW,
|
||||
RG_BROKEN_SWORD, RG_PRESCRIPTION, RG_EYEBALL_FROG, RG_EYEDROPS, RG_CLAIM_CHECK,
|
||||
};
|
||||
|
||||
std::set<RandomizerGet> StaticData::allowMasks = {
|
||||
RG_KEATON_MASK, RG_SKULL_MASK, RG_SPOOKY_MASK, RG_BUNNY_HOOD, RG_GORON_MASK,
|
||||
RG_ZORA_MASK, RG_GERUDO_MASK, RG_MASK_OF_TRUTH, RG_WEIRD_EGG, RG_ZELDAS_LETTER,
|
||||
};
|
||||
|
||||
std::set<RandomizerGet> StaticData::allowBottleMaskTrade = { RG_KEATON_MASK,
|
||||
RG_SKULL_MASK,
|
||||
RG_SPOOKY_MASK,
|
||||
RG_BUNNY_HOOD,
|
||||
RG_GORON_MASK,
|
||||
RG_ZORA_MASK,
|
||||
RG_GERUDO_MASK,
|
||||
RG_MASK_OF_TRUTH,
|
||||
RG_WEIRD_EGG,
|
||||
RG_ZELDAS_LETTER,
|
||||
RG_POCKET_EGG,
|
||||
RG_COJIRO,
|
||||
RG_ODD_MUSHROOM,
|
||||
RG_ODD_POTION,
|
||||
RG_POACHERS_SAW,
|
||||
RG_BROKEN_SWORD,
|
||||
RG_PRESCRIPTION,
|
||||
RG_EYEBALL_FROG,
|
||||
RG_EYEDROPS,
|
||||
RG_CLAIM_CHECK,
|
||||
RG_EMPTY_BOTTLE,
|
||||
RG_BOTTLE_WITH_MILK,
|
||||
RG_BOTTLE_WITH_RED_POTION,
|
||||
RG_BOTTLE_WITH_GREEN_POTION,
|
||||
RG_BOTTLE_WITH_BLUE_POTION,
|
||||
RG_BOTTLE_WITH_FAIRY,
|
||||
RG_BOTTLE_WITH_FISH,
|
||||
RG_BOTTLE_WITH_BLUE_FIRE,
|
||||
RG_BOTTLE_WITH_BUGS,
|
||||
RG_BOTTLE_WITH_POE,
|
||||
RG_RUTOS_LETTER,
|
||||
RG_BOTTLE_WITH_BIG_POE };
|
||||
|
||||
void Logic::ApplyItemEffect(Item& item, bool state) {
|
||||
auto randoGet = item.GetRandomizerGet();
|
||||
if (item.GetGIEntry()->objectId == OBJECT_GI_STICK) {
|
||||
|
||||
@@ -43,6 +43,8 @@ class Logic {
|
||||
bool CanUse(RandomizerGet itemName);
|
||||
bool HasProjectile(HasProjectileAge age);
|
||||
bool HasItem(RandomizerGet itemName);
|
||||
bool ItemUseAllowed(RandomizerGet itemName);
|
||||
bool BAllowed();
|
||||
bool HasBossSoul(RandomizerGet itemName);
|
||||
bool CanOpenOverworldDoor(RandomizerGet itemName);
|
||||
bool SmallKeys(s16 scene, uint8_t requiredAmount);
|
||||
|
||||
@@ -70,6 +70,7 @@ RANDO_ENUM_ITEM(RR_LH_FROM_WATER_TEMPLE)
|
||||
RANDO_ENUM_ITEM(RR_LH_FISHING_ISLAND)
|
||||
RANDO_ENUM_ITEM(RR_LH_OWL_FLIGHT)
|
||||
RANDO_ENUM_ITEM(RR_LH_LAB)
|
||||
RANDO_ENUM_ITEM(RR_LH_LAB_UNDERWATER)
|
||||
RANDO_ENUM_ITEM(RR_LH_FISHING_POND)
|
||||
RANDO_ENUM_ITEM(RR_LH_GROTTO)
|
||||
RANDO_ENUM_ITEM(RR_GERUDO_VALLEY)
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include "randomizerTypes.h"
|
||||
#include "item.h"
|
||||
#include "location.h"
|
||||
|
||||
namespace Rando {
|
||||
|
||||
/**
|
||||
* @brief Singleton for storing and accessing static Randomizer-related data
|
||||
*
|
||||
@@ -93,6 +95,12 @@ class StaticData {
|
||||
static std::vector<RandomizerGet> normalBottles;
|
||||
static std::vector<RandomizerGet> beanSouls;
|
||||
static std::vector<RandomizerGet> overworldKeys;
|
||||
static std::unordered_map<SceneID, std::set<RandomizerGet>> itemRestrictions;
|
||||
static std::set<RandomizerGet> restrictFW;
|
||||
static std::set<RandomizerGet> restrictSpells;
|
||||
static std::set<RandomizerGet> restrictTrade;
|
||||
static std::set<RandomizerGet> allowMasks;
|
||||
static std::set<RandomizerGet> allowBottleMaskTrade;
|
||||
|
||||
StaticData();
|
||||
~StaticData();
|
||||
|
||||
Reference in New Issue
Block a user