initial SharedSpirit implementation

This commit is contained in:
Pepper0ni 2025-04-12 20:37:13 +01:00
commit 403d905b7e
3 changed files with 59 additions and 38 deletions

View file

@ -210,12 +210,20 @@ bool Here(const RandomizerRegion region, ConditionFn condition) {
return areaTable[region].Here(condition);
}
bool SpiritExplosiveLogic(){
return logic->HasExplosives() ? 1 : ctx->GetOption(RSK_BOMBCHU_BAG) && logic->BombchuRefill() ? 2 : 3;
}
bool SpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) {
return areaTable[region].SpiritShared(condition, []{return logic->HasExplosives();}, []{return true;}, 5, 3, SpiritExplosiveLogic(), anyAge);
}
bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) {
return areaTable[region].MQSpiritShared(condition, false, anyAge);
return areaTable[region].SpiritShared(condition, []{return true;}, []{return true;}, 7, 0, 0, anyAge);
}
bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) {
return areaTable[region].MQSpiritShared(condition, true, anyAge);
return areaTable[region].SpiritShared(condition, []{return true;}, []{return true;}, 7, 7, 6, anyAge);
}
bool BeanPlanted(const RandomizerRegion region) {

View file

@ -8,6 +8,7 @@
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/Enhancements/randomizer/context.h"
#include "soh/Enhancements/randomizer/logic.h"
#include "soh/Enhancements/randomizer/dungeon.h"
typedef bool (*ConditionFn)();
@ -232,6 +233,7 @@ class Region {
}
/*
RANDOTODO edit this
* 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
@ -282,42 +284,57 @@ class Region {
* - 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)) {
bool SpiritShared(ConditionFn condition, ConditionFn childAccess, ConditionFn adultAccess, uint8_t adultKeys, uint8_t childKeys, uint8_t eitherKeys, bool anyAge = false){
//If we have all of the keys, we know that access is Certain Access
if (ctx->GetDungeon(Rando::SPIRIT_TEMPLE)->IsMQ() ? logic->SmallKeys(RR_SPIRIT_TEMPLE, 7) : logic->SmallKeys(RR_SPIRIT_TEMPLE, 5)) {
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;
// otherwise, we have to check the current age and...
} else if (Child() && logic->IsChild) {
bool result = condition();
//if we have enough keys to have Certain Access, we just run the condition
if (logic->SmallKeys(RR_SPIRIT_TEMPLE, childKeys)){
return result;
//otherwise we need to check both ages if we have enough keys that either can get there
} else if (result && logic->SmallKeys(RR_SPIRIT_TEMPLE, eitherKeys) && adultAccess) {
// 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;
result = condition();
logic->IsChild = pastChild;
logic->IsAdult = pastAdult;
return result;
}
} else if (Adult() && logic->IsAdult) {
bool result = condition();
//if we have enough keys to have Certain Access, we just run the condition
if (logic->SmallKeys(RR_SPIRIT_TEMPLE, childKeys)){
return result;
//otherwise we need to check both ages
} else if (result && logic->SmallKeys(RR_SPIRIT_TEMPLE, eitherKeys) && childAccess) {
// store current age variables
bool pastAdult = logic->IsAdult;
bool pastChild = logic->IsChild;
logic->IsChild = true;
logic->IsAdult = false;
result = condition();
logic->IsChild = pastChild;
logic->IsAdult = pastAdult;
return result;
}
}
return false;
}
@ -329,6 +346,7 @@ extern std::vector<EventAccess> grottoEvents;
bool Here(const RandomizerRegion region,
ConditionFn
condition); // RANDOTODO make a less stupid way to check own at either age than self referencing with this
bool SpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false);
bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false);
bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false);
bool CanPlantBean(const RandomizerRegion region);

View file

@ -160,14 +160,9 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_STATUE_ROOM] = Region("Spirit Temple Statue Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_SPIRIT_TEMPLE_MAP_CHEST, ((logic->HasExplosives() || logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHU_BAG) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) &&
(logic->HasFireSource() || (ctx->GetTrickOption(RT_SPIRIT_MAP_CHEST) && logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_STICKS)))) ||
(logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives() && logic->CanUse(RG_STICKS)) ||
(logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && (logic->CanUse(RG_FIRE_ARROWS) || (ctx->GetTrickOption(RT_SPIRIT_MAP_CHEST) && logic->CanUse(RG_FAIRY_BOW))) && logic->CanUse(RG_SILVER_GAUNTLETS))),
LOCATION(RC_SPIRIT_TEMPLE_GS_LOBBY, ((logic->HasExplosives() || logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHU_BAG) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) &&
ctx->GetTrickOption(RT_SPIRIT_LOBBY_GS) && logic->CanUse(RG_BOOMERANG) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP))) ||
(ctx->GetTrickOption(RT_SPIRIT_LOBBY_GS) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives() && logic->CanUse(RG_BOOMERANG)) ||
(logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_SILVER_GAUNTLETS) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)))),
LOCATION(RC_SPIRIT_TEMPLE_MAP_CHEST, SpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_STATUE_ROOM, []{return logic->HasFireSource() || (ctx->GetTrickOption(RT_SPIRIT_MAP_CHEST) && logic->CanUse(RG_FAIRY_BOW));})),
LOCATION(RC_SPIRIT_TEMPLE_GS_LOBBY, SpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_STATUE_ROOM, []{return logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA,
(ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP) || logic->CanUse(RG_HOVER_BOOTS)) ? ED_CLOSE : ctx->GetTrickOption(RT_SPIRIT_LOBBY_GS) ? ED_BOOMERANG : ED_HOOKSHOT);})),
LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_1, logic->CanBreakPots()),
LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_2, logic->CanBreakPots()),
LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_3, logic->CanBreakPots()),