Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 182 additions & 7 deletions Scripts/EllosBoonSelectorMod.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ EllosBoonSelectorMod.config = config

EllosBoonSelectorMod.RarityFilter = {}
EllosBoonSelectorMod.GodFilter = ""
EllosBoonSelectorMod.ChaosFilter = ""
EllosBoonSelectorMod.CurrentHammerIndex = 1

EllosBoonSelectorMod.RarityColors = {Color.BoonPatchCommon, Color.BoonPatchRare, Color.BoonPatchEpic, Color.BoonPatchLegendary}

EllosBoonSelectorMod.BoonGods = {"Aphrodite", "Ares", "Artemis", "Athena", "Demeter", "Dionysus", "Poseidon", "Zeus"}
EllosBoonSelectorMod.ChaosLocations = { "No Chaos", "Room 1 Chaos", "Room 2 Chaos" }
EllosBoonSelectorMod.PriorityBoons = {"WeaponTrait","SecondaryTrait","RangedTrait","RushTrait"}
EllosBoonSelectorMod.PriorityBoonsOrder = {WeaponTrait = 1, SecondaryTrait = 2, RangedTrait = 3, RushTrait = 4}
EllosBoonSelectorMod.PriorityBoonCannonicalNameToCodeName = {
Expand All @@ -25,7 +27,7 @@ EllosBoonSelectorMod.HammerOptions = {
SwordWeapon1 = {"SwordTwoComboTrait","SwordSecondaryAreaDamageTrait","SwordGoldDamageTrait","SwordBlinkTrait","SwordThrustWaveTrait","SwordHealthBufferDamageTrait","SwordSecondaryDoubleAttackTrait","SwordCriticalTrait","SwordBackstabTrait","SwordDoubleDashAttackTrait","SwordHeavySecondStrikeTrait","SwordCursedLifeStealTrait"},
SwordWeapon2 = {"SwordTwoComboTrait","SwordSecondaryAreaDamageTrait","SwordGoldDamageTrait","SwordBlinkTrait","SwordThrustWaveTrait","SwordHealthBufferDamageTrait","SwordSecondaryDoubleAttackTrait","SwordCriticalTrait","SwordBackstabTrait","SwordDoubleDashAttackTrait","SwordHeavySecondStrikeTrait","SwordCursedLifeStealTrait"},
SwordWeapon3 = {"SwordTwoComboTrait","SwordSecondaryAreaDamageTrait","SwordGoldDamageTrait","SwordBlinkTrait","SwordThrustWaveTrait","SwordHealthBufferDamageTrait","SwordSecondaryDoubleAttackTrait","SwordCriticalTrait","SwordBackstabTrait","SwordDoubleDashAttackTrait","SwordHeavySecondStrikeTrait","SwordCursedLifeStealTrait"},
SwordWeapon4 = {"SwordConsecrationBoostTrait","SwordSecondaryAreaDamageTrait","SwordGoldDamageTrait","SwordThrustWaveTrait","SwordHealthBufferDamageTrait","SwordSecondaryDoubleAttackTrait","SwordBackstabTrait","SwordDoubleDashAttackTrait","SwordCursedLifeStealTrait"},
SwordWeapon4 = {"SwordConsecrationBoostTrait","SwordSecondaryAreaDamageTrait","SwordGoldDamageTrait","SwordBlinkTrait","SwordThrustWaveTrait","SwordHealthBufferDamageTrait","SwordSecondaryDoubleAttackTrait","SwordBackstabTrait","SwordDoubleDashAttackTrait","SwordCursedLifeStealTrait"},
SpearWeapon1 = {"SpearReachAttack", "SpearAutoAttack", "SpearThrowExplode", "SpearThrowBounce", "SpearThrowPenetrate", "SpearThrowCritical", "SpearSpinDamageRadius", "SpearSpinChargeLevelTime", "SpearDashMultiStrike", "SpearThrowElectiveCharge", "SpearSpinChargeAreaDamageTrait", "SpearAttackPhalanxTrait"},
SpearWeapon2 = {"SpearReachAttack", "SpearAutoAttack", "SpearThrowPenetrate", "SpearThrowCritical", "SpearSpinDamageRadius", "SpearSpinChargeLevelTime", "SpearDashMultiStrike", "SpearSpinChargeAreaDamageTrait", "SpearAttackPhalanxTrait"},
SpearWeapon3 = {"SpearReachAttack", "SpearThrowExplode", "SpearThrowBounce", "SpearThrowPenetrate", "SpearThrowCritical", "SpearSpinDamageRadius", "SpearSpinChargeLevelTime", "SpearDashMultiStrike", "SpearThrowElectiveCharge", "SpearSpinChargeAreaDamageTrait", "SpearAttackPhalanxTrait"},
Expand All @@ -37,15 +39,15 @@ EllosBoonSelectorMod.HammerOptions = {
BowWeapon1 = {"BowDoubleShotTrait", "BowLongRangeDamageTrait", "BowSlowChargeDamageTrait", "BowTapFireTrait", "BowPenetrationTrait", "BowPowerShotTrait", "BowSecondaryBarrageTrait", "BowTripleShotTrait", "BowSecondaryFocusedFireTrait", "BowChainShotTrait", "BowCloseAttackTrait", "BowConsecutiveBarrageTrait"},
BowWeapon2 = {"BowDoubleShotTrait", "BowLongRangeDamageTrait", "BowSlowChargeDamageTrait", "BowTapFireTrait", "BowPenetrationTrait", "BowPowerShotTrait", "BowSecondaryBarrageTrait", "BowTripleShotTrait", "BowChainShotTrait", "BowCloseAttackTrait", "BowConsecutiveBarrageTrait"},
BowWeapon3 = {"BowDoubleShotTrait", "BowLongRangeDamageTrait", "BowSlowChargeDamageTrait", "BowTapFireTrait", "BowPenetrationTrait", "BowPowerShotTrait", "BowSecondaryBarrageTrait", "BowTripleShotTrait", "BowSecondaryFocusedFireTrait", "BowChainShotTrait", "BowCloseAttackTrait", "BowConsecutiveBarrageTrait"},
BowWeapon4 = {"BowBondBoostTrait", "BowDoubleShotTrait", "BowLongRangeDamageTrait", "BowSlowChargeDamageTrait", "BowPowerShotTrait", "BowSecondaryBarrageTrait", "BowTripleShotTrait", "BowSecondaryFocusedFireTrait", "BowChainShotTrait", "BowCloseAttackTrait"},
BowWeapon4 = {"BowBondBoostTrait", "BowDoubleShotTrait", "BowLongRangeDamageTrait", "BowSlowChargeDamageTrait", "BowPowerShotTrait", "BowSecondaryBarrageTrait", "BowTripleShotTrait", "BowChainShotTrait", "BowCloseAttackTrait"},
FistWeapon1 = {"FistReachAttackTrait", "FistDashAttackHealthBufferTrait", "FistTeleportSpecialTrait", "FistDoubleDashSpecialTrait", "FistChargeSpecialTrait", "FistKillTrait", "FistSpecialLandTrait", "FistAttackFinisherTrait", "FistConsecutiveAttackTrait", "FistSpecialFireballTrait", "FistAttackDefenseTrait", "FistHeavyAttackTrait"},
FistWeapon2 = {"FistReachAttackTrait", "FistDashAttackHealthBufferTrait", "FistKillTrait", "FistSpecialLandTrait", "FistAttackFinisherTrait", "FistConsecutiveAttackTrait", "FistAttackDefenseTrait", "FistHeavyAttackTrait", "FistDoubleDashSpecialTrait"},
FistWeapon3 = {"FistReachAttackTrait", "FistDashAttackHealthBufferTrait", "FistTeleportSpecialTrait", "FistDoubleDashSpecialTrait", "FistChargeSpecialTrait", "FistKillTrait", "FistAttackFinisherTrait", "FistConsecutiveAttackTrait", "FistSpecialFireballTrait", "FistAttackDefenseTrait", "FistHeavyAttackTrait"},
FistWeapon4 = {"FistDetonateBoostTrait", "FistSpecialLandTrait", "FistChargeSpecialTrait", "FistConsecutiveAttackTrait", "FistDashAttackHealthBufferTrait", "FistAttackFinisherTrait", "FistAttackDefenseTrait", "FistTeleportSpecialTrait", "FistDoubleDashSpecialTrait", "FistKillTrait"},
FistWeapon4 = {"FistDetonateBoostTrait", "FistSpecialLandTrait", "FistChargeSpecialTrait", "FistConsecutiveAttackTrait", "FistDashAttackHealthBufferTrait", "FistAttackDefenseTrait", "FistTeleportSpecialTrait", "FistDoubleDashSpecialTrait", "FistKillTrait"},
GunWeapon1 = {"GunSlowGrenade", "GunMinigunTrait", "GunShotgunTrait", "GunExplodingSecondaryTrait", "GunGrenadeFastTrait", "GunArmorPenerationTrait", "GunInfiniteAmmoTrait", "GunGrenadeClusterTrait", "GunGrenadeDropTrait", "GunHeavyBulletTrait", "GunChainShotTrait", "GunHomingBulletTrait"},
GunWeapon2 = {"GunSlowGrenade", "GunMinigunTrait", "GunShotgunTrait", "GunExplodingSecondaryTrait", "GunGrenadeFastTrait", "GunArmorPenerationTrait", "GunInfiniteAmmoTrait", "GunGrenadeClusterTrait", "GunGrenadeDropTrait", "GunHeavyBulletTrait", "GunChainShotTrait", "GunHomingBulletTrait"},
GunWeapon3 = {"GunSlowGrenade", "GunMinigunTrait", "GunShotgunTrait", "GunExplodingSecondaryTrait", "GunGrenadeFastTrait", "GunArmorPenerationTrait", "GunInfiniteAmmoTrait", "GunGrenadeClusterTrait", "GunGrenadeDropTrait", "GunHeavyBulletTrait", "GunChainShotTrait", "GunHomingBulletTrait"},
GunWeapon4 = {"GunLoadedGrenadeBoostTrait", "GunLoadedGrenadeLaserTrait", "GunLoadedGrenadeSpeedTrait", "GunLoadedGrenadeWideTrait", "GunLoadedGrenadeInfiniteAmmoTrait", "GunSlowGrenade", "GunGrenadeFastTrait", "GunArmorPenerationTrait", "GunGrenadeDropTrait"},
GunWeapon4 = {"GunLoadedGrenadeBoostTrait", "GunLoadedGrenadeLaserTrait", "GunLoadedGrenadeSpeedTrait", "GunLoadedGrenadeWideTrait", "GunLoadedGrenadeInfiniteAmmoTrait", "GunSlowGrenade", "GunGrenadeFastTrait", "GunArmorPenerationTrait"},
}

--[[
Expand Down Expand Up @@ -169,7 +171,7 @@ function OpenSeedControlScreen( args )
})

-- Roll seed for filters button
components.ClearFiltersButton = CreateScreenComponent({ Name = "ButtonDefault", Scale = 1.0, Group = "Combat_Menu", X = 320, Y = 760 })
components.ClearFiltersButton = CreateScreenComponent({ Name = "ButtonDefault", Scale = 1.0, Group = "Combat_Menu", X = 320, Y = 810 })
components.ClearFiltersButton.OnPressedFunctionName = "ClearFilters"
CreateTextBox({ Id = components.ClearFiltersButton.Id,
Text = "Clear Filters",
Expand All @@ -186,7 +188,7 @@ function OpenSeedControlScreen( args )
})

-- Roll seed for filters button
components.RollSeedForFiltersButton = CreateScreenComponent({ Name = "ButtonDefault", Scale = 1.0, Group = "Combat_Menu", X = 625, Y = 760 })
components.RollSeedForFiltersButton = CreateScreenComponent({ Name = "ButtonDefault", Scale = 1.0, Group = "Combat_Menu", X = 625, Y = 810 })
components.RollSeedForFiltersButton.OnPressedFunctionName = "RollSeedForFilters"
CreateTextBox({ Id = components.RollSeedForFiltersButton.Id,
Text = "Roll Seed For Filters",
Expand Down Expand Up @@ -245,6 +247,30 @@ function OpenSeedControlScreen( args )
end
end

-- Chaos filter buttons
x = -225
y = 290
for _, location in pairs(EllosBoonSelectorMod.ChaosLocations) do
components[location .. "Filter"] = CreateScreenComponent({ Name = "ButtonDefault", Scale = 0.66, Group = "Combat_Menu", X = 500 + x, Y = 450 + y })
components[location .. "Filter"].OnPressedFunctionName = "ToggleChaosFilter"
components[location .. "Filter"].ChaosLocation = location
CreateTextBox({ Id = components[location .. "Filter"].Id,
Text = location,
OffsetX = 0, OffsetY = 0,
FontSize = 16,
Color = Color.BoonPatchCommon,
Font = "AlegreyaSansSCRegular",
ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 2},
Justification = "Center",
DataProperties =
{
OpacityWithOwner = true,
},
})

x = x + 200
end

-- Rarity filter buttons
x = -250
y = 150
Expand Down Expand Up @@ -364,6 +390,34 @@ function OpenSeedControlScreen( args )
OpacityWithOwner = true,
},
})
components.NextRoomNameIndicator = CreateScreenComponent({ Name = "BlankObstacle", Scale = 1.0, Group = "Combat_Menu", X = 1200, Y = 650 })
CreateTextBox({ Id = components.NextRoomNameIndicator.Id,
Text = "",
OffsetX = 400, OffsetY = 70,
FontSize = 22,
Color = Color.White,
Font = "AlegreyaSansSCRegular",
ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 2},
Justification = "Center",
DataProperties =
{
OpacityWithOwner = true,
},
})
components.NextRoomRewardIndicator = CreateScreenComponent({ Name = "BlankObstacle", Scale = 1.0, Group = "Combat_Menu", X = 1200, Y = 650 })
CreateTextBox({ Id = components.NextRoomRewardIndicator.Id,
Text = "",
OffsetX = 400, OffsetY = 100,
FontSize = 22,
Color = Color.White,
Font = "AlegreyaSansSCRegular",
ShadowBlur = 0, ShadowColor = {0,0,0,1}, ShadowOffset={0, 2},
Justification = "Center",
DataProperties =
{
OpacityWithOwner = true,
},
})

