mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-04-28 13:17:58 +03:00
Merge 2635476919
into fbbfc07ff1
This commit is contained in:
commit
ef5cd7b424
7 changed files with 1230 additions and 329 deletions
|
@ -210,12 +210,201 @@ bool Here(const RandomizerRegion region, ConditionFn condition) {
|
||||||
return areaTable[region].Here(condition);
|
return areaTable[region].Here(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) {
|
/*
|
||||||
return areaTable[region].MQSpiritShared(condition, false, anyAge);
|
* This logic covers checks that exist in the shared areas of Spirit
|
||||||
|
* This code will fail if any glitch allows Adult to go in the Child spirit door first or vice versa as it relies on
|
||||||
|
specific ages
|
||||||
|
|
||||||
|
* In order to pass a check, we must either determine that Access is certain,
|
||||||
|
or that it is always possible to get a check somehow.
|
||||||
|
|
||||||
|
* But first I have to talk about parallel universes.
|
||||||
|
|
||||||
|
* In the first universe, the player enters spirit as child, and spends as many keys as they can to lock adult out
|
||||||
|
* In the second, they enter as adult and spend as many keys as they can to lock child out.
|
||||||
|
|
||||||
|
* Additionally, if it is possible to enter spirit in reverse, there are 2 more universes:
|
||||||
|
* In the third universe, adult enters in reverse, and wastes all the keys so noone can enter through the front
|
||||||
|
* In the forth, child manages to do the same, and lock people out of the front
|
||||||
|
* All access from the boss door in shared areas is Certain
|
||||||
|
|
||||||
|
* While other universes exist, such as both ages entering in reverse or
|
||||||
|
child using their key, getting stuck, then coming back to do the dungeon as adult, these
|
||||||
|
are all sub-possibilities of these 4 universes
|
||||||
|
|
||||||
|
* As we do not know which universe we are in until the player chooses one in-game,
|
||||||
|
we must be able to collect the check in both universes
|
||||||
|
|
||||||
|
* When an Age can no longer be kept out by conflicting universes, that age is said to have Certain Access to a
|
||||||
|
region
|
||||||
|
* If both ages have access to a region with a certain number of keys, but there is no Certain Access,
|
||||||
|
* then a check is only in logic if all possible universes can collect the check independently
|
||||||
|
|
||||||
|
* The universes converge when the player has all the keys, giving both ages Certain Access everywhere.
|
||||||
|
|
||||||
|
* We must check for these universes manually as we allow technical access with minimum keys for
|
||||||
|
* technical reasons as otherwise the logic code will never run
|
||||||
|
|
||||||
|
* The first and 3rd column list how many keys are needed for each age to have Certain Access
|
||||||
|
* the second column is child keys in case there's Child reverse access, due to an edge case in MQ spirit logic
|
||||||
|
* where the broken wall room can be reached with 6 keys if you can hit switches and have reverse Child access
|
||||||
|
|
||||||
|
* The first condition is the combined conditions needed to move from the 1F child lock to the area being checks
|
||||||
|
* the second condition is the same for adult 1F lock, and the third is the access from the boss door.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool SpiritExplosiveKeyLogic() {
|
||||||
|
return logic->SmallKeys(RR_SPIRIT_TEMPLE, logic->SpiritBrokenWallToStatue() ? 1
|
||||||
|
: ctx->GetOption(RSK_BOMBCHU_BAG) && logic->BombchuRefill() ? 2
|
||||||
|
: 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) {
|
// clang-format off
|
||||||
return areaTable[region].MQSpiritShared(condition, true, anyAge);
|
std::map<RandomizerRegion, SpiritLogicData> Region::spiritLogicData = {
|
||||||
|
//Vanilla
|
||||||
|
{RR_SPIRIT_TEMPLE_WEST_CLIMB_BASE, {5, 5, 5, []{return true;}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_BROKEN_WALL, {5, 5, 5, []{return true /*logic->CanClimbHigh()*/;}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_2F_MIRROR, {5, 5, 3, []{return logic->CanUse(RG_HOOKSHOT) && logic->SpiritBrokenWallToStatue();}, []{return true/*logic->CanClimbHigh()*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_STATUE_ROOM_WEST, {5, 5, 3, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_INNER_WEST_HAND, {5, 5, 3, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_GS_LEDGE, {5, 5, 3, []{return SpiritExplosiveKeyLogic() && logic->SpiritWestToSkull()/* && logic->CanClimbHigh()*/;}, []{return logic->SpiritWestToSkull()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->SpiritWestToSkull()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_STATUE_ROOM, {5, 5, 3, []{return SpiritExplosiveKeyLogic();}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return true;}}},
|
||||||
|
//Assumes SpiritSunBlockSouthLedge() for all access
|
||||||
|
{RR_SPIRIT_TEMPLE_SUN_BLOCK_SOUTH_LEDGE, {5, 5, 3, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return true/*((logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)) && str0) || (logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT))*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_SKULLTULA_STAIRS, {5, 5, 3, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return true/*((logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)) && str0) || (logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT))*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_OUTER_WEST_HAND, {5, 5, 3, []{return SpiritExplosiveKeyLogic() && logic->CanKillEnemy(RE_IRON_KNUCKLE) //For the purpose of shared, adult needs to get to west side via BOTH possible routes for it to count //Only using HasItem here is intended so this check can pass as child if adult can do their part. This works because this edge case assumes that you can only waste keys on adult side with adult
|
||||||
|
/*&& logic->CanClimbHigh() && str0*/;}, []{return logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT)/* && logic->CanClimbHigh() && str0*/;}, []{return logic->CanKillEnemy(RE_BEAMOS) && logic->HasItem(RG_LONGSHOT)/* && logic->CanClimb() && str0*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_STATUE_ROOM_EAST, {5, 5, 3, []{return logic->CanUse(RG_HOOKSHOT) && SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_INNER_EAST_HAND, {5, 5, 3, []{return logic->CanUse(RG_HOOKSHOT) && SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_SHORTCUT_SWITCH, {5, 5, 3, []{return logic->CanUse(RG_HOOKSHOT) && SpiritExplosiveKeyLogic() && logic->SpiritEastToSwitch();}, []{return logic->SpiritEastToSwitch()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->SpiritEastToSwitch() && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}}},
|
||||||
|
//MQ /*&& logic->CanClimbHigh()*/
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, {7, 6, 7, []{return true;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6) && logic->CanHitSwitch()/* && logic->Climb*/;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6) && logic->CanHitSwitch()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, {7, 6, 7, []{return logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6)/* && logic->Climb*/;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6)/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_WEST, {7, 7, 0, []{return logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return true/*logic->Climb*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_POT_LEDGE, {7, 7, 0, []{return logic->CanHitSwitch() && logic->MQSpiritWestToPots()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritWestToPots()/* && logic->Climb*/;}, []{return /*logic->CanUse(RG_HOVER_BOOTS) || (logic->CanClimb() && */logic->MQSpiritWestToPots()/*)*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_INNER_WEST_HAND, {7, 7, 0, []{return logic->CanHitSwitch() && logic->MQSpiritWestToPots()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritWestToPots()/* && logic->Climb*/;}, []{return /*logic->CanUse(RG_HOVER_BOOTS) || (logic->CanClimb() && */logic->MQSpiritWestToPots()/*)*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, {7, 7, 0, []{return logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return true;}, []{return true;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, {7, 7, 0, []{return logic->CanHitSwitch() && logic->MQSpiritStatueToSunBlock()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritStatueToSunBlock()/* && logic->Climb*/;}, []{return logic->MQSpiritStatueToSunBlock()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_OUTER_WEST_HAND, {7, 7, 4, []{return logic->CanHitSwitch() && logic->MQSpiritStatueToSunBlock() //For the purpose of shared, adult needs to get to west side via BOTH possible routes for it to count //Only using HasItem here for adult items so child can pass this check
|
||||||
|
/* && logic->CanClimbHigh() && str0*/;}, []{return logic->MQSpirit4KeyWestHand();}, []{return logic->CouldMQSpirit4KeyWestHand();}}},
|
||||||
|
{RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH, {7, 7, 0, []{return logic->CanHitSwitch() &&
|
||||||
|
areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH].Here([]{return logic->MQSpiritStatueSouthDoor();})
|
||||||
|
/* && logic->CanClimbHigh()*/;}, []{return true;}, []{return areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH].Here([]{return logic->MQSpiritStatueSouthDoor();});}}},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
bool SpiritCertainAccess(RandomizerRegion region) {
|
||||||
|
SpiritLogicData& curRegionData = Region::spiritLogicData[region];
|
||||||
|
uint8_t keys = curRegionData.adultKeys;
|
||||||
|
bool reverseAccess = logic->ReverseSpiritAdult;
|
||||||
|
if (logic->IsChild) {
|
||||||
|
// If child enters in reverse, then they have access to Certain Access to Broken Wall room in 6 keys,
|
||||||
|
// the ability to hit switches and the ability to climb because only child can reach the initial child lock
|
||||||
|
// without opening the Statue room to Broken Wall Room lock first
|
||||||
|
keys = (logic->ReverseSpiritChild && logic->CanHitSwitch() /* && CanClimbHigh()*/)
|
||||||
|
? curRegionData.childReverseKeys
|
||||||
|
: curRegionData.childKeys;
|
||||||
|
reverseAccess = logic->ReverseSpiritChild;
|
||||||
|
}
|
||||||
|
// If we have enough keys that an age cannot be kept out, we have Certain Access
|
||||||
|
// otherwise if we have entered in reverse and can reach from the face, we have Certain Access
|
||||||
|
return logic->SmallKeys(RR_SPIRIT_TEMPLE, keys) || (reverseAccess && curRegionData.reverseAccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spirit Shared can take up to 3 regions, this is because checks can exist in many regions at the same time
|
||||||
|
and the logic needs to be able to check the access logic from those regions to check the other universes properly.
|
||||||
|
|
||||||
|
*anyAge is equivalent to a self referencing Here, used for events and any check where that is relevent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge, RandomizerRegion otherRegion,
|
||||||
|
ConditionFn otherCondition, RandomizerRegion thirdRegion, ConditionFn thirdCondition) {
|
||||||
|
SpiritLogicData& curRegionData = Region::spiritLogicData[region];
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
// store current age variables
|
||||||
|
bool pastAdult = logic->IsAdult;
|
||||||
|
bool pastChild = logic->IsChild;
|
||||||
|
|
||||||
|
logic->IsChild = true;
|
||||||
|
logic->IsAdult = false;
|
||||||
|
|
||||||
|
bool ChildCertainAccess = SpiritCertainAccess(region);
|
||||||
|
|
||||||
|
// Switch back to adult to check adult access
|
||||||
|
logic->IsChild = false;
|
||||||
|
logic->IsAdult = true;
|
||||||
|
|
||||||
|
bool AdultCertainAccess = SpiritCertainAccess(region);
|
||||||
|
// If we are AnyAge and have any CeratinAccess, then we can check those ages
|
||||||
|
// we don't need to check ambiguity here as if this fails, then 1 of the ages has failed
|
||||||
|
if (anyAge && (ChildCertainAccess || AdultCertainAccess)) {
|
||||||
|
// set age access to the Certain Access
|
||||||
|
logic->IsChild = ChildCertainAccess;
|
||||||
|
logic->IsAdult = AdultCertainAccess;
|
||||||
|
|
||||||
|
// check condition as well as having at least child or adult access
|
||||||
|
result = condition();
|
||||||
|
|
||||||
|
// otherwise, we have to check the current age and...
|
||||||
|
} else if (areaTable[region].Child() && pastChild) {
|
||||||
|
// Switch to Child
|
||||||
|
logic->IsChild = true;
|
||||||
|
logic->IsAdult = false;
|
||||||
|
|
||||||
|
result = condition();
|
||||||
|
// If we have Certain Access, we just run the condition.
|
||||||
|
// Otherwise, if we have the keys to know either age can reach, we need to see if we could reach as Adult
|
||||||
|
// and if needed, in reverse
|
||||||
|
if (!ChildCertainAccess && result &&
|
||||||
|
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess())) {
|
||||||
|
// Switch to Adult
|
||||||
|
logic->IsChild = false;
|
||||||
|
logic->IsAdult = true;
|
||||||
|
// If Adult can get there and get the check, we can get the check in logic
|
||||||
|
// If reverse spirit is also possible, we need to make sure Adult can get it via reverse entry too
|
||||||
|
result = (curRegionData.adultAccess() &&
|
||||||
|
(!logic->IsReverseAccessPossible() || curRegionData.reverseAccess) && condition()) ||
|
||||||
|
(otherRegion != RR_NONE &&
|
||||||
|
(Region::spiritLogicData[otherRegion].adultAccess() &&
|
||||||
|
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) &&
|
||||||
|
otherCondition())) ||
|
||||||
|
(thirdRegion != RR_NONE &&
|
||||||
|
(Region::spiritLogicData[thirdRegion].adultAccess() &&
|
||||||
|
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[thirdRegion].reverseAccess()) &&
|
||||||
|
thirdCondition()));
|
||||||
|
}
|
||||||
|
} else if (areaTable[region].Adult() && pastAdult) {
|
||||||
|
result = condition();
|
||||||
|
// if we have enough keys to have Certain Access, we just run the condition
|
||||||
|
// Alternatively, if we have entered in reverse and can reach from the face, we have Certain Access
|
||||||
|
// Otherwise, if we have the keys to know either age can reach, we need to see if we could reach as Child
|
||||||
|
// and if needed, in reverse
|
||||||
|
if (!AdultCertainAccess && result &&
|
||||||
|
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess)) {
|
||||||
|
// Switch to Child
|
||||||
|
logic->IsChild = true;
|
||||||
|
logic->IsAdult = false;
|
||||||
|
|
||||||
|
// If Child can get there and get the check, we can get the check in logic
|
||||||
|
// If reverse spirit is also possible, we need to make sure Child can get it via reverse entry too
|
||||||
|
result = (curRegionData.childAccess() &&
|
||||||
|
(!logic->IsReverseAccessPossible() || curRegionData.reverseAccess()) && condition()) ||
|
||||||
|
(otherRegion != RR_NONE &&
|
||||||
|
(Region::spiritLogicData[otherRegion].childAccess() &&
|
||||||
|
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) &&
|
||||||
|
otherCondition())) ||
|
||||||
|
(thirdRegion != RR_NONE &&
|
||||||
|
(Region::spiritLogicData[thirdRegion].childAccess() &&
|
||||||
|
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[thirdRegion].reverseAccess()) &&
|
||||||
|
thirdCondition()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set back age variables
|
||||||
|
logic->IsChild = pastChild;
|
||||||
|
logic->IsAdult = pastAdult;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BeanPlanted(const RandomizerRegion region) {
|
bool BeanPlanted(const RandomizerRegion region) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "soh/Enhancements/randomizer/randomizerTypes.h"
|
#include "soh/Enhancements/randomizer/randomizerTypes.h"
|
||||||
#include "soh/Enhancements/randomizer/context.h"
|
#include "soh/Enhancements/randomizer/context.h"
|
||||||
#include "soh/Enhancements/randomizer/logic.h"
|
#include "soh/Enhancements/randomizer/logic.h"
|
||||||
|
#include "soh/Enhancements/randomizer/dungeon.h"
|
||||||
|
|
||||||
typedef bool (*ConditionFn)();
|
typedef bool (*ConditionFn)();
|
||||||
|
|
||||||
|
@ -110,6 +111,25 @@ class Entrance;
|
||||||
enum class EntranceType;
|
enum class EntranceType;
|
||||||
} // namespace Rando
|
} // namespace Rando
|
||||||
|
|
||||||
|
struct SpiritLogicData {
|
||||||
|
uint8_t childKeys; // the number of keys that guarantees Child can reach this region
|
||||||
|
// The number of keys that guarantees Child can reach this region if they have reverse access
|
||||||
|
// This changes for MQ broken wall room as the first child lock can only be opened by Child
|
||||||
|
// guaranteeing access with 6 keys
|
||||||
|
uint8_t childReverseKeys;
|
||||||
|
uint8_t adultKeys; // the number of keys that guarantees Adult can reach this region
|
||||||
|
// The area access condition to reach this region as Child, from the first lock,
|
||||||
|
// including the minimum number of keys for ambiguous access
|
||||||
|
// 1 key is always assumed to be required
|
||||||
|
ConditionFn childAccess;
|
||||||
|
// The area access condition to reach this region as Adult, from the first lock
|
||||||
|
// including the minimum number of keys for ambiguous access
|
||||||
|
// 1 key is always assumed to be required on vanilla
|
||||||
|
ConditionFn adultAccess;
|
||||||
|
// The area access condition to reach this region from the boss door,
|
||||||
|
ConditionFn reverseAccess;
|
||||||
|
};
|
||||||
|
|
||||||
class Region {
|
class Region {
|
||||||
public:
|
public:
|
||||||
Region();
|
Region();
|
||||||
|
@ -231,96 +251,7 @@ class Region {
|
||||||
std::to_string(adultNight);
|
std::to_string(adultNight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static std::map<RandomizerRegion, SpiritLogicData> spiritLogicData;
|
||||||
* This logic covers checks that exist in the shared areas of MQ spirit from a glitchless standpoint.
|
|
||||||
* This room has Quantum logic that I am currently handling with this function, however this is NOT suitable for
|
|
||||||
glitch logic as it relies on specific ages
|
|
||||||
* In this chunk there are 3 possibilities for passing a check, but first I have to talk about parallel universes.
|
|
||||||
|
|
||||||
* In MQ Spirit key logic, we mostly care about 2 possibilities for how the player can spend keys, creating 2
|
|
||||||
Parralel universes
|
|
||||||
* In the first universe, the player did not enter spirit as adult until after climbing as child, thus child spends
|
|
||||||
keys linearly, only needing 2 to reach statue room.
|
|
||||||
* In the second universe, the player went in as adult, possibly out of logic, and started wasting the keys to lock
|
|
||||||
child out.
|
|
||||||
* These Universes converge when the player has 7 keys (meaning adult can no longer lock child out) and adult is
|
|
||||||
known to be able to reach Statue room. This creates "Certain Access", which is tracked seperatly for each age.
|
|
||||||
* Child Certain Access is simple, if we have 7 keys and child access, it's Certain Access.
|
|
||||||
* Adult Certain Access is also simple, adult is not key locked, so if they make it to a location, it's Certain
|
|
||||||
Access.
|
|
||||||
* Things get complicated when we handle the overlap of the 2 universes,
|
|
||||||
* though an important detail is that if we have Certain Access as either age, we don't need to checked the overlap
|
|
||||||
because overlap logic is strictly stricter than either Certain Access.
|
|
||||||
|
|
||||||
* In order to track the first universe, the logic allows technical child access with the minimum number of keys,
|
|
||||||
and then checks in this function for if we have 7 keys to determine if that is Certain or not.
|
|
||||||
* This is for technical reasons, as areas with no access at all will simply not be checked.
|
|
||||||
* Normally we would need to do similar shenanigans to track the second universe, however adult must have go through
|
|
||||||
statue room to waste keys,
|
|
||||||
* so can go back there and get new keys for Child to use if they do, and the navigation logic for shared MQ spirit
|
|
||||||
from Statue Room is very simple for Adult.
|
|
||||||
* Additionally, we don't need to know if adult can actually reach spirit temple or climb to statue room, because if
|
|
||||||
the player can't do that, then universe 2 can't happen anyway,
|
|
||||||
* and if the player does so out of logic, they can do it again, as the only consumable used sets a permanent flag.
|
|
||||||
|
|
||||||
* The Adult Navigation logic is as such:
|
|
||||||
* - Broken Wall room is 6 key locked, because if the player tries to spend 6 keys in a way that would block adults
|
|
||||||
access, they would have to give child access instead.
|
|
||||||
* - The child side hammer switch for the time travelling chest is 7 key locked for adult
|
|
||||||
* - Reaching gauntlets hand is 7 key locked
|
|
||||||
* - Going back into big block room is complex, but the only check there is child only so not a concern
|
|
||||||
* - Everything else is possible with basic adult movement, or is impossible for child to reach glitchlessly
|
|
||||||
* Anything 7 key locked does not need to be checked as shared, as all child access is Certain and because of this
|
|
||||||
workaround we don't need to fake Adult access, meaning that is also Certain.
|
|
||||||
* All of this combined means that when checking if adult can reach a location in universe 2, we only have to ask if
|
|
||||||
it is a 6 key locked location or not.
|
|
||||||
|
|
||||||
* Knowing all of this this, we can confirm things are logical in 3 different ways:
|
|
||||||
* - If we have Adult Access, we know it is Certain Access, so they can get checks alone.
|
|
||||||
* - If we have 7 keys, child has Certain Access as we know they cannot be locked out, so can get checks alone,
|
|
||||||
otherwise we check the logical overlap
|
|
||||||
* - If Child and Adult can get the check (ignoring actual adult access to the location), and the location is either
|
|
||||||
not 6 key locked or we have 6 keys, we can get the check with the overlap
|
|
||||||
*/
|
|
||||||
bool MQSpiritShared(ConditionFn condition, bool IsBrokenWall, bool anyAge = false) {
|
|
||||||
// if we have Certain Access as child, we can check anyAge and if true, resolve a condition with Here as if
|
|
||||||
// adult is here it's also Certain Access
|
|
||||||
if (logic->SmallKeys(RR_SPIRIT_TEMPLE, 7)) {
|
|
||||||
if (anyAge) {
|
|
||||||
return Here(condition);
|
|
||||||
}
|
|
||||||
return condition();
|
|
||||||
// else, if we are here as adult, we have Certain Access from that and don't need special handling for
|
|
||||||
// checking adult
|
|
||||||
} else if (Adult() && logic->IsAdult) {
|
|
||||||
return condition();
|
|
||||||
// if we do not have Certain Access, we need to check the overlap by seeing if we are both here as child and
|
|
||||||
// meet the adult universe's access condition We only need to do it as child, as only child access matters
|
|
||||||
// for this check, as adult access is assumed based on keys
|
|
||||||
} else if (Child() && logic->IsChild && (!IsBrokenWall || logic->SmallKeys(RR_SPIRIT_TEMPLE, 6))) {
|
|
||||||
bool result = false;
|
|
||||||
// store current age variables
|
|
||||||
bool pastAdult = logic->IsAdult;
|
|
||||||
bool pastChild = logic->IsChild;
|
|
||||||
|
|
||||||
// First check if the check is possible as child
|
|
||||||
logic->IsChild = true;
|
|
||||||
logic->IsAdult = false;
|
|
||||||
result = condition();
|
|
||||||
// If so, check again as adult. both have to be true for result to be true
|
|
||||||
if (result) {
|
|
||||||
logic->IsChild = false;
|
|
||||||
logic->IsAdult = true;
|
|
||||||
result = condition();
|
|
||||||
}
|
|
||||||
|
|
||||||
// set back age variables
|
|
||||||
logic->IsChild = pastChild;
|
|
||||||
logic->IsAdult = pastAdult;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::array<Region, RR_MAX> areaTable;
|
extern std::array<Region, RR_MAX> areaTable;
|
||||||
|
@ -329,8 +260,11 @@ extern std::vector<EventAccess> grottoEvents;
|
||||||
bool Here(const RandomizerRegion region,
|
bool Here(const RandomizerRegion region,
|
||||||
ConditionFn
|
ConditionFn
|
||||||
condition); // RANDOTODO make a less stupid way to check own at either age than self referencing with this
|
condition); // RANDOTODO make a less stupid way to check own at either age than self referencing with this
|
||||||
bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false);
|
bool SpiritShared(
|
||||||
bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false);
|
RandomizerRegion region, ConditionFn condition, bool anyAge = false, RandomizerRegion otherRegion = RR_NONE,
|
||||||
|
ConditionFn otherCondition = [] { return false; }, RandomizerRegion thirdRegion = RR_NONE,
|
||||||
|
ConditionFn thirdCondition = [] { return false; });
|
||||||
|
bool SpiritCertainAccess(RandomizerRegion region);
|
||||||
bool CanPlantBean(const RandomizerRegion region);
|
bool CanPlantBean(const RandomizerRegion region);
|
||||||
bool BothAges(const RandomizerRegion region);
|
bool BothAges(const RandomizerRegion region);
|
||||||
bool ChildCanAccess(const RandomizerRegion region);
|
bool ChildCanAccess(const RandomizerRegion region);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -538,14 +538,11 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
|
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_BOMB_THROW:
|
case ED_BOMB_THROW:
|
||||||
killed = killed || CanUse(RG_BOMB_BAG);
|
killed = killed || CanUse(RG_BOMB_BAG) || CanUse(RG_DINS_FIRE);
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_BOOMERANG:
|
case ED_BOOMERANG:
|
||||||
// RANDOTODO test dins and chu range in a practical example
|
|
||||||
killed = killed || CanUse(RG_DINS_FIRE);
|
|
||||||
[[fallthrough]];
|
|
||||||
case ED_HOOKSHOT:
|
case ED_HOOKSHOT:
|
||||||
// RANDOTODO test dins and chu range in a practical example
|
// RANDOTODO test chu range in a practical example
|
||||||
killed = killed || CanUse(RG_HOOKSHOT) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
killed = killed || CanUse(RG_HOOKSHOT) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_LONGSHOT:
|
case ED_LONGSHOT:
|
||||||
|
@ -575,15 +572,15 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
|
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_BOMB_THROW:
|
case ED_BOMB_THROW:
|
||||||
// RANDOTODO test dins and chu range in a practical example
|
// RANDOTODO test chu range in a practical example
|
||||||
killed = killed || (!inWater && CanUse(RG_BOMB_BAG));
|
killed = killed || (!inWater && CanUse(RG_BOMB_BAG));
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_BOOMERANG:
|
case ED_BOOMERANG:
|
||||||
// RANDOTODO test dins and chu range in a practical example
|
// RANDOTODO test chu range in a practical example
|
||||||
killed = killed || CanUse(RG_BOOMERANG);
|
killed = killed || CanUse(RG_BOOMERANG);
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_HOOKSHOT:
|
case ED_HOOKSHOT:
|
||||||
// RANDOTODO test dins, bomb and chu range in a practical example
|
// RANDOTODO test chu range in a practical example
|
||||||
killed = killed || CanUse(RG_HOOKSHOT) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
killed = killed || CanUse(RG_HOOKSHOT) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_LONGSHOT:
|
case ED_LONGSHOT:
|
||||||
|
@ -628,7 +625,7 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_BOOMERANG:
|
case ED_BOOMERANG:
|
||||||
case ED_HOOKSHOT:
|
case ED_HOOKSHOT:
|
||||||
// RANDOTODO test dins and chu range in a practical example
|
// RANDOTODO test chu range in a practical example
|
||||||
killed = killed || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
killed = killed || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_LONGSHOT:
|
case ED_LONGSHOT:
|
||||||
|
@ -709,12 +706,11 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
|
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_BOMB_THROW:
|
case ED_BOMB_THROW:
|
||||||
// RANDOTODO test dins and chu range in a practical example
|
|
||||||
killed = killed || (!inWater && CanUse(RG_BOMB_BAG));
|
killed = killed || (!inWater && CanUse(RG_BOMB_BAG));
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_BOOMERANG:
|
case ED_BOOMERANG:
|
||||||
case ED_HOOKSHOT:
|
case ED_HOOKSHOT:
|
||||||
// RANDOTODO test dins, bomb and chu range in a practical example
|
// RANDOTODO test chu range in a practical example
|
||||||
killed = killed || CanUse(RG_HOOKSHOT) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
killed = killed || CanUse(RG_HOOKSHOT) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ED_LONGSHOT:
|
case ED_LONGSHOT:
|
||||||
|
@ -788,6 +784,35 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
case RE_OCTOROK:
|
case RE_OCTOROK:
|
||||||
return CanReflectNuts() || HookshotOrBoomerang() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) ||
|
return CanReflectNuts() || HookshotOrBoomerang() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) ||
|
||||||
CanUse(RG_BOMB_BAG) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
CanUse(RG_BOMB_BAG) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
|
||||||
|
case RE_WALLTULA:
|
||||||
|
switch (distance) {
|
||||||
|
case ED_CLOSE:
|
||||||
|
case ED_SHORT_JUMPSLASH:
|
||||||
|
killed = CanUse(RG_KOKIRI_SWORD);
|
||||||
|
[[fallthrough]];
|
||||||
|
case ED_MASTER_SWORD_JUMPSLASH:
|
||||||
|
killed = killed || CanUse(RG_MASTER_SWORD);
|
||||||
|
[[fallthrough]];
|
||||||
|
case ED_LONG_JUMPSLASH:
|
||||||
|
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
|
||||||
|
[[fallthrough]];
|
||||||
|
case ED_BOMB_THROW:
|
||||||
|
killed = killed || (!inWater && CanUse(RG_BOMB_BAG)) || CanUse(RG_DINS_FIRE);
|
||||||
|
[[fallthrough]];
|
||||||
|
case ED_BOOMERANG:
|
||||||
|
killed = killed || CanUse(RG_BOOMERANG);
|
||||||
|
[[fallthrough]];
|
||||||
|
case ED_HOOKSHOT:
|
||||||
|
killed = killed || CanUse(RG_HOOKSHOT) || CanUse(RG_BOMBCHU_5) || CanUse(RG_MEGATON_HAMMER);
|
||||||
|
[[fallthrough]];
|
||||||
|
case ED_LONGSHOT:
|
||||||
|
killed = killed || CanUse(RG_LONGSHOT);
|
||||||
|
[[fallthrough]];
|
||||||
|
case ED_FAR:
|
||||||
|
killed = killed || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return killed;
|
||||||
default:
|
default:
|
||||||
SPDLOG_ERROR("CanKillEnemy reached `default`.");
|
SPDLOG_ERROR("CanKillEnemy reached `default`.");
|
||||||
assert(false);
|
assert(false);
|
||||||
|
@ -840,6 +865,7 @@ bool Logic::CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
return CanUse(RG_HOOKSHOT) || CanUse(RG_SUNS_SONG);
|
return CanUse(RG_HOOKSHOT) || CanUse(RG_SUNS_SONG);
|
||||||
case RE_IRON_KNUCKLE:
|
case RE_IRON_KNUCKLE:
|
||||||
case RE_BIG_OCTO:
|
case RE_BIG_OCTO:
|
||||||
|
case RE_WALLTULA: // consistent with RT_SPIRIT_WALL
|
||||||
return false;
|
return false;
|
||||||
case RE_GREEN_BUBBLE:
|
case RE_GREEN_BUBBLE:
|
||||||
return TakeDamage() || CanUse(RG_NUTS) || CanUse(RG_BOOMERANG) || CanUse(RG_HOOKSHOT);
|
return TakeDamage() || CanUse(RG_NUTS) || CanUse(RG_BOOMERANG) || CanUse(RG_HOOKSHOT);
|
||||||
|
@ -886,9 +912,10 @@ bool Logic::CanAvoidEnemy(RandomizerEnemy enemy, bool grounded, uint8_t quantity
|
||||||
case RE_WALLMASTER:
|
case RE_WALLMASTER:
|
||||||
case RE_ANUBIS:
|
case RE_ANUBIS:
|
||||||
case RE_PURPLE_LEEVER:
|
case RE_PURPLE_LEEVER:
|
||||||
|
case RE_WALLTULA:
|
||||||
return true;
|
return true;
|
||||||
case RE_BEAMOS:
|
case RE_BEAMOS:
|
||||||
return !grounded || CanUse(RG_NUTS) ||
|
return !grounded || CanUse(RG_NUTS) || CanUse(RG_DINS_FIRE) ||
|
||||||
(quantity == 1 && (CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT)));
|
(quantity == 1 && (CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT)));
|
||||||
case RE_MAD_SCRUB:
|
case RE_MAD_SCRUB:
|
||||||
return !grounded || CanUse(RG_NUTS);
|
return !grounded || CanUse(RG_NUTS);
|
||||||
|
@ -898,6 +925,8 @@ bool Logic::CanAvoidEnemy(RandomizerEnemy enemy, bool grounded, uint8_t quantity
|
||||||
case RE_BLUE_BUBBLE:
|
case RE_BLUE_BUBBLE:
|
||||||
// RANDOTODO Trick to use shield hylian shield as child to stun these guys
|
// RANDOTODO Trick to use shield hylian shield as child to stun these guys
|
||||||
return !grounded || CanUse(RG_NUTS) || HookshotOrBoomerang() || CanStandingShield();
|
return !grounded || CanUse(RG_NUTS) || HookshotOrBoomerang() || CanStandingShield();
|
||||||
|
case RE_TORCH_SLUG:
|
||||||
|
return !grounded || CanUse(RG_NUTS) || CanUse(RG_HOOKSHOT) || CanUse(RG_DINS_FIRE);
|
||||||
default:
|
default:
|
||||||
SPDLOG_ERROR("CanPassEnemy reached `default`.");
|
SPDLOG_ERROR("CanPassEnemy reached `default`.");
|
||||||
assert(false);
|
assert(false);
|
||||||
|
@ -1258,6 +1287,10 @@ bool Logic::HasFireSourceWithTorch() {
|
||||||
return HasFireSource() || CanUse(RG_STICKS);
|
return HasFireSource() || CanUse(RG_STICKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Logic::SunlightArrows() {
|
||||||
|
return ctx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS);
|
||||||
|
}
|
||||||
|
|
||||||
// Is this best off signaling what you have already traded, or what step you are currently on?
|
// Is this best off signaling what you have already traded, or what step you are currently on?
|
||||||
bool Logic::TradeQuestStep(RandomizerGet rg) {
|
bool Logic::TradeQuestStep(RandomizerGet rg) {
|
||||||
if (ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE)) {
|
if (ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE)) {
|
||||||
|
@ -2331,6 +2364,65 @@ void Logic::SetInLogic(LogicVal logicVal, bool value) {
|
||||||
inLogic[logicVal] = value;
|
inLogic[logicVal] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Logic::IsReverseAccessPossible() {
|
||||||
|
return ctx->GetOption(RSK_SHUFFLE_BOSS_ENTRANCES) &&
|
||||||
|
(ctx->GetOption(RSK_DECOUPLED_ENTRANCES) || ctx->GetOption(RSK_MIX_BOSS_ENTRANCES));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::SpiritBrokenWallToStatue() {
|
||||||
|
return /*CanClimbHigh() &&*/ (HasExplosives() || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::SpiritEastToSwitch() {
|
||||||
|
return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) || CanUse(RG_HOVER_BOOTS) ||
|
||||||
|
(CanUse(RG_ZELDAS_LULLABY) && CanUse(RG_HOOKSHOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::SpiritWestToSkull() {
|
||||||
|
return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) || CanUse(RG_HOVER_BOOTS) || CanUse(RG_SCARECROW);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::SpiritSunBlockSouthLedge() {
|
||||||
|
// It's also possible to do a backwalk hover + backflip if you equip hovers as you start the backwalk to accelerate
|
||||||
|
// faster
|
||||||
|
return true /*str0 || IsAdult || CanKillEnemy(RE_BEAMOS) || BunnyHovers() ||
|
||||||
|
(CanUse(RG_HOOKSHOT) && (HasFireSource() ||
|
||||||
|
(SpiritSunBlockTorch && (logic->CanUse(STICKS) ||
|
||||||
|
(ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && logic->CanUse(RG_FAIRY_BOW))))))*/
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combines crossing the ledge directly and the jump from the hand
|
||||||
|
bool Logic::MQSpiritWestToPots() {
|
||||||
|
return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) || CanUse(RG_HOVER_BOOTS) || CanUse(RG_SONG_OF_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::MQSpiritStatueToSunBlock() {
|
||||||
|
return (IsAdult || ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) ||
|
||||||
|
CanUse(RG_SONG_OF_TIME) /* || CanBunnyJump()*/) /* && str0*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::MQSpiritStatueSouthDoor() {
|
||||||
|
return HasFireSource() || (ctx->GetTrickOption(RT_SPIRIT_MQ_FROZEN_EYE) && CanUse(RG_FAIRY_BOW) &&
|
||||||
|
CanUse(RG_SONG_OF_TIME) /* && CanClimb()*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::MQSpirit4KeyWestHand() {
|
||||||
|
return CanAvoidEnemy(RE_BEAMOS, true, 4) && CanUse(RG_SONG_OF_TIME) &&
|
||||||
|
CanJumpslash() && /*(str0 || SunlightArrows) &&*/
|
||||||
|
(ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)) && CanKillEnemy(RE_IRON_KNUCKLE) &&
|
||||||
|
CanUse(RG_LONGSHOT);
|
||||||
|
}
|
||||||
|
// This version of the function handles reaching there as child, based on what adult could do if they existed
|
||||||
|
bool Logic::CouldMQSpirit4KeyWestHand() {
|
||||||
|
return CanAvoidEnemy(RE_BEAMOS, true, 4) && CanUse(RG_SONG_OF_TIME) && HasItem(RG_MASTER_SWORD) ||
|
||||||
|
HasItem(RG_BIGGORON_SWORD) ||
|
||||||
|
HasItem(RG_MEGATON_HAMMER) &&
|
||||||
|
/*(str0 || SunlightArrows) &&*/
|
||||||
|
(ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)) && CanKillEnemy(RE_IRON_KNUCKLE) &&
|
||||||
|
HasItem(RG_LONGSHOT);
|
||||||
|
}
|
||||||
|
|
||||||
void Logic::Reset() {
|
void Logic::Reset() {
|
||||||
NewSaveContext();
|
NewSaveContext();
|
||||||
StartPerformanceTimer(PT_LOGIC_RESET);
|
StartPerformanceTimer(PT_LOGIC_RESET);
|
||||||
|
@ -2500,6 +2592,7 @@ void Logic::Reset() {
|
||||||
MQGTGMazeSwitch = false;
|
MQGTGMazeSwitch = false;
|
||||||
GTGPlatformSilverRupees = false;
|
GTGPlatformSilverRupees = false;
|
||||||
MQJabuHolesRoomDoor = false;
|
MQJabuHolesRoomDoor = false;
|
||||||
|
JabuRutoIn1F = false;
|
||||||
JabuWestTentacle = false;
|
JabuWestTentacle = false;
|
||||||
JabuEastTentacle = false;
|
JabuEastTentacle = false;
|
||||||
JabuNorthTentacle = false;
|
JabuNorthTentacle = false;
|
||||||
|
@ -2512,11 +2605,25 @@ void Logic::Reset() {
|
||||||
MQWaterB1Switch = false;
|
MQWaterB1Switch = false;
|
||||||
// MQWaterPillarSoTBlock = false;
|
// MQWaterPillarSoTBlock = false;
|
||||||
MQWaterOpenedPillarB1 = false;
|
MQWaterOpenedPillarB1 = false;
|
||||||
|
MQSpiritGibdosCleared = false;
|
||||||
MQSpiritCrawlBoulder = false;
|
MQSpiritCrawlBoulder = false;
|
||||||
MQSpiritMapRoomEnemies = false;
|
MQSpiritMapRoomEnemies = false;
|
||||||
|
MQSpiritTimeTravelChest = false;
|
||||||
|
MQSpiritStatueRoomTorches = false;
|
||||||
MQSpirit3SunsEnemies = false;
|
MQSpirit3SunsEnemies = false;
|
||||||
|
MQSpiritSymphonyRoomDoor = false;
|
||||||
|
MQSpiritBigWallSilvers = false;
|
||||||
Spirit1FSilverRupees = false;
|
Spirit1FSilverRupees = false;
|
||||||
JabuRutoIn1F = false;
|
SpiritChildSwitchBridge = false;
|
||||||
|
SpiritRupeeBridge = false;
|
||||||
|
SpiritSunBlockTorch = false;
|
||||||
|
SpiritBouldersSilvers = false;
|
||||||
|
SpiritStatueRoomSouthDoor = false;
|
||||||
|
SpiritPlatformLowered = false;
|
||||||
|
Spirit4FSwitch = false;
|
||||||
|
SpiritPushed4FMirrors = false;
|
||||||
|
ReverseSpiritChild = false;
|
||||||
|
ReverseSpiritAdult = false;
|
||||||
|
|
||||||
StopPerformanceTimer(PT_LOGIC_RESET);
|
StopPerformanceTimer(PT_LOGIC_RESET);
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,6 +162,7 @@ class Logic {
|
||||||
bool MQGTGRightSideSwitch = false;
|
bool MQGTGRightSideSwitch = false;
|
||||||
bool GTGPlatformSilverRupees = false;
|
bool GTGPlatformSilverRupees = false;
|
||||||
bool MQJabuHolesRoomDoor = false;
|
bool MQJabuHolesRoomDoor = false;
|
||||||
|
bool JabuRutoIn1F = false;
|
||||||
bool JabuWestTentacle = false;
|
bool JabuWestTentacle = false;
|
||||||
bool JabuEastTentacle = false;
|
bool JabuEastTentacle = false;
|
||||||
bool JabuNorthTentacle = false;
|
bool JabuNorthTentacle = false;
|
||||||
|
@ -174,12 +175,25 @@ class Logic {
|
||||||
bool MQWaterB1Switch = false;
|
bool MQWaterB1Switch = false;
|
||||||
// bool MQWaterPillarSoTBlock = false; should be irrelevant. SHOULD.
|
// bool MQWaterPillarSoTBlock = false; should be irrelevant. SHOULD.
|
||||||
bool MQWaterOpenedPillarB1 = false;
|
bool MQWaterOpenedPillarB1 = false;
|
||||||
|
bool MQSpiritGibdosCleared = false;
|
||||||
bool MQSpiritCrawlBoulder = false;
|
bool MQSpiritCrawlBoulder = false;
|
||||||
bool MQSpiritMapRoomEnemies = false;
|
bool MQSpiritMapRoomEnemies = false;
|
||||||
bool MQSpiritTimeTravelChest = false;
|
bool MQSpiritTimeTravelChest = false;
|
||||||
|
bool MQSpiritStatueRoomTorches = false;
|
||||||
bool MQSpirit3SunsEnemies = false;
|
bool MQSpirit3SunsEnemies = false;
|
||||||
|
bool MQSpiritSymphonyRoomDoor = false;
|
||||||
|
bool MQSpiritBigWallSilvers = false;
|
||||||
bool Spirit1FSilverRupees = false;
|
bool Spirit1FSilverRupees = false;
|
||||||
bool JabuRutoIn1F = false;
|
bool SpiritChildSwitchBridge = false;
|
||||||
|
bool SpiritRupeeBridge = false;
|
||||||
|
bool SpiritSunBlockTorch = false;
|
||||||
|
bool SpiritBouldersSilvers = false;
|
||||||
|
bool SpiritStatueRoomSouthDoor = false;
|
||||||
|
bool SpiritPlatformLowered = false;
|
||||||
|
bool Spirit4FSwitch = false;
|
||||||
|
bool SpiritPushed4FMirrors = false;
|
||||||
|
bool ReverseSpiritChild = false;
|
||||||
|
bool ReverseSpiritAdult = false;
|
||||||
|
|
||||||
/* --- END OF HELPERS AND LOCATION ACCESS --- */
|
/* --- END OF HELPERS AND LOCATION ACCESS --- */
|
||||||
|
|
||||||
|
@ -247,6 +261,7 @@ class Logic {
|
||||||
bool CanBreakSmallCrates();
|
bool CanBreakSmallCrates();
|
||||||
bool HasFireSource();
|
bool HasFireSource();
|
||||||
bool HasFireSourceWithTorch();
|
bool HasFireSourceWithTorch();
|
||||||
|
bool SunlightArrows();
|
||||||
bool TradeQuestStep(RandomizerGet rg);
|
bool TradeQuestStep(RandomizerGet rg);
|
||||||
bool CanFinishGerudoFortress();
|
bool CanFinishGerudoFortress();
|
||||||
bool CanStandingShield();
|
bool CanStandingShield();
|
||||||
|
@ -288,6 +303,16 @@ class Logic {
|
||||||
static std::map<uint32_t, uint32_t> RandoGetToDungeonScene;
|
static std::map<uint32_t, uint32_t> RandoGetToDungeonScene;
|
||||||
static std::map<RandomizerGet, uint32_t> RandoGetToEquipFlag;
|
static std::map<RandomizerGet, uint32_t> RandoGetToEquipFlag;
|
||||||
static std::map<RandomizerGet, uint32_t> RandoGetToRandInf;
|
static std::map<RandomizerGet, uint32_t> RandoGetToRandInf;
|
||||||
|
bool IsReverseAccessPossible();
|
||||||
|
bool SpiritBrokenWallToStatue();
|
||||||
|
bool SpiritEastToSwitch();
|
||||||
|
bool SpiritWestToSkull();
|
||||||
|
bool SpiritSunBlockSouthLedge();
|
||||||
|
bool MQSpiritWestToPots();
|
||||||
|
bool MQSpiritStatueToSunBlock();
|
||||||
|
bool MQSpiritStatueSouthDoor();
|
||||||
|
bool MQSpirit4KeyWestHand();
|
||||||
|
bool CouldMQSpirit4KeyWestHand();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Context> ctx;
|
std::shared_ptr<Context> ctx;
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#define TWO_ACTOR_PARAMS(a, b) ((((a)&0xFFFF) << 16) | ((b)&0xFFFF))
|
#define TWO_ACTOR_PARAMS(a, b) ((((a)&0xFFFF) << 16) | ((b)&0xFFFF))
|
||||||
|
|
||||||
|
typedef bool (*ConditionFn)();
|
||||||
|
|
||||||
// This should probably go in a less rando-specific location
|
// This should probably go in a less rando-specific location
|
||||||
// but the best location will probably be in the modding engine
|
// but the best location will probably be in the modding engine
|
||||||
// which doesn't exist yet.
|
// which doesn't exist yet.
|
||||||
|
@ -844,50 +846,103 @@ typedef enum {
|
||||||
RR_WATER_TEMPLE_BOSS_ROOM,
|
RR_WATER_TEMPLE_BOSS_ROOM,
|
||||||
|
|
||||||
RR_SPIRIT_TEMPLE_LOBBY,
|
RR_SPIRIT_TEMPLE_LOBBY,
|
||||||
RR_SPIRIT_TEMPLE_CHILD,
|
RR_SPIRIT_TEMPLE_1F_WEST,
|
||||||
RR_SPIRIT_TEMPLE_CHILD_CLIMB,
|
RR_SPIRIT_TEMPLE_SWITCH_BRIDGE_SOUTH,
|
||||||
RR_SPIRIT_TEMPLE_EARLY_ADULT,
|
RR_SPIRIT_TEMPLE_SWITCH_BRIDGE_NORTH,
|
||||||
RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER,
|
RR_SPIRIT_TEMPLE_1F_ANUBIS,
|
||||||
RR_SPIRIT_TEMPLE_OUTDOOR_HANDS,
|
RR_SPIRIT_TEMPLE_RUPEE_BRIDGE_SOUTH,
|
||||||
RR_SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR,
|
RR_SPIRIT_TEMPLE_RUPEE_BRIDGE_NORTH,
|
||||||
RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR,
|
RR_SPIRIT_TEMPLE_1F_BOXES,
|
||||||
RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD,
|
RR_SPIRIT_TEMPLE_WEST_CLIMB_BASE,
|
||||||
|
RR_SPIRIT_TEMPLE_BROKEN_WALL,
|
||||||
|
RR_SPIRIT_TEMPLE_1F_EAST,
|
||||||
|
RR_SPIRIT_TEMPLE_SAND_PIT,
|
||||||
|
RR_SPIRIT_TEMPLE_BOULDERS,
|
||||||
|
RR_SPIRIT_TEMPLE_ABOVE_BOULDERS,
|
||||||
|
RR_SPIRIT_TEMPLE_PAST_BOULDERS,
|
||||||
|
RR_SPIRIT_TEMPLE_EAST_CLIMB_BASE,
|
||||||
|
RR_SPIRIT_TEMPLE_2F_MIRROR,
|
||||||
|
RR_SPIRIT_TEMPLE_STATUE_ROOM,
|
||||||
|
RR_SPIRIT_TEMPLE_STATUE_ROOM_WEST,
|
||||||
|
RR_SPIRIT_TEMPLE_INNER_WEST_HAND,
|
||||||
|
RR_SPIRIT_TEMPLE_GS_LEDGE,
|
||||||
|
RR_SPIRIT_TEMPLE_STATUE_ROOM_EAST,
|
||||||
|
RR_SPIRIT_TEMPLE_INNER_EAST_HAND,
|
||||||
|
RR_SPIRIT_TEMPLE_SHORTCUT_SWITCH,
|
||||||
|
RR_SPIRIT_TEMPLE_SHORTCUT,
|
||||||
|
RR_SPIRIT_TEMPLE_EMPTY_STAIRS,
|
||||||
|
RR_SPIRIT_TEMPLE_SUN_BLOCK_ROOM,
|
||||||
|
RR_SPIRIT_TEMPLE_SUN_BLOCK_SOUTH_LEDGE,
|
||||||
|
RR_SPIRIT_TEMPLE_SKULLTULA_STAIRS,
|
||||||
|
RR_SPIRIT_TEMPLE_WEST_THRONE,
|
||||||
|
RR_SPIRIT_TEMPLE_WEST_HAND_EXIT,
|
||||||
|
RR_SPIRIT_TEMPLE_OUTER_WEST_HAND,
|
||||||
|
RR_SPIRIT_TEMPLE_POT_STAIRS,
|
||||||
|
RR_SPIRIT_TEMPLE_BEAMOS_PITS,
|
||||||
|
RR_SPIRIT_TEMPLE_FOUR_ARMOS,
|
||||||
|
RR_SPIRIT_TEMPLE_FOUR_ARMOS_SIDE_ROOM,
|
||||||
|
RR_SPIRIT_TEMPLE_CHEST_STAIRS,
|
||||||
|
RR_SPIRIT_TEMPLE_EAST_THRONE,
|
||||||
|
RR_SPIRIT_TEMPLE_EAST_HAND_EXIT,
|
||||||
|
RR_SPIRIT_TEMPLE_OUTER_EAST_HAND,
|
||||||
|
RR_SPIRIT_TEMPLE_BIG_WALL_BASE,
|
||||||
|
RR_SPIRIT_TEMPLE_BIG_WALL_UPPER,
|
||||||
|
RR_SPIRIT_TEMPLE_4F_CENTRAL,
|
||||||
|
RR_SPIRIT_TEMPLE_FAKE_DOORS_ROOM,
|
||||||
|
RR_SPIRIT_TEMPLE_BIG_MIRROR_ROOM,
|
||||||
|
RR_SPIRIT_TEMPLE_BIG_MIRROR_CAVE,
|
||||||
|
RR_SPIRIT_TEMPLE_PLATFORM,
|
||||||
|
RR_SPIRIT_TEMPLE_STATUE_HEAD,
|
||||||
|
|
||||||
RR_SPIRIT_TEMPLE_MQ_LOBBY,
|
RR_SPIRIT_TEMPLE_MQ_LOBBY,
|
||||||
RR_SPIRIT_TEMPLE_MQ_1F_WEST,
|
RR_SPIRIT_TEMPLE_MQ_1F_WEST,
|
||||||
RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_NORTH,
|
|
||||||
RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH,
|
RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_NORTH,
|
||||||
RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM,
|
||||||
RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_NORTH,
|
RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_NORTH,
|
||||||
RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH,
|
RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH,
|
||||||
RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH,
|
RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH,
|
||||||
RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE,
|
RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE,
|
||||||
RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_WEST,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_INNER_WEST_HAND,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_POT_LEDGE,
|
||||||
RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_FLAMETHROWER_STAIRS,
|
||||||
RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM,
|
||||||
RR_SPIRIT_TEMPLE_MQ_WEST_IRON_KNUCKLE,
|
RR_SPIRIT_TEMPLE_MQ_SKULLTULA_STAIRS,
|
||||||
RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND,
|
RR_SPIRIT_TEMPLE_MQ_WEST_THRONE,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_WEST_HAND_EXIT,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_OUTER_WEST_HAND,
|
||||||
RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH,
|
RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH,
|
||||||
RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH,
|
RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH,
|
||||||
RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST,
|
RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_INNER_EAST_HAND,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_CHEST_LEDGE,
|
||||||
RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F,
|
RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F,
|
||||||
RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_1F,
|
RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_1F,
|
||||||
RR_SPIRIT_TEMPLE_MQ_1F_EAST,
|
RR_SPIRIT_TEMPLE_MQ_1F_EAST,
|
||||||
RR_SPIRIT_TEMPLE_MQ_LEEVER_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_SAND_PIT,
|
||||||
RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_UPPER,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_LOWER,
|
||||||
RR_SPIRIT_TEMPLE_MQ_AFTER_SYMPHONY_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_AFTER_SYMPHONY_ROOM,
|
||||||
RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_FIRE_WALL_STAIRS_LOWER,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_FIRE_WALL_STAIRS_UPPER,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_BEAMOS_PITS,
|
||||||
RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM,
|
||||||
RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND,
|
RR_SPIRIT_TEMPLE_MQ_FLOORMASTER_STAIRS,
|
||||||
RR_SPIRIT_TEMPLE_MQ_EAST_IRON_KNUCKLE,
|
RR_SPIRIT_TEMPLE_MQ_EAST_THRONE,
|
||||||
RR_SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND,
|
RR_SPIRIT_TEMPLE_MQ_EAST_HAND_EXIT,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_OUTER_EAST_HAND,
|
||||||
RR_SPIRIT_TEMPLE_MQ_3F_GIBDO_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_3F_GIBDO_ROOM,
|
||||||
RR_SPIRIT_TEMPLE_MQ_BIG_WALL,
|
RR_SPIRIT_TEMPLE_MQ_BIG_WALL_LOWER,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_BIG_WALL_UPPER,
|
||||||
RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL,
|
RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL,
|
||||||
RR_SPIRIT_TEMPLE_MQ_NINE_CHAIRS_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_NINE_THRONES_ROOM,
|
||||||
RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_ROOM,
|
RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_ROOM,
|
||||||
RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE,
|
RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE,
|
||||||
RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD,
|
RR_SPIRIT_TEMPLE_MQ_PLATFORM,
|
||||||
|
RR_SPIRIT_TEMPLE_MQ_STATUE_HEAD,
|
||||||
|
|
||||||
RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY,
|
RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY,
|
||||||
RR_SPIRIT_TEMPLE_BOSS_ROOM,
|
RR_SPIRIT_TEMPLE_BOSS_ROOM,
|
||||||
|
@ -3629,7 +3684,7 @@ typedef enum {
|
||||||
RT_SHADOW_MQ_WINDY_WALKWAY,
|
RT_SHADOW_MQ_WINDY_WALKWAY,
|
||||||
RT_LENS_SPIRIT,
|
RT_LENS_SPIRIT,
|
||||||
RT_SPIRIT_CHILD_CHU,
|
RT_SPIRIT_CHILD_CHU,
|
||||||
RT_SPIRIT_LOBBY_GS,
|
RT_SPIRIT_WEST_LEDGE,
|
||||||
RT_SPIRIT_LOWER_ADULT_SWITCH,
|
RT_SPIRIT_LOWER_ADULT_SWITCH,
|
||||||
RT_SPIRIT_LOBBY_JUMP,
|
RT_SPIRIT_LOBBY_JUMP,
|
||||||
RT_SPIRIT_PLATFORM_HOOKSHOT,
|
RT_SPIRIT_PLATFORM_HOOKSHOT,
|
||||||
|
@ -6445,6 +6500,7 @@ typedef enum {
|
||||||
RE_BARI,
|
RE_BARI,
|
||||||
RE_SHABOM,
|
RE_SHABOM,
|
||||||
RE_OCTOROK,
|
RE_OCTOROK,
|
||||||
|
RE_WALLTULA,
|
||||||
} RandomizerEnemy;
|
} RandomizerEnemy;
|
||||||
|
|
||||||
// RANDOTODO compare child long jumpslash range with adult short
|
// RANDOTODO compare child long jumpslash range with adult short
|
||||||
|
|
|
@ -1006,11 +1006,11 @@ void Settings::CreateOptions() {
|
||||||
"Removes the requirements for the Lens of Truth in Spirit Temple.");
|
"Removes the requirements for the Lens of Truth in Spirit Temple.");
|
||||||
OPT_TRICK(RT_SPIRIT_CHILD_CHU, RCQUEST_VANILLA, RA_SPIRIT_TEMPLE, { Tricks::Tag::NOVICE },
|
OPT_TRICK(RT_SPIRIT_CHILD_CHU, RCQUEST_VANILLA, RA_SPIRIT_TEMPLE, { Tricks::Tag::NOVICE },
|
||||||
"Spirit Temple Child Side Bridge with Bombchu", "A carefully-timed Bombchu can hit the switch.");
|
"Spirit Temple Child Side Bridge with Bombchu", "A carefully-timed Bombchu can hit the switch.");
|
||||||
OPT_TRICK(RT_SPIRIT_LOBBY_GS, RCQUEST_VANILLA, RA_SPIRIT_TEMPLE, { Tricks::Tag::NOVICE },
|
OPT_TRICK(RT_SPIRIT_WEST_LEDGE, RCQUEST_BOTH, RA_SPIRIT_TEMPLE, { Tricks::Tag::NOVICE },
|
||||||
"Spirit Temple Main Room GS with Boomerang",
|
"Spirit Temple Statue Room West Ledge Checks with Boomerang",
|
||||||
"Standing on the highest part of the arm of the statue, a precise Boomerang throw can kill and obtain "
|
"By carefully walking onto the upper arm of the statue, it's possible to get a good angle on the "
|
||||||
"this Gold Skulltula. You must throw the Boomerang slightly off to the side so that it curves into the "
|
"Gold Skulltula (In Vanilla) and the farthest pot (In MQ) to collect the checks with Boomerang. "
|
||||||
"Skulltula, as aiming directly at it will clank off of the wall in front.");
|
"The nearest pot in MQ can be reached from the forearm and is always in logic.");
|
||||||
OPT_TRICK(RT_SPIRIT_LOWER_ADULT_SWITCH, RCQUEST_VANILLA, RA_SPIRIT_TEMPLE, { Tricks::Tag::ADVANCED },
|
OPT_TRICK(RT_SPIRIT_LOWER_ADULT_SWITCH, RCQUEST_VANILLA, RA_SPIRIT_TEMPLE, { Tricks::Tag::ADVANCED },
|
||||||
"Spirit Temple Lower Adult Switch with Bombs",
|
"Spirit Temple Lower Adult Switch with Bombs",
|
||||||
"A bomb can be used to hit the switch on the ceiling, but it must be thrown from a particular distance "
|
"A bomb can be used to hit the switch on the ceiling, but it must be thrown from a particular distance "
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue