This commit is contained in:
Pepper0ni 2025-04-24 21:50:53 +01:00
commit 9b2d092a5b
4 changed files with 73 additions and 62 deletions

View file

@ -239,7 +239,8 @@ uint8_t SpiritExplosiveLogic() {
* As we do not know which universe we are in until the player chooses one in-game, * 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 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 * 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, * 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 * then a check is only in logic if all possible universes can collect the check independently
@ -294,9 +295,8 @@ std::map<RandomizerRegion, SpiritLogicData> Region::spiritLogicData = {
*anyAge is equivalent to a self referencing Here, used for events and any check where that is relevent. *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, bool SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge, RandomizerRegion otherRegion,
RandomizerRegion otherRegion, ConditionFn otherCondition, ConditionFn otherCondition, RandomizerRegion thirdRegion, ConditionFn thirdCondition) {
RandomizerRegion thirdRegion, ConditionFn thirdCondition){
SpiritLogicData curRegionData = Region::spiritLogicData[region]; SpiritLogicData curRegionData = Region::spiritLogicData[region];
bool result = false; bool result = false;
@ -308,20 +308,24 @@ bool SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge,
// without opening the Statue room to Broken Wall Room lock first // without opening the Statue room to Broken Wall Room lock first
logic->IsChild = true; logic->IsChild = true;
logic->IsAdult = false; logic->IsAdult = false;
uint8_t childKeys = (logic->ReverseSpiritChild && logic->CanHitSwitch()/* && CanClimbHigh()*/) ? curRegionData.childReverseKeys : curRegionData.childKeys; uint8_t childKeys = (logic->ReverseSpiritChild && logic->CanHitSwitch() /* && CanClimbHigh()*/)
? curRegionData.childReverseKeys
: curRegionData.childKeys;
// If we have enough keys that an age cannot be kept out, we have Certain Access // 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 // otherwise if we have entered in reverse and can reach from the face, we have Certain Access
bool ChildCertainAccess = (logic->ReverseSpiritChild && curRegionData.reverseAccess()) || logic->SmallKeys(RR_SPIRIT_TEMPLE, childKeys); bool ChildCertainAccess =
(logic->ReverseSpiritChild && curRegionData.reverseAccess()) || logic->SmallKeys(RR_SPIRIT_TEMPLE, childKeys);
//Switch back to adult to check adult access // Switch back to adult to check adult access
logic->IsChild = false; logic->IsChild = false;
logic->IsAdult = true; logic->IsAdult = true;
bool AdultCertainAccess = (logic->ReverseSpiritAdult && curRegionData.reverseAccess()) || logic->SmallKeys(RR_SPIRIT_TEMPLE, curRegionData.adultKeys); bool AdultCertainAccess = (logic->ReverseSpiritAdult && curRegionData.reverseAccess()) ||
logic->SmallKeys(RR_SPIRIT_TEMPLE, curRegionData.adultKeys);
// If we are AnyAge and have any CeratinAccess, then we can check those ages // 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 // we don't need to check ambiguity here as if this fails, then 1 of the ages has failed
if (anyAge && (ChildCertainAccess || AdultCertainAccess)){ if (anyAge && (ChildCertainAccess || AdultCertainAccess)) {
// set age access to the Certain Access // set age access to the Certain Access
logic->IsChild = ChildCertainAccess; logic->IsChild = ChildCertainAccess;
logic->IsAdult = AdultCertainAccess; logic->IsAdult = AdultCertainAccess;
@ -331,7 +335,7 @@ bool SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge,
// otherwise, we have to check the current age and... // otherwise, we have to check the current age and...
} else if (areaTable[region].Child() && pastChild) { } else if (areaTable[region].Child() && pastChild) {
//Switch to Child // Switch to Child
logic->IsChild = true; logic->IsChild = true;
logic->IsAdult = false; logic->IsAdult = false;
@ -339,13 +343,15 @@ bool SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge,
// If we have Certain Access, we just run the 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 // 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 // and if needed, in reverse
if (!ChildCertainAccess && result && (!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess())) { if (!ChildCertainAccess && result &&
//Switch to Adult (!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess())) {
// Switch to Adult
logic->IsChild = false; logic->IsChild = false;
logic->IsAdult = true; logic->IsAdult = true;
// If Adult can get there and get the check, we can get the check in logic // 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 // 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()) || result = (curRegionData.adultAccess() &&
(!logic->IsReverseAccessPossible() || curRegionData.reverseAccess) && condition()) ||
(otherRegion != RR_NONE && (otherRegion != RR_NONE &&
(Region::spiritLogicData[otherRegion].adultAccess() && (Region::spiritLogicData[otherRegion].adultAccess() &&
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) && (!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) &&
@ -361,22 +367,24 @@ bool SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge,
// Alternatively, if we have entered in reverse and can reach from the face, we have Certain Access // 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 // 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 // and if needed, in reverse
if (!AdultCertainAccess && result && (!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess)){ if (!AdultCertainAccess && result &&
//Switch to Child (!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess)) {
// Switch to Child
logic->IsChild = true; logic->IsChild = true;
logic->IsAdult = false; logic->IsAdult = false;
// If Child can get there and get the check, we can get the check in logic // 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 // 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()) || result = (curRegionData.childAccess() &&
(otherRegion != RR_NONE && (!logic->IsReverseAccessPossible() || curRegionData.reverseAccess()) && condition()) ||
(Region::spiritLogicData[otherRegion].childAccess() && (otherRegion != RR_NONE &&
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) && (Region::spiritLogicData[otherRegion].childAccess() &&
otherCondition())) || (!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) &&
(thirdRegion != RR_NONE && otherCondition())) ||
(Region::spiritLogicData[thirdRegion].childAccess() && (thirdRegion != RR_NONE &&
(!logic->IsReverseAccessPossible() || Region::spiritLogicData[thirdRegion].reverseAccess()) && (Region::spiritLogicData[thirdRegion].childAccess() &&
thirdCondition())); (!logic->IsReverseAccessPossible() || Region::spiritLogicData[thirdRegion].reverseAccess()) &&
thirdCondition()));
} }
} }
// set back age variables // set back age variables

View file

@ -112,21 +112,21 @@ enum class EntranceType;
} // namespace Rando } // namespace Rando
struct SpiritLogicData { struct SpiritLogicData {
uint8_t childKeys; //the number of keys that guarantees Child can reach this region 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 // 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 // This changes for MQ broken wall room as the first child lock can only be opened by Child
//guaranteeing access with 6 keys // guaranteeing access with 6 keys
uint8_t childReverseKeys; uint8_t childReverseKeys;
uint8_t adultKeys; //the number of keys that guarantees Adult can reach this region 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, // The area access condition to reach this region as Child, from the first lock,
//including the minimum number of keys for ambiguous access // including the minimum number of keys for ambiguous access
// 1 key is always assumed to be required // 1 key is always assumed to be required
ConditionFn childAccess; ConditionFn childAccess;
//The area access condition to reach this region as Adult, from the first lock // The area access condition to reach this region as Adult, from the first lock
//including the minimum number of keys for ambiguous access // including the minimum number of keys for ambiguous access
//1 key is always assumed to be required on vanilla // 1 key is always assumed to be required on vanilla
ConditionFn adultAccess; ConditionFn adultAccess;
//The area access condition to reach this region from the boss door, // The area access condition to reach this region from the boss door,
ConditionFn reverseAccess; ConditionFn reverseAccess;
}; };
@ -260,9 +260,10 @@ 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 SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge = false, bool SpiritShared(
RandomizerRegion otherRegion = RR_NONE, ConditionFn otherCondition = []{return false;}, RandomizerRegion region, ConditionFn condition, bool anyAge = false, RandomizerRegion otherRegion = RR_NONE,
RandomizerRegion thirdRegion = RR_NONE, ConditionFn thirdCondition = []{return false;}); ConditionFn otherCondition = [] { return false; }, RandomizerRegion thirdRegion = RR_NONE,
ConditionFn thirdCondition = [] { return false; });
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);

View file

@ -864,7 +864,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 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);
@ -2362,10 +2362,9 @@ void Logic::SetInLogic(LogicVal logicVal, bool value) {
inLogic[logicVal] = value; inLogic[logicVal] = value;
} }
bool Logic::IsReverseAccessPossible(){ bool Logic::IsReverseAccessPossible() {
return ctx->GetOption(RSK_SHUFFLE_BOSS_ENTRANCES) && return ctx->GetOption(RSK_SHUFFLE_BOSS_ENTRANCES) &&
(ctx->GetOption(RSK_DECOUPLED_ENTRANCES) || (ctx->GetOption(RSK_DECOUPLED_ENTRANCES) || ctx->GetOption(RSK_MIX_BOSS_ENTRANCES));
ctx->GetOption(RSK_MIX_BOSS_ENTRANCES));
} }
bool Logic::SpiritBrokenWallToStatue() { bool Logic::SpiritBrokenWallToStatue() {
@ -2373,7 +2372,8 @@ bool Logic::SpiritBrokenWallToStatue() {
} }
bool Logic::SpiritEastToSwitch() { bool Logic::SpiritEastToSwitch() {
return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) || CanUse(RG_HOVER_BOOTS) || (CanUse(RG_ZELDAS_LULLABY) && CanUse(RG_HOOKSHOT)); return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) || CanUse(RG_HOVER_BOOTS) ||
(CanUse(RG_ZELDAS_LULLABY) && CanUse(RG_HOOKSHOT));
} }
bool Logic::SpiritWestToSkull() { bool Logic::SpiritWestToSkull() {
@ -2381,22 +2381,25 @@ bool Logic::SpiritWestToSkull() {
} }
bool Logic::SpiritSunBlockSouthLedge() { bool Logic::SpiritSunBlockSouthLedge() {
return true/*str0 || IsAdult || CanKillEnemy(RE_BEAMOS) || BunnyHovers() || return true /*str0 || IsAdult || CanKillEnemy(RE_BEAMOS) || BunnyHovers() ||
(CanUse(RG_HOOKSHOT) && (HasFireSource() || (CanUse(RG_HOOKSHOT) && (HasFireSource() ||
(SpiritSunBlockTorch && (logic->CanUse(STICKS) || (ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && logic->CanUse(RG_FAIRY_BOW))))))*/; (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 // Combines crossing the ledge directly and the jump from the hand
bool Logic::MQSpiritWestToPots() { bool Logic::MQSpiritWestToPots() {
return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) || CanUse(RG_HOVER_BOOTS) || CanUse(RG_SONG_OF_TIME); return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) || CanUse(RG_HOVER_BOOTS) || CanUse(RG_SONG_OF_TIME);
} }
bool Logic::MQSpiritStatueToSunBlock() { bool Logic::MQSpiritStatueToSunBlock() {
return (IsAdult || ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) || CanUse(RG_SONG_OF_TIME))/* && str0*/; return (IsAdult || ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) || CanUse(RG_SONG_OF_TIME)) /* && str0*/;
} }
bool Logic::MQSpiritStatueSouthDoor() { bool Logic::MQSpiritStatueSouthDoor() {
return HasFireSource() || (ctx->GetTrickOption(RT_SPIRIT_MQ_FROZEN_EYE) && CanUse(RG_FAIRY_BOW) && CanUse(RG_SONG_OF_TIME)/* && CanClimb()*/); return HasFireSource() || (ctx->GetTrickOption(RT_SPIRIT_MQ_FROZEN_EYE) && CanUse(RG_FAIRY_BOW) &&
CanUse(RG_SONG_OF_TIME) /* && CanClimb()*/);
} }
void Logic::Reset() { void Logic::Reset() {

View file

@ -26,7 +26,6 @@ enum class GlitchDifficulty {
HERO, HERO,
}; };
class Logic { class Logic {
public: public:
bool noVariable = false; bool noVariable = false;