local roomReward = PredictStartingRoomReward((NextSeeds[1] or 000000))
UpdateRewardPreview( screen, roomReward )
Expand All @@ -384,6 +438,14 @@ function OpenSeedControlScreen( args )
end

function DoesRewardMatchFilters(roomReward)
if EllosBoonSelectorMod.ChaosFilter == "No Chaos" and (roomReward.FirstRoomChaos or roomReward.SecondRoomChaos) then
return false
elseif EllosBoonSelectorMod.ChaosFilter == "Room 1 Chaos" and not roomReward.FirstRoomChaos then
return false
elseif EllosBoonSelectorMod.ChaosFilter == "Room 2 Chaos" and not roomReward.SecondRoomChaos then
return false
end
Comment on lines 440 to +447

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically this does not support the original functionality of "show if either, but don't filter". I guess my Hammer search is even more janky, but wanted to call it out

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean. If no filter is selected in the UI, EllosBoonSelectorMod.ChaosFilter is set to "", so none of these cases will apply and no filtering will happen.


local targetReward = "Boon"

if EllosBoonSelectorMod.GodFilter == "" and next(EllosBoonSelectorMod.RarityFilter) == nil then
Expand Down Expand Up @@ -469,12 +531,16 @@ end

function ClearFilters ( screen, button )
EllosBoonSelectorMod.GodFilter = ""
EllosBoonSelectorMod.ChaosFilter = ""
EllosBoonSelectorMod.RarityFilter = {}

