Trick logic (#2681)

* Trick and Glitch Rando UI implemented

* initial temp connection between ui and backend trick logic

Hacky way to connect the logic for testing. Ran into 1 crash but cannot reproduce

* UI overhaul to look more like AudioEditor tag section

* Mapped 3d tricks to enums and save cvar bug fixes

* Trick Logic Complete

Testing on whether the logic works as expected needs to be done

* Releasable trick version, tricks match text fixes also

* Remove 3D glitch logic location access

Easier to clean it up now than get confused

* Variable typo fix & initial trick enum reorganisation

* Removal of oot3d glitches

* bongo logic fix

* UI includes difficulty tags + cleanup and removal of glitched logic interface

* Bug fixes

* added enabled tricks to spoiler log

* comment clean up

* completed once over through logic

* merge fix

* update sohimgui to LUS

* Remove redundant 3d rando trick options

* Comment clean up

* Central GS Irons Logic Fix

* Farores wind central logic fix

---------

Co-authored-by: Christopher Leggett <chris@leggett.dev>
This commit is contained in:
inspectredc
2023-06-02 21:53:07 +01:00
committed by GitHub
parent c9bcd64beb
commit d922b91e15
40 changed files with 2308 additions and 1540 deletions

View File

@@ -286,11 +286,15 @@ namespace Logic {
bool CanFinishGerudoFortress = false;
bool HasShield = false;
bool CanShield = false;
bool CanJumpslash = false;
bool CanUseProjectile = false;
bool CanUseMagicArrow = false;
bool HasShield = false;
bool CanShield = false;
bool ChildShield = false;
bool AdultReflectShield = false;
bool AdultShield = false;
bool CanShieldFlick = false;
bool CanJumpslash = false;
bool CanUseProjectile = false;
bool CanUseMagicArrow = false;
//Bridge and LACS Requirements
uint8_t StoneCount = 0;
@@ -466,202 +470,24 @@ namespace Logic {
return 0;
}
bool CanDoGlitch(GlitchType glitch, GlitchDifficulty difficulty) {
uint8_t setDifficulty;
switch (glitch) {
//Restricted Items
case GlitchType::RestrictedItems:
setDifficulty = GetDifficultyValueFromString(GlitchRestrictedItems);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
//todo rewrite glitch section
bool CanEquipSwap(uint32_t itemName) {
if (!HasItem(itemName))
return false;
if (CanDoGlitch(GlitchType::EquipSwapDins) || CanDoGlitch(GlitchType::EquipSwap))
return true;
//Super Stab
case GlitchType::SuperStab:
setDifficulty = GetDifficultyValueFromString(GlitchSuperStab);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return CanShield && CanUse(STICKS);
return false;
}
//Infinite Sword Glitch
case GlitchType::ISG:
setDifficulty = GetDifficultyValueFromString(GlitchISG);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return CanShield && (IsAdult || KokiriSword || Sticks);
//Bomb Hover
case GlitchType::BombHover:
setDifficulty = GetDifficultyValueFromString(GlitchHover);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && (HasBombchus || (Bombs && setDifficulty >= static_cast<uint8_t>(GlitchDifficulty::ADVANCED)));
//Bomb Ocarina Items
case GlitchType::BombOI:
setDifficulty = GetDifficultyValueFromString(GlitchBombOI);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return Bombs && CanSurviveDamage;
case GlitchType::OutdoorBombOI:
return ((CanUse(FARORES_WIND) && (DinsFire || NayrusLove || LensOfTruth || HasBottle || HasBombchus || Nuts || StartingConsumables ||
(IsChild && (Sticks || ProgressiveBulletBag || (MagicBean || MagicBeanPack) || Boomerang || WeirdEgg || (Hammer && HammerAsChild))) ||
(IsAdult && (ProgressiveBow || Hookshot || HasBoots || Hammer || (Sticks && StickAsAdult) || (Boomerang && BoomerangAsAdult)))) &&
CanDoGlitch(GlitchType::BombOI, (static_cast<uint8_t>(difficulty) >= 3) ? difficulty : GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)) ||
(((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) ||
(CanUse(FARORES_WIND) && FaroresWindAnywhere)) && CanDoGlitch(GlitchType::BombOI, difficulty)));
case GlitchType::WindmillBombOI:
return (((CanUse(FARORES_WIND) || (!NeedNayrusLove && (NayrusLove || DinsFire))) && (LensOfTruth || HasBottle || HasBombchus || Nuts || StartingConsumables ||
(IsChild && (Sticks || ProgressiveBulletBag || (MagicBean || MagicBeanPack) || Boomerang || WeirdEgg || (Hammer && HammerAsChild))) ||
(IsAdult && (ProgressiveBow || Hookshot || HasBoots || Hammer || (Sticks && StickAsAdult) || (Boomerang && BoomerangAsAdult)))) &&
CanDoGlitch(GlitchType::BombOI, (static_cast<uint8_t>(difficulty) >= 3) ? difficulty : GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)) ||
(((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (CanUse(FARORES_WIND) && FaroresWindAnywhere)) && CanDoGlitch(GlitchType::BombOI, difficulty)));
case GlitchType::IndoorBombOI:
return (((IsAdult && ClaimCheck) && (HasBottle || HasBoots || (CanUse(FARORES_WIND) && FaroresWindAnywhere))) ||
((Bugs || Fish || Fairy) && (NumBottles >= 2 || (IsAdult && (ClaimCheck || HasBoots)) || (IsChild && WeirdEgg) || (CanUse(FARORES_WIND) && FaroresWindAnywhere))) ||
((CanUse(FARORES_WIND) && FaroresWindAnywhere) && (HasBottle || (IsAdult && (ClaimCheck || HasBoots)) || (IsChild && WeirdEgg))) ||
(((!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || CanUse(FARORES_WIND)) &&
(NumBottles + ((IsChild) ? ((WeirdEgg) ? 1 : 0) : (((IronBoots) ? 1 : 0) + ((HoverBoots) ? 1 : 0) + ((ClaimCheck) ? 1 : 0))) >= 2))) &&
CanDoGlitch(GlitchType::BombOI, difficulty) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE);
case GlitchType::DungeonBombOI:
return ((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || (CanUse(FARORES_WIND))) && CanDoGlitch(GlitchType::BombOI, difficulty);
//Hover Boost
case GlitchType::HoverBoost:
setDifficulty = GetDifficultyValueFromString(GlitchHoverBoost);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return Bombs && CanUse(HOVER_BOOTS) && CanSurviveDamage;
//Super Slide
case GlitchType::SuperSlide:
setDifficulty = GetDifficultyValueFromString(GlitchSuperSlide);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return true;
//Megaflip
case GlitchType::Megaflip:
setDifficulty = GetDifficultyValueFromString(GlitchMegaflip);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
// Bombchu megaflips should be considered 2 difficulty levels higher
return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast<uint8_t>(difficulty) + 2));
//A-Slide
case GlitchType::ASlide:
setDifficulty = GetDifficultyValueFromString(GlitchASlide);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
// Same deal as bombchu megaflips
return IsChild && CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast<uint8_t>(difficulty) + 2));
//Hammer Slide
case GlitchType::HammerSlide:
setDifficulty = GetDifficultyValueFromString(GlitchHammerSlide);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return CanUse(MEGATON_HAMMER) && CanUse(HOVER_BOOTS) && CanShield;
//Ledge Cancel
case GlitchType::LedgeCancel:
setDifficulty = GetDifficultyValueFromString(GlitchLedgeCancel);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
// Similar to bombchu megaflips / A-slides but doesn't scale beyond advanced
return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast<uint8_t>(GlitchDifficulty::ADVANCED)));
//Action Swap
case GlitchType::ActionSwap:
setDifficulty = GetDifficultyValueFromString(GlitchActionSwap);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return true;
//Quick Put Away
case GlitchType::QPA:
setDifficulty = GetDifficultyValueFromString(GlitchQPA);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
// Boot Put Away Delay Method Frame Perfect Method Ledge Grab Method
return (CanTakeDamage && Bombs && ((CanUse(HOVER_BOOTS) || CanUse(IRON_BOOTS)) || setDifficulty >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE))) || setDifficulty >= static_cast<uint8_t>(GlitchDifficulty::ADVANCED);
//Hookshot Clip
case GlitchType::HookshotClip:
setDifficulty = GetDifficultyValueFromString(GlitchHookshotClip);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return CanUse(HOOKSHOT);
//Hookshot Jump: Bonk
case GlitchType::HookshotJump_Bonk:
setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Bonk);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return IsAdult && Hookshot; // Child hookshot jumps are tiny so these stay as adult only until I check
//Hookshot Jump: Boots
case GlitchType::HookshotJump_Boots:
setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Boots);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return IsAdult && Hookshot && HasBoots; // Child hookshot jumps are tiny so these stay as adult only until I check
//Cutscene Dives
case GlitchType::CutsceneDive:
setDifficulty = GetDifficultyValueFromString(GlitchCutsceneDive);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return true;
//Navi Dives without TSC
case GlitchType::NaviDive_Stick:
setDifficulty = GetDifficultyValueFromString(GlitchNaviDive_Stick);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return IsChild && Sticks;
//Triple Slash Clip
case GlitchType::TripleSlashClip:
setDifficulty = GetDifficultyValueFromString(GlitchTripleSlashClip);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return IsAdult || KokiriSword;
//Ledge Clip
case GlitchType::LedgeClip:
setDifficulty = GetDifficultyValueFromString(GlitchLedgeClip);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return IsAdult;
//Seam Walks
case GlitchType::SeamWalk:
setDifficulty = GetDifficultyValueFromString(GlitchSeamWalk);
if (setDifficulty < static_cast<uint8_t>(difficulty)) {
return false;
}
return true;
bool CanDoGlitch(GlitchType glitch) {
switch(glitch) {
case GlitchType::EquipSwapDins:
return ((IsAdult && HasItem(DINS_FIRE)) || (IsChild && (HasItem(STICKS) || HasItem(DINS_FIRE)))) && GlitchEquipSwapDins;
case GlitchType::EquipSwap: // todo: add bunny hood to adult item equippable list and child trade item to child item equippable list
return ((IsAdult && (HasItem(DINS_FIRE) || HasItem(FARORES_WIND) || HasItem(NAYRUS_LOVE))) || (IsChild && (HasItem(STICKS) || HasItem(SLINGSHOT) || HasItem(BOOMERANG) || HasBottle || Nuts || Ocarina || HasItem(LENS_OF_TRUTH) || HasExplosives || (MagicBean || MagicBeanPack) || HasItem(DINS_FIRE) || HasItem(FARORES_WIND) || HasItem(NAYRUS_LOVE)))) && GlitchEquipSwap;
}
//Shouldn't be reached
@@ -767,11 +593,15 @@ namespace Logic {
(GerudoFortress.Is(GERUDOFORTRESS_FAST) && GerudoFortressKeys >= 1 && (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))) ||
(GerudoFortress.IsNot(GERUDOFORTRESS_NORMAL) && GerudoFortress.IsNot(GERUDOFORTRESS_FAST));
HasShield = CanUse(HYLIAN_SHIELD) || CanUse(DEKU_SHIELD); //Mirror shield can't reflect attacks
CanShield = CanUse(MIRROR_SHIELD) || HasShield;
CanJumpslash = IsAdult || Sticks || KokiriSword;
CanUseProjectile = HasExplosives || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT) || CanUse(BOOMERANG);
CanUseMagicArrow = CanUse(FIRE_ARROWS) || CanUse(ICE_ARROWS) || CanUse(LIGHT_ARROWS);
HasShield = CanUse(HYLIAN_SHIELD) || CanUse(DEKU_SHIELD); //Mirror shield can't reflect attacks
CanShield = CanUse(MIRROR_SHIELD) || HasShield;
ChildShield = IsChild && CanUse(DEKU_SHIELD); //hylian shield is not helpful for child
AdultReflectShield = IsAdult && CanUse(HYLIAN_SHIELD); //Mirror shield can't reflect attacks
AdultShield = IsAdult && (CanUse(HYLIAN_SHIELD) || CanUse(MIRROR_SHIELD));
CanShieldFlick = ChildShield || AdultShield;
CanJumpslash = IsAdult || Sticks || KokiriSword;
CanUseProjectile = HasExplosives || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT) || CanUse(BOOMERANG);
CanUseMagicArrow = CanUse(FIRE_ARROWS) || CanUse(ICE_ARROWS) || CanUse(LIGHT_ARROWS);
//Bridge and LACS Requirements
MedallionCount = (ForestMedallion ? 1:0) + (FireMedallion ? 1:0) + (WaterMedallion ? 1:0) + (SpiritMedallion ? 1:0) + (ShadowMedallion ? 1:0) + (LightMedallion ? 1:0);
@@ -806,58 +636,58 @@ namespace Logic {
bool SmallKeys(Key dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched) {
switch (dungeon) {
case FOREST_TEMPLE:
if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotJump_Boots) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHoverBoost) >= static_cast<uint8_t>(GlitchDifficulty::NOVICE) ||
/*if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotJump_Boots) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHoverBoost) >= static_cast<uint8_t>(GlitchDifficulty::NOVICE) ||
(GetDifficultyValueFromString(GlitchHover) >= static_cast<uint8_t>(GlitchDifficulty::NOVICE) && GetDifficultyValueFromString(GlitchISG) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE)))) {
return ForestTempleKeys >= requiredAmountGlitched;
}
}*/
return ForestTempleKeys >= requiredAmountGlitchless;
case FIRE_TEMPLE:
if (IsGlitched && (GetDifficultyValueFromString(GlitchLedgeClip) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE))) {
/*if (IsGlitched && (GetDifficultyValueFromString(GlitchLedgeClip) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE))) {
return FireTempleKeys >= requiredAmountGlitched;
}
}*/
return FireTempleKeys >= requiredAmountGlitchless;
case WATER_TEMPLE:
if (IsGlitched && (false)) {
/*if (IsGlitched && (false)) {
return WaterTempleKeys >= requiredAmountGlitched;
}
}*/
return WaterTempleKeys >= requiredAmountGlitchless;
case SPIRIT_TEMPLE:
if (IsGlitched && (false)) {
/*if (IsGlitched && (false)) {
return SpiritTempleKeys >= requiredAmountGlitched;
}
}*/
return SpiritTempleKeys >= requiredAmountGlitchless;
case SHADOW_TEMPLE:
if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotClip) >= static_cast<uint8_t>(GlitchDifficulty::NOVICE))) {
/*if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotClip) >= static_cast<uint8_t>(GlitchDifficulty::NOVICE))) {
return ShadowTempleKeys >= requiredAmountGlitched;
}
}*/
return ShadowTempleKeys >= requiredAmountGlitchless;
case BOTTOM_OF_THE_WELL:
if (IsGlitched && (false)) {
/*if (IsGlitched && (false)) {
return BottomOfTheWellKeys >= requiredAmountGlitched;
}
}*/
return BottomOfTheWellKeys >= requiredAmountGlitchless;
case GERUDO_TRAINING_GROUNDS:
if (IsGlitched && (false)) {
/*if (IsGlitched && (false)) {
return GerudoTrainingGroundsKeys >= requiredAmountGlitched;
}
}*/
return GerudoTrainingGroundsKeys >= requiredAmountGlitchless;
case GANONS_CASTLE:
if (IsGlitched && (false)) {
/*if (IsGlitched && (false)) {
return GanonsCastleKeys >= requiredAmountGlitched;
}
}*/
return GanonsCastleKeys >= requiredAmountGlitchless;
case MARKET_TREASURE_CHEST_GAME:
if (IsGlitched && (false)) {
/*if (IsGlitched && (false)) {
return TreasureGameKeys >= requiredAmountGlitched;
}
}*/
return TreasureGameKeys >= requiredAmountGlitchless;
default:
@@ -1164,11 +994,15 @@ namespace Logic {
CanFinishGerudoFortress = false;
HasShield = false;
CanShield = false;
CanJumpslash = false;
CanUseProjectile = false;
CanUseMagicArrow = false;
HasShield = false;
CanShield = false;
ChildShield = false;
AdultReflectShield = false;
AdultShield = false;
CanShieldFlick = false;
CanJumpslash = false;
CanUseProjectile = false;
CanUseMagicArrow = false;
//Bridge Requirements
HasAllStones = false;