-- TODO: Use a constant for the priority boons so we don't hardcode them in multiple places
for _, god in pairs(EllosBoonSelectorMod.BoonGods) do
ModifyTextBox({ Id = screen.Components[god .. "Filter"].Id, Color = Color.BoonPatchCommon })
end
for _, location in pairs(EllosBoonSelectorMod.ChaosLocations) do
ModifyTextBox({ Id = screen.Components[location .. "Filter"].Id, Color = Color.BoonPatchCommon })
end
for _, priorityBoon in pairs({"Attack", "Special", "Dash", "Cast"}) do
ModifyTextBox({ Id = screen.Components[priorityBoon .. "Filter"].Id, Color = Color.BoonPatchCommon })
end
Expand All @@ -494,6 +560,19 @@ function ToggleGodFilter ( screen, button )
end
end

function ToggleChaosFilter( screen, button )
local chaosLocation = button.ChaosLocation
EllosBoonSelectorMod.ChaosFilter = chaosLocation

for _, location in pairs(EllosBoonSelectorMod.ChaosLocations) do
if location == chaosLocation then
ModifyTextBox({ Id = screen.Components[location .. "Filter"].Id, Color = Color.BoonPatchCommon })
else
ModifyTextBox({ Id = screen.Components[location .. "Filter"].Id, Color = Color.Gray })
end
end
end

function CycleRarityFilter ( screen, button )
local priorityBoon = button.PriorityBoon

Expand Down Expand Up @@ -609,6 +688,58 @@ function CloseSeedControlScreen( screen, button )
OnScreenClosed({ Flag = screen.Name })
end

function IsSecondRoomRewardEligible(requirements, firstRoomReward)
if requirements.RequiredUpgradeableGodTraits ~= nil and requirements.RequiredUpgradeableGodTraits >= 1 and firstRoomReward ~= "Boon" then
return false
end
if requirements.RequiredMaxWeaponUpgrades ~= nil and requirements.RequiredMaxWeaponUpgrades < 1 and firstRoomReward == "Hammer" then
return false
end
if requirements.RequiredMinDepth ~= nil and requirements.RequiredMinDepth >= 2 then
return false
end
if requirements.RequiredMinBiomeDepth ~= nil and requirements.RequiredMinBiomeDepth >= 2 then
return false
end
if requirements.RequiredFalseCosmetics ~= nil then
return false
end
return true
Comment on lines +692 to +707

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiosity, how did you isolate just these cases. I'm assuming it uses the nightmare method isGameStateEligible in the real code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I just looked at all the different rewards in LootData.RunProgress and picked enough of the GameStateRequirements to eliminate all of the invalid values for the first room.

Another approach would be to construct a correct-looking CurrentRun from scratch, and then actually call IsGameStateEligible, but I wasn't quite willing to tackle that yet.

end

function PredictSecondRoomReward(seedForPrediction, firstRoomReward, firstRoomShrine, secondRoomName)
RandomSetNextInitSeed( {Seed = seedForPrediction} )
local rewardStore = "MetaProgress"
if firstRoomShrine or secondRoomName == "RoomSimple01" then
rewardStore = "RunProgress"
end
local eligibleRewards = {}
for key, reward in pairs(RewardStoreData[rewardStore]) do
if IsSecondRoomRewardEligible(reward.GameStateRequirements, firstRoomReward) then
table.insert(eligibleRewards, key)
end
end
RandomSynchronize(4)
local selectedKey = GetRandomValue( eligibleRewards )
local reward = RewardStoreData[rewardStore][selectedKey].Name
RemoveValueAndCollapse( eligibleRewards, selectedKey )
local eligibleGods = DeepCopyTable(EllosBoonSelectorMod.BoonGods)
if reward == "Boon" then
reward = GetRandomValue( eligibleGods )
RemoveValueAndCollapse( eligibleGods, reward )
end
if firstRoomShrine then
-- roll for the actual exit second
RandomSynchronize(4)
selectedKey = GetRandomValue( eligibleRewards )
reward = RewardStoreData.RunProgress[selectedKey].Name
if reward == "Boon" then
reward = GetRandomValue( eligibleGods )
end
end
return reward
end

--- Takes in a seed and returns the predicted RoomReward object for the starting room.
-- TODO: Update this to use a separate RNG entirely rather than using the current RNG and putting it back again
--
Expand All @@ -628,15 +759,57 @@ function PredictStartingRoomReward( seedForPrediction, currentSeed )
-- Get exact boon rewards and rarity and update the menu
roomReward.BoonData.Options = PredictStartingGodBoonOptions( roomReward.BoonData.God, seedForPrediction, currentSeed )
roomReward.FirstRoomChaos = PredictChaos(6, seedForPrediction)
if roomReward.FirstRoomChaos then
roomReward.FirstRoomShrine = false
else
roomReward.FirstRoomShrine = PredictChaos(7, seedForPrediction)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should refactor PredictChaos to be called something else. Since we are using the same code to check a variety of RNG calls.

end
elseif roomReward.Type == "Hammer" then
roomReward.HammerData = {}
local currentWeapon = GetEquippedWeapon()
roomReward.HammerData.Options = PredictHammerOptionsForWeapon(currentWeapon, GetEquippedWeaponTraitIndex( currentWeapon ), seedForPrediction, currentSeed)
roomReward.FirstRoomChaos = PredictChaos(5, seedForPrediction)

if roomReward.FirstRoomChaos then
roomReward.FirstRoomShrine = false
else
roomReward.FirstRoomShrine = PredictChaos(6, seedForPrediction)
end
end

roomReward.SecondRoomChaos = PredictChaos(2, seedForPrediction)
if roomReward.FirstRoomChaos then
roomReward.SecondRoomChaos = false
else
roomReward.SecondRoomChaos = PredictChaos(2, seedForPrediction)
end

RandomSynchronize(1) -- Known offset at which the RNG rolls the room
roomReward.SecondRoomName = GetRandomValue({
"A_Combat01",
"A_Combat02",
"A_Combat03",
"A_Combat04",
"A_Combat05",
"A_Combat06",
"A_Combat07",
"A_Combat08A",
"A_Combat09",
"A_Combat10",
"A_Combat12",
"A_Combat13",
"A_Combat14",
"A_Combat15",
"A_Combat16",
"A_Combat19",
"A_Combat21",
"A_Combat24",
"RoomSimple01"
})
roomReward.SecondRoomReward = PredictSecondRoomReward(
seedForPrediction,
roomReward.Type,
roomReward.FirstRoomShrine,
roomReward.SecondRoomName)
return roomReward
end

Expand Down Expand Up @@ -912,6 +1085,8 @@ function UpdateRewardPreview( screen, roomReward )
else
ModifyTextBox({ Id = screen.Components.ChaosRoomIndicator.Id, Text = "No Chaos" })
end
ModifyTextBox({ Id = screen.Components.NextRoomNameIndicator.Id, Text = roomReward.SecondRoomName})
ModifyTextBox({ Id = screen.Components.NextRoomRewardIndicator.Id, Text = roomReward.SecondRoomReward})
end

-- Convenient place to add a button to the AdvancedTooltipScreen
Expand Down